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?
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();

View File

@ -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);

View File

@ -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);
Chunk->SetValid();
LOG("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ);
m_pWorldGenerator->GenerateChunk(coords.m_ChunkX, 0, coords.m_ChunkZ);
// 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)
}

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 )
{
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()))

View File

@ -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 );

View File

@ -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[]
}

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)
{
m_MaxPlayers = MAX_PLAYERS;

View File

@ -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; }

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);
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();
}

View File

@ -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 );

View File

@ -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;