mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
Merge 898d4352a3 into 09df8928ee
This commit is contained in:
commit
5b266d4b4e
|
|
@ -66,6 +66,30 @@
|
||||||
#include "../Minecraft.World/GenericStats.h"
|
#include "../Minecraft.World/GenericStats.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
char mapIconToFrame(char iconSlot)
|
||||||
|
{
|
||||||
|
if (iconSlot >= 8) return iconSlot - 4;
|
||||||
|
return iconSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same hash as getRandomPlayerMapIcon in MapItemSavedData.cpp, returning
|
||||||
|
// the Iggy/SWF frame index (0-7) instead of the raw icon slot.
|
||||||
|
char computePlayerMapFrame(int entityId, int playerIndex)
|
||||||
|
{
|
||||||
|
static const char PLAYER_MAP_ICON_SLOTS[] = { 0, 1, 2, 3, 8, 9, 10, 11 };
|
||||||
|
unsigned int seed = static_cast<unsigned int>(entityId);
|
||||||
|
seed ^= static_cast<unsigned int>(playerIndex * 0x9E3779B9u);
|
||||||
|
seed ^= (seed >> 16);
|
||||||
|
seed *= 0x7FEB352Du;
|
||||||
|
seed ^= (seed >> 15);
|
||||||
|
seed *= 0x846CA68Bu;
|
||||||
|
seed ^= (seed >> 16);
|
||||||
|
return mapIconToFrame(PLAYER_MAP_ICON_SLOTS[seed % 8]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ClientConnection::ClientConnection(Minecraft *minecraft, const wstring& ip, int port)
|
ClientConnection::ClientConnection(Minecraft *minecraft, const wstring& ip, int port)
|
||||||
{
|
{
|
||||||
// 4J Stu - No longer used as we use the socket version below.
|
// 4J Stu - No longer used as we use the socket version below.
|
||||||
|
|
@ -377,6 +401,7 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
|
||||||
|
|
||||||
BYTE networkSmallId = getSocket()->getSmallId();
|
BYTE networkSmallId = getSocket()->getSmallId();
|
||||||
app.UpdatePlayerInfo(networkSmallId, packet->m_playerIndex, packet->m_uiGamePrivileges);
|
app.UpdatePlayerInfo(networkSmallId, packet->m_playerIndex, packet->m_uiGamePrivileges);
|
||||||
|
app.SetPlayerMapIcon(minecraft->player->getName().c_str(), computePlayerMapFrame(packet->clientVersion, packet->m_playerIndex));
|
||||||
minecraft->player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges);
|
minecraft->player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges);
|
||||||
|
|
||||||
// Assume all privileges are on, so that the first message we see only indicates things that have been turned off
|
// Assume all privileges are on, so that the first message we see only indicates things that have been turned off
|
||||||
|
|
@ -447,6 +472,7 @@ void ClientConnection::handleLogin(shared_ptr<LoginPacket> packet)
|
||||||
|
|
||||||
BYTE networkSmallId = getSocket()->getSmallId();
|
BYTE networkSmallId = getSocket()->getSmallId();
|
||||||
app.UpdatePlayerInfo(networkSmallId, packet->m_playerIndex, packet->m_uiGamePrivileges);
|
app.UpdatePlayerInfo(networkSmallId, packet->m_playerIndex, packet->m_uiGamePrivileges);
|
||||||
|
app.SetPlayerMapIcon(player->getName().c_str(), computePlayerMapFrame(packet->clientVersion, packet->m_playerIndex));
|
||||||
player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges);
|
player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges);
|
||||||
|
|
||||||
// Assume all privileges are on, so that the first message we see only indicates things that have been turned off
|
// Assume all privileges are on, so that the first message we see only indicates things that have been turned off
|
||||||
|
|
@ -917,6 +943,36 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Client-side registration: if we still have no IQNet entry for this remote
|
||||||
|
// player, create one so they appear in the Tab player list.
|
||||||
|
// Find the first available IQNet slot (customData == 0, skip slot 0 which
|
||||||
|
// is the host). We can't use packet->m_playerIndex directly because on
|
||||||
|
// dedicated servers the game-level player index starts at 0 for real
|
||||||
|
// players, conflicting with the IQNet host slot.
|
||||||
|
if (matchedQNetPlayer == nullptr)
|
||||||
|
{
|
||||||
|
for (int s = 1; s < MINECRAFT_NET_MAX_PLAYERS; ++s)
|
||||||
|
{
|
||||||
|
IQNetPlayer* qp = &IQNet::m_player[s];
|
||||||
|
if (qp->GetCustomDataValue() == 0 && qp->m_gamertag[0] == 0)
|
||||||
|
{
|
||||||
|
BYTE smallId = static_cast<BYTE>(s);
|
||||||
|
qp->m_smallId = smallId;
|
||||||
|
qp->m_isRemote = true;
|
||||||
|
qp->m_isHostPlayer = false;
|
||||||
|
qp->m_resolvedXuid = pktXuid;
|
||||||
|
wcsncpy_s(qp->m_gamertag, 32, packet->name.c_str(), _TRUNCATE);
|
||||||
|
if (smallId >= IQNet::s_playerCount)
|
||||||
|
IQNet::s_playerCount = smallId + 1;
|
||||||
|
|
||||||
|
extern CPlatformNetworkManagerStub* g_pPlatformNetworkManager;
|
||||||
|
g_pPlatformNetworkManager->NotifyPlayerJoined(qp);
|
||||||
|
matchedQNetPlayer = qp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (matchedQNetPlayer != nullptr)
|
if (matchedQNetPlayer != nullptr)
|
||||||
{
|
{
|
||||||
// Store packet-authoritative XUID on this network slot so later lookups by XUID
|
// Store packet-authoritative XUID on this network slot so later lookups by XUID
|
||||||
|
|
@ -946,6 +1002,7 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
|
||||||
player->setPlayerIndex( packet->m_playerIndex );
|
player->setPlayerIndex( packet->m_playerIndex );
|
||||||
player->setCustomSkin( packet->m_skinId );
|
player->setCustomSkin( packet->m_skinId );
|
||||||
player->setCustomCape( packet->m_capeId );
|
player->setCustomCape( packet->m_capeId );
|
||||||
|
app.SetPlayerMapIcon(packet->name.c_str(), computePlayerMapFrame(packet->id, packet->m_playerIndex));
|
||||||
player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges);
|
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 (!player->customTextureUrl.empty() && player->customTextureUrl.substr(0, 3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(player->customTextureUrl))
|
||||||
|
|
@ -1088,28 +1145,27 @@ void ClientConnection::handleRemoveEntity(shared_ptr<RemoveEntitiesPacket> packe
|
||||||
for (int i = 0; i < packet->ids.length; i++)
|
for (int i = 0; i < packet->ids.length; i++)
|
||||||
{
|
{
|
||||||
shared_ptr<Entity> entity = getEntity(packet->ids[i]);
|
shared_ptr<Entity> entity = getEntity(packet->ids[i]);
|
||||||
if (entity != nullptr && entity->GetType() == eTYPE_PLAYER)
|
if (entity != nullptr)
|
||||||
{
|
{
|
||||||
shared_ptr<Player> player = dynamic_pointer_cast<Player>(entity);
|
shared_ptr<Player> player = dynamic_pointer_cast<Player>(entity);
|
||||||
if (player != nullptr)
|
if (player != nullptr)
|
||||||
{
|
{
|
||||||
PlayerUID xuid = player->getXuid();
|
// Match by gamertag in the IQNet array (XUID may be 0 on dedicated servers)
|
||||||
INetworkPlayer* np = g_NetworkManager.GetPlayerByXuid(xuid);
|
for (int s = 1; s < MINECRAFT_NET_MAX_PLAYERS; ++s)
|
||||||
if (np != nullptr)
|
|
||||||
{
|
{
|
||||||
NetworkPlayerXbox* npx = (NetworkPlayerXbox*)np;
|
IQNetPlayer* qp = &IQNet::m_player[s];
|
||||||
IQNetPlayer* qp = npx->GetQNetPlayer();
|
if (qp->GetCustomDataValue() != 0 &&
|
||||||
if (qp != nullptr)
|
_wcsicmp(qp->m_gamertag, player->getName().c_str()) == 0)
|
||||||
{
|
{
|
||||||
extern CPlatformNetworkManagerStub* g_pPlatformNetworkManager;
|
extern CPlatformNetworkManagerStub* g_pPlatformNetworkManager;
|
||||||
g_pPlatformNetworkManager->NotifyPlayerLeaving(qp);
|
g_pPlatformNetworkManager->NotifyPlayerLeaving(qp);
|
||||||
qp->m_smallId = 0;
|
qp->m_smallId = 0;
|
||||||
qp->m_isRemote = false;
|
qp->m_isRemote = false;
|
||||||
qp->m_isHostPlayer = false;
|
qp->m_isHostPlayer = false;
|
||||||
// Clear resolved id to avoid stale XUID -> player matches after disconnect.
|
|
||||||
qp->m_resolvedXuid = INVALID_XUID;
|
qp->m_resolvedXuid = INVALID_XUID;
|
||||||
qp->m_gamertag[0] = 0;
|
qp->m_gamertag[0] = 0;
|
||||||
qp->SetCustomDataValue(0);
|
qp->SetCustomDataValue(0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,7 @@ CMinecraftApp::CMinecraftApp()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ZeroMemory(m_playerColours,MINECRAFT_NET_MAX_PLAYERS);
|
ZeroMemory(m_playerColours,MINECRAFT_NET_MAX_PLAYERS);
|
||||||
|
ZeroMemory(m_playerMapIcons,MINECRAFT_NET_MAX_PLAYERS);
|
||||||
|
|
||||||
m_iDLCOfferC=0;
|
m_iDLCOfferC=0;
|
||||||
m_bAllDLCContentRetrieved=true;
|
m_bAllDLCContentRetrieved=true;
|
||||||
|
|
@ -8551,6 +8552,39 @@ short CMinecraftApp::GetPlayerColour(BYTE networkSmallId)
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMinecraftApp::SetPlayerMapIcon(const wchar_t* name, char icon)
|
||||||
|
{
|
||||||
|
if (name == nullptr) return;
|
||||||
|
// Update existing entry or use first empty slot
|
||||||
|
int emptySlot = -1;
|
||||||
|
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i)
|
||||||
|
{
|
||||||
|
if (m_playerMapIcons[i].name[0] != 0 && _wcsicmp(m_playerMapIcons[i].name, name) == 0)
|
||||||
|
{
|
||||||
|
m_playerMapIcons[i].icon = icon;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (emptySlot < 0 && m_playerMapIcons[i].name[0] == 0)
|
||||||
|
emptySlot = i;
|
||||||
|
}
|
||||||
|
if (emptySlot >= 0)
|
||||||
|
{
|
||||||
|
wcsncpy_s(m_playerMapIcons[emptySlot].name, 32, name, _TRUNCATE);
|
||||||
|
m_playerMapIcons[emptySlot].icon = icon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char CMinecraftApp::GetPlayerMapIconByName(const wchar_t* name)
|
||||||
|
{
|
||||||
|
if (name == nullptr) return 0;
|
||||||
|
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i)
|
||||||
|
{
|
||||||
|
if (m_playerMapIcons[i].name[0] != 0 && _wcsicmp(m_playerMapIcons[i].name, name) == 0)
|
||||||
|
return m_playerMapIcons[i].icon;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int CMinecraftApp::GetPlayerPrivileges(BYTE networkSmallId)
|
unsigned int CMinecraftApp::GetPlayerPrivileges(BYTE networkSmallId)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -749,10 +749,14 @@ public:
|
||||||
private:
|
private:
|
||||||
BYTE m_playerColours[MINECRAFT_NET_MAX_PLAYERS]; // An array of QNet small-id's
|
BYTE m_playerColours[MINECRAFT_NET_MAX_PLAYERS]; // An array of QNet small-id's
|
||||||
unsigned int m_playerGamePrivileges[MINECRAFT_NET_MAX_PLAYERS];
|
unsigned int m_playerGamePrivileges[MINECRAFT_NET_MAX_PLAYERS];
|
||||||
|
struct PlayerMapIconEntry { wchar_t name[32]; char icon; };
|
||||||
|
PlayerMapIconEntry m_playerMapIcons[MINECRAFT_NET_MAX_PLAYERS];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void UpdatePlayerInfo(BYTE networkSmallId, SHORT playerColourIndex, unsigned int playerGamePrivileges);
|
void UpdatePlayerInfo(BYTE networkSmallId, SHORT playerColourIndex, unsigned int playerGamePrivileges);
|
||||||
short GetPlayerColour(BYTE networkSmallId);
|
short GetPlayerColour(BYTE networkSmallId);
|
||||||
|
void SetPlayerMapIcon(const wchar_t* name, char icon);
|
||||||
|
char GetPlayerMapIconByName(const wchar_t* name);
|
||||||
unsigned int GetPlayerPrivileges(BYTE networkSmallId);
|
unsigned int GetPlayerPrivileges(BYTE networkSmallId);
|
||||||
|
|
||||||
wstring getEntityName(eINSTANCEOF type);
|
wstring getEntityName(eINSTANCEOF type);
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,13 @@ UIScene_InGameInfoMenu::UIScene_InGameInfoMenu(int iPad, void *initData, UILayer
|
||||||
{
|
{
|
||||||
PlayerInfo *info = BuildPlayerInfo(player);
|
PlayerInfo *info = BuildPlayerInfo(player);
|
||||||
|
|
||||||
|
// Skip the dedicated server's phantom host entry (slot 0, empty name)
|
||||||
|
if (info->m_smallId == 0 && info->m_name.empty())
|
||||||
|
{
|
||||||
|
delete info;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
m_players.push_back(info);
|
m_players.push_back(info);
|
||||||
m_playerList.addItem(info->m_name, info->m_colorState, info->m_voiceStatus);
|
m_playerList.addItem(info->m_name, info->m_colorState, info->m_voiceStatus);
|
||||||
}
|
}
|
||||||
|
|
@ -174,6 +181,13 @@ void UIScene_InGameInfoMenu::handleReload()
|
||||||
{
|
{
|
||||||
PlayerInfo *info = BuildPlayerInfo(player);
|
PlayerInfo *info = BuildPlayerInfo(player);
|
||||||
|
|
||||||
|
// Skip the dedicated server's phantom host entry (slot 0, empty name)
|
||||||
|
if (info->m_smallId == 0 && info->m_name.empty())
|
||||||
|
{
|
||||||
|
delete info;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
m_players.push_back(info);
|
m_players.push_back(info);
|
||||||
m_playerList.addItem(info->m_name, info->m_colorState, info->m_voiceStatus);
|
m_playerList.addItem(info->m_name, info->m_colorState, info->m_voiceStatus);
|
||||||
}
|
}
|
||||||
|
|
@ -202,17 +216,16 @@ void UIScene_InGameInfoMenu::tick()
|
||||||
{
|
{
|
||||||
UIScene::tick();
|
UIScene::tick();
|
||||||
|
|
||||||
// Update players by index
|
// Update players by their stored smallId (not sequential index, which can mismatch
|
||||||
|
// when entries like the dedicated server host are filtered from the UI list)
|
||||||
for(DWORD i = 0; i < m_players.size(); ++i)
|
for(DWORD i = 0; i < m_players.size(); ++i)
|
||||||
{
|
{
|
||||||
INetworkPlayer *player = g_NetworkManager.GetPlayerByIndex( i );
|
INetworkPlayer *player = g_NetworkManager.GetPlayerBySmallId( m_players[i]->m_smallId );
|
||||||
|
|
||||||
if(player != nullptr)
|
if(player != nullptr)
|
||||||
{
|
{
|
||||||
PlayerInfo *info = BuildPlayerInfo(player);
|
PlayerInfo *info = BuildPlayerInfo(player);
|
||||||
|
|
||||||
m_players[i]->m_smallId = info->m_smallId;
|
|
||||||
|
|
||||||
if(info->m_voiceStatus != m_players[i]->m_voiceStatus)
|
if(info->m_voiceStatus != m_players[i]->m_voiceStatus)
|
||||||
{
|
{
|
||||||
m_players[i]->m_voiceStatus = info->m_voiceStatus;
|
m_players[i]->m_voiceStatus = info->m_voiceStatus;
|
||||||
|
|
@ -424,9 +437,17 @@ void UIScene_InGameInfoMenu::OnPlayerChanged(void *callbackParam, INetworkPlayer
|
||||||
// If the player is joining
|
// If the player is joining
|
||||||
if(!leaving)
|
if(!leaving)
|
||||||
{
|
{
|
||||||
|
PlayerInfo *info = scene->BuildPlayerInfo(pPlayer);
|
||||||
|
|
||||||
|
// Skip the dedicated server's phantom host entry (slot 0, empty name)
|
||||||
|
if (pPlayer->GetSmallId() == 0 && info->m_name.empty())
|
||||||
|
{
|
||||||
|
delete info;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
app.DebugPrintf("<UIScene_InGameInfoMenu::OnPlayerChanged> Player \"%ls\" not found, adding\n", pPlayer->GetOnlineName());
|
app.DebugPrintf("<UIScene_InGameInfoMenu::OnPlayerChanged> Player \"%ls\" not found, adding\n", pPlayer->GetOnlineName());
|
||||||
|
|
||||||
PlayerInfo *info = scene->BuildPlayerInfo(pPlayer);
|
|
||||||
scene->m_players.push_back(info);
|
scene->m_players.push_back(info);
|
||||||
|
|
||||||
// Note that the tick updates buttons every tick so it's only really important that we
|
// Note that the tick updates buttons every tick so it's only really important that we
|
||||||
|
|
@ -491,7 +512,7 @@ UIScene_InGameInfoMenu::PlayerInfo *UIScene_InGameInfoMenu::BuildPlayerInfo(INet
|
||||||
}
|
}
|
||||||
|
|
||||||
info->m_voiceStatus = voiceStatus;
|
info->m_voiceStatus = voiceStatus;
|
||||||
info->m_colorState = app.GetPlayerColour(info->m_smallId);
|
info->m_colorState = app.GetPlayerMapIconByName(player->GetOnlineName());
|
||||||
info->m_name = playerName;
|
info->m_name = playerName;
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
|
|
||||||
|
|
@ -193,12 +193,12 @@ void UIScene_TeleportMenu::tick()
|
||||||
{
|
{
|
||||||
m_players[i] = player->GetSmallId();
|
m_players[i] = player->GetSmallId();
|
||||||
|
|
||||||
short icon = app.GetPlayerColour( m_players[i] );
|
short icon = static_cast<short>(app.GetPlayerMapIconByName(player->GetOnlineName()));
|
||||||
|
|
||||||
if(icon != m_playersColourState[i])
|
if(icon != m_playersColourState[i])
|
||||||
{
|
{
|
||||||
m_playersColourState[i] = icon;
|
m_playersColourState[i] = icon;
|
||||||
m_playerList.setPlayerIcon( i, (int)app.GetPlayerColour( m_players[i] ) );
|
m_playerList.setPlayerIcon( i, (int)icon );
|
||||||
}
|
}
|
||||||
|
|
||||||
wstring playerName = L"";
|
wstring playerName = L"";
|
||||||
|
|
|
||||||
|
|
@ -496,6 +496,50 @@ void PlayerList::add(shared_ptr<ServerPlayer> player)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send AddPlayerPackets so all players appear in each other's Tab list
|
||||||
|
// regardless of render distance. The entity tracking system will send
|
||||||
|
// another AddPlayerPacket when they enter range, which is handled
|
||||||
|
// gracefully by putEntity replacing the old entity.
|
||||||
|
{
|
||||||
|
PlayerUID xuid = INVALID_XUID;
|
||||||
|
PlayerUID onlineXuid = INVALID_XUID;
|
||||||
|
#ifndef MINECRAFT_SERVER_BUILD
|
||||||
|
xuid = player->getXuid();
|
||||||
|
onlineXuid = player->getOnlineXuid();
|
||||||
|
#endif
|
||||||
|
int xp = Mth::floor(player->x * 32.0);
|
||||||
|
int yp = Mth::floor(player->y * 32.0);
|
||||||
|
int zp = Mth::floor(player->z * 32.0);
|
||||||
|
int yRotp = Mth::floor(player->yRot * 256.0f / 360.0f);
|
||||||
|
int xRotp = Mth::floor(player->xRot * 256.0f / 360.0f);
|
||||||
|
int yHeadRotp = Mth::floor(player->yHeadRot * 256.0f / 360.0f);
|
||||||
|
|
||||||
|
// Broadcast the new player to all existing players
|
||||||
|
broadcastAll(std::make_shared<AddPlayerPacket>(player, xuid, onlineXuid, xp, yp, zp, yRotp, xRotp, yHeadRotp));
|
||||||
|
|
||||||
|
// Send all existing players to the new player
|
||||||
|
for (size_t i = 0; i < players.size(); i++)
|
||||||
|
{
|
||||||
|
shared_ptr<ServerPlayer> op = players.at(i);
|
||||||
|
if (op != player && op->connection->getNetworkPlayer())
|
||||||
|
{
|
||||||
|
PlayerUID opXuid = INVALID_XUID;
|
||||||
|
PlayerUID opOnlineXuid = INVALID_XUID;
|
||||||
|
#ifndef MINECRAFT_SERVER_BUILD
|
||||||
|
opXuid = op->getXuid();
|
||||||
|
opOnlineXuid = op->getOnlineXuid();
|
||||||
|
#endif
|
||||||
|
int oxp = Mth::floor(op->x * 32.0);
|
||||||
|
int oyp = Mth::floor(op->y * 32.0);
|
||||||
|
int ozp = Mth::floor(op->z * 32.0);
|
||||||
|
int oyRotp = Mth::floor(op->yRot * 256.0f / 360.0f);
|
||||||
|
int oxRotp = Mth::floor(op->xRot * 256.0f / 360.0f);
|
||||||
|
int oyHeadRotp = Mth::floor(op->yHeadRot * 256.0f / 360.0f);
|
||||||
|
player->connection->send(std::make_shared<AddPlayerPacket>(op, opXuid, opOnlineXuid, oxp, oyp, ozp, oyRotp, oxRotp, oyHeadRotp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(level->isAtLeastOnePlayerSleeping())
|
if(level->isAtLeastOnePlayerSleeping())
|
||||||
{
|
{
|
||||||
shared_ptr<ServerPlayer> firstSleepingPlayer = nullptr;
|
shared_ptr<ServerPlayer> firstSleepingPlayer = nullptr;
|
||||||
|
|
@ -528,6 +572,14 @@ if (player->riding != nullptr)
|
||||||
level->removeEntityImmediately(player->riding);
|
level->removeEntityImmediately(player->riding);
|
||||||
app.DebugPrintf("removing player mount");
|
app.DebugPrintf("removing player mount");
|
||||||
}
|
}
|
||||||
|
// Notify all clients to remove this player entity, not just those who
|
||||||
|
// had the player in tracking range. This ensures players added to the
|
||||||
|
// Tab list via the AddPlayerPacket broadcast are properly cleaned up.
|
||||||
|
{
|
||||||
|
intArray ids(1);
|
||||||
|
ids[0] = player->entityId;
|
||||||
|
broadcastAll(std::make_shared<RemoveEntitiesPacket>(ids));
|
||||||
|
}
|
||||||
level->getTracker()->removeEntity(player);
|
level->getTracker()->removeEntity(player);
|
||||||
level->removeEntity(player);
|
level->removeEntity(player);
|
||||||
level->getChunkMap()->remove(player);
|
level->getChunkMap()->remove(player);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue