commit
781b3303a5
@ -410,7 +410,7 @@ typedef std::list<cChunkCoordsWithBool> cChunkCoordsWithBoolList;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Interface class used as a callback for operations that involve chunk coords
|
/** Interface class used as a callback for operations that involve chunk coords */
|
||||||
class cChunkCoordCallback
|
class cChunkCoordCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -424,6 +424,27 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Provides storage for a set of chunk coords together with a callback.
|
||||||
|
Used for chunk queues that notify about processed items. */
|
||||||
|
class cChunkCoordsWithCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cChunkCoordsWithCallback(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback):
|
||||||
|
m_ChunkX(a_ChunkX),
|
||||||
|
m_ChunkZ(a_ChunkZ),
|
||||||
|
m_Callback(a_Callback)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int m_ChunkX;
|
||||||
|
int m_ChunkZ;
|
||||||
|
cChunkCoordCallback * m_Callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Generic template that can store any kind of data together with a triplet of 3 coords*/
|
/** Generic template that can store any kind of data together with a triplet of 3 coords*/
|
||||||
template <typename X> class cCoordWithData
|
template <typename X> class cCoordWithData
|
||||||
{
|
{
|
||||||
|
@ -2349,6 +2349,103 @@ void cChunkMap::TouchChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::PrepareChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ);
|
||||||
|
|
||||||
|
// If the chunk is not prepared, queue it in the lighting thread, that will do all the needed processing:
|
||||||
|
if ((Chunk == nullptr) || !Chunk->IsValid() || !Chunk->IsLightValid())
|
||||||
|
{
|
||||||
|
m_World->GetLightingThread().QueueChunk(a_ChunkX, a_ChunkZ, a_Callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The chunk is present and lit, just call the callback:
|
||||||
|
if (a_Callback != nullptr)
|
||||||
|
{
|
||||||
|
a_Callback->Call(a_ChunkX, a_ChunkZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cChunkMap::GenerateChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ);
|
||||||
|
if (Chunk == nullptr)
|
||||||
|
{
|
||||||
|
// Generic error while getting the chunk - out of memory?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try loading the chunk:
|
||||||
|
if ((Chunk == nullptr) || (!Chunk->IsValid()))
|
||||||
|
{
|
||||||
|
class cPrepareLoadCallback: public cChunkCoordCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cPrepareLoadCallback(cWorld & a_World, cChunkMap & a_ChunkMap, cChunkCoordCallback * a_Callback):
|
||||||
|
m_World(a_World),
|
||||||
|
m_ChunkMap(a_ChunkMap),
|
||||||
|
m_Callback(a_Callback)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// cChunkCoordCallback override:
|
||||||
|
virtual void Call(int a_CBChunkX, int a_CBChunkZ) override
|
||||||
|
{
|
||||||
|
// The chunk has been loaded or an error occurred, check if it's valid now:
|
||||||
|
cChunkPtr CBChunk = m_ChunkMap.GetChunkNoLoad(a_CBChunkX, a_CBChunkZ);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the chunk is not valid, queue it in the generator:
|
||||||
|
if (!CBChunk->IsValid())
|
||||||
|
{
|
||||||
|
m_World.GetGenerator().QueueGenerateChunk(a_CBChunkX, a_CBChunkZ, false, m_Callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The chunk was loaded, call the callback:
|
||||||
|
if (m_Callback != nullptr)
|
||||||
|
{
|
||||||
|
m_Callback->Call(a_CBChunkX, a_CBChunkZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
cWorld & m_World;
|
||||||
|
cChunkMap & m_ChunkMap;
|
||||||
|
cChunkCoordCallback * m_Callback;
|
||||||
|
};
|
||||||
|
m_World->GetStorage().QueueLoadChunk(a_ChunkX, a_ChunkZ, new cPrepareLoadCallback(*m_World, *this, a_Callback));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The chunk is valid, just call the callback:
|
||||||
|
if (a_Callback != nullptr)
|
||||||
|
{
|
||||||
|
a_Callback->Call(a_ChunkX, a_ChunkZ);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ)
|
void cChunkMap::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLayers);
|
cCSLock Lock(m_CSLayers);
|
||||||
|
@ -280,6 +280,20 @@ public:
|
|||||||
|
|
||||||
/** Touches the chunk, causing it to be loaded or generated */
|
/** Touches the chunk, causing it to be loaded or generated */
|
||||||
void TouchChunk(int a_ChunkX, int a_ChunkZ);
|
void TouchChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
|
/** Queues the chunk for preparing - making sure that it's generated and lit.
|
||||||
|
The specified chunk is queued to be loaded or generated, and lit if needed.
|
||||||
|
The specified callback is called after the chunk has been prepared. If there's no preparation to do, only the callback is called.
|
||||||
|
It is legal to call without the callback. */
|
||||||
|
void PrepareChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallAfter = nullptr); // Lua-accessible
|
||||||
|
|
||||||
|
/** Queues the chunk for generating.
|
||||||
|
First attempts to load the chunk from the storage. If that fails, queues the chunk for generating.
|
||||||
|
The specified callback is called after the chunk has been loaded / generated.
|
||||||
|
It is legal to call without the callback.
|
||||||
|
Returns true if successful, false if not (possibly an out-of-memory error).
|
||||||
|
If the return value is true, the callback was / will be called. */
|
||||||
|
bool GenerateChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallAfter = nullptr); // Lua-accessible
|
||||||
|
|
||||||
/** Marks the chunk as failed-to-load */
|
/** Marks the chunk as failed-to-load */
|
||||||
void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ);
|
void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ);
|
||||||
|
@ -110,29 +110,19 @@ void cChunkGenerator::Stop(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate)
|
void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate, cChunkCoordCallback * a_Callback)
|
||||||
{
|
{
|
||||||
ASSERT(m_ChunkSink->IsChunkQueued(a_ChunkX, a_ChunkZ));
|
ASSERT(m_ChunkSink->IsChunkQueued(a_ChunkX, a_ChunkZ));
|
||||||
|
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CS);
|
cCSLock Lock(m_CS);
|
||||||
|
|
||||||
// Check if it is already in the queue:
|
|
||||||
for (cChunkCoordsWithBoolList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr)
|
|
||||||
{
|
|
||||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ))
|
|
||||||
{
|
|
||||||
// Already in the queue, bail out
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} // for itr - m_Queue[]
|
|
||||||
|
|
||||||
// Add to queue, issue a warning if too many:
|
// Add to queue, issue a warning if too many:
|
||||||
if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
|
if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
|
||||||
{
|
{
|
||||||
LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size());
|
LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size());
|
||||||
}
|
}
|
||||||
m_Queue.push_back(cChunkCoordsWithBool(a_ChunkX, a_ChunkZ, a_ForceGenerate));
|
m_Queue.push_back(cQueueItem{a_ChunkX, a_ChunkZ, a_ForceGenerate, a_Callback});
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Event.Set();
|
m_Event.Set();
|
||||||
@ -242,9 +232,9 @@ void cChunkGenerator::Execute(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
cChunkCoordsWithBool coords = m_Queue.front(); // Get next coord from queue
|
cQueueItem item = m_Queue.front(); // Get next chunk from the queue
|
||||||
bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
|
bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
|
||||||
m_Queue.erase(m_Queue.begin()); // Remove coordinate from queue
|
m_Queue.erase(m_Queue.begin()); // Remove the item from the queue
|
||||||
Lock.Unlock(); // Unlock ASAP
|
Lock.Unlock(); // Unlock ASAP
|
||||||
m_evtRemoved.Set();
|
m_evtRemoved.Set();
|
||||||
|
|
||||||
@ -258,22 +248,35 @@ void cChunkGenerator::Execute(void)
|
|||||||
LastReportTick = clock();
|
LastReportTick = clock();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!coords.m_ForceGenerate && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ))
|
// Skip the chunk if it's already generated and regeneration is not forced:
|
||||||
|
if (!item.m_ForceGenerate && m_ChunkSink->IsChunkValid(item.m_ChunkX, item.m_ChunkZ))
|
||||||
{
|
{
|
||||||
LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ);
|
LOGD("Chunk [%d, %d] already generated, skipping generation", item.m_ChunkX, item.m_ChunkZ);
|
||||||
// Already generated, ignore request
|
if (item.m_Callback != nullptr)
|
||||||
|
{
|
||||||
|
item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SkipEnabled && !m_ChunkSink->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ))
|
// 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]", coords.m_ChunkX, coords.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);
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGD("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ);
|
// Generate the chunk:
|
||||||
DoGenerate(coords.m_ChunkX, coords.m_ChunkZ);
|
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);
|
||||||
|
}
|
||||||
NumChunksGenerated++;
|
NumChunksGenerated++;
|
||||||
} // while (!bStop)
|
} // while (!bStop)
|
||||||
}
|
}
|
||||||
|
@ -119,8 +119,12 @@ public:
|
|||||||
bool Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile);
|
bool Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile);
|
||||||
void Stop(void);
|
void Stop(void);
|
||||||
|
|
||||||
/// Queues the chunk for generation; removes duplicate requests
|
/** Queues the chunk for generation
|
||||||
void QueueGenerateChunk(int a_ChunkX, int a_ChunkZ, bool a_ForceGenerate);
|
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.
|
/// 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 GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap);
|
||||||
@ -131,22 +135,46 @@ public:
|
|||||||
|
|
||||||
int GetSeed(void) const { return m_Seed; }
|
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
|
/** 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);
|
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.
|
/** 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);
|
static BLOCKTYPE GetIniBlock(cIniFile & a_IniFile, const AString & a_SectionName, const AString & a_ValueName, const AString & a_Default);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
struct cQueueItem
|
||||||
|
{
|
||||||
|
/** The chunk coords */
|
||||||
|
int m_ChunkX, m_ChunkZ;
|
||||||
|
|
||||||
|
/** Force the regeneration of an already existing chunk */
|
||||||
|
bool m_ForceGenerate;
|
||||||
|
|
||||||
|
/** Callback to call after generating.*/
|
||||||
|
cChunkCoordCallback * m_Callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::list<cQueueItem> cGenQueue;
|
||||||
|
|
||||||
|
|
||||||
|
/** Seed used for the generator. */
|
||||||
int m_Seed;
|
int m_Seed;
|
||||||
|
|
||||||
cCriticalSection m_CS;
|
/** CS protecting access to the queue. */
|
||||||
cChunkCoordsWithBoolList m_Queue;
|
cCriticalSection m_CS;
|
||||||
cEvent m_Event; ///< Set when an item is added to the queue or the thread should terminate
|
|
||||||
cEvent m_evtRemoved; ///< Set when an item is removed from the queue
|
/** 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;
|
||||||
|
|
||||||
cGenerator * m_Generator; ///< The actual generator engine used to generate chunks
|
/** The actual generator engine used to generate chunks. */
|
||||||
|
cGenerator * m_Generator;
|
||||||
|
|
||||||
/** The plugin interface that may modify the generated chunks */
|
/** The plugin interface that may modify the generated chunks */
|
||||||
cPluginInterface * m_PluginInterface;
|
cPluginInterface * m_PluginInterface;
|
||||||
@ -158,6 +186,7 @@ private:
|
|||||||
// cIsThread override:
|
// cIsThread override:
|
||||||
virtual void Execute(void) override;
|
virtual void Execute(void) override;
|
||||||
|
|
||||||
|
/** Generates the specified chunk and sets it into the chunksink. */
|
||||||
void DoGenerate(int a_ChunkX, int a_ChunkZ);
|
void DoGenerate(int a_ChunkX, int a_ChunkZ);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -236,6 +236,16 @@ void cLightingThread::Execute(void)
|
|||||||
|
|
||||||
void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
|
void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
|
||||||
{
|
{
|
||||||
|
// If the chunk is already lit, skip it:
|
||||||
|
if (m_World->IsChunkLighted(a_Item.m_ChunkX, a_Item.m_ChunkZ))
|
||||||
|
{
|
||||||
|
if (a_Item.m_CallbackAfter != nullptr)
|
||||||
|
{
|
||||||
|
a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cChunkDef::BlockNibbles BlockLight, SkyLight;
|
cChunkDef::BlockNibbles BlockLight, SkyLight;
|
||||||
|
|
||||||
ReadChunks(a_Item.m_ChunkX, a_Item.m_ChunkZ);
|
ReadChunks(a_Item.m_ChunkX, a_Item.m_ChunkZ);
|
||||||
|
@ -163,6 +163,29 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Removes all items for which the predicate returns true. */
|
||||||
|
template <class Predicate>
|
||||||
|
void RemoveIf(Predicate a_Predicate)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
for (auto itr = m_Contents.begin(); itr != m_Contents.end();)
|
||||||
|
{
|
||||||
|
if (a_Predicate(*itr))
|
||||||
|
{
|
||||||
|
auto itr2 = itr;
|
||||||
|
++itr2;
|
||||||
|
m_Contents.erase(itr);
|
||||||
|
m_evtRemoved.Set();
|
||||||
|
itr = itr2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
} // for itr - m_Contents[]
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The contents of the queue
|
/// The contents of the queue
|
||||||
QueueType m_Contents;
|
QueueType m_Contents;
|
||||||
|
@ -115,7 +115,7 @@ public:
|
|||||||
{
|
{
|
||||||
int chunkX, chunkZ;
|
int chunkX, chunkZ;
|
||||||
DecodeChunkCoords(i, chunkX, chunkZ);
|
DecodeChunkCoords(i, chunkX, chunkZ);
|
||||||
m_World.GetLightingThread().QueueChunk(chunkX, chunkZ, this);
|
m_World.PrepareChunk(chunkX, chunkZ, this);
|
||||||
} // for i
|
} // for i
|
||||||
|
|
||||||
// Wait for the lighting thread to prepare everything. Event is set in the Call() callback:
|
// Wait for the lighting thread to prepare everything. Event is set in the Call() callback:
|
||||||
@ -2907,6 +2907,15 @@ void cWorld::TouchChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::PrepareChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallAfter)
|
||||||
|
{
|
||||||
|
m_ChunkMap->PrepareChunk(a_ChunkX, a_ChunkZ, a_CallAfter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ)
|
void cWorld::ChunkLoadFailed(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
m_ChunkMap->ChunkLoadFailed(a_ChunkX, a_ChunkZ);
|
m_ChunkMap->ChunkLoadFailed(a_ChunkX, a_ChunkZ);
|
||||||
@ -3017,7 +3026,7 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ)
|
void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
m_ChunkMap->TouchChunk(a_ChunkX, a_ChunkZ);
|
m_ChunkMap->GenerateChunk(a_ChunkX, a_ChunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -375,6 +375,12 @@ public:
|
|||||||
|
|
||||||
/** Touches the chunk, causing it to be loaded or generated */
|
/** Touches the chunk, causing it to be loaded or generated */
|
||||||
void TouchChunk(int a_ChunkX, int a_ChunkZ);
|
void TouchChunk(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
|
/** Queues the chunk for preparing - making sure that it's generated and lit.
|
||||||
|
The specified chunk is queued to be loaded or generated, and lit if needed.
|
||||||
|
The specified callback is called after the chunk has been prepared. If there's no preparation to do, only the callback is called.
|
||||||
|
It is legal to call with no callback. */
|
||||||
|
void PrepareChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallAfter = nullptr);
|
||||||
|
|
||||||
/** Marks the chunk as failed-to-load: */
|
/** Marks the chunk as failed-to-load: */
|
||||||
void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ);
|
void ChunkLoadFailed(int a_ChunkX, int a_ChunkZ);
|
||||||
|
@ -140,11 +140,11 @@ size_t cWorldStorage::GetSaveQueueLength(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkZ)
|
void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback)
|
||||||
{
|
{
|
||||||
ASSERT(m_World->IsChunkQueued(a_ChunkX, a_ChunkZ));
|
ASSERT(m_World->IsChunkQueued(a_ChunkX, a_ChunkZ));
|
||||||
|
|
||||||
m_LoadQueue.EnqueueItem(cChunkCoords(a_ChunkX, a_ChunkZ));
|
m_LoadQueue.EnqueueItem(cChunkCoordsWithCallback(a_ChunkX, a_ChunkZ, a_Callback));
|
||||||
m_Event.Set();
|
m_Event.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,11 +152,11 @@ void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkZ)
|
void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback)
|
||||||
{
|
{
|
||||||
ASSERT(m_World->IsChunkValid(a_ChunkX, a_ChunkZ));
|
ASSERT(m_World->IsChunkValid(a_ChunkX, a_ChunkZ));
|
||||||
|
|
||||||
m_SaveQueue.EnqueueItemIfNotPresent(cChunkCoords(a_ChunkX, a_ChunkZ));
|
m_SaveQueue.EnqueueItem(cChunkCoordsWithCallback(a_ChunkX, a_ChunkZ, a_Callback));
|
||||||
m_Event.Set();
|
m_Event.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +166,11 @@ void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkZ)
|
void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
m_LoadQueue.Remove(cChunkCoords(a_ChunkX, a_ChunkZ));
|
m_LoadQueue.RemoveIf([=](cChunkCoordsWithCallback & a_Item)
|
||||||
|
{
|
||||||
|
return (a_Item.m_ChunkX == a_ChunkX) && (a_Item.m_ChunkZ == a_ChunkZ);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -175,7 +179,11 @@ void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkZ)
|
|||||||
|
|
||||||
void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk)
|
void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk)
|
||||||
{
|
{
|
||||||
m_SaveQueue.Remove(a_Chunk);
|
m_SaveQueue.RemoveIf([=](cChunkCoordsWithCallback & a_Item)
|
||||||
|
{
|
||||||
|
return (a_Item.m_ChunkX == a_Chunk.m_ChunkX) && (a_Item.m_ChunkZ == a_Chunk.m_ChunkZ);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -244,14 +252,23 @@ void cWorldStorage::Execute(void)
|
|||||||
|
|
||||||
bool cWorldStorage::LoadOneChunk(void)
|
bool cWorldStorage::LoadOneChunk(void)
|
||||||
{
|
{
|
||||||
cChunkCoords ToLoad(0, 0);
|
// Dequeue an item, bail out if there's none left:
|
||||||
|
cChunkCoordsWithCallback ToLoad(0, 0, nullptr);
|
||||||
bool ShouldLoad = m_LoadQueue.TryDequeueItem(ToLoad);
|
bool ShouldLoad = m_LoadQueue.TryDequeueItem(ToLoad);
|
||||||
|
if (!ShouldLoad)
|
||||||
if (ShouldLoad)
|
|
||||||
{
|
{
|
||||||
return LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkZ);
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
// Load the chunk:
|
||||||
|
bool res = LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkZ);
|
||||||
|
|
||||||
|
// Call the callback, if specified:
|
||||||
|
if (ToLoad.m_Callback != nullptr)
|
||||||
|
{
|
||||||
|
ToLoad.m_Callback->Call(ToLoad.m_ChunkX, ToLoad.m_ChunkZ);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -260,17 +277,30 @@ bool cWorldStorage::LoadOneChunk(void)
|
|||||||
|
|
||||||
bool cWorldStorage::SaveOneChunk(void)
|
bool cWorldStorage::SaveOneChunk(void)
|
||||||
{
|
{
|
||||||
cChunkCoords ToSave(0, 0);
|
// Dequeue one chunk to save:
|
||||||
|
cChunkCoordsWithCallback ToSave(0, 0, nullptr);
|
||||||
bool ShouldSave = m_SaveQueue.TryDequeueItem(ToSave);
|
bool ShouldSave = m_SaveQueue.TryDequeueItem(ToSave);
|
||||||
if (ShouldSave && m_World->IsChunkValid(ToSave.m_ChunkX, ToSave.m_ChunkZ))
|
if (!ShouldSave)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the chunk, if it's valid:
|
||||||
|
if (m_World->IsChunkValid(ToSave.m_ChunkX, ToSave.m_ChunkZ))
|
||||||
{
|
{
|
||||||
m_World->MarkChunkSaving(ToSave.m_ChunkX, ToSave.m_ChunkZ);
|
m_World->MarkChunkSaving(ToSave.m_ChunkX, ToSave.m_ChunkZ);
|
||||||
if (m_SaveSchema->SaveChunk(ToSave))
|
if (m_SaveSchema->SaveChunk(cChunkCoords(ToSave.m_ChunkX, ToSave.m_ChunkZ)))
|
||||||
{
|
{
|
||||||
m_World->MarkChunkSaved(ToSave.m_ChunkX, ToSave.m_ChunkZ);
|
m_World->MarkChunkSaved(ToSave.m_ChunkX, ToSave.m_ChunkZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ShouldSave;
|
|
||||||
|
// Call the callback, if specified:
|
||||||
|
if (ToSave.m_Callback != nullptr)
|
||||||
|
{
|
||||||
|
ToSave.m_Callback->Call(ToSave.m_ChunkX, ToSave.m_ChunkZ);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
// fwd:
|
// fwd:
|
||||||
class cWorld;
|
class cWorld;
|
||||||
|
|
||||||
typedef cQueue<cChunkCoords> cChunkCoordsQueue;
|
typedef cQueue<cChunkCoordsWithCallback> cChunkCoordsQueue;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -64,8 +64,8 @@ public:
|
|||||||
cWorldStorage(void);
|
cWorldStorage(void);
|
||||||
~cWorldStorage();
|
~cWorldStorage();
|
||||||
|
|
||||||
void QueueLoadChunk(int a_ChunkX, int a_ChunkZ);
|
void QueueLoadChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = nullptr);
|
||||||
void QueueSaveChunk(int a_ChunkX, int a_ChunkZ);
|
void QueueSaveChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = nullptr);
|
||||||
|
|
||||||
void UnqueueLoad(int a_ChunkX, int a_ChunkZ);
|
void UnqueueLoad(int a_ChunkX, int a_ChunkZ);
|
||||||
void UnqueueSave(const cChunkCoords & a_Chunk);
|
void UnqueueSave(const cChunkCoords & a_Chunk);
|
||||||
|
Loading…
Reference in New Issue
Block a user