From e88cdf8da714473624b221aca5a6feed2154a885 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sun, 5 May 2013 19:56:45 +0000 Subject: [PATCH] Re-worked generator subobject ownership, added a cache for the CompositionGen git-svn-id: http://mc-server.googlecode.com/svn/trunk@1447 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Generating/BioGen.cpp | 1 - source/Generating/BioGen.h | 2 +- source/Generating/ChunkDesc.h | 16 ++-- source/Generating/ChunkGenerator.cpp | 5 ++ source/Generating/CompoGen.cpp | 96 +++++++++++++++++++++++ source/Generating/CompoGen.h | 40 ++++++++++ source/Generating/ComposableGenerator.cpp | 79 +++++++------------ source/Generating/ComposableGenerator.h | 11 ++- source/Generating/HeiGen.cpp | 1 - source/Generating/HeiGen.h | 2 +- 10 files changed, 187 insertions(+), 66 deletions(-) diff --git a/source/Generating/BioGen.cpp b/source/Generating/BioGen.cpp index 16b32d711..1a73fe109 100644 --- a/source/Generating/BioGen.cpp +++ b/source/Generating/BioGen.cpp @@ -69,7 +69,6 @@ cBioGenCache::~cBioGenCache() { delete[] m_CacheData; delete[] m_CacheOrder; - delete m_BioGenToCache; } diff --git a/source/Generating/BioGen.h b/source/Generating/BioGen.h index cdb05b92e..f2afc3e8c 100644 --- a/source/Generating/BioGen.h +++ b/source/Generating/BioGen.h @@ -47,7 +47,7 @@ class cBioGenCache : typedef cBiomeGen super; public: - cBioGenCache(cBiomeGen * a_BioGenToCache, int a_CacheSize); // Takes ownership of a_BioGenToCache + cBioGenCache(cBiomeGen * a_BioGenToCache, int a_CacheSize); // Doesn't take ownership of a_BioGenToCache ~cBioGenCache(); protected: diff --git a/source/Generating/ChunkDesc.h b/source/Generating/ChunkDesc.h index bc952fbe4..41b85a814 100644 --- a/source/Generating/ChunkDesc.h +++ b/source/Generating/ChunkDesc.h @@ -30,6 +30,9 @@ class cChunkDesc public: // tolua_end + /// Uncompressed block metas, 1 meta per byte + typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks]; + cChunkDesc(int a_ChunkX, int a_ChunkZ); ~cChunkDesc(); @@ -172,13 +175,14 @@ public: void AddBlockEntity(cBlockEntity * a_BlockEntity); // Accessors used by cChunkGenerator::Generator descendants: - inline cChunkDef::BiomeMap & GetBiomeMap (void) { return m_BiomeMap; } - inline cChunkDef::BlockTypes & GetBlockTypes (void) { return *((cChunkDef::BlockTypes *)m_BlockArea.GetBlockTypes()); } + inline cChunkDef::BiomeMap & GetBiomeMap (void) { return m_BiomeMap; } + inline cChunkDef::BlockTypes & GetBlockTypes (void) { return *((cChunkDef::BlockTypes *)m_BlockArea.GetBlockTypes()); } // CANNOT, different compression! - // inline cChunkDef::BlockNibbles & GetBlockMetas (void) { return *((cChunkDef::BlockNibbles *)m_BlockArea.GetBlockMetas()); } - inline cChunkDef::HeightMap & GetHeightMap (void) { return m_HeightMap; } - inline cEntityList & GetEntities (void) { return m_Entities; } - inline cBlockEntityList & GetBlockEntities(void) { return m_BlockEntities; } + // inline cChunkDef::BlockNibbles & GetBlockMetas (void) { return *((cChunkDef::BlockNibbles *)m_BlockArea.GetBlockMetas()); } + inline BlockNibbleBytes & GetBlockMetasUncompressed(void) { return *((BlockNibbleBytes *)m_BlockArea.GetBlockMetas()); } + inline cChunkDef::HeightMap & GetHeightMap (void) { return m_HeightMap; } + inline cEntityList & GetEntities (void) { return m_Entities; } + inline cBlockEntityList & GetBlockEntities (void) { return m_BlockEntities; } /// Compresses the metas from the BlockArea format (1 meta per byte) into regular format (2 metas per byte) void CompressBlockMetas(cChunkDef::BlockNibbles & a_DestMetas); diff --git a/source/Generating/ChunkGenerator.cpp b/source/Generating/ChunkGenerator.cpp index a4717380d..d35b30460 100644 --- a/source/Generating/ChunkGenerator.cpp +++ b/source/Generating/ChunkGenerator.cpp @@ -272,6 +272,11 @@ void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc); cRoot::Get()->GetPluginManager()->CallHookChunkGenerated(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); + #ifdef _DEBUG + // Verify that the generator has produced valid data: + ChunkDesc.VerifyHeightmap(); + #endif + cChunkDef::BlockNibbles BlockMetas; ChunkDesc.CompressBlockMetas(BlockMetas); diff --git a/source/Generating/CompoGen.cpp b/source/Generating/CompoGen.cpp index 7fad38656..1d2affc94 100644 --- a/source/Generating/CompoGen.cpp +++ b/source/Generating/CompoGen.cpp @@ -483,3 +483,99 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc) + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cCompoGenCache: + +cCompoGenCache::cCompoGenCache(cTerrainCompositionGen * a_Underlying, int a_CacheSize) : + m_Underlying(a_Underlying), + m_CacheSize(a_CacheSize), + m_CacheOrder(new int[a_CacheSize]), + m_CacheData(new sCacheData[a_CacheSize]), + m_NumHits(0), + m_NumMisses(0), + m_TotalChain(0) +{ + for (int i = 0; i < m_CacheSize; i++) + { + m_CacheOrder[i] = i; + m_CacheData[i].m_ChunkX = 0x7fffffff; + m_CacheData[i].m_ChunkZ = 0x7fffffff; + } +} + + + + + +cCompoGenCache::~cCompoGenCache() +{ + delete[] m_CacheData; + delete[] m_CacheOrder; +} + + + + + +void cCompoGenCache::ComposeTerrain(cChunkDesc & a_ChunkDesc) +{ + //* + if (((m_NumHits + m_NumMisses) % 1024) == 10) + { + LOGD("CompoGenCache: %d hits, %d misses, saved %.2f %%", m_NumHits, m_NumMisses, 100.0 * m_NumHits / (m_NumHits + m_NumMisses)); + LOGD("CompoGenCache: Avg cache chain length: %.2f", (float)m_TotalChain / m_NumHits); + } + //*/ + + int ChunkX = a_ChunkDesc.GetChunkX(); + int ChunkZ = a_ChunkDesc.GetChunkZ(); + + for (int i = 0; i < m_CacheSize; i++) + { + if ( + (m_CacheData[m_CacheOrder[i]].m_ChunkX != ChunkX) || + (m_CacheData[m_CacheOrder[i]].m_ChunkZ != ChunkZ) + ) + { + continue; + } + // Found it in the cache + int Idx = m_CacheOrder[i]; + + // Move to front: + for (int j = i; j > 0; j--) + { + m_CacheOrder[j] = m_CacheOrder[j - 1]; + } + m_CacheOrder[0] = Idx; + + // Use the cached data: + memcpy(a_ChunkDesc.GetBlockTypes(), m_CacheData[Idx].m_BlockTypes, sizeof(a_ChunkDesc.GetBlockTypes())); + memcpy(a_ChunkDesc.GetBlockMetasUncompressed(), m_CacheData[Idx].m_BlockMetas, sizeof(a_ChunkDesc.GetBlockMetasUncompressed())); + + m_NumHits++; + m_TotalChain += i; + return; + } // for i - cache + + // Not in the cache: + m_NumMisses++; + m_Underlying->ComposeTerrain(a_ChunkDesc); + + // Insert it as the first item in the MRU order: + int Idx = m_CacheOrder[m_CacheSize - 1]; + for (int i = m_CacheSize - 1; i > 0; i--) + { + m_CacheOrder[i] = m_CacheOrder[i - 1]; + } // for i - m_CacheOrder[] + m_CacheOrder[0] = Idx; + memcpy(m_CacheData[Idx].m_BlockTypes, a_ChunkDesc.GetBlockTypes(), sizeof(a_ChunkDesc.GetBlockTypes())); + memcpy(m_CacheData[Idx].m_BlockMetas, a_ChunkDesc.GetBlockMetasUncompressed(), sizeof(a_ChunkDesc.GetBlockMetasUncompressed())); + m_CacheData[Idx].m_ChunkX = ChunkX; + m_CacheData[Idx].m_ChunkZ = ChunkZ; +} + + + + diff --git a/source/Generating/CompoGen.h b/source/Generating/CompoGen.h index 57233e2fd..8391de66e 100644 --- a/source/Generating/CompoGen.h +++ b/source/Generating/CompoGen.h @@ -6,6 +6,8 @@ - cCompoGenDebugBiomes - cCompoGenClassic - cCompoGenBiomal + - cCompoGenNether + - cCompoGenCache */ @@ -139,3 +141,41 @@ protected: + +/// Caches most-recently-used chunk composition of another composition generator. Caches only the types and metas +class cCompoGenCache : + public cTerrainCompositionGen +{ +public: + cCompoGenCache(cTerrainCompositionGen * a_Underlying, int a_CacheSize); // Doesn't take ownership of a_Underlying + ~cCompoGenCache(); + + // cTerrainCompositionGen override: + virtual void ComposeTerrain(cChunkDesc & a_ChunkDesc) override; + +protected: + + cTerrainCompositionGen * m_Underlying; + + struct sCacheData + { + int m_ChunkX; + int m_ChunkZ; + cChunkDef::BlockTypes m_BlockTypes; + cChunkDesc::BlockNibbleBytes m_BlockMetas; // The metas are uncompressed, 1 meta per byte + } ; + + // To avoid moving large amounts of data for the MRU behavior, we MRU-ize indices to an array of the actual data + int m_CacheSize; + int * m_CacheOrder; // MRU-ized order, indices into m_CacheData array + sCacheData * m_CacheData; // m_CacheData[m_CacheOrder[0]] is the most recently used + + // Cache statistics + int m_NumHits; + int m_NumMisses; + int m_TotalChain; // Number of cache items walked to get to a hit (only added for hits) +} ; + + + + diff --git a/source/Generating/ComposableGenerator.cpp b/source/Generating/ComposableGenerator.cpp index 0dd14aa50..7cf099c1f 100644 --- a/source/Generating/ComposableGenerator.cpp +++ b/source/Generating/ComposableGenerator.cpp @@ -37,10 +37,9 @@ cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) : m_BiomeGen(NULL), m_HeightGen(NULL), m_CompositionGen(NULL), - m_Noise3DComposable(NULL), - m_NumNoise3DComposableUses(0), - m_DistortedHeightmap(NULL), - m_NumDistortedHeightmapUses(0) + m_UnderlyingBiomeGen(NULL), + m_UnderlyingHeightGen(NULL), + m_UnderlyingCompositionGen(NULL) { } @@ -62,26 +61,18 @@ cComposableGenerator::~cComposableGenerator() } m_StructureGens.clear(); - // CompositionGen must not be freed if it is shared between HeightGenCache and CompositionGen: - int NumUsed = 1; - if (m_CompositionGen == m_Noise3DComposable) - { - NumUsed = m_NumNoise3DComposableUses; - } - else if (m_CompositionGen == m_DistortedHeightmap) - { - NumUsed = m_NumDistortedHeightmapUses; - } - if (NumUsed == 1) - { - delete m_CompositionGen; - } - + delete m_CompositionGen; m_CompositionGen = NULL; delete m_HeightGen; m_HeightGen = NULL; delete m_BiomeGen; m_BiomeGen = NULL; + delete m_UnderlyingCompositionGen; + m_UnderlyingCompositionGen = NULL; + delete m_UnderlyingHeightGen; + m_UnderlyingHeightGen = NULL; + delete m_UnderlyingBiomeGen; + m_UnderlyingBiomeGen = NULL; } @@ -216,7 +207,8 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile) CacheSize = 4; } LOGINFO("Using a cache for biomegen of size %d.", CacheSize); - m_BiomeGen = new cBioGenCache(m_BiomeGen, CacheSize); + m_UnderlyingBiomeGen = m_BiomeGen; + m_BiomeGen = new cBioGenCache(m_UnderlyingBiomeGen, CacheSize); } m_BiomeGen->Initialize(a_IniFile); } @@ -255,24 +247,13 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile) } else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0) { - if (m_DistortedHeightmap == NULL) - { - m_DistortedHeightmap = new cDistortedHeightmap(Seed, *m_BiomeGen); - m_DistortedHeightmap->Initialize(a_IniFile); - } - m_HeightGen = m_DistortedHeightmap; - m_NumDistortedHeightmapUses++; - // TODO: Optimize by sharing with CompoGen + m_HeightGen = new cDistortedHeightmap(Seed, *m_BiomeGen); + ((cDistortedHeightmap *)m_HeightGen)->Initialize(a_IniFile); } else if (NoCaseCompare(HeightGenName, "Noise3D") == 0) { - if (m_Noise3DComposable == NULL) - { - m_Noise3DComposable = new cNoise3DComposable(Seed); - m_Noise3DComposable->Initialize(a_IniFile); - } - m_HeightGen = m_Noise3DComposable; - m_NumNoise3DComposableUses++; + m_HeightGen = new cNoise3DComposable(Seed); + ((cNoise3DComposable *)m_HeightGen)->Initialize(a_IniFile); } else // "biomal" or { @@ -308,7 +289,8 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile) CacheSize = 4; } LOGINFO("Using a cache for Heightgen of size %d.", CacheSize); - m_HeightGen = new cHeiGenCache(m_HeightGen, CacheSize); + m_UnderlyingHeightGen = m_HeightGen; + m_HeightGen = new cHeiGenCache(m_UnderlyingHeightGen, CacheSize); } } @@ -352,13 +334,8 @@ void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile) } else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0) { - if (m_DistortedHeightmap == NULL) - { - m_DistortedHeightmap = new cDistortedHeightmap(m_ChunkGenerator.GetSeed(), *m_BiomeGen); - m_DistortedHeightmap->Initialize(a_IniFile); - } - m_CompositionGen = m_DistortedHeightmap; - m_NumDistortedHeightmapUses++; + m_CompositionGen = new cDistortedHeightmap(m_ChunkGenerator.GetSeed(), *m_BiomeGen); + ((cDistortedHeightmap *)m_CompositionGen)->Initialize(a_IniFile); } else if (NoCaseCompare(CompoGenName, "nether") == 0) { @@ -366,13 +343,8 @@ void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile) } else if (NoCaseCompare(CompoGenName, "Noise3D") == 0) { - if (m_Noise3DComposable == NULL) - { - m_Noise3DComposable = new cNoise3DComposable(m_ChunkGenerator.GetSeed()); - m_Noise3DComposable->Initialize(a_IniFile); - } - m_CompositionGen = m_Noise3DComposable; - m_NumNoise3DComposableUses++; + m_CompositionGen = new cNoise3DComposable(m_ChunkGenerator.GetSeed()); + ((cNoise3DComposable *)m_CompositionGen)->Initialize(a_IniFile); } else { @@ -399,6 +371,13 @@ void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile) LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); //*/ } + + int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64); + if (CompoGenCacheSize > 1) + { + m_UnderlyingCompositionGen = m_CompositionGen; + m_CompositionGen = new cCompoGenCache(m_UnderlyingCompositionGen, 32); + } } diff --git a/source/Generating/ComposableGenerator.h b/source/Generating/ComposableGenerator.h index ee38bdb9d..c32e7181f 100644 --- a/source/Generating/ComposableGenerator.h +++ b/source/Generating/ComposableGenerator.h @@ -148,13 +148,12 @@ protected: cStructureGenList m_StructureGens; cFinishGenList m_FinishGens; - // Specific generators that can be reused for different purposes - we don't want to create multiple objects for them - cNoise3DComposable * m_Noise3DComposable; - int m_NumNoise3DComposableUses; ///< How many times is it actually used? - cDistortedHeightmap * m_DistortedHeightmap; - int m_NumDistortedHeightmapUses; ///< How many times is it actually used? + // Generators underlying the caches: + cBiomeGen * m_UnderlyingBiomeGen; + cTerrainHeightGen * m_UnderlyingHeightGen; + cTerrainCompositionGen * m_UnderlyingCompositionGen; + - /// Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly void InitBiomeGen(cIniFile & a_IniFile); diff --git a/source/Generating/HeiGen.cpp b/source/Generating/HeiGen.cpp index 24042e3ff..d012792bb 100644 --- a/source/Generating/HeiGen.cpp +++ b/source/Generating/HeiGen.cpp @@ -53,7 +53,6 @@ cHeiGenCache::~cHeiGenCache() { delete[] m_CacheData; delete[] m_CacheOrder; - delete m_HeiGenToCache; } diff --git a/source/Generating/HeiGen.h b/source/Generating/HeiGen.h index 3bdfef993..4bc55a958 100644 --- a/source/Generating/HeiGen.h +++ b/source/Generating/HeiGen.h @@ -44,7 +44,7 @@ class cHeiGenCache : public cTerrainHeightGen { public: - cHeiGenCache(cTerrainHeightGen * a_HeiGenToCache, int a_CacheSize); // Takes ownership of a_HeiGenToCache + cHeiGenCache(cTerrainHeightGen * a_HeiGenToCache, int a_CacheSize); // Doesn't take ownership of a_HeiGenToCache ~cHeiGenCache(); // cTerrainHeightGen override: