summaryrefslogtreecommitdiffstats
path: root/src/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/Entities')
-rw-r--r--src/Entities/Entity.cpp2
-rw-r--r--src/Entities/Player.cpp56
-rw-r--r--src/Entities/Player.h36
3 files changed, 68 insertions, 26 deletions
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 74b184c54..e275d03da 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -1500,7 +1500,7 @@ bool cEntity::DetectPortal()
if (IsPlayer())
{
cPlayer * Player = static_cast<cPlayer *>(this);
- if (Player->GetBedWorld() == TargetWorld)
+ if (Player->GetRespawnWorld() == TargetWorld)
{
return MoveToWorld(*TargetWorld, Player->GetLastBedPos());
}
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index b4d806c4f..b99c0227a 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -786,8 +786,7 @@ void cPlayer::SetCustomName(const AString & a_CustomName)
void cPlayer::SetBedPos(const Vector3i a_Position)
{
- m_LastBedPos = a_Position;
- m_SpawnWorldName = m_World->GetName();
+ SetBedPos(a_Position, *m_World);
}
@@ -796,7 +795,8 @@ void cPlayer::SetBedPos(const Vector3i a_Position)
void cPlayer::SetBedPos(const Vector3i a_Position, const cWorld & a_World)
{
- m_LastBedPos = a_Position;
+ m_RespawnPosition = a_Position;
+ m_IsRespawnPointForced = false;
m_SpawnWorldName = a_World.GetName();
}
@@ -804,7 +804,18 @@ void cPlayer::SetBedPos(const Vector3i a_Position, const cWorld & a_World)
-cWorld * cPlayer::GetBedWorld()
+void cPlayer::SetRespawnPosition(const Vector3i a_Position, const cWorld & a_World)
+{
+ m_RespawnPosition = a_Position;
+ m_IsRespawnPointForced = true;
+ m_SpawnWorldName = a_World.GetName();
+}
+
+
+
+
+
+cWorld * cPlayer::GetRespawnWorld()
{
if (const auto World = cRoot::Get()->GetWorld(m_SpawnWorldName); World != nullptr)
{
@@ -943,14 +954,33 @@ void cPlayer::Respawn(void)
// Extinguish the fire:
StopBurning();
- if (const auto BedWorld = GetBedWorld(); m_World != BedWorld)
+ // Disable flying:
+ SetFlying(false);
+
+ if (!m_IsRespawnPointForced)
+ {
+ // Check if the bed is still present:
+ if (GetRespawnWorld()->GetBlock(m_RespawnPosition) != E_BLOCK_BED)
+ {
+ const auto & DefaultWorld = *cRoot::Get()->GetDefaultWorld();
+
+ // If not, reset spawn to default and inform:
+ SetRespawnPosition(Vector3d(DefaultWorld.GetSpawnX(), DefaultWorld.GetSpawnY(), DefaultWorld.GetSpawnZ()), DefaultWorld);
+ SendAboveActionBarMessage("Your home bed was missing or obstructed");
+ }
+
+ // TODO: bed obstruction check here
+ }
+
+
+ if (const auto RespawnWorld = GetRespawnWorld(); m_World != RespawnWorld)
{
- MoveToWorld(*BedWorld, GetLastBedPos(), false, false);
+ MoveToWorld(*RespawnWorld, m_RespawnPosition, false, false);
}
else
{
m_ClientHandle->SendRespawn(m_World->GetDimension(), true);
- TeleportToCoords(GetLastBedPos().x, GetLastBedPos().y, GetLastBedPos().z);
+ TeleportToCoords(m_RespawnPosition.x, m_RespawnPosition.y, m_RespawnPosition.z);
}
SetVisible(true);
@@ -1785,7 +1815,7 @@ void cPlayer::LoadFromDisk()
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, *m_World);
+ SetRespawnPosition(WorldSpawn, *m_World);
m_Inventory.Clear();
m_EnchantmentSeed = GetRandomProvider().RandInt<unsigned int>(); // Use a random number to seed the enchantment generator
@@ -1892,9 +1922,10 @@ bool cPlayer::LoadFromFile(const AString & a_FileName)
m_World = cRoot::Get()->GetDefaultWorld();
}
- 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_RespawnPosition.x = Root.get("SpawnX", m_World->GetSpawnX()).asInt();
+ m_RespawnPosition.y = Root.get("SpawnY", m_World->GetSpawnY()).asInt();
+ m_RespawnPosition.z = Root.get("SpawnZ", m_World->GetSpawnZ()).asInt();
+ m_IsRespawnPointForced = Root.get("SpawnForced", true).asBool();
m_SpawnWorldName = Root.get("SpawnWorld", cRoot::Get()->GetDefaultWorld()->GetName()).asString();
try
@@ -2006,6 +2037,7 @@ void cPlayer::SaveToDisk()
root["SpawnX"] = GetLastBedPos().x;
root["SpawnY"] = GetLastBedPos().y;
root["SpawnZ"] = GetLastBedPos().z;
+ root["SpawnForced"] = m_IsRespawnPointForced;
root["SpawnWorld"] = m_SpawnWorldName;
root["enchantmentSeed"] = m_EnchantmentSeed;
root["world"] = m_CurrentWorldName;
@@ -3236,7 +3268,7 @@ void cPlayer::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
else if (IsInBed())
{
// Check if sleeping is still possible:
- if ((GetPosition().Floor() != m_LastBedPos) || (m_World->GetBlock(m_LastBedPos) != E_BLOCK_BED))
+ if ((GetPosition().Floor() != m_RespawnPosition) || (m_World->GetBlock(m_RespawnPosition) != E_BLOCK_BED))
{
m_ClientHandle->HandleLeaveBed();
}
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index d71fedec5..d1dfffa0b 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -513,22 +513,28 @@ public:
The custom name will be used in the tab-list, in the player nametag and in the tab-completion. */
void SetCustomName(const AString & a_CustomName);
- /** Gets the last position that the player slept in
- This is initialised to the world spawn point if the player has not slept in a bed as of yet
- */
- Vector3i GetLastBedPos(void) const { return m_LastBedPos; }
+ /** Gets the player's potential respawn position (named LastBedPos for compatibility reasons). */
+ Vector3i GetLastBedPos(void) const { return m_RespawnPosition; }
+
+ /** Returns if the respawn point is unconditionally used. */
+ bool IsRespawnPointForced(void) const { return m_IsRespawnPointForced; }
- /** Sets the player's bed (home / respawn) position to the specified position.
- Sets the respawn world to the player's world. */
- void SetBedPos(const Vector3i a_Position);
+ /** Sets the player's bed position to the specified position.
+ Sets the respawn world to the player's world and unforces the respawn point.
+ The given position will be used subject to bed checks when respawning. */
+ void SetBedPos(Vector3i a_Position);
- /** Sets the player's bed (home / respawn) position and respawn world to the specified parameters. */
- void SetBedPos(const Vector3i a_Position, const cWorld & a_World);
+ /** Sets the player's bed position to the specified position.
+ The spawn point is unforced. The given position will be used subject to bed checks when respawning. */
+ void SetBedPos(Vector3i a_Position, const cWorld & a_World);
+
+ /** Sets the player's forced respawn position and world. */
+ void SetRespawnPosition(Vector3i a_Position, const cWorld & a_World);
// tolua_end
- // TODO lua export GetBedPos and GetBedWorld
- cWorld * GetBedWorld();
+ // TODO lua export GetRespawnWorld
+ cWorld * GetRespawnWorld();
/** Update movement-related statistics. */
void UpdateMovementStats(const Vector3d & a_DeltaPos, bool a_PreviousIsOnGround);
@@ -652,8 +658,9 @@ private:
cWindow * m_CurrentWindow;
cWindow * m_InventoryWindow;
- /** The player's last saved bed position */
- Vector3i m_LastBedPos;
+ /** The player's potential respawn position, initialised to world spawn by default.
+ During player respawn from death, if m_IsRespawnPointForced is false and no bed exists here, it will be reset to world spawn. */
+ Vector3i m_RespawnPosition;
/** The name of the world which the player respawns in upon death.
This is stored as a string to enable SaveToDisk to not touch cRoot, and thus can be safely called in the player's destructor. */
@@ -707,6 +714,9 @@ private:
/** Was the player frozen manually by a plugin or automatically by the server? */
bool m_IsManuallyFrozen;
+ /** Whether we unconditionally respawn to m_RespawnPosition, or check if a bed is unobstructed and available first. */
+ bool m_IsRespawnPointForced;
+
/** Flag used by food handling system to determine whether a teleport has just happened.
Will not apply food penalties if found to be true; will set to false after processing. */
bool m_IsTeleporting;