Merge remote-tracking branch 'kuwacom/fix/multiplayer-player-data' into feat/multiplayer-fix

This commit is contained in:
Loki Rautio
2026-03-05 09:46:50 -06:00
5 changed files with 88 additions and 5 deletions

View File

@@ -762,6 +762,18 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
return;
}
}
#ifdef _WINDOWS64
// Win64 player-data XUIDs are resolved from player name, so also guard against creating
// a duplicate remote player for a local slot by checking the username directly.
for (unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
{
if (minecraft->localplayers[idx] != NULL && minecraft->localplayers[idx]->name == packet->name)
{
app.DebugPrintf("AddPlayerPacket received for local player name %ls\n", packet->name.c_str());
return;
}
}
#endif
/*#ifdef _WINDOWS64
// On Windows64 all XUIDs are INVALID_XUID so the XUID check above never fires.
// packet->m_playerIndex is the server-assigned sequential index (set via LoginPacket),
@@ -3961,4 +3973,4 @@ ClientConnection::DeferredEntityLinkPacket::DeferredEntityLinkPacket(shared_ptr<
{
m_recievedTick = GetTickCount();
m_packet = packet;
}
}

View File

@@ -21,6 +21,7 @@
#include "Windows64\Social\SocialManager.h"
#include "Windows64\Sentient\DynamicConfigurations.h"
#include "Windows64\Network\WinsockNetLayer.h"
#include "Windows64\Windows64_NameXuid.h"
#elif defined __PSVITA__
#include "PSVita\Sentient\SentientManager.h"
#include "StatsCounter.h"
@@ -285,7 +286,19 @@ IQNetPlayer* IQNet::GetPlayerByXuid(PlayerUID xuid)
{
for (DWORD i = 0; i < s_playerCount; i++)
{
if (Win64_IsActivePlayer(&m_player[i], i) && m_player[i].GetXuid() == xuid) return &m_player[i];
// Conventional XUID implementation except for Windows 64.
if (!Win64_IsActivePlayer(&m_player[i], i))
continue;
if (m_player[i].GetXuid() == xuid)
return &m_player[i];
// For Windows 64, NameBase XUID is used.
#ifdef _WINDOWS64
PlayerUID nameXuid = Win64NameXuid::ResolvePersistentXuidFromName(m_player[i].GetGamertag());
if (nameXuid == xuid)
return &m_player[i];
#endif
}
return &m_player[0];
}

View File

@@ -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_NameXuid.h"
#include "ClientConnection.h"
#include "..\Minecraft.World\HellRandomLevelSource.h"
#include "..\Minecraft.World\net.minecraft.world.entity.animal.h"
@@ -1038,6 +1039,9 @@ shared_ptr<MultiplayerLocalPlayer> Minecraft::createExtraLocalPlayer(int idx, co
PlayerUID playerXUIDOnline = INVALID_XUID;
ProfileManager.GetXUID(idx,&playerXUIDOffline,false);
ProfileManager.GetXUID(idx,&playerXUIDOnline,true);
#ifdef _WINDOWS64
playerXUIDOffline = Win64NameXuid::ResolvePersistentXuidFromName(localplayers[idx]->name);
#endif
localplayers[idx]->setXuid(playerXUIDOffline);
localplayers[idx]->setOnlineXuid(playerXUIDOnline);
localplayers[idx]->setIsGuest(ProfileManager.IsGuest(idx));
@@ -4295,6 +4299,9 @@ 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
playerXUIDOffline = Win64NameXuid::ResolvePersistentXuidFromName(player->name);
#endif
player->setXuid(playerXUIDOffline);
player->setOnlineXuid(playerXUIDOnline);
@@ -4478,6 +4485,9 @@ 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
playerXUIDOffline = Win64NameXuid::ResolvePersistentXuidFromName(player->name);
#endif
player->setXuid(playerXUIDOffline);
player->setOnlineXuid(playerXUIDOnline);
player->setIsGuest( ProfileManager.IsGuest(iTempPad) );

View File

@@ -16,6 +16,7 @@
#include "..\Minecraft.World\ArrayWithLength.h"
#include "..\Minecraft.World\net.minecraft.network.packet.h"
#include "..\Minecraft.World\net.minecraft.network.h"
#include "Windows64\Windows64_NameXuid.h"
#include "..\Minecraft.World\Pos.h"
#include "..\Minecraft.World\ProgressListener.h"
#include "..\Minecraft.World\HellRandomLevelSource.h"
@@ -520,12 +521,13 @@ shared_ptr<ServerPlayer> PlayerList::getPlayerForLogin(PendingConnection *pendin
player->setOnlineXuid( onlineXuid ); // 4J Added
#ifdef _WINDOWS64
{
PlayerUID persistentXuid = Win64NameXuid::ResolvePersistentXuidFromName(userName);
player->setXuid(persistentXuid);
INetworkPlayer* np = pendingConnection->connection->getSocket()->getPlayer();
if (np != NULL)
{
PlayerUID realXuid = np->GetUID();
player->setXuid(realXuid);
player->setOnlineXuid(realXuid);
player->setOnlineXuid(np->GetUID());
}
}
#endif

View File

@@ -0,0 +1,46 @@
#pragma once
#ifdef _WINDOWS64
#include <string>
namespace Win64NameXuid
{
/**
* ## Resolves a persistent 64-bit player ID from the player's username.
*
* We keep this deterministic so existing player save/map systems can key off XUID.
*
* @param playerName The player's username.
* @return The resolved PlayerUID.
*/
inline PlayerUID ResolvePersistentXuidFromName(const std::wstring &playerName)
{
const unsigned __int64 fnvOffset = 14695981039346656037ULL;
const unsigned __int64 fnvPrime = 1099511628211ULL;
unsigned __int64 hash = fnvOffset;
for (size_t i = 0; i < playerName.length(); ++i)
{
unsigned short codeUnit = (unsigned short)playerName[i];
hash ^= (unsigned __int64)(codeUnit & 0xFF);
hash *= fnvPrime;
hash ^= (unsigned __int64)((codeUnit >> 8) & 0xFF);
hash *= fnvPrime;
}
// Namespace the hash away from legacy smallId-based values.
hash ^= 0x9E3779B97F4A7C15ULL;
hash |= 0x8000000000000000ULL;
if (hash == (unsigned __int64)INVALID_XUID)
{
hash ^= 0x0100000000000001ULL;
}
return (PlayerUID)hash;
}
}
#endif