mirror of
https://github.com/alicealys/t5-gsc-utils.git
synced 2025-04-19 20:42:54 +00:00
Don't use asmjit for function wrap
This commit is contained in:
parent
ddf3edb2ed
commit
7d4e4efc5f
@ -12,17 +12,17 @@
|
|||||||
|
|
||||||
namespace gsc
|
namespace gsc
|
||||||
{
|
{
|
||||||
namespace
|
|
||||||
{
|
|
||||||
utils::hook::detour get_function_hook;
|
|
||||||
utils::hook::detour get_method_hook;
|
|
||||||
|
|
||||||
std::unordered_map<std::string, function_t> functions;
|
std::unordered_map<std::string, function_t> functions;
|
||||||
std::unordered_map<std::string, function_t> methods;
|
std::unordered_map<std::string, function_t> methods;
|
||||||
|
|
||||||
std::unordered_map<std::string, void*> function_wraps;
|
std::unordered_map<std::string, void*> function_wraps;
|
||||||
std::unordered_map<std::string, void*> method_wraps;
|
std::unordered_map<std::string, void*> method_wraps;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
utils::hook::detour get_function_hook;
|
||||||
|
utils::hook::detour get_method_hook;
|
||||||
|
|
||||||
std::vector<scripting::script_value> get_arguments()
|
std::vector<scripting::script_value> get_arguments()
|
||||||
{
|
{
|
||||||
std::vector<scripting::script_value> args;
|
std::vector<scripting::script_value> args;
|
||||||
@ -46,80 +46,12 @@ namespace gsc
|
|||||||
scripting::push_value(value);
|
scripting::push_value(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_function(const function_t* function)
|
|
||||||
{
|
|
||||||
const auto args = get_arguments();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const auto value = function->operator()(args);
|
|
||||||
return_value(value);
|
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
game::Scr_Error(game::SCRIPTINSTANCE_SERVER, e.what(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void call_method(const function_t* method, const game::scr_entref_t entref)
|
|
||||||
{
|
|
||||||
const auto args = get_arguments();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const scripting::entity entity = game::Scr_GetEntityId(
|
|
||||||
game::SCRIPTINSTANCE_SERVER, entref.entnum, entref.classnum, 0);
|
|
||||||
|
|
||||||
std::vector<scripting::script_value> args_{};
|
|
||||||
args_.push_back(entity);
|
|
||||||
for (const auto& arg : args)
|
|
||||||
{
|
|
||||||
args_.push_back(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto value = method->operator()(args_);
|
|
||||||
return_value(value);
|
|
||||||
}
|
|
||||||
catch (const std::exception& e)
|
|
||||||
{
|
|
||||||
game::Scr_Error(game::SCRIPTINSTANCE_SERVER, e.what(), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* wrap_function_call(const function_t* function)
|
|
||||||
{
|
|
||||||
return utils::hook::assemble([&](utils::hook::assembler& a)
|
|
||||||
{
|
|
||||||
a.pushad();
|
|
||||||
a.push(function);
|
|
||||||
a.call(call_function);
|
|
||||||
a.add(esp, 0x4);
|
|
||||||
a.popad();
|
|
||||||
|
|
||||||
a.ret();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void* wrap_method_call(const function_t* method)
|
|
||||||
{
|
|
||||||
return utils::hook::assemble([&](utils::hook::assembler& a)
|
|
||||||
{
|
|
||||||
a.pushad();
|
|
||||||
a.push(dword_ptr(esp, 0x24));
|
|
||||||
a.push(method);
|
|
||||||
a.call(call_method);
|
|
||||||
a.add(esp, 0x8);
|
|
||||||
a.popad();
|
|
||||||
|
|
||||||
a.ret();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
script_function get_function_stub(const char** name, int* type)
|
script_function get_function_stub(const char** name, int* type)
|
||||||
{
|
{
|
||||||
if (function_wraps.find(*name) != function_wraps.end())
|
const auto iter = function_wraps.find(*name);
|
||||||
|
if (iter != function_wraps.end())
|
||||||
{
|
{
|
||||||
return reinterpret_cast<script_function>(function_wraps[*name]);
|
return reinterpret_cast<script_function>(iter->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_function_hook.invoke<script_function>(name, type);
|
return get_function_hook.invoke<script_function>(name, type);
|
||||||
@ -127,9 +59,10 @@ namespace gsc
|
|||||||
|
|
||||||
script_function get_method_stub(const char** name, int* type)
|
script_function get_method_stub(const char** name, int* type)
|
||||||
{
|
{
|
||||||
if (method_wraps.find(*name) != method_wraps.end())
|
const auto iter = method_wraps.find(*name);
|
||||||
|
if (iter != method_wraps.end())
|
||||||
{
|
{
|
||||||
return reinterpret_cast<script_function>(method_wraps[*name]);
|
return reinterpret_cast<script_function>(iter->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
return get_method_hook.invoke<script_function>(name, type);
|
return get_method_hook.invoke<script_function>(name, type);
|
||||||
@ -204,27 +137,43 @@ namespace gsc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace function
|
void call_function(const function_t* function)
|
||||||
{
|
{
|
||||||
void add_internal(const std::string& name, const function_t& function)
|
const auto args = get_arguments();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
const auto lower = utils::string::to_lower(name);
|
const auto value = function->operator()(args);
|
||||||
const auto [iterator, was_inserted] = functions.insert(std::make_pair(lower, function));
|
return_value(value);
|
||||||
const auto function_ptr = &iterator->second;
|
}
|
||||||
const auto call_wrap = wrap_function_call(function_ptr);
|
catch (const std::exception& e)
|
||||||
function_wraps[lower] = call_wrap;
|
{
|
||||||
|
game::Scr_Error(game::SCRIPTINSTANCE_SERVER, e.what(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace method
|
void call_method(const function_t* method, const game::scr_entref_t entref)
|
||||||
{
|
{
|
||||||
void add_internal(const std::string& name, const function_t& method)
|
const auto args = get_arguments();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
const auto lower = utils::string::to_lower(name);
|
const scripting::entity entity = game::Scr_GetEntityId(
|
||||||
const auto [iterator, was_inserted] = methods.insert(std::make_pair(lower, method));
|
game::SCRIPTINSTANCE_SERVER, entref.entnum, entref.classnum, 0);
|
||||||
const auto method_ptr = &iterator->second;
|
|
||||||
const auto call_wrap = wrap_method_call(method_ptr);
|
std::vector<scripting::script_value> args_{};
|
||||||
method_wraps[lower] = call_wrap;
|
args_.push_back(entity);
|
||||||
|
for (const auto& arg : args)
|
||||||
|
{
|
||||||
|
args_.push_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto value = method->operator()(args_);
|
||||||
|
return_value(value);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
game::Scr_Error(game::SCRIPTINSTANCE_SERVER, e.what(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,21 @@
|
|||||||
#include "game/scripting/array.hpp"
|
#include "game/scripting/array.hpp"
|
||||||
#include "game/scripting/execution.hpp"
|
#include "game/scripting/execution.hpp"
|
||||||
|
|
||||||
|
#if _HAS_CXX20
|
||||||
namespace gsc
|
namespace gsc
|
||||||
{
|
{
|
||||||
using function_t = std::function<scripting::script_value(const scripting::function_arguments& args)>;
|
using function_t = std::function<scripting::script_value(const scripting::function_arguments& args)>;
|
||||||
using script_function = void(*)(game::scr_entref_t);
|
using script_function = void(*)(game::scr_entref_t);
|
||||||
|
|
||||||
template <class... Args, std::size_t... I>
|
extern std::unordered_map<std::string, function_t> functions;
|
||||||
|
extern std::unordered_map<std::string, function_t> methods;
|
||||||
|
|
||||||
|
extern std::unordered_map<std::string, void*> function_wraps;
|
||||||
|
extern std::unordered_map<std::string, void*> method_wraps;
|
||||||
|
|
||||||
|
// auto = []{} forces template reevaluation
|
||||||
|
|
||||||
|
template <class... Args, std::size_t... I, auto = []{}>
|
||||||
auto wrap_function(const std::function<void(Args...)>& f, std::index_sequence<I...>)
|
auto wrap_function(const std::function<void(Args...)>& f, std::index_sequence<I...>)
|
||||||
{
|
{
|
||||||
return [f]([[maybe_unused]] const scripting::function_arguments& args)
|
return [f]([[maybe_unused]] const scripting::function_arguments& args)
|
||||||
@ -17,7 +26,7 @@ namespace gsc
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class... Args, std::size_t... I>
|
template <class... Args, std::size_t... I, auto = []{}>
|
||||||
auto wrap_function(const std::function<scripting::script_value(Args...)>& f, std::index_sequence<I...>)
|
auto wrap_function(const std::function<scripting::script_value(Args...)>& f, std::index_sequence<I...>)
|
||||||
{
|
{
|
||||||
return [f]([[maybe_unused]] const scripting::function_arguments& args)
|
return [f]([[maybe_unused]] const scripting::function_arguments& args)
|
||||||
@ -26,7 +35,7 @@ namespace gsc
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename R, class... Args, std::size_t... I>
|
template <typename R, class... Args, std::size_t... I, auto = []{}>
|
||||||
auto wrap_function(const std::function<R(Args...)>& f, std::index_sequence<I...>)
|
auto wrap_function(const std::function<R(Args...)>& f, std::index_sequence<I...>)
|
||||||
{
|
{
|
||||||
return [f]([[maybe_unused]] const scripting::function_arguments& args)
|
return [f]([[maybe_unused]] const scripting::function_arguments& args)
|
||||||
@ -35,51 +44,85 @@ namespace gsc
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename R, class... Args>
|
template <typename R, class... Args, auto = []{}>
|
||||||
auto wrap_function(const std::function<R(Args...)>& f)
|
auto wrap_function(const std::function<R(Args...)>& f)
|
||||||
{
|
{
|
||||||
return wrap_function(f, std::index_sequence_for<Args...>{});
|
return wrap_function(f, std::index_sequence_for<Args...>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class F>
|
template <class F, auto = []{}>
|
||||||
auto wrap_function(F f)
|
auto wrap_function(F f)
|
||||||
{
|
{
|
||||||
return wrap_function(std::function(f));
|
return wrap_function(std::function(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void call_function(const function_t* function);
|
||||||
|
void call_method(const function_t* method, const game::scr_entref_t entref);
|
||||||
|
|
||||||
namespace function
|
namespace function
|
||||||
{
|
{
|
||||||
void add_internal(const std::string& name, const function_t& function);
|
template <typename F, auto = []{}>
|
||||||
|
void add_internal(const std::string& name, F function)
|
||||||
|
{
|
||||||
|
static auto called = false;
|
||||||
|
assert(!called);
|
||||||
|
called = true;
|
||||||
|
|
||||||
template <typename F>
|
const auto lower = utils::string::to_lower(name);
|
||||||
|
static const auto [iterator, was_inserted] = functions.insert(std::make_pair(lower, function));
|
||||||
|
static const auto function_ptr = &iterator->second;
|
||||||
|
|
||||||
|
function_wraps[lower] = []()
|
||||||
|
{
|
||||||
|
call_function(function_ptr);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, auto = []{}>
|
||||||
void add(const std::string& name, F f)
|
void add(const std::string& name, F f)
|
||||||
{
|
{
|
||||||
add_internal(name, wrap_function(f));
|
add_internal(name, wrap_function(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ...Args, typename F>
|
template <typename ...Args, typename F, auto = []{}>
|
||||||
void add_multiple(F f, Args&& ...names)
|
void add_multiple(F f, Args&& ...names)
|
||||||
{
|
{
|
||||||
const auto wrap = wrap_function(f);
|
(add(names, f), ...);
|
||||||
(add_internal(names, wrap), ...);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace method
|
namespace method
|
||||||
{
|
{
|
||||||
void add_internal(const std::string& name, const function_t& function);
|
template <typename F, auto = []{}>
|
||||||
|
void add_internal(const std::string& name, F function)
|
||||||
|
{
|
||||||
|
static auto called = false;
|
||||||
|
assert(!called);
|
||||||
|
called = true;
|
||||||
|
|
||||||
template <typename F>
|
const auto lower = utils::string::to_lower(name);
|
||||||
|
static const auto [iterator, was_inserted] = functions.insert(std::make_pair(lower, function));
|
||||||
|
static const auto function_ptr = &iterator->second;
|
||||||
|
|
||||||
|
method_wraps[lower] = [](game::scr_entref_t entref)
|
||||||
|
{
|
||||||
|
call_method(function_ptr, entref);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F, auto = []{}>
|
||||||
void add(const std::string& name, F f)
|
void add(const std::string& name, F f)
|
||||||
{
|
{
|
||||||
add_internal(name, wrap_function(f));
|
add_internal(name, wrap_function(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ...Args, typename F>
|
template <typename ...Args, typename F, auto = []{}>
|
||||||
void add_multiple(F f, Args&& ...names)
|
void add_multiple(F f, Args&& ...names)
|
||||||
{
|
{
|
||||||
const auto wrap = wrap_function(f);
|
(add(names, f), ...);
|
||||||
(add_internal(names, wrap), ...);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
#error pre c++20 is not supported
|
||||||
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user