#pragma once #include using script::Arguments; using script::Array; using script::Boolean; using script::ByteBuffer; using script::ClassDefine; using script::defineClass; using script::EngineScope; using script::Exception; using script::ExitEngineScope; using script::Function; using script::Local; using script::Number; using script::Object; using script::ScriptClass; using script::ScriptEngine; using script::ScriptEngineImpl; using script::selectOverloadedFunc; using script::String; using script::Value; using script::ValueKind; #include #include #include #include #include #include #include #include #include // 输出异常信息 inline void PrintException(const script::Exception& e) { ostringstream sout; sout << "script::Exception "; sout << e; logger.error(sout.str()); } inline void PrintScriptStackTrace(std::string const& msg = "") { if (!msg.empty()) PrintException(script::Exception(msg)); else logger.error(script::Exception(msg).stacktrace()); } // 方便提取类型 #define toStr() asString().toString() #define toInt() asNumber().toInt32() // 实例类类型检查 template bool inline IsInstanceOf(Local v) { return EngineScope::currentEngine()->isInstanceOf(v); } std::string ValueKindToString(const ValueKind& kind); #if !defined(NEW_DEFINES) // 输出脚本调用堆栈,API名称,以及插件名 #define LOG_ERROR_WITH_SCRIPT_INFO(...) \ PrintScriptStackTrace(__VA_ARGS__); \ logger.error("In API: " __FUNCTION__); \ logger.error("In Plugin: " + ENGINE_OWN_DATA()->pluginName) // 参数类型错误输出 #define LOG_WRONG_ARG_TYPE() LOG_ERROR_WITH_SCRIPT_INFO("Wrong type of argument!"); // 参数数量错误输出 #define LOG_TOO_FEW_ARGS() LOG_ERROR_WITH_SCRIPT_INFO("Too Few arguments!"); // 参数数量错误输出 #define LOG_WRONG_ARGS_COUNT() LOG_ERROR_WITH_SCRIPT_INFO("Wrong number of arguments!"); // 至少COUNT个参数 #define CHECK_ARGS_COUNT(ARGS, COUNT) \ if (ARGS.size() < COUNT) { \ LOG_TOO_FEW_ARGS(); \ return Local(); \ } // 检查是否TYPE类型 #define CHECK_ARG_TYPE(ARG, TYPE) \ if (ARG.getKind() != TYPE) { \ LOG_WRONG_ARG_TYPE(); \ return Local(); \ } // 截获引擎异常 #define CATCH(LOG) \ catch (const script::Exception& e) { \ logger.error(LOG##"\n"); \ PrintException(e); \ logger.error("In Plugin: " + ENGINE_OWN_DATA()->pluginName); \ return Local(); \ } \ catch (const std::exception& e) { \ logger.error("C++ Uncaught Exception Detected!"); \ logger.error(TextEncoding::toUTF8(e.what())); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ return Local(); \ } \ catch (const seh_exception& e) { \ logger.error("SEH Uncaught Exception Detected!"); \ logger.error(TextEncoding::toUTF8(e.what())); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ return Local(); \ } \ catch (...) { \ logger.error("Uncaught Exception Detected!"); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ return Local(); \ } // 至少COUNT个参数_Constructor #define CHECK_ARGS_COUNT_C(ARGS, COUNT) \ if (ARGS.size() < COUNT) { \ LOG_TOO_FEW_ARGS(); \ return nullptr; \ } // 检查是否TYPE类型_Constructor #define CHECK_ARG_TYPE_C(ARG, TYPE) \ if (ARG.getKind() != TYPE) { \ LOG_WRONG_ARG_TYPE(); \ return nullptr; \ } // 检查是否TYPE类型_Setter #define CHECK_ARG_TYPE_S(ARG, TYPE) \ if (ARG.getKind() != TYPE) { \ LOG_WRONG_ARG_TYPE(); \ return; \ } // 截获引擎异常_Constructor #define CATCH_C(LOG) \ catch (const Exception& e) { \ logger.error(LOG##"\n"); \ PrintException(e); \ logger.error("In Plugin: " + ENGINE_OWN_DATA()->pluginName); \ return nullptr; \ } \ catch (const std::exception& e) { \ logger.error("C++ Uncaught Exception Detected!"); \ logger.error(TextEncoding::toUTF8(e.what())); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ return nullptr; \ } \ catch (const seh_exception& e) { \ logger.error("SEH Uncaught Exception Detected!"); \ logger.error(TextEncoding::toUTF8(e.what())); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ return nullptr; \ } \ catch (...) { \ logger.error("Uncaught Exception Detected!"); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ return nullptr; \ } // 截获引擎异常_Setter #define CATCH_S(LOG) \ catch (const Exception& e) { \ logger.error(LOG##"\n"); \ PrintException(e); \ logger.error("In Plugin: " + ENGINE_OWN_DATA()->pluginName); \ return; \ } \ catch (const std::exception& e) { \ logger.error("C++ Uncaught Exception Detected!"); \ logger.error(TextEncoding::toUTF8(e.what())); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ return; \ } \ catch (const seh_exception& e) { \ logger.error("SEH Uncaught Exception Detected!"); \ logger.error(TextEncoding::toUTF8(e.what())); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ return; \ } \ catch (...) { \ logger.error("Uncaught Exception Detected!"); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ return; \ } // 截获引擎异常_Constructor #define CATCH_WITHOUT_RETURN(LOG) \ catch (const Exception& e) { \ logger.error(LOG##"\n"); \ PrintException(e); \ logger.error("In Plugin: " + ENGINE_OWN_DATA()->pluginName); \ } \ catch (const std::exception& e) { \ logger.error("C++ Uncaught Exception Detected!"); \ logger.error(TextEncoding::toUTF8(e.what())); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ } \ catch (const seh_exception& e) { \ logger.error("SEH Uncaught Exception Detected!"); \ logger.error(TextEncoding::toUTF8(e.what())); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ } \ catch (...) { \ logger.error("Uncaught Exception Detected!"); \ LOG_ERROR_WITH_SCRIPT_INFO(); \ } // 截获回调函数异常 #define CATCH_IN_CALLBACK(callback) \ catch (const Exception& e) { \ PrintException(e); \ logger.error(std::string("In callback for ") + callback); \ logger.error("In Plugin: " + ENGINE_OWN_DATA()->pluginName); \ } #else // 新的宏定义, 把异常抛入脚本层处理 #define CATCH_AND_THROW \ catch (const Exception& e) { \ throw e; \ } \ catch (const std::exception& e) { \ throw Exception(e.what()); \ } \ catch (...) { \ throw Exception("Unknown exception in " __FUNCTION__); \ } #define CHECK_ARGS_COUNT(count) \ if (args.size() != count) { \ throw Exception(fmt::format("Invalid arguments count: {}, expect {}, in API {}", args.size(), count, __FUNCTION__)); \ } #define CHECK_ARGS_LEAST_COUNT(count) \ if (args.size() < count) { \ throw Exception(fmt::format("Invalid arguments count: {}, expect at least {}, in API {}", args.size(), count, __FUNCTION__)); \ } #define CHECK_ARG_TYPE(index, type) \ if (args[index].getKind() != ValueKind::type) { \ throw Exception(fmt::format("Wrong type of arguments[{}]: {}, expect {}, in API {}", index, ValueKindToString(args[index].getKind()), ValueKindToString(ValueKind::type), __FUNCTION__)); \ } #define CHECK_VAL_TYPE(val, type) \ if (val.getKind() != ValueKind::type) { \ throw Exception(fmt::format("Wrong type of value: {}, expect {}, in API {}", ValueKindToString(val.getKind()), ValueKindToString(ValueKind::type), __FUNCTION__)); \ } #endif // 判断是否为浮点数 bool CheckIsFloat(const Local& num); // 序列化 template void PrintValue(T& out, Local v); template void PrintValue(std::ostream& out, Local v); template void PrintValue(Logger::OutputStream& out, Local v); std::string ValueToString(Local v); // Json 序列化 反序列化 Local JsonToValue(std::string jsonStr); Local JsonToValue(fifo_json j); std::string ValueToJson(Local v, int formatIndent = -1); // Get the enum's ClassDefine object // Limitation: enum values must be in range of [-128, 128) template struct EnumDefineBuilder { template inline static Local serialize() { return Number::newNumber(static_cast(val)); } inline static Local keys() { try { auto arr = Array::newArray(); for (auto& name : magic_enum::enum_names()) { arr.add(String::newString(name)); } return arr; } catch (const std::exception&) { logger.error("Error in " __FUNCTION__); } return Local(); } inline static Local toObject() { try { auto obj = Object::newObject(); for (auto& [value, name] : magic_enum::enum_entries()) { obj.set(String::newString(name), Number::newNumber((int)value)); } return obj; } catch (const std::exception&) { logger.error("Error in " __FUNCTION__); } return Local(); } inline static Local getName(const Arguments& args) { try { if (args.size() < 1) return Local(); if (args[0].isString()) return magic_enum::enum_cast(args[0].toStr()).has_value() ? args[0] : Local(); if (args[0].isNumber()) return String::newString(magic_enum::enum_name(static_cast(args[0].toInt()))); return Local(); } catch (const std::exception&) { logger.error("Error in " __FUNCTION__); } return Local(); } inline static Local toString() { try { return String::newString(typeid(Type).name() + 5); } catch (const std::exception&) { logger.error("Error in " __FUNCTION__); } return Local(); } template , char> max = static_cast(*magic_enum::enum_values().rbegin())> inline static void buildBuilder(script::ClassDefineBuilder& builder) { if constexpr (static_cast(val) > max) return; if constexpr (!magic_enum::enum_name(val).empty()) { fmt::print("{} = {},\n", magic_enum::enum_name(val), static_cast(val)); builder.property(magic_enum::enum_name(val).data(), &serialize); } buildBuilder((static_cast(val) + 1)), max>(builder); } template , char> max = static_cast(*magic_enum::enum_values().rbegin())> inline static ClassDefine build(std::string const& enumName) { script::ClassDefineBuilder builder = defineClass(enumName); // fmt::print("枚举 {} 可能取值:\n", enumName); // buildBuilder<*magic_enum::enum_values().begin(), max>(builder); for (auto& [val, name] : magic_enum::enum_entries()) { // fmt::print("{} = {},\n", name, static_cast(val)); builder.property(std::string(name), [=]() -> Local { try { return Number::newNumber(static_cast(val)); } catch (const std::exception&) { logger.error("Error in get {}.{}", enumName, name); } return Local(); }); } builder.property("keys", &keys); // builder.property("object", &toObject); builder.function("getName", &getName); // fmt::print("\n"); return builder.build(); } };