From a8bfe3a4c1993b9bbc2defc5f0b667a2348c210e Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 25 Sep 2015 18:56:49 +0100 Subject: Prepared ScheduleTask for threading refactor * Llama-ified and condensed Schedule/QueueTask - Removed hackery done with piston animations --- src/Bindings/ManualBindings_World.cpp | 55 +++-------- src/Blocks/BlockPiston.cpp | 25 +---- src/World.cpp | 166 +++++++--------------------------- src/World.h | 107 +--------------------- 4 files changed, 55 insertions(+), 298 deletions(-) diff --git a/src/Bindings/ManualBindings_World.cpp b/src/Bindings/ManualBindings_World.cpp index 6f8499611..ba80d7130 100644 --- a/src/Bindings/ManualBindings_World.cpp +++ b/src/Bindings/ManualBindings_World.cpp @@ -374,7 +374,6 @@ static int tolua_cWorld_PrepareChunk(lua_State * tolua_S) class cLuaWorldTask : - public cWorld::cTask, public cPluginLua::cResettable { public: @@ -384,11 +383,7 @@ public: { } -protected: - int m_FnRef; - - // cWorld::cTask overrides: - virtual void Run(cWorld & a_World) override + void Run(cWorld & a_World) { cCSLock Lock(m_CSPlugin); if (m_Plugin != nullptr) @@ -396,7 +391,10 @@ protected: m_Plugin->Call(m_FnRef, &a_World); } } -} ; + +protected: + int m_FnRef; +}; @@ -433,9 +431,9 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S) return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); } - auto task = std::make_shared(*Plugin, FnRef); - Plugin->AddResettable(task); - self->QueueTask(task); + auto ResettableTask = std::make_shared(*Plugin, FnRef); + Plugin->AddResettable(ResettableTask); + self->QueueTask(std::bind(&cLuaWorldTask::Run, ResettableTask, std::placeholders::_1)); return 0; } @@ -483,35 +481,6 @@ static int tolua_cWorld_SetSignLines(lua_State * tolua_S) -class cLuaScheduledWorldTask : - public cWorld::cTask, - public cPluginLua::cResettable -{ -public: - cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef) : - cPluginLua::cResettable(a_Plugin), - m_FnRef(a_FnRef) - { - } - -protected: - int m_FnRef; - - // cWorld::cTask overrides: - virtual void Run(cWorld & a_World) override - { - cCSLock Lock(m_CSPlugin); - if (m_Plugin != nullptr) - { - m_Plugin->Call(m_FnRef, &a_World); - } - } -}; - - - - - static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) { // Binding for cWorld::ScheduleTask @@ -548,11 +517,9 @@ static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) return cManualBindings::lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); } - int DelayTicks = static_cast(tolua_tonumber(tolua_S, 2, 0)); - - auto task = std::make_shared(*Plugin, FnRef); - Plugin->AddResettable(task); - World->ScheduleTask(DelayTicks, static_cast(task)); + auto ResettableTask = std::make_shared(*Plugin, FnRef); + Plugin->AddResettable(ResettableTask); + World->ScheduleTask(static_cast(tolua_tonumber(tolua_S, 2, 0)), std::bind(&cLuaWorldTask::Run, ResettableTask, std::placeholders::_1)); return 0; } diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index 4e4814242..94782a7ed 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -27,7 +27,6 @@ } \ } -#define PISTON_TICK_DELAY 1 #define PISTON_MAX_PUSH_DISTANCE 12 @@ -156,15 +155,12 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, // Push blocks, from the furthest to the nearest: int oldx = a_BlockX, oldy = a_BlockY, oldz = a_BlockZ; NIBBLETYPE currBlockMeta; - std::vector ScheduledBlocks; - ScheduledBlocks.reserve(PISTON_MAX_PUSH_DISTANCE); for (int i = dist + 1; i > 1; i--) { AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); a_World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, currBlock, currBlockMeta); - a_World->SetBlock(oldx, oldy, oldz, currBlock, currBlockMeta, false); - ScheduledBlocks.push_back(Vector3i(oldx, oldy, oldz)); + a_World->SetBlock(oldx, oldy, oldz, currBlock, currBlockMeta); oldx = a_BlockX; oldy = a_BlockY; oldz = a_BlockZ; @@ -173,13 +169,11 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ, int extx = a_BlockX; int exty = a_BlockY; int extz = a_BlockZ; - ScheduledBlocks.push_back(Vector3i(extx, exty, extz)); AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1); // "a_Block" now at piston body, "ext" at future extension a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta | 0x8); - a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0), false); - a_World->ScheduleTask(PISTON_TICK_DELAY, static_cast(std::make_shared(ScheduledBlocks))); + a_World->SetBlock(extx, exty, extz, E_BLOCK_PISTON_EXTENSION, pistonMeta | (IsSticky(pistonBlock) ? 8 : 0)); } @@ -223,23 +217,14 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ if (CanPull(tempBlock, tempMeta)) { // Pull the block - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, tempBlock, tempMeta, false); - a_World->SetBlock(tempx, tempy, tempz, E_BLOCK_AIR, 0, false); - - std::vector ScheduledBlocks; - ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); - ScheduledBlocks.push_back(Vector3i(tempx, tempy, tempz)); - a_World->ScheduleTask(PISTON_TICK_DELAY + 1, static_cast(std::make_shared(ScheduledBlocks))); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, tempBlock, tempMeta); + a_World->SetBlock(tempx, tempy, tempz, E_BLOCK_AIR, 0); return; } } // Retract without pulling - a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0, false); - - std::vector ScheduledBlocks; - ScheduledBlocks.push_back(Vector3i(a_BlockX, a_BlockY, a_BlockZ)); - a_World->ScheduleTask(PISTON_TICK_DELAY + 1, static_cast(std::make_shared(ScheduledBlocks))); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); } diff --git a/src/World.cpp b/src/World.cpp index 5920b83fe..18d042382 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -839,7 +839,6 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La TickClients(static_cast(a_Dt.count())); TickQueuedBlocks(); TickQueuedTasks(); - TickScheduledTasks(); GetSimulatorManager()->Simulate(static_cast(a_Dt.count())); @@ -961,56 +960,40 @@ void cWorld::TickMobs(std::chrono::milliseconds 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 = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) - { - (*itr)->Run(*this); - } // for itr - m_Tasks[] -} - - - - - -void cWorld::TickScheduledTasks(void) { // Move the tasks to be executed to a seperate vector to avoid deadlocks on accessing m_Tasks - cScheduledTasks Tasks; + decltype(m_Tasks) Tasks; { - cCSLock Lock(m_CSScheduledTasks); - auto WorldAge = m_WorldAge; - - // Move all the due tasks from m_ScheduledTasks into Tasks: - for (auto itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end();) // Cannot use range-based for, we're modifying the container + cCSLock Lock(m_CSTasks); + if (m_Tasks.empty()) { - if ((*itr)->m_TargetTick < std::chrono::duration_cast(WorldAge).count()) - { - auto next = itr; - ++next; - Tasks.push_back(std::move(*itr)); - m_ScheduledTasks.erase(itr); - itr = next; - } - else + return; + } + + // Partition everything to be executed by returning false to move to end of list if time reached + auto MoveBeginIterator = std::partition(m_Tasks.begin(), m_Tasks.end(), [this](const decltype(m_Tasks)::value_type & a_Task) { - // All the eligible tasks have been moved, bail out now - break; + if (a_Task.first < std::chrono::duration_cast(m_WorldAge).count()) + { + return false; + } + return true; } - } + ); + + // Cut all the due tasks from m_Tasks into Tasks: + Tasks.insert( + Tasks.end(), + std::make_move_iterator(MoveBeginIterator), + std::make_move_iterator(m_Tasks.end()) + ); + m_Tasks.erase(MoveBeginIterator, m_Tasks.end()); } - // Execute and delete each task: - for (cScheduledTasks::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) + // Execute each task: + for (const auto & Task : Tasks) { - (*itr)->m_Task->Run(*this); + Task.second(*this); } // for itr - m_Tasks[] } @@ -2662,7 +2645,7 @@ void cWorld::UnloadUnusedChunks(void) void cWorld::QueueUnloadUnusedChunks(void) { - QueueTask(cpp14::make_unique()); + QueueTask([](cWorld & a_World) { a_World.UnloadUnusedChunks(); }); } @@ -3161,42 +3144,32 @@ void cWorld::SaveAllChunks(void) void cWorld::QueueSaveAllChunks(void) { - QueueTask(std::make_shared()); + QueueTask([](cWorld & a_World) { a_World.SaveAllChunks(); }); } -void cWorld::QueueTask(cTaskPtr a_Task) +void cWorld::QueueTask(std::function a_Task) { cCSLock Lock(m_CSTasks); - m_Tasks.push_back(std::move(a_Task)); + m_Tasks.emplace_back(0, a_Task); } -void cWorld::ScheduleTask(int a_DelayTicks, std::function a_Func) -{ - cTaskLambda task(a_Func); - ScheduleTask(a_DelayTicks, static_cast(std::make_shared(task))); -} -void cWorld::ScheduleTask(int a_DelayTicks, cTaskPtr a_Task) + +void cWorld::ScheduleTask(int a_DelayTicks, std::function a_Task) { Int64 TargetTick = a_DelayTicks + std::chrono::duration_cast(m_WorldAge).count(); - - // Insert the task into the list of scheduled tasks, ordered by its target tick - cCSLock Lock(m_CSScheduledTasks); - for (cScheduledTasks::iterator itr = m_ScheduledTasks.begin(), end = m_ScheduledTasks.end(); itr != end; ++itr) + + // Insert the task into the list of scheduled tasks { - if ((*itr)->m_TargetTick >= TargetTick) - { - m_ScheduledTasks.insert(itr, cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task))); - return; - } + cCSLock Lock(m_CSTasks); + m_Tasks.emplace_back(TargetTick, a_Task); } - m_ScheduledTasks.push_back(cScheduledTaskPtr(new cScheduledTask(TargetTick, a_Task))); } @@ -3624,75 +3597,6 @@ void cWorld::AddQueuedPlayers(void) -//////////////////////////////////////////////////////////////////////////////// -// cWorld::cTaskSaveAllChunks: - -void cWorld::cTaskSaveAllChunks::Run(cWorld & a_World) -{ - a_World.SaveAllChunks(); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cWorld::cTaskUnloadUnusedChunks - -void cWorld::cTaskUnloadUnusedChunks::Run(cWorld & a_World) -{ - a_World.UnloadUnusedChunks(); -} - - - - - -//////////////////////////////////////////////////////////////////////////////// -// cWorld::cTaskSendBlockToAllPlayers - -cWorld::cTaskSendBlockToAllPlayers::cTaskSendBlockToAllPlayers(std::vector & a_SendQueue) : - m_SendQueue(a_SendQueue) -{ -} - -void cWorld::cTaskSendBlockToAllPlayers::Run(cWorld & a_World) -{ - class cPlayerCallback : - public cPlayerListCallback - { - public: - cPlayerCallback(std::vector & a_SendQueue, cWorld & a_CallbackWorld) : - m_SendQueue(a_SendQueue), - m_World(a_CallbackWorld) - { - } - - virtual bool Item(cPlayer * a_Player) - { - for (std::vector::const_iterator itr = m_SendQueue.begin(); itr != m_SendQueue.end(); ++itr) - { - m_World.SendBlockTo(itr->x, itr->y, itr->z, a_Player); - } - return false; - } - - private: - - std::vector m_SendQueue; - cWorld & m_World; - - } PlayerCallback(m_SendQueue, a_World); - - a_World.ForEachPlayer(PlayerCallback); -} - -void cWorld::cTaskLambda::Run(cWorld & a_World) -{ - m_func(a_World); -} - - //////////////////////////////////////////////////////////////////////////////// // cWorld::cChunkGeneratorCallbacks: diff --git a/src/World.h b/src/World.h index 1902296be..44f18df4a 100644 --- a/src/World.h +++ b/src/World.h @@ -96,72 +96,8 @@ public: typedef cCSLock super; public: cLock(cWorld & a_World); - } ; - - - /** A common ancestor for all tasks queued onto the tick thread */ - class cTask - { - public: - cTask(const cTask & other) = default; - virtual ~cTask() {} - virtual void Run(cWorld & a_World) = 0; - - protected: - cTask() {} - } ; - - typedef SharedPtr cTaskPtr; - typedef std::vector cTasks; - - - class cTaskSaveAllChunks : - public cTask - { - protected: - // cTask overrides: - virtual void Run(cWorld & a_World) override; - } ; - - - class cTaskUnloadUnusedChunks : - public cTask - { - protected: - // cTask overrides: - virtual void Run(cWorld & a_World) override; - }; - - - class cTaskSendBlockToAllPlayers : - public cTask - { - public: - cTaskSendBlockToAllPlayers(std::vector & a_SendQueue); - - protected: - // cTask overrides: - virtual void Run(cWorld & a_World) override; - - std::vector m_SendQueue; - }; - - class cTaskLambda : - public cTask - { - - public: - cTaskLambda(std::function a_Func) : - m_func(a_Func) - { } - - protected: - virtual void Run(cWorld & a_World) override; - - std::function m_func; }; - static const char * GetClassStatic(void) // Needed for ManualBindings's ForEach templates { return "cWorld"; @@ -739,13 +675,10 @@ public: 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(cTaskPtr a_Task); // Exported in ManualBindings.cpp + void QueueTask(std::function a_Task); // Exported in ManualBindings.cpp /** Queues a lambda task onto the tick thread, with the specified delay. */ - void ScheduleTask(int a_DelayTicks, std::function a_Func); - - /** Queues a task onto the tick thread, with the specified delay. */ - void ScheduleTask(int a_DelayTicks, cTaskPtr a_Task); + void ScheduleTask(int a_DelayTicks, std::function a_Task); /** Returns the number of chunks loaded */ int GetNumChunks() const; // tolua_export @@ -912,27 +845,6 @@ private: public: cChunkGeneratorCallbacks(cWorld & a_World); } ; - - - /** A container for tasks that have been scheduled for a specific game tick */ - class cScheduledTask - { - public: - Int64 m_TargetTick; - cTaskPtr m_Task; - - /** Creates a new scheduled task; takes ownership of the task object passed to it. */ - cScheduledTask(Int64 a_TargetTick, cTaskPtr a_Task) : - m_TargetTick(a_TargetTick), - m_Task(a_Task) - { - } - - virtual ~cScheduledTask() {} - }; - - typedef std::unique_ptr cScheduledTaskPtr; - typedef std::list cScheduledTasks; AString m_WorldName; @@ -1062,16 +974,8 @@ private: /** Guards the m_Tasks */ cCriticalSection m_CSTasks; - /** Tasks that have been queued onto the tick thread; guarded by m_CSTasks */ - cTasks m_Tasks; - - /** Guards the m_ScheduledTasks */ - cCriticalSection m_CSScheduledTasks; - - /** Tasks that have been queued to be executed on the tick thread at target tick in the future. - Ordered by increasing m_TargetTick. - Guarded by m_CSScheduledTasks */ - cScheduledTasks m_ScheduledTasks; + /** Tasks that have been queued onto the tick thread, possibly to be executed at target tick in the future; guarded by m_CSTasks */ + std::vector>> m_Tasks; /** Guards m_Clients */ cCriticalSection m_CSClients; @@ -1118,9 +1022,6 @@ private: /** Executes all tasks queued onto the tick thread */ void TickQueuedTasks(void); - /** Executes all tasks queued onto the tick thread */ - void TickScheduledTasks(void); - /** Ticks all clients that are in this world */ void TickClients(float a_Dt); -- cgit v1.2.3