summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/ManualBindings_World.cpp4
-rw-r--r--src/CMakeLists.txt2
-rw-r--r--src/Chunk.cpp19
-rw-r--r--src/ChunkDef.h18
-rw-r--r--src/ChunkGeneratorThread.cpp264
-rw-r--r--src/ChunkGeneratorThread.h159
-rw-r--r--src/ChunkMap.cpp14
-rw-r--r--src/ChunkSender.cpp4
-rw-r--r--src/Generating/ChunkDesc.cpp18
-rw-r--r--src/Generating/ChunkDesc.h17
-rw-r--r--src/Generating/ChunkGenerator.cpp293
-rw-r--r--src/Generating/ChunkGenerator.h184
-rw-r--r--src/Generating/ComposableGenerator.cpp84
-rw-r--r--src/Generating/ComposableGenerator.h8
-rw-r--r--src/Generating/CompositedHeiGen.h2
-rw-r--r--src/Generating/FinishGen.cpp1
-rw-r--r--src/Generating/Noise3DGenerator.cpp6
-rw-r--r--src/Generating/Noise3DGenerator.h8
-rw-r--r--src/Generating/StructGen.cpp4
-rw-r--r--src/Generating/Trees.cpp87
-rw-r--r--src/Generating/Trees.h8
-rw-r--r--src/LightingThread.cpp4
-rw-r--r--src/SpawnPrepare.cpp4
-rw-r--r--src/World.cpp106
-rw-r--r--src/World.h22
-rw-r--r--src/WorldStorage/WorldStorage.cpp4
26 files changed, 681 insertions, 663 deletions
diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp
index ee0998f87..17a66b4c2 100644
--- a/src/Bindings/ManualBindings_World.cpp
+++ b/src/Bindings/ManualBindings_World.cpp
@@ -727,9 +727,9 @@ static int tolua_cWorld_PrepareChunk(lua_State * tolua_S)
{
public:
// cChunkCoordCallback override:
- virtual void Call(int a_CBChunkX, int a_CBChunkZ, bool a_IsSuccess) override
+ virtual void Call(cChunkCoords a_Coords, bool a_IsSuccess) override
{
- m_LuaCallback.Call(a_CBChunkX, a_CBChunkZ, a_IsSuccess);
+ m_LuaCallback.Call(a_Coords.m_ChunkX, a_Coords.m_ChunkZ, a_IsSuccess);
}
cLuaState::cOptionalCallback m_LuaCallback;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 072eb6c97..105f234f1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -27,6 +27,7 @@ SET (SRCS
ChatColor.cpp
Chunk.cpp
ChunkData.cpp
+ ChunkGeneratorThread.cpp
ChunkMap.cpp
ChunkSender.cpp
ChunkStay.cpp
@@ -100,6 +101,7 @@ SET (HDRS
ChunkData.h
ChunkDataCallback.h
ChunkDef.h
+ ChunkGeneratorThread.h
ChunkMap.h
ChunkSender.h
ChunkStay.h
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index 41a59c103..7a95bceed 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -50,23 +50,6 @@
////////////////////////////////////////////////////////////////////////////////
-// sSetBlock:
-
-sSetBlock::sSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta):
- m_RelX(a_BlockX),
- m_RelY(a_BlockY),
- m_RelZ(a_BlockZ),
- m_BlockType(a_BlockType),
- m_BlockMeta(a_BlockMeta)
-{
- cChunkDef::AbsoluteToRelative(m_RelX, m_RelY, m_RelZ, m_ChunkX, m_ChunkZ);
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
// cChunk:
cChunk::cChunk(
@@ -276,7 +259,7 @@ void cChunk::MarkLoadFailed(void)
// If the chunk is marked as needed, generate it:
if (m_ShouldGenerateIfLoadFailed)
{
- m_World->GetGenerator().QueueGenerateChunk(m_PosX, m_PosZ, false);
+ m_World->GetGenerator().QueueGenerateChunk({m_PosX, m_PosZ}, false);
}
else
{
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index bfed62aae..95abdaf58 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -65,6 +65,12 @@ public:
{
return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ));
}
+
+ /** Returns a string that describes the chunk coords, suitable for logging. */
+ AString ToString() const
+ {
+ return Printf("[%d, %d]", m_ChunkX, m_ChunkZ);
+ }
} ;
@@ -445,7 +451,15 @@ struct sSetBlock
BLOCKTYPE m_BlockType;
NIBBLETYPE m_BlockMeta;
- sSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+ sSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta):
+ m_RelX(a_BlockX),
+ m_RelY(a_BlockY),
+ m_RelZ(a_BlockZ),
+ m_BlockType(a_BlockType),
+ m_BlockMeta(a_BlockMeta)
+ {
+ cChunkDef::AbsoluteToRelative(m_RelX, m_RelY, m_RelZ, m_ChunkX, m_ChunkZ);
+ }
sSetBlock(int a_ChunkX, int a_ChunkZ, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) :
m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ),
@@ -525,7 +539,7 @@ public:
virtual ~cChunkCoordCallback() {}
/** Called with the chunk's coords, and an optional operation status flag for operations that support it. */
- virtual void Call(int a_ChunkX, int a_ChunkZ, bool a_IsSuccess) = 0;
+ virtual void Call(cChunkCoords a_Coords, bool a_IsSuccess) = 0;
} ;
diff --git a/src/ChunkGeneratorThread.cpp b/src/ChunkGeneratorThread.cpp
new file mode 100644
index 000000000..a5703bd2c
--- /dev/null
+++ b/src/ChunkGeneratorThread.cpp
@@ -0,0 +1,264 @@
+#include "Globals.h"
+#include "ChunkGeneratorThread.h"
+#include "Generating/ChunkGenerator.h"
+#include "Generating/ChunkDesc.h"
+
+
+
+
+
+/** If the generation queue size exceeds this number, a warning will be output */
+const size_t QUEUE_WARNING_LIMIT = 1000;
+
+/** If the generation queue size exceeds this number, chunks with no clients will be skipped */
+const size_t QUEUE_SKIP_LIMIT = 500;
+
+
+
+
+
+cChunkGeneratorThread::cChunkGeneratorThread(void) :
+ Super("cChunkGeneratorThread"),
+ m_Generator(nullptr),
+ m_PluginInterface(nullptr),
+ m_ChunkSink(nullptr)
+{
+}
+
+
+
+
+
+cChunkGeneratorThread::~cChunkGeneratorThread()
+{
+ Stop();
+}
+
+
+
+
+
+bool cChunkGeneratorThread::Initialize(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile)
+{
+ m_PluginInterface = &a_PluginInterface;
+ m_ChunkSink = &a_ChunkSink;
+
+ m_Generator = cChunkGenerator::CreateFromIniFile(a_IniFile);
+ if (m_Generator == nullptr)
+ {
+ LOGERROR("Generator could not start, aborting the server");
+ return false;
+ }
+ return true;
+}
+
+
+
+
+
+void cChunkGeneratorThread::Stop(void)
+{
+ m_ShouldTerminate = true;
+ m_Event.Set();
+ m_evtRemoved.Set(); // Wake up anybody waiting for empty queue
+ Super::Stop();
+ m_Generator.reset();
+}
+
+
+
+
+
+void cChunkGeneratorThread::QueueGenerateChunk(
+ cChunkCoords a_Coords,
+ bool a_ForceRegeneration,
+ cChunkCoordCallback * a_Callback
+)
+{
+ ASSERT(m_ChunkSink->IsChunkQueued(a_Coords));
+
+ {
+ cCSLock Lock(m_CS);
+
+ // Add to queue, issue a warning if too many:
+ if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
+ {
+ LOGWARN("WARNING: Adding chunk %s to generation queue; Queue is too big! (%zu)", a_Coords.ToString().c_str(), m_Queue.size());
+ }
+ m_Queue.push_back(QueueItem{a_Coords, a_ForceRegeneration, a_Callback});
+ }
+
+ m_Event.Set();
+}
+
+
+
+
+
+void cChunkGeneratorThread::GenerateBiomes(cChunkCoords a_Coords, cChunkDef::BiomeMap & a_BiomeMap)
+{
+ if (m_Generator != nullptr)
+ {
+ m_Generator->GenerateBiomes(a_Coords.m_ChunkX, a_Coords.m_ChunkZ, a_BiomeMap);
+ }
+}
+
+
+
+
+
+void cChunkGeneratorThread::WaitForQueueEmpty(void)
+{
+ cCSLock Lock(m_CS);
+ while (!m_ShouldTerminate && !m_Queue.empty())
+ {
+ cCSUnlock Unlock(Lock);
+ m_evtRemoved.Wait();
+ }
+}
+
+
+
+
+
+int cChunkGeneratorThread::GetQueueLength(void) const
+{
+ cCSLock Lock(m_CS);
+ return static_cast<int>(m_Queue.size());
+}
+
+
+
+
+
+int cChunkGeneratorThread::GetSeed() const
+{
+ return m_Generator->GetSeed();
+}
+
+
+
+
+
+EMCSBiome cChunkGeneratorThread::GetBiomeAt(int a_BlockX, int a_BlockZ)
+{
+ ASSERT(m_Generator != nullptr);
+ return m_Generator->GetBiomeAt(a_BlockX, a_BlockZ);
+}
+
+
+
+
+
+void cChunkGeneratorThread::Execute(void)
+{
+ // To be able to display performance information, the generator counts the chunks generated.
+ // When the queue gets empty, the count is reset, so that waiting for the queue is not counted into the total time.
+ int NumChunksGenerated = 0; // Number of chunks generated since the queue was last empty
+ clock_t GenerationStart = clock(); // Clock tick when the queue started to fill
+ clock_t LastReportTick = clock(); // Clock tick of the last report made (so that performance isn't reported too often)
+
+ while (!m_ShouldTerminate)
+ {
+ cCSLock Lock(m_CS);
+ while (m_Queue.empty())
+ {
+ if ((NumChunksGenerated > 16) && (clock() - LastReportTick > CLOCKS_PER_SEC))
+ {
+ /* LOG("Chunk generator performance: %.2f ch / sec (%d ch total)",
+ static_cast<double>(NumChunksGenerated) * CLOCKS_PER_SEC/ (clock() - GenerationStart),
+ NumChunksGenerated
+ ); */
+ }
+ cCSUnlock Unlock(Lock);
+ m_Event.Wait();
+ if (m_ShouldTerminate)
+ {
+ return;
+ }
+ NumChunksGenerated = 0;
+ GenerationStart = clock();
+ LastReportTick = clock();
+ }
+
+ if (m_Queue.empty())
+ {
+ // Sometimes the queue remains empty
+ // If so, we can't do any front() operations on it!
+ continue;
+ }
+
+ auto item = m_Queue.front(); // Get next chunk from the queue
+ bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
+ m_Queue.erase(m_Queue.begin()); // Remove the item from the queue
+ Lock.Unlock(); // Unlock ASAP
+ m_evtRemoved.Set();
+
+ // Display perf info once in a while:
+ if ((NumChunksGenerated > 512) && (clock() - LastReportTick > 2 * CLOCKS_PER_SEC))
+ {
+ LOG("Chunk generator performance: %.2f ch / sec (%d ch total)",
+ static_cast<double>(NumChunksGenerated) * CLOCKS_PER_SEC / (clock() - GenerationStart),
+ NumChunksGenerated
+ );
+ LastReportTick = clock();
+ }
+
+ // Skip the chunk if it's already generated and regeneration is not forced. Report as success:
+ if (!item.m_ForceRegeneration && m_ChunkSink->IsChunkValid(item.m_Coords))
+ {
+ LOGD("Chunk %s already generated, skipping generation", item.m_Coords.ToString().c_str());
+ if (item.m_Callback != nullptr)
+ {
+ item.m_Callback->Call(item.m_Coords, true);
+ }
+ continue;
+ }
+
+ // Skip the chunk if the generator is overloaded:
+ if (SkipEnabled && !m_ChunkSink->HasChunkAnyClients(item.m_Coords))
+ {
+ LOGWARNING("Chunk generator overloaded, skipping chunk %s", item.m_Coords.ToString().c_str());
+ if (item.m_Callback != nullptr)
+ {
+ item.m_Callback->Call(item.m_Coords, false);
+ }
+ continue;
+ }
+
+ // Generate the chunk:
+ DoGenerate(item.m_Coords);
+ if (item.m_Callback != nullptr)
+ {
+ item.m_Callback->Call(item.m_Coords, true);
+ }
+ NumChunksGenerated++;
+ } // while (!bStop)
+}
+
+
+
+
+
+void cChunkGeneratorThread::DoGenerate(cChunkCoords a_Coords)
+{
+ ASSERT(m_PluginInterface != nullptr);
+ ASSERT(m_ChunkSink != nullptr);
+
+ cChunkDesc ChunkDesc(a_Coords);
+ m_PluginInterface->CallHookChunkGenerating(ChunkDesc);
+ m_Generator->Generate(a_Coords.m_ChunkX, a_Coords.m_ChunkZ, ChunkDesc);
+ m_PluginInterface->CallHookChunkGenerated(ChunkDesc);
+
+ #ifdef _DEBUG
+ // Verify that the generator has produced valid data:
+ ChunkDesc.VerifyHeightmap();
+ #endif
+
+ m_ChunkSink->OnChunkGenerated(ChunkDesc);
+}
+
+
+
+
+
diff --git a/src/ChunkGeneratorThread.h b/src/ChunkGeneratorThread.h
new file mode 100644
index 000000000..f7a4b3da3
--- /dev/null
+++ b/src/ChunkGeneratorThread.h
@@ -0,0 +1,159 @@
+#pragma once
+
+#include "OSSupport/IsThread.h"
+
+
+
+
+
+// fwd:
+class cIniFile;
+class cChunkDesc;
+class cChunkGenerator;
+
+
+
+
+
+/** Takes requests for generating chunks and processes them in a separate thread one by one.
+The requests are not added to the queue if there is already a request with the same coords.
+Before generating, the thread checks if the chunk hasn't been already generated.
+It is theoretically possible to have multiple generator threads by having multiple instances of this object,
+but then it MAY happen that the chunk is generated twice.
+If the generator queue is overloaded, the generator skips chunks with no clients in them. */
+class cChunkGeneratorThread :
+ public cIsThread
+{
+ using Super = cIsThread;
+
+public:
+
+ /** The interface through which the plugins are called for their OnChunkGenerating / OnChunkGenerated hooks. */
+ class cPluginInterface
+ {
+ public:
+ // Force a virtual destructor
+ virtual ~cPluginInterface() {}
+
+ /** Called when the chunk is about to be generated.
+ The generator may be partly or fully overriden by the implementation. */
+ virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) = 0;
+
+ /** Called after the chunk is generated, before it is handed to the chunk sink.
+ a_ChunkDesc contains the generated chunk data. Implementation may modify this data. */
+ virtual void CallHookChunkGenerated(cChunkDesc & a_ChunkDesc) = 0;
+ } ;
+
+
+ /** The interface through which the generated chunks are handed to the cWorld or whoever created us. */
+ class cChunkSink
+ {
+ public:
+ // Force a virtual destructor
+ virtual ~cChunkSink() {}
+
+ /** Called after the chunk has been generated
+ The interface may store the chunk, send it over network, whatever.
+ The chunk is not expected to be modified, but the generator will survive if the implementation
+ changes the data within. All changes are ignored, though. */
+ virtual void OnChunkGenerated(cChunkDesc & a_ChunkDesc) = 0;
+
+ /** Called just before the chunk generation is started,
+ to verify that it hasn't been generated in the meantime.
+ If this callback returns true, the chunk is not generated. */
+ virtual bool IsChunkValid(cChunkCoords a_Coords) = 0;
+
+ /** Called when the generator is overloaded to skip chunks that are no longer needed.
+ If this callback returns false, the chunk is not generated. */
+ virtual bool HasChunkAnyClients(cChunkCoords a_Coords) = 0;
+
+ /** Called to check whether the specified chunk is in the queued state.
+ Currently used only in Debug-mode asserts. */
+ virtual bool IsChunkQueued(cChunkCoords a_Coords) = 0;
+ } ;
+
+
+ cChunkGeneratorThread (void);
+ virtual ~cChunkGeneratorThread() override;
+
+ /** Read settings from the ini file and initialize in preperation for being started. */
+ bool Initialize(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile);
+
+ void Stop(void);
+
+ /** Queues the chunk for generation
+ If a-ForceGenerate is set, the chunk is regenerated even if the data is already present in the chunksink.
+ a_Callback is called after the chunk is generated. If the chunk was already present, the callback is still called, even if not regenerating.
+ It is legal to set the callback to nullptr, no callback is called then.
+ If the generator becomes overloaded and skips this chunk, the callback is still called. */
+ void QueueGenerateChunk(cChunkCoords a_Coords, bool a_ForceRegeneration, cChunkCoordCallback * a_Callback = nullptr);
+
+ /** Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading. */
+ void GenerateBiomes(cChunkCoords a_Coords, cChunkDef::BiomeMap & a_BiomeMap);
+
+ void WaitForQueueEmpty();
+
+ int GetQueueLength() const;
+
+ int GetSeed() const;
+
+ /** Returns the biome at the specified coords. Used by ChunkMap if an invalid chunk is queried for biome */
+ EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ);
+
+
+private:
+
+ struct QueueItem
+ {
+ /** The chunk coords */
+ cChunkCoords m_Coords;
+
+ /** Force the regeneration of an already existing chunk */
+ bool m_ForceRegeneration;
+
+ /** Callback to call after generating. */
+ cChunkCoordCallback * m_Callback;
+
+ QueueItem(cChunkCoords a_Coords, bool a_ForceRegeneration, cChunkCoordCallback * a_Callback):
+ m_Coords(a_Coords),
+ m_ForceRegeneration(a_ForceRegeneration),
+ m_Callback(a_Callback)
+ {
+ }
+ };
+
+ using Queue = std::list<QueueItem>;
+
+
+ /** CS protecting access to the queue. */
+ mutable cCriticalSection m_CS;
+
+ /** Queue of the chunks to be generated. Protected against multithreaded access by m_CS. */
+ Queue m_Queue;
+
+ /** Set when an item is added to the queue or the thread should terminate. */
+ cEvent m_Event;
+
+ /** Set when an item is removed from the queue. */
+ cEvent m_evtRemoved;
+
+ /** The actual chunk generator engine used. */
+ std::unique_ptr<cChunkGenerator> m_Generator;
+
+ /** The plugin interface that may modify the generated chunks */
+ cPluginInterface * m_PluginInterface;
+
+ /** The destination where the generated chunks are sent */
+ cChunkSink * m_ChunkSink;
+
+
+ // cIsThread override:
+ virtual void Execute(void) override;
+
+ /** Generates the specified chunk and sets it into the chunksink. */
+ void DoGenerate(cChunkCoords a_Coords);
+};
+
+
+
+
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index dd8f1add1..b5a6252ff 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -1798,7 +1798,7 @@ void cChunkMap::PrepareChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkC
// The chunk is present and lit, just call the callback, report as success:
if (a_Callback != nullptr)
{
- a_Callback->Call(a_ChunkX, a_ChunkZ, true);
+ a_Callback->Call({a_ChunkX, a_ChunkZ}, true);
}
}
@@ -1831,34 +1831,34 @@ bool cChunkMap::GenerateChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback *
}
// cChunkCoordCallback override:
- virtual void Call(int a_CBChunkX, int a_CBChunkZ, bool a_CBIsSuccess) override
+ virtual void Call(cChunkCoords a_Coords, bool a_CBIsSuccess) override
{
// If success is reported, the chunk is already valid, no need to do anything else:
if (a_CBIsSuccess)
{
if (m_Callback != nullptr)
{
- m_Callback->Call(a_CBChunkX, a_CBChunkZ, true);
+ m_Callback->Call(a_Coords, true);
}
return;
}
// The chunk failed to load, generate it:
cCSLock CBLock(m_ChunkMap.m_CSChunks);
- cChunkPtr CBChunk = m_ChunkMap.GetChunkNoLoad(a_CBChunkX, a_CBChunkZ);
+ cChunkPtr CBChunk = m_ChunkMap.GetChunkNoLoad(a_Coords.m_ChunkX, a_Coords.m_ChunkZ);
if (CBChunk == nullptr)
{
// An error occurred, but we promised to call the callback, so call it even when there's no real chunk data:
if (m_Callback != nullptr)
{
- m_Callback->Call(a_CBChunkX, a_CBChunkZ, false);
+ m_Callback->Call(a_Coords, false);
}
return;
}
CBChunk->SetPresence(cChunk::cpQueued);
- m_World.GetGenerator().QueueGenerateChunk(a_CBChunkX, a_CBChunkZ, false, m_Callback);
+ m_World.GetGenerator().QueueGenerateChunk(a_Coords, false, m_Callback);
}
protected:
@@ -1873,7 +1873,7 @@ bool cChunkMap::GenerateChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback *
// The chunk is valid, just call the callback:
if (a_Callback != nullptr)
{
- a_Callback->Call(a_ChunkX, a_ChunkZ, true);
+ a_Callback->Call({a_ChunkX, a_ChunkZ}, true);
}
return true;
}
diff --git a/src/ChunkSender.cpp b/src/ChunkSender.cpp
index c5d56f354..a11852ed6 100644
--- a/src/ChunkSender.cpp
+++ b/src/ChunkSender.cpp
@@ -27,11 +27,11 @@
class cNotifyChunkSender :
public cChunkCoordCallback
{
- virtual void Call(int a_ChunkX, int a_ChunkZ, bool a_IsSuccess) override
+ virtual void Call(cChunkCoords a_Coords, bool a_IsSuccess) override
{
cChunkSender & ChunkSender = m_ChunkSender;
m_World.DoWithChunk(
- a_ChunkX, a_ChunkZ,
+ a_Coords.m_ChunkX, a_Coords.m_ChunkZ,
[&ChunkSender] (cChunk & a_Chunk) -> bool
{
ChunkSender.QueueSendChunkTo(a_Chunk.GetPosX(), a_Chunk.GetPosZ(), cChunkSender::E_CHUNK_PRIORITY_MIDHIGH, a_Chunk.GetAllClients());
diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp
index e5d213fe6..18947f401 100644
--- a/src/Generating/ChunkDesc.cpp
+++ b/src/Generating/ChunkDesc.cpp
@@ -13,9 +13,8 @@
-cChunkDesc::cChunkDesc(int a_ChunkX, int a_ChunkZ) :
- m_ChunkX(a_ChunkX),
- m_ChunkZ(a_ChunkZ),
+cChunkDesc::cChunkDesc(cChunkCoords a_Coords) :
+ m_Coords(a_Coords),
m_bUseDefaultBiomes(true),
m_bUseDefaultHeight(true),
m_bUseDefaultComposition(true),
@@ -43,10 +42,9 @@ cChunkDesc::~cChunkDesc()
-void cChunkDesc::SetChunkCoords(int a_ChunkX, int a_ChunkZ)
+void cChunkDesc::SetChunkCoords(cChunkCoords a_Coords)
{
- m_ChunkX = a_ChunkX;
- m_ChunkZ = a_ChunkZ;
+ m_Coords = a_Coords;
}
@@ -369,9 +367,9 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
int SizeY = a_MaxRelY - a_MinRelY;
int SizeZ = a_MaxRelZ - a_MinRelZ;
a_Dest.Clear();
- a_Dest.m_Origin.x = m_ChunkX * cChunkDef::Width + a_MinRelX;
+ a_Dest.m_Origin.x = m_Coords.m_ChunkX * cChunkDef::Width + a_MinRelX;
a_Dest.m_Origin.y = a_MinRelY;
- a_Dest.m_Origin.z = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
+ a_Dest.m_Origin.z = m_Coords.m_ChunkZ * cChunkDef::Width + a_MinRelZ;
a_Dest.SetSize(SizeX, SizeY, SizeZ, cBlockArea::baTypes | cBlockArea::baMetas);
for (int y = 0; y < SizeY; y++)
@@ -593,8 +591,8 @@ cBlockEntity * cChunkDesc::GetBlockEntity(int a_RelX, int a_RelY, int a_RelZ)
}
}
- int AbsX = a_RelX + m_ChunkX * cChunkDef::Width;
- int AbsZ = a_RelZ + m_ChunkZ * cChunkDef::Width;
+ int AbsX = a_RelX + m_Coords.m_ChunkX * cChunkDef::Width;
+ int AbsZ = a_RelZ + m_Coords.m_ChunkZ * cChunkDef::Width;
// The block entity is not created yet, try to create it and add to list:
cBlockEntity * be = cBlockEntity::CreateByBlockType(GetBlockType(a_RelX, a_RelY, a_RelZ), GetBlockMeta(a_RelX, a_RelY, a_RelZ), AbsX, a_RelY, AbsZ);
diff --git a/src/Generating/ChunkDesc.h b/src/Generating/ChunkDesc.h
index 709fccb70..997b640a3 100644
--- a/src/Generating/ChunkDesc.h
+++ b/src/Generating/ChunkDesc.h
@@ -39,15 +39,21 @@ public:
typedef NIBBLETYPE BlockNibbleBytes[cChunkDef::NumBlocks];
- cChunkDesc(int a_ChunkX, int a_ChunkZ);
+ cChunkDesc(cChunkCoords a_Coords);
~cChunkDesc();
- void SetChunkCoords(int a_ChunkX, int a_ChunkZ);
+ void SetChunkCoords(cChunkCoords a_Coords);
// tolua_begin
- int GetChunkX(void) const { return m_ChunkX; }
- int GetChunkZ(void) const { return m_ChunkZ; }
+ int GetChunkX() const { return m_Coords.m_ChunkX; } // Prefer GetChunkCoords() instead
+ int GetChunkZ() const { return m_Coords.m_ChunkZ; } // Prefer GetChunkCoords() instead
+
+ // tolua_end
+
+ cChunkCoords GetChunkCoords() const { return m_Coords; }
+
+ // tolua_begin
void FillBlocks(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void SetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
@@ -225,8 +231,7 @@ public:
#endif // _DEBUG
private:
- int m_ChunkX;
- int m_ChunkZ;
+ cChunkCoords m_Coords;
cChunkDef::BiomeMap m_BiomeMap;
cBlockArea m_BlockArea;
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index 166a05ca2..d426ca19c 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -12,46 +12,8 @@
-/** If the generation queue size exceeds this number, a warning will be output */
-const unsigned int QUEUE_WARNING_LIMIT = 1000;
-
-/** If the generation queue size exceeds this number, chunks with no clients will be skipped */
-const unsigned int QUEUE_SKIP_LIMIT = 500;
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cChunkGenerator:
-
-cChunkGenerator::cChunkGenerator(void) :
- super("cChunkGenerator"),
- m_Seed(0), // Will be overwritten by the actual generator
- m_Generator(nullptr),
- m_PluginInterface(nullptr),
- m_ChunkSink(nullptr)
-{
-}
-
-
-
-
-
-cChunkGenerator::~cChunkGenerator()
-{
- Stop();
-}
-
-
-
-
-
-bool cChunkGenerator::Initialize(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile)
+void cChunkGenerator::Initialize(cIniFile & a_IniFile)
{
- m_PluginInterface = &a_PluginInterface;
- m_ChunkSink = &a_ChunkSink;
-
// Get the seed; create a new one and log it if not found in the INI file:
if (a_IniFile.HasValue("Seed", "Seed"))
{
@@ -63,12 +25,20 @@ bool cChunkGenerator::Initialize(cPluginInterface & a_PluginInterface, cChunkSin
LOGINFO("Chosen a new random seed for world: %d", m_Seed);
a_IniFile.SetValueI("Seed", "Seed", m_Seed);
}
+}
+
+
+
+
+std::unique_ptr<cChunkGenerator> cChunkGenerator::CreateFromIniFile(cIniFile & a_IniFile)
+{
// Get the generator engine based on the INI file settings:
+ std::unique_ptr<cChunkGenerator> res;
AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable");
if (NoCaseCompare(GeneratorName, "Noise3D") == 0)
{
- m_Generator = new cNoise3DGenerator(*this);
+ res.reset(new cNoise3DGenerator());
}
else
{
@@ -76,90 +46,17 @@ bool cChunkGenerator::Initialize(cPluginInterface & a_PluginInterface, cChunkSin
{
LOGWARN("[Generator]::Generator value \"%s\" not recognized, using \"Composable\".", GeneratorName.c_str());
}
- m_Generator = new cComposableGenerator(*this);
+ res.reset(new cComposableGenerator());
}
- if (m_Generator == nullptr)
+ if (res == nullptr)
{
LOGERROR("Generator could not start, aborting the server");
- return false;
- }
-
- m_Generator->Initialize(a_IniFile);
- return true;
-}
-
-
-
-
-
-void cChunkGenerator::Stop(void)
-{
- m_ShouldTerminate = true;
- m_Event.Set();
- m_evtRemoved.Set(); // Wake up anybody waiting for empty queue
- super::Stop();
-
- delete m_Generator;
- m_Generator = nullptr;
-}
-
-
-
-
-
-void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate, cChunkCoordCallback * a_Callback)
-{
- ASSERT(m_ChunkSink->IsChunkQueued(a_ChunkX, a_ChunkZ));
-
- {
- cCSLock Lock(m_CS);
-
- // Add to queue, issue a warning if too many:
- if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
- {
- LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (%zu)", a_ChunkX, a_ChunkZ, m_Queue.size());
- }
- m_Queue.push_back(cQueueItem{a_ChunkX, a_ChunkZ, a_ForceGenerate, a_Callback});
- }
-
- m_Event.Set();
-}
-
-
-
-
-
-void cChunkGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
-{
- if (m_Generator != nullptr)
- {
- m_Generator->GenerateBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap);
+ return nullptr;
}
-}
-
-
-
-
-void cChunkGenerator::WaitForQueueEmpty(void)
-{
- cCSLock Lock(m_CS);
- while (!m_ShouldTerminate && !m_Queue.empty())
- {
- cCSUnlock Unlock(Lock);
- m_evtRemoved.Wait();
- }
-}
-
-
-
-
-
-int cChunkGenerator::GetQueueLength(void)
-{
- cCSLock Lock(m_CS);
- return static_cast<int>(m_Queue.size());
+ res->Initialize(a_IniFile);
+ return res;
}
@@ -168,166 +65,6 @@ int cChunkGenerator::GetQueueLength(void)
EMCSBiome cChunkGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ)
{
- ASSERT(m_Generator != nullptr);
- return m_Generator->GetBiomeAt(a_BlockX, a_BlockZ);
-}
-
-
-
-
-
-BLOCKTYPE cChunkGenerator::GetIniBlock(cIniFile & a_IniFile, const AString & a_SectionName, const AString & a_ValueName, const AString & a_Default)
-{
- AString BlockType = a_IniFile.GetValueSet(a_SectionName, a_ValueName, a_Default);
- int Block = BlockStringToType(BlockType);
- if (Block < 0)
- {
- LOGWARN("[%s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(), a_Default.c_str());
- return static_cast<BLOCKTYPE>(BlockStringToType(a_Default));
- }
- return static_cast<BLOCKTYPE>(Block);
-}
-
-
-
-
-
-void cChunkGenerator::Execute(void)
-{
- // To be able to display performance information, the generator counts the chunks generated.
- // When the queue gets empty, the count is reset, so that waiting for the queue is not counted into the total time.
- int NumChunksGenerated = 0; // Number of chunks generated since the queue was last empty
- clock_t GenerationStart = clock(); // Clock tick when the queue started to fill
- clock_t LastReportTick = clock(); // Clock tick of the last report made (so that performance isn't reported too often)
-
- while (!m_ShouldTerminate)
- {
- cCSLock Lock(m_CS);
- while (m_Queue.empty())
- {
- if ((NumChunksGenerated > 16) && (clock() - LastReportTick > CLOCKS_PER_SEC))
- {
- /* LOG("Chunk generator performance: %.2f ch / sec (%d ch total)",
- static_cast<double>(NumChunksGenerated) * CLOCKS_PER_SEC/ (clock() - GenerationStart),
- NumChunksGenerated
- ); */
- }
- cCSUnlock Unlock(Lock);
- m_Event.Wait();
- if (m_ShouldTerminate)
- {
- return;
- }
- NumChunksGenerated = 0;
- GenerationStart = clock();
- LastReportTick = clock();
- }
-
- if (m_Queue.empty())
- {
- // Sometimes the queue remains empty
- // If so, we can't do any front() operations on it!
- continue;
- }
-
- cQueueItem item = m_Queue.front(); // Get next chunk from the queue
- bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
- m_Queue.erase(m_Queue.begin()); // Remove the item from the queue
- Lock.Unlock(); // Unlock ASAP
- m_evtRemoved.Set();
-
- // Display perf info once in a while:
- if ((NumChunksGenerated > 512) && (clock() - LastReportTick > 2 * CLOCKS_PER_SEC))
- {
- LOG("Chunk generator performance: %.2f ch / sec (%d ch total)",
- static_cast<double>(NumChunksGenerated) * CLOCKS_PER_SEC / (clock() - GenerationStart),
- NumChunksGenerated
- );
- LastReportTick = clock();
- }
-
- // Skip the chunk if it's already generated and regeneration is not forced. Report as success:
- if (!item.m_ForceGenerate && m_ChunkSink->IsChunkValid(item.m_ChunkX, item.m_ChunkZ))
- {
- LOGD("Chunk [%d, %d] already generated, skipping generation", item.m_ChunkX, item.m_ChunkZ);
- if (item.m_Callback != nullptr)
- {
- item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ, true);
- }
- continue;
- }
-
- // Skip the chunk if the generator is overloaded:
- if (SkipEnabled && !m_ChunkSink->HasChunkAnyClients(item.m_ChunkX, item.m_ChunkZ))
- {
- LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", item.m_ChunkX, item.m_ChunkZ);
- if (item.m_Callback != nullptr)
- {
- item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ, false);
- }
- continue;
- }
-
- // Generate the chunk:
- // LOGD("Generating chunk [%d, %d]", item.m_ChunkX, item.m_ChunkZ);
- DoGenerate(item.m_ChunkX, item.m_ChunkZ);
- if (item.m_Callback != nullptr)
- {
- item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ, true);
- }
- NumChunksGenerated++;
- } // while (!bStop)
-}
-
-
-
-
-
-void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ)
-{
- ASSERT(m_PluginInterface != nullptr);
- ASSERT(m_ChunkSink != nullptr);
-
- cChunkDesc ChunkDesc(a_ChunkX, a_ChunkZ);
- m_PluginInterface->CallHookChunkGenerating(ChunkDesc);
- m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc);
- m_PluginInterface->CallHookChunkGenerated(ChunkDesc);
-
- #ifdef _DEBUG
- // Verify that the generator has produced valid data:
- ChunkDesc.VerifyHeightmap();
- #endif
-
- m_ChunkSink->OnChunkGenerated(ChunkDesc);
-}
-
-
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-// cChunkGenerator::cGenerator:
-
-cChunkGenerator::cGenerator::cGenerator(cChunkGenerator & a_ChunkGenerator) :
- m_ChunkGenerator(a_ChunkGenerator)
-{
-}
-
-
-
-
-
-void cChunkGenerator::cGenerator::Initialize(cIniFile & a_IniFile)
-{
- UNUSED(a_IniFile);
-}
-
-
-
-
-
-EMCSBiome cChunkGenerator::cGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ)
-{
cChunkDef::BiomeMap Biomes;
int Y = 0;
int ChunkX, ChunkZ;
diff --git a/src/Generating/ChunkGenerator.h b/src/Generating/ChunkGenerator.h
index c4be505da..d11e846dc 100644
--- a/src/Generating/ChunkGenerator.h
+++ b/src/Generating/ChunkGenerator.h
@@ -1,25 +1,5 @@
-
-// ChunkGenerator.h
-
-// Interfaces to the cChunkGenerator class representing the thread that generates chunks
-
-/*
-The object takes requests for generating chunks and processes them in a separate thread one by one.
-The requests are not added to the queue if there is already a request with the same coords
-Before generating, the thread checks if the chunk hasn't been already generated.
-It is theoretically possible to have multiple generator threads by having multiple instances of this object,
-but then it MAY happen that the chunk is generated twice.
-If the generator queue is overloaded, the generator skips chunks with no clients in them
-*/
-
-
-
-
-
#pragma once
-#include "../OSSupport/IsThread.h"
-
@@ -32,158 +12,44 @@ class cChunkDesc;
-class cChunkGenerator :
- public cIsThread
+/** The interface that all chunk generators must implement to provide the generated chunks.
+Also a static factory that creates the descendants based on INI file settings.
+The cChunkGeneratorThread uses this interface to generate chunks for a single world.
+Ths calls to generate chunks are synchronous - they don't return until the chunk is fully generated. */
+class cChunkGenerator
{
- typedef cIsThread super;
-
public:
- /** The interface that a class has to implement to become a generator */
- class cGenerator
- {
- public:
- cGenerator(cChunkGenerator & a_ChunkGenerator);
- virtual ~cGenerator() {} // Force a virtual destructor
-
- /** Called to initialize the generator on server startup. */
- virtual void Initialize(cIniFile & a_IniFile);
-
- /** Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading. */
- virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0;
-
- /** Returns the biome at the specified coords. Used by ChunkMap if an invalid chunk is queried for biome. Default implementation uses GenerateBiomes(). */
- virtual EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ);
-
- /** Called in a separate thread to do the actual chunk generation. Generator should generate into a_ChunkDesc. */
- virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) = 0;
-
- protected:
- cChunkGenerator & m_ChunkGenerator;
- } ;
-
-
- /** The interface through which the plugins are called for their OnChunkGenerating / OnChunkGenerated hooks. */
- class cPluginInterface
- {
- public:
- // Force a virtual destructor
- virtual ~cPluginInterface() {}
-
- /** Called when the chunk is about to be generated.
- The generator may be partly or fully overriden by the implementation. */
- virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) = 0;
-
- /** Called after the chunk is generated, before it is handed to the chunk sink.
- a_ChunkDesc contains the generated chunk data. Implementation may modify this data. */
- virtual void CallHookChunkGenerated(cChunkDesc & a_ChunkDesc) = 0;
- } ;
-
-
- /** The interface through which the generated chunks are handed to the cWorld or whoever created us. */
- class cChunkSink
- {
- public:
- // Force a virtual destructor
- virtual ~cChunkSink() {}
-
- /** Called after the chunk has been generated
- The interface may store the chunk, send it over network, whatever.
- The chunk is not expected to be modified, but the generator will survive if the implementation
- changes the data within. All changes are ignored, though. */
- virtual void OnChunkGenerated(cChunkDesc & a_ChunkDesc) = 0;
+ virtual ~cChunkGenerator() {} // Force a virtual destructor
- /** Called just before the chunk generation is started,
- to verify that it hasn't been generated in the meantime.
- If this callback returns true, the chunk is not generated. */
- virtual bool IsChunkValid(int a_ChunkX, int a_ChunkZ) = 0;
+ /** Called to initialize the generator on server startup.
+ Descendants should call Super::Initialize() before initializing themselves. */
+ virtual void Initialize(cIniFile & a_IniFile);
- /** Called when the generator is overloaded to skip chunks that are no longer needed.
- If this callback returns false, the chunk is not generated. */
- virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) = 0;
+ /** Generates the biomes for the specified chunk.
+ Used by the world loader if biomes failed loading. */
+ virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0;
- /** Called to check whether the specified chunk is in the queued state.
- Currently used only in Debug-mode asserts. */
- virtual bool IsChunkQueued(int a_ChunkX, int a_ChunkZ) = 0;
- } ;
+ /** Returns the biome at the specified coords.
+ Used by ChunkMap if an invalid chunk is queried for biome.
+ The default implementation uses GenerateBiomes(). */
+ virtual EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ);
+ /** Does the actual chunk generation.
+ Descendants need to override this and generate into a_ChunkDesc. */
+ virtual void Generate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) = 0;
- cChunkGenerator (void);
- virtual ~cChunkGenerator() override;
-
- /** Read settings from the ini file and initialize in preperation for being started. */
- bool Initialize(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile);
-
- void Stop(void);
-
- /** Queues the chunk for generation
- If a-ForceGenerate is set, the chunk is regenerated even if the data is already present in the chunksink.
- a_Callback is called after the chunk is generated. If the chunk was already present, the callback is still called, even if not regenerating.
- It is legal to set the callback to nullptr, no callback is called then.
- If the generator becomes overloaded and skips this chunk, the callback is still called. */
- void QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate, cChunkCoordCallback * a_Callback = nullptr);
-
- /** Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading. */
- void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap);
-
- void WaitForQueueEmpty(void);
-
- int GetQueueLength(void);
-
+ /** Returns the seed that was read from the INI file. */
int GetSeed(void) const { return m_Seed; }
- /** Returns the biome at the specified coords. Used by ChunkMap if an invalid chunk is queried for biome */
- EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ);
-
- /** Reads a block type from the ini file; returns the blocktype on success, emits a warning and returns a_Default's representation on failure. */
- static BLOCKTYPE GetIniBlock(cIniFile & a_IniFile, const AString & a_SectionName, const AString & a_ValueName, const AString & a_Default);
-
-private:
-
- struct cQueueItem
- {
- /** The chunk coords */
- int m_ChunkX, m_ChunkZ;
-
- /** Force the regeneration of an already existing chunk */
- bool m_ForceGenerate;
+ /** Creates and initializes the entire generator based on the settings in the INI file.
+ Initializes the generator, so that it can be used immediately after this call returns. */
+ static std::unique_ptr<cChunkGenerator> CreateFromIniFile(cIniFile & a_IniFile);
- /** Callback to call after generating. */
- cChunkCoordCallback * m_Callback;
- };
- typedef std::list<cQueueItem> cGenQueue;
+protected:
-
- /** Seed used for the generator. */
+ /** The main seed, read from the INI file, used for the entire generator. */
int m_Seed;
-
- /** CS protecting access to the queue. */
- cCriticalSection m_CS;
-
- /** Queue of the chunks to be generated. Protected against multithreaded access by m_CS. */
- cGenQueue m_Queue;
-
- /** Set when an item is added to the queue or the thread should terminate. */
- cEvent m_Event;
-
- /** Set when an item is removed from the queue. */
- cEvent m_evtRemoved;
-
- /** The actual generator engine used to generate chunks. */
- cGenerator * m_Generator;
-
- /** The plugin interface that may modify the generated chunks */
- cPluginInterface * m_PluginInterface;
-
- /** The destination where the generated chunks are sent */
- cChunkSink * m_ChunkSink;
-
-
- // cIsThread override:
- virtual void Execute(void) override;
-
- /** Generates the specified chunk and sets it into the chunksink. */
- void DoGenerate(int a_ChunkX, int a_ChunkZ);
};
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index c73ecf6cc..1cb3ed7c9 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -6,9 +6,7 @@
#include "Globals.h"
#include "ComposableGenerator.h"
-#include "../World.h"
#include "../IniFile.h"
-#include "../Root.h"
// Individual composed algorithms:
#include "BioGen.h"
@@ -110,8 +108,7 @@ cTerrainCompositionGenPtr cTerrainCompositionGen::CreateCompositionGen(cIniFile
////////////////////////////////////////////////////////////////////////////////
// cComposableGenerator:
-cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
- super(a_ChunkGenerator),
+cComposableGenerator::cComposableGenerator():
m_BiomeGen(),
m_ShapeGen(),
m_CompositionGen()
@@ -124,7 +121,7 @@ cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
void cComposableGenerator::Initialize(cIniFile & a_IniFile)
{
- super::Initialize(a_IniFile);
+ Super::Initialize(a_IniFile);
InitBiomeGen(a_IniFile);
InitShapeGen(a_IniFile);
@@ -148,7 +145,7 @@ void cComposableGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef:
-void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc)
+void cComposableGenerator::Generate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc)
{
if (a_ChunkDesc.IsUsingDefaultBiomes())
{
@@ -195,7 +192,7 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a
void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
{
bool CacheOffByDefault = false;
- m_BiomeGen = cBiomeGen::CreateBiomeGen(a_IniFile, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
+ m_BiomeGen = cBiomeGen::CreateBiomeGen(a_IniFile, m_Seed, CacheOffByDefault);
// Add a cache, if requested:
// The default is 16 * 128 caches, which is 2 MiB of RAM. Reasonable, for the amount of work this is saving.
@@ -231,7 +228,7 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
void cComposableGenerator::InitShapeGen(cIniFile & a_IniFile)
{
bool CacheOffByDefault = false;
- m_ShapeGen = cTerrainShapeGen::CreateShapeGen(a_IniFile, m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
+ m_ShapeGen = cTerrainShapeGen::CreateShapeGen(a_IniFile, m_BiomeGen, m_Seed, CacheOffByDefault);
/*
// TODO
@@ -258,7 +255,7 @@ void cComposableGenerator::InitShapeGen(cIniFile & a_IniFile)
void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
{
- m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, m_BiomeGen, m_ShapeGen, m_ChunkGenerator.GetSeed());
+ m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, m_BiomeGen, m_ShapeGen, m_Seed);
// Add a cache over the composition generator:
// Even a cache of size 1 is useful due to the CompositedHeiGen cache after us doing re-composition on its misses
@@ -279,7 +276,6 @@ void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
- int Seed = m_ChunkGenerator.GetSeed();
eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
auto seaLevel = a_IniFile.GetValueI("Generator", "SeaLevel");
@@ -298,7 +294,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
// Finishers, alpha-sorted:
if (NoCaseCompare(finisher, "Animals") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenPassiveMobs(Seed, a_IniFile, Dimension)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenPassiveMobs(m_Seed, a_IniFile, Dimension)));
}
else if (NoCaseCompare(finisher, "BottomLava") == 0)
{
@@ -327,15 +323,15 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
AllowedBlocks.push_back(E_BLOCK_HARDENED_CLAY);
AllowedBlocks.push_back(E_BLOCK_STAINED_CLAY);
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSingleTopBlock(Seed, E_BLOCK_DEAD_BUSH, AllowedBiomes, 2, AllowedBlocks)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSingleTopBlock(m_Seed, E_BLOCK_DEAD_BUSH, AllowedBiomes, 2, AllowedBlocks)));
}
else if (NoCaseCompare(finisher, "DirectOverhangs") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cStructGenDirectOverhangs(Seed)));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenDirectOverhangs(m_Seed)));
}
else if (NoCaseCompare(finisher, "DirtPockets") == 0)
{
- auto gen = std::make_shared<cFinishGenOrePockets>(Seed + 1, cFinishGenOrePockets::DefaultNaturalPatches());
+ auto gen = std::make_shared<cFinishGenOrePockets>(m_Seed + 1, cFinishGenOrePockets::DefaultNaturalPatches());
if (gen->Initialize(a_IniFile, "DirtPockets"))
{
m_FinishGens.push_back(gen);
@@ -343,12 +339,12 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
}
else if (NoCaseCompare(finisher, "DistortedMembraneOverhangs") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cStructGenDistortedMembraneOverhangs(Seed)));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenDistortedMembraneOverhangs(m_Seed)));
}
else if (NoCaseCompare(finisher, "DualRidgeCaves") == 0)
{
float Threshold = static_cast<float>(a_IniFile.GetValueSetF("Generator", "DualRidgeCavesThreshold", 0.3));
- m_FinishGens.push_back(cFinishGenPtr(new cStructGenDualRidgeCaves(Seed, Threshold)));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenDualRidgeCaves(m_Seed, Threshold)));
}
else if (NoCaseCompare(finisher, "DungeonRooms") == 0)
{
@@ -356,11 +352,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int MaxSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMaxSize", 7);
int MinSize = a_IniFile.GetValueSetI("Generator", "DungeonRoomsMinSize", 5);
AString HeightDistrib = a_IniFile.GetValueSet ("Generator", "DungeonRoomsHeightDistrib", "0, 0; 10, 10; 11, 500; 40, 500; 60, 40; 90, 1");
- m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_ShapeGen, Seed, GridSize, MaxSize, MinSize, HeightDistrib)));
+ m_FinishGens.push_back(cFinishGenPtr(new cDungeonRoomsFinisher(m_ShapeGen, m_Seed, GridSize, MaxSize, MinSize, HeightDistrib)));
}
else if (NoCaseCompare(finisher, "GlowStone") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenGlowStone(Seed)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenGlowStone(m_Seed)));
}
else if (NoCaseCompare(finisher, "Ice") == 0)
{
@@ -369,11 +365,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
else if (NoCaseCompare(finisher, "LavaLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "LavaLakesProbability", 10);
- m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, m_ShapeGen, Probability)));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(m_Seed * 5 + 16873, E_BLOCK_STATIONARY_LAVA, m_ShapeGen, Probability)));
}
else if (NoCaseCompare(finisher, "LavaSprings") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenFluidSprings(m_Seed, E_BLOCK_LAVA, a_IniFile, Dimension)));
}
else if (NoCaseCompare(finisher, "Lilypads") == 0)
{
@@ -387,11 +383,11 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
AllowedBlocks.push_back(E_BLOCK_WATER);
AllowedBlocks.push_back(E_BLOCK_STATIONARY_WATER);
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSingleTopBlock(Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSingleTopBlock(m_Seed, E_BLOCK_LILY_PAD, AllowedBiomes, 4, AllowedBlocks)));
}
else if (NoCaseCompare(finisher, "MarbleCaves") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cStructGenMarbleCaves(Seed)));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenMarbleCaves(m_Seed)));
}
else if (NoCaseCompare(finisher, "MineShafts") == 0)
{
@@ -402,22 +398,22 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200);
int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200);
m_FinishGens.push_back(cFinishGenPtr(new cStructGenMineShafts(
- Seed, GridSize, MaxOffset, MaxSystemSize,
+ m_Seed, GridSize, MaxOffset, MaxSystemSize,
ChanceCorridor, ChanceCrossing, ChanceStaircase
)));
}
else if (NoCaseCompare(finisher, "NaturalPatches") == 0)
{
- m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(Seed + 1, cFinishGenOreNests::DefaultNaturalPatches()));
+ m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(m_Seed + 1, cFinishGenOreNests::DefaultNaturalPatches()));
}
else if (NoCaseCompare(finisher, "NetherClumpFoliage") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenNetherClumpFoliage(Seed)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenNetherClumpFoliage(m_Seed)));
}
else if (NoCaseCompare(*itr, "NetherForts") == 0)
{
LOGINFO("The NetherForts finisher is obsolete, you should use \"PieceStructures: NetherFort\" instead.");
- auto gen = std::make_shared<cPieceStructuresGen>(Seed);
+ auto gen = std::make_shared<cPieceStructuresGen>(m_Seed);
if (gen->Initialize("NetherFort", seaLevel, m_BiomeGen, m_CompositedHeightCache))
{
m_FinishGens.push_back(gen);
@@ -425,15 +421,15 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
}
else if (NoCaseCompare(finisher, "NetherOreNests") == 0)
{
- m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(Seed + 2, cFinishGenOreNests::DefaultNetherOres()));
+ m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(m_Seed + 2, cFinishGenOreNests::DefaultNetherOres()));
}
else if (NoCaseCompare(finisher, "OreNests") == 0)
{
- m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(Seed + 3, cFinishGenOreNests::DefaultOverworldOres()));
+ m_FinishGens.push_back(std::make_shared<cFinishGenOreNests>(m_Seed + 3, cFinishGenOreNests::DefaultOverworldOres()));
}
else if (NoCaseCompare(finisher, "OrePockets") == 0)
{
- auto gen = std::make_shared<cFinishGenOrePockets>(Seed + 2, cFinishGenOrePockets::DefaultOverworldOres());
+ auto gen = std::make_shared<cFinishGenOrePockets>(m_Seed + 2, cFinishGenOrePockets::DefaultOverworldOres());
if (gen->Initialize(a_IniFile, "OrePockets"))
{
m_FinishGens.push_back(gen);
@@ -442,7 +438,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
else if (NoCaseCompare(finisher, "OverworldClumpFlowers") == 0)
{
auto flowers = cFinishGenClumpTopBlock::ParseIniFile(a_IniFile, "OverworldClumpFlowers");
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenClumpTopBlock(Seed, flowers)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenClumpTopBlock(m_Seed, flowers)));
}
else if (NoCaseCompare(finisher, "PieceStructures") == 0)
{
@@ -452,7 +448,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
continue;
}
- auto gen = std::make_shared<cPieceStructuresGen>(Seed);
+ auto gen = std::make_shared<cPieceStructuresGen>(m_Seed);
if (gen->Initialize(split[1], seaLevel, m_BiomeGen, m_CompositedHeightCache))
{
m_FinishGens.push_back(gen);
@@ -470,7 +466,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
else if (NoCaseCompare(finisher, "RainbowRoads") == 0)
{
LOGINFO("The RainbowRoads finisher is obsolete, you should use \"PieceStructures: RainbowRoads\" instead.");
- auto gen = std::make_shared<cPieceStructuresGen>(Seed);
+ auto gen = std::make_shared<cPieceStructuresGen>(m_Seed);
if (gen->Initialize("RainbowRoads", seaLevel, m_BiomeGen, m_CompositedHeightCache))
{
m_FinishGens.push_back(gen);
@@ -478,7 +474,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
}
else if (NoCaseCompare(finisher, "Ravines") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cStructGenRavines(Seed, 128)));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenRavines(m_Seed, 128)));
}
else if (NoCaseCompare(finisher, "RoughRavines") == 0)
{
@@ -499,7 +495,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
double MaxCeilingHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMaxCeilingHeightCenter", 58);
double MinCeilingHeightCenter = a_IniFile.GetValueSetF("Generator", "RoughRavinesMinCeilingHeightCenter", 36);
m_FinishGens.push_back(cFinishGenPtr(new cRoughRavines(
- Seed, MaxSize, MinSize,
+ m_Seed, MaxSize, MinSize,
static_cast<float>(MaxCenterWidth),
static_cast<float>(MinCenterWidth),
static_cast<float>(MaxRoughness),
@@ -517,7 +513,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
}
else if (NoCaseCompare(finisher, "SoulsandRims") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSoulsandRims(Seed)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenSoulsandRims(m_Seed)));
}
else if (NoCaseCompare(finisher, "Snow") == 0)
{
@@ -527,20 +523,20 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
int MaxCactusHeight = a_IniFile.GetValueI("Plants", "MaxCactusHeight", 3);
int MaxSugarcaneHeight = a_IniFile.GetValueI("Plants", "MaxSugarcaneHeight", 3);
- m_FinishGens.push_back(std::make_shared<cFinishGenSprinkleFoliage>(Seed, MaxCactusHeight, MaxSugarcaneHeight));
+ m_FinishGens.push_back(std::make_shared<cFinishGenSprinkleFoliage>(m_Seed, MaxCactusHeight, MaxSugarcaneHeight));
}
else if (NoCaseCompare(finisher, "TallGrass") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenTallGrass(Seed)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenTallGrass(m_Seed)));
}
else if (NoCaseCompare(finisher, "Trees") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(Seed, m_BiomeGen, m_ShapeGen, m_CompositionGen)));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenTrees(m_Seed, m_BiomeGen, m_ShapeGen, m_CompositionGen)));
}
else if (NoCaseCompare(finisher, "UnderwaterBases") == 0)
{
LOGINFO("The UnderwaterBases finisher is obsolete, you should use \"PieceStructures: UnderwaterBases\" instead.");
- auto gen = std::make_shared<cPieceStructuresGen>(Seed);
+ auto gen = std::make_shared<cPieceStructuresGen>(m_Seed);
if (gen->Initialize("UnderwaterBases", seaLevel, m_BiomeGen, m_CompositedHeightCache))
{
m_FinishGens.push_back(gen);
@@ -556,28 +552,28 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80);
AString PrefabList = a_IniFile.GetValueSet("Generator", "VillagePrefabs", "PlainsVillage, SandVillage");
auto Prefabs = StringSplitAndTrim(PrefabList, ",");
- m_FinishGens.push_back(std::make_shared<cVillageGen>(Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_CompositedHeightCache, seaLevel, Prefabs));
+ m_FinishGens.push_back(std::make_shared<cVillageGen>(m_Seed, GridSize, MaxOffset, MaxDepth, MaxSize, MinDensity, MaxDensity, m_BiomeGen, m_CompositedHeightCache, seaLevel, Prefabs));
}
else if (NoCaseCompare(finisher, "Vines") == 0)
{
int Level = a_IniFile.GetValueSetI("Generator", "VinesLevel", 40);
- m_FinishGens.push_back(std::make_shared<cFinishGenVines>(Seed, Level));
+ m_FinishGens.push_back(std::make_shared<cFinishGenVines>(m_Seed, Level));
}
else if (NoCaseCompare(finisher, "WaterLakes") == 0)
{
int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25);
- m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, m_ShapeGen, Probability)));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenLakes(m_Seed * 3 + 652, E_BLOCK_STATIONARY_WATER, m_ShapeGen, Probability)));
}
else if (NoCaseCompare(finisher, "WaterSprings") == 0)
{
- m_FinishGens.push_back(cFinishGenPtr(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension)));
+ m_FinishGens.push_back(cFinishGenPtr(new cFinishGenFluidSprings(m_Seed, E_BLOCK_WATER, a_IniFile, Dimension)));
}
else if (NoCaseCompare(finisher, "WormNestCaves") == 0)
{
int Size = a_IniFile.GetValueSetI("Generator", "WormNestCavesSize", 64);
int Grid = a_IniFile.GetValueSetI("Generator", "WormNestCavesGrid", 96);
int MaxOffset = a_IniFile.GetValueSetI("Generator", "WormNestMaxOffset", 32);
- m_FinishGens.push_back(cFinishGenPtr(new cStructGenWormNestCaves(Seed, Size, Grid, MaxOffset)));
+ m_FinishGens.push_back(cFinishGenPtr(new cStructGenWormNestCaves(m_Seed, Size, Grid, MaxOffset)));
}
else
{
diff --git a/src/Generating/ComposableGenerator.h b/src/Generating/ComposableGenerator.h
index 0b7e795d2..2eed12b74 100644
--- a/src/Generating/ComposableGenerator.h
+++ b/src/Generating/ComposableGenerator.h
@@ -183,17 +183,17 @@ typedef std::list<cFinishGenPtr> cFinishGenList;
class cComposableGenerator :
- public cChunkGenerator::cGenerator
+ public cChunkGenerator
{
- typedef cChunkGenerator::cGenerator super;
+ typedef cChunkGenerator Super;
public:
- cComposableGenerator(cChunkGenerator & a_ChunkGenerator);
+ cComposableGenerator();
// cChunkGenerator::cGenerator overrides:
virtual void Initialize(cIniFile & a_IniFile) override;
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
- virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
+ virtual void Generate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
protected:
// The generator's composition:
diff --git a/src/Generating/CompositedHeiGen.h b/src/Generating/CompositedHeiGen.h
index c4e6ce77d..2db781e04 100644
--- a/src/Generating/CompositedHeiGen.h
+++ b/src/Generating/CompositedHeiGen.h
@@ -34,7 +34,7 @@ public:
{
cChunkDesc::Shape shape;
m_ShapeGen->GenShape(a_ChunkX, a_ChunkZ, shape);
- cChunkDesc desc(a_ChunkX, a_ChunkZ);
+ cChunkDesc desc({a_ChunkX, a_ChunkZ});
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, desc.GetBiomeMap()); // Need to initialize biomes for the composition gen
desc.SetHeightFromShape(shape);
m_CompositionGen->ComposeTerrain(desc, shape);
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index 3c608e026..7aece7219 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -12,7 +12,6 @@
#include "FinishGen.h"
#include "../Simulator/FluidSimulator.h" // for cFluidSimulator::CanWashAway()
#include "../Simulator/FireSimulator.h"
-#include "../World.h"
#include "../IniFile.h"
#include "../MobSpawner.h"
diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp
index 4972a0505..64f5ed05f 100644
--- a/src/Generating/Noise3DGenerator.cpp
+++ b/src/Generating/Noise3DGenerator.cpp
@@ -148,8 +148,8 @@ public:
////////////////////////////////////////////////////////////////////////////////
// cNoise3DGenerator:
-cNoise3DGenerator::cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator) :
- super(a_ChunkGenerator),
+cNoise3DGenerator::cNoise3DGenerator():
+ Super(),
m_Perlin(1000),
m_Cubic(1000)
{
@@ -207,7 +207,7 @@ void cNoise3DGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::Bi
-void cNoise3DGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc)
+void cNoise3DGenerator::Generate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc)
{
NOISE_DATATYPE Noise[17 * 257 * 17];
GenerateNoiseArray(a_ChunkX, a_ChunkZ, Noise);
diff --git a/src/Generating/Noise3DGenerator.h b/src/Generating/Noise3DGenerator.h
index 91408a32b..fa760f5f3 100644
--- a/src/Generating/Noise3DGenerator.h
+++ b/src/Generating/Noise3DGenerator.h
@@ -21,17 +21,17 @@
class cNoise3DGenerator :
- public cChunkGenerator::cGenerator
+ public cChunkGenerator
{
- typedef cChunkGenerator::cGenerator super;
+ typedef cChunkGenerator Super;
public:
- cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator);
+ cNoise3DGenerator();
virtual ~cNoise3DGenerator() override;
virtual void Initialize(cIniFile & a_IniFile) override;
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
- virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
+ virtual void Generate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
protected:
// Linear interpolation step sizes, must be divisors of cChunkDef::Width and cChunkDef::Height, respectively:
diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp
index 918467f93..266308983 100644
--- a/src/Generating/StructGen.cpp
+++ b/src/Generating/StructGen.cpp
@@ -19,7 +19,7 @@ void cStructGenTrees::GenFinish(cChunkDesc & a_ChunkDesc)
int ChunkX = a_ChunkDesc.GetChunkX();
int ChunkZ = a_ChunkDesc.GetChunkZ();
- cChunkDesc WorkerDesc(ChunkX, ChunkZ);
+ cChunkDesc WorkerDesc({ChunkX, ChunkZ});
// Generate trees:
for (int x = 0; x <= 2; x++)
@@ -34,7 +34,7 @@ void cStructGenTrees::GenFinish(cChunkDesc & a_ChunkDesc)
if ((x != 1) || (z != 1))
{
Dest = &WorkerDesc;
- WorkerDesc.SetChunkCoords(BaseX, BaseZ);
+ WorkerDesc.SetChunkCoords({BaseX, BaseZ});
// TODO: This may cause a lot of wasted calculations, instead of pulling data out of a single (cChunkDesc) cache
diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp
index 1456c1d15..824c8cecd 100644
--- a/src/Generating/Trees.cpp
+++ b/src/Generating/Trees.cpp
@@ -5,7 +5,6 @@
#include "Globals.h"
#include "Trees.h"
-#include "../World.h"
@@ -1056,89 +1055,3 @@ void GetSmallJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise &
PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_OtherBlocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_JUNGLE);
a_OtherBlocks.push_back(sSetBlock(a_BlockX, hei, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_JUNGLE));
}
-
-
-
-
-
-bool GetLargeTreeAdjustment(cWorld & a_World, int & a_X, int & a_Y, int & a_Z, NIBBLETYPE a_Meta)
-{
- bool IsLarge = true;
- a_Meta = a_Meta & 0x07;
-
- // Check to see if we are the northwest corner
- for (int x = 0; x < 2; ++x)
- {
- for (int z = 0; z < 2; ++z)
- {
- NIBBLETYPE meta;
- BLOCKTYPE type;
- a_World.GetBlockTypeMeta(a_X + x, a_Y, a_Z + z, type, meta);
- IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
- }
- }
-
- if (IsLarge)
- {
- return true;
- }
-
- IsLarge = true;
- // Check to see if we are the southwest corner
- for (int x = 0; x < 2; ++x)
- {
- for (int z = 0; z > -2; --z)
- {
- NIBBLETYPE meta;
- BLOCKTYPE type;
- a_World.GetBlockTypeMeta(a_X + x, a_Y, a_Z + z, type, meta);
- IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
- }
- }
-
- if (IsLarge)
- {
- --a_Z;
- return true;
- }
-
- IsLarge = true;
- // Check to see if we are the southeast corner
- for (int x = 0; x > -2; --x)
- {
- for (int z = 0; z > -2; --z)
- {
- NIBBLETYPE meta;
- BLOCKTYPE type;
- a_World.GetBlockTypeMeta(a_X + x, a_Y, a_Z + z, type, meta);
- IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
- }
- }
-
- if (IsLarge)
- {
- --a_Z;
- --a_X;
- return true;
- }
-
- IsLarge = true;
- // Check to see if we are the northeast corner
- for (int x = 0; x > -2; --x)
- {
- for (int z = 0; z < 2; ++z)
- {
- NIBBLETYPE meta;
- BLOCKTYPE type;
- a_World.GetBlockTypeMeta(a_X + x, a_Y, a_Z + z, type, meta);
- IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
- }
- }
-
- if (IsLarge)
- {
- --a_X;
- }
-
- return IsLarge;
-}
diff --git a/src/Generating/Trees.h b/src/Generating/Trees.h
index db9940d0a..ff7ae1744 100644
--- a/src/Generating/Trees.h
+++ b/src/Generating/Trees.h
@@ -19,8 +19,6 @@ logs can overwrite others(leaves), but others shouldn't overwrite logs. This is
#include "../Noise/Noise.h"
-class cWorld;
-
@@ -104,9 +102,3 @@ void GetLargeJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise &
/** Generates an image of a small jungle tree (1x1 trunk) */
void GetSmallJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_LogBlocks, sSetBlockVector & a_OtherBlocks);
-
-/** Moves the x and z coordinants to the north-west corner of a 2x2 of saplings. Returns true if a 2x2 was found, otherwise it returns false */
-bool GetLargeTreeAdjustment(cWorld & a_World, int & a_X, int & a_Y, int & a_Z, NIBBLETYPE a_Meta);
-
-
-
diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp
index 8c445c8e4..c10c69ccd 100644
--- a/src/LightingThread.cpp
+++ b/src/LightingThread.cpp
@@ -237,7 +237,7 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
{
if (a_Item.m_CallbackAfter != nullptr)
{
- a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ, true);
+ a_Item.m_CallbackAfter->Call({a_Item.m_ChunkX, a_Item.m_ChunkZ}, true);
}
return;
}
@@ -318,7 +318,7 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
if (a_Item.m_CallbackAfter != nullptr)
{
- a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ, true);
+ a_Item.m_CallbackAfter->Call({a_Item.m_ChunkX, a_Item.m_ChunkZ}, true);
}
}
diff --git a/src/SpawnPrepare.cpp b/src/SpawnPrepare.cpp
index d861a498d..e9f9e3b09 100644
--- a/src/SpawnPrepare.cpp
+++ b/src/SpawnPrepare.cpp
@@ -21,9 +21,9 @@ protected:
std::shared_ptr<cSpawnPrepare> m_SpawnPrepare;
- virtual void Call(int a_ChunkX, int a_ChunkZ, bool a_IsSuccess) override
+ virtual void Call(cChunkCoords a_Coords, bool a_IsSuccess) override
{
- m_SpawnPrepare->PreparedChunkCallback(a_ChunkX, a_ChunkZ);
+ m_SpawnPrepare->PreparedChunkCallback(a_Coords.m_ChunkX, a_Coords.m_ChunkZ);
}
};
diff --git a/src/World.cpp b/src/World.cpp
index 2b151af8e..a619ea9c6 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -1648,13 +1648,13 @@ void cWorld::GrowTreeFromSapling(int a_X, int a_Y, int a_Z, NIBBLETYPE a_Sapling
case E_META_SAPLING_ACACIA: GetAcaciaTreeImage (a_X, a_Y, a_Z, Noise, WorldAge, Logs, Other); break;
case E_META_SAPLING_JUNGLE:
{
- bool IsLarge = GetLargeTreeAdjustment(*this, a_X, a_Y, a_Z, a_SaplingMeta);
+ bool IsLarge = GetLargeTreeAdjustment(a_X, a_Y, a_Z, a_SaplingMeta);
GetJungleTreeImage (a_X, a_Y, a_Z, Noise, WorldAge, Logs, Other, IsLarge);
break;
}
case E_META_SAPLING_DARK_OAK:
{
- if (!GetLargeTreeAdjustment(*this, a_X, a_Y, a_Z, a_SaplingMeta))
+ if (!GetLargeTreeAdjustment(a_X, a_Y, a_Z, a_SaplingMeta))
{
return;
}
@@ -1672,6 +1672,92 @@ void cWorld::GrowTreeFromSapling(int a_X, int a_Y, int a_Z, NIBBLETYPE a_Sapling
+bool cWorld::GetLargeTreeAdjustment(int & a_X, int & a_Y, int & a_Z, NIBBLETYPE a_Meta)
+{
+ bool IsLarge = true;
+ a_Meta = a_Meta & 0x07;
+
+ // Check to see if we are the northwest corner
+ for (int x = 0; x < 2; ++x)
+ {
+ for (int z = 0; z < 2; ++z)
+ {
+ NIBBLETYPE meta;
+ BLOCKTYPE type;
+ GetBlockTypeMeta(a_X + x, a_Y, a_Z + z, type, meta);
+ IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
+ }
+ }
+
+ if (IsLarge)
+ {
+ return true;
+ }
+
+ IsLarge = true;
+ // Check to see if we are the southwest corner
+ for (int x = 0; x < 2; ++x)
+ {
+ for (int z = 0; z > -2; --z)
+ {
+ NIBBLETYPE meta;
+ BLOCKTYPE type;
+ GetBlockTypeMeta(a_X + x, a_Y, a_Z + z, type, meta);
+ IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
+ }
+ }
+
+ if (IsLarge)
+ {
+ --a_Z;
+ return true;
+ }
+
+ IsLarge = true;
+ // Check to see if we are the southeast corner
+ for (int x = 0; x > -2; --x)
+ {
+ for (int z = 0; z > -2; --z)
+ {
+ NIBBLETYPE meta;
+ BLOCKTYPE type;
+ GetBlockTypeMeta(a_X + x, a_Y, a_Z + z, type, meta);
+ IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
+ }
+ }
+
+ if (IsLarge)
+ {
+ --a_Z;
+ --a_X;
+ return true;
+ }
+
+ IsLarge = true;
+ // Check to see if we are the northeast corner
+ for (int x = 0; x > -2; --x)
+ {
+ for (int z = 0; z < 2; ++z)
+ {
+ NIBBLETYPE meta;
+ BLOCKTYPE type;
+ GetBlockTypeMeta(a_X + x, a_Y, a_Z + z, type, meta);
+ IsLarge = IsLarge && (type == E_BLOCK_SAPLING) && ((a_Meta & meta) == a_Meta);
+ }
+ }
+
+ if (IsLarge)
+ {
+ --a_X;
+ }
+
+ return IsLarge;
+}
+
+
+
+
+
void cWorld::GrowTreeByBiome(int a_X, int a_Y, int a_Z)
{
cNoise Noise(m_Generator.GetSeed());
@@ -2514,7 +2600,7 @@ void cWorld::QueueSetChunkData(cSetChunkDataPtr a_SetChunkData)
if (!a_SetChunkData->AreBiomesValid())
{
// The biomes are not assigned, get them from the generator:
- m_Generator.GenerateBiomes(a_SetChunkData->GetChunkX(), a_SetChunkData->GetChunkZ(), a_SetChunkData->GetBiomes());
+ m_Generator.GenerateBiomes({a_SetChunkData->GetChunkX(), a_SetChunkData->GetChunkZ()}, a_SetChunkData->GetBiomes());
a_SetChunkData->MarkBiomesValid();
}
@@ -3157,7 +3243,7 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ)
{
m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ);
- m_Generator.QueueGenerateChunk(a_ChunkX, a_ChunkZ, true);
+ m_Generator.QueueGenerateChunk({a_ChunkX, a_ChunkZ}, true);
}
@@ -3770,27 +3856,27 @@ void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc
-bool cWorld::cChunkGeneratorCallbacks::IsChunkValid(int a_ChunkX, int a_ChunkZ)
+bool cWorld::cChunkGeneratorCallbacks::IsChunkValid(cChunkCoords a_Coords)
{
- return m_World->IsChunkValid(a_ChunkX, a_ChunkZ);
+ return m_World->IsChunkValid(a_Coords.m_ChunkX, a_Coords.m_ChunkZ);
}
-bool cWorld::cChunkGeneratorCallbacks::IsChunkQueued(int a_ChunkX, int a_ChunkZ)
+bool cWorld::cChunkGeneratorCallbacks::IsChunkQueued(cChunkCoords a_Coords)
{
- return m_World->IsChunkQueued(a_ChunkX, a_ChunkZ);
+ return m_World->IsChunkQueued(a_Coords.m_ChunkX, a_Coords.m_ChunkZ);
}
-bool cWorld::cChunkGeneratorCallbacks::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ)
+bool cWorld::cChunkGeneratorCallbacks::HasChunkAnyClients(cChunkCoords a_Coords)
{
- return m_World->HasChunkAnyClients(a_ChunkX, a_ChunkZ);
+ return m_World->HasChunkAnyClients(a_Coords.m_ChunkX, a_Coords.m_ChunkZ);
}
diff --git a/src/World.h b/src/World.h
index 7e18c53c3..b9fa57d8a 100644
--- a/src/World.h
+++ b/src/World.h
@@ -8,7 +8,7 @@
#include "Simulator/SimulatorManager.h"
#include "ChunkMap.h"
#include "WorldStorage/WorldStorage.h"
-#include "Generating/ChunkGenerator.h"
+#include "ChunkGeneratorThread.h"
#include "ChunkSender.h"
#include "Defines.h"
#include "LightingThread.h"
@@ -824,7 +824,7 @@ public:
// tolua_end
- cChunkGenerator & GetGenerator(void) { return m_Generator; }
+ cChunkGeneratorThread & GetGenerator(void) { return m_Generator; }
cWorldStorage & GetStorage (void) { return m_Storage; }
cChunkMap * GetChunkMap (void) { return m_ChunkMap.get(); }
@@ -883,16 +883,16 @@ private:
/** Implementation of the callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
class cChunkGeneratorCallbacks :
- public cChunkGenerator::cChunkSink,
- public cChunkGenerator::cPluginInterface
+ public cChunkGeneratorThread::cChunkSink,
+ public cChunkGeneratorThread::cPluginInterface
{
cWorld * m_World;
// cChunkSink overrides:
virtual void OnChunkGenerated (cChunkDesc & a_ChunkDesc) override;
- virtual bool IsChunkValid (int a_ChunkX, int a_ChunkZ) override;
- virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) override;
- virtual bool IsChunkQueued (int a_ChunkX, int a_ChunkZ) override;
+ virtual bool IsChunkValid (cChunkCoords a_Coords) override;
+ virtual bool HasChunkAnyClients(cChunkCoords a_Coords) override;
+ virtual bool IsChunkQueued (cChunkCoords a_Coords) override;
// cPluginInterface overrides:
virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) override;
@@ -1031,8 +1031,8 @@ private:
Only used when this world is an Overworld. */
AString m_LinkedEndWorldName;
-
- cChunkGenerator m_Generator;
+ /** The thread responsible for generating chunks. */
+ cChunkGeneratorThread m_Generator;
cScoreboard m_Scoreboard;
cMapManager m_MapManager;
@@ -1143,4 +1143,8 @@ private:
Modifies the a_SetChunkData - moves the entities contained in it into the chunk. */
void SetChunkData(cSetChunkData & a_SetChunkData);
+ /** Checks if the sapling at the specified block coord is a part of a large-tree sapling (2x2).
+ If so, adjusts the X and Z coords so that they point to the northwest (XM ZM) corner of the sapling area and returns true.
+ Returns false if not a part of large-tree sapling. */
+ bool GetLargeTreeAdjustment(int & a_BlockX, int & a_BlockY, int & a_BlockZ, NIBBLETYPE a_SaplingMeta);
}; // tolua_export
diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp
index a3aff0749..d1f9abf74 100644
--- a/src/WorldStorage/WorldStorage.cpp
+++ b/src/WorldStorage/WorldStorage.cpp
@@ -240,7 +240,7 @@ bool cWorldStorage::LoadOneChunk(void)
// Call the callback, if specified:
if (ToLoad.m_Callback != nullptr)
{
- ToLoad.m_Callback->Call(ToLoad.m_ChunkX, ToLoad.m_ChunkZ, res);
+ ToLoad.m_Callback->Call({ToLoad.m_ChunkX, ToLoad.m_ChunkZ}, res);
}
return res;
}
@@ -274,7 +274,7 @@ bool cWorldStorage::SaveOneChunk(void)
// Call the callback, if specified:
if (ToSave.m_Callback != nullptr)
{
- ToSave.m_Callback->Call(ToSave.m_ChunkX, ToSave.m_ChunkZ, Status);
+ ToSave.m_Callback->Call({ToSave.m_ChunkX, ToSave.m_ChunkZ}, Status);
}
return true;
}