mirror of
https://github.com/XLabsProject/s1x-client.git
synced 2023-08-02 15:02:12 +02:00
commit
34c4f99c4e
11
.github/workflows/build.yml
vendored
11
.github/workflows/build.yml
vendored
@ -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
1
.gitmodules
vendored
@ -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
2
deps/GSL
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 991fa6682e819590c695f00c6b880548e55fa914
|
Subproject commit 9c4212aca46fb4fe5bda2921c2269d35d6d1860f
|
2
deps/asmjit
vendored
2
deps/asmjit
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 15a603661871b86c048e697f0e6cd17374dcecc0
|
Subproject commit 8f2c237b8315a7d662e0e67d06807296a7bbe5ab
|
2
deps/gsc-tool
vendored
2
deps/gsc-tool
vendored
@ -1 +1 @@
|
|||||||
Subproject commit e5d6196da194457ba01cc94674a83da802b769ca
|
Subproject commit 842f168a67878f18ea6a42b9d3ce56ff9fafff0d
|
2
deps/libtommath
vendored
2
deps/libtommath
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 96f9edf9aaf145c6ecf5225eea3f5e86a0f26935
|
Subproject commit 03de03dee753442d4b23166982514639c4ccbc39
|
2
deps/lua
vendored
2
deps/lua
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 26be27459b11feabed52cf40aaa76f86c7edc977
|
Subproject commit c954db39241a8b21d7b32b42b87a066b4708f969
|
@ -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);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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>();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
116
src/client/component/game_log.cpp
Normal file
116
src/client/component/game_log.cpp
Normal 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)
|
6
src/client/component/game_log.hpp
Normal file
6
src/client/component/game_log.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace game_log
|
||||||
|
{
|
||||||
|
void g_log_printf(const char* fmt, ...);
|
||||||
|
}
|
148
src/client/component/gsc/script_error.cpp
Normal file
148
src/client/component/gsc/script_error.cpp
Normal 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)
|
6
src/client/component/gsc/script_error.hpp
Normal file
6
src/client/component/gsc/script_error.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace gsc
|
||||||
|
{
|
||||||
|
std::optional<std::pair<std::string, std::string>> find_function(const char* pos);
|
||||||
|
}
|
@ -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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
12
src/client/component/gsc/script_extension.hpp
Normal file
12
src/client/component/gsc/script_extension.hpp
Normal 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);
|
||||||
|
}
|
@ -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);
|
||||||
|
6
src/client/component/gsc/script_loading.hpp
Normal file
6
src/client/component/gsc/script_loading.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace gsc
|
||||||
|
{
|
||||||
|
game::ScriptFile* find_script(game::XAssetType type, const char* name, int allow_create_default);
|
||||||
|
}
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 = ' ');
|
||||||
|
@ -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)
|
@ -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);
|
@ -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');
|
||||||
});
|
});
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
@ -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)
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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(¬ifies::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(¬ifies::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(¬ifies::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(¬ifies::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(¬ifies::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;
|
||||||
};
|
};
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>())
|
||||||
|
@ -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,
|
||||||
|
@ -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};
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user