@@ -68,7 +68,7 @@ pub struct PlayerClient {
6868 pub packet_sender : Option < ActorRef < ConnectionActor < Self > > > ,
6969 session_key : Option < SessionKey > ,
7070 user : Option < user:: Model > ,
71- pub movement_state : Option < MovementState > ,
71+ movement_state : Option < MovementState > ,
7272}
7373
7474impl Debug for PlayerClient {
@@ -80,6 +80,17 @@ impl Debug for PlayerClient {
8080 }
8181}
8282impl PlayerClient {
83+ /// Get the player's effective current position used as a starting point for movement
84+ /// If there is an existing movement, we return its interpolated current position;
85+ /// otherwise we fall back to the stored player coordinates.
86+ pub ( crate ) fn effective_current_position ( & self ) -> anyhow:: Result < ( i32 , i32 , i32 ) > {
87+ if let Some ( movement) = & self . movement_state {
88+ Ok ( movement. calculate_current_position ( ) )
89+ } else {
90+ let player = self . try_get_selected_char ( ) ?;
91+ Ok ( ( player. get_x ( ) , player. get_y ( ) , player. get_z ( ) ) )
92+ }
93+ }
8394 pub fn new ( ip : Ipv4Addr , controller : Arc < GameController > , db_pool : DBPool ) -> Self {
8495 Self {
8596 status : ClientStatus :: Connected ,
@@ -327,16 +338,13 @@ impl PlayerClient {
327338 dest_z : i32 ,
328339 actor_ref : ActorRef < PlayerClient > ,
329340 ) -> anyhow:: Result < ( i32 , i32 , i32 ) > {
330- // Cancel existing movement if any and get the current position
331- let ( current_x, current_y, current_z) =
332- if let Some ( mut existing_movement) = self . movement_state . take ( ) {
333- existing_movement. cancel_task ( ) ;
334- existing_movement. calculate_current_position ( )
335- } else {
336- // Use a player's stored position
337- let player = self . try_get_selected_char ( ) ?;
338- ( player. get_x ( ) , player. get_y ( ) , player. get_z ( ) )
339- } ;
341+ // Compute effective current position consistent with validation logic
342+ let ( current_x, current_y, current_z) = self . effective_current_position ( ) ?;
343+
344+ // Cancel existing movement if any
345+ if let Some ( mut existing_movement) = self . movement_state . take ( ) {
346+ existing_movement. cancel_task ( ) ;
347+ }
340348
341349 // Get player speed
342350 let player = self . try_get_selected_char ( ) ?;
@@ -399,8 +407,25 @@ impl PlayerClient {
399407 /// Stop current movement and return the current interpolated position
400408 pub fn stop_movement ( & mut self ) -> Option < ( i32 , i32 , i32 ) > {
401409 if let Some ( mut movement) = self . movement_state . take ( ) {
410+ // Calculate current position at the time of stopping
411+ let ( x, y, z) = movement. calculate_current_position ( ) ;
412+
413+ // Stop periodic task
402414 movement. cancel_task ( ) ;
403- Some ( movement. calculate_current_position ( ) )
415+
416+ // Persist the position to the selected character so server state matches
417+ match self . try_get_selected_char_mut ( ) {
418+ Ok ( player) => {
419+ if let Err ( err) = player. set_location ( x, y, z) {
420+ error ! ( "Failed to persist player position on stop_movement: {err}" ) ;
421+ }
422+ }
423+ Err ( err) => {
424+ error ! ( "Failed to get selected character on stop_movement: {err}" ) ;
425+ }
426+ }
427+
428+ Some ( ( x, y, z) )
404429 } else {
405430 None
406431 }
0 commit comments