Introduce uid.dat (offline PlayerUIDs), fix multiplayer save data persistence (#536)
* fix: fix multiplayer player data mix between different players bug 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). * fix: preserve legacy host xuid (base xuid + 0) for existing world compatibility - 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. * update: migrate Win64 player uid to `uid.dat`-backed XUID and add XUID 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. * update: ensure uid.dat exists at startup in client mode for multiplayer
This commit is contained in:
@@ -52,6 +52,7 @@
|
||||
#include "..\Minecraft.World\net.minecraft.world.level.dimension.h"
|
||||
#include "..\Minecraft.World\net.minecraft.world.item.h"
|
||||
#include "..\Minecraft.World\Minecraft.World.h"
|
||||
#include "Windows64\Windows64_Xuid.h"
|
||||
#include "ClientConnection.h"
|
||||
#include "..\Minecraft.World\HellRandomLevelSource.h"
|
||||
#include "..\Minecraft.World\net.minecraft.world.entity.animal.h"
|
||||
@@ -1038,6 +1039,19 @@ shared_ptr<MultiplayerLocalPlayer> Minecraft::createExtraLocalPlayer(int idx, co
|
||||
PlayerUID playerXUIDOnline = INVALID_XUID;
|
||||
ProfileManager.GetXUID(idx,&playerXUIDOffline,false);
|
||||
ProfileManager.GetXUID(idx,&playerXUIDOnline,true);
|
||||
#ifdef _WINDOWS64
|
||||
// Compatibility rule for Win64 id migration
|
||||
// host keeps legacy host XUID, non-host uses persistent uid.dat XUID.
|
||||
INetworkPlayer *localNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
|
||||
if(localNetworkPlayer != NULL && localNetworkPlayer->IsHost())
|
||||
{
|
||||
playerXUIDOffline = Win64Xuid::GetLegacyEmbeddedHostXuid();
|
||||
}
|
||||
else
|
||||
{
|
||||
playerXUIDOffline = Win64Xuid::ResolvePersistentXuid();
|
||||
}
|
||||
#endif
|
||||
localplayers[idx]->setXuid(playerXUIDOffline);
|
||||
localplayers[idx]->setOnlineXuid(playerXUIDOnline);
|
||||
localplayers[idx]->setIsGuest(ProfileManager.IsGuest(idx));
|
||||
@@ -4298,6 +4312,19 @@ void Minecraft::setLevel(MultiPlayerLevel *level, int message /*=-1*/, shared_pt
|
||||
// player doesn't have an online UID, set it from the player name
|
||||
playerXUIDOnline.setForAdhoc();
|
||||
}
|
||||
#endif
|
||||
#ifdef _WINDOWS64
|
||||
// On Windows, the implementation has been changed to use a per-client pseudo XUID based on `uid.dat`.
|
||||
// To maintain player data compatibility with existing worlds, the world host (the first player) will use the previous embedded pseudo XUID.
|
||||
INetworkPlayer *localNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(iPrimaryPlayer);
|
||||
if(localNetworkPlayer != NULL && localNetworkPlayer->IsHost())
|
||||
{
|
||||
playerXUIDOffline = Win64Xuid::GetLegacyEmbeddedHostXuid();
|
||||
}
|
||||
else
|
||||
{
|
||||
playerXUIDOffline = Win64Xuid::ResolvePersistentXuid();
|
||||
}
|
||||
#endif
|
||||
player->setXuid(playerXUIDOffline);
|
||||
player->setOnlineXuid(playerXUIDOnline);
|
||||
@@ -4481,6 +4508,18 @@ void Minecraft::respawnPlayer(int iPad, int dimension, int newEntityId)
|
||||
PlayerUID playerXUIDOnline = INVALID_XUID;
|
||||
ProfileManager.GetXUID(iTempPad,&playerXUIDOffline,false);
|
||||
ProfileManager.GetXUID(iTempPad,&playerXUIDOnline,true);
|
||||
#ifdef _WINDOWS64
|
||||
// Same compatibility rule as create/init paths.
|
||||
INetworkPlayer *localNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(iTempPad);
|
||||
if(localNetworkPlayer != NULL && localNetworkPlayer->IsHost())
|
||||
{
|
||||
playerXUIDOffline = Win64Xuid::GetLegacyEmbeddedHostXuid();
|
||||
}
|
||||
else
|
||||
{
|
||||
playerXUIDOffline = Win64Xuid::ResolvePersistentXuid();
|
||||
}
|
||||
#endif
|
||||
player->setXuid(playerXUIDOffline);
|
||||
player->setOnlineXuid(playerXUIDOnline);
|
||||
player->setIsGuest( ProfileManager.IsGuest(iTempPad) );
|
||||
|
||||
Reference in New Issue
Block a user