mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2026-06-18 14:40:54 +00:00
Lua: Add CancelEventTimer
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
- ADDED `MP.GetStateMemoryUsage() -> number`: Current memory usage of the current state in bytes
|
- ADDED `MP.GetStateMemoryUsage() -> number`: Current memory usage of the current state in bytes
|
||||||
- ADDED `MP.GetLuaMemoryUsage() -> number`: Current memory usage of all states combined, in bytes
|
- ADDED `MP.GetLuaMemoryUsage() -> number`: Current memory usage of all states combined, in bytes
|
||||||
- ADDED `MP.CreateEventTimer(event,interval_ms)`: Replacement for `CreateThread` - calls the event in the given interval
|
- ADDED `MP.CreateEventTimer(event,interval_ms)`: Replacement for `CreateThread` - calls the event in the given interval
|
||||||
|
- ADDED `MP.CancelEventTimer(event)`: Cancels all event timers for that event
|
||||||
|
|
||||||
# v2.3.3
|
# v2.3.3
|
||||||
|
|
||||||
|
|||||||
@@ -91,9 +91,10 @@ public:
|
|||||||
}
|
}
|
||||||
std::set<std::string> GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId);
|
std::set<std::string> GetEventHandlersForState(const std::string& EventName, TLuaStateId StateId);
|
||||||
void CreateEventTimer(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS);
|
void CreateEventTimer(const std::string& EventName, TLuaStateId StateId, size_t IntervalMS);
|
||||||
|
void CancelEventTimers(const std::string& EventName, TLuaStateId StateId);
|
||||||
|
|
||||||
static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND";
|
static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND";
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void CollectAndInitPlugins();
|
void CollectAndInitPlugins();
|
||||||
void InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config);
|
void InitializePlugin(const fs::path& Folder, const TLuaPluginConfig& Config);
|
||||||
@@ -136,7 +137,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TimedEvent {
|
struct TimedEvent {
|
||||||
const std::chrono::high_resolution_clock::duration Duration {};
|
std::chrono::high_resolution_clock::duration Duration {};
|
||||||
std::chrono::high_resolution_clock::time_point LastCompletion {};
|
std::chrono::high_resolution_clock::time_point LastCompletion {};
|
||||||
std::string EventName;
|
std::string EventName;
|
||||||
TLuaStateId StateId;
|
TLuaStateId StateId;
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ std::string ThreadName(bool DebugModeOverride) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RegisterThread(const std::string& str) {
|
void RegisterThread(const std::string& str) {
|
||||||
|
beammp_info(str + " is " + std::to_string(gettid()));
|
||||||
auto Lock = std::unique_lock(ThreadNameMapMutex);
|
auto Lock = std::unique_lock(ThreadNameMapMutex);
|
||||||
threadNameMap[std::this_thread::get_id()] = str;
|
threadNameMap[std::this_thread::get_id()] = str;
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-38
@@ -44,58 +44,61 @@ void TLuaEngine::operator()() {
|
|||||||
beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage);
|
beammp_lua_error("Calling \"onInit\" on \"" + Future->StateId + "\" failed: " + Future->ErrorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::queue<std::pair<std::string, TLuaStateId>> ToTrigger;
|
std::queue<std::shared_ptr<TLuaResult>> ResultsToCheck;
|
||||||
std::mutex ToTriggerMutex;
|
std::recursive_mutex ResultsToCheckMutex;
|
||||||
std::condition_variable ToTriggerCond;
|
std::thread ResultCheckThread([&] {
|
||||||
auto TriggerThread = [&] {
|
|
||||||
while (!mShutdown) {
|
while (!mShutdown) {
|
||||||
std::unique_lock Lock(ToTriggerMutex);
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
ToTriggerCond.wait_for(Lock, std::chrono::milliseconds(10), [&ToTrigger] { return !ToTrigger.empty(); });
|
std::unique_lock Lock(ResultsToCheckMutex);
|
||||||
auto Timer = ToTrigger.front();
|
if (!ResultsToCheck.empty()) {
|
||||||
ToTrigger.pop();
|
auto Res = ResultsToCheck.front();
|
||||||
auto Handlers = GetEventHandlersForState(Timer.first, Timer.second);
|
ResultsToCheck.pop();
|
||||||
for (auto& Handler : Handlers) {
|
Lock.unlock();
|
||||||
beammp_ignore(mLuaStates[Timer.second]->EnqueueFunctionCall(Handler, {}));
|
|
||||||
|
size_t Waited = 0;
|
||||||
|
while (!Res->Ready) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
Waited++;
|
||||||
|
if (Waited > 1000) {
|
||||||
|
beammp_lua_error(Res->Function + " in " + Res->StateId + " took >1s to respond, not printing possible errors");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Res->Error) {
|
||||||
|
beammp_lua_error(Res->ErrorMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
std::vector<std::thread> Threads;
|
|
||||||
Threads.resize(1);
|
|
||||||
for (auto& Elem : Threads) {
|
|
||||||
Elem = std::thread(TriggerThread);
|
|
||||||
}
|
|
||||||
// event loop
|
// event loop
|
||||||
auto Before = std::chrono::high_resolution_clock::now();
|
auto Before = std::chrono::high_resolution_clock::now();
|
||||||
while (!mShutdown) {
|
while (!mShutdown) {
|
||||||
std::unique_lock Lock(mTimedEventsMutex);
|
{ // Timed Events Scope
|
||||||
for (auto& Timer : mTimedEvents) {
|
std::unique_lock Lock(mTimedEventsMutex);
|
||||||
if (Timer.Expired()) {
|
for (auto& Timer : mTimedEvents) {
|
||||||
if (Timer.EventName != "Asd") {
|
if (Timer.Expired()) {
|
||||||
beammp_debug("\"" + Timer.EventName + "\" expired");
|
Timer.Reset();
|
||||||
|
auto Handlers = GetEventHandlersForState(Timer.EventName, Timer.StateId);
|
||||||
|
std::unique_lock StateLock(mLuaStatesMutex);
|
||||||
|
std::unique_lock Lock2(ResultsToCheckMutex);
|
||||||
|
for (auto& Handler : Handlers) {
|
||||||
|
auto Res = mLuaStates[Timer.StateId]->EnqueueFunctionCall(Handler, {});
|
||||||
|
ResultsToCheck.push(Res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Timer.Reset();
|
|
||||||
{
|
|
||||||
std::unique_lock Lock2(ToTriggerMutex);
|
|
||||||
ToTrigger.emplace(Timer.EventName, Timer.StateId);
|
|
||||||
}
|
|
||||||
ToTriggerCond.notify_one();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// sleep for the remaining time to get to 1ms (our atom duration)
|
// sleep for the remaining time to get to 1ms (our atom duration)
|
||||||
if (std::chrono::high_resolution_clock::duration Diff;
|
if (std::chrono::high_resolution_clock::duration Diff;
|
||||||
(Diff = std::chrono::high_resolution_clock::now() - Before)
|
(Diff = std::chrono::high_resolution_clock::now() - Before)
|
||||||
< std::chrono::milliseconds(1)) {
|
< std::chrono::milliseconds(10)) {
|
||||||
// std::this_thread::sleep_for(Diff);
|
std::this_thread::sleep_for(Diff);
|
||||||
} else {
|
} else {
|
||||||
beammp_debug("Event loop cannot keep up! Currently using " + std::to_string(Threads.size()) + " threads, adding one");
|
beammp_debug("Event loop cannot keep up!");
|
||||||
Threads.push_back(std::thread(TriggerThread));
|
|
||||||
}
|
}
|
||||||
Before = std::chrono::high_resolution_clock::now();
|
Before = std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
for (auto& Elem : Threads) {
|
if (ResultCheckThread.joinable()) {
|
||||||
if (Elem.joinable()) {
|
ResultCheckThread.join();
|
||||||
Elem.join();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,8 +398,14 @@ TLuaEngine::StateThreadData::StateThreadData(const std::string& Name, std::atomi
|
|||||||
MPTable.set_function("Sleep", &LuaAPI::MP::Sleep);
|
MPTable.set_function("Sleep", &LuaAPI::MP::Sleep);
|
||||||
MPTable.set_function("PrintRaw", &LuaAPI::MP::PrintRaw);
|
MPTable.set_function("PrintRaw", &LuaAPI::MP::PrintRaw);
|
||||||
MPTable.set_function("CreateEventTimer", [&](const std::string& EventName, size_t IntervalMS) {
|
MPTable.set_function("CreateEventTimer", [&](const std::string& EventName, size_t IntervalMS) {
|
||||||
|
if (IntervalMS < 25) {
|
||||||
|
beammp_warn("Timer for \"" + EventName + "\" on \"" + mStateId + "\" is set to trigger at <25ms, which is likely too fast and won't cancel properly.");
|
||||||
|
}
|
||||||
mEngine->CreateEventTimer(EventName, mStateId, IntervalMS);
|
mEngine->CreateEventTimer(EventName, mStateId, IntervalMS);
|
||||||
});
|
});
|
||||||
|
MPTable.set_function("CancelEventTimer", [&](const std::string& EventName) {
|
||||||
|
mEngine->CancelEventTimers(EventName, mStateId);
|
||||||
|
});
|
||||||
MPTable.set_function("Set", &LuaAPI::MP::Set);
|
MPTable.set_function("Set", &LuaAPI::MP::Set);
|
||||||
MPTable.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple<int, std::string> {
|
MPTable.set_function("HttpsGET", [&](const std::string& Host, int Port, const std::string& Target) -> std::tuple<int, std::string> {
|
||||||
unsigned Status;
|
unsigned Status;
|
||||||
@@ -547,7 +556,7 @@ void TLuaEngine::StateThreadData::operator()() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +569,22 @@ void TLuaEngine::CreateEventTimer(const std::string& EventName, TLuaStateId Stat
|
|||||||
StateId
|
StateId
|
||||||
};
|
};
|
||||||
mTimedEvents.push_back(std::move(Event));
|
mTimedEvents.push_back(std::move(Event));
|
||||||
beammp_debug("created event timer for \"" + EventName + "\" on \"" + StateId + " with " + std::to_string(IntervalMS) + "ms interval");
|
beammp_trace("created event timer for \"" + EventName + "\" on \"" + StateId + "\" with " + std::to_string(IntervalMS) + "ms interval");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TLuaEngine::CancelEventTimers(const std::string& EventName, TLuaStateId StateId) {
|
||||||
|
std::unique_lock Lock(mTimedEventsMutex);
|
||||||
|
beammp_trace("cancelling event timer for \"" + EventName + "\" on \"" + StateId + "\"");
|
||||||
|
for (;;) {
|
||||||
|
auto Iter = std::find_if(mTimedEvents.begin(), mTimedEvents.end(), [&](const TimedEvent& Event) -> bool {
|
||||||
|
return Event.EventName == EventName && Event.StateId == StateId;
|
||||||
|
});
|
||||||
|
if (Iter != mTimedEvents.end()) {
|
||||||
|
mTimedEvents.erase(Iter);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) {
|
void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) {
|
||||||
|
|||||||
Reference in New Issue
Block a user