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

366 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <ScriptX/ScriptX.h>
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 <Global.hpp>
#include <Engine/EngineOwnData.h>
#include <Tools/JsonHelper.h>
#include <MC/Level.hpp>
#include <string>
#include <vector>
#include <exception>
#include <sstream>
#include <magic_enum/magic_enum.hpp>
// 输出异常信息
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 <typename T>
bool inline IsInstanceOf(Local<Value> v) {
return EngineScope::currentEngine()->isInstanceOf<T>(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<Value>(); \
}
// 检查是否TYPE类型
#define CHECK_ARG_TYPE(ARG, TYPE) \
if (ARG.getKind() != TYPE) { \
LOG_WRONG_ARG_TYPE(); \
return Local<Value>(); \
}
// 截获引擎异常
#define CATCH(LOG) \
catch (const script::Exception& e) { \
logger.error(LOG##"\n"); \
PrintException(e); \
logger.error("In Plugin: " + ENGINE_OWN_DATA()->pluginName); \
return Local<Value>(); \
} \
catch (const std::exception& e) { \
logger.error("C++ Uncaught Exception Detected!"); \
logger.error(TextEncoding::toUTF8(e.what())); \
LOG_ERROR_WITH_SCRIPT_INFO(); \
return Local<Value>(); \
} \
catch (const seh_exception& e) { \
logger.error("SEH Uncaught Exception Detected!"); \
logger.error(TextEncoding::toUTF8(e.what())); \
LOG_ERROR_WITH_SCRIPT_INFO(); \
return Local<Value>(); \
} \
catch (...) { \
logger.error("Uncaught Exception Detected!"); \
LOG_ERROR_WITH_SCRIPT_INFO(); \
return Local<Value>(); \
}
// 至少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<Value>& num);
// 序列化
template <typename T>
void PrintValue(T& out, Local<Value> v);
template void PrintValue(std::ostream& out, Local<Value> v);
template void PrintValue(Logger::OutputStream& out, Local<Value> v);
std::string ValueToString(Local<Value> v);
// Json 序列化 反序列化
Local<Value> JsonToValue(std::string jsonStr);
Local<Value> JsonToValue(fifo_json j);
std::string ValueToJson(Local<Value> v, int formatIndent = -1);
// Get the enum's ClassDefine<void> object
// Limitation: enum values must be in range of [-128, 128)
template <typename Type>
struct EnumDefineBuilder {
template <Type val>
inline static Local<Value> serialize() {
return Number::newNumber(static_cast<int>(val));
}
inline static Local<Value> keys() {
try {
auto arr = Array::newArray();
for (auto& name : magic_enum::enum_names<Type>()) {
arr.add(String::newString(name));
}
return arr;
} catch (const std::exception&) {
logger.error("Error in " __FUNCTION__);
}
return Local<Value>();
}
inline static Local<Value> toObject() {
try {
auto obj = Object::newObject();
for (auto& [value, name] : magic_enum::enum_entries<Type>()) {
obj.set(String::newString(name), Number::newNumber((int)value));
}
return obj;
} catch (const std::exception&) {
logger.error("Error in " __FUNCTION__);
}
return Local<Value>();
}
inline static Local<Value> getName(const Arguments& args) {
try {
if (args.size() < 1)
return Local<Value>();
if (args[0].isString())
return magic_enum::enum_cast<Type>(args[0].toStr()).has_value() ? args[0] : Local<Value>();
if (args[0].isNumber())
return String::newString(magic_enum::enum_name(static_cast<Type>(args[0].toInt())));
return Local<Value>();
} catch (const std::exception&) {
logger.error("Error in " __FUNCTION__);
}
return Local<Value>();
}
inline static Local<Value> toString() {
try {
return String::newString(typeid(Type).name() + 5);
} catch (const std::exception&) {
logger.error("Error in " __FUNCTION__);
}
return Local<Value>();
}
template <Type val, std::enable_if_t<std::is_enum_v<Type>, char> max = static_cast<char>(*magic_enum::enum_values<Type>().rbegin())>
inline static void buildBuilder(script::ClassDefineBuilder<void>& builder) {
if constexpr (static_cast<char>(val) > max)
return;
if constexpr (!magic_enum::enum_name(val).empty()) {
fmt::print("{} = {},\n", magic_enum::enum_name(val), static_cast<int>(val));
builder.property(magic_enum::enum_name(val).data(), &serialize<val>);
}
buildBuilder<static_cast<Type>((static_cast<char>(val) + 1)), max>(builder);
}
template <std::enable_if_t<std::is_enum_v<Type>, char> max = static_cast<char>(*magic_enum::enum_values<Type>().rbegin())>
inline static ClassDefine<void> build(std::string const& enumName) {
script::ClassDefineBuilder<void> builder = defineClass(enumName);
// fmt::print("枚举 {} 可能取值:\n", enumName);
// buildBuilder<*magic_enum::enum_values<Type>().begin(), max>(builder);
for (auto& [val, name] : magic_enum::enum_entries<Type>()) {
// fmt::print("{} = {},\n", name, static_cast<int>(val));
builder.property(std::string(name), [=]() -> Local<Value> {
try {
return Number::newNumber(static_cast<int>(val));
} catch (const std::exception&) {
logger.error("Error in get {}.{}", enumName, name);
}
return Local<Value>();
});
}
builder.property("keys", &keys);
// builder.property("object", &toObject);
builder.function("getName", &getName);
// fmt::print("\n");
return builder.build();
}
};