2023-12-08 17:16:22 +01:00

89 lines
2.3 KiB
C++

#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
namespace gsc {
namespace {
std::vector<int> main_handles;
std::vector<int> init_handles;
// Do not use C++ objects because Scr_LoadScript may longjmp
void g_scr_load_scripts_stub() {
// Clear handles (from previous GSC loading session)
main_handles.clear();
init_handles.clear();
char path[MAX_PATH]{};
auto num_files = 0;
const auto** files =
game::FS_ListFiles("scripts/", "gsc", game::FS_LIST_ALL, &num_files, 10);
for (auto i = 0; i < num_files; ++i) {
const auto* script_file = files[i];
game::Com_Printf(game::CON_CHANNEL_SERVER, "Loading script %s...\n",
script_file);
const auto len = sprintf_s(path, "%s/%s", "scripts", script_file);
if (len == -1) {
continue;
}
// Scr_LoadScriptInternal will add the '.gsc' suffix so we remove it
path[len - 4] = '\0';
if (!game::Scr_LoadScript(path)) {
game::Com_Printf(game::CON_CHANNEL_SERVER,
"Script %s encountered an error while loading\n", path);
continue;
}
game::Com_Printf(game::CON_CHANNEL_SERVER,
"Script %s.gsc loaded successfully\n", path);
const auto main_handle = game::Scr_GetFunctionHandle(path, "main");
if (main_handle) {
main_handles.push_back(main_handle);
}
const auto init_handle = game::Scr_GetFunctionHandle(path, "init");
if (init_handle) {
init_handles.push_back(init_handle);
}
// Allow scripts with no handles
}
game::FS_FreeFileList(files, 10);
}
void scr_load_level_stub() {
for (const auto& handle : main_handles) {
const auto id = game::Scr_ExecThread(handle, 0);
game::Scr_FreeThread(static_cast<std::uint16_t>(id));
}
utils::hook::invoke<void>(0x470860); // Scr_LoadLevel
for (const auto& handle : init_handles) {
const auto id = game::Scr_ExecThread(handle, 0);
game::Scr_FreeThread(static_cast<std::uint16_t>(id));
}
}
} // namespace
class loading final : public component_interface {
public:
void post_load() override {
utils::hook(0x4054C2, g_scr_load_scripts_stub, HOOK_JUMP)
.install()
->quick();
utils::hook(0x4C1E34, scr_load_level_stub, HOOK_CALL).install()->quick();
}
};
} // namespace gsc
REGISTER_COMPONENT(gsc::loading)