summaryrefslogtreecommitdiffstats
path: root/src/Entities/Player.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Entities/Player.cpp544
1 files changed, 301 insertions, 243 deletions
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index e4c0fdaa5..babe31978 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -36,6 +36,14 @@
// 1000 = once per second
#define PLAYER_LIST_TIME_MS std::chrono::milliseconds(1000)
+#define DO_WITH_VALID_CLIENTHANDLE(Command) \
+ auto ClientHandle = m_ClientHandle.lock(); \
+ if (ClientHandle != nullptr) \
+ { \
+ ClientHandle->Command \
+ }
+
+
@@ -50,7 +58,7 @@ const int cPlayer::EATING_TICKS = 30;
-cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
+cPlayer::cPlayer(std::weak_ptr<cClientHandle> a_Client, const AString & a_PlayerName) :
super(etPlayer, 0.6, 1.8),
m_bVisible(true),
m_FoodLevel(MAX_FOOD_LEVEL),
@@ -85,8 +93,8 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
m_FloaterID(cEntity::INVALID_ID),
m_Team(nullptr),
m_TicksUntilNextSave(PLAYER_INVENTORY_SAVE_INTERVAL),
- m_bIsTeleporting(false),
- m_UUID((a_Client != nullptr) ? a_Client->GetUUID() : ""),
+ m_IsChangingWorlds(false),
+ m_UUID(a_Client.lock()->GetUUID()),
m_CustomName("")
{
ASSERT(a_PlayerName.length() <= 16); // Otherwise this player could crash many clients...
@@ -148,25 +156,6 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
-bool cPlayer::Initialize(cWorld & a_World)
-{
- UNUSED(a_World);
- ASSERT(GetWorld() != nullptr);
- ASSERT(GetParentChunk() == nullptr);
- GetWorld()->AddPlayer(this);
-
- cPluginManager::Get()->CallHookSpawnedEntity(*GetWorld(), *this);
-
- // Spawn the entity on the clients:
- GetWorld()->BroadcastSpawnEntity(*this);
-
- return true;
-}
-
-
-
-
-
cPlayer::~cPlayer(void)
{
if (!cRoot::Get()->GetPluginManager()->CallHookPlayerDestroyed(*this))
@@ -180,10 +169,6 @@ cPlayer::~cPlayer(void)
// Notify the server that the player is being destroyed
cRoot::Get()->GetServer()->PlayerDestroying(this);
- SaveToDisk();
-
- m_ClientHandle = nullptr;
-
delete m_InventoryWindow;
m_InventoryWindow = nullptr;
@@ -196,6 +181,7 @@ cPlayer::~cPlayer(void)
void cPlayer::Destroyed()
{
+ SaveToDisk();
CloseWindow(false);
super::Destroyed();
}
@@ -206,7 +192,7 @@ void cPlayer::Destroyed()
void cPlayer::SpawnOn(cClientHandle & a_Client)
{
- if (!m_bVisible || (m_ClientHandle.get() == (&a_Client)))
+ if (!m_bVisible || (m_ClientHandle.lock().get() == &a_Client))
{
return;
}
@@ -225,28 +211,22 @@ void cPlayer::SpawnOn(cClientHandle & a_Client)
void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
- if (m_ClientHandle != nullptr)
+ auto ClientHandle = m_ClientHandle.lock();
+ if ((ClientHandle == nullptr) || ClientHandle->IsDestroyed())
{
- if (m_ClientHandle->IsDestroyed())
- {
- // This should not happen, because destroying a client will remove it from the world, but just in case
- ASSERT(!"Player ticked whilst in the process of destruction!");
- m_ClientHandle = nullptr;
- return;
- }
+ // If the ClientHandle was deleted or destroyed, the client has disconnected
+ // In theory, if it was only destroyed, we may continue ticking (just nothing would be sent over the network)
+ // For performance however, simply bail out
- if (!m_ClientHandle->IsPlaying())
- {
- // We're not yet in the game, ignore everything
- return;
- }
+ return;
}
- else
+
+ if (!ClientHandle->IsPlaying())
{
- ASSERT(!"Player ticked whilst in the process of destruction!");
+ // We're not yet in the game, ignore everything
+ return;
}
-
m_Stats.AddValue(statMinutesPlayed, 1);
// Handle a frozen player
@@ -255,9 +235,8 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
return;
}
- ASSERT((GetParentChunk() != nullptr) && (GetParentChunk()->IsValid()));
- ASSERT(a_Chunk.IsValid());
+ ASSERT(GetParentChunk() != nullptr);
super::Tick(a_Dt, a_Chunk);
@@ -273,7 +252,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
SendExperience();
}
- BroadcastMovementUpdate(m_ClientHandle.get());
+ BroadcastMovementUpdate(ClientHandle.get());
if (m_Health > 0) // make sure player is alive
{
@@ -319,55 +298,16 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cPlayer::TickFreezeCode()
{
- if (m_IsFrozen)
+ if (m_IsFrozen && (GetWorld()->GetWorldAge() % 100 == 0))
{
- if ((!m_IsManuallyFrozen) && (GetClientHandle()->IsPlayerChunkSent()))
- {
- // If the player was automatically frozen, unfreeze if the chunk the player is inside is loaded and sent
- Unfreeze();
+ // Despite the client side freeze, the player may be able to move a little by
+ // Jumping or canceling flight. Re-freeze every now and then
+ Freeze(GetPosition());
- // Pull the player out of any solids that might have loaded on them.
- PREPARE_REL_AND_CHUNK(GetPosition(), *(GetParentChunk()));
- if (RelSuccess)
- {
- int NewY = Rel.y;
- if (NewY < 0)
- {
- NewY = 0;
- }
- while (NewY < cChunkDef::Height - 2)
- {
- // If we find a position with enough space for the player
- if (
- (Chunk->GetBlock(Rel.x, NewY, Rel.z) == E_BLOCK_AIR) &&
- (Chunk->GetBlock(Rel.x, NewY + 1, Rel.z) == E_BLOCK_AIR)
- )
- {
- // If the found position is not the same as the original
- if (NewY != Rel.y)
- {
- SetPosition(GetPosition().x, NewY, GetPosition().z);
- GetClientHandle()->SendPlayerPosition();
- }
- break;
- }
- ++NewY;
- }
- }
- }
- else if (GetWorld()->GetWorldAge() % 100 == 0)
- {
- // Despite the client side freeze, the player may be able to move a little by
- // Jumping or canceling flight. Re-freeze every now and then
- FreezeInternal(GetPosition(), m_IsManuallyFrozen);
- }
- }
- else
- {
- if (!GetClientHandle()->IsPlayerChunkSent() || (!GetParentChunk()->IsValid()))
- {
- FreezeInternal(GetPosition(), false);
- }
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerPosition();
+ BroadcastMovementUpdate(ClientHandle.get());
+ )
}
}
@@ -499,7 +439,7 @@ void cPlayer::StartChargingBow(void)
LOGD("Player \"%s\" started charging their bow", GetName().c_str());
m_IsChargingBow = true;
m_BowCharge = 0;
- m_World->BroadcastEntityMetadata(*this, m_ClientHandle.get());
+ m_World->BroadcastEntityMetadata(*this, m_ClientHandle.lock().get());
}
@@ -512,7 +452,7 @@ int cPlayer::FinishChargingBow(void)
int res = m_BowCharge;
m_IsChargingBow = false;
m_BowCharge = 0;
- m_World->BroadcastEntityMetadata(*this, m_ClientHandle.get());
+ m_World->BroadcastEntityMetadata(*this, m_ClientHandle.lock().get());
return res;
}
@@ -526,7 +466,7 @@ void cPlayer::CancelChargingBow(void)
LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", GetName().c_str(), m_BowCharge);
m_IsChargingBow = false;
m_BowCharge = 0;
- m_World->BroadcastEntityMetadata(*this, m_ClientHandle.get());
+ m_World->BroadcastEntityMetadata(*this, m_ClientHandle.lock().get());
}
@@ -654,7 +594,11 @@ void cPlayer::FinishEating(void)
m_EatingFinishTick = -1;
// Send the packets:
- m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
+ auto ClientHandle = m_ClientHandle.lock();
+ if (ClientHandle == nullptr)
+ {
+ ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
+ }
m_World->BroadcastEntityMetadata(*this);
// consume the item:
@@ -684,10 +628,9 @@ void cPlayer::AbortEating(void)
void cPlayer::SendHealth(void)
{
- if (m_ClientHandle != nullptr)
- {
- m_ClientHandle->SendHealth();
- }
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendHealth();
+ )
}
@@ -696,11 +639,10 @@ void cPlayer::SendHealth(void)
void cPlayer::SendExperience(void)
{
- if (m_ClientHandle != nullptr)
- {
- m_ClientHandle->SendExperience();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendExperience();
m_bDirtyExperience = false;
- }
+ )
}
@@ -762,8 +704,9 @@ void cPlayer::SetNormalMaxSpeed(double a_Speed)
m_NormalMaxSpeed = a_Speed;
if (!m_IsSprinting && !m_IsFlying && !m_IsFrozen)
{
- // If we are frozen, we do not send this yet. We send when unfreeze() is called
- m_ClientHandle->SendPlayerMaxSpeed();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerMaxSpeed();
+ )
}
}
@@ -776,8 +719,9 @@ void cPlayer::SetSprintingMaxSpeed(double a_Speed)
m_SprintingMaxSpeed = a_Speed;
if (m_IsSprinting && !m_IsFlying && !m_IsFrozen)
{
- // If we are frozen, we do not send this yet. We send when unfreeze() is called
- m_ClientHandle->SendPlayerMaxSpeed();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerMaxSpeed();
+ )
}
}
@@ -789,11 +733,13 @@ void cPlayer::SetFlyingMaxSpeed(double a_Speed)
{
m_FlyingMaxSpeed = a_Speed;
- // Update the flying speed, always:
+ // Update the flying speed:
if (!m_IsFrozen)
{
// If we are frozen, we do not send this yet. We send when unfreeze() is called
- m_ClientHandle->SendPlayerAbilities();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerAbilities();
+ )
}
}
@@ -827,7 +773,9 @@ void cPlayer::SetSprint(bool a_IsSprinting)
}
m_IsSprinting = a_IsSprinting;
- m_ClientHandle->SendPlayerMaxSpeed();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerMaxSpeed();
+ )
}
@@ -842,7 +790,9 @@ void cPlayer::SetCanFly(bool a_CanFly)
}
m_CanFly = a_CanFly;
- m_ClientHandle->SendPlayerAbilities();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerAbilities();
+ )
}
@@ -904,7 +854,9 @@ void cPlayer::SetFlying(bool a_IsFlying)
if (!m_IsFrozen)
{
// If we are frozen, we do not send this yet. We send when unfreeze() is called
- m_ClientHandle->SendPlayerAbilities();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerAbilities();
+ )
}
}
@@ -1147,18 +1099,20 @@ void cPlayer::Respawn(void)
m_LifetimeTotalXp = 0;
// ToDo: send score to client? How?
- m_ClientHandle->SendRespawn(m_SpawnWorld->GetDimension(), true);
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendRespawn(m_SpawnWorld->GetDimension(), true);
+ )
// Extinguish the fire:
StopBurning();
if (GetWorld() != m_SpawnWorld)
{
- MoveToWorld(m_SpawnWorld, false, GetLastBedPos());
+ MoveToWorld(*m_SpawnWorld, GetLastBedPos());
}
else
{
- TeleportToCoords(GetLastBedPos().x, GetLastBedPos().y, GetLastBedPos().z);
+ TeleportToCoords(GetLastBedPos());
}
SetVisible(true);
@@ -1335,7 +1289,9 @@ void cPlayer::SetGameMode(eGameMode a_GameMode)
}
m_GameMode = a_GameMode;
- m_ClientHandle->SendGameMode(a_GameMode);
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendGameMode(a_GameMode);
+ )
SetCapabilities();
@@ -1422,7 +1378,9 @@ unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach)
StatValue New = m_Stats.AddValue(a_Ach);
// Achievement Get!
- m_ClientHandle->SendStatistics(m_Stats);
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendStatistics(m_Stats);
+ )
return static_cast<unsigned int>(New);
}
@@ -1432,18 +1390,18 @@ unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach)
-void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
+void cPlayer::TeleportToCoords(const Vector3d & a_Position)
{
- // ask plugins to allow teleport to the new position.
- if (!cRoot::Get()->GetPluginManager()->CallHookEntityTeleport(*this, m_LastPosition, Vector3d(a_PosX, a_PosY, a_PosZ)))
+ // Ask plugins to allow teleport to the new position.
+ if (!cRoot::Get()->GetPluginManager()->CallHookEntityTeleport(*this, m_LastPosition, a_Position))
{
- SetPosition(a_PosX, a_PosY, a_PosZ);
- FreezeInternal(GetPosition(), false);
- m_LastGroundHeight = a_PosY;
- m_bIsTeleporting = true;
+ SetPosition(a_Position);
+ m_LastGroundHeight = a_Position.y;
m_World->BroadcastTeleportEntity(*this, GetClientHandle());
- m_ClientHandle->SendPlayerMoveLook();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerMoveLook();
+ )
}
}
@@ -1453,7 +1411,32 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
void cPlayer::Freeze(const Vector3d & a_Location)
{
- FreezeInternal(a_Location, true);
+ SetSpeed(0, 0, 0);
+ SetPosition(a_Location);
+ m_IsFrozen = true;
+
+ double NormalMaxSpeed = GetNormalMaxSpeed();
+ double SprintMaxSpeed = GetSprintingMaxSpeed();
+ double FlyingMaxpeed = GetFlyingMaxSpeed();
+ bool IsFlying = m_IsFlying;
+
+ // Set the client-side speed to 0
+ m_NormalMaxSpeed = 0;
+ m_SprintingMaxSpeed = 0;
+ m_FlyingMaxSpeed = 0;
+ m_IsFlying = true;
+
+ // Send the client its fake speed and max speed of 0
+ GetClientHandle()->SendPlayerMoveLook();
+ GetClientHandle()->SendPlayerAbilities();
+ GetClientHandle()->SendPlayerMaxSpeed();
+ GetClientHandle()->SendEntityVelocity(*this);
+
+ // Keep the server side speed variables as they were in the first place
+ m_NormalMaxSpeed = NormalMaxSpeed;
+ m_SprintingMaxSpeed = SprintMaxSpeed;
+ m_FlyingMaxSpeed = FlyingMaxpeed;
+ m_IsFlying = IsFlying;
}
@@ -1475,8 +1458,10 @@ void cPlayer::Unfreeze()
GetClientHandle()->SendPlayerMaxSpeed();
m_IsFrozen = false;
- BroadcastMovementUpdate(GetClientHandle());
- GetClientHandle()->SendPlayerPosition();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerPosition();
+ BroadcastMovementUpdate(ClientHandle.get());
+ )
}
@@ -1487,7 +1472,9 @@ void cPlayer::SendRotation(double a_YawDegrees, double a_PitchDegrees)
{
SetYaw(a_YawDegrees);
SetPitch(a_PitchDegrees);
- m_ClientHandle->SendPlayerMoveLook();
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerMoveLook();
+ )
}
@@ -1524,15 +1511,6 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
-void cPlayer::ForceSetSpeed(const Vector3d & a_Speed)
-{
- SetSpeed(a_Speed);
-}
-
-
-
-
-
void cPlayer::DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ)
{
if (m_IsFrozen)
@@ -1542,7 +1520,9 @@ void cPlayer::DoSetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ)
}
super::DoSetSpeed(a_SpeedX, a_SpeedY, a_SpeedZ);
// Send the speed to the client so he actualy moves
- m_ClientHandle->SendEntityVelocity(*this);
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendEntityVelocity(*this);
+ )
}
@@ -1560,10 +1540,120 @@ void cPlayer::SetVisible(bool a_bVisible)
if (!a_bVisible && m_bVisible)
{
m_bVisible = false;
- m_World->BroadcastDestroyEntity(*this, m_ClientHandle.get()); // Destroy on all clients
+ m_World->BroadcastDestroyEntity(*this, m_ClientHandle.lock().get()); // Destroy on all clients
}
}
+void cPlayer::SendMessage(const AString & a_Message)
+{
+ SendMessage(cCompositeChat(a_Message, mtCustom));
+}
+
+
+
+
+
+void cPlayer::SendMessageInfo(const AString & a_Message)
+{
+ SendMessage(cCompositeChat(a_Message, mtInformation));
+}
+
+
+
+
+
+void cPlayer::SendMessageFailure(const AString & a_Message)
+{
+ SendMessage(cCompositeChat(a_Message, mtFailure));
+}
+
+
+
+
+
+void cPlayer::SendMessageSuccess(const AString & a_Message)
+{
+ SendMessage(cCompositeChat(a_Message, mtSuccess));
+}
+
+
+
+
+
+void cPlayer::SendMessageWarning(const AString & a_Message)
+{
+ SendMessage(cCompositeChat(a_Message, mtWarning));
+}
+
+
+
+
+
+void cPlayer::SendMessageFatal(const AString & a_Message)
+{
+ SendMessage(cCompositeChat(a_Message, mtFailure));
+}
+
+
+
+
+
+void cPlayer::SendMessagePrivateMsg(const AString & a_Message, const AString & a_Sender)
+{
+ SendMessage(cCompositeChat(a_Message, mtPrivateMessage, a_Sender));
+}
+
+
+
+
+
+void cPlayer::SendMessage(const cCompositeChat & a_Message)
+{
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendChat(a_Message);
+ )
+}
+
+
+
+
+
+void cPlayer::SendSystemMessage(const AString & a_Message)
+{
+ SendSystemMessage(cCompositeChat(a_Message));
+}
+
+
+
+
+
+void cPlayer::SendAboveActionBarMessage(const AString & a_Message)
+{
+ SendAboveActionBarMessage(cCompositeChat(a_Message));
+}
+
+
+
+
+
+void cPlayer::SendSystemMessage(const cCompositeChat & a_Message)
+{
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendChatSystem(a_Message);
+ )
+}
+
+
+
+
+
+void cPlayer::SendAboveActionBarMessage(const cCompositeChat & a_Message)
+{
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendChatAboveActionBar(a_Message);
+ )
+}
+
@@ -1760,77 +1850,94 @@ void cPlayer::TossItems(const cItems & a_Items)
-bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_NewPosition)
+bool cPlayer::OnPreWorldTravel(cWorld & a_NewWorld)
{
- ASSERT(a_World != nullptr);
- ASSERT(IsTicking());
-
- if (GetWorld() == a_World)
+ if ((GetWorld() == &a_NewWorld) || IsChangingWorlds())
{
- // Don't move to same world
+ // Don't move a) to same world or b) when already moving worlds
return false;
}
+ ASSERT(IsTicking());
// Ask the plugins if the player is allowed to changing the world
- if (cRoot::Get()->GetPluginManager()->CallHookEntityChangingWorld(*this, *a_World))
+ if (cRoot::Get()->GetPluginManager()->CallHookEntityChangingWorld(*this, a_NewWorld))
{
// A Plugin doesn't allow the player to changing the world
return false;
}
- // The clienthandle caches the coords of the chunk we're standing at. Invalidate this.
- GetClientHandle()->InvalidateCachedSentChunk();
-
// Prevent further ticking in this world
SetIsTicking(false);
- // Tell others we are gone
+ // Stop sending chunks
+ SetIsChangingWorlds(true);
+
+ auto ClientHandle = GetClientHandlePtr().lock();
+ if (ClientHandle != nullptr)
+ {
+ cRoot::Get()->GetServer()->QueueTask(
+ [ClientHandle]
+ {
+ ClientHandle->RemoveFromWorld();
+ }
+ );
+
+ GetWorld()->RemovePlayer(this);
+ ClientHandle->SendRespawn(a_NewWorld.GetDimension());
+
+ switch (a_NewWorld.GetDimension())
+ {
+ case eDimension::dimOverworld: break;
+ case eDimension::dimNether: AwardAchievement(achEnterPortal); break;
+ case eDimension::dimEnd: AwardAchievement(achEnterTheEnd); break;
+ default: ASSERT(!"Unexpected dimension during world travel.");
+ }
+ }
+ // If std::weak_ptr<>::lock returned nullptr, the destructor of cClientHandle would have handled player removal.
+
+ auto Entity = GetParentChunk()->AcquireAssociatedEntityPtr(*this);
+
+ // Broadcast for other people that the player is gone.
GetWorld()->BroadcastDestroyEntity(*this);
- // Remove player from world
- GetWorld()->RemovePlayer(this, false);
+ cpp14::move_on_copy_wrapper<decltype(Entity)> EntityPtr(std::move(Entity));
+ a_NewWorld.QueueTask(
+ [EntityPtr](cWorld & a_DestinationWorld) mutable
+ {
+ ASSERT(EntityPtr.value->IsPlayer());
+ auto Player = static_cast<cPlayer *>(EntityPtr.value.get());
- // Set position to the new position
- SetPosition(a_NewPosition);
- FreezeInternal(a_NewPosition, false);
+ // Player changed world, call the hook
+ cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*EntityPtr.value, *EntityPtr.value->GetWorld());
- // Stop all mobs from targeting this player
- StopEveryoneFromTargetingMe();
+ EntityPtr.value->Initialize(std::move(EntityPtr.value), a_DestinationWorld);
+ a_DestinationWorld.AddPlayer(Player);
- // Send the respawn packet:
- if (a_ShouldSendRespawn && (m_ClientHandle != nullptr))
- {
- m_ClientHandle->SendRespawn(a_World->GetDimension());
- }
+ Player->SetIsChangingWorlds(false);
+ }
+ );
+
+ return true;
+}
- // Update the view distance.
- m_ClientHandle->SetViewDistance(m_ClientHandle->GetRequestedViewDistance());
- // Send current weather of target world to player
- if (a_World->GetDimension() == dimOverworld)
- {
- m_ClientHandle->SendWeather(a_World->GetWeather());
- }
- // Broadcast the player into the new world.
- a_World->BroadcastSpawnEntity(*this);
- // Queue add to new world and removal from the old one
- cChunk * ParentChunk = GetParentChunk();
- cWorld * OldWorld = GetWorld();
- SetWorld(a_World); // Chunks may be streamed before cWorld::AddPlayer() sets the world to the new value
- OldWorld->QueueTask([this, ParentChunk, a_World](cWorld & a_OldWorld)
+
+void cPlayer::OnPostWorldTravel(eDimension a_PreviousDimension, const Vector3d & a_RecommendedPosition)
+{
+ if ((a_PreviousDimension == eDimension::dimEnd) && (GetWorld()->GetDimension() == eDimension::dimOverworld))
{
- LOGD("Warping player \"%s\" from world \"%s\" to \"%s\". Source chunk: (%d, %d) ",
- this->GetName().c_str(),
- a_OldWorld.GetName().c_str(), a_World->GetName().c_str(),
- ParentChunk->GetPosX(), ParentChunk->GetPosZ()
- );
- ParentChunk->RemoveEntity(this);
- a_World->AddPlayer(this);
- cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, a_OldWorld);
- });
- return true;
+ super::OnPostWorldTravel(a_PreviousDimension, GetLastBedPos());
+ }
+ else
+ {
+ super::OnPostWorldTravel(a_PreviousDimension, a_RecommendedPosition);
+ }
+
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendPlayerMoveLook();
+ )
}
@@ -2251,12 +2358,6 @@ bool cPlayer::IsClimbing(void) const
void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIsOnGround)
{
- if (m_bIsTeleporting)
- {
- m_bIsTeleporting = false;
- return;
- }
-
StatValue Value = FloorC<StatValue>(a_DeltaPos.Length() * 100 + 0.5);
if (m_AttachedTo == nullptr)
{
@@ -2412,7 +2513,9 @@ void cPlayer::SendBlocksAround(int a_BlockX, int a_BlockY, int a_BlockZ, int a_R
// Send the blocks for each affected chunk:
for (auto itr = Changes.cbegin(), end = Changes.cend(); itr != end; ++itr)
{
- m_ClientHandle->SendBlockChanges(itr->first.m_ChunkX, itr->first.m_ChunkZ, itr->second);
+ DO_WITH_VALID_CLIENTHANDLE(
+ SendBlockChanges(itr->first.m_ChunkX, itr->first.m_ChunkZ, itr->second);
+ )
}
}
@@ -2449,7 +2552,7 @@ bool cPlayer::PlaceBlocks(const sSetBlockVector & a_Blocks)
}
// Call the "placed" hooks:
- for (auto blk: a_Blocks)
+ for (const auto & blk: a_Blocks)
{
pm->CallHookPlayerPlacedBlock(*this, blk);
}
@@ -2482,7 +2585,7 @@ void cPlayer::Detach()
cBlockInfo::IsSolid(m_World->GetBlock(x, y - 1, z))
)
{
- TeleportToCoords(x + 0.5, y, z + 0.5);
+ TeleportToCoords(Vector3d(x + 0.5, y, z + 0.5));
return;
}
}
@@ -2494,16 +2597,6 @@ void cPlayer::Detach()
-void cPlayer::RemoveClientHandle(void)
-{
- ASSERT(m_ClientHandle != nullptr);
- m_ClientHandle.reset();
-}
-
-
-
-
-
AString cPlayer::GetUUIDFileName(const AString & a_UUID)
{
AString UUID = cMojangAPI::MakeUUIDDashed(a_UUID);
@@ -2516,38 +2609,3 @@ AString cPlayer::GetUUIDFileName(const AString & a_UUID)
res.append(".json");
return res;
}
-
-
-
-
-
-void cPlayer::FreezeInternal(const Vector3d & a_Location, bool a_ManuallyFrozen)
-{
- SetSpeed(0, 0, 0);
- SetPosition(a_Location);
- m_IsFrozen = true;
- m_IsManuallyFrozen = a_ManuallyFrozen;
-
- double NormalMaxSpeed = GetNormalMaxSpeed();
- double SprintMaxSpeed = GetSprintingMaxSpeed();
- double FlyingMaxpeed = GetFlyingMaxSpeed();
- bool IsFlying = m_IsFlying;
-
- // Set the client-side speed to 0
- m_NormalMaxSpeed = 0;
- m_SprintingMaxSpeed = 0;
- m_FlyingMaxSpeed = 0;
- m_IsFlying = true;
-
- // Send the client its fake speed and max speed of 0
- GetClientHandle()->SendPlayerMoveLook();
- GetClientHandle()->SendPlayerAbilities();
- GetClientHandle()->SendPlayerMaxSpeed();
- GetClientHandle()->SendEntityVelocity(*this);
-
- // Keep the server side speed variables as they were in the first place
- m_NormalMaxSpeed = NormalMaxSpeed;
- m_SprintingMaxSpeed = SprintMaxSpeed;
- m_FlyingMaxSpeed = FlyingMaxpeed;
- m_IsFlying = IsFlying;
-}