Modding Improvements #18
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/memory.hpp>
|
#include <utils/memory.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
#include <utils/io.hpp>
|
#include <utils/io.hpp>
|
||||||
|
|
||||||
namespace fastfiles
|
namespace fastfiles
|
||||||
@ -19,6 +20,25 @@ namespace fastfiles
|
|||||||
utils::hook::detour db_try_load_x_file_internal_hook;
|
utils::hook::detour db_try_load_x_file_internal_hook;
|
||||||
utils::hook::detour db_find_x_asset_header_hook;
|
utils::hook::detour db_find_x_asset_header_hook;
|
||||||
|
|
||||||
|
template <typename T> inline void merge(std::vector<T>* target, T* source, size_t length)
|
||||||
|
{
|
||||||
|
if (source)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
target->push_back(source[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> inline void merge(std::vector<T>* target, std::vector<T> source)
|
||||||
|
{
|
||||||
|
for (auto& entry : source)
|
||||||
|
{
|
||||||
|
target->push_back(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void db_try_load_x_file_internal(const char* zone_name, const int zone_flags, const int is_base_map)
|
void db_try_load_x_file_internal(const char* zone_name, const int zone_flags, const int is_base_map)
|
||||||
{
|
{
|
||||||
console::info("Loading fastfile %s\n", zone_name);
|
console::info("Loading fastfile %s\n", zone_name);
|
||||||
@ -90,6 +110,42 @@ namespace fastfiles
|
|||||||
console::info("Unloaded fastfile %s\n", name);
|
console::info("Unloaded fastfile %s\n", name);
|
||||||
game::PMem_Free(name, alloc_dir);
|
game::PMem_Free(name, alloc_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto skip_extra_zones_stub = utils::hook::assemble([](utils::hook::assembler& a)
|
||||||
|
{
|
||||||
|
const auto skip = a.newLabel();
|
||||||
|
const auto original = a.newLabel();
|
||||||
|
|
||||||
|
a.pushad64();
|
||||||
|
a.test(ebp, game::DB_ZONE_CUSTOM); // allocFlags
|
||||||
|
a.jnz(skip);
|
||||||
|
|
||||||
|
a.bind(original);
|
||||||
|
a.popad64();
|
||||||
|
a.mov(rdx, 0x140835F28);
|
||||||
|
a.mov(rcx, rsi);
|
||||||
|
a.call_aligned(strcmp);
|
||||||
|
a.jmp(0x1403217C0);
|
||||||
|
|
||||||
|
a.bind(skip);
|
||||||
|
a.popad64();
|
||||||
|
a.mov(r15d, 0x80);
|
||||||
|
a.not_(r15d);
|
||||||
|
a.and_(ebp, r15d);
|
||||||
|
a.jmp(0x1403217F6);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exists(const std::string& zone_name)
|
||||||
|
{
|
||||||
|
auto is_localized = game::DB_IsLocalized(zone_name.data());
|
||||||
|
auto handle = game::Sys_CreateFile(game::Sys_Folder(is_localized), utils::string::va("%s.ff", zone_name.data()));
|
||||||
|
if (handle != (HANDLE)-1)
|
||||||
|
{
|
||||||
|
CloseHandle(handle);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool include_override)
|
void enum_assets(const game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, const bool include_override)
|
||||||
@ -101,6 +157,57 @@ namespace fastfiles
|
|||||||
}), &callback, include_override);
|
}), &callback, include_override);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Load_CommonZones(game::XZoneInfo* zoneInfo, unsigned int zoneCount, game::DBSyncMode syncMode)
|
||||||
|
{
|
||||||
|
std::vector<game::XZoneInfo> data;
|
||||||
|
merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
|
if (fastfiles::exists("mod"))
|
||||||
|
{
|
||||||
|
data.push_back({ "mod", game::DB_ZONE_COMMON | game::DB_ZONE_CUSTOM, 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
game::DB_LoadXAssets(data.data(), static_cast<std::uint32_t>(data.size()), syncMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Load_LevelZones(game::XZoneInfo* zoneInfo, unsigned int zoneCount, game::DBSyncMode syncMode)
|
||||||
|
{
|
||||||
|
std::vector<game::XZoneInfo> data;
|
||||||
|
merge(&data, zoneInfo, zoneCount);
|
||||||
|
|
||||||
|
if (fastfiles::exists("mod"))
|
||||||
|
{
|
||||||
|
data.push_back({ "mod", game::DB_ZONE_COMMON | game::DB_ZONE_CUSTOM, 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
game::DB_LoadXAssets(data.data(), static_cast<std::uint32_t>(data.size()), syncMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::hook::detour sys_createfile_hook;
|
||||||
|
HANDLE sys_create_file_stub(game::Sys_Folder folder, const char* base_filename)
|
||||||
|
{
|
||||||
|
auto* fs_basepath = game::Dvar_FindVar("fs_basepath");
|
||||||
|
auto* fs_game = game::Dvar_FindVar("fs_game");
|
||||||
|
|
||||||
|
std::string dir = fs_basepath ? fs_basepath->current.string : "";
|
||||||
|
std::string mod_dir = fs_game ? fs_game->current.string : "";
|
||||||
|
|
||||||
|
if (base_filename == "mod.ff"s)
|
||||||
|
{
|
||||||
|
if (!mod_dir.empty())
|
||||||
|
{
|
||||||
|
auto path = utils::string::va("%s\\%s\\%s", dir.data(), mod_dir.data(), base_filename);
|
||||||
|
if (utils::io::file_exists(path))
|
||||||
|
{
|
||||||
|
return CreateFileA(path, 0x80000000, 1u, 0, 3u, 0x60000000u, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (HANDLE)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sys_createfile_hook.invoke<HANDLE>(folder, base_filename);
|
||||||
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -118,6 +225,19 @@ namespace fastfiles
|
|||||||
utils::hook::set<uint8_t>(0x1402FBF23, 0xEB); // DB_LoadXFile
|
utils::hook::set<uint8_t>(0x1402FBF23, 0xEB); // DB_LoadXFile
|
||||||
utils::hook::nop(0x1402FC445, 2); // DB_SetFileLoadCompressor
|
utils::hook::nop(0x1402FC445, 2); // DB_SetFileLoadCompressor
|
||||||
|
|
||||||
|
// Don't load eng_ + patch_ with loadzone
|
||||||
|
utils::hook::nop(0x1403217B1, 15);
|
||||||
|
utils::hook::jump(0x1403217B1, skip_extra_zones_stub, true);
|
||||||
|
|
||||||
|
// Add custom zone paths
|
||||||
|
sys_createfile_hook.create(game::Sys_CreateFile, sys_create_file_stub);
|
||||||
|
|
||||||
|
// Load our custom fastfiles (Mod)
|
||||||
|
utils::hook::call(0x1405E7113, Load_CommonZones);
|
||||||
|
|
||||||
|
// Reload mod after level is loaded to allow overriding map stuff
|
||||||
|
utils::hook::call(0x140320ED1, Load_LevelZones);
|
||||||
|
|
||||||
command::add("materiallist", [](const command::params& params)
|
command::add("materiallist", [](const command::params& params)
|
||||||
{
|
{
|
||||||
game::DB_EnumXAssets_FastFile(game::ASSET_TYPE_MATERIAL, [](const game::XAssetHeader header, void*)
|
game::DB_EnumXAssets_FastFile(game::ASSET_TYPE_MATERIAL, [](const game::XAssetHeader header, void*)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
namespace fastfiles
|
namespace fastfiles
|
||||||
{
|
{
|
||||||
void enum_assets(game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, bool include_override);
|
void enum_assets(game::XAssetType type, const std::function<void(game::XAssetHeader)>& callback, bool include_override);
|
||||||
|
@ -3,16 +3,27 @@
|
|||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
#include "game/dvars.hpp"
|
#include "game/dvars.hpp"
|
||||||
|
|
||||||
|
#include "command.hpp"
|
||||||
|
#include "console.hpp"
|
||||||
|
#include "filesystem.hpp"
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
#include "mods.hpp"
|
#include "mods.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
|
||||||
namespace mods
|
namespace mods
|
||||||
{
|
{
|
||||||
|
|
||||||
|
std::optional<std::string> mod_path;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
utils::hook::detour sys_create_file_hook;
|
utils::hook::detour sys_create_file_hook;
|
||||||
|
|
||||||
|
bool release_assets = false;
|
||||||
|
|
||||||
void db_build_os_path_from_source(const char* zone_name, game::FF_DIR source, unsigned int size, char* filename)
|
void db_build_os_path_from_source(const char* zone_name, game::FF_DIR source, unsigned int size, char* filename)
|
||||||
{
|
{
|
||||||
char user_map[MAX_PATH]{};
|
char user_map[MAX_PATH]{};
|
||||||
@ -38,66 +49,74 @@ namespace mods
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game::Sys_File sys_create_file_stub(const char* dir, const char* filename)
|
void restart()
|
||||||
{
|
{
|
||||||
auto result = sys_create_file_hook.invoke<game::Sys_File>(dir, filename);
|
scheduler::once([]()
|
||||||
|
|
||||||
if (result.handle != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
{
|
||||||
return result;
|
release_assets = true;
|
||||||
}
|
const auto _0 = gsl::finally([]()
|
||||||
|
|
||||||
if (!is_using_mods())
|
|
||||||
{
|
{
|
||||||
return result;
|
release_assets = false;
|
||||||
}
|
|
||||||
|
|
||||||
// .ff extension was added previously
|
|
||||||
if (!std::strcmp(filename, "mod.ff") && mods::db_mod_file_exists())
|
|
||||||
{
|
|
||||||
char file_path[MAX_PATH]{};
|
|
||||||
db_build_os_path_from_source("mod", game::FFD_MOD_DIR, sizeof(file_path), file_path);
|
|
||||||
result.handle = game::Sys_OpenFileReliable(file_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void db_load_x_assets_stub(game::XZoneInfo* zone_info, unsigned int zone_count, game::DBSyncMode sync_mode)
|
|
||||||
{
|
|
||||||
std::vector<game::XZoneInfo> zones(zone_info, zone_info + zone_count);
|
|
||||||
|
|
||||||
if (db_mod_file_exists())
|
|
||||||
{
|
|
||||||
zones.emplace_back("mod", game::DB_ZONE_COMMON | game::DB_ZONE_CUSTOM, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
game::DB_LoadXAssets(zones.data(), static_cast<unsigned int>(zones.size()), sync_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto skip_extra_zones_stub = utils::hook::assemble([](utils::hook::assembler& a)
|
|
||||||
{
|
|
||||||
const auto skip = a.newLabel();
|
|
||||||
const auto original = a.newLabel();
|
|
||||||
|
|
||||||
a.pushad64();
|
|
||||||
a.test(ebp, game::DB_ZONE_CUSTOM); // allocFlags
|
|
||||||
a.jnz(skip);
|
|
||||||
|
|
||||||
a.bind(original);
|
|
||||||
a.popad64();
|
|
||||||
a.mov(rdx, 0x140835F28);
|
|
||||||
a.mov(rcx, rsi);
|
|
||||||
a.call_aligned(strcmp);
|
|
||||||
a.jmp(0x1403217C0);
|
|
||||||
|
|
||||||
a.bind(skip);
|
|
||||||
a.popad64();
|
|
||||||
a.mov(r15d, 0x80);
|
|
||||||
a.not_(r15d);
|
|
||||||
a.and_(ebp, r15d);
|
|
||||||
a.jmp(0x1403217F6);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
game::Com_Shutdown("");
|
||||||
|
}, scheduler::pipeline::main);
|
||||||
|
}
|
||||||
|
|
||||||
|
void full_restart(const std::string& arg)
|
||||||
|
{
|
||||||
|
if (game::environment::is_mp())
|
||||||
|
{
|
||||||
|
command::execute("vid_restart");
|
||||||
|
scheduler::once([]
|
||||||
|
{
|
||||||
|
//mods::read_stats();
|
||||||
|
}, scheduler::main);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mode = game::environment::is_mp() ? " -multiplayer "s : " -singleplayer "s;
|
||||||
|
|
||||||
|
utils::nt::relaunch_self();
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_filesystem_data(const std::string& path, bool change_fs_game)
|
||||||
|
{
|
||||||
|
if (mod_path.has_value())
|
||||||
|
{
|
||||||
|
filesystem::unregister_path(mod_path.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (change_fs_game)
|
||||||
|
{
|
||||||
|
game::Dvar_SetFromStringByNameFromSource("fs_game", path.data(), game::DVAR_SOURCE_INTERNAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path != "")
|
||||||
|
{
|
||||||
|
filesystem::register_path(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_mod(const std::string& path, bool change_fs_game)
|
||||||
|
{
|
||||||
|
set_filesystem_data(path, change_fs_game);
|
||||||
|
|
||||||
|
if (path != "")
|
||||||
|
{
|
||||||
|
mod_path = path;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mod_path.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_using_mods()
|
bool is_using_mods()
|
||||||
@ -141,15 +160,72 @@ namespace mods
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't load eng_ + patch_ with loadzone
|
command::add("loadmod", [](const command::params& params)
|
||||||
utils::hook::nop(0x1403217B1, 15);
|
{
|
||||||
utils::hook::jump(0x1403217B1, skip_extra_zones_stub, true);
|
if (params.size() < 2)
|
||||||
|
{
|
||||||
|
console::info("Usage: loadmod mods/<modname>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Add custom zone paths
|
/*if (!game::Com_InFrontend() && (game::environment::is_mp() && !game::VirtualLobby_Loaded()))
|
||||||
sys_create_file_hook.create(game::Sys_CreateFile, sys_create_file_stub);
|
{
|
||||||
|
console::info("Cannot load mod while in-game!\n");
|
||||||
|
game::CG_GameMessage(0, "^1Cannot load mod while in-game!");
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
// Load mod.ff
|
const auto path = params.get(1);
|
||||||
utils::hook::call(0x1405E7113, db_load_x_assets_stub); // R_LoadGraphicsAssets According to myself but I don't remember where I got it from
|
if (!utils::io::directory_exists(path))
|
||||||
|
{
|
||||||
|
console::info("Mod %s not found!\n", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console::info("Loading mod %s\n", path);
|
||||||
|
set_mod(path, true);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
command::add("unloadmod", [](const command::params& params)
|
||||||
|
{
|
||||||
|
if (!mod_path.has_value())
|
||||||
|
{
|
||||||
|
console::info("No mod loaded\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (!game::Com_InFrontend() && (game::environment::is_mp() && !game::VirtualLobby_Loaded()))
|
||||||
|
{
|
||||||
|
console::info("Cannot unload mod while in-game!\n");
|
||||||
|
game::CG_GameMessage(0, "^1Cannot unload mod while in-game!");
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
console::info("Unloading mod %s\n", mod_path.value().data());
|
||||||
|
|
||||||
|
if (mod_requires_restart(mod_path.value()))
|
||||||
|
{
|
||||||
|
console::info("Restarting...\n");
|
||||||
|
set_mod("", true);
|
||||||
|
full_restart("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_mod("", true);
|
||||||
|
restart();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
58
src/client/component/weapon.cpp
Normal file
58
src/client/component/weapon.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include "fastfiles.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include <utils/hook.hpp>
|
||||||
|
|
||||||
|
namespace weapon
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
utils::hook::detour g_setup_level_weapon_def_hook;
|
||||||
|
void g_setup_level_weapon_def_stub()
|
||||||
|
{
|
||||||
|
// precache level weapons first
|
||||||
|
g_setup_level_weapon_def_hook.invoke<void>();
|
||||||
|
|
||||||
|
std::vector<game::WeaponCompleteDef*> weapons;
|
||||||
|
|
||||||
|
// find all weapons in asset pools
|
||||||
|
fastfiles::enum_assets(game::ASSET_TYPE_WEAPON, [&weapons](game::XAssetHeader header)
|
||||||
|
{
|
||||||
|
weapons.push_back(header.weapon);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
// sort weapons
|
||||||
|
std::sort(weapons.begin(), weapons.end(), [](game::WeaponCompleteDef* weapon1, game::WeaponCompleteDef* weapon2)
|
||||||
|
{
|
||||||
|
return std::string_view(weapon1->name) <
|
||||||
|
std::string_view(weapon2->name);
|
||||||
|
});
|
||||||
|
|
||||||
|
// precache items
|
||||||
|
for (std::size_t i = 0; i < weapons.size(); i++)
|
||||||
|
{
|
||||||
|
//console::debug("precaching weapon \"%s\"\n", weapons[i]->name);
|
||||||
|
game::G_GetWeaponForName(weapons[i]->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_unpack() override
|
||||||
|
{
|
||||||
|
if (!game::environment::is_sp())
|
||||||
|
{
|
||||||
|
// precache all weapons that are loaded in zones
|
||||||
|
g_setup_level_weapon_def_hook.create(0x1403DA910, g_setup_level_weapon_def_stub);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(weapon::component)
|
6
src/client/component/weapon.hpp
Normal file
6
src/client/component/weapon.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace weapon
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1955,6 +1955,16 @@ namespace game
|
|||||||
weapInventoryType_t inventoryType;
|
weapInventoryType_t inventoryType;
|
||||||
}; // Incomplete
|
}; // Incomplete
|
||||||
|
|
||||||
|
struct WeaponCompleteDef
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
const char* szInternalName;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
WeaponDef* weapDef;
|
||||||
|
};
|
||||||
|
|
||||||
struct RawFile
|
struct RawFile
|
||||||
{
|
{
|
||||||
const char* name;
|
const char* name;
|
||||||
@ -1998,9 +2008,9 @@ namespace game
|
|||||||
menuDef_t *menu;
|
menuDef_t *menu;
|
||||||
AnimationClass *animClass;
|
AnimationClass *animClass;
|
||||||
LocalizeEntry *localize;
|
LocalizeEntry *localize;
|
||||||
WeaponAttachment *attachment;
|
WeaponAttachment *attachment;*/
|
||||||
WeaponCompleteDef* weapon;
|
WeaponCompleteDef* weapon;
|
||||||
SndDriverGlobals *sndDriverGlobals;
|
/*SndDriverGlobals* sndDriverGlobals;
|
||||||
FxEffectDef *fx;
|
FxEffectDef *fx;
|
||||||
FxImpactTable *impactFx;
|
FxImpactTable *impactFx;
|
||||||
SurfaceFxTable *surfaceFx;*/
|
SurfaceFxTable *surfaceFx;*/
|
||||||
|
@ -8,6 +8,8 @@ namespace game
|
|||||||
* Functions
|
* Functions
|
||||||
**************************************************************/
|
**************************************************************/
|
||||||
|
|
||||||
|
WEAK symbol<void(char const* finalMessage)> Com_Shutdown{ 0x0, 0x140415B30 };
|
||||||
|
|
||||||
WEAK symbol<void(unsigned int id)> AddRefToObject{0x1403D7A10, 0x1404326D0};
|
WEAK symbol<void(unsigned int id)> AddRefToObject{0x1403D7A10, 0x1404326D0};
|
||||||
WEAK symbol<void(int type, VariableUnion u)> AddRefToValue{0x1403D7740, 0x1404326E0};
|
WEAK symbol<void(int type, VariableUnion u)> AddRefToValue{0x1403D7740, 0x1404326E0};
|
||||||
WEAK symbol<unsigned int(unsigned int id)> AllocThread{0, 0x1404329B0};
|
WEAK symbol<unsigned int(unsigned int id)> AllocThread{0, 0x1404329B0};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user