Refactor GetXuid and HostGame methods

IQNet::AddLocalPlayerByUserIndex was a no-op
The stub did nothing, so GetLocalPlayerByUserIndex returned NULL for controller 2, and NotifyPlayerJoined(NULL) crashed with an access violation at offset 0x48. Now it properly initialises the player slot.
This commit is contained in:
Michal Schiller 2026-03-06 18:23:44 +01:00 committed by GitHub
parent 7d96b6de4e
commit fbba14eda5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -21,7 +21,6 @@
#include "Windows64\Social\SocialManager.h"
#include "Windows64\Sentient\DynamicConfigurations.h"
#include "Windows64\Network\WinsockNetLayer.h"
#include "Windows64\Windows64_Xuid.h"
#elif defined __PSVITA__
#include "PSVita\Sentient\SentientManager.h"
#include "StatsCounter.h"
@ -201,15 +200,7 @@ DWORD IQNetPlayer::GetCurrentRtt() { return 0; }
bool IQNetPlayer::IsHost() { return m_isHostPlayer; }
bool IQNetPlayer::IsGuest() { return false; }
bool IQNetPlayer::IsLocal() { return !m_isRemote; }
PlayerUID IQNetPlayer::GetXuid()
{
// Compatibility model:
// - Preferred path: use per-player resolved XUID populated from login/add-player flow.
// - Fallback path: keep legacy base+smallId behavior for peers/saves still on old scheme.
if (m_resolvedXuid != INVALID_XUID)
return m_resolvedXuid;
return (PlayerUID)(0xe000d45248242f2e + m_smallId);
}
PlayerUID IQNetPlayer::GetXuid() { return (PlayerUID)(0xe000d45248242f2e + m_smallId); } // todo: restore to INVALID_XUID once saves support this
LPCWSTR IQNetPlayer::GetGamertag() { return m_gamertag; }
int IQNetPlayer::GetSessionIndex() { return m_smallId; }
bool IQNetPlayer::IsTalking() { return false; }
@ -235,7 +226,6 @@ void Win64_SetupRemoteQNetPlayer(IQNetPlayer * player, BYTE smallId, bool isHost
player->m_smallId = smallId;
player->m_isRemote = !isLocal;
player->m_isHostPlayer = isHost;
player->m_resolvedXuid = INVALID_XUID;
swprintf_s(player->m_gamertag, 32, L"Player%d", smallId);
if (smallId >= IQNet::s_playerCount)
IQNet::s_playerCount = smallId + 1;
@ -243,7 +233,23 @@ void Win64_SetupRemoteQNetPlayer(IQNetPlayer * player, BYTE smallId, bool isHost
static bool Win64_IsActivePlayer(IQNetPlayer* p, DWORD index);
HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex) { return S_OK; }
HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex)
{
if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS)
{
IQNetPlayer& p = m_player[dwUserIndex];
p.m_smallId = (BYTE)dwUserIndex;
p.m_isRemote = false;
p.m_isHostPlayer = (dwUserIndex == 0);
swprintf_s(p.m_gamertag, 32, L"Player%d", (int)dwUserIndex);
// Mark the slot active so Win64_IsActivePlayer returns true for index >= 1
if (dwUserIndex >= s_playerCount)
s_playerCount = dwUserIndex + 1;
if (p.GetCustomDataValue() == 0)
p.SetCustomDataValue(1);
}
return S_OK;
}
IQNetPlayer* IQNet::GetHostPlayer() { return &m_player[0]; }
IQNetPlayer* IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
{
@ -295,13 +301,8 @@ IQNetPlayer* IQNet::GetPlayerByXuid(PlayerUID xuid)
{
for (DWORD i = 0; i < s_playerCount; i++)
{
if (!Win64_IsActivePlayer(&m_player[i], i))
continue;
if (m_player[i].GetXuid() == xuid)
return &m_player[i];
if (Win64_IsActivePlayer(&m_player[i], i) && m_player[i].GetXuid() == xuid) return &m_player[i];
}
// Keep existing stub behavior: return host slot instead of NULL on miss.
return &m_player[0];
}
DWORD IQNet::GetPlayerCount()
@ -316,13 +317,7 @@ DWORD IQNet::GetPlayerCount()
QNET_STATE IQNet::GetState() { return _iQNetStubState; }
bool IQNet::IsHost() { return s_isHosting; }
HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO * pInviteInfo) { return S_OK; }
void IQNet::HostGame()
{
_iQNetStubState = QNET_STATE_SESSION_STARTING;
s_isHosting = true;
// Host slot keeps legacy XUID so old host player data remains addressable.
m_player[0].m_resolvedXuid = Win64Xuid::GetLegacyEmbeddedHostXuid();
}
void IQNet::HostGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = true; }
void IQNet::ClientJoinGame()
{
_iQNetStubState = QNET_STATE_SESSION_STARTING;
@ -333,7 +328,6 @@ void IQNet::ClientJoinGame()
m_player[i].m_smallId = (BYTE)i;
m_player[i].m_isRemote = true;
m_player[i].m_isHostPlayer = false;
m_player[i].m_resolvedXuid = INVALID_XUID;
m_player[i].m_gamertag[0] = 0;
m_player[i].SetCustomDataValue(0);
}
@ -348,14 +342,9 @@ void IQNet::EndGame()
m_player[i].m_smallId = (BYTE)i;
m_player[i].m_isRemote = false;
m_player[i].m_isHostPlayer = false;
m_player[i].m_resolvedXuid = INVALID_XUID;
m_player[i].m_gamertag[0] = 0;
m_player[i].SetCustomDataValue(0);
}
// Restore local player 0's gamertag so re-joining works correctly
extern wchar_t g_Win64UsernameW[17];
m_player[0].m_isHostPlayer = true;
wcscpy_s(m_player[0].m_gamertag, 32, g_Win64UsernameW);
}
DWORD MinecraftDynamicConfigurations::GetTrialTime() { return DYNAMIC_CONFIG_DEFAULT_TRIAL_TIME; }
@ -598,13 +587,10 @@ void C_4JProfile::GetXUID(int iPad, PlayerUID * pXuid, bool bOnlineXuid)
*pXuid = INVALID_XUID;
return;
}
// LoginPacket reads this value as client identity:
// - host keeps legacy host XUID for world compatibility
// - non-host uses persistent uid.dat-backed XUID
if (IQNet::s_isHosting)
*pXuid = Win64Xuid::GetLegacyEmbeddedHostXuid();
*pXuid = 0xe000d45248242f2e;
else
*pXuid = Win64Xuid::ResolvePersistentXuid();
*pXuid = 0xe000d45248242f2e + WinsockNetLayer::GetLocalSmallId();
#else
* pXuid = 0xe000d45248242f2e + iPad;
#endif