h1-mod/src/client/component/mods.cpp

209 lines
4.2 KiB
C++
Raw Normal View History

2022-04-08 10:18:00 -04:00
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/game.hpp"
#include "command.hpp"
#include "console.hpp"
#include "dvars.hpp"
2022-04-08 10:18:00 -04:00
#include "filesystem.hpp"
#include "fonts.hpp"
#include "localized_strings.hpp"
#include "materials.hpp"
2022-04-08 10:18:00 -04:00
#include "mods.hpp"
#include "scheduler.hpp"
2022-04-08 10:18:00 -04:00
#include <utils/hook.hpp>
#include <utils/io.hpp>
namespace mods
{
2022-12-22 12:07:51 -05:00
std::optional<std::string> mod_path;
2022-04-08 10:18:00 -04:00
namespace
{
utils::hook::detour db_release_xassets_hook;
bool release_assets = false;
void db_release_xassets_stub()
{
if (release_assets)
{
materials::clear();
fonts::clear();
}
db_release_xassets_hook.invoke<void>();
}
void restart()
{
scheduler::once([]()
{
release_assets = true;
const auto _0 = gsl::finally([]()
{
release_assets = false;
});
2022-04-08 10:18:00 -04:00
game::Com_Shutdown("");
}, scheduler::pipeline::main);
}
void full_restart(const std::string& arg)
{
2022-12-22 12:07:51 -05:00
if (game::environment::is_mp())
{
command::execute("vid_restart");
return;
}
auto mode = game::environment::is_mp() ? " -multiplayer "s : " -singleplayer "s;
utils::nt::relaunch_self(mode.append(arg), true);
utils::nt::terminate();
}
2022-12-22 12:33:44 -05:00
bool mod_requires_restart(const std::string& path)
2022-12-22 12:07:51 -05:00
{
2022-12-22 12:33:44 -05:00
return utils::io::file_exists(path + "/mod.ff") || utils::io::file_exists(path + "/zone/mod.ff");
2022-12-22 12:07:51 -05:00
}
void set_filesystem_data(const std::string& path, bool change_fs_game)
2022-12-22 12:07:51 -05:00
{
2022-12-22 12:33:44 -05:00
if (mod_path.has_value())
{
filesystem::unregister_path(mod_path.value());
}
if (change_fs_game)
2022-12-22 12:33:44 -05:00
{
game::Dvar_SetFromStringByNameFromSource("fs_game", path.data(), game::DVAR_SOURCE_INTERNAL);
}
if (path != "")
{
filesystem::register_path(path);
2022-12-22 12:33:44 -05:00
}
2022-12-22 12:07:51 -05:00
}
}
void set_mod(const std::string& path, bool change_fs_game)
2022-12-22 12:07:51 -05:00
{
set_filesystem_data(path, change_fs_game);
2022-12-22 12:07:51 -05:00
if (path != "")
{
mod_path = path;
}
else
{
mod_path.reset();
}
2022-12-22 12:07:51 -05:00
}
std::optional<std::string> get_mod()
{
return mod_path;
}
2022-04-08 10:18:00 -04:00
class component final : public component_interface
{
public:
void post_unpack() override
{
if (!utils::io::directory_exists("mods"))
{
utils::io::create_directory("mods");
}
2022-05-29 11:53:39 -04:00
db_release_xassets_hook.create(SELECT_VALUE(0x1F4DB0_b, 0x399740_b), db_release_xassets_stub);
2022-04-08 10:18:00 -04:00
dvars::callback::on_new_value("fs_game", [](game::dvar_value* value)
{
console::warn("fs_game value changed to '%s'\n", value->string);
set_mod(value->string, false);
});
2022-04-08 10:18:00 -04:00
command::add("loadmod", [](const command::params& params)
{
if (params.size() < 2)
{
console::info("Usage: loadmod mods/<modname>");
return;
}
2022-09-03 06:06:45 -04:00
if (!game::Com_InFrontend() && (game::environment::is_mp() && !game::VirtualLobby_Loaded()))
2022-04-08 10:18:00 -04:00
{
console::info("Cannot load mod while in-game!\n");
game::CG_GameMessage(0, "^1Cannot load mod while in-game!");
2022-04-08 10:18:00 -04:00
return;
}
const auto path = params.get(1);
if (!utils::io::directory_exists(path))
{
console::info("Mod %s not found!\n", path);
return;
}
console::info("Loading mod %s\n", path);
2022-12-22 12:07:51 -05:00
set_mod(path);
2022-12-22 12:07:51 -05:00
if ((mod_path.has_value() && mod_requires_restart(mod_path.value())) ||
mod_requires_restart(path))
{
console::info("Restarting...\n");
full_restart("-mod \""s + path + "\"");
}
else
{
restart();
}
2022-04-08 10:18:00 -04:00
});
command::add("unloadmod", [](const command::params& params)
{
2022-12-22 12:07:51 -05:00
if (!mod_path.has_value())
2022-04-08 10:18:00 -04:00
{
console::info("No mod loaded\n");
return;
}
2022-09-03 06:06:45 -04:00
if (!game::Com_InFrontend() && (game::environment::is_mp() && !game::VirtualLobby_Loaded()))
2022-04-08 10:18:00 -04:00
{
console::info("Cannot unload mod while in-game!\n");
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
return;
}
2022-12-22 12:07:51 -05:00
console::info("Unloading mod %s\n", mod_path.value().data());
2022-12-22 12:07:51 -05:00
if (mod_requires_restart(mod_path.value()))
{
console::info("Restarting...\n");
set_mod("");
full_restart("");
}
else
{
set_mod("");
restart();
}
});
command::add("com_restart", []()
{
2022-09-03 06:25:13 -04:00
if (!game::Com_InFrontend() && (game::environment::is_mp() && !game::VirtualLobby_Loaded()))
{
return;
}
2022-04-08 10:18:00 -04:00
restart();
});
}
};
}
2022-05-29 11:53:39 -04:00
REGISTER_COMPONENT(mods::component)