From 2928cb6853f1e007e98f174c37d75c793a0c09cc Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Thu, 16 Feb 2012 17:45:26 +0000 Subject: cWorldGenerator speedup - doesn't call GetChunk() anymore, not queueing the chunk it's generating to be loaded recursively. cChunk fix - setting a block to the same value doesn't mark chunk dirty (resulted in un-unloadable chunks) git-svn-id: http://mc-server.googlecode.com/svn/trunk@279 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/cChunk.cpp | 11 ++++++----- source/cChunk.h | 8 ++++---- source/cChunkGenerator.cpp | 19 ++++++++++++------- source/cChunkMap.cpp | 12 +++++++++++- source/cChunkMap.h | 15 ++++++++------- source/cMonsterConfig.cpp | 2 +- source/cWorld.cpp | 9 +++++++++ source/cWorld.h | 15 ++++++++------- source/cWorldGenerator.cpp | 21 +++++++++++++-------- source/cWorldGenerator.h | 7 +++++-- source/cWorldGenerator_Test.h | 4 ++++ 11 files changed, 81 insertions(+), 42 deletions(-) diff --git a/source/cChunk.cpp b/source/cChunk.cpp index 5ebf8b656..5bd6ca1e9 100644 --- a/source/cChunk.cpp +++ b/source/cChunk.cpp @@ -805,8 +805,6 @@ void cChunk::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_Block assert(IsValid()); // Is this chunk loaded / generated? - MarkDirty(); - int index = a_Y + (a_Z * 128) + (a_X * 128 * 16); char OldBlockMeta = GetLight( m_BlockMeta, index ); char OldBlockType = m_BlockType[index]; @@ -819,6 +817,8 @@ void cChunk::SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_Block return; } + MarkDirty(); + cCSLock Lock(m_CSBlockLists); m_PendingSendBlocks.push_back( index ); @@ -871,14 +871,15 @@ void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_B assert(IsValid()); - MarkDirty(); - const int index = a_Y + (a_Z * 128) + (a_X * 128 * 16); const char OldBlock = m_BlockType[index]; if (OldBlock == a_BlockType) { return; } + + MarkDirty(); + m_BlockType[index] = a_BlockType; { @@ -1107,7 +1108,7 @@ bool cChunk::HasClient( cClientHandle* a_Client ) -bool cChunk::HasAnyClient(void) +bool cChunk::HasAnyClients(void) { cCSLock Lock(m_CSClients); return !m_LoadedByClient.empty(); diff --git a/source/cChunk.h b/source/cChunk.h index ebaa21e34..66efa0d1e 100644 --- a/source/cChunk.h +++ b/source/cChunk.h @@ -114,10 +114,10 @@ public: void SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client ); - void AddClient ( cClientHandle* a_Client ); - void RemoveClient( cClientHandle* a_Client ); - bool HasClient ( cClientHandle* a_Client ); - bool HasAnyClient(void); // Returns true if theres any client in the chunk; false otherwise + void AddClient (cClientHandle* a_Client ); + void RemoveClient (cClientHandle* a_Client ); + bool HasClient (cClientHandle* a_Client ); + bool HasAnyClients(void); // Returns true if theres any client in the chunk; false otherwise void AddEntity( cEntity * a_Entity ); void RemoveEntity( cEntity * a_Entity); diff --git a/source/cChunkGenerator.cpp b/source/cChunkGenerator.cpp index 8755ea325..4d9aef421 100644 --- a/source/cChunkGenerator.cpp +++ b/source/cChunkGenerator.cpp @@ -53,11 +53,11 @@ bool cChunkGenerator::Start(cWorld * a_World, const AString & a_WorldGeneratorNa if (a_WorldGeneratorName.compare("Test") == 0 ) { - m_pWorldGenerator = new cWorldGenerator_Test(); + m_pWorldGenerator = new cWorldGenerator_Test(a_World); } else // Default { - m_pWorldGenerator = new cWorldGenerator(); + m_pWorldGenerator = new cWorldGenerator(a_World); } return super::Start(); @@ -129,17 +129,22 @@ void cChunkGenerator::Execute(void) bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT); Lock.Unlock(); // Unlock ASAP - cChunkPtr Chunk = m_World->GetChunk(coords.m_ChunkX, 0, coords.m_ChunkZ); - if ((Chunk != NULL) && (Chunk->IsValid() || (SkipEnabled && !Chunk->HasAnyClient()))) + if ( + m_World->IsChunkValid(coords.m_ChunkX, 0, coords.m_ChunkZ) || + (SkipEnabled && m_World->HasChunkAnyClients(coords.m_ChunkX, 0, coords.m_ChunkZ)) + ) { // Already generated / overload-skip, ignore request continue; } - + LOG("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); - m_pWorldGenerator->GenerateChunk(Chunk); + m_pWorldGenerator->GenerateChunk(coords.m_ChunkX, 0, coords.m_ChunkZ); - Chunk->SetValid(); + // Chunk->SetValid(); + + // Save the chunk right after generating, so that we don't have to generate it again on next run + m_World->GetStorage().QueueSaveChunk(coords.m_ChunkX, coords.m_ChunkZ); } // while (!bStop) } diff --git a/source/cChunkMap.cpp b/source/cChunkMap.cpp index 7b249dcae..dbe6607fc 100644 --- a/source/cChunkMap.cpp +++ b/source/cChunkMap.cpp @@ -276,6 +276,17 @@ bool cChunkMap::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +bool cChunkMap::HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + return (Chunk != NULL) && Chunk->HasAnyClients(); +} + + + + + void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom ) { cCSLock Lock(m_CSLayers); @@ -389,7 +400,6 @@ void cChunkMap::cChunkLayer::Save(void) void cChunkMap::cChunkLayer::UnloadUnusedChunks(void) { - cWorld * World = m_Parent->GetWorld(); for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) { if ((m_Chunks[i] != NULL) && (m_Chunks[i]->CanUnload())) diff --git a/source/cChunkMap.h b/source/cChunkMap.h index e53153c24..0b3e79931 100644 --- a/source/cChunkMap.h +++ b/source/cChunkMap.h @@ -36,13 +36,14 @@ public: void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL); void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // a_Player rclked block entity at the coords specified, handle it - void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); - void SetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); - void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); - bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkSaving (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void ChunkDataLoaded (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); + void SetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); + void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); + bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + bool HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ); void Tick( float a_Dt, MTRand & a_TickRand ); diff --git a/source/cMonsterConfig.cpp b/source/cMonsterConfig.cpp index 43c2ca689..7f4389e5f 100644 --- a/source/cMonsterConfig.cpp +++ b/source/cMonsterConfig.cpp @@ -105,7 +105,7 @@ void cMonsterConfig::AssignAttributes(cMonster *m, const char* n) m->SetAttackRange (itr->m_AttackRange); m->SetSightDistance(itr->m_SightDistance); m->SetAttackRate ((int)itr->m_AttackRate); - m->SetMaxHealth ((int)itr->m_MaxHealth); + m->SetMaxHealth ((short)itr->m_MaxHealth); } } // for itr - m_pState->AttributesList[] } diff --git a/source/cWorld.cpp b/source/cWorld.cpp index fc6941250..81058cd93 100644 --- a/source/cWorld.cpp +++ b/source/cWorld.cpp @@ -1009,6 +1009,15 @@ bool cWorld::IsChunkValid(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const +bool cWorld::HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const +{ + return m_ChunkMap->HasChunkAnyClients(a_ChunkX, a_ChunkY, a_ChunkZ); +} + + + + + void cWorld::SetMaxPlayers(int iMax) { m_MaxPlayers = MAX_PLAYERS; diff --git a/source/cWorld.h b/source/cWorld.h index 025d0782a..70b502780 100644 --- a/source/cWorld.h +++ b/source/cWorld.h @@ -70,13 +70,14 @@ public: void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL); - void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ); - void ChunkDataLoaded(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); - void SetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); - void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); - bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; + void MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkSaving (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ); + void ChunkDataLoaded (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); + void SetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, const char * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities); + void GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback * a_Callback); + bool IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; + bool HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const; // MOTD const AString & GetDescription(void) const {return m_Description; } diff --git a/source/cWorldGenerator.cpp b/source/cWorldGenerator.cpp index 5d087014b..fcbbcdad3 100644 --- a/source/cWorldGenerator.cpp +++ b/source/cWorldGenerator.cpp @@ -14,7 +14,8 @@ -cWorldGenerator::cWorldGenerator() +cWorldGenerator::cWorldGenerator(cWorld * a_World) : + m_World(a_World) { } @@ -30,15 +31,19 @@ cWorldGenerator::~cWorldGenerator() -void cWorldGenerator::GenerateChunk( cChunkPtr a_Chunk ) +void cWorldGenerator::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { - assert(!a_Chunk->IsValid()); + // TODO: use a raw char array instead of the entire chunk, then set it as chunk's blockdata - memset(a_Chunk->pGetBlockData(), 0, cChunk::c_BlockDataSize); - GenerateTerrain( a_Chunk ); - GenerateFoliage( a_Chunk ); - a_Chunk->CalculateHeightmap(); - a_Chunk->CalculateLighting(); + cChunkPtr Chunk = m_World->GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); + assert(!Chunk->IsValid()); + + memset(Chunk->pGetBlockData(), 0, cChunk::c_BlockDataSize); + GenerateTerrain(Chunk); + GenerateFoliage(Chunk); + Chunk->CalculateHeightmap(); + Chunk->CalculateLighting(); + Chunk->SetValid(); } diff --git a/source/cWorldGenerator.h b/source/cWorldGenerator.h index 933105d24..208178d4a 100644 --- a/source/cWorldGenerator.h +++ b/source/cWorldGenerator.h @@ -15,13 +15,16 @@ class cWorldGenerator { public: - cWorldGenerator(); + cWorldGenerator(cWorld * a_World); ~cWorldGenerator(); - virtual void GenerateChunk( cChunkPtr a_Chunk ); + virtual void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); protected: + cWorld * m_World; + + // Thread-unsafe: MTRand r1; virtual void GenerateTerrain( cChunkPtr a_Chunk ); diff --git a/source/cWorldGenerator_Test.h b/source/cWorldGenerator_Test.h index 0dd9d5b1c..5a5483fa9 100644 --- a/source/cWorldGenerator_Test.h +++ b/source/cWorldGenerator_Test.h @@ -10,6 +10,10 @@ class cWorldGenerator_Test : public cWorldGenerator { +public: + + cWorldGenerator_Test(cWorld * a_World) : cWorldGenerator(a_World) {} + protected: virtual void GenerateTerrain( cChunkPtr a_Chunk ) override; virtual void GenerateFoliage( cChunkPtr a_Chunk ) override; -- cgit v1.2.3