From 63bc9031c9712dcaf17b288e0a2f4bf5a377de41 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sat, 29 Mar 2025 00:28:49 -0400 Subject: [PATCH] Restore player position and rotation on login --- src/bin/kawari-world.rs | 8 +++++++- src/common/mod.rs | 30 ++++++++++++++++++++++++++++++ src/world/ipc/common_spawn.rs | 8 +++++--- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index dcf5633..2bf8de0 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -66,6 +66,7 @@ async fn main() { }; let mut exit_position = None; + let mut exit_rotation = None; let mut connection = ZoneConnection { socket, @@ -100,6 +101,9 @@ async fn main() { connection.player_data = database.find_player_data(actor_id.parse::().unwrap()); + exit_position = Some(connection.player_data.position); + exit_rotation = Some(connection.player_data.rotation); + // We have send THEM a keep alive { connection @@ -263,7 +267,7 @@ async fn main() { .await; } - let zone_id = chara_details.zone_id; + let zone_id = connection.player_data.zone_id; connection.zone = Some(Zone::load(zone_id)); // Player Setup @@ -372,6 +376,7 @@ async fn main() { ], pos: exit_position .unwrap_or(Position::default()), + rotation: exit_rotation.unwrap_or(0.0), ..Default::default() }, ..Default::default() @@ -410,6 +415,7 @@ async fn main() { // wipe any exit position so it isn't accidentally reused exit_position = None; + exit_rotation = None; } ClientZoneIpcData::Unk1 { .. } => { tracing::info!("Recieved Unk1!"); diff --git a/src/common/mod.rs b/src/common/mod.rs index 0b1d9c7..fe6d79f 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -64,6 +64,22 @@ pub(crate) fn write_string(str: &String) -> Vec { c_string.as_bytes_with_nul().to_vec() } +/// Converts a quantized rotation to degrees in f32 +pub(crate) fn read_quantized_rotation(quantized: u16) -> f32 { + let max = std::u16::MAX as f32; + let pi = std::f32::consts::PI; + + quantized as f32 / max * (2.0 * pi) - pi +} + +/// Converts a rotation (in degrees) to +pub(crate) fn write_quantized_rotation(quantized: &f32) -> u16 { + let max = std::u16::MAX as f32; + let pi = std::f32::consts::PI; + + ((quantized + pi / (2.0 * pi)) * max) as u16 +} + /// Get the number of seconds since UNIX epoch. pub fn timestamp_secs() -> u32 { SystemTime::now() @@ -136,3 +152,17 @@ pub fn determine_initial_starting_zone(citystate_id: u8) -> u16 { _ => panic!("This is not a valid city-state id!"), } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn quantized_rotations() { + assert_eq!(read_quantized_rotation(0), -std::f32::consts::PI); + assert_eq!(read_quantized_rotation(65535), std::f32::consts::PI); + + assert_eq!(write_quantized_rotation(&-std::f32::consts::PI), 0); + assert_eq!(write_quantized_rotation(&std::f32::consts::PI), 65535); + } +} diff --git a/src/world/ipc/common_spawn.rs b/src/world/ipc/common_spawn.rs index 52ec4fd..34d6ed9 100644 --- a/src/world/ipc/common_spawn.rs +++ b/src/world/ipc/common_spawn.rs @@ -3,8 +3,8 @@ use binrw::binrw; use bitflags::bitflags; use crate::common::{ - CHAR_NAME_MAX_LENGTH, CustomizeData, ObjectId, ObjectTypeId, Position, read_string, - write_string, + CHAR_NAME_MAX_LENGTH, CustomizeData, ObjectId, ObjectTypeId, Position, read_quantized_rotation, + read_string, write_quantized_rotation, write_string, }; use super::StatusEffect; @@ -166,7 +166,9 @@ pub struct CommonSpawn { pub unk: u16, /// See ModelChara Excel sheet pub model_chara: u16, - pub rotation: u16, // assumed + #[br(map = read_quantized_rotation)] + #[bw(map = write_quantized_rotation)] + pub rotation: f32, pub current_mount: u16, // assumed pub active_minion: u16, // assumed pub u23: u8, // assumed