Skip to content

Fix multiplayer player data mix between different players bug#536

Merged
codeHusky merged 5 commits intosmartcmd:mainfrom
kuwacom:fix/multiplayer-player-data
Mar 6, 2026
Merged

Fix multiplayer player data mix between different players bug#536
codeHusky merged 5 commits intosmartcmd:mainfrom
kuwacom:fix/multiplayer-player-data

Conversation

@kuwacom
Copy link
Contributor

@kuwacom kuwacom commented Mar 5, 2026

Description

This PR fixes a Win64 multiplayer identity bug where player save data (players/*.dat) could be loaded for the wrong player when join order changed.

On Win64, player identity was effectively tied to connection-order smallId-based XUIDs.
This PR introduces a deterministic username-derived persistent XUID and wires it into the existing XUID-based save/load flow.

fixed.mp4

Changes

Previous Behavior

inventory/progress/map ownership could appear swapped between players.

Root Cause

  • Save/load and map ownership logic are keyed by Player::xuid.
  • Win64 networking identity (IQNetPlayer::GetXuid) was tied to smallId, not a stable per-user identifier.
  • This created instability in player-data lookup whenever connection ordering changed.

New Behavior

  • Added Windows64_NameXuid for deterministic name -> persistent xuid resolution.
  • On Win64 login (PlayerList), ServerPlayer::xuid is now resolved from username.
  • Local player xuid assignment (Minecraft) is aligned to the same resolver in create/init/respawn paths.
  • Added a Win64 local-self guard in ClientConnection::handleAddPlayer (name check) to prevent duplicate local remote-player creation.
  • IQNet::GetPlayerByXuid keeps compatibility fallback behavior, but now also resolves username-based XUIDs.
  • Canonical implementation is in Minecraft.Client/Windows64/Windows64_NameXuid.h; legacy Win64NameXuid.h remains as a compatibility include.

Rename migration is intentionally out of scope (same-name identity only).

Related Issues

Fixes a Win64 multiplayer issue where player data (`players/*.dat`) could be mismatched because identity was effectively tied to connection-order `smallId` XUIDs.
Introduces a deterministic username-derived persistent XUID and integrates it into the existing XUID-based save pipeline.

- Added `Windows64_NameXuid` for deterministic `name -> persistent xuid` resolution
- On Win64 login (`PlayerList`), set `ServerPlayer::xuid` from username-based resolver
- Aligned local player `xuid` assignment (`Minecraft`) for create/init/respawn paths to use the same resolver
- Added Win64 local-self guard in `ClientConnection::handleAddPlayer` using name match to avoid duplicate local remote-player creation
- Kept `IQNet::GetPlayerByXuid` compatibility fallback behavior, while extending lookup to also resolve username-based XUIDs
- Moved implementation to `Minecraft.Client/Windows64/Windows64_NameXuid.h`; kept legacy `Win64NameXuid.h` as compatibility include

Rename migration is intentionally out of scope (same-name identity only).
@codeHusky
Copy link
Collaborator

codeHusky commented Mar 5, 2026

@kuwacom In my opinion it makes more sense for the game to simply generate a random Xuid value upon first boot and store it alongside where the username is configured.

That way we mirror Java-like username-uuid decoupling and prevent issues where people change their username (very likely to happen) and just lose progress for no reason. It also makes their Xuid less easy to guess, though eventually (if we support stuff like Steam networking) we will just use platform ID values

@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 5, 2026

That's right. Considering the current situation, it might be better to generate the Xuid the first time and set it in a file.

@codeHusky
Copy link
Collaborator

If you do that I'll test & merge this in

@codeHusky codeHusky added priority: EXTREME multiplayer Multiplayer, CO-OP, Hot Seat, call it whatever you want. labels Mar 5, 2026
@codeHusky
Copy link
Collaborator

Trying to fix this up in feat/multiplayer-fix

@codeHusky
Copy link
Collaborator

This breaks loading existing saves data unfortunately. May have to just patch the save/load singleplayer to allow the hardcoded xuid as a fallback

@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 5, 2026

I got some sleep and went out.

This breaks loading existing saves data unfortunately. May have to just patch the save/load singleplayer to allow the hardcoded xuid as a fallback

That's so true.
I made this without thinking about compatibility.
I made the change in the middle of working on my own dedicated server, so I didn't think about people who were already playing the game.

I’ll try modifying it so that only the first player in singleplayer uses the previous XUID as a hardcoded value (like in Bedrock Edition)

…patibility

- Add legacy embedded host XUID helper (base + 0).
- When Minecraft.Client is hosting, force only the first host player to use legacy host XUID.
- Keep name-based XUID for non-host players.
- Prevent old singleplayer/hosted worlds from losing/mismatching host player data.
@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

I implemented compatibility first.
I hardcoded it by adding connection order 0 to the previous base XUID.

@codeHusky
Copy link
Collaborator

If that works and you can decouple usernames from UIDs that'd be about perfect. We'll have a long term solution in 4JLibs but loading the uid from something like a uid.dat would be ideal. If we have that then we have at least the foundation of working multiplayer

@codeHusky
Copy link
Collaborator

I have some preliminary stuff I did in https://github.com/smartcmd/MinecraftConsoles/tree/feat/multiplayer-fix that probably doesn't work, but it's at least more or less what I was intending to do if that's any help

kuwacom added 2 commits March 6, 2026 14:04
…D based duplicate login guards

- Replace Win64 username-derived XUID resolution with persistent `uid.dat`-backed identity (`Windows64_Xuid` / `Win64Xuid`).
- Persist a per-client XUID next to the executable, with first-run generation, read/write, and process-local caching.
- Keep legacy host compatibility by pinning host self to legacy embedded `base + 0` XUID for existing world/playerdata continuity.
- Propagate packet-authoritative XUIDs into QNet player slots via `m_resolvedXuid`, and use it for `GetXuid`/`GetPlayerByXuid` with legacy fallback.
- Update Win64 profile/network paths to use persistent XUID for non-host clients and clear resolved identity on disconnect.
- Add login-time duplicate checks: reject connections when the same XUID is already connected (in addition to existing duplicate-name checks on Win64).
- Add inline compatibility comments around legacy/new identity coexistence paths for easier future maintenance.
@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

OK, everything is working smoothly.
for now, it's complete.

  • The XUID is stored as uid.dat in the same directory as the executable.
  • In multiplayer, the host now also checks for duplicate players by XUID in addition to the user name.
  • Compatible with unpatched clients as well.
  • In singleplayer (world host mode), the previous embedded XUID is used to maintain compatibility with existing worlds.

@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

If this implementation is going to be merged, I’d like to merge it into the dedicated server implementation as well.

@codeHusky
Copy link
Collaborator

codeHusky commented Mar 6, 2026

I'm not seeing uid.dat generate in the game directory on my end, testing with release builds. Do I need to connect to a server to generate it?

@codeHusky
Copy link
Collaborator

codeHusky commented Mar 6, 2026

Yep it's on connect - it'd be good to make the uid.dat generate on game launch and not just on connection to the world. If you change that up it's good to merge, and yes I do intend to merge this in

@codeHusky
Copy link
Collaborator

codeHusky commented Mar 6, 2026

separate issues but still notable (prob split into an issue after this pr)

  • reconnecting more than once or twice to a server breaks your ability to connect to it again
    • seems to break connecting for all future players for some reason
  • worlds do not save, even when using /save-all or /stop the world data does not save/load properly for players
  • jumping out of a server from the server list results in a "texture pack not installed" error on the client for some reason

occurs with dedicated server

@codeHusky
Copy link
Collaborator

confirmed player data saves when doing LAN play so this is mergeable as-is when your good with it @kuwacom

@codeHusky codeHusky added game saves World/settings/etc. saving problems good PR Exceptionally good Pull Request labels Mar 6, 2026
@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

separate issues but still notable (prob split into an issue after this pr)

  • reconnecting more than once or twice to a server breaks your ability to connect to it again

    • seems to break connecting for all future players for some reason
  • worlds do not save, even when using /save-all or /stop the world data does not save/load properly for players

  • jumping out of a server from the server list results in a "texture pack not installed" error on the client for some reason

occurs with dedicated server

Is this an issue with the separated dedicated server version that my pull request?

@codeHusky
Copy link
Collaborator

codeHusky commented Mar 6, 2026

no, its an issue with the current -server option in this PR. if thats addressed in ur other pr we're prob fine

@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

So far, I haven’t observed this issue on my server.

I remember that the world save/load logic was quite tricky on the client-side implementation (because of that, I ended up partially separating the world management and changing the save path).

@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

If this implementation is going to be merged, I’d like to merge it into the dedicated server implementation as well.

The merge I mentioned here refers to the isolation dedicated server in my pull request, not the -server dedicated server.
Sorry for the confusion.

I haven’t looked closely at the -server implementation, but it should probably be fine to merge it as-is.

@codeHusky
Copy link
Collaborator

Where does the isolated dedicated server build to? I only see Minecraft.Client.exe in the builds I'm making in VS

@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

Where does the isolated dedicated server build to? I only see Minecraft.Client.exe in the builds I'm making in VS

I should have linked it directly from the start.
sorry

#498

@codeHusky
Copy link
Collaborator

Could you merge the changes from #498 into this then? Would make it easier for me to test and it's a similarly important feature

@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

Yep it's on connect - it'd be good to make the uid.dat generate on game launch and not just on connection to the world. If you change that up it's good to merge, and yes I do intend to merge this in

At startup, I added a check for uid.dat in Windows64_Minecraft.cpp if it's not running in server mode (i.e., not started with -server).

@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

Could you merge the changes from #498 into this then? Would make it easier for me to test and it's a similarly important feature

Once this pull request is merged, I’ll continue the remaining work in the #498

@codeHusky
Copy link
Collaborator

Am I good to merge this as-is then?

@kuwacom
Copy link
Contributor Author

kuwacom commented Mar 6, 2026

ok!

@codeHusky codeHusky merged commit 182d76f into smartcmd:main Mar 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

game saves World/settings/etc. saving problems good PR Exceptionally good Pull Request multiplayer Multiplayer, CO-OP, Hot Seat, call it whatever you want. priority: EXTREME

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MULTIPLAYER BUG] Inventory data may mix between different players

2 participants