#include "RemoteCallAPI.h" #include #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 #include #include #include #include #include #include #include #include #include using namespace std; #define DEFAULT_REMOTE_CALL_NAME_SPACE "LLSEGlobal" //////////////////// Remote Call //////////////////// RemoteCall::ValueType pack(Local value); RemoteCall::ValueType pack(Local value) { // Player*, Actor*, ItemStack*, Block*, BlockActor*, Container*, Vec3, BlockPos, CompoundTag* if (IsInstanceOf(value)) return PlayerClass::extract(value); if (IsInstanceOf(value)) return EntityClass::extract(value); if (IsInstanceOf(value)) return ItemClass::extract(value); if (IsInstanceOf(value)) { auto blk = EngineScope::currentEngine()->getNativeInstance(value); return blk->toBlockInstance(); } if (IsInstanceOf(value)) return BlockEntityClass::extract(value); if (IsInstanceOf(value)) return ContainerClass::extract(value); if (IsInstanceOf(value)) { auto pos = FloatPos::extractPos(value); return std::make_pair(pos->getVec3(), pos->getDimensionId()); } if (IsInstanceOf(value)) { auto pos = IntPos::extractPos(value); return std::make_pair(pos->getBlockPos(), pos->getDimensionId()); } if (IsInstanceOf(value)) return NbtCompoundClass::extract(value); std::unordered_map result; for (auto& k : value.getKeyNames()) result.emplace(k, pack(value.get(k))); return std::move(result); } RemoteCall::ValueType pack(Local value) { std::vector 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) { 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 _extractValue(bool v) { return Boolean::newBoolean(v); }; Local _extractValue(std::string v) { return String::newString(v); }; Local _extractValue(std::nullptr_t v) { return Local(); }; Local _extractValue(std::string* v) { return Local(); }; Local _extractValue(Player* v) { return PlayerClass::newPlayer(v); }; Local _extractValue(Actor* v) { return EntityClass::newEntity(v); }; Local _extractValue(Block* v) { return BlockClass::newBlock(const_cast(v), &BlockPos::ZERO, -1); }; Local _extractValue(BlockActor* const& v) { return BlockEntityClass::newBlockEntity(v, -1); }; Local _extractValue(Container* v) { return ContainerClass::newContainer(v); }; Local _extractValue(RemoteCall::WorldPosType v) { return FloatPos::newPos(v.pos, v.dimId); }; Local _extractValue(RemoteCall::BlockPosType v) { return IntPos::newPos(v.pos, v.dimId); }; Local _extractValue(RemoteCall::BlockType v) { return BlockClass::newBlock(v.get()); }; Local _extractValue(RemoteCall::NumberType v) { return Number::newNumber(v.get()); }; Local _extractValue(RemoteCall::ItemType&& v) { if (v.own) return ItemClass::newItem(v.tryGetUniquePtr().release()); else return ItemClass::newItem(const_cast(v.ptr)); }; Local _extractValue(RemoteCall::NbtType&& v) { if (v.own) return NbtCompoundClass::pack(v.tryGetUniquePtr()); else return NbtCompoundClass::pack(const_cast(v.ptr), false); }; Local extract(RemoteCall::ValueType&& val); Local extractValue(RemoteCall::Value&& val) { static_assert(std::variant_size_v == 13); switch (val.index()) { #define Extra(index) \ case index: \ return _extractValue(std::move(std::get(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 extractValue(std::vector&& val) { auto arr = Array::newArray(); for (auto& v : val) arr.add(extract(std::move(v))); return arr; }; Local extractValue(std::unordered_map&& val) { auto obj = Object::newObject(); for (auto& [k, v] : val) { obj.set(k, extract(std::move(v))); } return obj; }; Local extract(RemoteCall::ValueType&& val) { static_assert(std::variant_size_v == 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(); break; } } Local 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(); } std::vector 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& func, const string& nameSpace, const string& funcName) { // Putting script::Global value into lambda capture list may cause crash // script::Global callback = script::Global(func); std::string identifier = nameSpace + "::" + funcName; RemoteCall::CallbackFn cb = [engine, identifier /*, scriptCallback = std::move(callback)*/](std::vector 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> 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(func)}); return true; } return false; } bool LLSERemoveAllExportedFuncs(ScriptEngine* engine) { // enter scope to prevent crash in script::Global::~Global() EngineScope enter(engine); std::vector> 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 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 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 { return MakeRemoteCall(nameSpace, funcName, args); }); } CATCH("Fail in LLSEImport!") } Local 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!") }