summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Bindings/ManualBindings.cpp62
-rw-r--r--src/World.cpp39
-rw-r--r--src/World.h24
3 files changed, 121 insertions, 4 deletions
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index a9368f613..b12fa5f03 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -941,10 +941,6 @@ protected:
}
} ;
-
-
-
-
static int tolua_cWorld_QueueTask(lua_State * tolua_S)
{
// Binding for cWorld::QueueTask
@@ -980,7 +976,65 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S)
return 0;
}
+class cLuaScheduledWorldTask :
+ public cWorld::cScheduledTask
+{
+public:
+ cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef, int a_Ticks) :
+ cScheduledTask(a_Ticks),
+ m_Plugin(a_Plugin),
+ m_FnRef(a_FnRef)
+ {
+ }
+
+protected:
+ cPluginLua & m_Plugin;
+ int m_FnRef;
+
+ // cWorld::cTask overrides:
+ virtual void Run(cWorld & a_World) override
+ {
+ m_Plugin.Call(m_FnRef, &a_World);
+ }
+};
+
+
+static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
+{
+ // Binding for cWorld::ScheduleTask
+ // Params: function, Ticks
+
+ // Retrieve the cPlugin from the LuaState:
+ cPluginLua * Plugin = GetLuaPlugin(tolua_S);
+ if (Plugin == NULL)
+ {
+ // An error message has been already printed in GetLuaPlugin()
+ return 0;
+ }
+
+ // Retrieve the args:
+ cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, 0);
+ if (self == NULL)
+ {
+ return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance");
+ }
+ if (!lua_isfunction(tolua_S, 2))
+ {
+ return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1");
+ }
+
+ // Create a reference to the function:
+ int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
+ if (FnRef == LUA_REFNIL)
+ {
+ return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1");
+ }
+
+ int Ticks = (int) tolua_tonumber (tolua_S, 3, 0);
+ self->ScheduleTask(new cLuaScheduledWorldTask(*Plugin, FnRef,Ticks));
+ return 0;
+}
diff --git a/src/World.cpp b/src/World.cpp
index 1cf82d641..2b85e4b58 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -690,6 +690,7 @@ void cWorld::Tick(float a_Dt, int a_LastTickDurationMSec)
TickClients(a_Dt);
TickQueuedBlocks();
TickQueuedTasks();
+ TickScheduledTasks();
GetSimulatorManager()->Simulate(a_Dt);
@@ -861,6 +862,31 @@ void cWorld::TickQueuedTasks(void)
} // for itr - m_Tasks[]
}
+void cWorld::TickScheduledTasks()
+{
+ ScheduledTaskList Tasks;
+ // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks
+ {
+ cCSLock Lock(m_CSScheduledTasks);
+ ScheduledTaskList::iterator itr = m_ScheduledTasks.begin();
+ while (itr != m_ScheduledTasks.end() && (*itr)->Ticks > 0)
+ {
+ Tasks.push_back(m_ScheduledTasks.front());
+ m_ScheduledTasks.pop_front();
+ }
+ for(;itr != m_ScheduledTasks.end(); itr++)
+ {
+ (*itr)->Ticks--;
+ }
+ }
+
+ // Execute and delete each task:
+ for (ScheduledTaskList::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr)
+ {
+ (*itr)->Run(*this);
+ delete *itr;
+ } // for itr - m_Tasks[]
+}
@@ -2571,6 +2597,19 @@ void cWorld::QueueTask(cTask * a_Task)
m_Tasks.push_back(a_Task);
}
+void cWorld::ScheduleTask(cScheduledTask * a_Task)
+{
+ cCSLock Lock(m_CSScheduledTasks);
+ for(ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end(); itr++)
+ {
+ if((*itr)->Ticks >= a_Task->Ticks)
+ {
+ m_ScheduledTasks.insert(itr, a_Task);
+ return;
+ }
+ }
+ m_ScheduledTasks.push_back(a_Task);
+}
diff --git a/src/World.h b/src/World.h
index b61708d03..6ddb3ec86 100644
--- a/src/World.h
+++ b/src/World.h
@@ -82,7 +82,18 @@ public:
virtual void Run(cWorld & a_World) = 0;
} ;
+ /// A common ancestor for all scheduled tasks queued onto the tick thread
+ class cScheduledTask
+ {
+ public:
+ cScheduledTask(const int a_Ticks) : Ticks(a_Ticks) {};
+ virtual ~cScheduledTask() {};
+ virtual void Run(cWorld & a_World) = 0;
+ int Ticks;
+ };
+
typedef std::vector<cTask *> cTasks;
+ typedef std::list<cScheduledTask *> ScheduledTaskList;
class cTaskSaveAllChunks :
public cTask
@@ -533,6 +544,9 @@ public:
/// Queues a task onto the tick thread. The task object will be deleted once the task is finished
void QueueTask(cTask * a_Task); // Exported in ManualBindings.cpp
+
+ // Queues a task onto the tick thread. The task object will be deleted once the task is finished
+ void ScheduleTask(cScheduledTask * a_Task);
/// Returns the number of chunks loaded
int GetNumChunks() const; // tolua_export
@@ -745,9 +759,16 @@ private:
/// Guards the m_Tasks
cCriticalSection m_CSTasks;
+ /// Guards the m_ScheduledTasks
+ cCriticalSection m_CSScheduledTasks;
+
/// Tasks that have been queued onto the tick thread; guarded by m_CSTasks
cTasks m_Tasks;
+ /// Tasks that have been queued to be executed on the tick thread at some number of ticks in
+ /// the future; guarded by m_CSScheduledTasks
+ ScheduledTaskList m_ScheduledTasks;
+
/// Guards m_Clients
cCriticalSection m_CSClients;
@@ -775,6 +796,9 @@ 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);