add gsc io funcs

This commit is contained in:
m 2022-09-12 15:51:23 -05:00
parent 81e91b939f
commit c2b2ce8e4c
5 changed files with 247 additions and 118 deletions

View File

@ -8,6 +8,7 @@
#include "command.hpp"
#include "console.hpp"
#include "game_console.hpp"
#include "gsc.hpp"
#include "fastfiles.hpp"
#include "filesystem.hpp"
#include "scheduler.hpp"
@ -607,6 +608,12 @@ namespace command
utils::hook::jump(SELECT_VALUE(0x3A7C80_b, 0x4E9F40_b), dvar_command_stub, true);
add_commands_generic();
gsc::function::add("executecommand", []()
{
const auto cmd = gsc::get_argument(0).as<std::string>();
command::execute(cmd, true);
});
}
private:

View File

@ -3,12 +3,10 @@
#include "console.hpp"
#include "fastfiles.hpp"
#include "gsc.hpp"
#include "filesystem.hpp"
#include "logfile.hpp"
#include "gsc.hpp"
#include "scripting.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include "game/scripting/functions.hpp"
@ -452,16 +450,6 @@ namespace gsc
}
}
scripting::script_value get_argument(int index)
{
if (index >= static_cast<int>(game::scr_VmPub->outparamcount))
{
return {};
}
return game::scr_VmPub->top[-index];
}
void execute_custom_function(builtin_function function)
{
auto error = false;
@ -551,18 +539,6 @@ namespace gsc
current_filename = filename;
scr_emit_function_hook.invoke<void>(filename, thread_name, code_pos);
}
void replace(std::string& str, const std::string& from, const std::string& to)
{
const auto start_pos = str.find(from);
if (start_pos == std::string::npos)
{
return;
}
str.replace(start_pos, from.length(), to);
}
}
game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/)
@ -606,6 +582,16 @@ namespace gsc
}
}
scripting::script_value get_argument(int index)
{
if (index >= static_cast<int>(game::scr_VmPub->outparamcount))
{
return {};
}
return game::scr_VmPub->top[-index];
}
namespace function
{
void add(const std::string& name, builtin_function function)
@ -715,94 +701,6 @@ namespace gsc
utils::hook::nop(SELECT_VALUE(0x3CBA4E_b, 0x512AAE_b), 2);
utils::hook::call(SELECT_VALUE(0x3CBA46_b, 0x512AA6_b), vm_call_builtin_method_stub);
function::add("print", []()
{
const auto num = game::Scr_GetNumParam();
std::string buffer{};
for (auto i = 0; i < num; i++)
{
const auto str = game::Scr_GetString(i);
buffer.append(str);
buffer.append("\t");
}
console::info("[SCRIPT] %s\n", buffer.data());
});
function::add("assert", []()
{
const auto expr = get_argument(0).as<int>();
if (!expr)
{
throw std::runtime_error("assert fail");
}
});
function::add("assertex", []()
{
const auto expr = get_argument(0).as<int>();
if (!expr)
{
const auto error = get_argument(1).as<std::string>();
throw std::runtime_error(error);
}
});
function::add("replacefunc", []()
{
const auto what = get_argument(0).get_raw();
const auto with = get_argument(1).get_raw();
if (what.type != game::SCRIPT_FUNCTION)
{
throw std::runtime_error("replaceFunc: parameter 1 must be a function");
return;
}
if (with.type != game::SCRIPT_FUNCTION)
{
throw std::runtime_error("replaceFunc: parameter 2 must be a function");
return;
}
logfile::set_gsc_hook(what.u.codePosValue, with.u.codePosValue);
});
function::add("toupper", []()
{
const auto string = get_argument(0).as<std::string>();
game::Scr_AddString(utils::string::to_upper(string).data());
});
function::add("logprint", []()
{
std::string buffer{};
const auto params = game::Scr_GetNumParam();
for (auto i = 0; i < params; i++)
{
const auto string = game::Scr_GetString(i);
buffer.append(string);
}
game::G_LogPrintf("%s", buffer.data());
});
function::add("va", []()
{
auto fmt = get_argument(0).as<std::string>();
const auto params = game::Scr_GetNumParam();
for (auto i = 1; i < params; i++)
{
const auto arg = get_argument(i).to_string();
replace(fmt, "%s", arg);
}
game::Scr_AddString(fmt.data());
});
scripting::on_shutdown([](int free_scripts)
{
if (free_scripts)

View File

@ -1,6 +1,6 @@
#pragma once
#include "game/game.hpp"
#include "game/scripting/script_value.hpp"
namespace gsc
{
@ -15,6 +15,8 @@ namespace gsc
void load_main_handles();
void load_init_handles();
scripting::script_value get_argument(int index);
namespace function
{
void add(const std::string& name, builtin_function function);

220
src/client/component/io.cpp Normal file
View File

@ -0,0 +1,220 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "console.hpp"
#include "gsc.hpp"
#include "logfile.hpp"
#include "scheduler.hpp"
#include "gsc.hpp"
#include <utils/hook.hpp>
#include <utils/http.hpp>
#include <utils/io.hpp>
namespace io
{
namespace
{
void replace(std::string& str, const std::string& from, const std::string& to)
{
const auto start_pos = str.find(from);
if (start_pos == std::string::npos)
{
return;
}
str.replace(start_pos, from.length(), to);
}
}
class component final : public component_interface
{
public:
void post_unpack() override
{
gsc::function::add("print", []()
{
const auto num = game::Scr_GetNumParam();
std::string buffer{};
for (auto i = 0; i < num; i++)
{
const auto str = game::Scr_GetString(i);
buffer.append(str);
buffer.append("\t");
}
#ifdef DEBUG
console::debug("[SCRIPT] %s\n", buffer.data());
#else
console::info("[SCRIPT] %s\n", buffer.data());
#endif
});
gsc::function::add("assert", []()
{
const auto expr = gsc::get_argument(0).as<int>();
if (!expr)
{
throw std::runtime_error("assert fail");
}
});
gsc::function::add("assertex", []()
{
const auto expr = gsc::get_argument(0).as<int>();
if (!expr)
{
const auto error = gsc::get_argument(1).as<std::string>();
throw std::runtime_error(error);
}
});
gsc::function::add("replacefunc", []()
{
const auto what = gsc::get_argument(0).get_raw();
const auto with = gsc::get_argument(1).get_raw();
if (what.type != game::SCRIPT_FUNCTION)
{
throw std::runtime_error("replaceFunc: parameter 1 must be a function");
return;
}
if (with.type != game::SCRIPT_FUNCTION)
{
throw std::runtime_error("replaceFunc: parameter 2 must be a function");
return;
}
logfile::set_gsc_hook(what.u.codePosValue, with.u.codePosValue);
});
gsc::function::add("toupper", []()
{
const auto string = gsc::get_argument(0).as<std::string>();
game::Scr_AddString(utils::string::to_upper(string).data());
});
gsc::function::add("logprint", []()
{
std::string buffer{};
const auto params = game::Scr_GetNumParam();
for (auto i = 0; i < params; i++)
{
const auto string = game::Scr_GetString(i);
buffer.append(string);
}
game::G_LogPrintf("%s", buffer.data());
});
gsc::function::add("va", []()
{
auto fmt = gsc::get_argument(0).as<std::string>();
const auto params = game::Scr_GetNumParam();
for (auto i = 1; i < params; i++)
{
const auto arg = gsc::get_argument(i).to_string();
replace(fmt, "%s", arg);
}
game::Scr_AddString(fmt.data());
});
gsc::function::add("fileexists", []()
{
const auto path = gsc::get_argument(0).as<std::string>();
game::Scr_AddBool(utils::io::file_exists(path));
});
gsc::function::add("writefile", []()
{
const auto path = gsc::get_argument(0).as<std::string>();
const auto data = gsc::get_argument(1).as<std::string>();
const auto params = game::Scr_GetNumParam();
auto append = false;
if (params > 2)
{
append = gsc::get_argument(2).as<bool>();
}
game::Scr_AddBool(utils::io::write_file(path, data, append));
});
gsc::function::add("readfile", []()
{
const auto path = gsc::get_argument(0).as<std::string>();
game::Scr_AddString(utils::io::read_file(path).data());
});
/*
gsc::function::add("filesize", []()
{
const auto path = gsc::get_argument(0).as<std::string>();
// return type is size_t, so we probably need to find a way to do that :P maybe just make it a string? lmao
game::Scr_AddInt(utils::io::file_size(path));
});
*/
gsc::function::add("createdirectory", []()
{
const auto path = gsc::get_argument(0).as<std::string>();
game::Scr_AddBool(utils::io::create_directory(path));
});
gsc::function::add("directoryexists", []()
{
const auto path = gsc::get_argument(0).as<std::string>();
game::Scr_AddBool(utils::io::directory_exists(path));
});
gsc::function::add("directoryisempty", []()
{
const auto path = gsc::get_argument(0).as<std::string>();
game::Scr_AddBool(utils::io::directory_is_empty(path));
});
/*
gsc::function::add("listfiles", []()
{
const auto path = gsc::get_argument(0).as<std::string>();
const auto files = utils::io::list_files(path);
scripting::array array{};
for (const auto& file : files)
{
array.push(file);
}
return array;
});
*/
gsc::function::add("copyfolder", []()
{
const auto source = gsc::get_argument(0).as<std::string>();
const auto target = gsc::get_argument(1).as<std::string>();
utils::io::copy_folder(source, target);
});
gsc::function::add("removefile", []()
{
const auto path = gsc::get_argument(0).as<std::string>();
game::Scr_AddBool(utils::io::remove_file(path));
});
}
};
}
REGISTER_COMPONENT(io::component)

View File

@ -152,6 +152,8 @@ namespace game
unsigned int paramcount)> VM_Execute{0x3C9E50, 0x510EB0};
WEAK symbol<void(const char* value)> Scr_AddString{0x3C7B20, 0x50EC50};
WEAK symbol<void(int value)> Scr_AddInt{0x3C7A40, 0x50EB70};
WEAK symbol<void(int value)> Scr_AddBool{0x3C77C0, 0x50E8F0};
WEAK symbol<void(unsigned int id, scr_string_t stringValue,
unsigned int paramcount)> Scr_NotifyId{0x3C92E0, 0x510340};
@ -191,10 +193,10 @@ namespace game
WEAK symbol<void(XZoneInfo* zoneInfo, unsigned int zoneCount, DBSyncMode syncMode)> DB_LoadXAssets{0x1F31E0, 0x397500};
WEAK symbol<bool(const char* zoneName)> DB_IsLocalized{0x1F23C0, 0x396790};
WEAK symbol<void(int clientNum, const char* menu,
int a3, int a4, unsigned int a5)> LUI_OpenMenu{0x3F20A0, 0x1E1210};
WEAK symbol<void(int clientNum, const char* menu, int a3,
hks::lua_State* a4)> LUI_LeaveMenuByName{0xF6D00, 0x26BE80};
WEAK symbol<void(int client_num, const char* menu,
int is_popup, int client_num, unsigned int is_exclusive)> LUI_OpenMenu{0x3F20A0, 0x1E1210};
WEAK symbol<void(int clientNum, const char* menu, int immediate,
hks::lua_State* state)> LUI_LeaveMenuByName{0xF6D00, 0x26BE80};
WEAK symbol<void()> LUI_EnterCriticalSection{0xF19A0, 0x2669B0};
WEAK symbol<void()> LUI_LeaveCriticalSection{0xF6C40, 0x26BDC0};