summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Entities/Player.cpp83
-rw-r--r--src/Entities/Player.h30
2 files changed, 112 insertions, 1 deletions
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 33ded6ab9..bede603e2 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -63,6 +63,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
m_GameMode(eGameMode_NotSet),
m_IP(""),
m_ClientHandle(a_Client),
+ m_FreezeCounter(-1),
m_NormalMaxSpeed(1.0),
m_SprintingMaxSpeed(1.3),
m_FlyingMaxSpeed(1.0),
@@ -112,6 +113,7 @@ cPlayer::cPlayer(cClientHandlePtr a_Client, const AString & a_PlayerName) :
m_LastGroundHeight = static_cast<float>(GetPosY());
m_Stance = GetPosY() + 1.62;
+ FreezeInternal(GetPosition(), false); // Freeze. Will be unfrozen once the chunk is loaded
if (m_GameMode == gmNotSet)
{
@@ -220,8 +222,35 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
m_Stats.AddValue(statMinutesPlayed, 1);
+ // Handle a frozen player
+ if (m_IsFrozen)
+ {
+ m_FreezeCounter += 1;
+ if (!m_IsManuallyFrozen && a_Chunk.IsValid())
+ {
+ // If the player was automatically frozen, unfreeze if the chunk the player is inside is loaded
+ Unfreeze();
+ }
+ else
+ {
+ // If the player was externally / manually frozen (plugin, etc.) or if the chunk isn't loaded yet:
+ // 1. Set the location to m_FrozenPosition every tick.
+ // 2. Zero out the speed every tick.
+ // 3. Send location updates every 60 ticks.
+ SetPosition(m_FrozenPosition);
+ SetSpeed(0, 0, 0);
+ if (m_FreezeCounter % 60 == 0)
+ {
+ BroadcastMovementUpdate(m_ClientHandle.get());
+ m_ClientHandle->SendPlayerPosition();
+ }
+ return;
+ }
+ }
+
if (!a_Chunk.IsValid())
{
+ FreezeInternal(GetPosition(), false);
// This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83)
return;
}
@@ -1263,6 +1292,46 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
+void cPlayer::Freeze(const Vector3d & a_Location)
+{
+ FreezeInternal(a_Location, true);
+}
+
+
+
+
+
+bool cPlayer::IsFrozen()
+{
+ return m_IsFrozen;
+}
+
+
+
+
+
+int cPlayer::GetFrozenDuration()
+{
+ return m_FreezeCounter;
+}
+
+
+
+
+
+void cPlayer::Unfreeze()
+{
+ m_FreezeCounter = -1;
+ m_IsFrozen = false;
+ SetPosition(m_FrozenPosition);
+ BroadcastMovementUpdate(m_ClientHandle.get());
+ m_ClientHandle->SendPlayerPosition();
+}
+
+
+
+
+
void cPlayer::SendRotation(double a_YawDegrees, double a_PitchDegrees)
{
SetYaw(a_YawDegrees);
@@ -1533,6 +1602,20 @@ void cPlayer::TossItems(const cItems & a_Items)
}
+
+
+
+void cPlayer::FreezeInternal(const Vector3d & a_Location, bool a_ManuallyFrozen)
+{
+ m_IsFrozen = true;
+ m_FrozenPosition = a_Location;
+ m_IsManuallyFrozen = a_ManuallyFrozen;
+}
+
+
+
+
+
bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d a_NewPosition)
{
ASSERT(a_World != nullptr);
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index bff9599f7..10c9106a3 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -138,6 +138,18 @@ public:
// tolua_begin
+ /** Prevent the player from moving and lock him into a_Location. */
+ void Freeze(const Vector3d & a_Location);
+
+ /** Is the player frozen? */
+ bool IsFrozen();
+
+ /** How long has the player been frozen? */
+ int GetFrozenDuration();
+
+ /** Cancels Freeze(...) and allows the player to move naturally. */
+ void Unfreeze();
+
/** Sends the "look" packet to the player, forcing them to set their rotation to the specified values.
a_YawDegrees is clipped to range [-180, +180),
a_PitchDegrees is clipped to range [-180, +180) but the client only uses [-90, +90]
@@ -240,7 +252,7 @@ public:
void SendMessageFatal (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); }
void SendMessagePrivateMsg (const AString & a_Message, const AString & a_Sender) { m_ClientHandle->SendChat(a_Message, mtPrivateMessage, a_Sender); }
void SendMessage (const cCompositeChat & a_Message) { m_ClientHandle->SendChat(a_Message); }
-
+
void SendSystemMessage (const AString & a_Message) { m_ClientHandle->SendChatSystem(a_Message, mtCustom); }
void SendAboveActionBarMessage(const AString & a_Message) { m_ClientHandle->SendChatAboveActionBar(a_Message, mtCustom); }
void SendSystemMessage (const cCompositeChat & a_Message) { m_ClientHandle->SendChatSystem(a_Message); }
@@ -576,6 +588,18 @@ protected:
cSlotNums m_InventoryPaintSlots;
+ /** if m_IsFrozen is true, we lock m_Location to this position. */
+ Vector3d m_FrozenPosition;
+
+ /** If true, we are locking m_Position to m_FrozenPosition. */
+ bool m_IsFrozen;
+
+ /** */
+ int m_FreezeCounter;
+
+ /** Was the player frozen manually by a plugin or automatically by the server? */
+ bool m_IsManuallyFrozen;
+
/** Max speed, relative to the game default.
1 means regular speed, 2 means twice as fast, 0.5 means half-speed.
Default value is 1. */
@@ -661,6 +685,10 @@ protected:
/** Tosses a list of items. */
void TossItems(const cItems & a_Items);
+ /** Pins the player to a_Location until Unfreeze() is called.
+ If ManuallyFrozen is false, the player will unfreeze when the chunk is loaded. */
+ void FreezeInternal(const Vector3d & a_Location, bool a_ManuallyFrozen);
+
/** Returns the filename for the player data based on the UUID given.
This can be used both for online and offline UUIDs. */
AString GetUUIDFileName(const AString & a_UUID);