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/Chunk.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'src/Chunk.cpp') diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 4140d4f85..0dc333468 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -668,8 +668,10 @@ void cChunk::SpawnMobs(cMobSpawner & a_MobSpawner) void cChunk::Tick(std::chrono::milliseconds a_Dt) { + const auto ShouldTick = ShouldBeTicked(); + // If we are not valid, tick players and bailout - if (!IsValid()) + if (!ShouldTick) { for (const auto & Entity : m_Entities) { @@ -681,11 +683,6 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) return; } - CheckBlocks(); - - // Tick simulators: - m_World->GetSimulatorManager()->SimulateChunk(a_Dt, m_PosX, m_PosZ, this); - TickBlocks(); // Tick all block entities in this chunk: @@ -745,6 +742,13 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt) ApplyWeatherToTop(); + // Tick simulators: + m_World->GetSimulatorManager()->SimulateChunk(a_Dt, m_PosX, m_PosZ, this); + + // Check blocks after everything else to apply at least one round of queued ticks (i.e. cBlockHandler::Check) this tick: + CheckBlocks(); + + // Finally, tell the client about all block changes: BroadcastPendingBlockChanges(); } @@ -768,9 +772,11 @@ void cChunk::MoveEntityToNewChunk(OwnedEntity a_Entity) cChunk * Neighbor = GetNeighborChunk(a_Entity->GetChunkX() * cChunkDef::Width, a_Entity->GetChunkZ() * cChunkDef::Width); if (Neighbor == nullptr) { - LOGWARNING("%s: Failed to move entity, destination chunk unreachable. Entity lost", __FUNCTION__); - a_Entity->OnRemoveFromWorld(*m_World); - return; + LOGWARNING("%s: Entity at %p (%s, ID %d) moving to a non-existent chunk.", + __FUNCTION__, static_cast(a_Entity.get()), a_Entity->GetClass(), a_Entity->GetUniqueID() + ); + + Neighbor = &m_ChunkMap->ConstructChunk(a_Entity->GetChunkX(), a_Entity->GetChunkZ()); } ASSERT(Neighbor != this); // Moving into the same chunk? wtf? @@ -1480,7 +1486,7 @@ cBlockEntity * cChunk::GetBlockEntityRel(Vector3i a_RelPos) bool cChunk::ShouldBeTicked(void) const { - return (HasAnyClients() || (m_AlwaysTicked > 0)); + return IsValid() && (HasAnyClients() || (m_AlwaysTicked > 0)); } -- cgit v1.2.3