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 "loader/component_loader.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include "scripting.hpp" #include "scripting.hpp"
#include "command.hpp"
#include "game/scripting/event.hpp" #include "game/scripting/event.hpp"
#include "game/scripting/execution.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 class component final : public component_interface
{ {
public: public:
@ -276,6 +304,32 @@ namespace gsc
return {}; 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(0x56C8EB, call_builtin_stub);
utils::hook::jump(0x56CBDC, call_builtin_method_stub); utils::hook::jump(0x56CBDC, call_builtin_method_stub);
utils::hook::jump(0x56B726, vm_execute_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); 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 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 gsc_to_json(scripting::script_value value);
nlohmann::json entity_to_array(unsigned int id) nlohmann::json entity_to_array(unsigned int id)
@ -154,22 +127,22 @@ namespace json
return obj.get<std::string>(); return obj.get<std::string>();
case (nlohmann::detail::value_t::array): case (nlohmann::detail::value_t::array):
{ {
const auto arr = make_array(); const auto arr = gsc::make_array();
for (const auto& [key, value] : obj.items()) 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); return scripting::entity(arr);
} }
case (nlohmann::detail::value_t::object): case (nlohmann::detail::value_t::object):
{ {
const auto arr = make_array(); const auto arr = gsc::make_array();
for (const auto& [key, value] : obj.items()) 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); return scripting::entity(arr);

View File

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

View File

@ -140,6 +140,7 @@ namespace scripting
{ {
const auto id = entity.get_entity_id(); const auto id = entity.get_entity_id();
stack_isolation _;
for (auto i = arguments.rbegin(); i != arguments.rend(); ++i) for (auto i = arguments.rbegin(); i != arguments.rend(); ++i)
{ {
push_value(*i); push_value(*i);
@ -149,16 +150,9 @@ namespace scripting
const auto local_id = game::AllocThread(id); const auto local_id = game::AllocThread(id);
const auto result = game::VM_Execute(local_id, pos, arguments.size()); const auto result = game::VM_Execute(local_id, pos, arguments.size());
game::RemoveRefToObject(result);
const auto value = get_return_value(); return get_return_value();
game::RemoveRefToValue(game::scr_VmPub->top->type, game::scr_VmPub->top->u);
game::scr_VmPub->top->type = (game::scriptType_e)0;
--game::scr_VmPub->top;
--game::scr_VmPub->inparamcount;
return value;
} }
script_value call_script_function(const entity& entity, const std::string& filename, script_value call_script_function(const entity& entity, const std::string& filename,

View File

@ -17,6 +17,15 @@ namespace game
int flags; int flags;
}; };
struct CmdArgs
{
int nesting;
int localClientNum[8];
int controllerIndex[8];
int argc[8];
const char** argv[8];
};
struct msg_t struct msg_t
{ {
int overflowed; int overflowed;

View File

@ -18,8 +18,9 @@ namespace game
WEAK symbol<const char*(int index)> ConcatArgs{0x502150}; WEAK symbol<const char*(int index)> ConcatArgs{0x502150};
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x545680}; WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x545680};
WEAK symbol<void(const char* cmdName, void(), cmd_function_t* allocedCmd)> Cmd_AddCommandInternal{0x0}; WEAK symbol<void(const char* cmdName, void(), cmd_function_t* allocedCmd)> Cmd_AddCommandInternal{0x545DF0};
WEAK symbol<const char*(int index)> Cmd_Argv{0x0}; WEAK symbol<void(const char* cmdName)> Cmd_RemoveCommand{0x545E20};
WEAK symbol<const char*(int index)> Cmd_Argv{0x467600};
WEAK symbol<const dvar_t*(const char*)> Dvar_FindVar{0x5BDCC0}; WEAK symbol<const dvar_t*(const char*)> Dvar_FindVar{0x5BDCC0};
@ -60,6 +61,8 @@ namespace game
// Variables // Variables
WEAK symbol<CmdArgs> cmd_args{0x1C978D0};
WEAK symbol<int> g_script_error_level{0x20B21FC}; WEAK symbol<int> g_script_error_level{0x20B21FC};
WEAK symbol<jmp_buf> g_script_error{0x20B4218}; WEAK symbol<jmp_buf> g_script_error{0x20B4218};

View File

@ -54,14 +54,14 @@ namespace utils
return this->pool_.empty(); return this->pool_.empty();
} }
/*char* memory::allocator::duplicate_string(const std::string& string) char* memory::allocator::duplicate_string(const std::string& string)
{ {
std::lock_guard _(this->mutex_); std::lock_guard _(this->mutex_);
const auto data = memory::duplicate_string(string); const auto data = memory::duplicate_string(string);
this->pool_.push_back(data); this->pool_.push_back(data);
return data; return data;
}*/ }
void* memory::allocate(const size_t length) void* memory::allocate(const size_t length)
{ {
@ -70,12 +70,12 @@ namespace utils
return data; return data;
} }
/*char* memory::duplicate_string(const std::string& string) char* memory::duplicate_string(const std::string& string)
{ {
const auto new_string = allocate_array<char>(string.size() + 1); const auto new_string = allocate_array<char>(string.size() + 1);
std::memcpy(new_string, string.data(), string.size()); std::memcpy(new_string, string.data(), string.size());
return new_string; return new_string;
}*/ }
void memory::free(void* data) void memory::free(void* data)
{ {

View File

@ -34,7 +34,7 @@ namespace utils
bool empty() const; bool empty() const;
//char* duplicate_string(const std::string& string); char* duplicate_string(const std::string& string);
private: private:
std::mutex mutex_; std::mutex mutex_;
@ -55,7 +55,7 @@ namespace utils
return static_cast<T*>(allocate(count * sizeof(T))); return static_cast<T*>(allocate(count * sizeof(T)));
} }
//static char* duplicate_string(const std::string& string); static char* duplicate_string(const std::string& string);
static void free(void* data); static void free(void* data);
static void free(const void* data); static void free(const void* data);