iw5-mod/src/module/scripting.cpp

196 lines
4.2 KiB
C++
Raw Normal View History

2019-01-13 05:16:19 -05:00
#include <std_include.hpp>
2019-01-13 15:28:05 -05:00
#include "notification.hpp"
#include "utils/io.hpp"
#include "utils/string.hpp"
2019-01-13 05:16:19 -05:00
2019-01-13 13:03:46 -05:00
utils::hook scripting::start_hook_;
utils::hook scripting::stop_hook_;
std::mutex scripting::mutex_;
std::vector<std::function<void()>> scripting::start_callbacks_;
std::vector<std::function<void()>> scripting::stop_callbacks_;
scripting::variable::variable(game::native::VariableValue value) : value_(value)
2019-01-13 05:16:19 -05:00
{
2019-01-13 15:53:52 -05:00
game::native::AddRefToValue(&value);
2019-01-13 13:03:46 -05:00
}
scripting::variable::~variable()
{
2019-01-13 15:53:52 -05:00
game::native::RemoveRefToValue(this->value_.type, this->value_.u);
2019-01-13 13:03:46 -05:00
}
scripting::variable::operator game::native::VariableValue() const
{
return this->value_;
}
2019-01-13 15:28:05 -05:00
void scripting::post_start()
{
on_start(std::bind(&scripting::initialize, this));
on_stop([this]()
{
this->chai_ = {};
});
}
2019-01-13 13:03:46 -05:00
void scripting::post_load()
{
start_hook_.initialize(SELECT_VALUE(0x50C575, 0x50D4F2, 0x48A026), []()
2019-01-13 05:16:19 -05:00
{
2019-01-13 13:03:46 -05:00
start_execution();
static_cast<void(*)()>(start_hook_.get_original())();
}, HOOK_CALL)->install()->quick();
stop_hook_.initialize(SELECT_VALUE(0x528B04, 0x569E46, 0x4F03FA), []()
{
stop_execution();
static_cast<void(*)()>(stop_hook_.get_original())();
}, HOOK_CALL)->install()->quick();
2019-01-13 15:28:05 -05:00
}
void scripting::pre_destroy()
{
this->chai_ = {};
start_callbacks_.clear();
stop_callbacks_.clear();
}
2019-01-13 13:03:46 -05:00
2019-01-13 15:28:05 -05:00
void scripting::initialize()
{
this->chai_ = std::make_unique<chaiscript::ChaiScript>();
this->chai_->add(chaiscript::fun([](const std::string& string)
2019-01-13 13:03:46 -05:00
{
2019-01-13 15:28:05 -05:00
printf("%s\n", string.data());
}), "print");
2019-01-13 13:03:46 -05:00
2019-01-13 15:28:05 -05:00
this->chai_->add(chaiscript::fun(
[this](const std::function<void(const std::string&,
const std::vector<chaiscript::Boxed_Value>&)>& callback)
{
std::lock_guard _(mutex_);
this->callbacks_.push_back(callback);
}), "onNotify");
this->load_scripts();
notification::listen([this](notification::event* event)
2019-01-13 13:03:46 -05:00
{
2019-01-13 15:53:52 -05:00
std::vector<chaiscript::Boxed_Value> arguments;
for (const auto& argument : event->arguments)
{
arguments.push_back(make_boxed(argument));
}
2019-01-13 15:28:05 -05:00
decltype(this->callbacks_) copy;
{
std::lock_guard _(mutex_);
copy = this->callbacks_;
}
for (const auto& callback : copy)
{
2019-01-13 15:53:52 -05:00
try
{
callback(event->name, arguments);
}
2019-01-13 16:59:01 -05:00
catch (chaiscript::exception::eval_error &e)
{
printf("Failed to handle event: %s\n", e.pretty_print().data());
}
2019-01-13 15:53:52 -05:00
catch (std::exception& e)
{
printf("Failed to handle event: %s\n", e.what());
}
2019-01-13 15:28:05 -05:00
}
2019-01-13 13:03:46 -05:00
});
}
2019-01-13 15:28:05 -05:00
void scripting::load_scripts() const
2019-01-13 13:03:46 -05:00
{
2019-01-13 15:28:05 -05:00
const auto scripts = utils::io::list_files("open-iw5/scripts/");
for (const auto& script : scripts)
{
if (script.substr(script.find_last_of('.') + 1) == "chai")
{
2019-01-13 15:53:52 -05:00
try
{
this->chai_->eval_file(script);
}
2019-01-13 16:59:01 -05:00
catch (chaiscript::exception::eval_error &e)
{
printf("Failed to load script %s: %s\n", script.data(), e.pretty_print().data());
}
2019-01-13 15:53:52 -05:00
catch (std::exception& e)
{
printf("Failed to load script %s: %s\n", script.data(), e.what());
}
2019-01-13 15:28:05 -05:00
}
}
2019-01-13 13:03:46 -05:00
}
2019-01-13 15:53:52 -05:00
chaiscript::Boxed_Value scripting::make_boxed(const game::native::VariableValue value)
{
if (value.type == game::native::SCRIPT_STRING)
{
const std::string string = game::native::SL_ConvertToString(value.u.stringValue);
return chaiscript::var(string);
}
else if (value.type == game::native::SCRIPT_FLOAT)
{
return chaiscript::var(value.u.floatValue);
}
else if (value.type == game::native::SCRIPT_INTEGER)
{
return chaiscript::var(value.u.intValue);
}
return {};
}
2019-01-13 13:03:46 -05:00
void scripting::on_start(const std::function<void()>& callback)
{
std::lock_guard _(mutex_);
start_callbacks_.push_back(callback);
}
void scripting::on_stop(const std::function<void()>& callback)
{
std::lock_guard _(mutex_);
stop_callbacks_.push_back(callback);
}
void scripting::start_execution()
{
2019-01-13 15:28:05 -05:00
decltype(start_callbacks_) copy;
2019-01-13 13:03:46 -05:00
{
std::lock_guard _(mutex_);
copy = start_callbacks_;
}
for (const auto& callback : copy)
{
callback();
2019-01-13 05:16:19 -05:00
}
2019-01-13 13:03:46 -05:00
}
void scripting::stop_execution()
{
2019-01-13 15:28:05 -05:00
decltype(stop_callbacks_) copy;
2019-01-13 13:03:46 -05:00
{
std::lock_guard _(mutex_);
copy = stop_callbacks_;
2019-01-13 15:28:05 -05:00
std::reverse(copy.begin(), copy.end());
2019-01-13 13:03:46 -05:00
}
2019-01-13 06:07:19 -05:00
2019-01-13 13:03:46 -05:00
for (const auto& callback : copy)
{
callback();
}
}
2019-01-13 06:07:19 -05:00
2019-01-13 05:16:19 -05:00
REGISTER_MODULE(scripting)