diff options
-rw-r--r-- | src/Entities/Entity.cpp | 21 | ||||
-rw-r--r-- | src/World.cpp | 30 | ||||
-rw-r--r-- | src/World.h | 4 |
3 files changed, 44 insertions, 11 deletions
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index c31f05211..b78c4dd82 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -223,8 +223,6 @@ cChunk * cEntity::GetParentChunk() void cEntity::Destroy(bool a_ShouldBroadcast) { - ASSERT(IsTicking()); - ASSERT(GetParentChunk() != nullptr); SetIsTicking(false); // Unleash leashed mobs @@ -238,17 +236,17 @@ void cEntity::Destroy(bool a_ShouldBroadcast) m_World->BroadcastDestroyEntity(*this); } - cChunk * ParentChunk = GetParentChunk(); - m_World->QueueTask([this, ParentChunk](cWorld & a_World) + auto ParentChunkCoords = cChunkDef::BlockToChunk(GetPosition()); + m_World->QueueTask([this, ParentChunkCoords](cWorld & a_World) { LOGD("Destroying entity #%i (%s) from chunk (%d, %d)", this->GetUniqueID(), this->GetClass(), - ParentChunk->GetPosX(), ParentChunk->GetPosZ() + ParentChunkCoords.m_ChunkX, ParentChunkCoords.m_ChunkZ ); // Make sure that RemoveEntity returned a valid smart pointer // Also, not storing the returned pointer means automatic destruction - VERIFY(ParentChunk->RemoveEntity(*this)); + VERIFY(a_World.RemoveEntity(*this)); }); Destroyed(); } @@ -1565,7 +1563,6 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d { UNUSED(a_ShouldSendRespawn); ASSERT(a_World != nullptr); - ASSERT(IsTicking()); if (GetWorld() == a_World) { @@ -1586,6 +1583,9 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d // Tell others we are gone GetWorld()->BroadcastDestroyEntity(*this); + // Take note of old chunk coords + auto OldChunkCoords = cChunkDef::BlockToChunk(GetPosition()); + // Set position to the new position SetPosition(a_NewPosition); @@ -1600,16 +1600,15 @@ bool cEntity::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn, Vector3d // Queue add to new world and removal from the old one cWorld * OldWorld = GetWorld(); - cChunk * ParentChunk = GetParentChunk(); SetWorld(a_World); // Chunks may be streamed before cWorld::AddPlayer() sets the world to the new value - OldWorld->QueueTask([this, ParentChunk, a_World](cWorld & a_OldWorld) + OldWorld->QueueTask([this, OldChunkCoords, a_World](cWorld & a_OldWorld) { LOGD("Warping entity #%i (%s) from world \"%s\" to \"%s\". Source chunk: (%d, %d) ", this->GetUniqueID(), this->GetClass(), a_OldWorld.GetName().c_str(), a_World->GetName().c_str(), - ParentChunk->GetPosX(), ParentChunk->GetPosZ() + OldChunkCoords.m_ChunkX, OldChunkCoords.m_ChunkZ ); - a_World->AddEntity(ParentChunk->RemoveEntity(*this)); + a_World->AddEntity(a_OldWorld.RemoveEntity(*this)); cRoot::Get()->GetPluginManager()->CallHookEntityChangedWorld(*this, a_OldWorld); }); return true; diff --git a/src/World.cpp b/src/World.cpp index acec3049e..0ecf9a274 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -3709,6 +3709,36 @@ bool cWorld::HasEntity(UInt32 a_UniqueID) +OwnedEntity cWorld::RemoveEntity(cEntity & a_Entity) +{ + // Check if the entity is in the chunkmap: + auto Entity = m_ChunkMap->RemoveEntity(a_Entity); + if (Entity != nullptr) + { + return Entity; + } + + // Check if the entity is in the queue to be added to the world: + cCSLock Lock(m_CSEntitiesToAdd); + auto itr = std::find_if(m_EntitiesToAdd.begin(), m_EntitiesToAdd.end(), + [&a_Entity](const OwnedEntity & a_OwnedEntity) + { + return (a_OwnedEntity.get() == &a_Entity); + } + ); + + if (itr != m_EntitiesToAdd.end()) + { + Entity = std::move(*itr); + m_EntitiesToAdd.erase(itr); + } + return Entity; +} + + + + + /* unsigned int cWorld::GetNumPlayers(void) { diff --git a/src/World.h b/src/World.h index cbaf9cb95..b1a5e8d79 100644 --- a/src/World.h +++ b/src/World.h @@ -301,6 +301,10 @@ public: Note: Only loaded chunks are considered. */ bool HasEntity(UInt32 a_UniqueID); + /** Removes the entity from the world. + Returns an owning reference to the found entity. */ + OwnedEntity RemoveEntity(cEntity & a_Entity); + /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp |