Merge pull request #2522 from cuberite/FixLoaderGenRaceCondition
Fixed a race condition between chunk loader and generator.
This commit is contained in:
commit
0786fda18b
@ -348,11 +348,11 @@ static int tolua_cWorld_PrepareChunk(lua_State * tolua_S)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cChunkCoordCallback override:
|
// cChunkCoordCallback override:
|
||||||
virtual void Call(int a_CBChunkX, int a_CBChunkZ) override
|
virtual void Call(int a_CBChunkX, int a_CBChunkZ, bool a_IsSuccess) override
|
||||||
{
|
{
|
||||||
if (m_Callback.IsValid())
|
if (m_Callback.IsValid())
|
||||||
{
|
{
|
||||||
m_LuaState.Call(m_Callback, a_CBChunkX, a_CBChunkZ);
|
m_LuaState.Call(m_Callback, a_CBChunkX, a_CBChunkZ, a_IsSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the last reference of this object, we must delete it so that it doesn't leak:
|
// This is the last reference of this object, we must delete it so that it doesn't leak:
|
||||||
|
@ -464,7 +464,8 @@ public:
|
|||||||
|
|
||||||
virtual ~cChunkCoordCallback() {}
|
virtual ~cChunkCoordCallback() {}
|
||||||
|
|
||||||
virtual void Call(int a_ChunkX, int a_ChunkZ) = 0;
|
/** 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;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -2396,10 +2396,10 @@ void cChunkMap::PrepareChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkC
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The chunk is present and lit, just call the callback:
|
// The chunk is present and lit, just call the callback, report as success:
|
||||||
if (a_Callback != nullptr)
|
if (a_Callback != nullptr)
|
||||||
{
|
{
|
||||||
a_Callback->Call(a_ChunkX, a_ChunkZ);
|
a_Callback->Call(a_ChunkX, a_ChunkZ, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2432,9 +2432,19 @@ bool cChunkMap::GenerateChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cChunkCoordCallback override:
|
// cChunkCoordCallback override:
|
||||||
virtual void Call(int a_CBChunkX, int a_CBChunkZ) override
|
virtual void Call(int a_CBChunkX, int a_CBChunkZ, bool a_CBIsSuccess) override
|
||||||
{
|
{
|
||||||
// The chunk has been loaded or an error occurred, check if it's valid now:
|
// 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);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The chunk failed to load, generate it:
|
||||||
cCSLock Lock(m_ChunkMap.m_CSLayers);
|
cCSLock Lock(m_ChunkMap.m_CSLayers);
|
||||||
cChunkPtr CBChunk = m_ChunkMap.GetChunkNoLoad(a_CBChunkX, a_CBChunkZ);
|
cChunkPtr CBChunk = m_ChunkMap.GetChunkNoLoad(a_CBChunkX, a_CBChunkZ);
|
||||||
|
|
||||||
@ -2443,23 +2453,13 @@ bool cChunkMap::GenerateChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback *
|
|||||||
// An error occurred, but we promised to call the callback, so call it even when there's no real chunk data:
|
// 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)
|
if (m_Callback != nullptr)
|
||||||
{
|
{
|
||||||
m_Callback->Call(a_CBChunkX, a_CBChunkZ);
|
m_Callback->Call(a_CBChunkX, a_CBChunkZ, false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the chunk is not valid, queue it in the generator:
|
CBChunk->SetPresence(cChunk::cpQueued);
|
||||||
if (!CBChunk->IsValid())
|
|
||||||
{
|
|
||||||
m_World.GetGenerator().QueueGenerateChunk(a_CBChunkX, a_CBChunkZ, false, m_Callback);
|
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:
|
protected:
|
||||||
@ -2474,7 +2474,7 @@ bool cChunkMap::GenerateChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback *
|
|||||||
// The chunk is valid, just call the callback:
|
// The chunk is valid, just call the callback:
|
||||||
if (a_Callback != nullptr)
|
if (a_Callback != nullptr)
|
||||||
{
|
{
|
||||||
a_Callback->Call(a_ChunkX, a_ChunkZ);
|
a_Callback->Call(a_ChunkX, a_ChunkZ, true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
class cNotifyChunkSender :
|
class cNotifyChunkSender :
|
||||||
public cChunkCoordCallback
|
public cChunkCoordCallback
|
||||||
{
|
{
|
||||||
virtual void Call(int a_ChunkX, int a_ChunkZ) override
|
virtual void Call(int a_ChunkX, int a_ChunkZ, bool a_IsSuccess) override
|
||||||
{
|
{
|
||||||
cChunkSender & ChunkSender = m_ChunkSender;
|
cChunkSender & ChunkSender = m_ChunkSender;
|
||||||
m_World.DoWithChunk(
|
m_World.DoWithChunk(
|
||||||
|
@ -248,13 +248,13 @@ void cChunkGenerator::Execute(void)
|
|||||||
LastReportTick = clock();
|
LastReportTick = clock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip the chunk if it's already generated and regeneration is not forced:
|
// 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))
|
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);
|
LOGD("Chunk [%d, %d] already generated, skipping generation", item.m_ChunkX, item.m_ChunkZ);
|
||||||
if (item.m_Callback != nullptr)
|
if (item.m_Callback != nullptr)
|
||||||
{
|
{
|
||||||
item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ);
|
item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ, true);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -265,7 +265,7 @@ void cChunkGenerator::Execute(void)
|
|||||||
LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", 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)
|
if (item.m_Callback != nullptr)
|
||||||
{
|
{
|
||||||
item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ);
|
item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ, false);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -275,7 +275,7 @@ void cChunkGenerator::Execute(void)
|
|||||||
DoGenerate(item.m_ChunkX, item.m_ChunkZ);
|
DoGenerate(item.m_ChunkX, item.m_ChunkZ);
|
||||||
if (item.m_Callback != nullptr)
|
if (item.m_Callback != nullptr)
|
||||||
{
|
{
|
||||||
item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ);
|
item.m_Callback->Call(item.m_ChunkX, item.m_ChunkZ, true);
|
||||||
}
|
}
|
||||||
NumChunksGenerated++;
|
NumChunksGenerated++;
|
||||||
} // while (!bStop)
|
} // while (!bStop)
|
||||||
|
@ -238,12 +238,12 @@ 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 the chunk is already lit, skip it (report as success):
|
||||||
if (m_World->IsChunkLighted(a_Item.m_ChunkX, a_Item.m_ChunkZ))
|
if (m_World->IsChunkLighted(a_Item.m_ChunkX, a_Item.m_ChunkZ))
|
||||||
{
|
{
|
||||||
if (a_Item.m_CallbackAfter != nullptr)
|
if (a_Item.m_CallbackAfter != nullptr)
|
||||||
{
|
{
|
||||||
a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ);
|
a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ, true);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -324,7 +324,7 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item)
|
|||||||
|
|
||||||
if (a_Item.m_CallbackAfter != nullptr)
|
if (a_Item.m_CallbackAfter != nullptr)
|
||||||
{
|
{
|
||||||
a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ);
|
a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,8 @@ public:
|
|||||||
|
|
||||||
void Stop(void);
|
void Stop(void);
|
||||||
|
|
||||||
/** Queues the entire chunk for lighting */
|
/** Queues the entire chunk for lighting.
|
||||||
|
The callback, if specified, is called after the lighting has been processed. */
|
||||||
void QueueChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_CallbackAfter);
|
void QueueChunk(int a_ChunkX, int a_ChunkZ, std::unique_ptr<cChunkCoordCallback> a_CallbackAfter);
|
||||||
|
|
||||||
/** Blocks until the queue is empty or the thread is terminated */
|
/** Blocks until the queue is empty or the thread is terminated */
|
||||||
|
@ -20,7 +20,7 @@ protected:
|
|||||||
|
|
||||||
cSpawnPrepare & m_SpawnPrepare;
|
cSpawnPrepare & m_SpawnPrepare;
|
||||||
|
|
||||||
virtual void Call(int a_ChunkX, int a_ChunkZ) override
|
virtual void Call(int a_ChunkX, int a_ChunkZ, bool a_IsSuccess) override
|
||||||
{
|
{
|
||||||
m_SpawnPrepare.PreparedChunkCallback(a_ChunkX, a_ChunkZ);
|
m_SpawnPrepare.PreparedChunkCallback(a_ChunkX, a_ChunkZ);
|
||||||
}
|
}
|
||||||
|
@ -164,32 +164,6 @@ void cWorldStorage::QueueSaveChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallba
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::UnqueueLoad(int a_ChunkX, int a_ChunkZ)
|
|
||||||
{
|
|
||||||
m_LoadQueue.RemoveIf([=](cChunkCoordsWithCallback & a_Item)
|
|
||||||
{
|
|
||||||
return (a_Item.m_ChunkX == a_ChunkX) && (a_Item.m_ChunkZ == a_ChunkZ);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::UnqueueSave(const cChunkCoords & 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);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldStorage::InitSchemas(int a_StorageCompressionFactor)
|
void cWorldStorage::InitSchemas(int a_StorageCompressionFactor)
|
||||||
{
|
{
|
||||||
// The first schema added is considered the default
|
// The first schema added is considered the default
|
||||||
@ -266,7 +240,7 @@ bool cWorldStorage::LoadOneChunk(void)
|
|||||||
// Call the callback, if specified:
|
// Call the callback, if specified:
|
||||||
if (ToLoad.m_Callback != nullptr)
|
if (ToLoad.m_Callback != nullptr)
|
||||||
{
|
{
|
||||||
ToLoad.m_Callback->Call(ToLoad.m_ChunkX, ToLoad.m_ChunkZ);
|
ToLoad.m_Callback->Call(ToLoad.m_ChunkX, ToLoad.m_ChunkZ, res);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -286,19 +260,21 @@ bool cWorldStorage::SaveOneChunk(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Save the chunk, if it's valid:
|
// Save the chunk, if it's valid:
|
||||||
|
bool Status = false;
|
||||||
if (m_World->IsChunkValid(ToSave.m_ChunkX, ToSave.m_ChunkZ))
|
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(cChunkCoords(ToSave.m_ChunkX, ToSave.m_ChunkZ)))
|
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);
|
||||||
|
Status = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the callback, if specified:
|
// Call the callback, if specified:
|
||||||
if (ToSave.m_Callback != nullptr)
|
if (ToSave.m_Callback != nullptr)
|
||||||
{
|
{
|
||||||
ToSave.m_Callback->Call(ToSave.m_ChunkX, ToSave.m_ChunkZ);
|
ToSave.m_Callback->Call(ToSave.m_ChunkX, ToSave.m_ChunkZ, Status);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -64,11 +64,13 @@ public:
|
|||||||
cWorldStorage(void);
|
cWorldStorage(void);
|
||||||
~cWorldStorage();
|
~cWorldStorage();
|
||||||
|
|
||||||
|
/** Queues a chunk to be loaded, asynchronously.
|
||||||
|
The callback, if specified, will be called with the result of the load operation. */
|
||||||
void QueueLoadChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = nullptr);
|
void QueueLoadChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = nullptr);
|
||||||
void QueueSaveChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = nullptr);
|
|
||||||
|
|
||||||
void UnqueueLoad(int a_ChunkX, int a_ChunkZ);
|
/** Queues a chunk to be saved, asynchronously.
|
||||||
void UnqueueSave(const cChunkCoords & a_Chunk);
|
The callback, if specified, will be called with the result of the save operation. */
|
||||||
|
void QueueSaveChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = nullptr);
|
||||||
|
|
||||||
bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args
|
bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args
|
||||||
void Stop(void); // Hide the cIsThread's Stop() method, we need to signal the event
|
void Stop(void); // Hide the cIsThread's Stop() method, we need to signal the event
|
||||||
|
Loading…
Reference in New Issue
Block a user