diff --git a/iw4/Components/AssetHandler.cpp b/iw4/Components/AssetHandler.cpp index c4a47d70..21632d6f 100644 --- a/iw4/Components/AssetHandler.cpp +++ b/iw4/Components/AssetHandler.cpp @@ -4,6 +4,7 @@ namespace Components { bool AssetHandler::BypassState = false; std::map AssetHandler::TypeCallbacks; + std::vector AssetHandler::RestrictCallbacks; Game::XAssetHeader AssetHandler::FindAsset(Game::XAssetType type, const char* filename) { @@ -60,7 +61,6 @@ namespace Components jmp eax finishFound: - pop edi pop esi pop ebp @@ -70,14 +70,65 @@ namespace Components } } + bool AssetHandler::IsAssetEligible(Game::XAssetType type, Game::XAssetHeader *asset) + { + const char* name = Game::DB_GetXAssetNameHandlers[type](asset); + if (!name) return false; + + for (auto callback : AssetHandler::RestrictCallbacks) + { + if (!callback(type, *asset, name)) + { + return false; + } + } + + return true; + } + + void __declspec(naked) AssetHandler::AddAssetStub() + { + __asm + { + push [esp + 8] + push [esp + 8] + call AssetHandler::IsAssetEligible + add esp, 08h + + test al, al + jz doNotLoad + +// push [esp + 8] +// push [esp + 8] +// call DoBeforeLoadAsset +// add esp, 08h + + mov eax, [esp + 8] + sub esp, 14h + mov ecx, 5BB657h + jmp ecx + + doNotLoad: + mov eax, [esp + 8] + retn + } + } + void AssetHandler::On(Game::XAssetType type, AssetHandler::Callback callback) { AssetHandler::TypeCallbacks[type] = callback; } + void AssetHandler::Restrict(RestrictCallback callback) + { + AssetHandler::RestrictCallbacks.push_back(callback); + } + AssetHandler::AssetHandler() { Utils::Hook(Game::DB_FindXAssetHeader, AssetHandler::FindAssetStub).Install()->Quick(); + + Utils::Hook(0x5BB650, AssetHandler::AddAssetStub, HOOK_JUMP).Install()->Quick(); } AssetHandler::~AssetHandler() diff --git a/iw4/Components/AssetHandler.hpp b/iw4/Components/AssetHandler.hpp index 6848b60c..31360b74 100644 --- a/iw4/Components/AssetHandler.hpp +++ b/iw4/Components/AssetHandler.hpp @@ -4,19 +4,24 @@ namespace Components { public: typedef Game::XAssetHeader(*Callback)(Game::XAssetType, const char*); + typedef bool(*RestrictCallback)(Game::XAssetType type, Game::XAssetHeader asset, const char* name); AssetHandler(); ~AssetHandler(); const char* GetName() { return "AssetHandler"; }; static void On(Game::XAssetType type, Callback callback); + static void Restrict(RestrictCallback callback); private: static bool BypassState; static Game::XAssetHeader FindAsset(Game::XAssetType type, const char* filename); + static bool IsAssetEligible(Game::XAssetType type, Game::XAssetHeader* asset); static void FindAssetStub(); + static void AddAssetStub(); static std::map TypeCallbacks; + static std::vector RestrictCallbacks; }; } diff --git a/iw4/Components/FastFiles.cpp b/iw4/Components/FastFiles.cpp index fe747b3b..2a1926d1 100644 --- a/iw4/Components/FastFiles.cpp +++ b/iw4/Components/FastFiles.cpp @@ -53,6 +53,18 @@ namespace Components FastFiles::ZonePaths.push_back(path); } + std::string FastFiles::Current() + { + const char* file = (Utils::Hook::Get(0x112A680) + 4); + + if ((int)file == 4) + { + return ""; + } + + return file; + } + FastFiles::FastFiles() { // Redirect zone paths @@ -62,6 +74,27 @@ namespace Components Utils::Hook(0x506BC7, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick(); Utils::Hook(0x60B4AC, FastFiles::LoadDLCUIZones, HOOK_CALL).Install()->Quick(); + // basic checks (hash jumps, both normal and playlist) + Utils::Hook::Nop(0x5B97A3, 2); + Utils::Hook::Nop(0x5BA493, 2); + + Utils::Hook::Nop(0x5B991C, 2); + Utils::Hook::Nop(0x5BA60C, 2); + + Utils::Hook::Nop(0x5B97B4, 2); + Utils::Hook::Nop(0x5BA4A4, 2); + + // allow loading of IWffu (unsigned) files + Utils::Hook::Set(0x4158D9, 0xEB); // main function + Utils::Hook::Nop(0x4A1D97, 2); // DB_AuthLoad_InflateInit + + // some other, unknown, check + Utils::Hook::Set(0x5B9912, 0xB8); + Utils::Hook::Set(0x5B9913, 1); + + Utils::Hook::Set(0x5BA602, 0xB8); + Utils::Hook::Set(0x5BA603, 1); + // Add custom zone paths FastFiles::AddZonePath("zone\\patch\\"); FastFiles::AddZonePath("zone\\dlc\\"); diff --git a/iw4/Components/FastFiles.hpp b/iw4/Components/FastFiles.hpp index c8e62ece..4cca26ab 100644 --- a/iw4/Components/FastFiles.hpp +++ b/iw4/Components/FastFiles.hpp @@ -8,6 +8,7 @@ namespace Components const char* GetName() { return "FastFiles"; }; static void AddZonePath(std::string path); + static std::string Current(); private: static std::vector ZonePaths; diff --git a/iw4/Components/Loader.cpp b/iw4/Components/Loader.cpp index 5ca42f3a..bc9849a6 100644 --- a/iw4/Components/Loader.cpp +++ b/iw4/Components/Loader.cpp @@ -7,6 +7,7 @@ namespace Components void Loader::Initialize() { Loader::Register(new Dvar()); + Loader::Register(new Maps()); Loader::Register(new Menus()); Loader::Register(new Party()); Loader::Register(new Colors()); diff --git a/iw4/Components/Loader.hpp b/iw4/Components/Loader.hpp index be8dcbc7..2771b3fa 100644 --- a/iw4/Components/Loader.hpp +++ b/iw4/Components/Loader.hpp @@ -21,6 +21,7 @@ namespace Components } #include "Dvar.hpp" +#include "Maps.hpp" #include "Menus.hpp" #include "Colors.hpp" #include "Logger.hpp" diff --git a/iw4/Components/Localization.cpp b/iw4/Components/Localization.cpp index 94c45279..5bc5ef4f 100644 --- a/iw4/Components/Localization.cpp +++ b/iw4/Components/Localization.cpp @@ -2,6 +2,7 @@ namespace Components { + Dvar::Var Localization::UseLocalization; std::map Localization::LocalizeMap; void Localization::Set(const char* key, const char* value) @@ -11,6 +12,8 @@ namespace Components const char* Localization::Get(const char* key) { + if (!Localization::UseLocalization.Get()) return key; + if (Localization::LocalizeMap.find(key) != Localization::LocalizeMap.end()) { return Localization::LocalizeMap[key].data(); @@ -30,7 +33,8 @@ namespace Components { Utils::Hook(0x629B90, Localization::Get, HOOK_JUMP).Install()->Quick(); - Localization::Set("MENU_MULTIPLAYER_CAPS", "^5Fotze"); + //Localization::Set("MENU_MULTIPLAYER_CAPS", "^5Fotze"); + Localization::UseLocalization = Dvar::Var::Register("ui_localize", true, Game::dvar_flag::DVAR_FLAG_NONE, "Use localization strings"); } Localization::~Localization() diff --git a/iw4/Components/Localization.hpp b/iw4/Components/Localization.hpp index 4f199c73..50caaa44 100644 --- a/iw4/Components/Localization.hpp +++ b/iw4/Components/Localization.hpp @@ -12,5 +12,6 @@ namespace Components private: static std::map LocalizeMap; + static Dvar::Var UseLocalization; }; } diff --git a/iw4/Components/Maps.cpp b/iw4/Components/Maps.cpp new file mode 100644 index 00000000..3882c226 --- /dev/null +++ b/iw4/Components/Maps.cpp @@ -0,0 +1,104 @@ +#include "..\STDInclude.hpp" + +namespace Components +{ + void* Maps::WorldMP = 0; + void* Maps::WorldSP = 0; + + void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname) + { + if (_strnicmp("mp_", mapname, 3)) + { + format = "maps/%s.d3dbsp"; + + Utils::Hook::Set(0x4D90B7, (char*)Maps::WorldSP + 52); + } + else + { + Utils::Hook::Set(0x4D90B7, (char*)Maps::WorldMP + 4); + } + + _snprintf(buffer, size, format, mapname); + } + + typedef struct + { + char unknown[16]; + } xAssetEntry_t; + + static xAssetEntry_t xEntries[789312]; + + void ReallocXAssetEntries() + { + int newsize = 516 * 2048; + //newEnts = malloc(newsize); + + // get (obfuscated) memory locations + unsigned int origMin = 0x134CAD8; + unsigned int origMax = 0x134CAE8; + + unsigned int difference = (unsigned int)xEntries - origMin; + + // scan the .text memory + char* scanMin = (char*)0x401000; + char* scanMax = (char*)0x6D7000; + char* current = scanMin; + + for (; current < scanMax; current += 1) { + unsigned int* intCur = (unsigned int*)current; + + // if the address points to something within our range of interest + if (*intCur == origMin || *intCur == origMax) { + // patch it + *intCur += difference; + } + } + + *(DWORD*)0x5BAEB0 = 789312; + } + + Maps::Maps() + { + // hunk size (was 300 MiB) + Utils::Hook::Set(0x64A029, 0x1C200000); // 450 MiB + Utils::Hook::Set(0x64A057, 0x1C200000); + + // Intercept BSP name resolving + Utils::Hook(0x4C5979, Maps::GetBSPName, HOOK_CALL).Install()->Quick(); + + Maps::WorldSP = Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAME_MAP_SP, 1); + Maps::WorldMP = Utils::Hook::Get(0x4D90B7) - 4; + + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_FX, 1200); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOCALIZE, 14000); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XANIM, 8192); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_XMODEL, 5125); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PHYSPRESET, 128); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_PIXELSHADER, 10000); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXSHADER, 3072); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_MATERIAL, 8192); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_VERTEXDECL, 196); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, 2400); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_STRINGTABLE, 800); + + ReallocXAssetEntries(); + + AssetHandler::Restrict([] (Game::XAssetType type, Game::XAssetHeader asset, const char* name) -> bool + { + if (type == Game::XAssetType::ASSET_TYPE_MAP_ENTS) + { + static std::string mapEntities; + FileSystem::File ents(Utils::VA("%s.ents", name)); + if (ents.Exists()) + { + mapEntities = ents.GetBuffer(); + asset.mapEnts->entitystring = mapEntities.data(); + } + } + + return true; + }); + } +} diff --git a/iw4/Components/Maps.hpp b/iw4/Components/Maps.hpp new file mode 100644 index 00000000..27cc8297 --- /dev/null +++ b/iw4/Components/Maps.hpp @@ -0,0 +1,15 @@ +namespace Components +{ + class Maps : public Component + { + public: + Maps(); + const char* GetName() { return "Maps"; }; + + private: + static void* WorldMP; + static void* WorldSP; + + static void GetBSPName(char* buffer, size_t size, const char* format, const char* mapname); + }; +} diff --git a/iw4/Components/Menus.cpp b/iw4/Components/Menus.cpp index aca628e9..87a5e016 100644 --- a/iw4/Components/Menus.cpp +++ b/iw4/Components/Menus.cpp @@ -153,8 +153,6 @@ namespace Components } } - OutputDebugStringA(Utils::VA("%X %s", menu->window.name, menu->window.name)); - return menu; } diff --git a/iw4/Components/QuickPatch.cpp b/iw4/Components/QuickPatch.cpp index 5f6d0d33..08f37871 100644 --- a/iw4/Components/QuickPatch.cpp +++ b/iw4/Components/QuickPatch.cpp @@ -69,8 +69,5 @@ namespace Components Utils::Hook::Nop(0x6830B1, 20); Utils::Hook(0x682EBF, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick(); Utils::Hook(0x6830B1, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick(); - - // Why? - Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, 2400); } } diff --git a/iw4/Game/Functions.cpp b/iw4/Game/Functions.cpp index 57042c7e..762983e7 100644 --- a/iw4/Game/Functions.cpp +++ b/iw4/Game/Functions.cpp @@ -15,6 +15,7 @@ namespace Game Com_Milliseconds_t Com_Milliseconds = (Com_Milliseconds_t)0x42A660; DB_FindXAssetHeader_t DB_FindXAssetHeader = (DB_FindXAssetHeader_t)0x407930; + DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers = (DB_GetXAssetNameHandler_t*)0x799328; DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers = (DB_GetXAssetSizeHandler_t*)0x799488; DB_LoadXAssets_t DB_LoadXAssets = (DB_LoadXAssets_t)0x4E5930; diff --git a/iw4/Game/Functions.hpp b/iw4/Game/Functions.hpp index a1b12845..512ecc94 100644 --- a/iw4/Game/Functions.hpp +++ b/iw4/Game/Functions.hpp @@ -27,6 +27,9 @@ namespace Game typedef XAssetHeader (__cdecl * DB_FindXAssetHeader_t)(XAssetType type, const char* filename); extern DB_FindXAssetHeader_t DB_FindXAssetHeader; + typedef const char* (__cdecl * DB_GetXAssetNameHandler_t)(Game::XAssetHeader* asset); + extern DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers; + typedef int(__cdecl * DB_GetXAssetSizeHandler_t)(); extern DB_GetXAssetSizeHandler_t* DB_GetXAssetSizeHandlers; diff --git a/iw4/Game/Structs.hpp b/iw4/Game/Structs.hpp index 1f5a57f8..43eec1d1 100644 --- a/iw4/Game/Structs.hpp +++ b/iw4/Game/Structs.hpp @@ -858,6 +858,12 @@ namespace Game const char* name; }; + struct MapEnts + { + const char* name; + const char* entitystring; + }; + union XAssetHeader { void *data; @@ -866,5 +872,12 @@ namespace Game Material *material; snd_alias_list_t *aliasList; localizedEntry_s *localize; + MapEnts* mapEnts; + }; + + struct XAsset + { + XAssetType type; + XAssetHeader header; }; } diff --git a/iw4/iw4.vcxproj b/iw4/iw4.vcxproj index 2bb8f626..100d4d6f 100644 --- a/iw4/iw4.vcxproj +++ b/iw4/iw4.vcxproj @@ -61,6 +61,7 @@ + @@ -96,6 +97,7 @@ + diff --git a/iw4/iw4.vcxproj.filters b/iw4/iw4.vcxproj.filters index c17b0a50..f3c559b3 100644 --- a/iw4/iw4.vcxproj.filters +++ b/iw4/iw4.vcxproj.filters @@ -125,6 +125,9 @@ Source\Components\Modules + + Source\Components\Modules + @@ -226,5 +229,8 @@ Source\Components\Modules + + Source\Components\Modules + \ No newline at end of file