diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 0256e02c4..83a9e1518 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 01/01/12 05:42:24. +** Generated automatically by tolua++-1.0.92 on 01/01/12 17:14:14. */ #ifndef __cplusplus @@ -8907,6 +8907,69 @@ static int tolua_AllToLua_cWorld_GetName00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: SaveAllChunks of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_SaveAllChunks00 +static int tolua_AllToLua_cWorld_SaveAllChunks00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SaveAllChunks'", NULL); +#endif + { + self->SaveAllChunks(); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'SaveAllChunks'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetNumChunks of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GetNumChunks00 +static int tolua_AllToLua_cWorld_GetNumChunks00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumChunks'", NULL); +#endif + { + int tolua_ret = (int) self->GetNumChunks(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetNumChunks'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: CastThunderbolt of class cWorld */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_CastThunderbolt00 static int tolua_AllToLua_cWorld_CastThunderbolt00(lua_State* tolua_S) @@ -16108,6 +16171,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GrowTree",tolua_AllToLua_cWorld_GrowTree00); tolua_function(tolua_S,"GetWorldSeed",tolua_AllToLua_cWorld_GetWorldSeed00); tolua_function(tolua_S,"GetName",tolua_AllToLua_cWorld_GetName00); + tolua_function(tolua_S,"SaveAllChunks",tolua_AllToLua_cWorld_SaveAllChunks00); + tolua_function(tolua_S,"GetNumChunks",tolua_AllToLua_cWorld_GetNumChunks00); tolua_function(tolua_S,"CastThunderbolt",tolua_AllToLua_cWorld_CastThunderbolt00); tolua_function(tolua_S,"SetWeather",tolua_AllToLua_cWorld_SetWeather00); tolua_function(tolua_S,"GetWeather",tolua_AllToLua_cWorld_GetWeather00); diff --git a/source/Bindings.h b/source/Bindings.h index 5b0973d35..b0ca12919 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 01/01/12 05:42:24. +** Generated automatically by tolua++-1.0.92 on 01/01/12 17:14:15. */ /* Exported function */ diff --git a/source/cChunk.cpp b/source/cChunk.cpp index fae2c2507..47e92555f 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -52,12 +52,18 @@ extern bool g_bWaterPhysics; +typedef std::map< int, std::string > ReferenceMap; typedef std::list< cFurnaceEntity* > FurnaceEntityList; typedef std::list< cClientHandle* > ClientHandleList; typedef std::list< cBlockEntity* > BlockEntityList; typedef std::list< cEntity* > EntityList; struct cChunk::sChunkState { + sChunkState() + : TotalReferencesEver( 0 ) + , MinusReferences( 0 ) + {} + FurnaceEntityList TickBlockEntities; std::map< unsigned int, int > ToTickBlocks; // Protected by BlockListCriticalSection std::vector< unsigned int > PendingSendBlocks; // Protected by BlockListCriticalSection @@ -67,6 +73,12 @@ struct cChunk::sChunkState EntityList Entities; cCriticalSection BlockListCriticalSection; + + // Reference counting + cCriticalSection ReferenceCriticalSection; + ReferenceMap References; + int MinusReferences; // References.size() - MinusReferences = Actual amount of references. This is due to removal of reference without an ID (don't know which to remove, so remove none) + int TotalReferencesEver; // For creating a unique reference ID }; cChunk::~cChunk() @@ -77,6 +89,13 @@ cChunk::~cChunk() LOGWARN("WARNING: Deleting cChunk while it contains %i clients!", m_pState->LoadedByClient.size() ); } + m_pState->ReferenceCriticalSection.Lock(); + if( GetReferenceCount() > 0 ) + { + LOGWARN("WARNING: Deleting cChunk while it still has %i references!", GetReferenceCount() ); + } + m_pState->ReferenceCriticalSection.Unlock(); + m_pState->BlockListCriticalSection.Lock(); for( std::list::iterator itr = m_pState->BlockEntities.begin(); itr != m_pState->BlockEntities.end(); ++itr) { @@ -1158,6 +1177,63 @@ void cChunk::PositionToWorldPosition(int a_ChunkX, int a_ChunkY, int a_ChunkZ, i a_Z = m_PosZ * 16 + a_ChunkZ; } +int cChunk::AddReference( const char* a_Info /* = 0 */ ) +{ + m_pState->ReferenceCriticalSection.Lock(); + + m_pState->TotalReferencesEver++; + + std::string Info; + if( a_Info ) Info = a_Info; + + m_pState->References[ m_pState->TotalReferencesEver ] = Info; + + int ID = m_pState->TotalReferencesEver; + m_pState->ReferenceCriticalSection.Unlock(); + return ID; +} + +void cChunk::RemoveReference( int a_ID ) +{ + m_pState->ReferenceCriticalSection.Lock(); + + if( a_ID > -1 ) // Remove reference with an ID + { + bool bFound = false; + for( ReferenceMap::iterator itr = m_pState->References.begin(); itr != m_pState->References.end(); ++itr ) + { + if( itr->first == a_ID ) + { + bFound = true; + m_pState->References.erase( itr ); + break; + } + } + + if( !bFound ) + { + LOGWARN("WARNING: cChunk: Tried to remove reference %i but it could not be found! May cause memory leak", a_ID ); + } + } + else // No ID so add one to MinusReferences + { + m_pState->MinusReferences++; + if( (int)m_pState->References.size() - m_pState->MinusReferences < 0 ) + { + LOGWARN("WARNING: cChunk: Tried to remove reference %i, but the chunk is not referenced!", a_ID); + } + } + + m_pState->ReferenceCriticalSection.Unlock(); +} + +int cChunk::GetReferenceCount() +{ + m_pState->ReferenceCriticalSection.Unlock(); + int Refs = (int)m_pState->References.size() - m_pState->MinusReferences; + m_pState->ReferenceCriticalSection.Lock(); + return Refs; +} #if !C_CHUNK_USE_INLINE # include "cChunk.inc" diff --git a/source/cChunk.h b/source/cChunk.h index fcf258bab..8555e01cf 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -100,6 +100,11 @@ public: static const int c_NumBlocks = 16*128*16; static const int c_BlockDataSize = c_NumBlocks * 2 + (c_NumBlocks/2); // 2.5 * numblocks + + // Reference counting + int AddReference( const char* a_Info = 0 ); // a_Info is for debugging + void RemoveReference( int a_ID = -1 ); + int GetReferenceCount(); private: struct sChunkState; sChunkState* m_pState; diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 90b3258e7..d05fd4a43 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -462,7 +462,7 @@ void cChunkMap::UnloadUnusedChunks() for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i ) { cChunk* Chunk = Layer.m_Chunks[i].m_LiveChunk; - if( Chunk && Chunk->GetClients().size() == 0 ) + if( Chunk && Chunk->GetClients().size() == 0 && Chunk->GetReferenceCount() <= 0 ) { Chunk->SaveToDisk(); World->RemoveSpread( Chunk ); @@ -716,3 +716,13 @@ cChunkMap::cChunkLayer* cChunkMap::LoadLayer(int a_LayerX, int a_LayerZ ) } return 0; } + +int cChunkMap::GetNumChunks() +{ + int NumChunks = 0; + for( int i = 0; i < m_NumLayers; ++i ) + { + NumChunks += m_Layers[i].m_NumChunksLoaded; + } + return NumChunks; +} \ No newline at end of file diff --git a/source/cChunkMap.h b/source/cChunkMap.h index c728514e1..b2292870f 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -22,6 +22,8 @@ public: void SaveAllChunks(); cWorld* GetWorld() { return m_World; } + + int GetNumChunks(); private: class cChunkData { diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 5daa53138..10364243e 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -127,7 +127,7 @@ cClientHandle::cClientHandle(const cSocket & a_Socket) , m_pState( new sClientHandleState ) , m_Ping(1000) { - LOG("cClientHandle::cClientHandle"); + LOG("cClientHandle::cClientHandle"); cTimer t1; m_LastPingTime = t1.GetNowTime(); @@ -239,9 +239,9 @@ cClientHandle::~cClientHandle() if(m_Player) { m_Player->SetClientHandle( 0 ); - m_Player->Destroy(); - m_Player = 0; - } + m_Player->Destroy(); + m_Player = 0; + } for(int i = 0; i < 256; i++) { if( m_pState->PacketMap[i] ) @@ -990,7 +990,7 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) LOG("Dir: %i", PacketData->m_Direction); if( PacketData->m_Direction == 1 ) { - LOG("Player Rotation: %f", m_Player->GetRotation() ); + LOG("Player Rotation: %f", m_Player->GetRotation() ); MetaData = cSign::RotationToMetaData( m_Player->GetRotation() ); LOG("Sign rotation %i", MetaData); PacketData->m_ItemType = E_BLOCK_SIGN_POST; @@ -1215,7 +1215,7 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) break; case E_DISCONNECT: { - LOG("Received d/c packet from %s", GetUsername() ); + LOG("Received d/c packet from %s", GetUsername() ); cPacket_Disconnect* PacketData = reinterpret_cast(a_Packet); if( !cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_DISCONNECT, 2, PacketData->m_Reason.c_str(), m_Player ) ) { @@ -1237,7 +1237,7 @@ void cClientHandle::HandlePacket( cPacket* a_Packet ) } break; default: - break; + break; } } } @@ -1362,7 +1362,7 @@ void cClientHandle::Send( const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* } } break; - default: + default: break; } if( bBreak ) diff --git a/source/cServer.cpp b/source/cServer.cpp index 81444f8e1..d3e8e43a7 100644 --- a/source/cServer.cpp +++ b/source/cServer.cpp @@ -470,7 +470,7 @@ void cServer::ServerCommand( const char* a_Cmd ) } if( split[0].compare( "numchunks" ) == 0 ) { - //printf("Num loaded chunks: %i\n", cRoot::Get()->GetWorld()->GetChunks().size() ); + printf("Num loaded chunks: %i\n", cRoot::Get()->GetWorld()->GetNumChunks() ); return; } if(split[0].compare("monsters") == 0 ){ diff --git a/source/cWorld.cpp b/source/cWorld.cpp index 0b1ee7010..d10d01a0d 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -434,7 +434,8 @@ void cWorld::Tick(float a_Dt) //LOG("Spreading: %p", Chunk ); Chunk->SpreadLight( Chunk->pGetSkyLight() ); Chunk->SpreadLight( Chunk->pGetLight() ); - m_pState->SpreadQueue.remove( &*Chunk ); + m_pState->SpreadQueue.remove( Chunk ); + Chunk->RemoveReference(); TimesSpreaded++; } if( TimesSpreaded >= 50 ) @@ -676,6 +677,7 @@ void cWorld::UnloadUnusedChunks() m_LastUnload = m_Time; LockChunks(); + LOGINFO("Unloading unused chunks"); m_ChunkMap->UnloadUnusedChunks(); UnlockChunks(); } @@ -1055,13 +1057,18 @@ void cWorld::ReSpreadLighting( cChunk* a_Chunk ) LockChunks(); m_pState->SpreadQueue.remove( a_Chunk ); m_pState->SpreadQueue.push_back( a_Chunk ); +#define STRINGIZE(x) #x + a_Chunk->AddReference( __FILE__ ": " STRINGIZE(__LINE__) ); UnlockChunks(); } void cWorld::RemoveSpread( cChunk* a_Chunk ) { LockChunks(); + size_t SizeBefore = m_pState->SpreadQueue.size(); m_pState->SpreadQueue.remove( a_Chunk ); + if( SizeBefore != m_pState->SpreadQueue.size() ) + a_Chunk->RemoveReference(); UnlockChunks(); } @@ -1102,3 +1109,10 @@ const char* cWorld::GetName() { return m_pState->WorldName.c_str(); } +int cWorld::GetNumChunks() +{ + LockChunks(); + int NumChunks = m_ChunkMap->GetNumChunks(); + UnlockChunks(); + return NumChunks; +} \ No newline at end of file diff --git a/source/cWorld.h b/source/cWorld.h index 47c60fb87..ab99c11b1 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -134,7 +134,8 @@ public: if(a_Z < 0 && a_Z % 16 != 0) a_ChunkZ--; } - void SaveAllChunks(); + void SaveAllChunks(); //tolua_export + int GetNumChunks(); //tolua_export void Tick(float a_Dt);