Don't use asmjit for function wrap

This commit is contained in:
fed 2023-11-07 18:01:59 +01:00
parent ddf3edb2ed
commit 7d4e4efc5f
No known key found for this signature in database
GPG Key ID: 1D2C630F04722996
2 changed files with 100 additions and 108 deletions

View File

@ -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);
} }
} }

View File

@ -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