89 lines
2.3 KiB
C++
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)
|