2023-03-01 00:54:41 -05:00
|
|
|
#include <std_include.hpp>
|
|
|
|
#include "loader/component_loader.hpp"
|
|
|
|
#include "game/game.hpp"
|
|
|
|
|
|
|
|
#include "scheduler.hpp"
|
|
|
|
|
|
|
|
#include <utils/hook.hpp>
|
|
|
|
#include <utils/string.hpp>
|
|
|
|
#include <utils/io.hpp>
|
|
|
|
|
|
|
|
namespace script
|
|
|
|
{
|
|
|
|
namespace
|
2023-02-28 17:58:07 -05:00
|
|
|
{
|
|
|
|
utils::hook::detour db_findxassetheader_hook;
|
|
|
|
|
|
|
|
struct globals_t
|
|
|
|
{
|
|
|
|
std::unordered_map<std::string, game::RawFile*> loaded_scripts;
|
|
|
|
};
|
|
|
|
|
|
|
|
globals_t globals;
|
|
|
|
|
|
|
|
game::RawFile* get_loaded_script(const std::string& name)
|
|
|
|
{
|
|
|
|
const auto itr = globals.loaded_scripts.find(name);
|
2023-03-01 00:54:41 -05:00
|
|
|
return (itr == globals.loaded_scripts.end()) ? nullptr : itr->second;
|
2023-02-28 17:58:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void print_loading_script(const std::string& name)
|
|
|
|
{
|
|
|
|
printf("Loading GSC script '%s'\n", name.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
void load_script(std::string& name, const std::string& data)
|
|
|
|
{
|
|
|
|
auto& allocator = *utils::memory::get_allocator();
|
2023-03-01 00:54:41 -05:00
|
|
|
const auto* file_string = allocator.duplicate_string(data);
|
2023-02-28 17:58:07 -05:00
|
|
|
|
|
|
|
const utils::nt::library host{};
|
2023-03-01 00:54:41 -05:00
|
|
|
const auto appdata_path = (game::get_appdata_path() / "data/").generic_string();
|
|
|
|
const auto host_path = (host.get_folder() / "boiii/").generic_string();
|
|
|
|
|
|
|
|
auto i = name.find(appdata_path);
|
2023-02-28 17:58:07 -05:00
|
|
|
if (i != std::string::npos)
|
2023-03-01 00:54:41 -05:00
|
|
|
{
|
2023-02-28 17:58:07 -05:00
|
|
|
name.erase(i, appdata_path.length());
|
2023-03-01 00:54:41 -05:00
|
|
|
}
|
|
|
|
|
2023-02-28 17:58:07 -05:00
|
|
|
i = name.find(host_path);
|
|
|
|
if (i != std::string::npos)
|
2023-03-01 00:54:41 -05:00
|
|
|
{
|
2023-02-28 17:58:07 -05:00
|
|
|
name.erase(i, host_path.length());
|
2023-03-01 00:54:41 -05:00
|
|
|
}
|
2023-02-28 17:58:07 -05:00
|
|
|
|
2023-03-01 00:54:41 -05:00
|
|
|
auto* rawfile = allocator.allocate<game::RawFile>();
|
2023-02-28 17:58:07 -05:00
|
|
|
rawfile->name = name.c_str();
|
|
|
|
rawfile->buffer = file_string;
|
2023-02-28 18:13:25 -05:00
|
|
|
rawfile->len = static_cast<int>(data.length());
|
2023-02-28 17:58:07 -05:00
|
|
|
|
|
|
|
globals.loaded_scripts[name] = rawfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
void load_scripts_folder(const std::string& script_dir)
|
|
|
|
{
|
|
|
|
if (!utils::io::directory_exists(script_dir))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto scripts = utils::io::list_files(script_dir);
|
|
|
|
|
|
|
|
for (const auto& script : scripts)
|
|
|
|
{
|
|
|
|
std::string data;
|
|
|
|
auto script_file = script.generic_string();
|
|
|
|
if (!std::filesystem::is_directory(script) && utils::io::read_file(script_file, &data))
|
|
|
|
{
|
|
|
|
print_loading_script(script_file);
|
|
|
|
load_script(script_file, data);
|
|
|
|
}
|
|
|
|
else if (std::filesystem::is_directory(script))
|
|
|
|
{
|
|
|
|
load_scripts_folder(script_file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void load_scripts()
|
|
|
|
{
|
|
|
|
globals = {};
|
|
|
|
const utils::nt::library host{};
|
|
|
|
load_scripts_folder((game::get_appdata_path() / "data/scripts").string());
|
|
|
|
load_scripts_folder((host.get_folder() / "boiii/scripts").string());
|
|
|
|
}
|
|
|
|
|
2023-03-01 00:54:41 -05:00
|
|
|
game::RawFile* db_findxassetheader_stub(game::XAssetType type, const char* name, bool errorIfMissing,
|
|
|
|
int waitTime)
|
2023-02-28 17:58:07 -05:00
|
|
|
{
|
|
|
|
if (type != game::ASSET_TYPE_SCRIPTPARSETREE)
|
|
|
|
{
|
|
|
|
return db_findxassetheader_hook.invoke<game::RawFile*>(type, name, errorIfMissing, waitTime);
|
|
|
|
}
|
|
|
|
|
2023-03-01 00:54:41 -05:00
|
|
|
auto* asset_header = db_findxassetheader_hook.invoke<game::RawFile*>(type, name, errorIfMissing, waitTime);
|
2023-02-28 17:58:07 -05:00
|
|
|
if (globals.loaded_scripts.contains(name))
|
|
|
|
{
|
2023-03-01 00:54:41 -05:00
|
|
|
auto* script = get_loaded_script(name);
|
2023-02-28 17:58:07 -05:00
|
|
|
|
2023-03-01 00:54:41 -05:00
|
|
|
// Copy over the checksum of the original script
|
|
|
|
utils::hook::copy(const_cast<char*>(script->buffer + 0x8), asset_header->buffer + 0x8, 4);
|
2023-02-28 17:58:07 -05:00
|
|
|
|
|
|
|
return script;
|
|
|
|
}
|
|
|
|
|
|
|
|
return asset_header;
|
|
|
|
}
|
|
|
|
}
|
2023-03-01 00:54:41 -05:00
|
|
|
|
|
|
|
struct component final : generic_component
|
|
|
|
{
|
|
|
|
void post_unpack() override
|
2023-02-28 17:58:07 -05:00
|
|
|
{
|
|
|
|
if (game::is_server())
|
|
|
|
{
|
|
|
|
load_scripts();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
scheduler::once(load_scripts, scheduler::pipeline::renderer);
|
|
|
|
}
|
|
|
|
|
2023-03-01 00:54:41 -05:00
|
|
|
db_findxassetheader_hook.create(game::select(0x141420ED0, 0x1401D5FB0), db_findxassetheader_stub);
|
|
|
|
}
|
2023-02-28 17:58:07 -05:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
REGISTER_COMPONENT(script::component)
|