diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index fa142b1..a6ae881 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -3,7 +3,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; use kawari::common::custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType}; -use kawari::common::{GameData, timestamp_secs}; +use kawari::common::{GameData, ObjectId, timestamp_secs}; use kawari::common::{Position, determine_initial_starting_zone}; use kawari::config::get_config; use kawari::lobby::CharaMake; @@ -488,6 +488,9 @@ async fn client_loop( // wipe any exit position so it isn't accidentally reused exit_position = None; exit_rotation = None; + + // tell the other players we're here + connection.handle.send(ToServer::ActorSpawned(connection.id, Actor { id: ObjectId(connection.player_data.actor_id), hp: 100 })).await; } ClientZoneIpcData::Unk1 { category, param1, .. @@ -608,6 +611,8 @@ async fn client_loop( connection.player_data.rotation = *rotation; connection.player_data.position = *position; + + connection.handle.send(ToServer::ActorMoved(connection.id, connection.player_data.actor_id, *position)).await; } ClientZoneIpcData::LogOut { .. } => { tracing::info!("Recieved log out from client!"); @@ -768,6 +773,7 @@ async fn client_loop( EffectKind::Damage => { actor.hp -= effect.value as u32; } + _ => todo!() } } diff --git a/src/common/mod.rs b/src/common/mod.rs index c65442f..e3a2e06 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -77,6 +77,26 @@ pub(crate) fn write_quantized_rotation(quantized: &f32) -> u16 { ((quantized + pi / (2.0 * pi)) * max) as u16 } +pub(crate) fn read_packed_float(packed: u16) -> f32 { + todo!() +} + +pub(crate) fn write_packed_float(float: f32) -> u16 { + (((float + 1000.0) * 100.0) * 0.32767501) as u16 +} + +pub(crate) fn read_packed_position(packed: [u16; 3]) -> Position { + todo!() +} + +pub(crate) fn write_packed_position(pos: &Position) -> [u16; 3] { + [ + write_packed_float(pos.x), + write_packed_float(pos.y), + write_packed_float(pos.z), + ] +} + /// Get the number of seconds since UNIX epoch. pub fn timestamp_secs() -> u32 { SystemTime::now() diff --git a/src/world/chat_handler.rs b/src/world/chat_handler.rs index 7634597..1adcb54 100644 --- a/src/world/chat_handler.rs +++ b/src/world/chat_handler.rs @@ -154,32 +154,6 @@ impl ChatHandler { }) .await; } - - // move - { - let ipc = ServerZoneIpcSegment { - unk1: 20, - unk2: 0, - op_code: ServerZoneIpcType::ActorMove, - server_id: 0, - timestamp: timestamp_secs(), - data: ServerZoneIpcData::ActorMove { - pos: Position { - x: 1.0, - y: 0.0, - z: 1.0, - }, - }, - }; - - connection - .send_segment(PacketSegment { - source_actor: 0x106ad804, - target_actor: connection.player_data.actor_id, - segment_type: SegmentType::Ipc { data: ipc }, - }) - .await; - } } "!spawnnpc" => { // spawn another one of us diff --git a/src/world/connection.rs b/src/world/connection.rs index e379021..1e065a4 100644 --- a/src/world/connection.rs +++ b/src/world/connection.rs @@ -21,9 +21,10 @@ use super::{ Actor, Event, Inventory, Item, LuaPlayer, StatusEffects, WorldDatabase, Zone, chat_handler::CUSTOMIZE_DATA, ipc::{ - ActorControlSelf, ActorSetPos, BattleNpcSubKind, ClientZoneIpcSegment, CommonSpawn, - ContainerInfo, ContainerType, InitZone, ItemInfo, NpcSpawn, ObjectKind, ServerZoneIpcData, - ServerZoneIpcSegment, StatusEffect, StatusEffectList, UpdateClassInfo, WeatherChange, + ActorControlSelf, ActorMove, ActorSetPos, BattleNpcSubKind, ClientZoneIpcSegment, + CommonSpawn, ContainerInfo, ContainerType, InitZone, ItemInfo, NpcSpawn, ObjectKind, + ServerZoneIpcData, ServerZoneIpcSegment, StatusEffect, StatusEffectList, UpdateClassInfo, + WeatherChange, }, }; @@ -258,7 +259,11 @@ impl ZoneConnection { let ipc = ServerZoneIpcSegment { op_code: ServerZoneIpcType::ActorMove, timestamp: timestamp_secs(), - data: ServerZoneIpcData::ActorMove { pos: position }, + data: ServerZoneIpcData::ActorMove(ActorMove { + speed: 24, + position, + ..Default::default() + }), ..Default::default() }; diff --git a/src/world/ipc/action_result.rs b/src/world/ipc/action_result.rs index c47eaa8..cba68de 100644 --- a/src/world/ipc/action_result.rs +++ b/src/world/ipc/action_result.rs @@ -7,7 +7,9 @@ use crate::common::{ObjectTypeId, read_quantized_rotation, write_quantized_rotat #[brw(repr = u8)] pub enum EffectKind { #[default] + Miss = 0, // FIXME: is this correct? Damage = 3, + BeginCombo = 27, } #[binrw] @@ -80,7 +82,7 @@ mod tests { assert_eq!(action_result.effect_count, 1); // effect 0: attack - assert_eq!(action_result.effects[0].action_type, 3); + assert_eq!(action_result.effects[0].kind, EffectKind::Damage); assert_eq!(action_result.effects[0].param0, 0); assert_eq!(action_result.effects[0].param1, 113); assert_eq!(action_result.effects[0].param2, 0); @@ -89,6 +91,6 @@ mod tests { assert_eq!(action_result.effects[0].value, 22); // effect 1: start action combo - assert_eq!(action_result.effects[1].action_type, 27); + assert_eq!(action_result.effects[1].kind, EffectKind::BeginCombo); } } diff --git a/src/world/ipc/actor_move.rs b/src/world/ipc/actor_move.rs new file mode 100644 index 0000000..55aac50 --- /dev/null +++ b/src/world/ipc/actor_move.rs @@ -0,0 +1,17 @@ +use binrw::binrw; + +use crate::common::{Position, read_packed_position, write_packed_position}; + +#[binrw] +#[derive(Debug, Clone, Default)] +pub struct ActorMove { + pub dir: u8, + pub dir_before_slip: u8, + pub flag1: u8, + pub flat2: u8, + pub speed: u8, + #[brw(pad_before = 1, pad_after = 4)] // empty + #[br(map = read_packed_position)] + #[bw(map = write_packed_position)] + pub position: Position, +} diff --git a/src/world/ipc/actor_set_pos.rs b/src/world/ipc/actor_set_pos.rs new file mode 100644 index 0000000..cb0514d --- /dev/null +++ b/src/world/ipc/actor_set_pos.rs @@ -0,0 +1,12 @@ +use binrw::binrw; + +use crate::common::Position; + +#[binrw] +#[derive(Debug, Clone, Default)] +pub struct ActorSetPos { + pub unk: u32, + pub layer_id: u32, + pub position: Position, + pub unk3: u32, +} diff --git a/src/world/ipc/mod.rs b/src/world/ipc/mod.rs index 56cc5be..d3f4950 100644 --- a/src/world/ipc/mod.rs +++ b/src/world/ipc/mod.rs @@ -62,6 +62,12 @@ pub use event_start::EventStart; mod action_result; pub use action_result::{ActionEffect, ActionResult, EffectKind}; +mod actor_move; +pub use actor_move::ActorMove; + +mod actor_set_pos; +pub use actor_set_pos::ActorSetPos; + use crate::common::Position; use crate::common::read_string; use crate::common::write_string; @@ -116,16 +122,6 @@ impl Default for ServerZoneIpcSegment { } } -// TODO: move to their own files -#[binrw] -#[derive(Debug, Clone, Default)] -pub struct ActorSetPos { - pub unk: u32, - pub layer_id: u32, - pub position: Position, - pub unk3: u32, -} - #[binrw] #[brw(repr = u8)] #[derive(Clone, PartialEq, Debug)] @@ -197,10 +193,7 @@ pub enum ServerZoneIpcData { /// Sent by the server ActorControl(ActorControl), /// Sent by the server - ActorMove { - #[brw(pad_after = 4)] // empty - pos: Position, - }, + ActorMove(ActorMove), /// Sent by the server Unk17 { unk: [u8; 104] }, /// Sent by the server in response to SocialListRequest @@ -450,6 +443,10 @@ mod tests { ServerZoneIpcType::ActionResult, ServerZoneIpcData::ActionResult(ActionResult::default()), ), + ( + ServerZoneIpcType::ActorMove, + ServerZoneIpcData::ActorMove(ActorMove::default()), + ), ]; for (opcode, data) in &ipc_types {