Perform bed checks upon respawn (#5300)
Co-authored-by: Tiger Wang <ziwei.tiger@outlook.com>
This commit is contained in:
parent
1a0d9450ea
commit
be3111d133
@ -10463,7 +10463,7 @@ a_Player:OpenWindow(Window);
|
||||
Type = "Vector3i",
|
||||
},
|
||||
},
|
||||
Notes = "Returns the position of the last bed the player has slept in, or the world's spawn if no such position was recorded.",
|
||||
Notes = "Returns the player's respawn position. The player is guaranteed to respawn from death here if {{cPlayer}}:IsRespawnPointForced is true or if a bed exists at this position.",
|
||||
},
|
||||
GetMaxSpeed =
|
||||
{
|
||||
@ -10827,6 +10827,15 @@ a_Player:OpenWindow(Window);
|
||||
},
|
||||
Notes = "Returns true if the player's left hand is dominant.",
|
||||
},
|
||||
IsRespawnPointForced = {
|
||||
Returns =
|
||||
{
|
||||
{
|
||||
Type = "boolean",
|
||||
},
|
||||
},
|
||||
Notes = "Returns true if the player unconditionally respawns from death at the position given by {{cPlayer}}:GetLastBedPos with no bed checks performed.",
|
||||
},
|
||||
IsSatiated =
|
||||
{
|
||||
Returns =
|
||||
@ -11098,7 +11107,7 @@ a_Player:OpenWindow(Window);
|
||||
IsOptional = true,
|
||||
},
|
||||
},
|
||||
Notes = "Sets the position and world of the player's respawn point, which is also known as the bed position. The player will respawn at this position and world upon death. If the world is not specified, it is set to the player's current world.",
|
||||
Notes = "Sets the position and world of the player's bed. If the world is not specified, it is set to the player's current world. The player will respawn at this position and world upon death if there is a bed there.",
|
||||
},
|
||||
SetCanFly =
|
||||
{
|
||||
@ -11298,6 +11307,21 @@ a_Player:OpenWindow(Window);
|
||||
},
|
||||
Notes = "Sets the normal (walking) maximum speed, relative to the game default speed. The default value is 1. Sends the updated speed to the client, if appropriate.",
|
||||
},
|
||||
SetRespawnPosition =
|
||||
{
|
||||
Params =
|
||||
{
|
||||
{
|
||||
Name = "Position",
|
||||
Type = "Vector3i",
|
||||
},
|
||||
{
|
||||
Name = "World",
|
||||
Type = "cWorld",
|
||||
},
|
||||
},
|
||||
Notes = "Sets the position and world of the player's respawn point. The player will respawn at this position and world upon death.",
|
||||
},
|
||||
SetSprint =
|
||||
{
|
||||
Params =
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 189690e30d3c9175843d5ed27c447b8c12054f3e
|
||||
Subproject commit 9913cece597eed01177086a620ad304a68a4693c
|
@ -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());
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
MoveToWorld(*BedWorld, GetLastBedPos(), false, false);
|
||||
// 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(*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();
|
||||
}
|
||||
|
@ -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; }
|
||||
|
||||
/** 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);
|
||||
/** Returns if the respawn point is unconditionally used. */
|
||||
bool IsRespawnPointForced(void) const { return m_IsRespawnPointForced; }
|
||||
|
||||
/** 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.
|
||||
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 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;
|
||||
|
Loading…
Reference in New Issue
Block a user