mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-21 15:07:45 +00:00
Start informing the player of the consequences of their actions
This doesn't work 100% reliably yet, but I do see the action appear in my battle log.
This commit is contained in:
parent
ff3313a0f9
commit
d54b4c945e
6 changed files with 180 additions and 23 deletions
|
@ -144,6 +144,11 @@
|
|||
"name": "UpdateHpMpTp",
|
||||
"opcode": 325,
|
||||
"size": 8
|
||||
},
|
||||
{
|
||||
"name": "ActionResult",
|
||||
"opcode": 785,
|
||||
"size": 124
|
||||
}
|
||||
],
|
||||
"ClientZoneIpcType": [
|
||||
|
|
|
@ -2,8 +2,8 @@ use std::sync::{Arc, Mutex};
|
|||
|
||||
use kawari::common::custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType};
|
||||
use kawari::common::{
|
||||
INVALID_OBJECT_ID, ObjectId, Position, determine_initial_starting_zone, get_citystate,
|
||||
get_world_name,
|
||||
INVALID_OBJECT_ID, ObjectId, ObjectTypeId, Position, determine_initial_starting_zone,
|
||||
get_citystate, get_world_name,
|
||||
};
|
||||
use kawari::common::{get_racial_base_attributes, timestamp_secs};
|
||||
use kawari::config::get_config;
|
||||
|
@ -15,8 +15,9 @@ use kawari::packet::{
|
|||
send_packet,
|
||||
};
|
||||
use kawari::world::ipc::{
|
||||
ClientZoneIpcData, CommonSpawn, DisplayFlag, GameMasterCommandType, GameMasterRank, ObjectKind,
|
||||
OnlineStatus, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType,
|
||||
ActionEffect, ActionResult, ClientZoneIpcData, CommonSpawn, DisplayFlag, GameMasterCommandType,
|
||||
GameMasterRank, ObjectKind, OnlineStatus, PlayerSubKind, ServerZoneIpcData,
|
||||
ServerZoneIpcSegment, SocialListRequestType,
|
||||
};
|
||||
use kawari::world::{
|
||||
ChatHandler, Inventory, Zone, ZoneConnection,
|
||||
|
@ -362,7 +363,7 @@ async fn main() {
|
|||
gm_rank: GameMasterRank::Debug,
|
||||
online_status: OnlineStatus::GameMasterBlue,
|
||||
common: CommonSpawn {
|
||||
class_job: 35,
|
||||
class_job: 1,
|
||||
name: chara_details.name,
|
||||
hp_curr: 100,
|
||||
hp_max: 100,
|
||||
|
@ -782,7 +783,7 @@ async fn main() {
|
|||
|
||||
println!("Found action: {:#?}", action_row);
|
||||
|
||||
//if request.target.object_id == INVALID_OBJECT_ID {
|
||||
// placeholder for now
|
||||
if let Some(actor) =
|
||||
connection.get_actor(ObjectId(0x106ad804))
|
||||
{
|
||||
|
@ -793,22 +794,61 @@ async fn main() {
|
|||
.update_hp_mp(actor.id, actor.hp, 10000)
|
||||
.await;
|
||||
}
|
||||
//} else {
|
||||
let lua = lua.lock().unwrap();
|
||||
lua.scope(|scope| {
|
||||
let connection_data = scope
|
||||
.create_userdata_ref_mut(&mut lua_player)
|
||||
.unwrap();
|
||||
|
||||
let func: Function =
|
||||
lua.globals().get("doAction").unwrap();
|
||||
{
|
||||
let lua = lua.lock().unwrap();
|
||||
lua.scope(|scope| {
|
||||
let connection_data = scope
|
||||
.create_userdata_ref_mut(&mut lua_player)
|
||||
.unwrap();
|
||||
|
||||
func.call::<()>(connection_data).unwrap();
|
||||
let func: Function =
|
||||
lua.globals().get("doAction").unwrap();
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
//}
|
||||
func.call::<()>(connection_data).unwrap();
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// tell them the action results
|
||||
{
|
||||
let ipc = ServerZoneIpcSegment {
|
||||
op_code: ServerZoneIpcType::ActionResult,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::ActionResult(
|
||||
ActionResult {
|
||||
main_target: ObjectTypeId {
|
||||
object_id: ObjectId(0x106ad804),
|
||||
object_type: 0,
|
||||
},
|
||||
action_id: 31,
|
||||
animation_lock_time: 0.6,
|
||||
rotation: connection.player_data.rotation,
|
||||
action_animation_id: 31,
|
||||
flag: 1,
|
||||
effect_count: 1,
|
||||
effects: [ActionEffect {
|
||||
action_type: 3,
|
||||
value: 50,
|
||||
..Default::default()
|
||||
};
|
||||
8],
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
connection
|
||||
.send_segment(PacketSegment {
|
||||
source_actor: connection.player_data.actor_id,
|
||||
target_actor: connection.player_data.actor_id,
|
||||
segment_type: SegmentType::Ipc { data: ipc },
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
ClientZoneIpcData::Unk16 { .. } => {
|
||||
tracing::info!("Recieved Unk16!");
|
||||
|
|
|
@ -132,7 +132,7 @@ impl ZoneConnection {
|
|||
op_code: ServerZoneIpcType::UpdateClassInfo,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::UpdateClassInfo(UpdateClassInfo {
|
||||
class_id: 35,
|
||||
class_id: 1,
|
||||
unknown: 1,
|
||||
synced_level: 90,
|
||||
class_level: 90,
|
||||
|
@ -348,7 +348,7 @@ impl ZoneConnection {
|
|||
};
|
||||
|
||||
self.send_segment(PacketSegment {
|
||||
source_actor: actor_id.0,
|
||||
source_actor: self.player_data.actor_id,
|
||||
target_actor: actor_id.0,
|
||||
segment_type: SegmentType::Ipc { data: ipc },
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use binrw::binrw;
|
||||
|
||||
use crate::common::ObjectTypeId;
|
||||
use crate::common::{ObjectTypeId, read_quantized_rotation, write_quantized_rotation};
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Default)]
|
||||
|
@ -18,10 +18,38 @@ pub struct ActionRequest {
|
|||
pub action_kind: ActionKind,
|
||||
#[brw(pad_before = 2)] // this ISNT empty
|
||||
pub action_id: u32, // See Action Excel sheet
|
||||
pub request_id: u32,
|
||||
pub request_id: u16,
|
||||
#[br(map = read_quantized_rotation)]
|
||||
#[bw(map = write_quantized_rotation)]
|
||||
pub rotation: f32,
|
||||
pub dir: u16,
|
||||
pub dir_target: u16,
|
||||
pub target: ObjectTypeId,
|
||||
pub arg: u32,
|
||||
pub padding_prob: u32,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{fs::read, io::Cursor, path::PathBuf};
|
||||
|
||||
use binrw::BinRead;
|
||||
|
||||
use crate::common::ObjectId;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn read_actionrequest() {
|
||||
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
d.push("resources/tests/action_request.bin");
|
||||
|
||||
let buffer = read(d).unwrap();
|
||||
let mut buffer = Cursor::new(&buffer);
|
||||
|
||||
let action_request = ActionRequest::read_le(&mut buffer).unwrap();
|
||||
assert_eq!(action_request.target.object_id, ObjectId(0x400097d0));
|
||||
assert_eq!(action_request.request_id, 0x2);
|
||||
assert_eq!(action_request.rotation, 1.9694216);
|
||||
}
|
||||
}
|
||||
|
|
75
src/world/ipc/action_result.rs
Normal file
75
src/world/ipc/action_result.rs
Normal file
|
@ -0,0 +1,75 @@
|
|||
use binrw::binrw;
|
||||
|
||||
use crate::common::{ObjectTypeId, read_quantized_rotation, write_quantized_rotation};
|
||||
|
||||
#[binrw]
|
||||
#[brw(little)]
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ActionEffect {
|
||||
pub action_type: u8,
|
||||
pub param0: u8,
|
||||
pub param1: u8,
|
||||
pub param2: u8,
|
||||
pub param3: u8,
|
||||
pub param4: u8,
|
||||
pub value: u16,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[brw(little)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct ActionResult {
|
||||
pub main_target: ObjectTypeId,
|
||||
pub action_id: u32,
|
||||
pub unk1: u32,
|
||||
pub animation_lock_time: f32,
|
||||
pub unk2: u32,
|
||||
pub hidden_animation: u16,
|
||||
#[br(map = read_quantized_rotation)]
|
||||
#[bw(map = write_quantized_rotation)]
|
||||
pub rotation: f32,
|
||||
pub action_animation_id: u16,
|
||||
pub variation: u8,
|
||||
pub flag: u8,
|
||||
pub unk3: u8,
|
||||
pub effect_count: u8,
|
||||
pub unk4: u16,
|
||||
pub unk5: [u8; 6],
|
||||
#[brw(pad_after = 18)] // idk, target is here too?
|
||||
pub effects: [ActionEffect; 8],
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{fs::read, io::Cursor, path::PathBuf};
|
||||
|
||||
use binrw::BinRead;
|
||||
|
||||
use crate::common::ObjectId;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn read_actionresult() {
|
||||
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
d.push("resources/tests/action_result.bin");
|
||||
|
||||
let buffer = read(d).unwrap();
|
||||
let mut buffer = Cursor::new(&buffer);
|
||||
|
||||
let action_result = ActionResult::read_le(&mut buffer).unwrap();
|
||||
assert_eq!(action_result.main_target.object_id, ObjectId(0x400097d0));
|
||||
assert_eq!(action_result.action_id, 31);
|
||||
assert_eq!(action_result.animation_lock_time, 0.6);
|
||||
assert_eq!(action_result.rotation, 1.9694216);
|
||||
assert_eq!(action_result.action_animation_id, 31);
|
||||
assert_eq!(action_result.flag, 1);
|
||||
assert_eq!(action_result.effect_count, 1);
|
||||
|
||||
// effect 0: attack
|
||||
assert_eq!(action_result.effects[0].action_type, 3);
|
||||
|
||||
// effect 1: start action combo
|
||||
assert_eq!(action_result.effects[1].action_type, 27);
|
||||
}
|
||||
}
|
|
@ -59,6 +59,9 @@ pub use event_play::EventPlay;
|
|||
mod event_start;
|
||||
pub use event_start::EventStart;
|
||||
|
||||
mod action_result;
|
||||
pub use action_result::{ActionEffect, ActionResult};
|
||||
|
||||
use crate::common::Position;
|
||||
use crate::common::read_string;
|
||||
use crate::common::write_string;
|
||||
|
@ -222,6 +225,8 @@ pub enum ServerZoneIpcData {
|
|||
mp: u16,
|
||||
unk: u16, // it's filled with... something
|
||||
},
|
||||
/// Sent to inform the client the consequences of their actions
|
||||
ActionResult(ActionResult),
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
|
@ -437,6 +442,10 @@ mod tests {
|
|||
ServerZoneIpcType::EventStart,
|
||||
ServerZoneIpcData::EventStart(EventStart::default()),
|
||||
),
|
||||
(
|
||||
ServerZoneIpcType::ActionResult,
|
||||
ServerZoneIpcData::ActionResult(ActionResult::default()),
|
||||
),
|
||||
];
|
||||
|
||||
for (opcode, data) in &ipc_types {
|
||||
|
|
Loading…
Add table
Reference in a new issue