diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 430fa6fc8..420ba078f 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -70,14 +70,19 @@ cChunk::~cChunk() m_pState->m_BlockEntities.clear(); LockEntities(); - for( EntityList::iterator itr = m_pState->m_Entities.begin(); itr != m_pState->m_Entities.end(); ++itr) + if( m_pState->m_Entities.size() > 0 ) { - if( (*itr)->GetEntityType() != cEntity::E_PLAYER ) + EntityList Entities = m_pState->m_Entities; // Copy list to a temporary list + for( EntityList::iterator itr = Entities.begin(); itr != Entities.end(); ++itr) { - m_World->AddToRemoveEntityQueue( **itr ); // World also destroys the entity + if( (*itr)->GetEntityType() != cEntity::E_PLAYER ) + { + (*itr)->RemoveFromChunk( this ); + (*itr)->Destroy(); + } } + m_pState->m_Entities.clear(); } - m_pState->m_Entities.clear(); UnlockEntities(); if( m_EntitiesCriticalSection ) @@ -1027,14 +1032,17 @@ void cChunk::RemoveClient( cClientHandle* a_Client ) { m_pState->m_LoadedByClient.remove( a_Client ); - LockEntities(); - for( EntityList::iterator itr = m_pState->m_Entities.begin(); itr != m_pState->m_Entities.end(); ++itr ) + if( !a_Client->IsDestroyed() ) { - LOG("%i %i %i Destroying on %s", m_PosX, m_PosY, m_PosZ, a_Client->GetUsername() ); - cPacket_DestroyEntity DestroyEntity( *itr ); - a_Client->Send( DestroyEntity ); + LockEntities(); + for( EntityList::iterator itr = m_pState->m_Entities.begin(); itr != m_pState->m_Entities.end(); ++itr ) + { + LOG("%i %i %i Destroying on %s", m_PosX, m_PosY, m_PosZ, a_Client->GetUsername() ); + cPacket_DestroyEntity DestroyEntity( *itr ); + a_Client->Send( DestroyEntity ); + } + UnlockEntities(); } - UnlockEntities(); } void cChunk::AddEntity( cEntity & a_Entity ) diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index a694ea97e..621e8a19e 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -432,7 +432,9 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) } // Now initialize player (adds to entity list etc.) - m_Player->Initialize( cRoot::Get()->GetDefaultWorld() ); // TODO - Get correct world for player + cWorld* PlayerWorld = cRoot::Get()->GetWorld( m_Player->GetLoadedWorldName() ); + if( !PlayerWorld ) PlayerWorld = cRoot::Get()->GetDefaultWorld(); + m_Player->Initialize( PlayerWorld ); // TODO - Get correct world for player // Broadcasts to all but this ( this is actually handled in cChunk.cpp, after entity is added to the chunk ) //m_Player->SpawnOn( 0 ); @@ -937,13 +939,15 @@ void cClientHandle::Tick(float a_Dt) { m_bSendLoginResponse = false; - cWorld* World = cRoot::Get()->GetDefaultWorld(); // TODO - Get the correct world or better yet, move this to the main thread so we don't have to lock anything - World->LockEntities(); // Spawn player (only serversided, so data is loaded) m_Player = new cPlayer( this, GetUsername() ); // !!DO NOT INITIALIZE!! <- is done after receiving MoveLook Packet + + cWorld* World = cRoot::Get()->GetWorld( m_Player->GetLoadedWorldName() ); // TODO - Get the correct world or better yet, move this to the main thread so we don't have to lock anything + if( !World ) World = cRoot::Get()->GetDefaultWorld(); + World->LockEntities(); m_Player->SetGameMode ( World->GetGameMode() ); //set player's gamemode to server's gamemode at login. - cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_PLAYER_SPAWN, 1, m_Player ); // TODO - this function is called from a seperate thread, which might be dangerous + cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_PLAYER_SPAWN, 1, m_Player ); // Return a server login packet cPacket_Login LoginResponse; diff --git a/source/cEntity.cpp b/source/cEntity.cpp index c22be3def..b9cbbd9f6 100644 --- a/source/cEntity.cpp +++ b/source/cEntity.cpp @@ -28,6 +28,7 @@ cEntity::cEntity(const double & a_X, const double & a_Y, const double & a_Z) , m_bDestroyed( false ) , m_EntityType( E_ENTITY ) , m_World( 0 ) + , m_bRemovedFromChunk( false ) { m_EntityCount++; m_UniqueID = m_EntityCount; @@ -35,18 +36,12 @@ cEntity::cEntity(const double & a_X, const double & a_Y, const double & a_Z) cEntity::~cEntity() { + if( !m_bDestroyed || !m_bRemovedFromChunk ) + { + LOGERROR("ERROR: Entity deallocated without being destroyed %i or unlinked %i", m_bDestroyed, m_bRemovedFromChunk ); + } delete m_Referencers; delete m_References; - if( m_World ) - { - cChunk* Chunk = m_World->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ ); - if( Chunk ) - { - cPacket_DestroyEntity DestroyEntity( this ); - Chunk->Broadcast( DestroyEntity ); - Chunk->RemoveEntity( *this ); - } - } delete m_Pos; delete m_Rot; } @@ -143,6 +138,30 @@ void cEntity::MoveToCorrectChunk() } } +void cEntity::Destroy() +{ + if( !m_bDestroyed ) + { + m_bDestroyed = true; + if( !m_bRemovedFromChunk ) + RemoveFromChunk(0); + } +} + +void cEntity::RemoveFromChunk( cChunk* a_Chunk ) +{ + if( m_World ) + { + cChunk* Chunk = ( a_Chunk ? a_Chunk : m_World->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ ) ); + if( Chunk ) + { + cPacket_DestroyEntity DestroyEntity( this ); + Chunk->Broadcast( DestroyEntity ); + Chunk->RemoveEntity( *this ); + m_bRemovedFromChunk = true; + } + } +} CLASS_DEF_GETCLASS( cEntity ); bool cEntity::IsA( const char* a_EntityType ) diff --git a/source/cEntity.h b/source/cEntity.h index 509a5c1d5..c25c3e293 100644 --- a/source/cEntity.h +++ b/source/cEntity.h @@ -27,6 +27,7 @@ CLASS_DEF_ISA( classname, superclass ) \ CLASS_DEF_GETCLASS( classname ) +class cChunk; class cWorld; class cReferenceManager; class Vector3d; @@ -76,7 +77,8 @@ public: //tolua_export inline int GetUniqueID() { return m_UniqueID; } //tolua_export inline bool IsDestroyed() { return m_bDestroyed; } //tolua_export - void Destroy() { m_bDestroyed = true; } //tolua_export + void Destroy(); //tolua_export + void RemoveFromChunk( cChunk* a_Chunk ); // for internal use in cChunk virtual void Tick(float a_Dt) = 0; //tolua_export @@ -105,6 +107,7 @@ protected: bool m_bDirtyOrientation; bool m_bDestroyed; + bool m_bRemovedFromChunk; ENUM_ENTITY_TYPE m_EntityType; private: diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp index 69e163629..85eec3e2d 100644 --- a/source/cPlayer.cpp +++ b/source/cPlayer.cpp @@ -55,6 +55,7 @@ struct cPlayer::sPlayerState cPlayer::GroupList Groups; std::string PlayerName; + std::string LoadedWorldName; }; cPlayer::cPlayer(cClientHandle* a_Client, const char* a_PlayerName) @@ -110,7 +111,7 @@ cPlayer::~cPlayer(void) m_Inventory = 0; } delete m_pState; - cRoot::Get()->GetWorld()->RemovePlayer( this ); // TODO - Remove from correct world? Or get rid of this? + GetWorld()->RemovePlayer( this ); // TODO - Remove from correct world? Or get rid of this? } @@ -702,6 +703,8 @@ bool cPlayer::LoadFromDisk() // TODO - This should also get/set/whatever the cor m_Health = (short)root.get("health", 0 ).asInt(); m_Inventory->LoadFromJson(root["inventory"]); + + m_pState->LoadedWorldName = root.get("world", "world").asString(); return true; } @@ -731,6 +734,7 @@ bool cPlayer::SaveToDisk() root["rotation"] = JSON_PlayerRotation; root["inventory"] = JSON_Inventory; root["health"] = m_Health; + root["world"] = GetWorld()->GetName(); Json::StyledWriter writer; std::string JsonData = writer.write( root ); @@ -769,3 +773,8 @@ const cPlayer::GroupList & cPlayer::GetGroups() { return m_pState->Groups; } + +const char* cPlayer::GetLoadedWorldName() +{ + return m_pState->LoadedWorldName.c_str(); +} \ No newline at end of file diff --git a/source/cPlayer.h b/source/cPlayer.h index 4dedde727..fc546bd8d 100644 --- a/source/cPlayer.h +++ b/source/cPlayer.h @@ -56,7 +56,7 @@ public: bool CanUseCommand( const char* a_Command ); //tolua_export bool HasPermission( const char* a_Permission ); //tolua_export const GroupList & GetGroups(); // >> EXPORTED IN MANUALBINDINGS << - bool IsInGroup( const char* a_Group ); //tolua_export + bool IsInGroup( const char* a_Group ); //tolua_export std::string GetColor(); //tolua_export @@ -73,6 +73,8 @@ public: bool SaveToDisk(); bool LoadFromDisk(); + const char* GetLoadedWorldName(); + //Burning logic bool m_bBurnable; enum PMetaState{NORMAL,BURNING,CROUCHED,RIDING} e_EPMetaState; diff --git a/source/cWorld.cpp b/source/cWorld.cpp index a5f4bf1c3..c67998064 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -88,6 +88,7 @@ cWorld::~cWorld() { cEntity* Entity = *m_pState->m_AllEntities.begin(); m_pState->m_AllEntities.remove( Entity ); + if( !Entity->IsDestroyed() ) Entity->Destroy(); RemoveEntity( Entity ); } UnlockEntities(); diff --git a/source/cWorld.h b/source/cWorld.h index 383ffaec3..10f73fae3 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -56,7 +56,6 @@ public: cPlayer* GetPlayer( const char* a_PlayerName ); //tolua_export void AddEntity( cEntity* a_Entity ); - void AddToRemoveEntityQueue( cEntity & a_Entity ); bool RemoveEntityFromChunk( cEntity & a_Entity, cChunk* a_CalledFrom = 0 ); EntityList & GetEntities(); @@ -129,6 +128,7 @@ private: struct sWorldState; sWorldState* m_pState; + void AddToRemoveEntityQueue( cEntity & a_Entity ); void RemoveEntity( cEntity* a_Entity ); void UnloadUnusedChunks();