From 6e681269d9dfb33b5b73f4f01a61def247b3aee7 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 21 Jun 2014 22:07:38 +0100 Subject: Fixed invalid iterators --- src/Chunk.cpp | 33 ++++++++++----------------------- src/Chunk.h | 1 - src/Entities/Entity.cpp | 3 ++- src/Entities/Entity.h | 10 +++++++++- src/Entities/Player.cpp | 1 + src/World.cpp | 14 ++++---------- src/World.h | 3 --- 7 files changed, 26 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 8255fdcaf..727eb451d 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -71,7 +71,6 @@ cChunk::cChunk( m_IsDirty(false), m_IsSaving(false), m_HasLoadFailed(false), - m_EntityTickIteratorData(std::make_pair(false, m_Entities.end())), m_StayCount(0), m_PosX(a_ChunkX), m_PosY(a_ChunkY), @@ -577,44 +576,39 @@ void cChunk::Tick(float a_Dt) } // Tick all entities in this chunk (except mobs): - m_EntityTickIteratorData.first = true; - for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { // Mobs are ticked inside cWorld::TickMobs() (as we don't have to tick them if they are far away from players) // Don't tick things queued to be removed if (!((*itr)->IsMob())) { - m_EntityTickIteratorData.second = itr; (*itr)->Tick(a_Dt, *this); - - if (itr != m_EntityTickIteratorData.second) - { - itr = m_EntityTickIteratorData.second; - } - else - { - ++itr; - } continue; } - ++itr; } // for itr - m_Entitites[] - m_EntityTickIteratorData.first = false; for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end();) { if ((*itr)->IsDestroyed()) // Remove all entities that were scheduled for removal: { LOGD("Destroying entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); + MarkDirty(); cEntity * ToDelete = *itr; itr = m_Entities.erase(itr); delete ToDelete; } + else if ((*itr)->IsTravellingThroughPortal()) + { + MarkDirty(); + (*itr)->SetIsTravellingThroughPortal(false); + itr = m_Entities.erase(itr); + } else if ( // If any entity moved out of the chunk, move it to the neighbor: ((*itr)->GetChunkX() != m_PosX) || ((*itr)->GetChunkZ() != m_PosZ) ) { + MarkDirty(); MoveEntityToNewChunk(*itr); itr = m_Entities.erase(itr); } @@ -1874,14 +1868,7 @@ void cChunk::AddEntity(cEntity * a_Entity) void cChunk::RemoveEntity(cEntity * a_Entity) { - if (m_EntityTickIteratorData.first) - { - m_EntityTickIteratorData.second = m_Entities.erase(m_EntityTickIteratorData.second); - } - else - { - m_Entities.remove(a_Entity); - } + m_Entities.remove(a_Entity); // Mark as dirty if it was a server-generated entity: if (!a_Entity->IsPlayer()) diff --git a/src/Chunk.h b/src/Chunk.h index 1619df333..dfdabea04 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -425,7 +425,6 @@ private: // A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers cClientHandleList m_LoadedByClient; cEntityList m_Entities; - std::pair m_EntityTickIteratorData; 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/Entities/Entity.cpp b/src/Entities/Entity.cpp index 9110cd83b..9a8c6586d 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -57,6 +57,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Width(a_Width) , m_Height(a_Height) , m_InvulnerableTicks(0) + , m_IsTravellingThroughPortal(false) { cCSLock Lock(m_CSCount); m_EntityCount++; @@ -1183,7 +1184,7 @@ bool cEntity::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ } // Remove all links to the old world - GetWorld()->RemoveEntity(this); + SetIsTravellingThroughPortal(true); // cChunk handles entity removal GetWorld()->BroadcastDestroyEntity(*this); // Queue add to new world diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 8975803a2..0293968ab 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -374,6 +374,12 @@ public: virtual bool MoveToWorld(const AString & a_WorldName, cWorld * a_World = NULL, bool a_ShouldSendRespawn = true); // tolua_end + + /** Returns if the entity is travelling through a portal. Set to true by MoveToWorld and to false when the entity is removed by the old chunk */ + bool IsTravellingThroughPortal(void) const { return m_IsTravellingThroughPortal; } + + /** Sets if the entity has begun travelling through a portal or not */ + void SetIsTravellingThroughPortal(bool a_Flag) { m_IsTravellingThroughPortal = a_Flag; } /// Updates clients of changes in the entity. virtual void BroadcastMovementUpdate(const cClientHandle * a_Exclude = NULL); @@ -470,6 +476,9 @@ protected: /** True when entity is initialised (Initialize()) and false when destroyed pending deletion (Destroy()) */ bool m_IsInitialized; + /** True when entity is being moved across worlds, false anytime else */ + bool m_IsTravellingThroughPortal; + eEntityType m_EntityType; cWorld * m_World; @@ -492,7 +501,6 @@ protected: /// Time, in ticks, since the last damage dealt by the void. Reset to zero when moving out of the void. int m_TicksSinceLastVoidDamage; - virtual void Destroyed(void) {} // Called after the entity has been destroyed /** Called in each tick to handle air-related processing i.e. drowning */ diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index e975abdf5..b72f14f57 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1600,6 +1600,7 @@ bool cPlayer::MoveToWorld(const AString & a_WorldName, cWorld * a_World, bool a_ } // Remove player from the old world + SetIsTravellingThroughPortal(true); // cChunk handles entity removal m_World->RemovePlayer(this); // Queue adding player to the new world, including all the necessary adjustments to the object diff --git a/src/World.cpp b/src/World.cpp index 3ed2f5f13..c9199b6ba 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2417,7 +2417,10 @@ void cWorld::AddPlayer(cPlayer * a_Player) void cWorld::RemovePlayer(cPlayer * a_Player) { - m_ChunkMap->RemoveEntity(a_Player); + if (!a_Player->IsTravellingThroughPortal()) + { + m_ChunkMap->RemoveEntity(a_Player); + } { cCSLock Lock(m_CSPlayersToAdd); m_PlayersToAdd.remove(a_Player); @@ -2919,15 +2922,6 @@ bool cWorld::HasEntity(int a_UniqueID) -void cWorld::RemoveEntity(cEntity * a_Entity) -{ - m_ChunkMap->RemoveEntity(a_Entity); -} - - - - - /* unsigned int cWorld::GetNumPlayers(void) { diff --git a/src/World.h b/src/World.h index 0592c78fc..1d9026a5d 100644 --- a/src/World.h +++ b/src/World.h @@ -313,9 +313,6 @@ public: bool HasEntity(int a_UniqueID); - /** Removes the entity, the entity ptr ownership is assumed taken by the caller */ - void 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 -- cgit v1.2.3