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
master
madmaxoft@gmail.com 2012-02-16 17:45:26 +00:00
parent 008addf5d7
commit 2928cb6853
11 changed files with 82 additions and 43 deletions

View File

@ -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? assert(IsValid()); // Is this chunk loaded / generated?
MarkDirty();
int index = a_Y + (a_Z * 128) + (a_X * 128 * 16); int index = a_Y + (a_Z * 128) + (a_X * 128 * 16);
char OldBlockMeta = GetLight( m_BlockMeta, index ); char OldBlockMeta = GetLight( m_BlockMeta, index );
char OldBlockType = m_BlockType[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; return;
} }
MarkDirty();
cCSLock Lock(m_CSBlockLists); cCSLock Lock(m_CSBlockLists);
m_PendingSendBlocks.push_back( index ); 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()); assert(IsValid());
MarkDirty();
const int index = a_Y + (a_Z * 128) + (a_X * 128 * 16); const int index = a_Y + (a_Z * 128) + (a_X * 128 * 16);
const char OldBlock = m_BlockType[index]; const char OldBlock = m_BlockType[index];
if (OldBlock == a_BlockType) if (OldBlock == a_BlockType)
{ {
return; return;
} }
MarkDirty();
m_BlockType[index] = a_BlockType; 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); cCSLock Lock(m_CSClients);
return !m_LoadedByClient.empty(); return !m_LoadedByClient.empty();

View File

@ -114,10 +114,10 @@ public:
void SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client ); void SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client );
void AddClient ( cClientHandle* a_Client ); void AddClient (cClientHandle* a_Client );
void RemoveClient( cClientHandle* a_Client ); void RemoveClient (cClientHandle* a_Client );
bool HasClient ( cClientHandle* a_Client ); bool HasClient (cClientHandle* a_Client );
bool HasAnyClient(void); // Returns true if theres any client in the chunk; false otherwise bool HasAnyClients(void); // Returns true if theres any client in the chunk; false otherwise
void AddEntity( cEntity * a_Entity ); void AddEntity( cEntity * a_Entity );
void RemoveEntity( cEntity * a_Entity); void RemoveEntity( cEntity * a_Entity);

View File

@ -53,11 +53,11 @@ bool cChunkGenerator::Start(cWorld * a_World, const AString & a_WorldGeneratorNa
if (a_WorldGeneratorName.compare("Test") == 0 ) if (a_WorldGeneratorName.compare("Test") == 0 )
{ {
m_pWorldGenerator = new cWorldGenerator_Test(); m_pWorldGenerator = new cWorldGenerator_Test(a_World);
} }
else // Default else // Default
{ {
m_pWorldGenerator = new cWorldGenerator(); m_pWorldGenerator = new cWorldGenerator(a_World);
} }
return super::Start(); return super::Start();
@ -129,17 +129,22 @@ void cChunkGenerator::Execute(void)
bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT); bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
Lock.Unlock(); // Unlock ASAP Lock.Unlock(); // Unlock ASAP
cChunkPtr Chunk = m_World->GetChunk(coords.m_ChunkX, 0, coords.m_ChunkZ); if (
if ((Chunk != NULL) && (Chunk->IsValid() || (SkipEnabled && !Chunk->HasAnyClient()))) 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 // Already generated / overload-skip, ignore request
continue; continue;
} }
LOG("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); 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) } // while (!bStop)
} }

View File

@ -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 ) void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
{ {
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
@ -389,7 +400,6 @@ void cChunkMap::cChunkLayer::Save(void)
void cChunkMap::cChunkLayer::UnloadUnusedChunks(void) void cChunkMap::cChunkLayer::UnloadUnusedChunks(void)
{ {
cWorld * World = m_Parent->GetWorld();
for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++)
{ {
if ((m_Chunks[i] != NULL) && (m_Chunks[i]->CanUnload())) if ((m_Chunks[i] != NULL) && (m_Chunks[i]->CanUnload()))

View File

@ -37,12 +37,13 @@ public:
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 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 MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
void MarkChunkSaving(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 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 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 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); 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 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 ); void Tick( float a_Dt, MTRand & a_TickRand );

View File

@ -105,7 +105,7 @@ void cMonsterConfig::AssignAttributes(cMonster *m, const char* n)
m->SetAttackRange (itr->m_AttackRange); m->SetAttackRange (itr->m_AttackRange);
m->SetSightDistance(itr->m_SightDistance); m->SetSightDistance(itr->m_SightDistance);
m->SetAttackRate ((int)itr->m_AttackRate); m->SetAttackRate ((int)itr->m_AttackRate);
m->SetMaxHealth ((int)itr->m_MaxHealth); m->SetMaxHealth ((short)itr->m_MaxHealth);
} }
} // for itr - m_pState->AttributesList[] } // for itr - m_pState->AttributesList[]
} }

View File

@ -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) void cWorld::SetMaxPlayers(int iMax)
{ {
m_MaxPlayers = MAX_PLAYERS; m_MaxPlayers = MAX_PLAYERS;

View File

@ -71,12 +71,13 @@ public:
void BroadcastToChunkOfBlock(int a_X, int a_Y, int a_Z, cPacket * a_Packet, cClientHandle * a_Exclude = NULL); 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 MarkChunkDirty (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
void MarkChunkSaving(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 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 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 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); 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 IsChunkValid (int a_ChunkX, int a_ChunkY, int a_ChunkZ) const;
bool HasChunkAnyClients(int a_ChunkX, int a_ChunkY, int a_ChunkZ) const;
// MOTD // MOTD
const AString & GetDescription(void) const {return m_Description; } const AString & GetDescription(void) const {return m_Description; }

View File

@ -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); cChunkPtr Chunk = m_World->GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ);
GenerateTerrain( a_Chunk ); assert(!Chunk->IsValid());
GenerateFoliage( a_Chunk );
a_Chunk->CalculateHeightmap(); memset(Chunk->pGetBlockData(), 0, cChunk::c_BlockDataSize);
a_Chunk->CalculateLighting(); GenerateTerrain(Chunk);
GenerateFoliage(Chunk);
Chunk->CalculateHeightmap();
Chunk->CalculateLighting();
Chunk->SetValid();
} }

View File

@ -15,13 +15,16 @@
class cWorldGenerator class cWorldGenerator
{ {
public: public:
cWorldGenerator(); cWorldGenerator(cWorld * a_World);
~cWorldGenerator(); ~cWorldGenerator();
virtual void GenerateChunk( cChunkPtr a_Chunk ); virtual void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
protected: protected:
cWorld * m_World;
// Thread-unsafe:
MTRand r1; MTRand r1;
virtual void GenerateTerrain( cChunkPtr a_Chunk ); virtual void GenerateTerrain( cChunkPtr a_Chunk );

View File

@ -10,6 +10,10 @@
class cWorldGenerator_Test : class cWorldGenerator_Test :
public cWorldGenerator public cWorldGenerator
{ {
public:
cWorldGenerator_Test(cWorld * a_World) : cWorldGenerator(a_World) {}
protected: protected:
virtual void GenerateTerrain( cChunkPtr a_Chunk ) override; virtual void GenerateTerrain( cChunkPtr a_Chunk ) override;
virtual void GenerateFoliage( cChunkPtr a_Chunk ) override; virtual void GenerateFoliage( cChunkPtr a_Chunk ) override;