Ghost/shadow player fix

When player 2 joined, player 1's connection received an AddPlayerPacket and created a RemotePlayer shadow in the world. The existing XUID deduplication check never fired on Windows64 (XUIDs are always INVALID_XUID). Added a Windows64-specific check that matches by IQNet-derived XUID (0xe000d45248242f2e + smallId), which is set up before the connection loop, making it race-free.
This commit is contained in:
Michal Schiller 2026-03-06 18:25:26 +01:00 committed by GitHub
parent e513d6b8c5
commit a2a0837fbd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -168,9 +168,9 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
PlayerUID OnlineXuid;
ProfileManager.GetXUID(m_userIndex,&OnlineXuid,true); // online xuid
MOJANG_DATA *pMojangData = NULL;
if(!g_NetworkManager.IsLocalGame())
{
{
pMojangData=app.GetMojangDataForXuid(OnlineXuid);
}
@ -222,7 +222,7 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
// check the file is not already in
bRes=app.IsFileInMemoryTextures(wstr);
if(!bRes)
{
{
#ifdef _XBOX
C4JStorage::ETMSStatus eTMSStatus;
eTMSStatus=StorageManager.ReadTMSFile(iUserID,C4JStorage::eGlobalStorage_Title,C4JStorage::eTMS_FileType_Graphic,pMojangData->wchSkin,&pBuffer, &dwSize);
@ -234,17 +234,17 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
if(bRes)
{
app.AddMemoryTextureFile(wstr,pBuffer,dwSize);
}
}
}
// a cloak?
if(pMojangData->wchCape[0]!=0L)
{
{
wstring wstr=pMojangData->wchCape;
// check the file is not already in
bRes=app.IsFileInMemoryTextures(wstr);
if(!bRes)
{
{
#ifdef _XBOX
C4JStorage::ETMSStatus eTMSStatus;
eTMSStatus=StorageManager.ReadTMSFile(iUserID,C4JStorage::eGlobalStorage_Title,C4JStorage::eTMS_FileType_Graphic,pMojangData->wchCape,&pBuffer, &dwSize);
@ -302,7 +302,7 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
app.DebugPrintf("ClientConnection - DIFFICULTY --- %d\n",packet->difficulty);
level->difficulty = packet->difficulty; // 4J Added
level->isClientSide = true;
minecraft->setLevel(level);
minecraft->setLevel(level);
}
minecraft->player->setPlayerIndex( packet->m_playerIndex );
@ -362,7 +362,7 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
// 4J Stu - At time of writing ProfileManager.GetGamertag() does not always return the correct name,
// if sign-ins are turned off while the player signed in. Using the qnetPlayer instead.
// need to have a level before create extra local player
MultiPlayerLevel *levelpassedin=(MultiPlayerLevel *)level;
MultiPlayerLevel *levelpassedin=(MultiPlayerLevel *)level;
player = minecraft->createExtraLocalPlayer(m_userIndex, networkPlayer->GetOnlineName(), m_userIndex, packet->dimension, this,levelpassedin);
// need to have a player before the setlevel
@ -384,7 +384,7 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
player->setPlayerIndex( packet->m_playerIndex );
player->setCustomSkin( app.GetPlayerSkinId(m_userIndex) );
player->setCustomCape( app.GetPlayerCapeId(m_userIndex) );
BYTE networkSmallId = getSocket()->getSmallId();
app.UpdatePlayerInfo(networkSmallId, packet->m_playerIndex, packet->m_uiGamePrivileges);
@ -396,21 +396,21 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
displayPrivilegeChanges(minecraft->localplayers[m_userIndex],startingPrivileges);
}
maxPlayers = packet->maxPlayers;
// need to have a player before the setLocalCreativeMode
shared_ptr<MultiplayerLocalPlayer> lastPlayer = minecraft->player;
minecraft->player = minecraft->localplayers[m_userIndex];
((MultiPlayerGameMode *)minecraft->localgameModes[m_userIndex])->setLocalMode(GameType::byId(packet->gameType));
minecraft->player = lastPlayer;
// make sure the UI offsets for this player are set correctly
if(iUserID!=-1)
{
ui.UpdateSelectedItemPos(iUserID);
}
TelemetryManager->RecordLevelStart(m_userIndex, eSen_FriendOrMatch_Playing_With_Invited_Friends, eSen_CompeteOrCoop_Coop_and_Competitive, Minecraft::GetInstance()->getLevel(packet->dimension)->difficulty, app.GetLocalPlayerCount(), g_NetworkManager.GetOnlinePlayerCount());
}
@ -448,7 +448,7 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
}
}
}
if (owner != NULL && owner->instanceof(eTYPE_PLAYER))
{
shared_ptr<Player> player = dynamic_pointer_cast<Player>(owner);
@ -574,7 +574,7 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
}
packet->data = 0;
}
if (packet->type == AddEntityPacket::ARROW) e = shared_ptr<Entity>( new Arrow(level, x, y, z) );
if (packet->type == AddEntityPacket::SNOWBALL) e = shared_ptr<Entity>( new Snowball(level, x, y, z) );
if (packet->type == AddEntityPacket::THROWN_ENDERPEARL) e = shared_ptr<Entity>( new ThrownEnderpearl(level, x, y, z) );
@ -620,19 +620,22 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
e->yRotp = packet->yRot;
e->xRotp = packet->xRot;
if (setRot)
if (setRot)
{
e->yRot = 0.0f;
e->xRot = 0.0f;
}
vector<shared_ptr<Entity> > *subEntities = e->getSubEntities();
if (subEntities)
if (subEntities != NULL)
{
int offs = packet->id - e->entityId;
for ( auto it : *subEntities )
{
it->entityId += offs;
//for (int i = 0; i < subEntities.length; i++)
for(AUTO_VAR(it, subEntities->begin()); it != subEntities->end(); ++it)
{
(*it)->entityId += offs;
//subEntities[i].entityId += offs;
//System.out.println(subEntities[i].entityId);
}
}
@ -682,10 +685,10 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
}
}
e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0);
e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0);
}
// 4J: Check our deferred entity link packets
// 4J: Check our deferred entity link packets
checkDeferredEntityLinkPackets(e->entityId);
}
}
@ -760,32 +763,28 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
}
}
#ifdef _WINDOWS64
// Win64 keeps local-player identity separate from network smallId; 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)
// On Windows64 ProfileManager.GetXUID always returns INVALID_XUID so the check above
// never fires. Instead compare packet->xuid against the IQNetPlayer-derived XUID for
// every locally-registered controller slot. This check is race-free: the IQNet slot is
// populated by AddLocalPlayerByUserIndex *before* the connection loop starts, so
// GetLocalPlayerByUserIndex is valid long before handleAddPlayer runs.
{
if (minecraft->localplayers[idx] != NULL && minecraft->localplayers[idx]->name == packet->name)
const PlayerUID WIN64_XUID_BASE = (PlayerUID)0xe000d45248242f2e;
for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
{
app.DebugPrintf("AddPlayerPacket received for local player name %ls\n", packet->name.c_str());
return;
INetworkPlayer *localNetPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx);
if(localNetPlayer != NULL)
{
PlayerUID localXuid = WIN64_XUID_BASE + localNetPlayer->GetSmallId();
if(localXuid == packet->xuid)
{
app.DebugPrintf("AddPlayerPacket received for local controller %d (xuid match), skipping RemotePlayer creation\n", idx);
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),
// NOT the controller slot — so we must scan all local player slots and match by
// their stored server index rather than using it directly as an array subscript.
for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx)
{
if(minecraft->localplayers[idx] != NULL &&
minecraft->localplayers[idx]->getPlayerIndex() == packet->m_playerIndex)
{
app.DebugPrintf("AddPlayerPacket received for local player (controller %d, server index %d), skipping RemotePlayer creation\n", idx, packet->m_playerIndex);
return;
}
}
#endif*/
double x = packet->x / 32.0;
double y = packet->y / 32.0;
@ -812,50 +811,22 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
#ifdef _WINDOWS64
{
IQNetPlayer* matchedQNetPlayer = NULL;
PlayerUID pktXuid = player->getXuid();
const PlayerUID WIN64_XUID_BASE = (PlayerUID)0xe000d45248242f2e;
// Legacy compatibility path for peers still using embedded smallId XUIDs.
if (pktXuid >= WIN64_XUID_BASE && pktXuid < WIN64_XUID_BASE + MINECRAFT_NET_MAX_PLAYERS)
{
BYTE smallId = (BYTE)(pktXuid - WIN64_XUID_BASE);
INetworkPlayer* np = g_NetworkManager.GetPlayerBySmallId(smallId);
if (np != NULL)
{
NetworkPlayerXbox* npx = (NetworkPlayerXbox*)np;
matchedQNetPlayer = npx->GetQNetPlayer();
}
}
// Current Win64 path: identify QNet player by name and attach packet XUID.
if (matchedQNetPlayer == NULL)
{
for (BYTE smallId = 0; smallId < MINECRAFT_NET_MAX_PLAYERS; ++smallId)
{
INetworkPlayer* np = g_NetworkManager.GetPlayerBySmallId(smallId);
if (np == NULL)
continue;
NetworkPlayerXbox* npx = (NetworkPlayerXbox*)np;
IQNetPlayer* qp = npx->GetQNetPlayer();
if (qp != NULL && _wcsicmp(qp->m_gamertag, packet->name.c_str()) == 0)
if (qp != NULL && qp->m_gamertag[0] == 0)
{
matchedQNetPlayer = qp;
break;
wcsncpy_s(qp->m_gamertag, 32, packet->name.c_str(), _TRUNCATE);
}
}
}
if (matchedQNetPlayer != NULL)
{
// Store packet-authoritative XUID on this network slot so later lookups by XUID
// (e.g. remove player, display mapping) work for both legacy and uid.dat clients.
matchedQNetPlayer->m_resolvedXuid = pktXuid;
if (matchedQNetPlayer->m_gamertag[0] == 0)
{
wcsncpy_s(matchedQNetPlayer->m_gamertag, 32, packet->name.c_str(), _TRUNCATE);
}
}
}
#endif
@ -876,7 +847,7 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
player->setCustomSkin( packet->m_skinId );
player->setCustomCape( packet->m_capeId );
player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges);
if(!player->customTextureUrl.empty() && player->customTextureUrl.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(player->customTextureUrl))
{
if( minecraft->addPendingClientTextureRequest(player->customTextureUrl) )
@ -893,7 +864,7 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
}
app.DebugPrintf("Custom skin for player %ls is %ls\n",player->name.c_str(),player->customTextureUrl.c_str());
if(!player->customTextureUrl2.empty() && player->customTextureUrl2.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(player->customTextureUrl2))
{
if( minecraft->addPendingClientTextureRequest(player->customTextureUrl2) )
@ -1025,8 +996,6 @@ void ClientConnection::handleRemoveEntity(shared_ptr<RemoveEntitiesPacket> packe
qp->m_smallId = 0;
qp->m_isRemote = false;
qp->m_isHostPlayer = false;
// Clear resolved id to avoid stale XUID -> player matches after disconnect.
qp->m_resolvedXuid = INVALID_XUID;
qp->m_gamertag[0] = 0;
qp->SetCustomDataValue(0);
}
@ -1073,7 +1042,7 @@ void ClientConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet)
packet->yView = player->y;
connection->send(packet);
if (!started)
{
{
if(!g_NetworkManager.IsHost() )
{
@ -1089,7 +1058,7 @@ void ClientConnection::handleMovePlayer(shared_ptr<MovePlayerPacket> packet)
started = true;
minecraft->setScreen(NULL);
// Fix for #105852 - TU12: Content: Gameplay: Local splitscreen Players are spawned at incorrect places after re-joining previously saved and loaded "Mass Effect World".
// Move this check from Minecraft::createExtraLocalPlayer
// 4J-PB - can't call this when this function is called from the qnet thread (GetGameStarted will be false)
@ -1163,7 +1132,7 @@ void ClientConnection::handleChunkTilesUpdate(shared_ptr<ChunkTilesUpdatePacket>
// Don't bother setting this to dirty if it isn't going to visually change - we get a lot of
// water changing from static to dynamic for instance
if(!( ( ( prevTile == Tile::water_Id ) && ( tile == Tile::calmWater_Id ) ) ||
( ( prevTile == Tile::calmWater_Id ) && ( tile == Tile::water_Id ) ) ||
( ( prevTile == Tile::calmWater_Id ) && ( tile == Tile::water_Id ) ) ||
( ( prevTile == Tile::lava_Id ) && ( tile == Tile::calmLava_Id ) ) ||
( ( prevTile == Tile::calmLava_Id ) && ( tile == Tile::calmLava_Id ) ) ||
( ( prevTile == Tile::calmLava_Id ) && ( tile == Tile::lava_Id ) ) ) )
@ -1292,7 +1261,7 @@ void ClientConnection::handleDisconnect(shared_ptr<DisconnectPacket> packet)
{
connection->close(DisconnectPacket::eDisconnect_Kicked);
done = true;
Minecraft *pMinecraft = Minecraft::GetInstance();
pMinecraft->connectionDisconnected( m_userIndex , packet->reason );
app.SetDisconnectReason( packet->reason );
@ -1376,7 +1345,7 @@ void ClientConnection::handleTakeItemEntity(shared_ptr<TakeItemEntityPacket> pac
if (from != NULL)
{
// If this is a local player, then we only want to do processing for it if this connection is associated with the player it is for. In
// If this is a local player, then we only want to do processing for it if this connection is associated with the player it is for. In
// particular, we don't want to remove the item entity until we are processing it for the right connection, or else we won't have a valid
// "from" reference if we've already removed the item for an earlier processed connection
if( isLocalPlayer )
@ -1441,9 +1410,6 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
switch(packet->m_messageType)
{
case ChatPacket::e_ChatCustom:
message = (packet->m_stringArgs.size() >= 1) ? packet->m_stringArgs[0] : L"";
break;
case ChatPacket::e_ChatBedOccupied:
message = app.GetString(IDS_TILE_BED_OCCUPIED);
break;
@ -1464,7 +1430,7 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
case ChatPacket::e_ChatBedMeSleep:
message=app.GetString(IDS_TILE_BED_MESLEEP);
break;
case ChatPacket::e_ChatPlayerJoinedGame:
case ChatPacket::e_ChatPlayerJoinedGame:
message=app.GetString(IDS_PLAYER_JOINED);
iPos=message.find(L"%s");
message.replace(iPos,2,playerDisplayName);
@ -1579,7 +1545,7 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
replaceEntitySource = true;
break;
case ChatPacket::e_ChatDeathFellAccidentLadder:
message=app.GetString(IDS_DEATH_FELL_ACCIDENT_LADDER);
replacePlayer = true;
@ -1744,7 +1710,7 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
message=app.GetString(IDS_MAX_WOLVES_BRED);
break;
// can't shear the mooshroom
// can't shear the mooshroom
case ChatPacket::e_ChatPlayerCantShearMooshroom:
message=app.GetString(IDS_CANT_SHEAR_MOOSHROOM);
break;
@ -1752,16 +1718,16 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
// Paintings/Item Frames
case ChatPacket::e_ChatPlayerMaxHangingEntities:
message=app.GetString(IDS_MAX_HANGINGENTITIES);
break;
break;
// Enemy spawn eggs in peaceful
case ChatPacket::e_ChatPlayerCantSpawnInPeaceful:
message=app.GetString(IDS_CANT_SPAWN_IN_PEACEFUL);
break;
break;
// Enemy spawn eggs in peaceful
case ChatPacket::e_ChatPlayerMaxBoats:
message=app.GetString(IDS_MAX_BOATS);
break;
break;
case ChatPacket::e_ChatCommandTeleportSuccess:
message=app.GetString(IDS_COMMAND_TELEPORT_SUCCESS);
@ -1893,7 +1859,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
BOOL isAtLeastOneFriend = g_NetworkManager.IsHost();
BOOL isFriendsWithHost = TRUE;
BOOL cantPlayContentRestricted = FALSE;
if(!g_NetworkManager.IsHost())
{
// set the game host settings
@ -1927,7 +1893,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
}
if( playerXuid != INVALID_XUID )
{
// Is this user friends with the host player?
// Is this user friends with the host player?
BOOL result;
DWORD error;
error = XUserAreUsersFriends(idx,&packet->m_playerXuids[packet->m_hostIndex],1,&result,NULL);
@ -1957,7 +1923,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
}
if( playerXuid != INVALID_XUID )
{
// Is this user friends with the host player?
// Is this user friends with the host player?
BOOL result;
DWORD error;
error = XUserAreUsersFriends(m_userIndex,&packet->m_playerXuids[packet->m_hostIndex],1,&result,NULL);
@ -2072,7 +2038,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
if(m_userIndex == ProfileManager.GetPrimaryPad() )
{
// Is this user friends with the host player?
// Is this user friends with the host player?
bool isFriend = true;
unsigned int friendCount = 0;
#ifdef __PS3__
@ -2102,7 +2068,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
requestParam.offset = 0;
requestParam.userInfo.userId = ProfileManager.getUserID(ProfileManager.GetPrimaryPad());
int ret = sce::Toolkit::NP::Friends::Interface::getFriendslist(&friendList, &requestParam, false);
int ret = sce::Toolkit::NP::Friends::Interface::getFriendslist(&friendList, &requestParam, false);
if( ret == 0 )
{
if( friendList.hasResult() )
@ -2112,7 +2078,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
}
#endif
if( ret == 0 )
{
{
isFriend = false;
SceNpId npid;
for( unsigned int i = 0; i < friendCount; i++ )
@ -2195,7 +2161,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
isAtLeastOneFriend = true;
break;
}
}
}
}
app.DebugPrintf("ClientConnection::handlePreLogin: User has at least one friend? %s\n", isAtLeastOneFriend ? "Yes" : "No");
@ -2237,8 +2203,8 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
DisconnectPacket::eDisconnectReason reason = DisconnectPacket::eDisconnect_NoUGC_Remote;
#else
DisconnectPacket::eDisconnectReason reason = DisconnectPacket::eDisconnect_None;
#endif
if(m_userIndex == ProfileManager.GetPrimaryPad())
#endif
if(m_userIndex == ProfileManager.GetPrimaryPad())
{
if(!isFriendsWithHost) reason = DisconnectPacket::eDisconnect_NotFriendsWithHost;
else if(!isAtLeastOneFriend) reason = DisconnectPacket::eDisconnect_NoFriendsInGame;
@ -2250,7 +2216,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_ExitWorld,(void *)TRUE);
}
else
{
{
if(!isFriendsWithHost) reason = DisconnectPacket::eDisconnect_NotFriendsWithHost;
else if(!canPlayLocal) reason = DisconnectPacket::eDisconnect_NoUGC_Single_Local;
else if(cantPlayContentRestricted) reason = DisconnectPacket::eDisconnect_ContentRestricted_Single_Local;
@ -2263,7 +2229,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
app.SetDisconnectReason( reason );
// 4J-PB - this locks up on the read and write threads not closing down, because they are trying to lock the incoming critsec when it's already locked by this thread
// 4J-PB - this locks up on the read and write threads not closing down, because they are trying to lock the incoming critsec when it's already locked by this thread
// Minecraft::GetInstance()->connectionDisconnected( m_userIndex , reason );
// done = true;
// connection->flush();
@ -2320,7 +2286,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
#endif
// On PS3, all non-signed in players (even guests) can get a useful offlineXUID
#if !(defined __PS3__ || defined _DURANGO )
#if !(defined __PS3__ || defined _DURANGO )
if( !ProfileManager.IsGuest( m_userIndex ) )
#endif
{
@ -2329,7 +2295,7 @@ void ClientConnection::handlePreLogin(shared_ptr<PreLoginPacket> packet)
}
BOOL allAllowed, friendsAllowed;
ProfileManager.AllowedPlayerCreatedContent(m_userIndex,true,&allAllowed,&friendsAllowed);
send( shared_ptr<LoginPacket>( new LoginPacket(minecraft->user->name, SharedConstants::NETWORK_PROTOCOL_VERSION, offlineXUID, onlineXUID, (allAllowed!=TRUE && friendsAllowed==TRUE),
send( shared_ptr<LoginPacket>( new LoginPacket(minecraft->user->name, SharedConstants::NETWORK_PROTOCOL_VERSION, offlineXUID, onlineXUID, (allAllowed!=TRUE && friendsAllowed==TRUE),
packet->m_ugcPlayersVersion, app.GetPlayerSkinId(m_userIndex), app.GetPlayerCapeId(m_userIndex), ProfileManager.IsGuest( m_userIndex ))));
if(!g_NetworkManager.IsHost() )
@ -2387,12 +2353,14 @@ void ClientConnection::handleAddMob(shared_ptr<AddMobPacket> packet)
mob->xRotp = packet->xRot;
vector<shared_ptr<Entity> > *subEntities = mob->getSubEntities();
if (subEntities)
if (subEntities != NULL)
{
int offs = packet->id - mob->entityId;
for (auto& it : *subEntities )
{
it->entityId += offs;
//for (int i = 0; i < subEntities.length; i++)
for(AUTO_VAR(it, subEntities->begin()); it != subEntities->end(); ++it)
{
//subEntities[i].entityId += offs;
(*it)->entityId += offs;
}
}
@ -2478,7 +2446,7 @@ void ClientConnection::handleEntityLinkPacket(shared_ptr<SetEntityLinkPacket> pa
minecraft.gui.setOverlayMessage(I18n.get("mount.onboard", Options.getTranslatedKeyMessage(options.keySneak.key)), false);
}
*/
}
}
else if (packet->type == SetEntityLinkPacket::LEASH)
{
if ( (sourceEntity != NULL) && sourceEntity->instanceof(eTYPE_MOB) )
@ -2548,7 +2516,7 @@ void ClientConnection::handleTexture(shared_ptr<TexturePacket> packet)
wprintf(L"Client received request for custom texture %ls\n",packet->textureName.c_str());
#endif
PBYTE pbData=NULL;
DWORD dwBytes=0;
DWORD dwBytes=0;
app.GetMemFileDetails(packet->textureName,&pbData,&dwBytes);
if(dwBytes!=0)
@ -2580,7 +2548,7 @@ void ClientConnection::handleTextureAndGeometry(shared_ptr<TextureAndGeometryPac
wprintf(L"Client received request for custom texture and geometry %ls\n",packet->textureName.c_str());
#endif
PBYTE pbData=NULL;
DWORD dwBytes=0;
DWORD dwBytes=0;
app.GetMemFileDetails(packet->textureName,&pbData,&dwBytes);
DLCSkinFile *pDLCSkinFile = app.m_dlcManager.getSkinFile(packet->textureName);
@ -2614,9 +2582,9 @@ void ClientConnection::handleTextureAndGeometry(shared_ptr<TextureAndGeometryPac
// Add the texture data
app.AddMemoryTextureFile(packet->textureName,packet->pbData,packet->dwTextureBytes);
// Add the geometry data
if(packet->dwBoxC!=0)
if(packet->dwBoxC!=0)
{
app.SetAdditionalSkinBoxes(packet->dwSkinID,packet->BoxDataA,packet->dwBoxC);
app.SetAdditionalSkinBoxes(packet->dwSkinID,packet->BoxDataA,packet->dwBoxC);
}
// Add the anim override
app.SetAnimOverrideBitmask(packet->dwSkinID,packet->uiAnimOverrideBitmask);
@ -2662,7 +2630,7 @@ void ClientConnection::handleTextureChange(shared_ptr<TextureChangePacket> packe
#endif
break;
}
if(!packet->path.empty() && packet->path.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(packet->path))
{
if( minecraft->addPendingClientTextureRequest(packet->path) )
@ -2734,10 +2702,6 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
int oldDimension = minecraft->localplayers[m_userIndex]->dimension;
started = false;
// Stop any streaming music (e.g. jukebox) when changing dimensions
// so it doesn't leak into the new dimension
level->playStreamingMusic(L"", 0, 0, 0);
// Remove client connection from this level
level->removeClientConnection(this, false);
@ -2768,7 +2732,7 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
level->removeEntity( shared_ptr<Entity>(minecraft->localplayers[m_userIndex]) );
level = dimensionLevel;
// Whilst calling setLevel, make sure that minecraft::player is set up to be correct for this
// connection
shared_ptr<MultiplayerLocalPlayer> lastPlayer = minecraft->player;
@ -2777,7 +2741,7 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
minecraft->player = lastPlayer;
TelemetryManager->RecordLevelExit(m_userIndex, eSen_LevelExitStatus_Succeeded);
//minecraft->player->dimension = packet->dimension;
minecraft->localplayers[m_userIndex]->dimension = packet->dimension;
//minecraft->setScreen(new ReceivingLevelScreen(this));
@ -2828,12 +2792,12 @@ void ClientConnection::handleRespawn(shared_ptr<RespawnPacket> packet)
{
ui.NavigateToScene(m_userIndex, eUIScene_ConnectingProgress, param);
}
app.SetAction( m_userIndex, eAppAction_WaitForDimensionChangeComplete);
}
//minecraft->respawnPlayer(minecraft->player->GetXboxPad(),true, packet->dimension);
// Wrap respawnPlayer call up in code to set & restore the player/gamemode etc. as some things
// in there assume that we are set up for the player that the respawn is coming in for
int oldIndex = minecraft->getLocalPlayerIdx();
@ -2858,7 +2822,7 @@ void ClientConnection::handleExplosion(shared_ptr<ExplodePacket> packet)
MultiPlayerLevel *mpLevel = (MultiPlayerLevel *)minecraft->level;
mpLevel->enableResetChanges(false);
// 4J - now directly pass a pointer to the toBlow array in the packet rather than copying around
e->finalizeExplosion(true, &packet->toBlow);
e->finalizeExplosion(true, &packet->toBlow);
mpLevel->enableResetChanges(true);
PIXEndNamedEvent();
PIXEndNamedEvent();
@ -2904,7 +2868,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -2918,7 +2882,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -2932,7 +2896,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -2947,7 +2911,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -2962,7 +2926,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -2977,7 +2941,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -2989,7 +2953,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -3001,7 +2965,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -3015,7 +2979,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -3030,7 +2994,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -3042,7 +3006,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -3065,7 +3029,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -3077,7 +3041,7 @@ void ClientConnection::handleContainerOpen(shared_ptr<ContainerOpenPacket> packe
}
else
{
failed = true;
failed = true;
}
}
break;
@ -3155,7 +3119,7 @@ void ClientConnection::handleContainerAck(shared_ptr<ContainerAckPacket> packet)
void ClientConnection::handleContainerContent(shared_ptr<ContainerSetContentPacket> packet)
{
shared_ptr<MultiplayerLocalPlayer> player = minecraft->localplayers[m_userIndex];
if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_INVENTORY)
if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_INVENTORY)
{
player->inventoryMenu->setAll(&packet->items);
}
@ -3235,7 +3199,7 @@ void ClientConnection::handleTileEntityData(shared_ptr<TileEntityDataPacket> pac
else if (packet->type == TileEntityDataPacket::TYPE_BEACON && dynamic_pointer_cast<BeaconTileEntity>(te) != NULL)
{
dynamic_pointer_cast<BeaconTileEntity>(te)->load(packet->tag);
}
}
else if (packet->type == TileEntityDataPacket::TYPE_SKULL && dynamic_pointer_cast<SkullTileEntity>(te) != NULL)
{
dynamic_pointer_cast<SkullTileEntity>(te)->load(packet->tag);
@ -3313,7 +3277,7 @@ void ClientConnection::handleGameEvent(shared_ptr<GameEventPacket> gameEventPack
else if (event == GameEventPacket::WIN_GAME)
{
ui.SetWinUserIndex( (BYTE)gameEventPacket->param );
#ifdef _XBOX
// turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen
@ -3553,7 +3517,7 @@ void ClientConnection::displayPrivilegeChanges(shared_ptr<MultiplayerLocalPlayer
case Player::ePlayerGamePrivilege_Invulnerable:
if(privOn) message = app.GetString(IDS_PRIV_INVULNERABLE_TOGGLE_ON);
else message = app.GetString(IDS_PRIV_INVULNERABLE_TOGGLE_OFF);
break;
break;
case Player::ePlayerGamePrivilege_CanToggleInvisible:
if(privOn) message = app.GetString(IDS_PRIV_CAN_INVISIBLE_TOGGLE_ON);
else message = app.GetString(IDS_PRIV_CAN_INVISIBLE_TOGGLE_OFF);
@ -3627,7 +3591,7 @@ void ClientConnection::handleCustomPayload(shared_ptr<CustomPayloadPacket> custo
UIScene_TradingMenu *screen = (UIScene_TradingMenu *)scene;
trader = screen->getMerchant();
#endif
MerchantRecipeList *recipeList = MerchantRecipeList::createFromStream(&input);
trader->overrideOffers(recipeList);
}
@ -3714,7 +3678,7 @@ int ClientConnection::HostDisconnectReturned(void *pParam,int iPad,C4JStorage::E
DLCPack *pDLCPack=pDLCTexPack->getDLCInfoParentPack();//tPack->getDLCPack();
if(!pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" ))
{
{
// no upsell, we're about to quit
MinecraftServer::getInstance()->setSaveOnExit( false );
// flag a app action of exit game
@ -3768,7 +3732,7 @@ int ClientConnection::HostDisconnectReturned(void *pParam,int iPad,C4JStorage::E
int ClientConnection::ExitGameAndSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result)
{
// results switched for this dialog
if(result==C4JStorage::EMessage_ResultDecline)
if(result==C4JStorage::EMessage_ResultDecline)
{
//INT saveOrCheckpointId = 0;
//bool validSave = StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId);
@ -3787,7 +3751,7 @@ int ClientConnection::ExitGameAndSaveReturned(void *pParam,int iPad,C4JStorage::
return 0;
}
//
//
wstring ClientConnection::GetDisplayNameByGamertag(wstring gamertag)
{
#ifdef _DURANGO
@ -3932,31 +3896,31 @@ void ClientConnection::handleUpdateAttributes(shared_ptr<UpdateAttributesPacket>
if ( !entity->instanceof(eTYPE_LIVINGENTITY) )
{
// Entity is not a living entity!
assert(0);
assert(0);
}
BaseAttributeMap *attributes = (dynamic_pointer_cast<LivingEntity>(entity))->getAttributes();
unordered_set<UpdateAttributesPacket::AttributeSnapshot *> attributeSnapshots = packet->getValues();
for ( UpdateAttributesPacket::AttributeSnapshot *attribute : attributeSnapshots )
unordered_set<UpdateAttributesPacket::AttributeSnapshot *> attributeSnapshots = packet->getValues();
for (AUTO_VAR(it,attributeSnapshots.begin()); it != attributeSnapshots.end(); ++it)
{
UpdateAttributesPacket::AttributeSnapshot *attribute = *it;
AttributeInstance *instance = attributes->getInstance(attribute->getId());
if (instance)
if (instance == NULL)
{
// 4J - TODO: revisit, not familiar with the attribute system, why are we passing in MIN_NORMAL (Java's smallest non-zero value conforming to IEEE Standard 754 (?)) and MAX_VALUE
instance = attributes->registerAttribute(new RangedAttribute(attribute->getId(), 0, Double::MIN_NORMAL, Double::MAX_VALUE));
instance->setBaseValue(attribute->getBase());
instance->removeModifiers();
unordered_set<AttributeModifier *> *modifiers = attribute->getModifiers();
}
if ( modifiers )
{
for ( AttributeModifier* modifier : *modifiers )
{
instance->addModifier(new AttributeModifier(modifier->getId(), modifier->getAmount(), modifier->getOperation()));
}
}
instance->setBaseValue(attribute->getBase());
instance->removeModifiers();
unordered_set<AttributeModifier *> *modifiers = attribute->getModifiers();
for (AUTO_VAR(it2,modifiers->begin()); it2 != modifiers->end(); ++it2)
{
AttributeModifier* modifier = *it2;
instance->addModifier(new AttributeModifier(modifier->getId(), modifier->getAmount(), modifier->getOperation() ) );
}
}
}