From 829cc866cd63c50ebff4dac2f942a0df93d269fc Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 11 Aug 2013 21:05:44 +0200 Subject: [PATCH] Added cWorld:QueueSaveAllChunks() function for saving chunks asynchronously. The cWorld:SaveAllChunks() is therefore deprecated in the API and will be removed soon, use QueueSaveAllChunks() instead. --- source/Bindings.cpp | 34 ++++++++++++++++++++++++++- source/Bindings.h | 2 +- source/World.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++- source/World.h | 38 ++++++++++++++++++++++++++++-- 4 files changed, 125 insertions(+), 5 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index ca6b42902..46c5f0f07 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/11/13 19:12:37. +** Generated automatically by tolua++-1.0.92 on 08/11/13 20:59:51. */ #ifndef __cplusplus @@ -13434,6 +13434,37 @@ static int tolua_AllToLua_cWorld_SaveAllChunks00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: QueueSaveAllChunks of class cWorld */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_QueueSaveAllChunks00 +static int tolua_AllToLua_cWorld_QueueSaveAllChunks00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'QueueSaveAllChunks'", NULL); +#endif + { + self->QueueSaveAllChunks(); + } + } + return 0; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'QueueSaveAllChunks'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetNumChunks of class cWorld */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GetNumChunks00 static int tolua_AllToLua_cWorld_GetNumChunks00(lua_State* tolua_S) @@ -29878,6 +29909,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetBiomeAt",tolua_AllToLua_cWorld_GetBiomeAt00); tolua_function(tolua_S,"GetName",tolua_AllToLua_cWorld_GetName00); tolua_function(tolua_S,"SaveAllChunks",tolua_AllToLua_cWorld_SaveAllChunks00); + tolua_function(tolua_S,"QueueSaveAllChunks",tolua_AllToLua_cWorld_QueueSaveAllChunks00); tolua_function(tolua_S,"GetNumChunks",tolua_AllToLua_cWorld_GetNumChunks00); tolua_function(tolua_S,"GetGeneratorQueueLength",tolua_AllToLua_cWorld_GetGeneratorQueueLength00); tolua_function(tolua_S,"GetLightingQueueLength",tolua_AllToLua_cWorld_GetLightingQueueLength00); diff --git a/source/Bindings.h b/source/Bindings.h index d80c98782..10f874e41 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/11/13 19:12:37. +** Generated automatically by tolua++-1.0.92 on 08/11/13 20:59:52. */ /* Exported function */ diff --git a/source/World.cpp b/source/World.cpp index af66d1ead..9212202e9 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "BlockID.h" @@ -242,7 +243,7 @@ cWorld::cWorld(const AString & a_WorldName) : m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) m_TickThread(*this) { - LOGD("cWorld::cWorld(%s)", a_WorldName.c_str()); + LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); cMakeDir::MakeDir(m_WorldName.c_str()); } @@ -587,6 +588,7 @@ void cWorld::Tick(float a_Dt) m_ChunkMap->Tick(a_Dt); TickQueuedBlocks(a_Dt); + TickQueuedTasks(); GetSimulatorManager()->Simulate(a_Dt); @@ -781,6 +783,27 @@ void cWorld::TickSpawnMobs(float a_Dt) +void cWorld::TickQueuedTasks(void) +{ + // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks + cTasks Tasks; + { + cCSLock Lock(m_CSTasks); + std::swap(Tasks, m_Tasks); + } + + // Execute and delete each task: + for (cTasks::iterator itr = m_Tasks.begin(), end = m_Tasks.end(); itr != end; ++itr) + { + (*itr)->Run(*this); + delete *itr; + } // for itr - m_Tasks[] +} + + + + + void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) { return m_ChunkMap->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); @@ -2307,6 +2330,25 @@ void cWorld::SaveAllChunks(void) +void cWorld::QueueSaveAllChunks(void) +{ + QueueTask(new cWorld::cTaskSaveAllChunks); +} + + + + + +void cWorld::QueueTask(cTask * a_Task) +{ + cCSLock Lock(m_CSTasks); + m_Tasks.push_back(a_Task); +} + + + + + void cWorld::AddEntity(cEntity * a_Entity) { m_ChunkMap->AddEntity(a_Entity); @@ -2552,3 +2594,15 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cWorld::cTaskSaveAllChunks: + +void cWorld::cTaskSaveAllChunks::Run(cWorld & a_World) +{ + a_World.SaveAllChunks(); +} + + + + diff --git a/source/World.h b/source/World.h index a12a9e40e..d84920470 100644 --- a/source/World.h +++ b/source/World.h @@ -69,6 +69,24 @@ public: public: cLock(cWorld & a_World); } ; + + /// A common ancestor for all tasks queued onto the tick thread + class cTask + { + public: + virtual void Run(cWorld & a_World) = 0; + } ; + + typedef std::vector cTasks; + + class cTaskSaveAllChunks : + public cTask + { + protected: + // cTask overrides: + virtual void Run(cWorld & a_World) override; + } ; + // tolua_begin @@ -461,10 +479,17 @@ public: if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--; } - void SaveAllChunks(void); // tolua_export + /// Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead + void SaveAllChunks(void); // tolua_export + + /// Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources + void QueueSaveAllChunks(void); // tolua_export + + /// Queues a task onto the tick thread. The task object will be deleted once the task is finished + void QueueTask(cTask * a_Task); /// Returns the number of chunks loaded - int GetNumChunks() const; // tolua_export + int GetNumChunks() const; // tolua_export /// Returns the number of chunks loaded and dirty, and in the lighting queue void GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue); @@ -629,6 +654,12 @@ private: cChunkSender m_ChunkSender; cLightingThread m_Lighting; cTickThread m_TickThread; + + /// Guards the m_Tasks + cCriticalSection m_CSTasks; + + /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks + cTasks m_Tasks; cWorld(const AString & a_WorldName); @@ -639,6 +670,9 @@ private: void TickWeather(float a_Dt); // Handles weather each tick void TickSpawnMobs(float a_Dt); // Handles mob spawning each tick + /// Executes all tasks queued onto the tick thread + void TickQueuedTasks(void); + /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock); }; // tolua_export