Skip to content

Fix player position desync during movement#768

Closed
itayalroy wants to merge 4 commits intoMUnique:masterfrom
itayalroy:player_movement
Closed

Fix player position desync during movement#768
itayalroy wants to merge 4 commits intoMUnique:masterfrom
itayalroy:player_movement

Conversation

@itayalroy
Copy link
Copy Markdown
Contributor

@itayalroy itayalroy commented May 8, 2026

The current Walker implementation is too inaccurate compared to client-side player movement. As a result, the server could think a player was at an older or newer position than the client, reject valid walk requests, and send forced move corrections back, causing a flaky movement experience overall.

Instead of updating player position from a background task with a fixed 300ms/500ms step delay, this PR calculates the player's current position on demand from the active walk path and elapsed movement time. Step duration is calculated per step using client-like movement speed rules, including safezone walking, wings, pets, Fenrir, and diagonal tile distance. When a walk completes or is interrupted, the projected position is persisted back to the stored character position.

Additionally, this PR fixes some issues with observer range, attacks involving safe zones, and stops sending movement paths to observers by default (as MuMain does not use them anymore).

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly refactors the player movement system to eliminate desynchronization issues and enhance the overall movement experience. By introducing a projected walker that dynamically calculates player positions and step durations based on client-like rules, the server's understanding of player location is now much more accurate. This change resolves flaky movement behavior and improves consistency between client and server states, while also refining related game mechanics like observer updates and safezone attack validations.

Highlights

  • Movement System Overhaul: The Walker implementation has been replaced with a new ProjectedWalker to provide more accurate client-side player movement simulation, addressing previous desync issues.
  • Dynamic Position Calculation: Player position is now calculated on demand based on the active walk path and elapsed movement time, rather than fixed-step background tasks.
  • Client-like Movement Speed Rules: Step durations are calculated per step, incorporating various factors such as safezone walking, equipped wings, pets, Fenrir, and diagonal tile distances to match client behavior.
  • Observer and Attack Logic Improvements: Issues related to observer range and attacks involving safe zones have been addressed, and movement paths are no longer sent to observers by default, aligning with MuMain's current practices.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request replaces the timer-based Walker with a new ProjectedWalker that calculates player positions based on elapsed time. It also introduces detailed movement speed logic influenced by equipment (wings, pets, and mounts) and implements safezone-based attack blocking. Review feedback identifies a critical issue in the AOI manager where players may fail to update their bucket during a walk, a logic error in the projection causing a one-tile desync, and the presence of side effects within the Position property getter.

if (obj is ISupportWalk supportWalk)
{
target = supportWalk.WalkTarget;
target = obj is IBucketMapObserver ? obj.Position : supportWalk.WalkTarget;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Changing the target to obj.Position for players (IBucketMapObserver) when the move type is Walk prevents the player from being moved to their destination bucket in the AOI manager. Since the ProjectedWalker does not trigger periodic bucket updates as the player moves, the player will remain stuck in their starting bucket for the entire duration of the walk. This will cause them to miss updates for objects appearing near their destination and potentially make them invisible to observers at the target location. It is recommended to revert to using supportWalk.WalkTarget to ensure the player is moved to the destination bucket immediately, which is the standard behavior for this architecture.

                target = supportWalk.WalkTarget;

Copy link
Copy Markdown
Contributor Author

@itayalroy itayalroy May 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating the bucket to the walk target immediately (as done on main branch) is wrong as well, since it immediately removes the player from the current bucket making him invisible for players nearby. I will figure out a way to fix this.

Comment thread src/GameLogic/ProjectedWalker.cs Outdated
Comment on lines +80 to +89
public Point Position
{
get
{
this.Refresh();
lock (this._walkStateLock)
{
return this.GetProjectedPositionNoLock(out _);
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The Position property getter calls Refresh(), which mutates the internal state of the ProjectedWalker and triggers external side effects via _positionChanged (which eventually calls IAttackableMovedPlugIn). Mutating state and triggering plugin logic inside a property getter is generally considered a bad practice as it can lead to unexpected side effects during debugging or simple state inspection. Furthermore, since Refresh updates the character's stored coordinates without a lock on the character object, it introduces potential thread-safety issues if the position is queried from multiple threads (e.g., AOI updates from other players).

@itayalroy itayalroy force-pushed the player_movement branch 2 times, most recently from 6afb1a5 to a59ae7a Compare May 8, 2026 15:40
@itayalroy itayalroy marked this pull request as draft May 8, 2026 15:57
@itayalroy itayalroy closed this May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant