mirror of
https://github.com/alicealys/t5-gsc-utils.git
synced 2025-04-19 12:32:53 +00:00
Some changes + support STL containers as argument types
This commit is contained in:
parent
cdd2c51568
commit
9512add5ad
@ -13,22 +13,22 @@
|
|||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
|
|
||||||
namespace scripting
|
namespace gsc
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
utils::hook::detour get_function_hook;
|
utils::hook::detour get_function_hook;
|
||||||
utils::hook::detour get_method_hook;
|
utils::hook::detour get_method_hook;
|
||||||
|
|
||||||
std::unordered_map<std::string, std::function<script_value(const function_arguments& args)>> functions;
|
std::unordered_map<std::string, std::function<scripting::script_value(const scripting::function_arguments& args)>> functions;
|
||||||
std::unordered_map<std::string, std::function<script_value(const function_arguments& args)>> methods;
|
std::unordered_map<std::string, std::function<scripting::script_value(const scripting::function_arguments& args)>> 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;
|
||||||
|
|
||||||
std::vector<script_value> get_arguments()
|
std::vector<scripting::script_value> get_arguments()
|
||||||
{
|
{
|
||||||
std::vector<script_value> args;
|
std::vector<scripting::script_value> args;
|
||||||
|
|
||||||
for (auto i = 0; static_cast<unsigned int>(i) < game::scr_VmPub->outparamcount; i++)
|
for (auto i = 0; static_cast<unsigned int>(i) < game::scr_VmPub->outparamcount; i++)
|
||||||
{
|
{
|
||||||
@ -46,7 +46,7 @@ namespace scripting
|
|||||||
game::Scr_ClearOutParams(game::SCRIPTINSTANCE_SERVER);
|
game::Scr_ClearOutParams(game::SCRIPTINSTANCE_SERVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
push_value(value);
|
scripting::push_value(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_function(const char* name)
|
void call_function(const char* name)
|
||||||
@ -82,10 +82,10 @@ namespace scripting
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
const entity entity = game::Scr_GetEntityId(
|
const scripting::entity entity = game::Scr_GetEntityId(
|
||||||
game::SCRIPTINSTANCE_SERVER, entref.entnum, entref.classnum, 0);
|
game::SCRIPTINSTANCE_SERVER, entref.entnum, entref.classnum, 0);
|
||||||
|
|
||||||
std::vector<script_value> args_{};
|
std::vector<scripting::script_value> args_{};
|
||||||
args_.push_back(entity);
|
args_.push_back(entity);
|
||||||
for (const auto& arg : args)
|
for (const auto& arg : args)
|
||||||
{
|
{
|
||||||
@ -134,6 +134,11 @@ namespace scripting
|
|||||||
|
|
||||||
script_function get_function_stub(const char** name, int* type)
|
script_function get_function_stub(const char** name, int* type)
|
||||||
{
|
{
|
||||||
|
if (*name == "print"s)
|
||||||
|
{
|
||||||
|
MessageBoxA(nullptr, "", "", 0);
|
||||||
|
}
|
||||||
|
|
||||||
if (function_wraps.find(*name) != function_wraps.end())
|
if (function_wraps.find(*name) != function_wraps.end())
|
||||||
{
|
{
|
||||||
return reinterpret_cast<script_function>(function_wraps[*name]);
|
return reinterpret_cast<script_function>(function_wraps[*name]);
|
||||||
@ -169,26 +174,32 @@ namespace scripting
|
|||||||
utils::hook::detour scr_settings_hook;
|
utils::hook::detour scr_settings_hook;
|
||||||
void scr_settings_stub(int /*developer*/, int developer_script, int /*abort_on_error*/, int inst)
|
void scr_settings_stub(int /*developer*/, int developer_script, int /*abort_on_error*/, int inst)
|
||||||
{
|
{
|
||||||
scr_settings_hook.invoke<void>(0x55D010, developer_script, developer_script, 0, inst);
|
scr_settings_hook.invoke<void>(SELECT_VALUE(0x0, 0x55D010), developer_script, developer_script, 0, inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
namespace function
|
||||||
void add_function(const std::string& name, F f)
|
|
||||||
{
|
{
|
||||||
const auto wrap = wrap_function(f);
|
template <typename F>
|
||||||
functions[name] = wrap;
|
void add(const std::string& name, F f)
|
||||||
const auto call_wrap = wrap_function_call(name);
|
{
|
||||||
function_wraps[name] = call_wrap;
|
const auto wrap = wrap_function(f);
|
||||||
|
functions[name] = wrap;
|
||||||
|
const auto call_wrap = wrap_function_call(name);
|
||||||
|
function_wraps[name] = call_wrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
namespace method
|
||||||
void add_method(const std::string& name, F f)
|
|
||||||
{
|
{
|
||||||
const auto wrap = wrap_function(f);
|
template <typename F>
|
||||||
methods[name] = wrap;
|
void add(const std::string& name, F f)
|
||||||
const auto call_wrap = wrap_method_call(name);
|
{
|
||||||
method_wraps[name] = call_wrap;
|
const auto wrap = wrap_function(f);
|
||||||
|
methods[name] = wrap;
|
||||||
|
const auto call_wrap = wrap_method_call(name);
|
||||||
|
method_wraps[name] = call_wrap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
@ -197,34 +208,51 @@ namespace scripting
|
|||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
// Don't com_error on gsc errors
|
// Don't com_error on gsc errors
|
||||||
utils::hook::nop(SELECT_VALUE(0, 0x4D9BB1), 5);
|
utils::hook::nop(SELECT_VALUE(0x0, 0x4D9BB1), 5);
|
||||||
utils::hook::jump(0x568B90, print);
|
utils::hook::jump(SELECT_VALUE(0x0, 0x568B90), print);
|
||||||
|
|
||||||
scr_settings_hook.create(SELECT_VALUE(0x0, 0x55D010), scr_settings_stub);
|
scr_settings_hook.create(SELECT_VALUE(0x0, 0x55D010), scr_settings_stub);
|
||||||
get_function_hook.create(SELECT_VALUE(0x0, 0x465E20), get_function_stub);
|
get_function_hook.create(SELECT_VALUE(0x0, 0x465E20), get_function_stub);
|
||||||
get_method_hook.create(SELECT_VALUE(0x0, 0x555580), get_method_stub);
|
get_method_hook.create(SELECT_VALUE(0x0, 0x555580), get_method_stub);
|
||||||
|
|
||||||
add_function("print_", [](const variadic_args& args)
|
function::add("print_", [](const scripting::variadic_args& va)
|
||||||
{
|
{
|
||||||
for (const auto& arg : args)
|
for (const auto& arg : va)
|
||||||
{
|
{
|
||||||
printf("%s\t", arg.to_string().data());
|
printf("%s\t", arg.to_string().data());
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
add_function("fileexists", utils::io::file_exists);
|
function::add("writefile", [](const std::string& file, const std::string& data,
|
||||||
add_function("writefile", utils::io::write_file);
|
const scripting::variadic_args& va)
|
||||||
add_function("movefile", utils::io::move_file);
|
{
|
||||||
add_function("filesize", utils::io::file_size);
|
auto append = false;
|
||||||
add_function("createdirectory", utils::io::create_directory);
|
|
||||||
add_function("directoryexists", utils::io::directory_exists);
|
if (va.size() > 0)
|
||||||
add_function("directoryisempty", utils::io::directory_is_empty);
|
{
|
||||||
add_function("listfiles", utils::io::list_files);
|
append = va[0];
|
||||||
add_function("removefile", utils::io::remove_file);
|
}
|
||||||
add_function("readfile", static_cast<std::string(*)(const std::string&)>(utils::io::read_file));
|
|
||||||
|
return utils::io::write_file(file, data, append);
|
||||||
|
});
|
||||||
|
|
||||||
|
function::add("appendfile", [](const std::string& file, const std::string& data)
|
||||||
|
{
|
||||||
|
return utils::io::write_file(file, data, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
function::add("fileexists", utils::io::file_exists);
|
||||||
|
function::add("movefile", utils::io::move_file);
|
||||||
|
function::add("filesize", utils::io::file_size);
|
||||||
|
function::add("createdirectory", utils::io::create_directory);
|
||||||
|
function::add("directoryexists", utils::io::directory_exists);
|
||||||
|
function::add("directoryisempty", utils::io::directory_is_empty);
|
||||||
|
function::add("listfiles", utils::io::list_files);
|
||||||
|
function::add("removefile", utils::io::remove_file);
|
||||||
|
function::add("readfile", static_cast<std::string(*)(const std::string&)>(utils::io::read_file));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
REGISTER_COMPONENT(scripting::component)
|
REGISTER_COMPONENT(gsc::component)
|
||||||
|
@ -2,24 +2,24 @@
|
|||||||
#include "game/scripting/array.hpp"
|
#include "game/scripting/array.hpp"
|
||||||
#include "game/scripting/execution.hpp"
|
#include "game/scripting/execution.hpp"
|
||||||
|
|
||||||
namespace scripting
|
namespace gsc
|
||||||
{
|
{
|
||||||
using script_function = void(*)(game::scr_entref_t);
|
using script_function = void(*)(game::scr_entref_t);
|
||||||
|
|
||||||
template <class... Args, std::size_t... I>
|
template <class... Args, std::size_t... I>
|
||||||
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 function_arguments& args)
|
return [f]([[maybe_unused]] const scripting::function_arguments& args)
|
||||||
{
|
{
|
||||||
f(args[I]...);
|
f(args[I]...);
|
||||||
return script_value{};
|
return scripting::script_value{};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class... Args, std::size_t... I>
|
template <class... Args, std::size_t... I>
|
||||||
auto wrap_function(const std::function<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 function_arguments& args)
|
return [f]([[maybe_unused]] const scripting::function_arguments& args)
|
||||||
{
|
{
|
||||||
return f(args[I]...);
|
return f(args[I]...);
|
||||||
};
|
};
|
||||||
@ -28,9 +28,9 @@ namespace scripting
|
|||||||
template <typename R, class... Args, std::size_t... I>
|
template <typename R, class... Args, std::size_t... I>
|
||||||
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 function_arguments& args)
|
return [f]([[maybe_unused]] const scripting::function_arguments& args)
|
||||||
{
|
{
|
||||||
return script_value{f(args[I]...)};
|
return scripting::script_value{f(args[I]...)};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,9 +46,15 @@ namespace scripting
|
|||||||
return wrap_function(std::function(f));
|
return wrap_function(std::function(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename F>
|
namespace function
|
||||||
void add_function(const std::string& name, F f);
|
{
|
||||||
|
template <typename F>
|
||||||
|
void add(const std::string& name, F f);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename F>
|
namespace method
|
||||||
void add_method(const std::string& name, F f);
|
{
|
||||||
|
template <typename F>
|
||||||
|
void add(const std::string& name, F f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,9 +143,9 @@ namespace scripting
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int array::size() const
|
int array::size() const
|
||||||
{
|
{
|
||||||
return game::Scr_GetSelf(game::SCRIPTINSTANCE_SERVER, this->id_);
|
return static_cast<int>(game::Scr_GetSelf(game::SCRIPTINSTANCE_SERVER, this->id_));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int array::push(const script_value& value) const
|
unsigned int array::push(const script_value& value) const
|
||||||
|
@ -28,7 +28,7 @@ namespace scripting
|
|||||||
array& operator=(array&& other) noexcept;
|
array& operator=(array&& other) noexcept;
|
||||||
|
|
||||||
std::vector<script_value> get_keys() const;
|
std::vector<script_value> get_keys() const;
|
||||||
unsigned int size() const;
|
int size() const;
|
||||||
|
|
||||||
unsigned int push(const script_value&) const;
|
unsigned int push(const script_value&) const;
|
||||||
void erase(const unsigned int) const;
|
void erase(const unsigned int) const;
|
||||||
|
@ -330,6 +330,18 @@ namespace scripting
|
|||||||
*
|
*
|
||||||
**********************************************/
|
**********************************************/
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool script_value::is<script_value>() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
script_value script_value::get() const
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
const game::VariableValue& script_value::get_raw() const
|
const game::VariableValue& script_value::get_raw() const
|
||||||
{
|
{
|
||||||
return this->value_.get();
|
return this->value_.get();
|
||||||
@ -372,11 +384,13 @@ namespace scripting
|
|||||||
return this->type_name();
|
return this->type_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
function_argument::function_argument(const arguments& args, const script_value& value, const int index)
|
function_argument::function_argument(const arguments& args, const script_value& value, const int index, const bool exists)
|
||||||
: values_(args)
|
: values_(args)
|
||||||
, value_(value)
|
, value_(value)
|
||||||
, index_(index)
|
, index_(index)
|
||||||
|
, exists_(exists)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function_arguments::function_arguments(const arguments& values)
|
function_arguments::function_arguments(const arguments& values)
|
||||||
|
@ -144,7 +144,7 @@ namespace scripting
|
|||||||
{
|
{
|
||||||
const auto type = get_typename(this->get_raw());
|
const auto type = get_typename(this->get_raw());
|
||||||
const auto c_type = get_c_typename<T>();
|
const auto c_type = get_c_typename<T>();
|
||||||
throw std::runtime_error(std::string("has type '" + type + "' but should be '" + c_type + "'"));
|
throw std::runtime_error(utils::string::va("has type '%s' but should be '%s'", type.data(), c_type.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return get<T>();
|
return get<T>();
|
||||||
@ -190,18 +190,22 @@ namespace scripting
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class variadic_args : public arguments
|
class function_argument;
|
||||||
{
|
using variadic_args = std::vector<function_argument>;
|
||||||
};
|
|
||||||
|
|
||||||
class function_argument
|
class function_argument
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
function_argument(const arguments& args, const script_value& value, const int index);
|
function_argument(const arguments& args, const script_value& value, const int index, const bool exists);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T as() const
|
T as() const
|
||||||
{
|
{
|
||||||
|
if (!this->exists_)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(utils::string::va("parameter %d does not exist", this->index_));
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return this->value_.as<T>();
|
return this->value_.as<T>();
|
||||||
@ -209,7 +213,7 @@ namespace scripting
|
|||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
throw std::runtime_error(utils::string::va("parameter %d %s",
|
throw std::runtime_error(utils::string::va("parameter %d %s",
|
||||||
this->index_ + 1, e.what()));
|
this->index_, e.what()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,17 +223,68 @@ namespace scripting
|
|||||||
variadic_args args{};
|
variadic_args args{};
|
||||||
for (auto i = this->index_; i < static_cast<int>(this->values_.size()); i++)
|
for (auto i = this->index_; i < static_cast<int>(this->values_.size()); i++)
|
||||||
{
|
{
|
||||||
args.push_back(this->values_[i]);
|
args.push_back({this->values_, this->values_[i], i, true});
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
std::string to_string() const
|
||||||
script_value as() const
|
{
|
||||||
|
return this->value_.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string type_name() const
|
||||||
|
{
|
||||||
|
return this->value_.type_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
script_value get_raw() const
|
||||||
{
|
{
|
||||||
return this->value_;
|
return this->value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator variadic_args() const
|
||||||
|
{
|
||||||
|
variadic_args args{};
|
||||||
|
for (auto i = this->index_; i < static_cast<int>(this->values_.size()); i++)
|
||||||
|
{
|
||||||
|
args.push_back({this->values_, this->values_[i], i, true});
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <template<class, class> class C, class T, class ArrayType = array>
|
||||||
|
operator C<T, std::allocator<T>>() const
|
||||||
|
{
|
||||||
|
const auto container_type = get_c_typename<C<T, std::allocator<T>>>();
|
||||||
|
if (!this->value_.is<array>())
|
||||||
|
{
|
||||||
|
const auto type = get_typename(this->value_.get_raw());
|
||||||
|
|
||||||
|
throw std::runtime_error(utils::string::va("has type '%s' but should be '%s'",
|
||||||
|
type.data(),
|
||||||
|
container_type.data()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
C<T, std::allocator<T>> container{};
|
||||||
|
const auto array = this->value_.as<ArrayType>();
|
||||||
|
for (auto i = 0; i < array.size(); i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
container.push_back(array.get(i).as<T>());
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(utils::string::va("element %d of parameter %d of type '%s' %s",
|
||||||
|
i, this->index_, container_type.data(), e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
operator T() const
|
operator T() const
|
||||||
{
|
{
|
||||||
@ -240,6 +295,7 @@ namespace scripting
|
|||||||
arguments values_{};
|
arguments values_{};
|
||||||
script_value value_{};
|
script_value value_{};
|
||||||
int index_{};
|
int index_{};
|
||||||
|
bool exists_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class function_arguments
|
class function_arguments
|
||||||
@ -251,10 +307,10 @@ namespace scripting
|
|||||||
{
|
{
|
||||||
if (index >= static_cast<int>(values_.size()))
|
if (index >= static_cast<int>(values_.size()))
|
||||||
{
|
{
|
||||||
throw std::runtime_error(utils::string::va("parameter %d does not exist", index));
|
return {values_, {}, index, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {values_, values_[index], index};
|
return {values_, values_[index], index, true};
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
arguments values_{};
|
arguments values_{};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user