2022-01-27 18:51:44 -05:00
|
|
|
#include <std_include.hpp>
|
|
|
|
#include "loader/component_loader.hpp"
|
|
|
|
|
|
|
|
#include "game/game.hpp"
|
|
|
|
|
|
|
|
#include "command.hpp"
|
2022-06-17 14:22:12 -04:00
|
|
|
#include "console.hpp"
|
2022-01-27 18:51:44 -05:00
|
|
|
#include "scheduler.hpp"
|
2022-03-19 18:06:00 -04:00
|
|
|
#include "filesystem.hpp"
|
|
|
|
#include "materials.hpp"
|
|
|
|
#include "fonts.hpp"
|
2022-03-21 13:39:51 -04:00
|
|
|
#include "mods.hpp"
|
2022-06-28 06:06:04 -04:00
|
|
|
#include "mapents.hpp"
|
2022-07-15 18:29:44 -04:00
|
|
|
#include "localized_strings.hpp"
|
2022-07-18 13:20:09 -04:00
|
|
|
#include "loadscreen.hpp"
|
2022-07-31 17:59:01 -04:00
|
|
|
#include "sound.hpp"
|
2022-01-27 18:51:44 -05:00
|
|
|
|
|
|
|
#include <utils/hook.hpp>
|
|
|
|
#include <utils/io.hpp>
|
|
|
|
|
|
|
|
namespace mods
|
|
|
|
{
|
2022-03-21 13:39:51 -04:00
|
|
|
std::string mod_path{};
|
|
|
|
|
2022-03-19 18:06:00 -04:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
utils::hook::detour db_release_xassets_hook;
|
2022-03-20 14:40:15 -04:00
|
|
|
bool release_assets = false;
|
|
|
|
|
2022-03-19 18:06:00 -04:00
|
|
|
void db_release_xassets_stub()
|
|
|
|
{
|
2022-03-20 14:40:15 -04:00
|
|
|
if (release_assets)
|
|
|
|
{
|
|
|
|
materials::clear();
|
|
|
|
fonts::clear();
|
2022-06-28 06:33:49 -04:00
|
|
|
mapents::clear_dvars();
|
2022-07-18 13:20:09 -04:00
|
|
|
loadscreen::clear();
|
2022-03-20 14:40:15 -04:00
|
|
|
}
|
|
|
|
|
2022-06-28 06:06:04 -04:00
|
|
|
mapents::clear();
|
2022-07-15 18:29:44 -04:00
|
|
|
localized_strings::clear();
|
2022-07-31 17:59:01 -04:00
|
|
|
sound::clear();
|
2022-06-28 06:06:04 -04:00
|
|
|
|
2022-03-19 18:06:00 -04:00
|
|
|
db_release_xassets_hook.invoke<void>();
|
|
|
|
}
|
|
|
|
|
|
|
|
void restart()
|
|
|
|
{
|
|
|
|
scheduler::once([]()
|
|
|
|
{
|
2022-03-20 14:40:15 -04:00
|
|
|
release_assets = true;
|
2022-07-13 22:10:28 -04:00
|
|
|
const auto _0 = gsl::finally([]()
|
|
|
|
{
|
|
|
|
release_assets = false;
|
|
|
|
});
|
|
|
|
|
2022-03-19 18:06:00 -04:00
|
|
|
game::Com_Shutdown("");
|
|
|
|
}, scheduler::pipeline::main);
|
|
|
|
}
|
2022-08-21 19:42:13 -04:00
|
|
|
|
|
|
|
void full_restart(const std::string& arg)
|
|
|
|
{
|
|
|
|
utils::nt::relaunch_self(" -singleplayer "s.append(arg), true);
|
|
|
|
utils::nt::terminate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool mod_requires_restart(const std::string& path)
|
|
|
|
{
|
|
|
|
return utils::io::file_exists(path + "/mod.ff") || utils::io::file_exists(path + "/zone/mod.ff");
|
2022-03-19 18:06:00 -04:00
|
|
|
}
|
|
|
|
|
2022-01-27 18:51:44 -05:00
|
|
|
class component final : public component_interface
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void post_unpack() override
|
|
|
|
{
|
|
|
|
if (!utils::io::directory_exists("mods"))
|
|
|
|
{
|
|
|
|
utils::io::create_directory("mods");
|
|
|
|
}
|
|
|
|
|
2022-03-19 18:06:00 -04:00
|
|
|
db_release_xassets_hook.create(0x140416A80, db_release_xassets_stub);
|
|
|
|
|
2022-01-27 18:51:44 -05:00
|
|
|
command::add("loadmod", [](const command::params& params)
|
|
|
|
{
|
|
|
|
if (params.size() < 2)
|
|
|
|
{
|
2022-06-17 14:22:12 -04:00
|
|
|
console::info("Usage: loadmod mods/<modname>");
|
2022-01-27 18:51:44 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-19 18:06:00 -04:00
|
|
|
if (!game::Com_InFrontend())
|
2022-01-27 18:51:44 -05:00
|
|
|
{
|
2022-06-17 14:22:12 -04:00
|
|
|
console::error("Cannot load mod while in-game!\n");
|
2022-01-27 18:51:44 -05:00
|
|
|
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto path = params.get(1);
|
|
|
|
if (!utils::io::directory_exists(path))
|
|
|
|
{
|
2022-06-17 14:22:12 -04:00
|
|
|
console::error("Mod %s not found!\n", path);
|
2022-01-27 18:51:44 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-17 14:22:12 -04:00
|
|
|
console::info("Loading mod %s\n", path);
|
2022-08-21 19:42:13 -04:00
|
|
|
|
|
|
|
if (mod_requires_restart(mod_path) || mod_requires_restart(path))
|
|
|
|
{
|
|
|
|
// vid_restart is still broken :(
|
|
|
|
console::info("Restarting...\n");
|
|
|
|
full_restart("-mod "s + path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
filesystem::unregister_path(mod_path);
|
|
|
|
filesystem::register_path(path);
|
|
|
|
mod_path = path;
|
|
|
|
restart();
|
|
|
|
}
|
2022-01-27 18:51:44 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
command::add("unloadmod", [](const command::params& params)
|
|
|
|
{
|
2022-03-21 13:39:51 -04:00
|
|
|
if (mod_path.empty())
|
2022-01-27 18:51:44 -05:00
|
|
|
{
|
2022-06-17 14:22:12 -04:00
|
|
|
console::info("No mod loaded\n");
|
2022-01-27 18:51:44 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-03-19 18:06:00 -04:00
|
|
|
if (!game::Com_InFrontend())
|
2022-01-27 18:51:44 -05:00
|
|
|
{
|
2022-06-17 14:22:12 -04:00
|
|
|
console::error("Cannot unload mod while in-game!\n");
|
2022-01-27 18:51:44 -05:00
|
|
|
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-06-17 14:22:12 -04:00
|
|
|
console::info("Unloading mod %s\n", mod_path.data());
|
2022-08-21 19:42:13 -04:00
|
|
|
|
|
|
|
if (mod_requires_restart(mod_path))
|
|
|
|
{
|
|
|
|
console::info("Restarting...\n");
|
|
|
|
full_restart("");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
filesystem::unregister_path(mod_path);
|
|
|
|
mod_path.clear();
|
|
|
|
restart();
|
|
|
|
}
|
2022-01-27 18:51:44 -05:00
|
|
|
});
|
2022-07-13 22:10:28 -04:00
|
|
|
|
|
|
|
command::add("com_restart", []()
|
|
|
|
{
|
|
|
|
if (!game::Com_InFrontend())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
restart();
|
|
|
|
});
|
2022-01-27 18:51:44 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
REGISTER_COMPONENT(mods::component)
|