diff options
-rw-r--r-- | src/Chunk.h | 3 | ||||
-rw-r--r-- | src/ChunkMap.cpp | 4 | ||||
-rw-r--r-- | src/Entities/Entity.cpp | 51 |
3 files changed, 33 insertions, 25 deletions
diff --git a/src/Chunk.h b/src/Chunk.h index de46b5f8f..ecb594191 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -519,9 +519,8 @@ private: std::vector<Vector3i> m_ToTickBlocks; sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients - // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers - std::vector<cClientHandle *> m_LoadedByClient; cEntityList m_Entities; + std::vector<std::weak_ptr<cClientHandle>> m_LoadedByClient; cBlockEntityList m_BlockEntities; /** Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded */ diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index 7f53865d0..2e6153f0e 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1582,10 +1582,7 @@ void cChunkMap::RemoveChunkClient(int a_ChunkX, int a_ChunkZ, const std::shared_ - -void cChunkMap::RemoveClientFromChunks(cClientHandle * a_Client) { - cCSLock Lock(m_CSChunks); for (const auto & Chunk : m_Chunks) { Chunk.second->RemoveClient(a_Client); @@ -1613,6 +1610,7 @@ void cChunkMap::AddEntity(cEntity * a_Entity) + ASSERT(GetWorld()->IsInTickThread()); void cChunkMap::AddEntityIfNotPresent(cEntity * a_Entity) { diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 8d74ee99a..489b55cf8 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -132,7 +132,9 @@ const char * cEntity::GetParentClass(void) const bool cEntity::Initialize(cWorld & a_World) { - if (cPluginManager::Get()->CallHookSpawningEntity(a_World, *this)) + ASSERT(a_EntityWorld.IsInTickThread()); + + if (cPluginManager::Get()->CallHookSpawningEntity(a_EntityWorld, *this) && !IsPlayer()) { return false; } @@ -144,15 +146,22 @@ bool cEntity::Initialize(cWorld & a_World) ); */ - ASSERT(m_World == nullptr); ASSERT(GetParentChunk() == nullptr); - a_World.AddEntity(this); - ASSERT(m_World != nullptr); + cpp14::move_on_copy_wrapper<decltype(a_Entity)> Entity(std::move(a_Entity)); + + // So that entities do not appear in the middle of ticks + a_EntityWorld.QueueTask( + [Entity, &a_EntityWorld](cWorld & a_World) + { + auto & EntityPtr = *Entity.value; - cPluginManager::Get()->CallHookSpawnedEntity(a_World, *this); + EntityPtr.SetWorld(&a_EntityWorld); + a_EntityWorld.AddEntity(std::move(Entity.value)); - // Spawn the entity on the clients: - a_World.BroadcastSpawnEntity(*this); + a_EntityWorld.BroadcastSpawnEntity(EntityPtr); + cPluginManager::Get()->CallHookSpawnedEntity(a_EntityWorld, EntityPtr); + } + ); return true; } @@ -209,8 +218,7 @@ cChunk * cEntity::GetParentChunk() const void cEntity::Destroy(bool a_ShouldBroadcast) { - ASSERT(IsTicking()); - ASSERT(GetParentChunk() != nullptr); + ASSERT(GetWorld()->IsInTickThread()); SetIsTicking(false); if (a_ShouldBroadcast) @@ -218,17 +226,20 @@ void cEntity::Destroy(bool a_ShouldBroadcast) m_World->BroadcastDestroyEntity(*this); } - cChunk * ParentChunk = GetParentChunk(); - m_World->QueueTask([this, ParentChunk](cWorld & a_World) - { - LOGD("Destroying entity #%i (%s) from chunk (%d, %d)", - this->GetUniqueID(), this->GetClass(), - ParentChunk->GetPosX(), ParentChunk->GetPosZ() - ); - ParentChunk->RemoveEntity(this); - delete this; - }); - Destroyed(); + // So that entities do not disappear unexpectedly during ticks + m_World->QueueTask( + [this](cWorld & a_World) + { + auto ParentChunk = GetParentChunk(); + LOGD("Destroying entity #%i (%s) from chunk (%d, %d)", + GetUniqueID(), GetClass(), + ParentChunk->GetPosX(), ParentChunk->GetPosZ() + ); + + Destroyed(); // TODO: rename to OnPreDestroy() + ParentChunk->RemoveEntity(*this); + } + ); } |