mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-05 03:43:40 +00:00
528 lines
18 KiB
C++
528 lines
18 KiB
C++
#pragma once
|
|
#include "Global.h"
|
|
#include "llapi/utils/WinHelper.h"
|
|
#include "Nlohmann/json.hpp"
|
|
#include "llapi/mc/CompoundTag.hpp"
|
|
#include "llapi/mc/Container.hpp"
|
|
#include "llapi/mc/ItemStack.hpp"
|
|
#include "llapi/mc/BlockInstance.hpp"
|
|
#include "llapi/mc/VanillaDimensions.hpp"
|
|
#include "llapi/mc/Player.hpp"
|
|
#include "llapi/mc/Block.hpp"
|
|
#include "llapi/mc/BlockActor.hpp"
|
|
#define TEST_NEW_VALUE_TYPE
|
|
|
|
///////////////////////////////////////////////////////
|
|
// Remote Call API
|
|
// Mainly designed for scripting engines
|
|
// Please call it in MC_SERVER thread or in ScheduleAPI
|
|
// make sure the callback parameter type can be converted to json
|
|
//
|
|
// [Usage]
|
|
// RemoteCall::exportAs("TestNameSpace", "strSize", [](std::string const& arg) -> int { return arg.size(); });
|
|
//
|
|
// // in other plugin
|
|
// auto strSize = RemoteCall::importAs<int(std::string const& arg)>("TestNameSpace", "strSize");
|
|
// logger.info("Size of str: {}", strSize("12345678"));
|
|
//
|
|
// // in js plugin
|
|
// const strSize = ll.import("TestNameSpace", "strSize");
|
|
// logger.info(`Size of str: ${strSize("12345678")}`);
|
|
//
|
|
/////////////////////////////////////////////////////
|
|
namespace RemoteCall {
|
|
#ifdef TEST_NEW_VALUE_TYPE
|
|
// .....
|
|
struct NbtType {
|
|
CompoundTag const* ptr = nullptr;
|
|
bool own = false;
|
|
NbtType(std::unique_ptr<CompoundTag> tag)
|
|
: ptr(tag.release())
|
|
, own(true){};
|
|
NbtType(CompoundTag const* ptr)
|
|
: ptr(ptr)
|
|
, own(false){};
|
|
inline std::unique_ptr<CompoundTag> tryGetUniquePtr() {
|
|
if (!own)
|
|
return {};
|
|
own = false;
|
|
auto uptr = std::unique_ptr<CompoundTag>(const_cast<CompoundTag*>(ptr));
|
|
ptr = nullptr;
|
|
return std::move(uptr);
|
|
}
|
|
template <typename RTN>
|
|
inline RTN get() = delete;
|
|
template <>
|
|
inline CompoundTag const* get() {
|
|
return ptr;
|
|
};
|
|
template <>
|
|
inline CompoundTag* get() {
|
|
return const_cast<CompoundTag*>(ptr);
|
|
};
|
|
template <>
|
|
inline std::unique_ptr<CompoundTag> get() {
|
|
return tryGetUniquePtr();
|
|
};
|
|
};
|
|
|
|
struct ItemType {
|
|
ItemStack const* ptr = nullptr;
|
|
bool own = false;
|
|
ItemType(std::unique_ptr<ItemStack> tag)
|
|
: ptr(tag.release())
|
|
, own(true){};
|
|
ItemType(ItemStack const* ptr)
|
|
: ptr(ptr)
|
|
, own(false){};
|
|
inline std::unique_ptr<ItemStack> tryGetUniquePtr() {
|
|
if (!own)
|
|
return {};
|
|
own = false;
|
|
auto uptr = std::unique_ptr<ItemStack>(const_cast<ItemStack*>(ptr));
|
|
ptr = nullptr;
|
|
return std::move(uptr);
|
|
}
|
|
template <typename RTN>
|
|
inline RTN get() = delete;
|
|
template <>
|
|
inline ItemStack const* get() {
|
|
return ptr;
|
|
};
|
|
template <>
|
|
inline ItemStack* get() {
|
|
return const_cast<ItemStack*>(ptr);
|
|
};
|
|
template <>
|
|
inline std::unique_ptr<ItemStack> get() {
|
|
return tryGetUniquePtr();
|
|
};
|
|
};
|
|
|
|
struct BlockType {
|
|
BlockInstance instance;
|
|
BlockType(BlockInstance instance)
|
|
: instance(instance){};
|
|
BlockType(Block const* ptr)
|
|
: instance(BlockInstance::createBlockInstance(const_cast<Block*>(ptr), BlockPos::ZERO, -1)){};
|
|
template <typename RTN>
|
|
inline RTN get() = delete;
|
|
template <>
|
|
inline Block const* get() {
|
|
return instance.getBlock();
|
|
};
|
|
template <>
|
|
inline BlockInstance get() {
|
|
return instance;
|
|
};
|
|
};
|
|
|
|
struct NumberType {
|
|
__int64 i = 0;
|
|
double f = 0;
|
|
NumberType(__int64 i, double f)
|
|
: i(i)
|
|
, f(f){};
|
|
template <typename T>
|
|
std::enable_if_t<std::is_integral_v<T> || std::is_floating_point_v<T>, NumberType&> operator=(T v) {
|
|
i = static_cast<__int64>(v);
|
|
f = static_cast<double>(v);
|
|
}
|
|
NumberType(double v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
NumberType(float v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
NumberType(__int64 v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
NumberType(int v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
NumberType(short v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
NumberType(char v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
NumberType(unsigned __int64 v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
NumberType(unsigned int v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
NumberType(unsigned short v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
NumberType(unsigned char v)
|
|
: i(static_cast<__int64>(v))
|
|
, f(static_cast<double>(v)){};
|
|
template <typename RTN>
|
|
inline std::enable_if_t<std::is_integral_v<RTN>, RTN> get() {
|
|
return static_cast<RTN>(i);
|
|
};
|
|
template <typename RTN>
|
|
inline std::enable_if_t<std::is_floating_point_v<RTN>, RTN> get() {
|
|
return static_cast<RTN>(f);
|
|
};
|
|
};
|
|
|
|
struct WorldPosType {
|
|
Vec3 pos = Vec3::ZERO;
|
|
int dimId = 3; // VanillaDimensions::Undefined;
|
|
WorldPosType(Vec3 const& pos, int dimId = 3)
|
|
: pos(pos)
|
|
, dimId(dimId){};
|
|
WorldPosType(std::pair<Vec3, int> const& pos)
|
|
: pos(pos.first)
|
|
, dimId(pos.second){};
|
|
template <typename RTN>
|
|
inline RTN get() = delete;
|
|
template <>
|
|
inline Vec3 get() {
|
|
return pos;
|
|
};
|
|
template <>
|
|
inline BlockPos get() {
|
|
return BlockPos(pos);
|
|
};
|
|
template <>
|
|
inline std::pair<Vec3, int> get() {
|
|
return std::make_pair(pos, dimId);
|
|
};
|
|
template <>
|
|
inline std::pair<BlockPos, int> get() {
|
|
return std::make_pair(BlockPos(pos), dimId);
|
|
};
|
|
};
|
|
|
|
struct BlockPosType {
|
|
BlockPos pos = BlockPos::ZERO;
|
|
int dimId = 0;
|
|
BlockPosType(BlockPos const& pos, int dimId = 0)
|
|
: pos(pos)
|
|
, dimId(dimId){};
|
|
BlockPosType(std::pair<BlockPos, int> const& pos)
|
|
: pos(pos.first)
|
|
, dimId(pos.second){};
|
|
template <typename RTN>
|
|
inline RTN get() = delete;
|
|
template <>
|
|
inline BlockPos get() {
|
|
return pos;
|
|
};
|
|
template <>
|
|
inline std::pair<BlockPos, int> get() {
|
|
return std::make_pair(pos, dimId);
|
|
};
|
|
template <>
|
|
inline Vec3 get() {
|
|
return pos.toVec3();
|
|
};
|
|
template <>
|
|
inline std::pair<Vec3, int> get() {
|
|
return std::make_pair(pos.toVec3(), dimId);
|
|
};
|
|
};
|
|
|
|
|
|
// std::string -> json
|
|
// std::string* -> bytes
|
|
#define ExtraType std::nullptr_t, NumberType, Player*, Actor*, BlockActor*, Container*, WorldPosType, BlockPosType, ItemType, BlockType, NbtType
|
|
#define ElementType bool, std::string, ExtraType
|
|
template <typename _Ty, class... _Types>
|
|
static constexpr bool is_one_of_v = std::_Meta_find_unique_index<std::variant<_Types...>, _Ty>::value < sizeof...(_Types);
|
|
template <typename _Ty>
|
|
static constexpr bool is_extra_type_v = std::_Is_any_of_v<_Ty, ExtraType>;
|
|
|
|
static_assert(sizeof(std::variant<ElementType>) == sizeof(std::string) + 8);
|
|
|
|
template <typename>
|
|
constexpr bool is_vector_v = false;
|
|
template <class _Ty, class _Alloc>
|
|
constexpr bool is_vector_v<std::vector<_Ty, _Alloc>> = true;
|
|
template <typename>
|
|
constexpr bool is_map_v = false;
|
|
template <class _Kty, class _Ty, class _Pr, class _Alloc>
|
|
constexpr bool is_map_v<std::map<_Kty, _Ty, _Pr, _Alloc>> = true;
|
|
template <class _Kty, class _Ty, class _Hasher, class _Keyeq, class _Alloc>
|
|
constexpr bool is_map_v<std::unordered_map<_Kty, _Ty, _Hasher, _Keyeq, _Alloc>> = true;
|
|
using Value = std::variant<ElementType>;
|
|
// struct Value
|
|
//{
|
|
// std::variant<ElementType> value;
|
|
// Value(bool v)
|
|
// : value(v){};
|
|
// Value(__int64 v)
|
|
// : value(v){};
|
|
// Value(double v)
|
|
// : value(v){};
|
|
// Value(std::string const& v)
|
|
// : value(v){};
|
|
// Value(std::string* v)
|
|
// : value(v){};
|
|
// Value(Player* v)
|
|
// : value(v){};
|
|
// Value(Actor* v)
|
|
// : value(v){};
|
|
// Value(ItemStack* v)
|
|
// : value(v){};
|
|
// Value(Block* v)
|
|
// : value(v){};
|
|
// Value(BlockActor* v)
|
|
// : value(v){};
|
|
// Value(Container* v)
|
|
// : value(v){};
|
|
// Value(Vec3* v)
|
|
// : value(v){};
|
|
// Value(BlockPos* v)
|
|
// : value(v){};
|
|
// Value(CompoundTag* v)
|
|
// : value(v){};
|
|
// operator std::variant<ElementType>()
|
|
// {
|
|
// return value;
|
|
// }
|
|
// };
|
|
struct ValueType {
|
|
using ArrayType = std::vector<ValueType>;
|
|
using ObjectType = std::unordered_map<std::string, ValueType>;
|
|
using Type = std::variant<Value, ArrayType, ObjectType>;
|
|
Type value;
|
|
ValueType()
|
|
: value({}){};
|
|
// ValueType(ValueType const& v) = delete;
|
|
// ValueType(Value const& v) = delete;
|
|
ValueType(Value&& v)
|
|
: value(std::move(v)){};
|
|
ValueType(Value v)
|
|
: value(std::move(v)){};
|
|
// ValueType(ValueType&& v) noexcept
|
|
// : value(std::move(v.value)){};
|
|
ValueType(std::vector<ValueType>&& v)
|
|
: value(std::move(v)){};
|
|
ValueType(std::unordered_map<std::string, ValueType>&& v)
|
|
: value(std::move(v)){};
|
|
template <typename T>
|
|
ValueType(T const& v)
|
|
: value(Value(v)){};
|
|
};
|
|
|
|
template <typename _Ty>
|
|
static constexpr bool is_supported_type_v = std::is_void_v<_Ty> ||
|
|
is_one_of_v<_Ty, ElementType> ||
|
|
std::is_assignable_v<NumberType, _Ty> ||
|
|
std::is_assignable_v<NbtType, _Ty> ||
|
|
std::is_assignable_v<BlockType, _Ty> ||
|
|
std::is_assignable_v<ItemType, _Ty> ||
|
|
std::is_assignable_v<WorldPosType, _Ty> ||
|
|
std::is_assignable_v<BlockPosType, _Ty> ||
|
|
std::is_base_of_v<Player, std::remove_pointer_t<_Ty>> ||
|
|
std::is_base_of_v<Actor, std::remove_pointer_t<_Ty>>;
|
|
|
|
template <typename RTN>
|
|
RTN extract(ValueType&& val);
|
|
template <typename T>
|
|
ValueType pack(T val);
|
|
|
|
template <typename RTN>
|
|
RTN extractValue(Value&& value) {
|
|
using Type = std::remove_const_t<std::remove_reference_t<RTN>>;
|
|
static_assert(is_supported_type_v<Type>, "Unsupported Type:");
|
|
if constexpr (is_one_of_v<Type, ElementType>)
|
|
return std::get<Type>(value);
|
|
else if constexpr (std::is_assignable_v<NumberType, RTN>)
|
|
return std::get<NumberType>(value).get<Type>();
|
|
else if constexpr (std::is_assignable_v<NbtType, RTN>)
|
|
return std::get<NbtType>(value).get<Type>();
|
|
else if constexpr (std::is_assignable_v<ItemType, RTN>)
|
|
return std::get<ItemType>(value).get<Type>();
|
|
else if constexpr (std::is_assignable_v<BlockType, RTN>)
|
|
return std::get<BlockType>(value).get<Type>();
|
|
else if constexpr (std::is_assignable_v<WorldPosType, RTN>)
|
|
return std::get<WorldPosType>(value).get<Type>();
|
|
else if constexpr (std::is_assignable_v<BlockPosType, RTN>)
|
|
return std::get<BlockPosType>(value).get<Type>();
|
|
else if constexpr (std::is_base_of_v<Player, std::remove_pointer_t<RTN>>)
|
|
return static_cast<RTN>(std::get<Player*>(value));
|
|
else if constexpr (std::is_base_of_v<Actor, std::remove_pointer_t<RTN>>)
|
|
return static_cast<RTN>(std::get<Actor*>(value));
|
|
else if constexpr (std::is_void_v<Type>)
|
|
return;
|
|
else
|
|
throw std::exception(fmt::format(__FUNCTION__ " - Unsupported Type: {}", typeid(RTN).name()).c_str());
|
|
}
|
|
|
|
template <typename RTN>
|
|
bool extractValue(std::vector<ValueType>& value, std::vector<RTN>& rtn) {
|
|
for (ValueType& val : value) {
|
|
rtn.emplace_back(std::move(extract<RTN>(std::move(val))));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <typename RTN>
|
|
bool extractValue(std::unordered_map<std::string, ValueType>& value, std::unordered_map<std::string, RTN>& rtn) {
|
|
for (auto& [key, val] : value) {
|
|
rtn.emplace(key, std::move(extract<RTN>(std::move(val))));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
template <typename RTN>
|
|
RTN extract(ValueType&& val) {
|
|
if constexpr (is_vector_v<RTN>) {
|
|
RTN rtn{};
|
|
extractValue(std::get<std::vector<ValueType>>(val.value), rtn);
|
|
return std::move(rtn);
|
|
} else if constexpr (is_map_v<RTN>) {
|
|
RTN rtn{};
|
|
extractValue(std::get<std::unordered_map<std::string, ValueType>>(val.value), rtn);
|
|
return std::move(rtn);
|
|
} else
|
|
return extractValue<RTN>(std::move(std::get<Value>(val.value)));
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
ValueType packValue(T val) {
|
|
using RawType = std::remove_reference_t<std::remove_const_t<T>>;
|
|
static_assert(is_supported_type_v<RawType>, "Unsupported Type");
|
|
if constexpr (is_one_of_v<RawType, ElementType>)
|
|
return ValueType(std::forward<T>(val));
|
|
else if constexpr (std::is_assignable_v<NumberType, T>)
|
|
return ValueType(NumberType{std::forward<T>(val)});
|
|
else if constexpr (std::is_assignable_v<NbtType, T>)
|
|
return ValueType(NbtType(std::forward<T>(val)));
|
|
else if constexpr (std::is_assignable_v<ItemType, T>)
|
|
return ValueType(ItemType(std::forward<T>(val)));
|
|
else if constexpr (std::is_assignable_v<BlockType, T>)
|
|
return ValueType(BlockType(std::forward<T>(val)));
|
|
else if constexpr (std::is_assignable_v<WorldPosType, T>)
|
|
return ValueType(WorldPosType(std::forward<T>(val)));
|
|
else if constexpr (std::is_assignable_v<BlockPosType, T>)
|
|
return ValueType(BlockPosType(std::forward<T>(val)));
|
|
else if constexpr (std::is_base_of_v<Player, std::remove_pointer_t<T>>)
|
|
return ValueType(static_cast<Player*>(std::forward<T>(val)));
|
|
else if constexpr (std::is_base_of_v<Actor, std::remove_pointer_t<T>>)
|
|
return ValueType(static_cast<Actor*>(std::forward<T>(val)));
|
|
else if constexpr (std::is_void_v<RawType>)
|
|
return ValueType();
|
|
throw std::runtime_error(fmt::format(__FUNCTION__ " - Unsupported Type: {}", typeid(T).name()).c_str());
|
|
return ValueType();
|
|
}
|
|
template <typename T>
|
|
std::vector<ValueType> packArray(std::vector<T> const& val) {
|
|
std::vector<ValueType> result;
|
|
for (auto& v : val) {
|
|
result.emplace_back(pack(v));
|
|
}
|
|
return result;
|
|
}
|
|
template <typename T>
|
|
std::unordered_map<std::string, ValueType> packObject(std::unordered_map<std::string, T> const& val) {
|
|
std::unordered_map<std::string, ValueType> result;
|
|
for (auto& [k, v] : val) {
|
|
result.emplace(k, pack(v));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template <typename T>
|
|
ValueType pack(T val) {
|
|
using RawType = std::remove_reference_t<std::remove_const_t<T>>;
|
|
if constexpr (is_vector_v<RawType>) {
|
|
return packArray(std::forward<T>(val));
|
|
} else if constexpr (is_map_v<RawType>) {
|
|
return packObject(std::forward<T>(val));
|
|
} else
|
|
return packValue(std::forward<T>(val));
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
// Use string as value type because it is easy to convert between script types and native types
|
|
using ValueType = std::string; // Json string
|
|
|
|
template <typename T>
|
|
std::remove_reference_t<T> extract(ValueType const& val) {
|
|
return nlohmann::json::parse(val).get<std::remove_reference_t<T>>();
|
|
}
|
|
|
|
template <typename T>
|
|
ValueType pack(T const& val) {
|
|
return nlohmann::json(val).dump();
|
|
}
|
|
|
|
#endif // TEST_NEW_VALUE_TYPE
|
|
|
|
using CallbackFn = std::function<ValueType(std::vector<ValueType>)>;
|
|
|
|
struct ExportedFuncData {
|
|
HMODULE handle;
|
|
CallbackFn callback;
|
|
};
|
|
|
|
LIAPI extern CallbackFn const EMPTY_FUNC;
|
|
LIAPI bool exportFunc(std::string const& nameSpace, std::string const& funcName, CallbackFn&& callback, HMODULE handle = GetCurrentModule());
|
|
LIAPI CallbackFn const& importFunc(std::string const& nameSpace, std::string const& funcName);
|
|
|
|
|
|
inline ValueType _expandArg(std::vector<ValueType>& args, int& index) {
|
|
return std::move(args[--index]);
|
|
}
|
|
|
|
template <typename RTN, typename... Args>
|
|
inline bool _exportAs(std::string const& nameSpace, std::string const& funcName, std::function<RTN(Args...)>&& callback) {
|
|
CallbackFn cb = [callback = std::move(callback)](std::vector<ValueType> args) -> ValueType {
|
|
if (sizeof...(Args) != args.size())
|
|
return std::move(ValueType());
|
|
int index = sizeof...(Args);
|
|
if constexpr (std::is_void_v<RTN>) {
|
|
callback(extract<Args>(_expandArg(args, index))...);
|
|
return std::move(ValueType());
|
|
} else {
|
|
return pack(callback(extract<Args>(_expandArg(args, index))...));
|
|
}
|
|
};
|
|
return exportFunc(nameSpace, funcName, std::move(cb), GetCurrentModule());
|
|
}
|
|
|
|
LIAPI bool hasFunc(std::string const& nameSpace, std::string const& funcName);
|
|
LIAPI bool removeFunc(std::string const& nameSpace, std::string const& funcName);
|
|
LIAPI int removeNameSpace(std::string const& nameSpace);
|
|
LIAPI int removeFuncs(std::vector<std::pair<std::string, std::string>> funcs);
|
|
LIAPI void _onCallError(std::string const& msg, HMODULE handle = GetCurrentModule());
|
|
|
|
template <typename RTN, typename... Args>
|
|
inline bool _importAs(std::string const& nameSpace, std::string const& funcName, std::function<RTN(Args...)>& func) {
|
|
func = [nameSpace, funcName](Args... args) -> RTN {
|
|
auto& rawFunc = importFunc(nameSpace, funcName);
|
|
if (!rawFunc) {
|
|
_onCallError(fmt::format("Fail to import! Function [{}::{}] has not been exported", nameSpace, funcName));
|
|
return RTN();
|
|
}
|
|
std::vector<ValueType> params = {pack(std::forward<Args>(args))...};
|
|
ValueType&& res = rawFunc(std::move(params));
|
|
return extract<RTN>(std::move(res));
|
|
};
|
|
return true;
|
|
}
|
|
|
|
template <typename CB, typename Func = std::conditional_t<std::is_function_v<CB>, std::function<CB>, CB>>
|
|
inline Func importAs(std::string const& nameSpace, std::string const& funcName) {
|
|
Func callback{};
|
|
bool res = _importAs(nameSpace, funcName, callback);
|
|
return std::move(callback);
|
|
}
|
|
|
|
template <typename CB>
|
|
inline bool exportAs(std::string const& nameSpace, std::string const& funcName, CB&& callback) {
|
|
return _exportAs(nameSpace, funcName, std::function(std::move(callback)));
|
|
}
|
|
|
|
}; // namespace RemoteCall
|