Merge pull request #504 from XLabsProject/develop

Release v2.0.8
This commit is contained in:
Maurice Heumann 2022-11-01 11:39:59 +01:00 committed by GitHub
commit 34c4f99c4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 1069 additions and 1963 deletions

View File

@ -35,10 +35,9 @@ jobs:
lfs: false lfs: false
- name: Add msbuild to PATH - name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.1 uses: microsoft/setup-msbuild@v1.1.3
- name: Generate project files - name: Generate project files
#run: tools/premake5 vs2022 --ci-build
run: tools/premake5 vs2022 run: tools/premake5 vs2022
- name: Set up problem matching - name: Set up problem matching
@ -48,7 +47,7 @@ jobs:
run: msbuild /m /v:minimal /p:Configuration=${{matrix.configuration}} /p:Platform=x64 build/s1x.sln run: msbuild /m /v:minimal /p:Configuration=${{matrix.configuration}} /p:Platform=x64 build/s1x.sln
- name: Upload ${{matrix.configuration}} binaries - name: Upload ${{matrix.configuration}} binaries
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3.1.0
with: with:
name: ${{matrix.configuration}} binaries name: ${{matrix.configuration}} binaries
path: | path: |
@ -56,7 +55,7 @@ jobs:
build/bin/x64/${{matrix.configuration}}/s1x.pdb build/bin/x64/${{matrix.configuration}}/s1x.pdb
- name: Upload ${{matrix.configuration}} data artifacts - name: Upload ${{matrix.configuration}} data artifacts
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v3.1.0
with: with:
name: ${{matrix.configuration}} data artifacts name: ${{matrix.configuration}} data artifacts
path: | path: |
@ -77,12 +76,12 @@ jobs:
run: echo "XLABS_MASTER_PATH=${{ secrets.XLABS_MASTER_SSH_PATH_DEV }}" >> $GITHUB_ENV run: echo "XLABS_MASTER_PATH=${{ secrets.XLABS_MASTER_SSH_PATH_DEV }}" >> $GITHUB_ENV
- name: Download Release binaries - name: Download Release binaries
uses: actions/download-artifact@v2 uses: actions/download-artifact@v3
with: with:
name: Release binaries name: Release binaries
- name: Download Release data artifacts - name: Download Release data artifacts
uses: actions/download-artifact@v2 uses: actions/download-artifact@v3
with: with:
name: Release data artifacts name: Release data artifacts
path: data path: data

1
.gitmodules vendored
View File

@ -47,3 +47,4 @@
[submodule "deps/gsc-tool"] [submodule "deps/gsc-tool"]
path = deps/gsc-tool path = deps/gsc-tool
url = https://github.com/xensik/gsc-tool.git url = https://github.com/xensik/gsc-tool.git
branch = xlabs

2
deps/GSL vendored

@ -1 +1 @@
Subproject commit 991fa6682e819590c695f00c6b880548e55fa914 Subproject commit 9c4212aca46fb4fe5bda2921c2269d35d6d1860f

2
deps/asmjit vendored

@ -1 +1 @@
Subproject commit 15a603661871b86c048e697f0e6cd17374dcecc0 Subproject commit 8f2c237b8315a7d662e0e67d06807296a7bbe5ab

2
deps/gsc-tool vendored

@ -1 +1 @@
Subproject commit e5d6196da194457ba01cc94674a83da802b769ca Subproject commit 842f168a67878f18ea6a42b9d3ce56ff9fafff0d

2
deps/libtommath vendored

@ -1 +1 @@
Subproject commit 96f9edf9aaf145c6ecf5225eea3f5e86a0f26935 Subproject commit 03de03dee753442d4b23166982514639c4ccbc39

2
deps/lua vendored

@ -1 +1 @@
Subproject commit 26be27459b11feabed52cf40aaa76f86c7edc977 Subproject commit c954db39241a8b21d7b32b42b87a066b4708f969

View File

@ -6,6 +6,7 @@
#include "auth.hpp" #include "auth.hpp"
#include "command.hpp" #include "command.hpp"
#include "network.hpp" #include "network.hpp"
#include "console.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
@ -219,9 +220,9 @@ namespace auth
utils::hook::call(0x140208C54, send_connect_data_stub); utils::hook::call(0x140208C54, send_connect_data_stub);
} }
command::add("guid", []() command::add("guid", []
{ {
printf("Your guid: %llX\n", steam::SteamUser()->GetSteamID().bits); console::info("Your guid: %llX\n", steam::SteamUser()->GetSteamID().bits);
}); });
} }
}; };

View File

@ -4,6 +4,7 @@
#include "game/scripting/execution.hpp" #include "game/scripting/execution.hpp"
#include "command.hpp" #include "command.hpp"
#include "console.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include "party.hpp" #include "party.hpp"
#include "network.hpp" #include "network.hpp"
@ -93,7 +94,7 @@ namespace bots
game::netadr_s master{}; game::netadr_s master{};
if (server_list::get_master_server(master)) if (server_list::get_master_server(master))
{ {
printf("Getting bots...\n"); console::info("Getting bots...\n");
network::send(master, "getbots"); network::send(master, "getbots");
} }
} }

View File

@ -10,6 +10,7 @@
#include "console.hpp" #include "console.hpp"
#include "game_console.hpp" #include "game_console.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include "fastfiles.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
@ -20,6 +21,8 @@ namespace command
{ {
namespace namespace
{ {
constexpr auto CMD_MAX_NESTING = 8;
utils::hook::detour client_command_hook; utils::hook::detour client_command_hook;
std::unordered_map<std::string, std::function<void(params&)>> handlers; std::unordered_map<std::string, std::function<void(params&)>> handlers;
@ -30,9 +33,9 @@ namespace command
params params = {}; params params = {};
const auto command = utils::string::to_lower(params[0]); const auto command = utils::string::to_lower(params[0]);
if (handlers.find(command) != handlers.end()) if (const auto itr = handlers.find(command); itr != handlers.end())
{ {
handlers[command](params); itr->second(params);
} }
} }
@ -47,9 +50,9 @@ namespace command
params_sv params = {}; params_sv params = {};
const auto command = utils::string::to_lower(params[0]); const auto command = utils::string::to_lower(params[0]);
if (const auto got = handlers_sv.find(command); got != handlers_sv.end()) if (const auto itr = handlers_sv.find(command); itr != handlers_sv.end())
{ {
got->second(&game::mp::g_entities[client_num], params); itr->second(&game::mp::g_entities[client_num], params);
} }
client_command_hook.invoke<void>(client_num); client_command_hook.invoke<void>(client_num);
@ -130,6 +133,7 @@ namespace command
params::params() params::params()
: nesting_(game::cmd_args->nesting) : nesting_(game::cmd_args->nesting)
{ {
assert(this->nesting_ < CMD_MAX_NESTING);
} }
int params::size() const int params::size() const
@ -162,6 +166,7 @@ namespace command
params_sv::params_sv() params_sv::params_sv()
: nesting_(game::sv_cmd_args->nesting) : nesting_(game::sv_cmd_args->nesting)
{ {
assert(this->nesting_ < CMD_MAX_NESTING);
} }
int params_sv::size() const int params_sv::size() const
@ -200,8 +205,10 @@ namespace command
{ {
const auto command = utils::string::to_lower(name); const auto command = utils::string::to_lower(name);
if (handlers.find(command) == handlers.end()) if (!handlers.contains(command))
{
add_raw(name, main_handler); add_raw(name, main_handler);
}
handlers[command] = callback; handlers[command] = callback;
} }
@ -214,15 +221,17 @@ namespace command
}); });
} }
void add_sv(const char* name, std::function<void(game::mp::gentity_s*, const params_sv&)> callback) void add_sv(const char* name, const std::function<void(game::mp::gentity_s*, const params_sv&)>& callback)
{ {
// doing this so the sv command would show up in the console // doing this so the sv command would show up in the console
add_raw(name, nullptr); add_raw(name, nullptr);
const auto command = utils::string::to_lower(name); const auto command = utils::string::to_lower(name);
if (handlers_sv.find(command) == handlers_sv.end()) if (!handlers_sv.contains(command))
handlers_sv[command] = std::move(callback); {
handlers_sv[command] = callback;
}
} }
bool cheats_ok(const game::mp::gentity_s* ent) bool cheats_ok(const game::mp::gentity_s* ent)
@ -258,15 +267,6 @@ namespace command
} }
} }
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool includeOverride)
{
game::DB_EnumXAssets_Internal(type, static_cast<void(*)(game::XAssetHeader, void*)>([](game::XAssetHeader header, void* data)
{
const auto& cb = *static_cast<const std::function<void(game::XAssetHeader)>*>(data);
cb(header);
}), &callback, includeOverride);
}
class component final : public component_interface class component final : public component_interface
{ {
public: public:
@ -407,7 +407,7 @@ namespace command
console::info("Listing assets in pool %s\n", game::g_assetNames[type]); console::info("Listing assets in pool %s\n", game::g_assetNames[type]);
const std::string filter = params.get(2); const std::string filter = params.get(2);
enum_assets(type, [type, filter](const game::XAssetHeader header) fastfiles::enum_assets(type, [type, filter](const game::XAssetHeader header)
{ {
const auto asset = game::XAsset{ type, header }; const auto asset = game::XAsset{ type, header };
const auto* const asset_name = game::DB_GetXAssetName(&asset); const auto* const asset_name = game::DB_GetXAssetName(&asset);

View File

@ -44,7 +44,7 @@ namespace command
void add(const char* name, const std::function<void(const params&)>& callback); void add(const char* name, const std::function<void(const params&)>& callback);
void add(const char* name, const std::function<void()>& callback); void add(const char* name, const std::function<void()>& callback);
void add_sv(const char* name, std::function<void(game::mp::gentity_s*, const params_sv&)> callback); void add_sv(const char* name, const std::function<void(game::mp::gentity_s*, const params_sv&)>& callback);
void execute(std::string command, bool sync = false); void execute(std::string command, bool sync = false);
} }

View File

@ -1,9 +1,10 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "console.hpp"
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "game/game.hpp" #include "game/game.hpp"
#include "command.hpp"
#include "command.hpp"
#include "console.hpp"
#include "game_console.hpp"
#include "rcon.hpp" #include "rcon.hpp"
#include <utils/thread.hpp> #include <utils/thread.hpp>
@ -11,11 +12,6 @@
#include <utils/concurrency.hpp> #include <utils/concurrency.hpp>
#include <utils/hook.hpp> #include <utils/hook.hpp>
namespace game_console
{
void print(int type, const std::string& data);
}
namespace console namespace console
{ {
namespace namespace
@ -40,7 +36,7 @@ namespace console
{ {
static thread_local char buffer[0x1000]; static thread_local char buffer[0x1000];
const auto count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); const auto count = vsnprintf_s(buffer, _TRUNCATE, message, *ap);
if (count < 0) return {}; if (count < 0) return {};
return {buffer, static_cast<size_t>(count)}; return {buffer, static_cast<size_t>(count)};
@ -113,7 +109,7 @@ namespace console
messages.access([&](message_queue& msgs) messages.access([&](message_queue& msgs)
{ {
msgs = {}; msgs = std::queue<std::string>();
}); });
} }
@ -190,7 +186,7 @@ namespace console
messages.access([&](message_queue& msgs) messages.access([&](message_queue& msgs)
{ {
message_queue_copy = std::move(msgs); message_queue_copy = std::move(msgs);
msgs = {}; msgs = std::queue<std::string>();
}); });
} }

View File

@ -1,10 +1,12 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "console.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include "server_list.hpp" #include "server_list.hpp"
#include "network.hpp" #include "network.hpp"
#include "command.hpp" #include "command.hpp"
#include "game/game.hpp"
#include "dvars.hpp" #include "dvars.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
@ -78,12 +80,11 @@ namespace dedicated
return console_command_queue; return console_command_queue;
} }
void execute_console_command(const int client, const char* command) void execute_console_command([[maybe_unused]] const int local_client_num, const char* command)
{ {
if (game::Live_SyncOnlineDataFlags(0) == 0) if (game::Live_SyncOnlineDataFlags(0) == 0)
{ {
game::Cbuf_AddText(client, command); command::execute(command);
game::Cbuf_AddText(client, "\n");
} }
else else
{ {
@ -145,7 +146,7 @@ namespace dedicated
va_end(ap); va_end(ap);
scheduler::once([]() scheduler::once([]
{ {
command::execute("map_rotate"); command::execute("map_rotate");
}, scheduler::main, 3s); }, scheduler::main, 3s);
@ -285,7 +286,7 @@ namespace dedicated
{ {
if (game::Live_SyncOnlineDataFlags(0) == 32 && game::Sys_IsDatabaseReady2()) if (game::Live_SyncOnlineDataFlags(0) == 32 && game::Sys_IsDatabaseReady2())
{ {
scheduler::once([]() scheduler::once([]
{ {
command::execute("xstartprivateparty", true); command::execute("xstartprivateparty", true);
command::execute("disconnect", true); // 32 -> 0 command::execute("disconnect", true); // 32 -> 0
@ -296,13 +297,13 @@ namespace dedicated
return scheduler::cond_continue; return scheduler::cond_continue;
}, scheduler::pipeline::main, 1s); }, scheduler::pipeline::main, 1s);
scheduler::on_game_initialized([]() scheduler::on_game_initialized([]
{ {
initialize(); initialize();
printf("==================================\n"); console::info("==================================\n");
printf("Server started!\n"); console::info("Server started!\n");
printf("==================================\n"); console::info("==================================\n");
// remove disconnect command // remove disconnect command
game::Cmd_RemoveCommand(reinterpret_cast<const char*>(751)); game::Cmd_RemoveCommand(reinterpret_cast<const char*>(751));

View File

@ -353,7 +353,7 @@ namespace demonware
va_list ap; va_list ap;
va_start(ap, msg); va_start(ap, msg);
vsnprintf_s(buffer, sizeof(buffer), _TRUNCATE, msg, ap); vsnprintf_s(buffer, _TRUNCATE, msg, ap);
printf("%s: %s\n", function, buffer); printf("%s: %s\n", function, buffer);
va_end(ap); va_end(ap);

View File

@ -5,7 +5,6 @@
#include "game/dvars.hpp" #include "game/dvars.hpp"
#include "console.hpp" #include "console.hpp"
#include "scheduler.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp> #include <utils/string.hpp>
@ -177,17 +176,14 @@ namespace dvar_cheats
utils::hook::call(0x1401BB782, cg_set_client_dvar_from_server); utils::hook::call(0x1401BB782, cg_set_client_dvar_from_server);
// check for dvars being sent as string before parsing ids // check for dvars being sent as string before parsing ids
scheduler::once([]()
{
#ifdef _DEBUG #ifdef _DEBUG
constexpr auto value = true; constexpr auto value = true;
#else #else
constexpr auto value = false; constexpr auto value = false;
#endif #endif
dvars::sv_cheats = game::Dvar_RegisterBool("sv_cheats", value, game::DvarFlags::DVAR_FLAG_REPLICATED, dvars::sv_cheats = game::Dvar_RegisterBool("sv_cheats", value, game::DVAR_FLAG_REPLICATED,
"Allow cheat commands and dvars on this server"); "Allow cheat commands and dvars on this server");
}, scheduler::pipeline::main);
} }
}; };
} }

View File

@ -53,9 +53,15 @@ namespace filesystem
custom_path_registered = false; custom_path_registered = false;
register_path(get_binary_directory() + "\\data"); register_path(get_binary_directory() + "\\data");
register_path(".");
register_path("s1x"); register_path("s1x");
// game's search paths
register_path("devraw");
register_path("devraw_shared");
register_path("raw_shared");
register_path("raw");
register_path("main");
game::FS_Startup(gamename); game::FS_Startup(gamename);
} }

View File

@ -365,7 +365,7 @@ namespace game_console
void print_internal(const char* fmt, ...) void print_internal(const char* fmt, ...)
{ {
char va_buffer[0x200] = {0}; char va_buffer[0x200]{};
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);

View File

@ -2,6 +2,8 @@
namespace game_console namespace game_console
{ {
void print(int type, const std::string& data);
bool console_char_event(int local_client_num, int key); bool console_char_event(int local_client_num, int key);
bool console_key_event(int local_client_num, int key, int down); bool console_key_event(int local_client_num, int key, int down);

View File

@ -0,0 +1,116 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include "scheduler.hpp"
#include "scripting.hpp"
#include "console.hpp"
#include "game_log.hpp"
#include "gsc/script_extension.hpp"
#include <utils/hook.hpp>
#include <utils/io.hpp>
#include <utils/string.hpp>
namespace game_log
{
namespace
{
void gscr_log_print()
{
char buf[1024]{};
std::size_t out_chars = 0;
for (auto i = 0u; i < game::Scr_GetNumParam(); ++i)
{
const auto* value = game::Scr_GetString(i);
const auto len = std::strlen(value);
out_chars += len;
if (out_chars >= sizeof(buf))
{
break;
}
strncat_s(buf, value, _TRUNCATE);
}
g_log_printf("%s", buf);
}
}
void g_log_printf(const char* fmt, ...)
{
const auto* log = dvars::g_log->current.string;
if (*log == '\0')
{
return;
}
char buffer[0x400]{};
va_list ap;
va_start(ap, fmt);
vsprintf_s(buffer, fmt, ap);
va_end(ap);
const auto time = *game::level_time / 1000;
utils::io::write_file(log, utils::string::va("%3i:%i%i %s",
time / 60,
time % 60 / 10,
time % 60 % 10,
buffer
), true);
}
class component final : public component_interface
{
public:
void post_load() override
{
if (game::environment::is_sp())
{
return;
}
gsc::override_function("logprint", &gscr_log_print);
scheduler::once([]
{
dvars::g_log = game::Dvar_RegisterString("g_log", "logs/games_mp.log", game::DVAR_FLAG_NONE, "Log file name");
}, scheduler::pipeline::main);
scripting::on_init([]
{
console::info("------- Game Initialization -------\n");
console::info("gamename: S1\n");
console::info("gamedate: " __DATE__ "\n");
const auto* log = dvars::g_log->current.string;
if (*log == '\0')
{
console::info("Not logging to disk.\n");
return;
}
console::info("Logging to disk: '%s'.\n", log);
g_log_printf("------------------------------------------------------------\n");
g_log_printf("InitGame\n");
});
scripting::on_shutdown([](int free_scripts)
{
console::info("==== ShutdownGame (%d) ====\n", free_scripts);
g_log_printf("ShutdownGame:\n");
g_log_printf("------------------------------------------------------------\n");
});
}
};
}
REGISTER_COMPONENT(game_log::component)

View File

@ -0,0 +1,6 @@
#pragma once
namespace game_log
{
void g_log_printf(const char* fmt, ...);
}

View File

@ -0,0 +1,148 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "script_extension.hpp"
#include "script_error.hpp"
#include "component/scripting.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
namespace gsc
{
namespace
{
utils::hook::detour scr_emit_function_hook;
unsigned int current_filename = 0;
std::string unknown_function_error;
void scr_emit_function_stub(unsigned int filename, unsigned int thread_name, char* code_pos)
{
current_filename = filename;
scr_emit_function_hook.invoke<void>(filename, thread_name, code_pos);
}
std::string get_filename_name()
{
const auto filename_str = game::SL_ConvertToString(static_cast<game::scr_string_t>(current_filename));
const auto id = std::atoi(filename_str);
if (!id)
{
return filename_str;
}
return scripting::get_token(id);
}
void get_unknown_function_error(const char* code_pos)
{
const auto function = find_function(code_pos);
if (function.has_value())
{
const auto& pos = function.value();
unknown_function_error = std::format(
"while processing function '{}' in script '{}':\nunknown script '{}'", pos.first, pos.second, scripting::current_file
);
}
else
{
unknown_function_error = std::format("unknown script '{}'", scripting::current_file);
}
}
void get_unknown_function_error(unsigned int thread_name)
{
const auto filename = get_filename_name();
const auto name = scripting::get_token(thread_name);
unknown_function_error = std::format(
"while processing script '{}':\nunknown function '{}::{}'", scripting::current_file, filename, name
);
}
void compile_error_stub(const char* code_pos, [[maybe_unused]] const char* msg)
{
get_unknown_function_error(code_pos);
game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data());
}
unsigned int find_variable_stub(unsigned int parent_id, unsigned int thread_name)
{
const auto res = game::FindVariable(parent_id, thread_name);
if (!res)
{
get_unknown_function_error(thread_name);
game::Com_Error(game::ERR_DROP, "script link error\n%s", unknown_function_error.data());
}
return res;
}
unsigned int scr_get_const_string(unsigned int index)
{
if (index < game::scr_VmPub->outparamcount)
{
auto* value = game::scr_VmPub->top - index;
if (game::Scr_CastString(value))
{
assert(value->type == game::SCRIPT_STRING);
return value->u.stringValue;
}
game::Scr_ErrorInternal();
}
scr_error(utils::string::va("Parameter %u does not exist", index + 1));
return 0;
}
}
std::optional<std::pair<std::string, std::string>> find_function(const char* pos)
{
for (const auto& file : scripting::script_function_table_sort)
{
for (auto i = file.second.begin(); i != file.second.end() && std::next(i) != file.second.end(); ++i)
{
const auto next = std::next(i);
if (pos >= i->second && pos < next->second)
{
return {std::make_pair(i->first, file.first)};
}
}
}
return {};
}
class error final : public component_interface
{
public:
void post_unpack() override
{
if (game::environment::is_sp())
{
return;
}
scr_emit_function_hook.create(0x1403ED900, &scr_emit_function_stub);
utils::hook::call(0x1403ED894, compile_error_stub); // LinkFile
utils::hook::call(0x1403ED8E8, compile_error_stub); // LinkFile
utils::hook::call(0x1403ED9DB, find_variable_stub); // Scr_EmitFunction
// Restore basic error messages to scr functions
utils::hook::jump(0x1403F8510, scr_get_const_string);
}
void pre_destroy() override
{
scr_emit_function_hook.clear();
}
};
}
REGISTER_COMPONENT(gsc::error)

View File

@ -0,0 +1,6 @@
#pragma once
namespace gsc
{
std::optional<std::pair<std::string, std::string>> find_function(const char* pos);
}

View File

@ -1,34 +1,182 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "game/game.hpp" #include "game/game.hpp"
#include "game/scripting/functions.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include "component/console.hpp" #include "component/console.hpp"
#include "component/command.hpp"
#include "script_error.hpp"
#include "script_extension.hpp"
#include <utils/string.hpp>
#include <xsk/gsc/types.hpp> #include <xsk/gsc/types.hpp>
#include <xsk/resolver.hpp> #include <xsk/resolver.hpp>
namespace gsc namespace gsc
{ {
std::uint16_t function_id_start = 0x2DF;
void* func_table[0x1000];
const game::dvar_t* developer_script = nullptr;
namespace namespace
{ {
typedef void(*builtin_function)(); #define RVA(ptr) static_cast<std::uint32_t>(reinterpret_cast<std::size_t>(ptr) - 0x140000000)
std::unordered_map<std::uint32_t, builtin_function> builtin_funcs_overrides;
struct gsc_error : public std::runtime_error
{
using std::runtime_error::runtime_error;
};
std::unordered_map<std::uint16_t, game::BuiltinFunction> functions;
bool force_error_print = false;
std::optional<std::string> gsc_error_msg;
std::unordered_map<std::uint32_t, game::BuiltinFunction> builtin_funcs_overrides;
utils::hook::detour scr_register_function_hook; utils::hook::detour scr_register_function_hook;
void override_function(const std::string& name, builtin_function func) unsigned int scr_get_function_stub(const char** p_name, int* type)
{ {
const auto id = xsk::gsc::s1::resolver::function_id(name); const auto result = utils::hook::invoke<unsigned int>(0x1403318B0, p_name, type);
builtin_funcs_overrides.emplace(id, func);
for (const auto& [name, func] : functions)
{
game::Scr_RegisterFunction(func, 0, name);
}
return result;
}
void execute_custom_function(game::BuiltinFunction function)
{
auto error = false;
try
{
function();
}
catch (const std::exception& ex)
{
error = true;
force_error_print = true;
gsc_error_msg = ex.what();
}
if (error)
{
game::Scr_ErrorInternal();
}
}
void vm_call_builtin_function(const std::uint32_t index)
{
const auto func = reinterpret_cast<game::BuiltinFunction>(scripting::get_function_by_index(index));
const auto custom = functions.contains(static_cast<std::uint16_t>(index));
if (!custom)
{
func();
}
else
{
execute_custom_function(func);
}
}
void builtin_call_error(const std::string& error)
{
const auto pos = game::scr_function_stack->pos;
const auto function_id = *reinterpret_cast<std::uint16_t*>(reinterpret_cast<std::size_t>(pos - 2));
if (function_id > 0x1000)
{
console::warn("in call to builtin method \"%s\"%s", xsk::gsc::s1::resolver::method_name(function_id).data(), error.data());
}
else
{
console::warn("in call to builtin function \"%s\"%s", xsk::gsc::s1::resolver::function_name(function_id).data(), error.data());
}
}
std::optional<std::string> get_opcode_name(const std::uint8_t opcode)
{
try
{
return {xsk::gsc::s1::resolver::opcode_name(opcode)};
}
catch (...)
{
return {};
}
}
void print_callstack()
{
for (auto frame = game::scr_VmPub->function_frame; frame != game::scr_VmPub->function_frame_start; --frame)
{
const auto pos = frame == game::scr_VmPub->function_frame ? game::scr_function_stack->pos : frame->fs.pos;
const auto function = find_function(frame->fs.pos);
if (function.has_value())
{
console::warn("\tat function \"%s\" in file \"%s.gsc\"\n", function.value().first.data(), function.value().second.data());
}
else
{
console::warn("\tat unknown location %p\n", pos);
}
}
}
void vm_error_stub(int mark_pos)
{
if (!developer_script->current.enabled && !force_error_print)
{
utils::hook::invoke<void>(0x1404B6790, mark_pos);
return;
}
console::warn("******* script runtime error ********\n");
const auto opcode_id = *reinterpret_cast<std::uint8_t*>(0x148806768);
const std::string error = gsc_error_msg.has_value() ? std::format(": {}", gsc_error_msg.value()) : std::string();
if ((opcode_id >= 0x1A && opcode_id <= 0x20) || (opcode_id >= 0xA9 && opcode_id <= 0xAF))
{
builtin_call_error(error);
}
else
{
const auto opcode = get_opcode_name(opcode_id);
if (opcode.has_value())
{
console::warn("while processing instruction %s%s\n", opcode.value().data(), error.data());
}
else
{
console::warn("while processing instruction 0x%X%s\n", opcode_id, error.data());
}
}
force_error_print = false;
gsc_error_msg = {};
print_callstack();
console::warn("************************************\n");
utils::hook::invoke<void>(0x1404B6790, mark_pos);
} }
void scr_register_function_stub(void* func, int type, unsigned int name) void scr_register_function_stub(void* func, int type, unsigned int name)
{ {
if (const auto got = builtin_funcs_overrides.find(name); got != builtin_funcs_overrides.end()) if (const auto itr = builtin_funcs_overrides.find(name); itr != builtin_funcs_overrides.end())
{ {
func = got->second; func = itr->second;
} }
scr_register_function_hook.invoke<void>(func, type, name); scr_register_function_hook.invoke<void>(func, type, name);
@ -51,6 +199,48 @@ namespace gsc
console::info("\n"); console::info("\n");
} }
void assert_cmd()
{
if (!game::Scr_GetInt(0))
{
scr_error("Assert fail");
}
}
void assert_ex_cmd()
{
if (!game::Scr_GetInt(0))
{
scr_error(utils::string::va("Assert fail: %s", game::Scr_GetString(1)));
}
}
void assert_msg_cmd()
{
scr_error(utils::string::va("Assert fail: %s", game::Scr_GetString(0)));
}
}
void scr_error(const char* error)
{
force_error_print = true;
gsc_error_msg = error;
game::Scr_ErrorInternal();
}
void override_function(const std::string& name, game::BuiltinFunction func)
{
const auto id = xsk::gsc::s1::resolver::function_id(name);
builtin_funcs_overrides.emplace(id, func);
}
void add_function(const std::string& name, game::BuiltinFunction function)
{
++function_id_start;
functions[function_id_start] = function;
xsk::gsc::s1::resolver::add_function(name, function_id_start);
} }
class extension final : public component_interface class extension final : public component_interface
@ -62,6 +252,36 @@ namespace gsc
override_function("print", &scr_print); override_function("print", &scr_print);
override_function("println", &scr_print_ln); override_function("println", &scr_print_ln);
utils::hook::set<std::uint32_t>(SELECT_VALUE(0x1403115BC, 0x1403EDAEC), 0x1000); // Scr_RegisterFunction
utils::hook::set<std::uint32_t>(SELECT_VALUE(0x1403115C2 + 4, 0x1403EDAF2 + 4), RVA(&func_table)); // Scr_RegisterFunction
utils::hook::set<std::uint32_t>(SELECT_VALUE(0x14031F097 + 3, 0x1403FB7F7 + 3), RVA(&func_table)); // VM_Execute_0
utils::hook::inject(SELECT_VALUE(0x140311964 + 3, 0x1403EDEE4 + 3), &func_table); // Scr_BeginLoadScripts
if (game::environment::is_sp())
{
return;
}
developer_script = game::Dvar_RegisterBool("developer_script", false, game::DVAR_FLAG_NONE, "Enable developer script comments");
utils::hook::nop(0x1403FB7F7 + 5, 2);
utils::hook::call(0x1403FB7F7, vm_call_builtin_function);
utils::hook::call(0x1403FCAB0, vm_error_stub); // LargeLocalResetToMark
utils::hook::call(0x1403EDF1F, scr_get_function_stub);
override_function("assert", &assert_cmd);
override_function("assertex", &assert_ex_cmd);
override_function("assertmsg", &assert_ex_cmd);
add_function("executecommand", []
{
const auto* cmd = game::Scr_GetString(0);
command::execute(cmd);
});
} }
}; };
} }

View File

@ -0,0 +1,12 @@
#pragma once
namespace gsc
{
extern void* func_table[0x1000];
extern const game::dvar_t* developer_script;
void scr_error(const char* error);
void override_function(const std::string& name, game::BuiltinFunction func);
void add_function(const std::string& name, game::BuiltinFunction function);
}

View File

@ -10,6 +10,8 @@
#include "component/scripting.hpp" #include "component/scripting.hpp"
#include "component/fastfiles.hpp" #include "component/fastfiles.hpp"
#include "script_loading.hpp"
#include <xsk/gsc/types.hpp> #include <xsk/gsc/types.hpp>
#include <xsk/gsc/interfaces/compiler.hpp> #include <xsk/gsc/interfaces/compiler.hpp>
#include <xsk/gsc/interfaces/decompiler.hpp> #include <xsk/gsc/interfaces/decompiler.hpp>
@ -47,7 +49,8 @@ namespace gsc
return true; return true;
} }
// This will prevent 'fake' GSC raw files from being compiled. They are parsed by the game's own parser later. // This will prevent 'fake' GSC raw files from being compiled.
// They are parsed by the game's own parser later as they are special files.
if (name.starts_with("maps/createfx") || name.starts_with("maps/createart") || if (name.starts_with("maps/createfx") || name.starts_with("maps/createart") ||
(name.starts_with("maps/mp") && name.ends_with("_fx.gsc"))) (name.starts_with("maps/mp") && name.ends_with("_fx.gsc")))
{ {
@ -78,9 +81,9 @@ namespace gsc
game::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name) game::ScriptFile* load_custom_script(const char* file_name, const std::string& real_name)
{ {
if (const auto got = loaded_scripts.find(real_name); got != loaded_scripts.end()) if (const auto itr = loaded_scripts.find(real_name); itr != loaded_scripts.end())
{ {
return got->second; return itr->second;
} }
std::string source_buffer{}; std::string source_buffer{};
@ -225,24 +228,6 @@ namespace gsc
} }
} }
game::ScriptFile* find_script(game::XAssetType /*type*/, const char* name, int /*allow_create_default*/)
{
std::string real_name = name;
const auto id = static_cast<std::uint16_t>(std::atoi(name));
if (id)
{
real_name = xsk::gsc::s1::resolver::token_name(id);
}
auto* script = load_custom_script(name, real_name);
if (script)
{
return script;
}
return game::DB_FindXAssetHeader(game::ASSET_TYPE_SCRIPTFILE, name, 1).scriptfile;
}
int db_is_x_asset_default(game::XAssetType type, const char* name) int db_is_x_asset_default(game::XAssetType type, const char* name)
{ {
if (loaded_scripts.contains(name)) if (loaded_scripts.contains(name))
@ -253,9 +238,9 @@ namespace gsc
return game::DB_IsXAssetDefault(type, name); return game::DB_IsXAssetDefault(type, name);
} }
void gscr_load_game_type_script_stub() void gscr_post_load_scripts_stub()
{ {
utils::hook::invoke<void>(0x140330490); utils::hook::invoke<void>(0x140323F20);
clear(); clear();
@ -314,6 +299,24 @@ namespace gsc
} }
} }
game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default)
{
std::string real_name = name;
const auto id = static_cast<std::uint16_t>(std::atoi(name));
if (id)
{
real_name = xsk::gsc::s1::resolver::token_name(id);
}
auto* script = load_custom_script(name, real_name);
if (script)
{
return script;
}
return game::DB_FindXAssetHeader(type, name, allow_create_default).scriptfile;
}
class loading final : public component_interface class loading final : public component_interface
{ {
public: public:
@ -352,7 +355,7 @@ namespace gsc
utils::hook::call(0x1403F7327, db_is_x_asset_default); utils::hook::call(0x1403F7327, db_is_x_asset_default);
// GScr_LoadScripts // GScr_LoadScripts
utils::hook::call(0x140330B19, gscr_load_game_type_script_stub); utils::hook::call(0x140330B97, gscr_post_load_scripts_stub);
// Load our scripts with an uncompressed stack // Load our scripts with an uncompressed stack
utils::hook::call(0x1403F7380, db_get_raw_buffer_stub); utils::hook::call(0x1403F7380, db_get_raw_buffer_stub);

View File

@ -0,0 +1,6 @@
#pragma once
namespace gsc
{
game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default);
}

View File

@ -3,6 +3,7 @@
#include "game/game.hpp" #include "game/game.hpp"
#include "command.hpp" #include "command.hpp"
#include "console.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
@ -126,7 +127,7 @@ namespace map_rotation
change_process_priority(); change_process_priority();
if (!game::SV_MapExists(value.data())) if (!game::SV_MapExists(value.data()))
{ {
printf("map_rotation: '%s' map doesn't exist!\n", value.data()); console::info("map_rotation: '%s' map doesn't exist!\n", value.data());
launch_default_map(); launch_default_map();
return; return;
} }
@ -135,7 +136,7 @@ namespace map_rotation
} }
else else
{ {
printf("Invalid map rotation key: %s\n", key.data()); console::info("Invalid map rotation key: %s\n", key.data());
} }
} }

View File

@ -31,7 +31,7 @@ namespace network
return false; return false;
} }
const std::string_view data(message->data + offset, message->cursize - offset); const std::string data(message->data + offset, message->cursize - offset);
handler->second(*address, data); handler->second(*address, data);
return true; return true;
@ -274,11 +274,10 @@ namespace network
utils::hook::set<int>(0x1403DAD35, max_packet_size); utils::hook::set<int>(0x1403DAD35, max_packet_size);
// ignore built in "print" oob command and add in our own // ignore built in "print" oob command and add in our own
utils::hook::set<uint8_t>(0x14020A723, 0xEB); utils::hook::set<std::uint8_t>(0x14020A723, 0xEB);
on("print", [](const game::netadr_s&, const std::string_view& data) on("print", [](const game::netadr_s&, const std::string& data)
{ {
const std::string message{data}; console::info("%s", data.data());
console::info(message.data());
}); });
} }
} }

View File

@ -1,9 +1,8 @@
#pragma once #pragma once
#include "game/game.hpp"
namespace network namespace network
{ {
using callback = std::function<void(const game::netadr_s&, const std::string_view&)>; using callback = std::function<void(const game::netadr_s&, const std::string&)>;
void on(const std::string& command, const callback& callback); void on(const std::string& command, const callback& callback);
void send(const game::netadr_s& address, const std::string& command, const std::string& data = {}, char separator = ' '); void send(const game::netadr_s& address, const std::string& command, const std::string& data = {}, char separator = ' ');

View File

@ -1,6 +1,5 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "scheduler.hpp"
#include "game/scripting/entity.hpp" #include "game/scripting/entity.hpp"
#include "game/scripting/execution.hpp" #include "game/scripting/execution.hpp"
@ -9,23 +8,32 @@
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include "logfile.hpp" #include "scheduler.hpp"
#include "notifies.hpp"
#include "scripting.hpp"
namespace logfile namespace notifies
{ {
std::unordered_map<const char*, sol::protected_function> vm_execute_hooks; bool hook_enabled = true;
namespace namespace
{ {
struct gsc_hook
{
bool is_lua_hook{};
const char* target_pos{};
sol::protected_function lua_function;
};
std::unordered_map<const char*, gsc_hook> vm_execute_hooks;
utils::hook::detour scr_player_killed_hook; utils::hook::detour scr_player_killed_hook;
utils::hook::detour scr_player_damage_hook; utils::hook::detour scr_player_damage_hook;
std::vector<sol::protected_function> player_killed_callbacks; std::vector<sol::protected_function> player_killed_callbacks;
std::vector<sol::protected_function> player_damage_callbacks; std::vector<sol::protected_function> player_damage_callbacks;
utils::hook::detour vm_execute_hook;
char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END char empty_function[2] = {0x32, 0x34}; // CHECK_CLEAR_PARAMS, END
bool hook_enabled = true; const char* target_function = nullptr;
sol::lua_value convert_entity(lua_State* state, const game::mp::gentity_s* ent) sol::lua_value convert_entity(lua_State* state, const game::mp::gentity_s* ent)
{ {
@ -41,7 +49,7 @@ namespace logfile
std::string get_weapon_name(unsigned int weapon, bool isAlternate) std::string get_weapon_name(unsigned int weapon, bool isAlternate)
{ {
char output[1024] = { 0 }; char output[1024]{};
game::BG_GetWeaponNameComplete(weapon, isAlternate, output, 1024); game::BG_GetWeaponNameComplete(weapon, isAlternate, output, 1024);
return output; return output;
@ -68,13 +76,13 @@ namespace logfile
} }
void scr_player_killed_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, game::mp::gentity_s* attacker, int damage, void scr_player_killed_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, game::mp::gentity_s* attacker, int damage,
const int meansOfDeath, const unsigned int weapon, const bool isAlternate, const float* vDir, const unsigned int hitLoc, int psTimeOffset, int deathAnimDuration) const int means_of_death, const unsigned int weapon, const bool is_alternate, const float* v_dir, const unsigned int hit_loc, int ps_time_offset, int death_anim_duration)
{ {
{ {
const std::string _hitLoc = reinterpret_cast<const char**>(0x1409B5400)[hitLoc]; const std::string _hit_loc = reinterpret_cast<const char**>(0x1409E62B0)[hit_loc];
const auto _mod = convert_mod(meansOfDeath); const auto _mod = convert_mod(means_of_death);
const auto _weapon = get_weapon_name(weapon, isAlternate); const auto _weapon = get_weapon_name(weapon, is_alternate);
for (const auto& callback : player_killed_callbacks) for (const auto& callback : player_killed_callbacks)
{ {
@ -84,9 +92,9 @@ namespace logfile
const auto _inflictor = convert_entity(state, inflictor); const auto _inflictor = convert_entity(state, inflictor);
const auto _attacker = convert_entity(state, attacker); const auto _attacker = convert_entity(state, attacker);
const auto _vDir = convert_vector(state, vDir); const auto _v_dir = convert_vector(state, v_dir);
const auto result = callback(_self, _inflictor, _attacker, damage, _mod, _weapon, _vDir, _hitLoc, psTimeOffset, deathAnimDuration); const auto result = callback(_self, _inflictor, _attacker, damage, _mod, _weapon, _v_dir, _hit_loc, ps_time_offset, death_anim_duration);
scripting::lua::handle_error(result); scripting::lua::handle_error(result);
@ -102,17 +110,17 @@ namespace logfile
} }
} }
scr_player_killed_hook.invoke<void>(self, inflictor, attacker, damage, meansOfDeath, weapon, isAlternate, vDir, hitLoc, psTimeOffset, deathAnimDuration); scr_player_killed_hook.invoke<void>(self, inflictor, attacker, damage, means_of_death, weapon, is_alternate, v_dir, hit_loc, ps_time_offset, death_anim_duration);
} }
void scr_player_damage_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, game::mp::gentity_s* attacker, int damage, int dflags, void scr_player_damage_stub(game::mp::gentity_s* self, const game::mp::gentity_s* inflictor, game::mp::gentity_s* attacker, int damage, int dflags,
const int meansOfDeath, const unsigned int weapon, const bool isAlternate, const float* vPoint, const float* vDir, const unsigned int hitLoc, const int timeOffset) const int means_of_death, const unsigned int weapon, const bool is_alternate, const float* v_point, const float* v_dir, const unsigned int hit_loc, const int time_offset)
{ {
{ {
const std::string _hitLoc = reinterpret_cast<const char**>(0x1409B5400)[hitLoc]; const std::string _hit_loc = reinterpret_cast<const char**>(0x1409E62B0)[hit_loc];
const auto _mod = convert_mod(meansOfDeath); const auto _mod = convert_mod(means_of_death);
const auto _weapon = get_weapon_name(weapon, isAlternate); const auto _weapon = get_weapon_name(weapon, is_alternate);
for (const auto& callback : player_damage_callbacks) for (const auto& callback : player_damage_callbacks)
{ {
@ -122,10 +130,10 @@ namespace logfile
const auto _inflictor = convert_entity(state, inflictor); const auto _inflictor = convert_entity(state, inflictor);
const auto _attacker = convert_entity(state, attacker); const auto _attacker = convert_entity(state, attacker);
const auto _vPoint = convert_vector(state, vPoint); const auto _v_point = convert_vector(state, v_point);
const auto _vDir = convert_vector(state, vDir); const auto _v_dir = convert_vector(state, v_dir);
const auto result = callback(_self, _inflictor, _attacker, damage, dflags, _mod, _weapon, _vPoint, _vDir, _hitLoc); const auto result = callback(_self, _inflictor, _attacker, damage, dflags, _mod, _weapon, _v_point, _v_dir, _hit_loc);
scripting::lua::handle_error(result); scripting::lua::handle_error(result);
@ -141,15 +149,20 @@ namespace logfile
} }
} }
scr_player_damage_hook.invoke<void>(self, inflictor, attacker, damage, dflags, meansOfDeath, weapon, isAlternate, vPoint, vDir, hitLoc, timeOffset); scr_player_damage_hook.invoke<void>(self, inflictor, attacker, damage, dflags, means_of_death, weapon, is_alternate, v_point, v_dir, hit_loc, time_offset);
} }
void client_command_stub(const int clientNum) void client_command_stub(const int client_num)
{ {
auto self = &game::mp::g_entities[clientNum]; auto self = &game::mp::g_entities[client_num];
char cmd[1024]{};
game::SV_Cmd_ArgvBuffer(0, cmd, 1024); if (!self->client)
{
return;
}
char cmd[1024]{};
game::SV_Cmd_ArgvBuffer(0, cmd, sizeof(cmd));
if (cmd == "say"s || cmd == "say_team"s) if (cmd == "say"s || cmd == "say_team"s)
{ {
@ -175,18 +188,7 @@ namespace logfile
} }
// ClientCommand // ClientCommand
return reinterpret_cast<void(*)(int)>(0x1402E98F0)(clientNum); utils::hook::invoke<void>(0x1402E98F0, client_num);
}
void g_shutdown_game_stub(const int freeScripts)
{
{
const scripting::entity level{*game::levelEntityId};
scripting::notify(level, "shutdownGame_called", {1});
}
// G_ShutdownGame
return reinterpret_cast<void(*)(int)>(0x1402F8C10)(freeScripts);
} }
unsigned int local_id_to_entity(unsigned int local_id) unsigned int local_id_to_entity(unsigned int local_id)
@ -197,7 +199,7 @@ namespace logfile
bool execute_vm_hook(const char* pos) bool execute_vm_hook(const char* pos)
{ {
if (vm_execute_hooks.find(pos) == vm_execute_hooks.end()) if (!vm_execute_hooks.contains(pos))
{ {
hook_enabled = true; hook_enabled = true;
return false; return false;
@ -210,21 +212,28 @@ namespace logfile
} }
const auto hook = vm_execute_hooks[pos]; const auto hook = vm_execute_hooks[pos];
const auto state = hook.lua_state(); if (hook.is_lua_hook)
const scripting::entity self = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId);
std::vector<sol::lua_value> args;
const auto top = game::scr_function_stack->top;
for (auto* value = top; value->type != game::SCRIPT_END; --value)
{ {
args.push_back(scripting::lua::convert(state, *value)); const auto& function = hook.lua_function;
} const auto state = function.lua_state();
const auto result = hook(self, sol::as_args(args)); const scripting::entity self = local_id_to_entity(game::scr_VmPub->function_frame->fs.localId);
scripting::lua::handle_error(result); std::vector<sol::lua_value> args;
const auto top = game::scr_function_stack->top;
for (auto* value = top; value->type != game::SCRIPT_END; --value)
{
args.push_back(scripting::lua::convert(state, *value));
}
const auto result = function(self, sol::as_args(args));
scripting::lua::handle_error(result);
target_function = empty_function;
}
else
{
target_function = hook.target_pos;
}
return true; return true;
} }
@ -257,7 +266,8 @@ namespace logfile
a.bind(replace); a.bind(replace);
a.popad64(); a.popad64();
a.mov(r14, reinterpret_cast<char*>(empty_function)); a.mov(rax, qword_ptr(reinterpret_cast<std::int64_t>(&target_function)));
a.mov(r14, rax);
a.jmp(end); a.jmp(end);
} }
} }
@ -289,6 +299,32 @@ namespace logfile
hook_enabled = false; hook_enabled = false;
} }
void set_lua_hook(const char* pos, const sol::protected_function& callback)
{
gsc_hook hook;
hook.is_lua_hook = true;
hook.lua_function = callback;
vm_execute_hooks[pos] = hook;
}
void set_gsc_hook(const char* source, const char* target)
{
gsc_hook hook;
hook.is_lua_hook = false;
hook.target_pos = target;
vm_execute_hooks[source] = hook;
}
void clear_hook(const char* pos)
{
vm_execute_hooks.erase(pos);
}
std::size_t get_hook_count()
{
return vm_execute_hooks.size();
}
class component final : public component_interface class component final : public component_interface
{ {
public: public:
@ -304,12 +340,20 @@ namespace logfile
scr_player_damage_hook.create(0x140332150, scr_player_damage_stub); scr_player_damage_hook.create(0x140332150, scr_player_damage_stub);
scr_player_killed_hook.create(0x1403323D0, scr_player_killed_stub); scr_player_killed_hook.create(0x1403323D0, scr_player_killed_stub);
utils::hook::call(0x14043E550, g_shutdown_game_stub);
utils::hook::call(0x14043EA11, g_shutdown_game_stub);
utils::hook::jump(0x1403FA134, utils::hook::assemble(vm_execute_stub), true); utils::hook::jump(0x1403FA134, utils::hook::assemble(vm_execute_stub), true);
scripting::on_shutdown([](bool free_scripts)
{
if (free_scripts)
{
vm_execute_hooks.clear();
}
const scripting::entity level{*game::levelEntityId};
scripting::notify(level, "shutdownGame_called", {free_scripts});
});
} }
}; };
} }
REGISTER_COMPONENT(logfile::component) REGISTER_COMPONENT(notifies::component)

View File

@ -1,8 +1,13 @@
#pragma once #pragma once
namespace logfile namespace notifies
{ {
extern std::unordered_map<const char*, sol::protected_function> vm_execute_hooks; extern bool hook_enabled;
void set_lua_hook(const char* pos, const sol::protected_function&);
void set_gsc_hook(const char* source, const char* target);
void clear_hook(const char* pos);
std::size_t get_hook_count();
void add_player_damage_callback(const sol::protected_function& callback); void add_player_damage_callback(const sol::protected_function& callback);
void add_player_killed_callback(const sol::protected_function& callback); void add_player_killed_callback(const sol::protected_function& callback);

View File

@ -14,6 +14,8 @@
#include <utils/cryptography.hpp> #include <utils/cryptography.hpp>
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <version.hpp>
namespace party namespace party
{ {
namespace namespace
@ -80,29 +82,18 @@ namespace party
std::string get_dvar_string(const std::string& dvar) std::string get_dvar_string(const std::string& dvar)
{ {
auto* dvar_value = game::Dvar_FindVar(dvar.data()); const auto* dvar_value = game::Dvar_FindVar(dvar.data());
if (dvar_value && dvar_value->current.string) if (dvar_value && dvar_value->current.string)
{ {
return dvar_value->current.string; return {dvar_value->current.string};
} }
return {}; return {};
} }
int get_dvar_int(const std::string& dvar)
{
auto* dvar_value = game::Dvar_FindVar(dvar.data());
if (dvar_value && dvar_value->current.integer)
{
return dvar_value->current.integer;
}
return -1;
}
bool get_dvar_bool(const std::string& dvar) bool get_dvar_bool(const std::string& dvar)
{ {
auto* dvar_value = game::Dvar_FindVar(dvar.data()); const auto* dvar_value = game::Dvar_FindVar(dvar.data());
if (dvar_value && dvar_value->current.enabled) if (dvar_value && dvar_value->current.enabled)
{ {
return dvar_value->current.enabled; return dvar_value->current.enabled;
@ -128,22 +119,20 @@ namespace party
{ {
if (game::CL_IsCgameInitialized()) if (game::CL_IsCgameInitialized())
{ {
// CL_ForwardCommandToServer game::CL_ForwardCommandToServer(0, "disconnect");
reinterpret_cast<void (*)(int, const char*)>(0x14020B310)(0, "disconnect"); game::CL_WritePacket(0);
// CL_WritePacket
reinterpret_cast<void (*)(int)>(0x1402058F0)(0);
} }
// CL_Disconnect
reinterpret_cast<void (*)(int)>(0x140209EC0)(0); game::CL_Disconnect(0);
} }
} }
utils::hook::detour cldisconnect_hook; utils::hook::detour cl_disconnect_hook;
void cldisconnect_stub(int a1) void cl_disconnect_stub(int a1)
{ {
clear_sv_motd(); clear_sv_motd();
cldisconnect_hook.invoke<void>(a1); cl_disconnect_hook.invoke<void>(a1);
} }
const auto drop_reason_stub = utils::hook::assemble([](utils::hook::assembler& a) const auto drop_reason_stub = utils::hook::assemble([](utils::hook::assembler& a)
@ -156,7 +145,7 @@ namespace party
void clear_sv_motd() void clear_sv_motd()
{ {
party::sv_motd.clear(); sv_motd.clear();
} }
int get_client_num_by_name(const std::string& name) int get_client_num_by_name(const std::string& name)
@ -305,7 +294,7 @@ namespace party
utils::hook::jump(0x14020A010, disconnect_stub); utils::hook::jump(0x14020A010, disconnect_stub);
// detour CL_Disconnect to clear motd // detour CL_Disconnect to clear motd
cldisconnect_hook.create(0x140209EC0, cldisconnect_stub); cl_disconnect_hook.create(0x140209EC0, cl_disconnect_stub);
if (game::environment::is_mp()) if (game::environment::is_mp())
{ {
@ -548,6 +537,7 @@ namespace party
info.set("playmode", utils::string::va("%i", game::Com_GetCurrentCoDPlayMode())); info.set("playmode", utils::string::va("%i", game::Com_GetCurrentCoDPlayMode()));
info.set("sv_running", utils::string::va("%i", get_dvar_bool("sv_running"))); info.set("sv_running", utils::string::va("%i", get_dvar_bool("sv_running")));
info.set("dedicated", utils::string::va("%i", get_dvar_bool("dedicated"))); info.set("dedicated", utils::string::va("%i", get_dvar_bool("dedicated")));
info.set("shortversion", SHORTVERSION);
network::send(target, "infoResponse", info.build(), '\n'); network::send(target, "infoResponse", info.build(), '\n');
}); });

View File

@ -14,7 +14,7 @@
#include <utils/string.hpp> #include <utils/string.hpp>
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include "version.hpp" #include <version.hpp>
namespace patches namespace patches
{ {
@ -118,7 +118,7 @@ namespace patches
return 0; return 0;
} }
const char* db_read_raw_file_stub(const char* filename, char* buf, const int size) char* db_read_raw_file_stub(const char* filename, char* buf, const int size)
{ {
std::string file_name = filename; std::string file_name = filename;
if (file_name.find(".cfg") == std::string::npos) if (file_name.find(".cfg") == std::string::npos)
@ -133,9 +133,7 @@ namespace patches
return buf; return buf;
} }
// DB_ReadRawFile return game::DB_ReadRawFile(filename, buf, size);
return reinterpret_cast<const char*(*)(const char*, char*, int)>(SELECT_VALUE(0x140180E30, 0x140273080))(
filename, buf, size);
} }
void aim_assist_add_to_target_list(void* a1, void* a2) void aim_assist_add_to_target_list(void* a1, void* a2)

View File

@ -1,7 +1,5 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
#include "game/game.hpp" #include "game/game.hpp"
#include "command.hpp" #include "command.hpp"
@ -9,6 +7,9 @@
#include "network.hpp" #include "network.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
namespace rcon namespace rcon
{ {
namespace namespace
@ -112,6 +113,7 @@ namespace rcon
network::send(redirect_target_, "print", message); network::send(redirect_target_, "print", message);
return true; return true;
} }
return false; return false;
} }

View File

@ -1,8 +1,6 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include "game/game.hpp" #include "game/game.hpp"
#include <utils/hook.hpp>
#include "game/scripting/entity.hpp" #include "game/scripting/entity.hpp"
#include "game/scripting/functions.hpp" #include "game/scripting/functions.hpp"
@ -13,9 +11,17 @@
#include "scheduler.hpp" #include "scheduler.hpp"
#include "scripting.hpp" #include "scripting.hpp"
#include "gsc/script_loading.hpp"
#include <utils/hook.hpp>
namespace scripting namespace scripting
{ {
std::unordered_map<std::string, std::unordered_map<std::string, const char*>> script_function_table; std::unordered_map<std::string, std::unordered_map<std::string, const char*>> script_function_table;
std::unordered_map<std::string, std::vector<std::pair<std::string, const char*>>> script_function_table_sort;
std::unordered_map<const char*, std::pair<std::string, std::string>> script_function_table_rev;
std::string current_file;
namespace namespace
{ {
@ -25,13 +31,17 @@ namespace scripting
utils::hook::detour scr_set_thread_position_hook; utils::hook::detour scr_set_thread_position_hook;
utils::hook::detour process_script_hook; utils::hook::detour process_script_hook;
utils::hook::detour sl_get_canonical_string_hook;
std::string current_file; std::string current_script_file;
std::uint32_t current_file_id = 0;
std::unordered_map<unsigned int, std::string> canonical_string_table;
std::vector<std::function<void(int)>> shutdown_callbacks; std::vector<std::function<void(int)>> shutdown_callbacks;
std::vector<std::function<void()>> init_callbacks;
void vm_notify_stub(const unsigned int notify_list_owner_id, const game::scr_string_t string_value, void vm_notify_stub(const unsigned int notify_list_owner_id, const game::scr_string_t string_value, game::VariableValue* top)
game::VariableValue* top)
{ {
if (!game::VirtualLobby_Loaded()) if (!game::VirtualLobby_Loaded())
{ {
@ -49,7 +59,7 @@ namespace scripting
if (e.name == "connected") if (e.name == "connected")
{ {
scripting::clear_entity_fields(e.entity); clear_entity_fields(e.entity);
} }
lua::engine::notify(e); lua::engine::notify(e);
@ -65,6 +75,11 @@ namespace scripting
if (!game::VirtualLobby_Loaded()) if (!game::VirtualLobby_Loaded())
{ {
lua::engine::start(); lua::engine::start();
for (const auto& callback : init_callbacks)
{
callback();
}
} }
} }
@ -72,6 +87,13 @@ namespace scripting
{ {
lua::engine::stop(); lua::engine::stop();
if (free_scripts)
{
script_function_table_sort.clear();
script_function_table.clear();
canonical_string_table.clear();
}
for (const auto& callback : shutdown_callbacks) for (const auto& callback : shutdown_callbacks)
{ {
callback(free_scripts); callback(free_scripts);
@ -82,25 +104,85 @@ namespace scripting
void process_script_stub(const char* filename) void process_script_stub(const char* filename)
{ {
current_script_file = filename;
const auto file_id = atoi(filename); const auto file_id = atoi(filename);
if (file_id) if (file_id)
{ {
current_file = scripting::find_token(file_id); current_file_id = static_cast<std::uint16_t>(file_id);
} }
else else
{ {
current_file_id = 0;
current_file = filename; current_file = filename;
} }
process_script_hook.invoke<void>(filename); process_script_hook.invoke<void>(filename);
} }
void scr_set_thread_position_stub(unsigned int threadName, const char* codePos) void add_function_sort(unsigned int id, const char* pos)
{ {
const auto function_name = scripting::find_token(threadName); std::string filename = current_file;
script_function_table[current_file][function_name] = codePos; if (current_file_id)
scr_set_thread_position_hook.invoke<void>(threadName, codePos); {
filename = get_token(current_file_id);
}
if (!script_function_table_sort.contains(filename))
{
const auto script = gsc::find_script(game::ASSET_TYPE_SCRIPTFILE, current_script_file.data(), false);
if (script)
{
const auto* end = &script->bytecode[script->bytecodeLen];
script_function_table_sort[filename].emplace_back("__end__", reinterpret_cast<const char*>(end));
}
}
const auto name = scripting::get_token(id);
auto& itr = script_function_table_sort[filename];
itr.insert(itr.end() - 1, {name, pos});
} }
void add_function(const std::string& file, unsigned int id, const char* pos)
{
const auto name = get_token(id);
script_function_table[file][name] = pos;
script_function_table_rev[pos] = {file, name};
}
void scr_set_thread_position_stub(unsigned int thread_name, const char* code_pos)
{
add_function_sort(thread_name, code_pos);
if (current_file_id)
{
const auto name = get_token(current_file_id);
add_function(name, thread_name, code_pos);
}
else
{
add_function(current_file, thread_name, code_pos);
}
scr_set_thread_position_hook.invoke<void>(thread_name, code_pos);
}
unsigned int sl_get_canonical_string_stub(const char* str)
{
const auto result = sl_get_canonical_string_hook.invoke<unsigned int>(str);
canonical_string_table[result] = str;
return result;
}
}
std::string get_token(unsigned int id)
{
if (const auto itr = canonical_string_table.find(id); itr != canonical_string_table.end())
{
return itr->second;
}
return find_token(id);
} }
void on_shutdown(const std::function<void(int)>& callback) void on_shutdown(const std::function<void(int)>& callback)
@ -108,20 +190,36 @@ namespace scripting
shutdown_callbacks.push_back(callback); shutdown_callbacks.push_back(callback);
} }
void on_init(const std::function<void()>& callback)
{
init_callbacks.push_back(callback);
}
std::optional<std::string> get_canonical_string(const unsigned int id)
{
if (const auto itr = canonical_string_table.find(id); itr != canonical_string_table.end())
{
return {itr->second};
}
return {};
}
class component final : public component_interface class component final : public component_interface
{ {
public: public:
void post_unpack() override void post_unpack() override
{ {
vm_notify_hook.create(SELECT_VALUE(0x140320E50, 0x1403FD5B0), vm_notify_stub); vm_notify_hook.create(SELECT_VALUE(0x140320E50, 0x1403FD5B0), &vm_notify_stub);
// SP address is wrong, but should be ok // SP address is wrong, but should be ok
scr_load_level_hook.create(SELECT_VALUE(0x140005260, 0x140325B90), scr_load_level_stub); scr_load_level_hook.create(SELECT_VALUE(0x140005260, 0x140325B90), &scr_load_level_stub);
g_shutdown_game_hook.create(SELECT_VALUE(0x140228BA0, 0x1402F8C10), g_shutdown_game_stub); g_shutdown_game_hook.create(SELECT_VALUE(0x140228BA0, 0x1402F8C10), &g_shutdown_game_stub);
scr_set_thread_position_hook.create(SELECT_VALUE(0x1403115E0, 0x1403EDB10), scr_set_thread_position_stub); scr_set_thread_position_hook.create(SELECT_VALUE(0x1403115E0, 0x1403EDB10), &scr_set_thread_position_stub);
process_script_hook.create(SELECT_VALUE(0x14031AB30, 0x1403F7300), process_script_stub); process_script_hook.create(SELECT_VALUE(0x14031AB30, 0x1403F7300), &process_script_stub);
sl_get_canonical_string_hook.create(game::SL_GetCanonicalString, &sl_get_canonical_string_stub);
scheduler::loop([]() scheduler::loop([]
{ {
lua::engine::run_frame(); lua::engine::run_frame();
}, scheduler::pipeline::server); }, scheduler::pipeline::server);

View File

@ -3,6 +3,14 @@
namespace scripting namespace scripting
{ {
extern std::unordered_map<std::string, std::unordered_map<std::string, const char*>> script_function_table; extern std::unordered_map<std::string, std::unordered_map<std::string, const char*>> script_function_table;
extern std::unordered_map<std::string, std::vector<std::pair<std::string, const char*>>> script_function_table_sort;
extern std::unordered_map<const char*, std::pair<std::string, std::string>> script_function_table_rev;
extern std::string current_file;
void on_shutdown(const std::function<void(int)>& callback); void on_shutdown(const std::function<void(int)>& callback);
void on_init(const std::function<void()>& callback);
std::optional<std::string> get_canonical_string(unsigned int id);
std::string get_token(unsigned int id);
} }

View File

@ -1,8 +1,11 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "loader/component_loader.hpp" #include "loader/component_loader.hpp"
#include <utils/hook.hpp>
#include "game/game.hpp" #include "game/game.hpp"
#include "console.hpp"
#include <utils/hook.hpp>
namespace security namespace security
{ {
namespace namespace
@ -21,7 +24,7 @@ namespace security
if(snapshot.num_clients > 1200 && !printed) if(snapshot.num_clients > 1200 && !printed)
{ {
printed = true; printed = true;
printf("Too many entities (%d)... remapping!\n", snapshot.num_clients); console::info("Too many entities (%d)... remapping!\n", snapshot.num_clients);
} }
snapshot.num_clients = std::min(snapshot.num_clients, 1200); snapshot.num_clients = std::min(snapshot.num_clients, 1200);

View File

@ -138,17 +138,6 @@ namespace ui_scripting
{ {
const auto lua = get_globals(); const auto lua = get_globals();
lua["io"]["fileexists"] = utils::io::file_exists;
lua["io"]["writefile"] = utils::io::write_file;
lua["io"]["movefile"] = utils::io::move_file;
lua["io"]["filesize"] = utils::io::file_size;
lua["io"]["createdirectory"] = utils::io::create_directory;
lua["io"]["directoryexists"] = utils::io::directory_exists;
lua["io"]["directoryisempty"] = utils::io::directory_is_empty;
lua["io"]["listfiles"] = utils::io::list_files;
lua["io"]["removefile"] = utils::io::remove_file;
lua["io"]["readfile"] = static_cast<std::string(*)(const std::string&)>(utils::io::read_file);
using game = table; using game = table;
auto game_type = game(); auto game_type = game();
lua["game"] = game_type; lua["game"] = game_type;

View File

@ -25,6 +25,7 @@ namespace dvars
game::dvar_t* g_gravity = nullptr; game::dvar_t* g_gravity = nullptr;
game::dvar_t* g_speed = nullptr; game::dvar_t* g_speed = nullptr;
game::dvar_t* g_elevators = nullptr; game::dvar_t* g_elevators = nullptr;
game::dvar_t* g_log = nullptr;
game::dvar_t* jump_height = nullptr; game::dvar_t* jump_height = nullptr;
game::dvar_t* jump_ladderPushVel = nullptr; game::dvar_t* jump_ladderPushVel = nullptr;

View File

@ -24,6 +24,7 @@ namespace dvars
extern game::dvar_t* g_gravity; extern game::dvar_t* g_gravity;
extern game::dvar_t* g_speed; extern game::dvar_t* g_speed;
extern game::dvar_t* g_elevators; extern game::dvar_t* g_elevators;
extern game::dvar_t* g_log;
extern game::dvar_t* jump_height; extern game::dvar_t* jump_height;
extern game::dvar_t* jump_ladderPushVel; extern game::dvar_t* jump_ladderPushVel;

File diff suppressed because it is too large Load Diff

View File

@ -3,97 +3,89 @@
#include <utils/string.hpp> #include <utils/string.hpp>
#include "component/gsc/script_extension.hpp"
#include <xsk/gsc/types.hpp>
#include <xsk/resolver.hpp>
namespace scripting namespace scripting
{ {
namespace namespace
{ {
std::unordered_map<std::string, unsigned> lowercase_map(
const std::unordered_map<std::string, unsigned>& old_map)
{
std::unordered_map<std::string, unsigned> new_map{};
for (auto& entry : old_map)
{
new_map[utils::string::to_lower(entry.first)] = entry.second;
}
return new_map;
}
const std::unordered_map<std::string, unsigned>& get_methods()
{
static auto methods = lowercase_map(method_map);
return methods;
}
const std::unordered_map<std::string, unsigned>& get_functions()
{
static auto function = lowercase_map(function_map);
return function;
}
int find_function_index(const std::string& name, const bool prefer_global) int find_function_index(const std::string& name, const bool prefer_global)
{ {
const auto target = utils::string::to_lower(name); const auto target = utils::string::to_lower(name);
auto first = xsk::gsc::s1::resolver::function_id;
const auto& primary_map = prefer_global auto second = xsk::gsc::s1::resolver::method_id;
? get_functions() if (!prefer_global)
: get_methods();
const auto& secondary_map = !prefer_global
? get_functions()
: get_methods();
auto function_entry = primary_map.find(target);
if (function_entry != primary_map.end())
{ {
return function_entry->second; std::swap(first, second);
} }
function_entry = secondary_map.find(target); const auto first_res = first(target);
if (function_entry != secondary_map.end()) if (first_res)
{ {
return function_entry->second; return first_res;
}
const auto second_res = second(target);
if (second_res)
{
return second_res;
} }
return -1; return -1;
} }
script_function get_function_by_index(const unsigned index)
{
static const auto function_table = SELECT_VALUE(0x149668F50, 0x147DD1850);
static const auto method_table = SELECT_VALUE(0x14966A670, 0x147DD2F50);
if (index < 0x2DF)
{
return reinterpret_cast<script_function*>(function_table)[index];
}
return reinterpret_cast<script_function*>(method_table)[index - 0x8000];
}
} }
std::string find_token(unsigned int id) std::uint32_t parse_token_id(const std::string& name)
{ {
for (const auto& token : token_map) if (name.starts_with("_ID"))
{ {
if (token.second == id) return static_cast<std::uint32_t>(std::strtol(name.substr(3).data(), nullptr, 10));
{
return token.first;
}
} }
return utils::string::va("_ID%i", id); return 0;
}
std::string find_token(std::uint32_t id)
{
return xsk::gsc::s1::resolver::token_name(static_cast<std::uint16_t>(id));
}
std::string find_token_single(std::uint32_t id)
{
return xsk::gsc::s1::resolver::token_name(static_cast<std::uint16_t>(id));
} }
unsigned int find_token_id(const std::string& name) unsigned int find_token_id(const std::string& name)
{ {
const auto result = token_map.find(name); const auto id = xsk::gsc::s1::resolver::token_id(name);
if (id)
if (result != token_map.end())
{ {
return result->second; return id;
} }
return 0; const auto parsed_id = parse_token_id(name);
if (parsed_id)
{
return parsed_id;
}
return game::SL_GetCanonicalString(name.data());
}
script_function get_function_by_index(const std::uint32_t index)
{
static const auto function_table = &gsc::func_table;
static const auto method_table = SELECT_VALUE(0x14966A670, 0x147DD2F50);
if (index < 0x1000)
{
return reinterpret_cast<script_function*>(function_table)[index - 1];
}
return reinterpret_cast<script_function*>(method_table)[index - 0x8000];
} }
script_function find_function(const std::string& name, const bool prefer_global) script_function find_function(const std::string& name, const bool prefer_global)

View File

@ -3,14 +3,12 @@
namespace scripting namespace scripting
{ {
extern std::unordered_map<std::string, unsigned> method_map;
extern std::unordered_map<std::string, unsigned> function_map;
extern std::unordered_map<std::string, unsigned> token_map;
using script_function = void(*)(game::scr_entref_t); using script_function = void(*)(game::scr_entref_t);
std::string find_token(unsigned int id); std::string find_token(std::uint32_t id);
std::string find_token_single(std::uint32_t id);
unsigned int find_token_id(const std::string& name); unsigned int find_token_id(const std::string& name);
script_function find_function(const std::string& name, const bool prefer_global); script_function get_function_by_index(std::uint32_t index);
script_function find_function(const std::string& name, bool prefer_global);
} }

View File

@ -3,15 +3,17 @@
#include "error.hpp" #include "error.hpp"
#include "value_conversion.hpp" #include "value_conversion.hpp"
#include "../execution.hpp" #include "game/scripting/execution.hpp"
#include "../functions.hpp"
#include "../../../component/command.hpp" #include "component/command.hpp"
#include "../../../component/logfile.hpp" #include "component/notifies.hpp"
#include "../../../component/scripting.hpp" #include "component/scripting.hpp"
#include <utils/string.hpp> #include <utils/string.hpp>
#include <xsk/gsc/types.hpp>
#include <xsk/resolver.hpp>
namespace scripting::lua namespace scripting::lua
{ {
namespace namespace
@ -244,10 +246,10 @@ namespace scripting::lua
auto entity_type = state.new_usertype<entity>("entity"); auto entity_type = state.new_usertype<entity>("entity");
for (const auto& func : method_map) for (const auto& func : xsk::gsc::s1::resolver::get_methods())
{ {
const auto name = utils::string::to_lower(func.first); const auto name = std::string(func.first);
entity_type[name.data()] = [name](const entity& entity, const sol::this_state s, sol::variadic_args va) entity_type[name] = [name](const entity& entity, const sol::this_state s, sol::variadic_args va)
{ {
std::vector<script_value> arguments{}; std::vector<script_value> arguments{};
@ -376,9 +378,9 @@ namespace scripting::lua
auto game_type = state.new_usertype<game>("game_"); auto game_type = state.new_usertype<game>("game_");
state["game"] = game(); state["game"] = game();
for (const auto& func : function_map) for (const auto& func : xsk::gsc::s1::resolver::get_functions())
{ {
const auto name = utils::string::to_lower(func.first); const auto name = std::string(func.first);
game_type[name] = [name](const game&, const sol::this_state s, sol::variadic_args va) game_type[name] = [name](const game&, const sol::this_state s, sol::variadic_args va)
{ {
std::vector<script_value> arguments{}; std::vector<script_value> arguments{};
@ -424,12 +426,12 @@ namespace scripting::lua
game_type["onplayerdamage"] = [](const game&, const sol::protected_function& callback) game_type["onplayerdamage"] = [](const game&, const sol::protected_function& callback)
{ {
logfile::add_player_damage_callback(callback); notifies::add_player_damage_callback(callback);
}; };
game_type["onplayerkilled"] = [](const game&, const sol::protected_function& callback) game_type["onplayerkilled"] = [](const game&, const sol::protected_function& callback)
{ {
logfile::add_player_killed_callback(callback); notifies::add_player_killed_callback(callback);
}; };
game_type["getgamevar"] = [](const sol::this_state s) game_type["getgamevar"] = [](const sol::this_state s)
@ -455,43 +457,40 @@ namespace scripting::lua
for (const auto& function : scripting::script_function_table[filename]) for (const auto& function : scripting::script_function_table[filename])
{ {
functions[function.first] = sol::overload( functions[function.first] = sol::overload([filename, function](const entity& entity, const sol::this_state s, sol::variadic_args va)
[filename, function](const entity& entity, const sol::this_state s, sol::variadic_args va) {
std::vector<script_value> arguments{};
for (auto arg : va)
{ {
std::vector<script_value> arguments{}; arguments.push_back(convert({s, arg}));
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
gsl::finally(&logfile::enable_vm_execute_hook);
logfile::disable_vm_execute_hook();
return convert(s, call_script_function(entity, filename, function.first, arguments));
},
[filename, function](const sol::this_state s, sol::variadic_args va)
{
std::vector<script_value> arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
gsl::finally(&logfile::enable_vm_execute_hook);
logfile::disable_vm_execute_hook();
return convert(s, call_script_function(*::game::levelEntityId, filename, function.first, arguments));
} }
);
const auto _0 = gsl::finally(&notifies::enable_vm_execute_hook);
notifies::disable_vm_execute_hook();
return convert(s, call_script_function(entity, filename, function.first, arguments));
},
[filename, function](const sol::this_state s, sol::variadic_args va)
{
std::vector<script_value> arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
const auto _0 = gsl::finally(&notifies::enable_vm_execute_hook);
notifies::disable_vm_execute_hook();
return convert(s, call_script_function(*::game::levelEntityId, filename, function.first, arguments));
});
} }
return functions; return functions;
}; };
game_type["scriptcall"] = [](const game&, const sol::this_state s, const std::string& filename, game_type["scriptcall"] = [](const game&, const sol::this_state s, const std::string& filename, const std::string function, sol::variadic_args va)
const std::string function, sol::variadic_args va)
{ {
std::vector<script_value> arguments{}; std::vector<script_value> arguments{};
@ -500,8 +499,8 @@ namespace scripting::lua
arguments.push_back(convert({s, arg})); arguments.push_back(convert({s, arg}));
} }
gsl::finally(&logfile::enable_vm_execute_hook); const auto _0 = gsl::finally(&notifies::enable_vm_execute_hook);
logfile::disable_vm_execute_hook(); notifies::disable_vm_execute_hook();
return convert(s, call_script_function(*::game::levelEntityId, filename, function, arguments)); return convert(s, call_script_function(*::game::levelEntityId, filename, function, arguments));
}; };
@ -510,50 +509,48 @@ namespace scripting::lua
const std::string function_name, const sol::protected_function& function) const std::string function_name, const sol::protected_function& function)
{ {
const auto pos = get_function_pos(filename, function_name); const auto pos = get_function_pos(filename, function_name);
logfile::vm_execute_hooks[pos] = function; notifies::set_lua_hook(pos, function);
auto detour = sol::table::create(function.lua_state()); auto detour = sol::table::create(function.lua_state());
detour["disable"] = [pos]() detour["disable"] = [pos]
{ {
logfile::vm_execute_hooks.erase(pos); notifies::clear_hook(pos);
}; };
detour["enable"] = [pos, function]() detour["enable"] = [pos, function]
{ {
logfile::vm_execute_hooks[pos] = function; notifies::set_lua_hook(pos, function);
}; };
detour["invoke"] = sol::overload( detour["invoke"] = sol::overload([filename, function_name](const entity& entity, const sol::this_state s, sol::variadic_args va)
[filename, function_name](const entity& entity, const sol::this_state s, sol::variadic_args va) {
std::vector<script_value> arguments{};
for (auto arg : va)
{ {
std::vector<script_value> arguments{}; arguments.push_back(convert({s, arg}));
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
gsl::finally(&logfile::enable_vm_execute_hook);
logfile::disable_vm_execute_hook();
return convert(s, call_script_function(entity, filename, function_name, arguments));
},
[filename, function_name](const sol::this_state s, sol::variadic_args va)
{
std::vector<script_value> arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
gsl::finally(&logfile::enable_vm_execute_hook);
logfile::disable_vm_execute_hook();
return convert(s, call_script_function(*::game::levelEntityId, filename, function_name, arguments));
} }
);
const auto _0 = gsl::finally(&notifies::enable_vm_execute_hook);
notifies::disable_vm_execute_hook();
return convert(s, call_script_function(entity, filename, function_name, arguments));
},
[filename, function_name](const sol::this_state s, sol::variadic_args va)
{
std::vector<script_value> arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
const auto _0 = gsl::finally(&notifies::enable_vm_execute_hook);
notifies::disable_vm_execute_hook();
return convert(s, call_script_function(*::game::levelEntityId, filename, function_name, arguments));
});
return detour; return detour;
}; };

View File

@ -1,10 +1,11 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "engine.hpp" #include "engine.hpp"
#include "context.hpp" #include "context.hpp"
#include "game/scripting/execution.hpp"
#include "../execution.hpp" #include "component/notifies.hpp"
#include "../../../component/logfile.hpp" #include "component/game_module.hpp"
#include "../../../component/game_module.hpp"
#include <utils/io.hpp> #include <utils/io.hpp>
@ -39,7 +40,7 @@ namespace scripting::lua::engine
void stop() void stop()
{ {
logfile::clear_callbacks(); notifies::clear_callbacks();
get_scripts().clear(); get_scripts().clear();
} }

View File

@ -1,8 +1,9 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "value_conversion.hpp" #include "value_conversion.hpp"
#include "../functions.hpp"
#include "../execution.hpp" #include "game/scripting/functions.hpp"
#include ".../../component/logfile.hpp" #include "game/scripting/execution.hpp"
#include "component/notifies.hpp"
namespace scripting::lua namespace scripting::lua
{ {
@ -120,9 +121,8 @@ namespace scripting::lua
game::VariableValue convert_function(sol::lua_value value) game::VariableValue convert_function(sol::lua_value value)
{ {
const auto function = value.as<sol::protected_function>(); const auto function = value.as<sol::protected_function>();
const auto index = reinterpret_cast<char*>(logfile::vm_execute_hooks.size()); const auto index = reinterpret_cast<char*>(notifies::get_hook_count() + 1);
notifies::set_lua_hook(index, function);
logfile::vm_execute_hooks[index] = function;
game::VariableValue func; game::VariableValue func;
func.type = game::SCRIPT_FUNCTION; func.type = game::SCRIPT_FUNCTION;
@ -133,30 +133,28 @@ namespace scripting::lua
sol::lua_value convert_function(lua_State* state, const char* pos) sol::lua_value convert_function(lua_State* state, const char* pos)
{ {
return sol::overload( return sol::overload([pos](const entity& entity, const sol::this_state s, sol::variadic_args va)
[pos](const entity& entity, const sol::this_state s, sol::variadic_args va) {
std::vector<script_value> arguments{};
for (auto arg : va)
{ {
std::vector<script_value> arguments{}; arguments.push_back(convert({s, arg}));
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
return convert(s, exec_ent_thread(entity, pos, arguments));
},
[pos](const sol::this_state s, sol::variadic_args va)
{
std::vector<script_value> arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
return convert(s, exec_ent_thread(*game::levelEntityId, pos, arguments));
} }
);
return convert(s, exec_ent_thread(entity, pos, arguments));
},
[pos](const sol::this_state s, sol::variadic_args va)
{
std::vector<script_value> arguments{};
for (auto arg : va)
{
arguments.push_back(convert({s, arg}));
}
return convert(s, exec_ent_thread(*game::levelEntityId, pos, arguments));
});
} }
} }
@ -167,8 +165,7 @@ namespace scripting::lua
const auto offset = 64000 * (parent_id & 3); const auto offset = 64000 * (parent_id & 3);
metatable[sol::meta_function::new_index] = [offset, parent_id](const sol::table t, const sol::this_state s, metatable[sol::meta_function::new_index] = [offset, parent_id](const sol::table t, const sol::this_state s, const sol::lua_value& field, const sol::lua_value& value)
const sol::lua_value& field, const sol::lua_value& value)
{ {
const auto id = field.is<std::string>() const auto id = field.is<std::string>()
? scripting::find_token_id(field.as<std::string>()) ? scripting::find_token_id(field.as<std::string>())
@ -190,8 +187,7 @@ namespace scripting::lua
variable->u.u = new_variable.u; variable->u.u = new_variable.u;
}; };
metatable[sol::meta_function::index] = [offset, parent_id](const sol::table t, const sol::this_state s, metatable[sol::meta_function::index] = [offset, parent_id](const sol::table t, const sol::this_state s, const sol::lua_value& field)
const sol::lua_value& field)
{ {
const auto id = field.is<std::string>() const auto id = field.is<std::string>()
? scripting::find_token_id(field.as<std::string>()) ? scripting::find_token_id(field.as<std::string>())

View File

@ -22,6 +22,9 @@ namespace game
unsigned short classnum; unsigned short classnum;
}; };
typedef void(*BuiltinMethod)(scr_entref_t);
typedef void(*BuiltinFunction)();
enum scriptType_e enum scriptType_e
{ {
SCRIPT_NONE = 0, SCRIPT_NONE = 0,

View File

@ -24,12 +24,8 @@ namespace game
WEAK symbol<void(float, float, int)> Com_SetSlowMotion{0, 0x1403D19B0}; WEAK symbol<void(float, float, int)> Com_SetSlowMotion{0, 0x1403D19B0};
WEAK symbol<void()> Com_Quit_f{0x1402F9390, 0x1403D08C0}; WEAK symbol<void()> Com_Quit_f{0x1402F9390, 0x1403D08C0};
WEAK symbol<void(const char* cmdName, void (), cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{ WEAK symbol<void(const char* cmdName, void (), cmd_function_s* allocedCmd)> Cmd_AddCommandInternal{0x1402EDDB0, 0x1403AF2C0};
0x1402EDDB0, 0x1403AF2C0 WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{0x1402EE350, 0x1403AF900};
};
WEAK symbol<void(int localClientNum, int controllerIndex, const char* text)> Cmd_ExecuteSingleCommand{
0x1402EE350, 0x1403AF900
};
WEAK symbol<void(const char*)> Cmd_RemoveCommand{0x1402EE910, 0x1403AFEF0}; WEAK symbol<void(const char*)> Cmd_RemoveCommand{0x1402EE910, 0x1403AFEF0};
WEAK symbol<void(const char* text_in)> Cmd_TokenizeString{0x1402EEA30, 0x1403B0020}; WEAK symbol<void(const char* text_in)> Cmd_TokenizeString{0x1402EEA30, 0x1403B0020};
WEAK symbol<void()> Cmd_EndTokenizeString{0x1402EE000, 0x1403AF5B0}; WEAK symbol<void()> Cmd_EndTokenizeString{0x1402EE000, 0x1403AF5B0};
@ -40,10 +36,12 @@ namespace game
WEAK symbol<void(int localClientNum, void (*)(int localClientNum))> Cbuf_AddCall{0x1402ED820, 0x1403AECF0}; WEAK symbol<void(int localClientNum, void (*)(int localClientNum))> Cbuf_AddCall{0x1402ED820, 0x1403AECF0};
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x1402ED890, 0x1403AED70}; WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x1402ED890, 0x1403AED70};
WEAK symbol<void(int localClientNum, int controllerIndex, const char* buffer, WEAK symbol<void(int localClientNum, int controllerIndex, const char* buffer, void (int, int, const char*))> Cbuf_ExecuteBufferInternal{0x1402ED9A0, 0x1403AEE80};
void (int, int, const char*))> Cbuf_ExecuteBufferInternal{0x1402ED9A0, 0x1403AEE80};
WEAK symbol<bool()> CL_IsCgameInitialized{0x140136560, 0x1401FD510}; WEAK symbol<bool()> CL_IsCgameInitialized{0x140136560, 0x1401FD510};
WEAK symbol<void(int localClientNum, const char* string)> CL_ForwardCommandToServer{0x0, 0x14020B310};
WEAK symbol<void(int localClientNum)> CL_WritePacket{0x0, 0x1402058F0};
WEAK symbol<void(int localClientNum)> CL_Disconnect{0x0, 0x140209EC0};
WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessage{0x1400EE500, 0x1401A3050}; WEAK symbol<void(int localClientNum, const char* message)> CG_GameMessage{0x1400EE500, 0x1401A3050};
WEAK symbol<void(int localClientNum, /*mp::cg_s**/void* cg, const char* dvar, const char* value)> CG_SetClientDvarFromServer{0, 0x1401BF0A0}; WEAK symbol<void(int localClientNum, /*mp::cg_s**/void* cg, const char* dvar, const char* value)> CG_SetClientDvarFromServer{0, 0x1401BF0A0};
@ -59,6 +57,7 @@ namespace game
WEAK symbol<int(XAssetType type, const char* name)> DB_IsXAssetDefault{0x0, 0x140270320}; WEAK symbol<int(XAssetType type, const char* name)> DB_IsXAssetDefault{0x0, 0x140270320};
WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x0, 0x14026FCC0}; WEAK symbol<int(const RawFile* rawfile)> DB_GetRawFileLen{0x0, 0x14026FCC0};
WEAK symbol<void(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x0, 0x14026FB90}; WEAK symbol<void(const RawFile* rawfile, char* buf, int size)> DB_GetRawBuffer{0x0, 0x14026FB90};
WEAK symbol<char*(const char* filename, char* buf, int size)> DB_ReadRawFile{0x140180E30, 0x140273080};
WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x140370860, 0x1404BF8B0}; WEAK symbol<dvar_t*(const char* name)> Dvar_FindVar{0x140370860, 0x1404BF8B0};
WEAK symbol<void(const dvar_t* dvar)> Dvar_ClearModified{0x140370700, 0x1404BF690}; WEAK symbol<void(const dvar_t* dvar)> Dvar_ClearModified{0x140370700, 0x1404BF690};
@ -67,9 +66,7 @@ namespace game
WEAK symbol<void(dvar_t* dvar, DvarSetSource source)> Dvar_Reset{0x140372950, 0x1404C1DB0}; WEAK symbol<void(dvar_t* dvar, DvarSetSource source)> Dvar_Reset{0x140372950, 0x1404C1DB0};
WEAK symbol<void(const char* dvar, const char* buffer)> Dvar_SetCommand{0x1403730D0, 0x1404C2520}; WEAK symbol<void(const char* dvar, const char* buffer)> Dvar_SetCommand{0x1403730D0, 0x1404C2520};
WEAK symbol<void(dvar_t* dvar, const char* string)> Dvar_SetString{0x140373DE0, 0x1404C3610}; WEAK symbol<void(dvar_t* dvar, const char* string)> Dvar_SetString{0x140373DE0, 0x1404C3610};
WEAK symbol<void(const char*, const char*, DvarSetSource)> Dvar_SetFromStringByNameFromSource{ WEAK symbol<void(const char*, const char*, DvarSetSource)> Dvar_SetFromStringByNameFromSource{0x1403737D0, 0x1404C2E40};
0x1403737D0, 0x1404C2E40
};
WEAK symbol<const char*(dvar_t* dvar, dvar_value value)> Dvar_ValueToString{0x140374E10, 0x1404C47B0}; WEAK symbol<const char*(dvar_t* dvar, dvar_value value)> Dvar_ValueToString{0x140374E10, 0x1404C47B0};
WEAK symbol<dvar_t*(const char* dvarName, bool value, unsigned int flags, const char* description)> WEAK symbol<dvar_t*(const char* dvarName, bool value, unsigned int flags, const char* description)>
@ -101,9 +98,7 @@ namespace game
WEAK symbol<unsigned int(unsigned int parentId, unsigned int name)> FindVariable{0x1403165D0, 0x1403F2DC0}; WEAK symbol<unsigned int(unsigned int parentId, unsigned int name)> FindVariable{0x1403165D0, 0x1403F2DC0};
WEAK symbol<unsigned int(int entnum, unsigned int classnum)> FindEntityId{0x1403166D0, 0x1403F2CC0}; WEAK symbol<unsigned int(int entnum, unsigned int classnum)> FindEntityId{0x1403166D0, 0x1403F2CC0};
WEAK symbol<scr_string_t(unsigned int parentId, unsigned int id)> GetVariableName{0x1403170E0, 0x1403F37F0}; WEAK symbol<scr_string_t(unsigned int parentId, unsigned int id)> GetVariableName{0x1403170E0, 0x1403F37F0};
WEAK symbol<void(VariableValue* result, unsigned int classnum, int entnum, int offset)> GetEntityFieldValue{ WEAK symbol<void(VariableValue* result, unsigned int classnum, int entnum, int offset)> GetEntityFieldValue{0x14031AAD0, 0x1403F72A0};
0x14031AAD0, 0x1403F72A0
};
WEAK symbol<unsigned int(unsigned int)> GetObjectType{0x140316F70, 0x1403F3670}; WEAK symbol<unsigned int(unsigned int)> GetObjectType{0x140316F70, 0x1403F3670};
WEAK symbol<unsigned int(unsigned int, unsigned int)> GetVariable{0x0, 0x1403F3730}; WEAK symbol<unsigned int(unsigned int, unsigned int)> GetVariable{0x0, 0x1403F3730};
@ -111,9 +106,7 @@ namespace game
WEAK symbol<int(int clientNum)> G_GetClientScore{0, 0x1402F6AB0}; WEAK symbol<int(int clientNum)> G_GetClientScore{0, 0x1402F6AB0};
WEAK symbol<unsigned int(const char* name)> G_GetWeaponForName{0x140274590, 0x14033FF60}; WEAK symbol<unsigned int(const char* name)> G_GetWeaponForName{0x140274590, 0x14033FF60};
WEAK symbol<int(playerState_s* ps, unsigned int weapon, int dualWield, int startInAltMode, int, int, int, char, WEAK symbol<int(playerState_s* ps, unsigned int weapon, int dualWield, int startInAltMode, int, int, int, char)> G_GivePlayerWeapon{0x1402749B0, 0x140340470};
...)>
G_GivePlayerWeapon{0x1402749B0, 0x140340470};
WEAK symbol<void(playerState_s* ps, unsigned int weapon, int hadWeapon)> G_InitializeAmmo{0x1402217F0, 0x1402F22B0}; WEAK symbol<void(playerState_s* ps, unsigned int weapon, int hadWeapon)> G_InitializeAmmo{0x1402217F0, 0x1402F22B0};
WEAK symbol<void(int clientNum, unsigned int weapon)> G_SelectWeapon{0x140275380, 0x140340D50}; WEAK symbol<void(int clientNum, unsigned int weapon)> G_SelectWeapon{0x140275380, 0x140340D50};
WEAK symbol<int(playerState_s* ps, unsigned int weapon)> G_TakePlayerWeapon{0x1402754E0, 0x1403411D0}; WEAK symbol<int(playerState_s* ps, unsigned int weapon)> G_TakePlayerWeapon{0x1402754E0, 0x1403411D0};
@ -161,6 +154,7 @@ namespace game
WEAK symbol<scr_entref_t(unsigned int entId)> Scr_GetEntityIdRef{0x14031A0D0, 0x1403F68A0}; WEAK symbol<scr_entref_t(unsigned int entId)> Scr_GetEntityIdRef{0x14031A0D0, 0x1403F68A0};
WEAK symbol<int(unsigned int classnum, int entnum, int offset)> Scr_SetObjectField{0x14026B620, 0x140339450}; WEAK symbol<int(unsigned int classnum, int entnum, int offset)> Scr_SetObjectField{0x14026B620, 0x140339450};
WEAK symbol<void(unsigned int id, scr_string_t stringValue, unsigned int paramcount)> Scr_NotifyId{0x14031CB80, 0x1403F92D0}; WEAK symbol<void(unsigned int id, scr_string_t stringValue, unsigned int paramcount)> Scr_NotifyId{0x14031CB80, 0x1403F92D0};
WEAK symbol<bool(VariableValue* value)> Scr_CastString{0x0, 0x1403F4500};
WEAK symbol<unsigned __int16(int handle, unsigned int paramcount)> Scr_ExecThread{0x0, 0x1403F8120}; WEAK symbol<unsigned __int16(int handle, unsigned int paramcount)> Scr_ExecThread{0x0, 0x1403F8120};
WEAK symbol<unsigned int(const char* name)> Scr_LoadScript{0x0, 0x1403EE250}; WEAK symbol<unsigned int(const char* name)> Scr_LoadScript{0x0, 0x1403EE250};
@ -168,10 +162,12 @@ namespace game
WEAK symbol<unsigned int(void* func, int type, unsigned int name)> Scr_RegisterFunction{0x1403115B0, 0x1403EDAE0}; WEAK symbol<unsigned int(void* func, int type, unsigned int name)> Scr_RegisterFunction{0x1403115B0, 0x1403EDAE0};
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x0, 0x1403F9E40}; WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x0, 0x1403F9E40};
WEAK symbol<void()> Scr_ErrorInternal{0x0, 0x1403F80A0};
WEAK symbol<const char*(scr_string_t stringValue)> SL_ConvertToString{0x140314850, 0x1403F0F10}; WEAK symbol<const char*(scr_string_t stringValue)> SL_ConvertToString{0x140314850, 0x1403F0F10};
WEAK symbol<scr_string_t(const char* str)> SL_FindString{0x140314AF0, 0x1403F11C0}; WEAK symbol<scr_string_t(const char* str)> SL_FindString{0x140314AF0, 0x1403F11C0};
WEAK symbol<scr_string_t(const char* str, unsigned int user)> SL_GetString{0x140314D90, 0x1403F1440}; WEAK symbol<scr_string_t(const char* str, unsigned int user)> SL_GetString{0x140314D90, 0x1403F1440};
WEAK symbol<unsigned int(char const* str)> SL_GetCanonicalString{0x140311770, 0x1403EDCA0};
WEAK symbol<void(int arg, char* buffer, int bufferLength)> SV_Cmd_ArgvBuffer{0x1402EEFD0, 0x1403B05C0}; WEAK symbol<void(int arg, char* buffer, int bufferLength)> SV_Cmd_ArgvBuffer{0x1402EEFD0, 0x1403B05C0};
WEAK symbol<void(const char* text_in)> SV_Cmd_TokenizeString{0, 0x1403B0640}; WEAK symbol<void(const char* text_in)> SV_Cmd_TokenizeString{0, 0x1403B0640};
@ -254,6 +250,8 @@ namespace game
WEAK symbol<SOCKET> query_socket{0, 0x14B5B9180}; WEAK symbol<SOCKET> query_socket{0, 0x14B5B9180};
WEAK symbol<int> level_time{0x0, 0x144959C2C};
WEAK symbol<void*> DB_XAssetPool{0x140804690, 0x1409B40D0}; WEAK symbol<void*> DB_XAssetPool{0x140804690, 0x1409B40D0};
WEAK symbol<unsigned int> db_hashTable{0x142C3E050, 0x143716B10}; WEAK symbol<unsigned int> db_hashTable{0x142C3E050, 0x143716B10};
WEAK symbol<XAssetEntry> g_assetEntryPool{0x142CC2400, 0x14379F100}; WEAK symbol<XAssetEntry> g_assetEntryPool{0x142CC2400, 0x14379F100};

View File

@ -1,10 +1,7 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "execution.hpp" #include "execution.hpp"
#include "component/ui_scripting.hpp"
#include "component/console.hpp" #include "component/console.hpp"
#include <utils/string.hpp>
namespace ui_scripting namespace ui_scripting
{ {
namespace namespace

View File

@ -2,7 +2,6 @@
#include "execution.hpp" #include "execution.hpp"
#include "types.hpp" #include "types.hpp"
#include "script_value.hpp" #include "script_value.hpp"
#include "../../component/ui_scripting.hpp"
namespace ui_scripting namespace ui_scripting
{ {

View File

@ -55,6 +55,7 @@
#undef min #undef min
#endif #endif
#include <ranges>
#include <map> #include <map>
#include <atomic> #include <atomic>
#include <vector> #include <vector>
@ -72,6 +73,7 @@
#include <optional> #include <optional>
#include <unordered_set> #include <unordered_set>
#include <variant> #include <variant>
#include <format>
#include <gsl/gsl> #include <gsl/gsl>
#include <udis86.h> #include <udis86.h>