feat(mods): add LUI menu

This commit is contained in:
diamante0018 2025-01-27 22:28:55 +01:00
parent 3d77a21f3d
commit bc0372a249
No known key found for this signature in database
GPG Key ID: F2000F181A4F7C85
6 changed files with 127 additions and 15 deletions

View File

@ -11,7 +11,7 @@
namespace dvar_cheats namespace dvar_cheats
{ {
void apply_sv_cheats(const game::dvar_t* dvar, const game::DvarSetSource source, game::dvar_value* value) void apply_sv_cheats(const game::dvar_t* dvar, const game::DvarSetSource source, game::DvarValue* value)
{ {
if (dvar && dvar->name == "sv_cheats"s) if (dvar && dvar->name == "sv_cheats"s)
{ {

View File

@ -83,20 +83,22 @@ namespace filesystem
void startup() void startup()
{ {
register_path("iw6"); const auto base = std::filesystem::current_path();
register_path(base / "iw6");
register_path(get_binary_directory() + "\\data"); register_path(get_binary_directory() + "\\data");
if (get_binary_directory() != std::filesystem::current_path()) if (get_binary_directory() != base)
{ {
register_path(std::filesystem::current_path() / "data"); register_path(base / "data");
} }
// game's search paths // game's search paths
register_path("devraw"); register_path(base / "devraw");
register_path("devraw_shared"); register_path(base / "devraw_shared");
register_path("raw_shared"); register_path(base / "raw_shared");
register_path("raw"); register_path(base / "raw");
register_path("main"); register_path(base / "main");
} }
void check_for_startup() void check_for_startup()

View File

@ -3,9 +3,12 @@
#include "game/game.hpp" #include "game/game.hpp"
#include "game/dvars.hpp" #include "game/dvars.hpp"
#include "command.hpp"
#include "console.hpp"
#include "mods.hpp" #include "mods.hpp"
#include <utils/hook.hpp> #include <utils/hook.hpp>
#include <utils/string.hpp>
namespace mods namespace mods
{ {
@ -98,6 +101,40 @@ namespace mods
a.and_(ebp, r15d); a.and_(ebp, r15d);
a.jmp(0x1403217F6); a.jmp(0x1403217F6);
}); });
bool fs_game_dir_domain_func(game::dvar_t* dvar, game::DvarValue new_value)
{
if (*new_value.string == '\0')
{
return true;
}
if (game::I_strnicmp(new_value.string, "mods", 4) != 0)
{
game::LiveStorage_StatsWriteNotNeeded(game::CONTROLLER_INDEX_0);
console::error("ERROR: Invalid server value '%s' for '%s'\n", new_value.string, dvar->name);
return false;
}
if (5 < std::strlen(new_value.string) && (new_value.string[4] == '\\' || new_value.string[4] == '/'))
{
const auto* s1 = std::strstr(new_value.string, "..");
const auto* s2 = std::strstr(new_value.string, "::");
if (s1 == nullptr && s2 == nullptr)
{
return true;
}
game::LiveStorage_StatsWriteNotNeeded(game::CONTROLLER_INDEX_0);
console::error("ERROR: Invalid server value '%s' for '%s'\n", new_value.string, dvar->name);
return false;
}
// Invalid path specified
game::LiveStorage_StatsWriteNotNeeded(game::CONTROLLER_INDEX_0);
console::error("ERROR: Invalid server value '%s' for '%s'\n", new_value.string, dvar->name);
return false;
}
} }
bool is_using_mods() bool is_using_mods()
@ -136,6 +173,8 @@ namespace mods
// Remove DVAR_INIT from fs_game // Remove DVAR_INIT from fs_game
utils::hook::set<std::uint32_t>(SELECT_VALUE(0x14041C085 + 2, 0x1404DDA45 + 2), SELECT_VALUE(game::DVAR_FLAG_NONE, game::DVAR_FLAG_SERVERINFO)); utils::hook::set<std::uint32_t>(SELECT_VALUE(0x14041C085 + 2, 0x1404DDA45 + 2), SELECT_VALUE(game::DVAR_FLAG_NONE, game::DVAR_FLAG_SERVERINFO));
utils::hook::inject(SELECT_VALUE(0x14041C097 + 3, 0x1404DDA57 + 3), &fs_game_dir_domain_func);
if (game::environment::is_sp()) if (game::environment::is_sp())
{ {
return; return;
@ -150,6 +189,44 @@ namespace mods
// Load mod.ff // Load mod.ff
utils::hook::call(0x1405E7113, db_load_x_assets_stub); // R_LoadGraphicsAssets According to myself but I don't remember where I got it from utils::hook::call(0x1405E7113, db_load_x_assets_stub); // R_LoadGraphicsAssets According to myself but I don't remember where I got it from
command::add("loadmod", [](const command::params& params) -> void
{
if (params.size() != 2)
{
console::info("USAGE: %s \"mods/<mod name>\"", params.get(0));
return;
}
std::string mod_name = utils::string::to_lower(params.get(1));
if (!mod_name.empty() && !mod_name.starts_with("mods/"))
{
mod_name = "mods/" + mod_name;
}
// change fs_game if needed
if (mod_name != (*dvars::fs_gameDirVar)->current.string)
{
game::Dvar_SetString((*dvars::fs_gameDirVar), mod_name.c_str());
command::execute("vid_restart\n");
}
});
command::add("unloadmod", [](const command::params& params) -> void
{
if (*dvars::fs_gameDirVar == nullptr || *(*dvars::fs_gameDirVar)->current.string == '\0')
{
return;
}
game::Dvar_SetString(*dvars::fs_gameDirVar, "");
command::execute("vid_restart\n");
});
// TODO: without a way to monitor all the ways fs_game can be changed there is no way to detect when we
// should unregister the path from the internal filesystem we use
// HINT: It could be done in fs_game_dir_domain_func, but I haven't tested if that's the best place to monitor for changes and register/unregister the mods folder
} }
}; };
} }

View File

@ -195,6 +195,27 @@ namespace ui_scripting
setup_functions(); setup_functions();
lua["print"] = function(reinterpret_cast<game::hks::lua_function>(0x14017B120)); // hks::base_print lua["print"] = function(reinterpret_cast<game::hks::lua_function>(0x14017B120)); // hks::base_print
lua["directoryexists"] = [](const std::string& string)
{
return utils::io::directory_exists(string);
};
lua["listfiles"] = [](const std::string& string)
{
return utils::io::list_files(string);
};
lua["directoryisempty"] = [](const std::string& string)
{
return utils::io::directory_is_empty(string);
};
lua["fileexists"] = [](const std::string& string)
{
return utils::io::file_exists(string);
};
lua["table"]["unpack"] = lua["unpack"]; lua["table"]["unpack"] = lua["unpack"];
lua["luiglobals"] = lua; lua["luiglobals"] = lua;

View File

@ -10,6 +10,14 @@ namespace game
typedef vec_t vec3_t[3]; typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4]; typedef vec_t vec4_t[4];
enum ControllerIndex_t
{
INVALID_CONTROLLER_PORT = -1,
CONTROLLER_INDEX_0 = 0x0,
CONTROLLER_INDEX_FIRST = 0x0,
CONTROLLER_INDEX_COUNT = 0x1,
};
enum enum
{ {
FL_GODMODE = 0x1, FL_GODMODE = 0x1,
@ -1171,7 +1179,7 @@ namespace game
rgb = 9 // Color without alpha rgb = 9 // Color without alpha
}; };
union dvar_value union DvarValue
{ {
bool enabled; bool enabled;
int integer; int integer;
@ -1214,9 +1222,9 @@ namespace game
unsigned int flags; //08 unsigned int flags; //08
dvar_type type; //0C dvar_type type; //0C
bool modified; //0D bool modified; //0D
dvar_value current; //10 DvarValue current; //10
dvar_value latched; DvarValue latched;
dvar_value reset; DvarValue reset;
dvar_limits domain; dvar_limits domain;
}; };
@ -1967,7 +1975,7 @@ namespace game
{ {
const char* szInternalName; const char* szInternalName;
WeaponDef* weapDef; WeaponDef* weapDef;
}; // Incomplete };
union XAssetHeader union XAssetHeader
{ {

View File

@ -20,6 +20,7 @@ namespace game
WEAK symbol<void(unsigned int weapon, bool isAlternate, char* output, unsigned int maxStringLen)> BG_GetWeaponNameComplete{0, 0x140239370}; WEAK symbol<void(unsigned int weapon, bool isAlternate, char* output, unsigned int maxStringLen)> BG_GetWeaponNameComplete{0, 0x140239370};
WEAK symbol<void()> BG_ClearWeaponDef{0x0, 0x140238D20}; WEAK symbol<void()> BG_ClearWeaponDef{0x0, 0x140238D20};
WEAK symbol<bool()> BG_BotsConnectType{0x0, 0x140217080};
WEAK symbol<void()> Com_Frame_Try_Block_Function{0x1403BC980, 0x1404131A0}; WEAK symbol<void()> Com_Frame_Try_Block_Function{0x1403BC980, 0x1404131A0};
WEAK symbol<const char*(char const**)> Com_Parse{0x1404313E0, 0x1404F50E0}; WEAK symbol<const char*(char const**)> Com_Parse{0x1404313E0, 0x1404F50E0};
@ -87,7 +88,7 @@ namespace game
WEAK symbol<void(const dvar_t* dvar, const char* string)> Dvar_SetString{0x14042D6E0, 0x1404F08E0}; WEAK symbol<void(const dvar_t* dvar, const char* string)> Dvar_SetString{0x14042D6E0, 0x1404F08E0};
WEAK symbol<void(const char*, const char*, DvarSetSource)> Dvar_SetFromStringByNameFromSource{0x14042D000, 0x1404F00B0}; WEAK symbol<void(const char*, const char*, DvarSetSource)> Dvar_SetFromStringByNameFromSource{0x14042D000, 0x1404F00B0};
WEAK symbol<void()> Dvar_Sort{0x14042DEF0, 0x1404F1210}; WEAK symbol<void()> Dvar_Sort{0x14042DEF0, 0x1404F1210};
WEAK symbol<const char*(dvar_t* dvar, dvar_value value)> Dvar_ValueToString{0x14042E710, 0x1404F1A30}; WEAK symbol<const char*(dvar_t* dvar, DvarValue value)> Dvar_ValueToString{0x14042E710, 0x1404F1A30};
WEAK symbol<long long (const char* qpath, char** buffer)> FS_ReadFile{0x14041D0B0, 0x1404DE900}; WEAK symbol<long long (const char* qpath, char** buffer)> FS_ReadFile{0x14041D0B0, 0x1404DE900};
WEAK symbol<void(void* buffer)> FS_FreeFile{0x14041D0A0, 0x1404DE8F0}; WEAK symbol<void(void* buffer)> FS_FreeFile{0x14041D0A0, 0x1404DE8F0};
@ -120,6 +121,7 @@ namespace game
WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x14023D9A0, 0x1402C40E0}; WEAK symbol<const char*(int, int, int)> Key_KeynumToString{0x14023D9A0, 0x1402C40E0};
WEAK symbol<unsigned int (int)> Live_SyncOnlineDataFlags{0, 0x1405ABF70}; WEAK symbol<unsigned int (int)> Live_SyncOnlineDataFlags{0, 0x1405ABF70};
WEAK symbol<void(int localControllerIndex)> LiveStorage_StatsWriteNotNeeded{0x1403BA420, 0x140409120};
WEAK symbol<bool(int controllerIndex, unsigned int name, int value, StatsGroup statsGroup)> LiveStorage_PlayerDataSetIntByName{0x1403B8C20, 0x140404730}; WEAK symbol<bool(int controllerIndex, unsigned int name, int value, StatsGroup statsGroup)> LiveStorage_PlayerDataSetIntByName{0x1403B8C20, 0x140404730};
WEAK symbol<bool(std::uint8_t* persistentData, const char* lookupString, int value, std::uint8_t* modifiedFlags, StatsGroup statsGroup)> LiveStorage_PlayerDataSetReservedInt{0x1403B8D00, 0x140404820}; WEAK symbol<bool(std::uint8_t* persistentData, const char* lookupString, int value, std::uint8_t* modifiedFlags, StatsGroup statsGroup)> LiveStorage_PlayerDataSetReservedInt{0x1403B8D00, 0x140404820};
@ -262,6 +264,8 @@ namespace game
WEAK symbol<void(unsigned __int64 markPos)> LargeLocalResetToMark{0x140423B50, 0x1404E4D00}; WEAK symbol<void(unsigned __int64 markPos)> LargeLocalResetToMark{0x140423B50, 0x1404E4D00};
WEAK symbol<int(const char* s0, const char* s1, int n)> I_strnicmp{0x140432840, 0x1404F67D0};
WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14062E030, 0x140738060}; WEAK symbol<void*(jmp_buf* Buf, int Value)> longjmp{0x14062E030, 0x140738060};
WEAK symbol<int (jmp_buf* Buf)> _setjmp{0x14062F030, 0x140739060}; WEAK symbol<int (jmp_buf* Buf)> _setjmp{0x14062F030, 0x140739060};