Streamline player abilities handling
* Update player list gamemode on world change * Fix invisibility for spectators, use entity metadata * Populate m_World for cPlayers on load - Remove SendPlayerMaxSpeed, a duplicate of SendEntityProperties
This commit is contained in:
@@ -144,30 +144,10 @@ cPlayer::cPlayer(const std::shared_ptr<cClientHandle> & a_Client) :
|
||||
SetMaxHealth(MAX_HEALTH);
|
||||
m_Health = MAX_HEALTH;
|
||||
|
||||
cWorld * World = nullptr;
|
||||
LoadFromDisk(World);
|
||||
LoadFromDisk();
|
||||
UpdateCapabilities();
|
||||
|
||||
m_LastGroundHeight = static_cast<float>(GetPosY());
|
||||
|
||||
if (m_GameMode == gmNotSet)
|
||||
{
|
||||
if (World->IsGameModeCreative())
|
||||
{
|
||||
m_IsFlightCapable = true;
|
||||
}
|
||||
if (World->IsGameModeSpectator()) // Otherwise Player will fall out of the world on join
|
||||
{
|
||||
m_IsFlightCapable = true;
|
||||
m_IsFlying = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_GameMode == gmSpectator) // If player is reconnecting to the server in spectator mode
|
||||
{
|
||||
m_IsFlightCapable = true;
|
||||
m_IsFlying = true;
|
||||
m_IsVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -614,10 +594,11 @@ double cPlayer::GetMaxSpeed(void) const
|
||||
void cPlayer::SetNormalMaxSpeed(double a_Speed)
|
||||
{
|
||||
m_NormalMaxSpeed = a_Speed;
|
||||
if (!IsSprinting() && !IsFlying() && !IsFrozen())
|
||||
|
||||
if (!m_IsFrozen)
|
||||
{
|
||||
// If we are frozen, we do not send this yet. We send when unfreeze() is called
|
||||
m_ClientHandle->SendPlayerMaxSpeed();
|
||||
m_World->BroadcastEntityProperties(*this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,10 +609,11 @@ void cPlayer::SetNormalMaxSpeed(double a_Speed)
|
||||
void cPlayer::SetSprintingMaxSpeed(double a_Speed)
|
||||
{
|
||||
m_SprintingMaxSpeed = a_Speed;
|
||||
if (IsSprinting() && !m_IsFlying && !m_IsFrozen)
|
||||
|
||||
if (!m_IsFrozen)
|
||||
{
|
||||
// If we are frozen, we do not send this yet. We send when unfreeze() is called
|
||||
m_ClientHandle->SendPlayerMaxSpeed();
|
||||
m_World->BroadcastEntityProperties(*this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -643,7 +625,6 @@ void cPlayer::SetFlyingMaxSpeed(double a_Speed)
|
||||
{
|
||||
m_FlyingMaxSpeed = a_Speed;
|
||||
|
||||
// Update the flying speed, always:
|
||||
if (!m_IsFrozen)
|
||||
{
|
||||
// If we are frozen, we do not send this yet. We send when unfreeze() is called
|
||||
@@ -723,6 +704,7 @@ void cPlayer::SetSprint(const bool a_ShouldSprint)
|
||||
}
|
||||
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
m_World->BroadcastEntityProperties(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1325,49 +1307,38 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
|
||||
}
|
||||
|
||||
m_GameMode = a_GameMode;
|
||||
UpdateCapabilities();
|
||||
|
||||
m_ClientHandle->SendGameMode(a_GameMode);
|
||||
|
||||
SetCapabilities();
|
||||
|
||||
m_ClientHandle->SendInventorySlot(-1, -1, m_DraggingItem);
|
||||
m_World->BroadcastPlayerListUpdateGameMode(*this);
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetCapabilities()
|
||||
void cPlayer::UpdateCapabilities()
|
||||
{
|
||||
// Fly ability
|
||||
// Fly ability:
|
||||
if (IsGameModeCreative() || IsGameModeSpectator())
|
||||
{
|
||||
SetCanFly(true);
|
||||
m_IsFlightCapable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFlying(false);
|
||||
SetCanFly(false);
|
||||
m_IsFlying = false;
|
||||
m_IsFlightCapable = false;
|
||||
}
|
||||
|
||||
// Visible
|
||||
if (IsGameModeSpectator())
|
||||
{
|
||||
SetVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetVisible(true);
|
||||
}
|
||||
// Visible:
|
||||
m_IsVisible = !IsGameModeSpectator();
|
||||
|
||||
// Set for spectator
|
||||
// Clear the current dragging item of spectators:
|
||||
if (IsGameModeSpectator())
|
||||
{
|
||||
// Clear the current dragging item of the player
|
||||
if (GetWindow() != nullptr)
|
||||
{
|
||||
m_DraggingItem.Empty();
|
||||
GetClientHandle()->SendInventorySlot(-1, -1, m_DraggingItem);
|
||||
}
|
||||
m_DraggingItem.Empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1449,8 +1420,8 @@ void cPlayer::Unfreeze()
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
}
|
||||
|
||||
GetClientHandle()->SendPlayerAbilities();
|
||||
GetClientHandle()->SendPlayerMaxSpeed();
|
||||
m_ClientHandle->SendPlayerAbilities();
|
||||
m_World->BroadcastEntityProperties(*this);
|
||||
|
||||
m_IsFrozen = false;
|
||||
BroadcastMovementUpdate(m_ClientHandle.get());
|
||||
@@ -1521,21 +1492,7 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
|
||||
|
||||
eGameMode cPlayer::GetEffectiveGameMode(void) const
|
||||
{
|
||||
// Since entities' m_World aren't set until Initialize, but cClientHandle sends the player's gamemode early
|
||||
// the below block deals with m_World being nullptr when called.
|
||||
|
||||
auto World = m_World;
|
||||
|
||||
if (World == nullptr)
|
||||
{
|
||||
World = cRoot::Get()->GetDefaultWorld();
|
||||
}
|
||||
else if (IsWorldChangeScheduled())
|
||||
{
|
||||
World = m_WorldChangeInfo.m_NewWorld;
|
||||
}
|
||||
|
||||
return (m_GameMode == gmNotSet) ? World->GetGameMode() : m_GameMode;
|
||||
return (m_GameMode == gmNotSet) ? m_World->GetGameMode() : m_GameMode;
|
||||
}
|
||||
|
||||
|
||||
@@ -1553,17 +1510,16 @@ void cPlayer::ForceSetSpeed(const Vector3d & a_Speed)
|
||||
|
||||
void cPlayer::SetVisible(bool a_bVisible)
|
||||
{
|
||||
// Need to Check if the player or other players are in gamemode spectator, but will break compatibility
|
||||
if (a_bVisible && !m_IsVisible) // Make visible
|
||||
if (a_bVisible && !m_IsVisible)
|
||||
{
|
||||
m_IsVisible = true;
|
||||
m_World->BroadcastSpawnEntity(*this);
|
||||
}
|
||||
if (!a_bVisible && m_IsVisible)
|
||||
{
|
||||
m_IsVisible = false;
|
||||
m_World->BroadcastDestroyEntity(*this, m_ClientHandle.get()); // Destroy on all clients
|
||||
}
|
||||
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
}
|
||||
|
||||
|
||||
@@ -1806,25 +1762,25 @@ void cPlayer::TossPickup(const cItem & a_Item)
|
||||
|
||||
|
||||
|
||||
void cPlayer::LoadFromDisk(cWorldPtr & a_World)
|
||||
void cPlayer::LoadFromDisk()
|
||||
{
|
||||
LoadRank();
|
||||
|
||||
const auto & UUID = GetUUID();
|
||||
|
||||
// Load from the UUID file:
|
||||
if (LoadFromFile(GetUUIDFileName(UUID), a_World))
|
||||
if (LoadFromFile(GetUUIDFileName(UUID)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Player not found:
|
||||
a_World = cRoot::Get()->GetDefaultWorld();
|
||||
m_World = cRoot::Get()->GetDefaultWorld();
|
||||
LOG("Player \"%s\" (%s) data not found, resetting to defaults", GetName().c_str(), UUID.ToShortString().c_str());
|
||||
|
||||
const Vector3i WorldSpawn(static_cast<int>(a_World->GetSpawnX()), static_cast<int>(a_World->GetSpawnY()), static_cast<int>(a_World->GetSpawnZ()));
|
||||
const Vector3i WorldSpawn(static_cast<int>(m_World->GetSpawnX()), static_cast<int>(m_World->GetSpawnY()), static_cast<int>(m_World->GetSpawnZ()));
|
||||
SetPosition(WorldSpawn);
|
||||
SetBedPos(WorldSpawn, a_World);
|
||||
SetBedPos(WorldSpawn, m_World);
|
||||
|
||||
m_Inventory.Clear();
|
||||
m_EnchantmentSeed = GetRandomProvider().RandInt<unsigned int>(); // Use a random number to seed the enchantment generator
|
||||
@@ -1836,7 +1792,7 @@ void cPlayer::LoadFromDisk(cWorldPtr & a_World)
|
||||
|
||||
|
||||
|
||||
bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
|
||||
bool cPlayer::LoadFromFile(const AString & a_FileName)
|
||||
{
|
||||
Json::Value Root;
|
||||
|
||||
@@ -1925,16 +1881,15 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
|
||||
cEnderChestEntity::LoadFromJson(Root["enderchestinventory"], m_EnderChestContents);
|
||||
|
||||
m_CurrentWorldName = Root.get("world", "world").asString();
|
||||
a_World = cRoot::Get()->GetWorld(GetLoadedWorldName());
|
||||
if (a_World == nullptr)
|
||||
m_World = cRoot::Get()->GetWorld(m_CurrentWorldName);
|
||||
if (m_World == nullptr)
|
||||
{
|
||||
a_World = cRoot::Get()->GetDefaultWorld();
|
||||
m_World = cRoot::Get()->GetDefaultWorld();
|
||||
}
|
||||
|
||||
|
||||
m_LastBedPos.x = Root.get("SpawnX", a_World->GetSpawnX()).asInt();
|
||||
m_LastBedPos.y = Root.get("SpawnY", a_World->GetSpawnY()).asInt();
|
||||
m_LastBedPos.z = Root.get("SpawnZ", a_World->GetSpawnZ()).asInt();
|
||||
m_LastBedPos.x = Root.get("SpawnX", m_World->GetSpawnX()).asInt();
|
||||
m_LastBedPos.y = Root.get("SpawnY", m_World->GetSpawnY()).asInt();
|
||||
m_LastBedPos.z = Root.get("SpawnZ", m_World->GetSpawnZ()).asInt();
|
||||
m_SpawnWorldName = Root.get("SpawnWorld", cRoot::Get()->GetDefaultWorld()->GetName()).asString();
|
||||
|
||||
try
|
||||
@@ -1949,7 +1904,7 @@ bool cPlayer::LoadFromFile(const AString & a_FileName, cWorldPtr & a_World)
|
||||
}
|
||||
|
||||
FLOGD("Player {0} was read from file \"{1}\", spawning at {2:.2f} in world \"{3}\"",
|
||||
GetName(), a_FileName, GetPosition(), a_World->GetName()
|
||||
GetName(), a_FileName, GetPosition(), m_World->GetName()
|
||||
);
|
||||
|
||||
return true;
|
||||
@@ -2689,10 +2644,10 @@ void cPlayer::FreezeInternal(const Vector3d & a_Location, bool a_ManuallyFrozen)
|
||||
m_IsFlying = true;
|
||||
|
||||
// Send the client its fake speed and max speed of 0
|
||||
GetClientHandle()->SendPlayerMoveLook();
|
||||
GetClientHandle()->SendPlayerAbilities();
|
||||
GetClientHandle()->SendPlayerMaxSpeed();
|
||||
GetClientHandle()->SendEntityVelocity(*this);
|
||||
m_ClientHandle->SendPlayerMoveLook();
|
||||
m_ClientHandle->SendPlayerAbilities();
|
||||
m_ClientHandle->SendEntityVelocity(*this);
|
||||
m_World->BroadcastEntityProperties(*this);
|
||||
|
||||
// Keep the server side speed variables as they were in the first place
|
||||
m_NormalMaxSpeed = NormalMaxSpeed;
|
||||
@@ -3050,6 +3005,15 @@ float cPlayer::GetEnchantmentBlastKnockbackReduction()
|
||||
|
||||
|
||||
|
||||
bool cPlayer::IsInvisible() const
|
||||
{
|
||||
return !m_IsVisible || Super::IsInvisible();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cPlayer::IsCrouched(void) const
|
||||
{
|
||||
return std::holds_alternative<BodyStanceCrouching>(m_BodyStance);
|
||||
@@ -3079,6 +3043,7 @@ bool cPlayer::IsSprinting(void) const
|
||||
|
||||
void cPlayer::OnAddToWorld(cWorld & a_World)
|
||||
{
|
||||
// Sends player spawn:
|
||||
Super::OnAddToWorld(a_World);
|
||||
|
||||
// Update world name tracking:
|
||||
@@ -3087,8 +3052,10 @@ void cPlayer::OnAddToWorld(cWorld & a_World)
|
||||
// Fix to stop the player falling through the world, until we get serversided collision detection:
|
||||
FreezeInternal(GetPosition(), false);
|
||||
|
||||
// Set capabilities based on new world:
|
||||
SetCapabilities();
|
||||
// UpdateCapabilities was called in the constructor, and in OnRemoveFromWorld, possibly changing our visibility.
|
||||
// If world is in spectator mode, invisibility will need updating. If we just connected, we might be on fire from a previous game.
|
||||
// Hence, tell the client by sending metadata:
|
||||
m_ClientHandle->SendEntityMetadata(*this);
|
||||
|
||||
// Send contents of the inventory window:
|
||||
m_ClientHandle->SendWholeInventory(*m_CurrentWindow);
|
||||
@@ -3168,8 +3135,13 @@ void cPlayer::OnRemoveFromWorld(cWorld & a_World)
|
||||
AwardAchievement(Statistic::AchPortal);
|
||||
}
|
||||
|
||||
// Set capabilities based on new world:
|
||||
UpdateCapabilities();
|
||||
|
||||
// Clientside warp start:
|
||||
m_ClientHandle->SendRespawn(DestinationDimension, false);
|
||||
m_ClientHandle->SendPlayerListUpdateGameMode(*this);
|
||||
m_World->BroadcastPlayerListUpdateGameMode(*this);
|
||||
|
||||
// Clear sent chunk lists from the clienthandle:
|
||||
m_ClientHandle->RemoveFromWorld();
|
||||
@@ -3184,7 +3156,7 @@ void cPlayer::OnRemoveFromWorld(cWorld & a_World)
|
||||
|
||||
void cPlayer::SpawnOn(cClientHandle & a_Client)
|
||||
{
|
||||
if (!m_IsVisible || (m_ClientHandle.get() == (&a_Client)))
|
||||
if (m_ClientHandle.get() == &a_Client)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user