Add addCommand function

This commit is contained in:
Federico Cecchetto
2021-06-17 16:31:35 +02:00
parent 4185224323
commit ee109d622a
11 changed files with 219 additions and 52 deletions

104
src/component/command.cpp Normal file
View File

@ -0,0 +1,104 @@
#include <stdinc.hpp>
#include "loader/component_loader.hpp"
#include "game/scripting/entity.hpp"
#include "game/scripting/execution.hpp"
#include "command.hpp"
namespace command
{
std::unordered_map<std::string, std::function<void(params&)>> handlers;
void main_handler()
{
params params = {};
const auto command = utils::string::to_lower(params[0]);
if (handlers.find(command) != handlers.end())
{
handlers[command](params);
}
}
params::params()
: nesting_(game::cmd_args->nesting)
{
}
int params::size() const
{
return game::cmd_args->argc[this->nesting_];
}
const char* params::get(const int index) const
{
if (index >= this->size())
{
return "";
}
return game::cmd_args->argv[this->nesting_][index];
}
std::string params::join(const int index) const
{
std::string result = {};
for (auto i = index; i < this->size(); i++)
{
if (i > index) result.append(" ");
result.append(this->get(i));
}
return result;
}
void add_raw(const char* name, void (*callback)())
{
game::Cmd_AddCommandInternal(name, callback, utils::memory::get_allocator()->allocate<game::cmd_function_t>());
}
void add(const char* name, const std::function<void(const params&)>& callback)
{
const auto command = utils::string::to_lower(name);
if (handlers.find(command) == handlers.end())
{
add_raw(name, main_handler);
}
handlers[command] = callback;
}
std::vector<std::string> script_commands;
utils::memory::allocator allocator;
void add_script_command(const std::string& name, const std::function<void(const params&)>& callback)
{
script_commands.push_back(name);
const auto _name = allocator.duplicate_string(name);
add(_name, callback);
}
void clear_script_commands()
{
for (const auto& name : script_commands)
{
handlers.erase(name);
game::Cmd_RemoveCommand(name.data());
}
allocator.clear();
script_commands.clear();
}
class component final : public component_interface
{
public:
void post_unpack() override
{
}
};
}
REGISTER_COMPONENT(command::component)

28
src/component/command.hpp Normal file
View File

@ -0,0 +1,28 @@
#pragma once
namespace command
{
class params
{
public:
params();
int size() const;
const char* get(int index) const;
std::string join(int index) const;
const char* operator[](const int index) const
{
return this->get(index);
}
private:
int nesting_;
};
void add_raw(const char* name, void (*callback)());
void add(const char* name, const std::function<void(const params&)>& callback);
void add_script_command(const std::string& name, const std::function<void(const params&)>& callback);
void clear_script_commands();
}

View File

@ -2,6 +2,7 @@
#include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "scripting.hpp"
#include "command.hpp"
#include "game/scripting/event.hpp"
#include "game/scripting/execution.hpp"
@ -250,6 +251,33 @@ namespace gsc
}
}
unsigned int make_array()
{
unsigned int index = 0;
const auto variable = game::AllocVariable(&index);
variable->w.type = game::SCRIPT_ARRAY;
variable->u.f.prev = 0;
variable->u.f.next = 0;
return index;
}
void add_array_key_value(unsigned int parent_id, const std::string& _key, const scripting::script_value& value)
{
const auto key = game::SL_GetString(_key.data(), 0);
scripting::push_value(scripting::entity(parent_id));
scripting::push_value(value);
game::Scr_AddArrayStringIndexed(key);
}
void add_array_value(unsigned int parent_id, const scripting::script_value& value)
{
scripting::push_value(scripting::entity(parent_id));
scripting::push_value(value);
game::Scr_AddArray();
}
class component final : public component_interface
{
public:
@ -276,6 +304,32 @@ namespace gsc
return {};
});
function::add("addcommand", [](function_args args) -> scripting::script_value
{
const auto name = args[0].as<std::string>();
const auto function = args[1].get_raw();
if (function.type != game::SCRIPT_FUNCTION)
{
throw std::runtime_error("Invalid type");
}
const auto pos = function.u.codePosValue;
command::add_script_command(name, [pos](const command::params& params)
{
const auto array = make_array();
for (auto i = 0; i < params.size(); i++)
{
add_array_value(array, params[i]);
}
const auto entity = scripting::entity(array);
scripting::exec_ent_thread(*game::levelEntityId, pos, {entity});
});
return {};
});
utils::hook::jump(0x56C8EB, call_builtin_stub);
utils::hook::jump(0x56CBDC, call_builtin_method_stub);
utils::hook::jump(0x56B726, vm_execute_stub);

View File

@ -19,4 +19,8 @@ namespace gsc
{
void add(const std::string& name, const script_method& func);
}
unsigned int make_array();
void add_array_key_value(unsigned int parent_id, const std::string& _key, const scripting::script_value& value);
void add_array_value(unsigned int parent_id, const scripting::script_value& value);
}

View File

@ -15,33 +15,6 @@ namespace json
{
namespace
{
unsigned int make_array()
{
unsigned int index = 0;
const auto variable = game::AllocVariable(&index);
variable->w.type = game::SCRIPT_ARRAY;
variable->u.f.prev = 0;
variable->u.f.next = 0;
return index;
}
void add_array_key_value(unsigned int parent_id, const std::string& _key, const scripting::script_value& value)
{
const auto key = game::SL_GetString(_key.data(), 0);
scripting::push_value(scripting::entity(parent_id));
scripting::push_value(value);
game::Scr_AddArrayStringIndexed(key);
}
void add_array_value(unsigned int parent_id, const scripting::script_value& value)
{
scripting::push_value(scripting::entity(parent_id));
scripting::push_value(value);
game::Scr_AddArray();
}
nlohmann::json gsc_to_json(scripting::script_value value);
nlohmann::json entity_to_array(unsigned int id)
@ -154,22 +127,22 @@ namespace json
return obj.get<std::string>();
case (nlohmann::detail::value_t::array):
{
const auto arr = make_array();
const auto arr = gsc::make_array();
for (const auto& [key, value] : obj.items())
{
add_array_value(arr, json_to_gsc(value));
gsc::add_array_value(arr, json_to_gsc(value));
}
return scripting::entity(arr);
}
case (nlohmann::detail::value_t::object):
{
const auto arr = make_array();
const auto arr = gsc::make_array();
for (const auto& [key, value] : obj.items())
{
add_array_key_value(arr, key, json_to_gsc(value));
gsc::add_array_key_value(arr, key, json_to_gsc(value));
}
return scripting::entity(arr);

View File

@ -2,6 +2,7 @@
#include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "command.hpp"
#include "game/scripting/event.hpp"
#include "game/scripting/execution.hpp"
@ -69,8 +70,8 @@ namespace scripting
void g_shutdown_game_stub(const int free_scripts)
{
command::clear_script_commands();
replaced_functions.clear();
g_shutdown_game_hook.invoke<void>(free_scripts);
}
@ -133,9 +134,6 @@ namespace scripting
g_shutdown_game_hook.create(0x50C100, g_shutdown_game_stub);
scr_add_class_field_hook.create(0x567CD0, scr_add_class_field_stub);
//vm_notify_hook.create(0x569720, vm_notify_stub);
//scr_emit_function_hook.create(0x561400, scr_emit_function_stub);
}
};
}