Implemented cServer::ScheduleTask() and cServer::TickQueuedTasks() (#5224)
This commit is contained in:
parent
d92509a6e7
commit
9ddc3635d6
@ -22,6 +22,7 @@ Diusrex
|
|||||||
Duralex
|
Duralex
|
||||||
Earboxer (Zach DeCook)
|
Earboxer (Zach DeCook)
|
||||||
FakeTruth (founder)
|
FakeTruth (founder)
|
||||||
|
feyokorenhof
|
||||||
Gareth Nelson
|
Gareth Nelson
|
||||||
GefaketHD
|
GefaketHD
|
||||||
HaoTNN
|
HaoTNN
|
||||||
|
@ -12307,6 +12307,21 @@ end
|
|||||||
},
|
},
|
||||||
Notes = "Add a Forge mod name/version to the server ping list.",
|
Notes = "Add a Forge mod name/version to the server ping list.",
|
||||||
},
|
},
|
||||||
|
ScheduleTask =
|
||||||
|
{
|
||||||
|
Params =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
Name = "DelayTicks",
|
||||||
|
Type = "number",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name = "TaskFunction",
|
||||||
|
Type = "function",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Notes = "Queues the specified function to be executed in the server's tick thread after a the specified number of ticks. This enables operations to be queued for execution in the future. The function signature is <pre class=\"pretty-print lang-lua\">function({{cServer|Server}})</pre>All return values from the function are ignored. Note that it is unsafe to store references to Cuberite objects, such as entities, across from the caller to the task handler function; store the EntityID instead.",
|
||||||
|
},
|
||||||
SetMaxPlayers =
|
SetMaxPlayers =
|
||||||
{
|
{
|
||||||
Params =
|
Params =
|
||||||
|
@ -3585,6 +3585,48 @@ static int tolua_cServer_RegisterForgeMod(lua_State * a_LuaState)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int tolua_cServer_ScheduleTask(lua_State * a_LuaState)
|
||||||
|
{
|
||||||
|
// Function signature:
|
||||||
|
// Server:ScheduleTask(NumTicks, Callback)
|
||||||
|
|
||||||
|
// Retrieve the args:
|
||||||
|
cLuaState L(a_LuaState);
|
||||||
|
if (
|
||||||
|
!L.CheckParamUserType(1, "cServer") ||
|
||||||
|
!L.CheckParamNumber(2) ||
|
||||||
|
!L.CheckParamFunction(3)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
cServer * Server;
|
||||||
|
int NumTicks;
|
||||||
|
auto Task = std::make_shared<cLuaState::cCallback>();
|
||||||
|
if (!L.GetStackValues(1, Server, NumTicks, Task))
|
||||||
|
{
|
||||||
|
return cManualBindings::lua_do_error(a_LuaState, "Error in function call '#funcname#': Cannot read parameters");
|
||||||
|
}
|
||||||
|
if (Server == nullptr)
|
||||||
|
{
|
||||||
|
return cManualBindings::lua_do_error(a_LuaState, "Error in function call '#funcname#': Not called on an object instance");
|
||||||
|
}
|
||||||
|
if (!Task->IsValid())
|
||||||
|
{
|
||||||
|
return cManualBindings::lua_do_error(a_LuaState, "Error in function call '#funcname#': Could not store the callback parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
Server->ScheduleTask(cTickTime(NumTicks), [Task](cServer & a_Server)
|
||||||
|
{
|
||||||
|
Task->Call(&a_Server);
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int tolua_cScoreboard_GetTeamNames(lua_State * L)
|
static int tolua_cScoreboard_GetTeamNames(lua_State * L)
|
||||||
{
|
{
|
||||||
cLuaState S(L);
|
cLuaState S(L);
|
||||||
@ -4625,6 +4667,7 @@ void cManualBindings::Bind(lua_State * tolua_S)
|
|||||||
|
|
||||||
tolua_beginmodule(tolua_S, "cServer");
|
tolua_beginmodule(tolua_S, "cServer");
|
||||||
tolua_function(tolua_S, "RegisterForgeMod", tolua_cServer_RegisterForgeMod);
|
tolua_function(tolua_S, "RegisterForgeMod", tolua_cServer_RegisterForgeMod);
|
||||||
|
tolua_function(tolua_S, "ScheduleTask", tolua_cServer_ScheduleTask);
|
||||||
tolua_endmodule(tolua_S);
|
tolua_endmodule(tolua_S);
|
||||||
|
|
||||||
tolua_beginmodule(tolua_S, "cStringCompression");
|
tolua_beginmodule(tolua_S, "cStringCompression");
|
||||||
|
@ -298,7 +298,3 @@ public:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -117,7 +117,8 @@ cServer::cServer(void) :
|
|||||||
m_MaxPlayers(0),
|
m_MaxPlayers(0),
|
||||||
m_bIsHardcore(false),
|
m_bIsHardcore(false),
|
||||||
m_TickThread(*this),
|
m_TickThread(*this),
|
||||||
m_ShouldAuthenticate(false)
|
m_ShouldAuthenticate(false),
|
||||||
|
m_UpTime(0)
|
||||||
{
|
{
|
||||||
// Initialize the LuaStateTracker singleton before the app goes multithreaded:
|
// Initialize the LuaStateTracker singleton before the app goes multithreaded:
|
||||||
cLuaStateTracker::GetStats();
|
cLuaStateTracker::GetStats();
|
||||||
@ -326,6 +327,9 @@ cTCPLink::cCallbacksPtr cServer::OnConnectionAccepted(const AString & a_RemoteIP
|
|||||||
|
|
||||||
void cServer::Tick(float a_Dt)
|
void cServer::Tick(float a_Dt)
|
||||||
{
|
{
|
||||||
|
// Update server uptime
|
||||||
|
m_UpTime++;
|
||||||
|
|
||||||
// Send the tick to the plugins, as well as let the plugin manager reload, if asked to (issue #102):
|
// Send the tick to the plugins, as well as let the plugin manager reload, if asked to (issue #102):
|
||||||
cPluginManager::Get()->Tick(a_Dt);
|
cPluginManager::Get()->Tick(a_Dt);
|
||||||
|
|
||||||
@ -334,6 +338,9 @@ void cServer::Tick(float a_Dt)
|
|||||||
|
|
||||||
// Tick all clients not yet assigned to a world:
|
// Tick all clients not yet assigned to a world:
|
||||||
TickClients(a_Dt);
|
TickClients(a_Dt);
|
||||||
|
|
||||||
|
// Process all queued tasks
|
||||||
|
TickQueuedTasks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -442,6 +449,20 @@ void cServer::QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCa
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cServer::ScheduleTask(cTickTime a_DelayTicks, std::function<void(cServer &)> a_Task)
|
||||||
|
{
|
||||||
|
const auto TargetTick = a_DelayTicks + m_UpTime;
|
||||||
|
// Insert the task into the list of scheduled tasks
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSTasks);
|
||||||
|
m_Tasks.emplace_back(TargetTick, std::move(a_Task));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
|
void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
|
||||||
{
|
{
|
||||||
AStringVector split = StringSplit(a_Cmd, " ");
|
AStringVector split = StringSplit(a_Cmd, " ");
|
||||||
@ -725,3 +746,42 @@ void cServer::TickCommands(void)
|
|||||||
ExecuteConsoleCommand(Command.first, *Command.second);
|
ExecuteConsoleCommand(Command.first, *Command.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cServer::TickQueuedTasks(void)
|
||||||
|
{
|
||||||
|
// Move the tasks to be executed to a seperate vector to avoid deadlocks on
|
||||||
|
// accessing m_Tasks
|
||||||
|
decltype(m_Tasks) Tasks;
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSTasks);
|
||||||
|
if (m_Tasks.empty())
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
return a_Task.first >= m_UpTime;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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 each task:
|
||||||
|
for (const auto & Task : Tasks)
|
||||||
|
{
|
||||||
|
Task.second(*this);
|
||||||
|
} // for itr - m_Tasks[]
|
||||||
|
}
|
||||||
|
20
src/Server.h
20
src/Server.h
@ -105,6 +105,9 @@ public:
|
|||||||
The command's output will be written to the a_Output callback. */
|
The command's output will be written to the a_Output callback. */
|
||||||
void QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
|
void QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output);
|
||||||
|
|
||||||
|
/** Queues a lambda task onto the server tick thread, with the specified delay in ticks. */
|
||||||
|
void ScheduleTask(cTickTime a_DelayTicks, std::function<void(class cServer &)> a_Task);
|
||||||
|
|
||||||
/** Lists all available console commands and their helpstrings */
|
/** Lists all available console commands and their helpstrings */
|
||||||
void PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & a_Output);
|
void PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & a_Output);
|
||||||
|
|
||||||
@ -245,6 +248,18 @@ private:
|
|||||||
AStringVector m_Ports;
|
AStringVector m_Ports;
|
||||||
|
|
||||||
|
|
||||||
|
/** Time, in ticks, since the server started
|
||||||
|
Not persistent across server restarts */
|
||||||
|
cTickTimeLong m_UpTime;
|
||||||
|
|
||||||
|
/** Guards the m_Tasks */
|
||||||
|
cCriticalSection m_CSTasks;
|
||||||
|
|
||||||
|
/** 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<std::pair<std::chrono::milliseconds, std::function<void(class cServer &)>>> m_Tasks;
|
||||||
|
|
||||||
|
|
||||||
cServer(void);
|
cServer(void);
|
||||||
|
|
||||||
/** Executes the console command, sends output through the specified callback. */
|
/** Executes the console command, sends output through the specified callback. */
|
||||||
@ -268,6 +283,11 @@ private:
|
|||||||
/** Executes commands queued in the command queue. */
|
/** Executes commands queued in the command queue. */
|
||||||
void TickCommands(void);
|
void TickCommands(void);
|
||||||
|
|
||||||
|
|
||||||
|
/** Executes all tasks queued onto the tick thread */
|
||||||
|
void TickQueuedTasks(void);
|
||||||
|
|
||||||
|
|
||||||
}; // tolua_export
|
}; // tolua_export
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user