mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-06 20:03:51 +00:00
319 lines
11 KiB
C++
319 lines
11 KiB
C++
#include <API/APIHelp.h>
|
|
#include "TimeTaskSystem.h"
|
|
#include "MessageSystem.h"
|
|
#include <Engine/EngineOwnData.h>
|
|
#include <Engine/EngineManager.h>
|
|
#include <ScheduleAPI.h>
|
|
#include <Utils/STLHelper.h>
|
|
#include <map>
|
|
#include <vector>
|
|
using namespace std;
|
|
|
|
std::atomic_uint timeTaskId = 0;
|
|
CsLock locker;
|
|
struct TimeTaskData {
|
|
ScheduleTask task;
|
|
script::Global<Function> func;
|
|
vector<script::Global<Value>> paras;
|
|
script::Global<String> code;
|
|
ScriptEngine* engine;
|
|
inline void swap(TimeTaskData& rhs) {
|
|
std::swap(rhs.task, task);
|
|
std::swap(rhs.engine, engine);
|
|
rhs.code.swap(code);
|
|
rhs.paras.swap(paras);
|
|
rhs.func.swap(func);
|
|
}
|
|
};
|
|
std::unordered_map<int, TimeTaskData> timeTaskMap;
|
|
|
|
#define TIMETASK_CATCH(TASK_TYPE) \
|
|
catch (const Exception& e) { \
|
|
EngineScope scope(engine); \
|
|
logger.error("Error occurred in {}", TASK_TYPE); \
|
|
PrintException(e); \
|
|
logger.error("In Plugin: " + ENGINE_GET_DATA(engine)->pluginName); \
|
|
} \
|
|
catch (const seh_exception& e) { \
|
|
logger.error("Error occurred in {}", TASK_TYPE); \
|
|
logger.error("SEH Uncaught Exception Detected!"); \
|
|
logger.error(TextEncoding::toUTF8(e.what())); \
|
|
logger.error("In Plugin: " + ENGINE_GET_DATA(engine)->pluginName); \
|
|
} \
|
|
catch (const std::exception& e) { \
|
|
logger.error("Error occurred in {}", TASK_TYPE); \
|
|
logger.error("C++ Uncaught Exception Detected!"); \
|
|
logger.error(TextEncoding::toUTF8(e.what())); \
|
|
logger.error("In Plugin: " + ENGINE_GET_DATA(engine)->pluginName); \
|
|
} \
|
|
catch (...) { \
|
|
logger.error("Error occurred in {}", TASK_TYPE); \
|
|
logger.error("Uncaught Exception Detected!"); \
|
|
logger.error("In Plugin: " + ENGINE_GET_DATA(engine)->pluginName); \
|
|
}
|
|
|
|
|
|
//////////////////// API ////////////////////
|
|
|
|
// void NewTimeout_s(script::Global<Function> func, vector<script::Local<Value>> paras, int timeout, ScriptEngine* engine)
|
|
//{
|
|
// std::vector<script::Global<Value>> tmp;
|
|
// if (paras.size() > 0) {
|
|
// EngineScope enter(engine);
|
|
// for (auto& para : paras)
|
|
// tmp.emplace_back(std::move(para));
|
|
// }
|
|
// Schedule::delay(
|
|
// [engine, func = std::move(func), paras = std::move(tmp)]() {
|
|
// if (LL::isServerStopping())
|
|
// return;
|
|
// if (!EngineManager::isValid(engine))
|
|
// return;
|
|
// EngineScope enter(engine);
|
|
// if (paras.empty()) {
|
|
// func.get().call();
|
|
// }
|
|
// else
|
|
// {
|
|
// vector<Local<Value>> args;
|
|
// for (auto& para : paras)
|
|
// if (para.isEmpty())
|
|
// return;
|
|
// else
|
|
// args.emplace_back(para.get());
|
|
// func.get().call({}, args);
|
|
// }
|
|
// },
|
|
// timeout / 50);
|
|
// }
|
|
|
|
|
|
int NewTimeout(Local<Function> func, vector<Local<Value>> paras, int timeout) {
|
|
int tid = ++timeTaskId;
|
|
TimeTaskData data;
|
|
|
|
data.func = func;
|
|
data.engine = EngineScope::currentEngine();
|
|
for (auto& para : paras)
|
|
data.paras.emplace_back(std::move(para));
|
|
|
|
data.task = Schedule::delay(
|
|
[engine{EngineScope::currentEngine()}, id{tid}]() {
|
|
try {
|
|
if (LL::isServerStopping())
|
|
return;
|
|
if (!EngineManager::isValid(engine))
|
|
return;
|
|
// lock after enter EngineScope to prevent deadlock
|
|
EngineScope scope(engine);
|
|
TimeTaskData taskData;
|
|
{
|
|
CsLockHolder lock(locker);
|
|
|
|
auto t = timeTaskMap.find(id);
|
|
if (t == timeTaskMap.end())
|
|
return;
|
|
t->second.swap(taskData);
|
|
timeTaskMap.erase(id);
|
|
}
|
|
|
|
if (taskData.func.isEmpty())
|
|
return;
|
|
auto func = taskData.func.get();
|
|
if (taskData.paras.empty()) {
|
|
func.call();
|
|
} else {
|
|
vector<Local<Value>> args;
|
|
for (auto& para : taskData.paras)
|
|
if (para.isEmpty())
|
|
return;
|
|
else
|
|
args.emplace_back(para.get());
|
|
func.call({}, args);
|
|
}
|
|
}
|
|
TIMETASK_CATCH("setTimeout-Function");
|
|
},
|
|
timeout / 50);
|
|
CsLockHolder lock(locker);
|
|
data.swap(timeTaskMap[tid]);
|
|
return tid;
|
|
}
|
|
|
|
int NewTimeout(Local<String> func, int timeout) {
|
|
int tid = ++timeTaskId;
|
|
TimeTaskData data;
|
|
|
|
data.code = func;
|
|
data.engine = EngineScope::currentEngine();
|
|
|
|
data.task = Schedule::delay(
|
|
[engine{EngineScope::currentEngine()}, id{tid}]() {
|
|
try {
|
|
if (LL::isServerStopping())
|
|
return;
|
|
if (!EngineManager::isValid(engine))
|
|
return;
|
|
EngineScope scope(engine);
|
|
TimeTaskData taskData;
|
|
{
|
|
CsLockHolder lock(locker);
|
|
|
|
auto t = timeTaskMap.find(id);
|
|
if (t == timeTaskMap.end())
|
|
return;
|
|
t->second.swap(taskData);
|
|
timeTaskMap.erase(id);
|
|
}
|
|
|
|
if (taskData.code.isEmpty())
|
|
return;
|
|
auto code = taskData.code.get().toString();
|
|
engine->eval(code);
|
|
}
|
|
TIMETASK_CATCH("setTimeout-String");
|
|
},
|
|
timeout / 50);
|
|
|
|
CsLockHolder lock(locker);
|
|
data.swap(timeTaskMap[tid]);
|
|
return tid;
|
|
}
|
|
|
|
int NewInterval(Local<Function> func, vector<Local<Value>> paras, int timeout) {
|
|
int tid = ++timeTaskId;
|
|
TimeTaskData data;
|
|
|
|
data.func = func;
|
|
data.engine = EngineScope::currentEngine();
|
|
for (auto& para : paras)
|
|
data.paras.emplace_back(std::move(para));
|
|
|
|
data.task = Schedule::repeat(
|
|
[engine{EngineScope::currentEngine()}, id{tid}]() {
|
|
try {
|
|
if (LL::isServerStopping())
|
|
return;
|
|
if (!EngineManager::isValid(engine)) {
|
|
ClearTimeTask(id);
|
|
return;
|
|
}
|
|
EngineScope scope(engine);
|
|
Local<Value> func = Local<Value>();
|
|
vector<Local<Value>> args;
|
|
{
|
|
CsLockHolder lock(locker);
|
|
|
|
auto t = timeTaskMap.find(id);
|
|
if (t == timeTaskMap.end())
|
|
return;
|
|
|
|
TimeTaskData& taskData = t->second;
|
|
|
|
if (taskData.func.isEmpty())
|
|
return;
|
|
func = taskData.func.get();
|
|
if (!taskData.paras.empty()) {
|
|
vector<Local<Value>> args;
|
|
for (auto& para : taskData.paras)
|
|
if (para.isEmpty())
|
|
return;
|
|
else
|
|
args.emplace_back(para.get());
|
|
}
|
|
}
|
|
if (!func.isFunction())
|
|
return;
|
|
if (args.size() > 0)
|
|
func.asFunction().call({}, args);
|
|
else
|
|
func.asFunction().call();
|
|
}
|
|
TIMETASK_CATCH("setInterval-Function");
|
|
},
|
|
timeout / 50);
|
|
|
|
CsLockHolder lock(locker);
|
|
data.swap(timeTaskMap[tid]);
|
|
return tid;
|
|
}
|
|
|
|
int NewInterval(Local<String> func, int timeout) {
|
|
int tid = ++timeTaskId;
|
|
TimeTaskData data;
|
|
|
|
data.code = func;
|
|
data.engine = EngineScope::currentEngine();
|
|
|
|
data.task = Schedule::repeat(
|
|
[engine{EngineScope::currentEngine()}, id{tid}]() {
|
|
try {
|
|
if (LL::isServerStopping())
|
|
return;
|
|
if (!EngineManager::isValid(engine)) {
|
|
ClearTimeTask(id);
|
|
return;
|
|
}
|
|
EngineScope scope(engine);
|
|
std::string code;
|
|
{
|
|
CsLockHolder lock(locker);
|
|
|
|
auto t = timeTaskMap.find(id);
|
|
if (t == timeTaskMap.end())
|
|
return;
|
|
TimeTaskData& taskData = t->second;
|
|
|
|
if (taskData.code.isEmpty())
|
|
return;
|
|
code = taskData.code.get().toString();
|
|
}
|
|
if (!code.empty())
|
|
engine->eval(code);
|
|
}
|
|
TIMETASK_CATCH("setInterval-String");
|
|
},
|
|
timeout / 50);
|
|
|
|
CsLockHolder lock(locker);
|
|
data.swap(timeTaskMap[tid]);
|
|
return tid;
|
|
}
|
|
|
|
bool ClearTimeTask(int id) {
|
|
assert(EngineScope::currentEngine() != nullptr);
|
|
TimeTaskData data;
|
|
try {
|
|
CsLockHolder lock(locker);
|
|
auto it = timeTaskMap.find(id);
|
|
if (it != timeTaskMap.end()) {
|
|
data.swap(timeTaskMap[id]);
|
|
timeTaskMap.erase(id);
|
|
}
|
|
} catch (...) {
|
|
logger.error("Fail in ClearTimeTask");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
///////////////////////// Func /////////////////////////
|
|
|
|
void LLSERemoveTimeTaskData(ScriptEngine* engine) {
|
|
// enter scope to prevent script::Global::~Global() from crashing
|
|
EngineScope enter(engine);
|
|
std::unordered_map<int, TimeTaskData> tmpMap;
|
|
try {
|
|
CsLockHolder lock(locker);
|
|
for (auto it = timeTaskMap.begin(); it != timeTaskMap.end();) {
|
|
if (it->second.engine == engine) {
|
|
it->second.swap(tmpMap[it->first]);
|
|
it = timeTaskMap.erase(it);
|
|
} else
|
|
++it;
|
|
}
|
|
} catch (...) {
|
|
logger.info("Fail in LLSERemoveTimeTaskData");
|
|
}
|
|
tmpMap.clear();
|
|
} |