From 054a89dd9e5d6819adede9d7ba781b69f98ff2f4 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Wed, 6 Jan 2021 00:35:42 +0000 Subject: Clarify cClientHandle, cPlayer ownership semantics + A cPlayer, once created, has a strong pointer to the cClientHandle. The player ticks the clienthandle. If he finds the handle destroyed, he destroys himself in turn. Nothing else can kill the player. * The client handle has a pointer to the player. Once a player is created, the client handle never outlasts the player, nor does it manage the player's lifetime. The pointer is always safe to use after FinishAuthenticate, which is also the point where cProtocol is put into the Game state that allows player manipulation. + Entities are once again never lost by constructing a chunk when they try to move into one that doesn't exist. * Fixed a forgotten Super invocation in cPlayer::OnRemoveFromWorld. * Fix SaveToDisk usage in destructor by only saving things cPlayer owns, instead of accessing cWorld. --- src/Entities/Entity.cpp | 86 +++++++++---------------------------------------- 1 file changed, 16 insertions(+), 70 deletions(-) (limited to 'src/Entities/Entity.cpp') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index f07eab415..a185b8f69 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1183,12 +1183,6 @@ void cEntity::ApplyFriction(Vector3d & a_Speed, double a_SlowdownMultiplier, flo void cEntity::TickBurning(cChunk & a_Chunk) { - // If we're about to change worlds, then we can't accurately determine whether we're in lava (#3939) - if (IsWorldChangeScheduled()) - { - return; - } - // Remember the current burning state: bool HasBeenBurning = (m_TicksLeftBurning > 0); @@ -1359,12 +1353,6 @@ void cEntity::DetectMagma(void) bool cEntity::DetectPortal() { - // If somebody scheduled a world change, do nothing. - if (IsWorldChangeScheduled()) - { - return true; - } - if (GetWorld()->GetDimension() == dimOverworld) { if (GetWorld()->GetLinkedNetherWorldName().empty() && GetWorld()->GetLinkedEndWorldName().empty()) @@ -1380,7 +1368,7 @@ bool cEntity::DetectPortal() } int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; - if ((Y > 0) && (Y < cChunkDef::Height)) + if (cChunkDef::IsValidHeight(Y)) { switch (GetWorld()->GetBlock(X, Y, Z)) { @@ -1413,24 +1401,16 @@ bool cEntity::DetectPortal() { return false; } - cWorld * DestinationWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedOverworldName()); - eDimension DestionationDim = DestinationWorld->GetDimension(); m_PortalCooldownData.m_ShouldPreventTeleportation = true; // Stop portals from working on respawn - if (IsPlayer()) - { - // Send a respawn packet before world is loaded / generated so the client isn't left in limbo - (static_cast(this))->GetClientHandle()->SendRespawn(DestionationDim); - } - Vector3d TargetPos = GetPosition(); TargetPos.x *= 8.0; TargetPos.z *= 8.0; cWorld * TargetWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedOverworldName()); ASSERT(TargetWorld != nullptr); // The linkage checker should have prevented this at startup. See cWorld::start() - LOGD("Jumping %s -> %s", DimensionToString(dimNether).c_str(), DimensionToString(DestionationDim).c_str()); + LOGD("Jumping %s -> %s", DimensionToString(dimNether).c_str(), DimensionToString(TargetWorld->GetDimension()).c_str()); new cNetherPortalScanner(*this, *TargetWorld, TargetPos, cChunkDef::Height); return true; } @@ -1441,28 +1421,16 @@ bool cEntity::DetectPortal() { return false; } - cWorld * DestinationWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedNetherWorldName()); - eDimension DestionationDim = DestinationWorld->GetDimension(); m_PortalCooldownData.m_ShouldPreventTeleportation = true; - if (IsPlayer()) - { - if (DestionationDim == dimNether) - { - static_cast(this)->AwardAchievement(Statistic::AchPortal); - } - - static_cast(this)->GetClientHandle()->SendRespawn(DestionationDim); - } - Vector3d TargetPos = GetPosition(); TargetPos.x /= 8.0; TargetPos.z /= 8.0; cWorld * TargetWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedNetherWorldName()); ASSERT(TargetWorld != nullptr); // The linkage checker should have prevented this at startup. See cWorld::start() - LOGD("Jumping %s -> %s", DimensionToString(dimOverworld).c_str(), DimensionToString(DestionationDim).c_str()); + LOGD("Jumping %s -> %s", DimensionToString(dimOverworld).c_str(), DimensionToString(TargetWorld->GetDimension()).c_str()); new cNetherPortalScanner(*this, *TargetWorld, TargetPos, (cChunkDef::Height / 2)); return true; } @@ -1483,34 +1451,26 @@ bool cEntity::DetectPortal() // End portal in the end if (GetWorld()->GetDimension() == dimEnd) { - if (GetWorld()->GetLinkedOverworldName().empty()) { return false; } - cWorld * DestinationWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedOverworldName()); - eDimension DestionationDim = DestinationWorld->GetDimension(); - m_PortalCooldownData.m_ShouldPreventTeleportation = true; + cWorld * TargetWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedOverworldName()); + ASSERT(TargetWorld != nullptr); // The linkage checker should have prevented this at startup. See cWorld::start() + LOGD("Jumping %s -> %s", DimensionToString(dimEnd).c_str(), DimensionToString(TargetWorld->GetDimension()).c_str()); + if (IsPlayer()) { cPlayer * Player = static_cast(this); - if (Player->GetBedWorld() == DestinationWorld) - { - Player->TeleportToCoords(Player->GetLastBedPos().x, Player->GetLastBedPos().y, Player->GetLastBedPos().z); - } - else + if (Player->GetBedWorld() == TargetWorld) { - Player->TeleportToCoords(DestinationWorld->GetSpawnX(), DestinationWorld->GetSpawnY(), DestinationWorld->GetSpawnZ()); + return MoveToWorld(*TargetWorld, Player->GetLastBedPos()); } - Player->GetClientHandle()->SendRespawn(DestionationDim); } - cWorld * TargetWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedOverworldName()); - ASSERT(TargetWorld != nullptr); // The linkage checker should have prevented this at startup. See cWorld::start() - LOGD("Jumping %s -> %s", DimensionToString(dimEnd).c_str(), DimensionToString(DestionationDim).c_str()); return MoveToWorld(*TargetWorld, false); } // End portal in the overworld @@ -1520,23 +1480,12 @@ bool cEntity::DetectPortal() { return false; } - cWorld * DestinationWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedEndWorldName()); - eDimension DestionationDim = DestinationWorld->GetDimension(); m_PortalCooldownData.m_ShouldPreventTeleportation = true; - if (IsPlayer()) - { - if (DestionationDim == dimEnd) - { - static_cast(this)->AwardAchievement(Statistic::AchTheEnd); - } - static_cast(this)->GetClientHandle()->SendRespawn(DestionationDim); - } - cWorld * TargetWorld = cRoot::Get()->GetWorld(GetWorld()->GetLinkedEndWorldName()); ASSERT(TargetWorld != nullptr); // The linkage checker should have prevented this at startup. See cWorld::start() - LOGD("Jumping %s -> %s", DimensionToString(dimOverworld).c_str(), DimensionToString(DestionationDim).c_str()); + LOGD("Jumping %s -> %s", DimensionToString(dimOverworld).c_str(), DimensionToString(TargetWorld->GetDimension()).c_str()); return MoveToWorld(*TargetWorld, false); } @@ -1559,13 +1508,14 @@ void cEntity::DoMoveToWorld(const sWorldChangeInfo & a_WorldChangeInfo) { ASSERT(a_WorldChangeInfo.m_NewWorld != nullptr); + // Reset portal cooldown: if (a_WorldChangeInfo.m_SetPortalCooldown) { m_PortalCooldownData.m_TicksDelayed = 0; m_PortalCooldownData.m_ShouldPreventTeleportation = true; } - if (GetWorld() == a_WorldChangeInfo.m_NewWorld) + if (m_World == a_WorldChangeInfo.m_NewWorld) { // Moving to same world, don't need to remove from world SetPosition(a_WorldChangeInfo.m_NewPosition); @@ -1578,23 +1528,19 @@ void cEntity::DoMoveToWorld(const sWorldChangeInfo & a_WorldChangeInfo) GetChunkX(), GetChunkZ() ); - // If entity is attached to another entity, detach, to prevent client side effects - Detach(); - // Stop ticking, in preperation for detaching from this world. SetIsTicking(false); // Remove from the old world + const auto OldWorld = m_World; auto Self = m_World->RemoveEntity(*this); - // Update entity before calling hook + // Update entity: ResetPosition(a_WorldChangeInfo.m_NewPosition); SetWorld(a_WorldChangeInfo.m_NewWorld); - cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, *m_World); - // Don't do anything after adding as the old world's CS no longer protects us - a_WorldChangeInfo.m_NewWorld->AddEntity(std::move(Self)); + a_WorldChangeInfo.m_NewWorld->AddEntity(std::move(Self), OldWorld); } @@ -1614,7 +1560,7 @@ bool cEntity::MoveToWorld(cWorld & a_World, Vector3d a_NewPosition, bool a_SetPo // Create new world change info // (The last warp command always takes precedence) - m_WorldChangeInfo = { &a_World, a_NewPosition, a_SetPortalCooldown, a_ShouldSendRespawn }; + m_WorldChangeInfo = { &a_World, a_NewPosition, a_SetPortalCooldown }; if (OldWorld != nullptr) { -- cgit v1.2.3