feat(mods): add LUI menu
This commit is contained in:
parent
3d77a21f3d
commit
bc0372a249
@ -11,7 +11,7 @@
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -83,20 +83,22 @@ namespace filesystem
|
||||
|
||||
void startup()
|
||||
{
|
||||
register_path("iw6");
|
||||
const auto base = std::filesystem::current_path();
|
||||
|
||||
register_path(base / "iw6");
|
||||
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
|
||||
register_path("devraw");
|
||||
register_path("devraw_shared");
|
||||
register_path("raw_shared");
|
||||
register_path("raw");
|
||||
register_path("main");
|
||||
register_path(base / "devraw");
|
||||
register_path(base / "devraw_shared");
|
||||
register_path(base / "raw_shared");
|
||||
register_path(base / "raw");
|
||||
register_path(base / "main");
|
||||
}
|
||||
|
||||
void check_for_startup()
|
||||
|
@ -3,9 +3,12 @@
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "command.hpp"
|
||||
#include "console.hpp"
|
||||
#include "mods.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace mods
|
||||
{
|
||||
@ -98,6 +101,40 @@ namespace mods
|
||||
a.and_(ebp, r15d);
|
||||
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()
|
||||
@ -136,6 +173,8 @@ namespace mods
|
||||
// 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::inject(SELECT_VALUE(0x14041C097 + 3, 0x1404DDA57 + 3), &fs_game_dir_domain_func);
|
||||
|
||||
if (game::environment::is_sp())
|
||||
{
|
||||
return;
|
||||
@ -150,6 +189,44 @@ namespace mods
|
||||
|
||||
// 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
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -195,6 +195,27 @@ namespace ui_scripting
|
||||
setup_functions();
|
||||
|
||||
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["luiglobals"] = lua;
|
||||
|
||||
|
@ -10,6 +10,14 @@ namespace game
|
||||
typedef vec_t vec3_t[3];
|
||||
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
|
||||
{
|
||||
FL_GODMODE = 0x1,
|
||||
@ -1171,7 +1179,7 @@ namespace game
|
||||
rgb = 9 // Color without alpha
|
||||
};
|
||||
|
||||
union dvar_value
|
||||
union DvarValue
|
||||
{
|
||||
bool enabled;
|
||||
int integer;
|
||||
@ -1214,9 +1222,9 @@ namespace game
|
||||
unsigned int flags; //08
|
||||
dvar_type type; //0C
|
||||
bool modified; //0D
|
||||
dvar_value current; //10
|
||||
dvar_value latched;
|
||||
dvar_value reset;
|
||||
DvarValue current; //10
|
||||
DvarValue latched;
|
||||
DvarValue reset;
|
||||
dvar_limits domain;
|
||||
};
|
||||
|
||||
@ -1967,7 +1975,7 @@ namespace game
|
||||
{
|
||||
const char* szInternalName;
|
||||
WeaponDef* weapDef;
|
||||
}; // Incomplete
|
||||
};
|
||||
|
||||
union XAssetHeader
|
||||
{
|
||||
|
@ -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()> BG_ClearWeaponDef{0x0, 0x140238D20};
|
||||
WEAK symbol<bool()> BG_BotsConnectType{0x0, 0x140217080};
|
||||
|
||||
WEAK symbol<void()> Com_Frame_Try_Block_Function{0x1403BC980, 0x1404131A0};
|
||||
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 char*, const char*, DvarSetSource)> Dvar_SetFromStringByNameFromSource{0x14042D000, 0x1404F00B0};
|
||||
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<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<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(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<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<int (jmp_buf* Buf)> _setjmp{0x14062F030, 0x140739060};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user