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

342 lines
12 KiB
C++

#include "RemoteCallAPI.h"
#include <RemoteCallAPI.h>
#include "PlayerAPI.h"
#include "EntityAPI.h"
#include "ItemAPI.h"
#include "BlockAPI.h"
#include "BlockEntityAPI.h"
#include "BaseAPI.h"
#include "ContainerAPI.h"
#include "NbtAPI.h"
#include <API/APIHelp.h>
#include <API/LlAPI.h>
#include <Engine/GlobalShareData.h>
#include <Engine/MessageSystem.h>
#include <Utils/STLHelper.h>
#include <sstream>
#include <string>
#include <map>
#include <process.h>
#include <Configs.h>
using namespace std;
#define DEFAULT_REMOTE_CALL_NAME_SPACE "LLSEGlobal"
//////////////////// Remote Call ////////////////////
RemoteCall::ValueType pack(Local<Value> value);
RemoteCall::ValueType pack(Local<Object> value) {
// Player*, Actor*, ItemStack*, Block*, BlockActor*, Container*, Vec3, BlockPos, CompoundTag*
if (IsInstanceOf<PlayerClass>(value))
return PlayerClass::extract(value);
if (IsInstanceOf<EntityClass>(value))
return EntityClass::extract(value);
if (IsInstanceOf<ItemClass>(value))
return ItemClass::extract(value);
if (IsInstanceOf<BlockClass>(value)) {
auto blk = EngineScope::currentEngine()->getNativeInstance<BlockClass>(value);
return blk->toBlockInstance();
}
if (IsInstanceOf<BlockEntityClass>(value))
return BlockEntityClass::extract(value);
if (IsInstanceOf<ContainerClass>(value))
return ContainerClass::extract(value);
if (IsInstanceOf<FloatPos>(value)) {
auto pos = FloatPos::extractPos(value);
return std::make_pair(pos->getVec3(), pos->getDimensionId());
}
if (IsInstanceOf<IntPos>(value)) {
auto pos = IntPos::extractPos(value);
return std::make_pair(pos->getBlockPos(), pos->getDimensionId());
}
if (IsInstanceOf<NbtCompoundClass>(value))
return NbtCompoundClass::extract(value);
std::unordered_map<std::string, RemoteCall::ValueType> result;
for (auto& k : value.getKeyNames())
result.emplace(k, pack(value.get(k)));
return std::move(result);
}
RemoteCall::ValueType pack(Local<Array> value) {
std::vector<RemoteCall::ValueType> result;
for (size_t index = 0ULL, mEnd = value.size(); index < mEnd; ++index) {
result.push_back(pack(value.get(index)));
}
return std::move(result);
}
RemoteCall::ValueType pack(Local<Value> value) {
switch (value.getKind()) {
case script::ValueKind::kNull:
return nullptr;
break;
case script::ValueKind::kObject:
return pack(value.asObject());
break;
case script::ValueKind::kString:
return value.toStr();
break;
case script::ValueKind::kNumber: {
auto num = value.asNumber();
return RemoteCall::NumberType(num.toInt64(), num.toDouble());
break;
}
case script::ValueKind::kBoolean:
return value.asBoolean().value();
break;
case script::ValueKind::kFunction:
throw std::exception(fmt::format(__FUNCTION__ " - Unsupported Type: kFunction").c_str());
break;
case script::ValueKind::kArray:
return pack(value.asArray());
break;
case script::ValueKind::kByteBuffer:
throw std::exception(fmt::format(__FUNCTION__ " - Unsupported Type: kByteBuffer").c_str());
return value.asByteBuffer().describeUtf8();
break;
case script::ValueKind::kUnsupported:
throw std::exception(fmt::format(__FUNCTION__ " - Unsupported Type: kUnsupported").c_str());
break;
default:
throw std::exception(fmt::format(__FUNCTION__ " - Unsupported Type: Unknown").c_str());
break;
}
return RemoteCall::ValueType();
}
// Player*, Actor*, ItemStack*, Block*, BlockActor*, Container*, Vec3, BlockPos, CompoundTag*
Local<Value> _extractValue(bool v) {
return Boolean::newBoolean(v);
};
Local<Value> _extractValue(std::string v) {
return String::newString(v);
};
Local<Value> _extractValue(std::nullptr_t v) {
return Local<Value>();
};
Local<Value> _extractValue(std::string* v) {
return Local<Value>();
};
Local<Value> _extractValue(Player* v) {
return PlayerClass::newPlayer(v);
};
Local<Value> _extractValue(Actor* v) {
return EntityClass::newEntity(v);
};
Local<Value> _extractValue(Block* v) {
return BlockClass::newBlock(const_cast<Block*>(v), &BlockPos::ZERO, -1);
};
Local<Value> _extractValue(BlockActor* const& v) {
return BlockEntityClass::newBlockEntity(v, -1);
};
Local<Value> _extractValue(Container* v) {
return ContainerClass::newContainer(v);
};
Local<Value> _extractValue(RemoteCall::WorldPosType v) {
return FloatPos::newPos(v.pos, v.dimId);
};
Local<Value> _extractValue(RemoteCall::BlockPosType v) {
return IntPos::newPos(v.pos, v.dimId);
};
Local<Value> _extractValue(RemoteCall::BlockType v) {
return BlockClass::newBlock(v.get<BlockInstance>());
};
Local<Value> _extractValue(RemoteCall::NumberType v) {
return Number::newNumber(v.get<double>());
};
Local<Value> _extractValue(RemoteCall::ItemType&& v) {
if (v.own)
return ItemClass::newItem(v.tryGetUniquePtr().release());
else
return ItemClass::newItem(const_cast<ItemStack*>(v.ptr));
};
Local<Value> _extractValue(RemoteCall::NbtType&& v) {
if (v.own)
return NbtCompoundClass::pack(v.tryGetUniquePtr());
else
return NbtCompoundClass::pack(const_cast<CompoundTag*>(v.ptr), false);
};
Local<Value> extract(RemoteCall::ValueType&& val);
Local<Value> extractValue(RemoteCall::Value&& val) {
static_assert(std::variant_size_v<RemoteCall::Value> == 13);
switch (val.index()) {
#define Extra(index) \
case index: \
return _extractValue(std::move(std::get<index>(val)));
Extra(0);
Extra(1);
Extra(2);
Extra(3);
Extra(4);
Extra(5);
Extra(6);
Extra(7);
Extra(8);
Extra(9);
Extra(10);
Extra(11);
Extra(12);
default:
throw std::exception("Unsupported Type!");
break;
}
};
Local<Value> extractValue(std::vector<RemoteCall::ValueType>&& val) {
auto arr = Array::newArray();
for (auto& v : val)
arr.add(extract(std::move(v)));
return arr;
};
Local<Value> extractValue(std::unordered_map<std::string, RemoteCall::ValueType>&& val) {
auto obj = Object::newObject();
for (auto& [k, v] : val) {
obj.set(k, extract(std::move(v)));
}
return obj;
};
Local<Value> extract(RemoteCall::ValueType&& val) {
static_assert(std::variant_size_v<RemoteCall::ValueType::Type> == 3);
switch (val.value.index()) {
case 0:
return extractValue(std::move(std::get<0>(val.value)));
case 1:
return extractValue(std::move(std::get<1>(val.value)));
case 2:
return extractValue(std::move(std::get<2>(val.value)));
default:
throw std::exception("Unsupported Type");
return Local<Value>();
break;
}
}
Local<Value> MakeRemoteCall(const string& nameSpace, const string& funcName, const Arguments& args) {
auto& func = RemoteCall::importFunc(nameSpace, funcName);
if (!func) {
logger.error("Fail to import! Function [{}::{}] has not been exported!", nameSpace, funcName);
logger.error("In plugin <{}>", ENGINE_OWN_DATA()->pluginName);
return Local<Value>();
}
std::vector<RemoteCall::ValueType> params;
for (int i = 0; i < args.size(); ++i) {
params.emplace_back(pack(args[i]));
}
return extract(func(std::move(params)));
}
bool LLSEExportFunc(ScriptEngine* engine, const Local<Function>& func, const string& nameSpace, const string& funcName) {
// Putting script::Global value into lambda capture list may cause crash
// script::Global<Function> callback = script::Global<Function>(func);
std::string identifier = nameSpace + "::" + funcName;
RemoteCall::CallbackFn cb = [engine, identifier /*, scriptCallback = std::move(callback)*/](std::vector<RemoteCall::ValueType> params) -> RemoteCall::ValueType {
if (LL::isServerStopping() || !EngineManager::isValid(engine) || engine->isDestroying())
return "";
EngineScope enter(engine);
try {
auto iter = ENGINE_GET_DATA(engine)->exportFuncs.find(identifier);
if (iter == ENGINE_GET_DATA(engine)->exportFuncs.end()) {
logger.debug("");
return "";
}
auto scriptCallback = iter->second.callback.get();
std::vector<script::Local<Value>> scriptParams;
for (auto& param : params) {
scriptParams.emplace_back(extract(std::move(param)));
}
return pack(scriptCallback.call({}, scriptParams));
}
CATCH_WITHOUT_RETURN("Fail in Remote Call");
return "";
};
if (RemoteCall::exportFunc(nameSpace, funcName, std::move(cb))) {
ENGINE_GET_DATA(engine)->exportFuncs.emplace(identifier, RemoteCallData{nameSpace, funcName, script::Global<Function>(func)});
return true;
}
return false;
}
bool LLSERemoveAllExportedFuncs(ScriptEngine* engine) {
// enter scope to prevent crash in script::Global::~Global()
EngineScope enter(engine);
std::vector<std::pair<std::string, std::string>> funcs;
for (auto& [key, data] : ENGINE_GET_DATA(engine)->exportFuncs) {
funcs.emplace_back(data.nameSpace, data.funcName);
}
int count = RemoteCall::removeFuncs(std::move(funcs));
ENGINE_GET_DATA(engine)->exportFuncs.clear();
return count;
}
//////////////////// APIs ////////////////////
Local<Value> LlClass::exportFunc(const Arguments& args) {
CHECK_ARGS_COUNT(args, 2);
CHECK_ARG_TYPE(args[0], ValueKind::kFunction);
CHECK_ARG_TYPE(args[1], ValueKind::kString);
try {
std::string nameSpace;
std::string funcName;
if (args.size() > 2) {
CHECK_ARG_TYPE(args[2], ValueKind::kString);
nameSpace = args[1].toStr();
funcName = args[2].toStr();
} else {
nameSpace = DEFAULT_REMOTE_CALL_NAME_SPACE;
funcName = args[1].toStr();
}
return Boolean::newBoolean(LLSEExportFunc(EngineScope::currentEngine(), args[0].asFunction(), nameSpace, funcName));
}
CATCH("Fail in LLSEExport!");
}
Local<Value> LlClass::importFunc(const Arguments& args) {
CHECK_ARGS_COUNT(args, 1);
CHECK_ARG_TYPE(args[0], ValueKind::kString);
try {
std::string nameSpace;
std::string funcName;
if (args.size() > 1) {
CHECK_ARG_TYPE(args[1], ValueKind::kString);
nameSpace = args[0].toStr();
funcName = args[1].toStr();
} else {
nameSpace = DEFAULT_REMOTE_CALL_NAME_SPACE;
funcName = args[0].toStr();
}
//远程调用
return Function::newFunction([nameSpace{nameSpace}, funcName{funcName}](const Arguments& args) -> Local<Value> {
return MakeRemoteCall(nameSpace, funcName, args);
});
}
CATCH("Fail in LLSEImport!")
}
Local<Value> LlClass::hasFuncExported(const Arguments& args) {
CHECK_ARGS_COUNT(args, 1);
CHECK_ARG_TYPE(args[0], ValueKind::kString);
try {
std::string nameSpace;
std::string funcName;
if (args.size() > 1) {
CHECK_ARG_TYPE(args[1], ValueKind::kString);
nameSpace = args[0].toStr();
funcName = args[1].toStr();
} else {
nameSpace = DEFAULT_REMOTE_CALL_NAME_SPACE;
funcName = args[0].toStr();
}
//远程调用
return Boolean::newBoolean(RemoteCall::hasFunc(nameSpace, funcName));
}
CATCH("Fail in LLSEHasExported!")
}