LiteLoaderBDS-1.16.40/ScriptEngine/API/CommandCompatibleAPI.cpp
2022-09-21 19:47:03 +08:00

194 lines
6.6 KiB
C++

#include "CommandAPI.h"
#include "APIHelp.h"
#include "McAPI.h"
#include "PlayerAPI.h"
#include <Tools/Utils.h>
#include <Engine/GlobalShareData.h>
#include <Engine/LocalShareData.h>
#include <Engine/EngineOwnData.h>
#include <Utils/STLHelper.h>
#include <RegCommandAPI.h>
#include <Global.hpp>
#include <filesystem>
#include <Configs.h>
#include <vector>
#include <string>
using namespace std;
//////////////////// Helper ////////////////////
bool RegisterCmd(const string& cmd, const string& describe, int cmdLevel) {
::Global<CommandRegistry>->registerCommand(cmd, describe.c_str(), (CommandPermissionLevel)cmdLevel, {(CommandFlagValue)0},
{(CommandFlagValue)0x80});
return true;
}
// Helper
void LLSERegisterNewCmd(bool isPlayerCmd, string cmd, const string& describe, int level, Local<Function> func) {
if (cmd[0] == '/')
cmd = cmd.erase(0, 1);
if (isPlayerCmd) {
localShareData->playerCmdCallbacks[cmd] = {EngineScope::currentEngine(), level, script::Global<Function>(func)};
globalShareData->playerRegisteredCmd[cmd] = LLSE_BACKEND_TYPE;
} else {
localShareData->consoleCmdCallbacks[cmd] = {EngineScope::currentEngine(), level, script::Global<Function>(func)};
globalShareData->consoleRegisteredCmd[cmd] = LLSE_BACKEND_TYPE;
}
//延迟注册
if (isCmdRegisterEnabled)
RegisterCmd(cmd, describe, level);
else
toRegCmdQueue.push_back({cmd, describe, level});
}
bool LLSERemoveCmdRegister(ScriptEngine* engine) {
erase_if(localShareData->playerCmdCallbacks, [&engine](auto& data) {
return data.second.fromEngine == engine;
});
erase_if(localShareData->consoleCmdCallbacks, [&engine](auto& data) {
return data.second.fromEngine == engine;
});
return true;
}
// Helper
Local<Value> McClass::regPlayerCmd(const Arguments& args) {
CHECK_ARGS_COUNT(args, 3);
CHECK_ARG_TYPE(args[0], ValueKind::kString);
CHECK_ARG_TYPE(args[1], ValueKind::kString);
CHECK_ARG_TYPE(args[2], ValueKind::kFunction);
if (args.size() >= 4)
CHECK_ARG_TYPE(args[3], ValueKind::kNumber);
try {
string cmd = args[0].asString().toString();
string describe = args[1].asString().toString();
int level = 0;
if (args.size() >= 4) {
int newLevel = args[3].asNumber().toInt32();
if (newLevel >= 0 && newLevel <= 3)
level = newLevel;
}
LLSERegisterNewCmd(true, cmd, describe, level, args[2].asFunction());
return Boolean::newBoolean(true);
}
CATCH("Fail in RegisterPlayerCmd!");
}
Local<Value> McClass::regConsoleCmd(const Arguments& args) {
CHECK_ARGS_COUNT(args, 3);
CHECK_ARG_TYPE(args[0], ValueKind::kString);
CHECK_ARG_TYPE(args[1], ValueKind::kString);
CHECK_ARG_TYPE(args[2], ValueKind::kFunction);
try {
string cmd = args[0].asString().toString();
string describe = args[1].asString().toString();
LLSERegisterNewCmd(false, cmd, describe, 4, args[2].asFunction());
return Boolean::newBoolean(true);
}
CATCH("Fail in RegisterConsoleCmd!");
}
// Helper
bool SendCmdOutput(const std::string& output) {
string finalOutput(output);
finalOutput += "\r\n";
SymCall("??$_Insert_string@DU?$char_traits@D@std@@_K@std@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@0@AEAV10@QEBD_K@Z",
ostream&, ostream&, const char*, unsigned)(cout, finalOutput.c_str(), finalOutput.size());
return true;
}
// Helper
Local<Value> McClass::sendCmdOutput(const Arguments& args) {
CHECK_ARGS_COUNT(args, 1);
CHECK_ARG_TYPE(args[0], ValueKind::kString);
try {
return Boolean::newBoolean(SendCmdOutput(args[0].toStr()));
}
CATCH("Fail in SendCmdOutput!");
}
void ProcessRegCmdQueue() {
for (auto& cmdData : toRegCmdQueue) {
RegisterCmd(cmdData.cmd, cmdData.describe, cmdData.level);
}
toRegCmdQueue.clear();
}
string LLSEFindCmdReg(bool isPlayerCmd, const string& cmd, vector<string>& receiveParas, bool* fromOtherEngine) {
std::unordered_map<std::string, std::string>& registeredMap =
isPlayerCmd ? globalShareData->playerRegisteredCmd : globalShareData->consoleRegisteredCmd;
for (auto& [prefix, fromEngine] : registeredMap) {
if (cmd == prefix || (cmd.find(prefix) == 0 && cmd[prefix.size()] == ' '))
//如果命令与注册前缀全匹配,或者目标前缀后面为空格
{
// Matched
if (fromEngine != LLSE_BACKEND_TYPE) {
*fromOtherEngine = true;
return string();
}
}
}
std::map<std::string, CmdCallbackData, CmdCallbackMapCmp>& cmdMap =
isPlayerCmd ? localShareData->playerCmdCallbacks : localShareData->consoleCmdCallbacks;
for (auto& cmdData : cmdMap) {
string prefix = cmdData.first;
if (cmd == prefix || (cmd.find(prefix) == 0 && cmd[prefix.size()] == ' '))
//如果命令与注册前缀全匹配,或者目标前缀后面为空格
{
// Matched
if (cmd.size() > prefix.size()) {
//除了注册前缀之外还有额外参数
receiveParas = SplitCmdLine(cmd.substr(prefix.size() + 1));
} else
receiveParas = vector<string>();
return prefix;
}
}
return string();
}
bool CallPlayerCmdCallback(Player* player, const string& cmdPrefix, const vector<string>& paras) {
EngineScope enter(localShareData->playerCmdCallbacks[cmdPrefix].fromEngine);
auto cmdData = localShareData->playerCmdCallbacks[cmdPrefix];
Local<Value> res{};
try {
Local<Array> args = Array::newArray();
for (auto& para : paras)
args.add(String::newString(para));
res = cmdData.func.get().call({}, PlayerClass::newPlayer(player), args);
}
CATCH_IN_CALLBACK("PlayerCmd");
if (res.isNull() || (res.isBoolean() && res.asBoolean().value() == false))
return false;
return true;
}
bool CallServerCmdCallback(const string& cmdPrefix, const vector<string>& paras) {
EngineScope enter(localShareData->consoleCmdCallbacks[cmdPrefix].fromEngine);
auto cmdData = localShareData->consoleCmdCallbacks[cmdPrefix];
Local<Value> res{};
try {
Local<Array> args = Array::newArray();
for (auto& para : paras)
args.add(String::newString(para));
res = cmdData.func.get().call({}, args);
}
CATCH_IN_CALLBACK("ServerCmd");
if (res.isNull() || (res.isBoolean() && res.asBoolean().value() == false))
return false;
return true;
}