Map dependencies

This commit is contained in:
momo5502 2015-12-26 14:27:34 +01:00
parent 18cc328efc
commit ca9725e5a4
8 changed files with 162 additions and 57 deletions

View File

@ -114,12 +114,12 @@ namespace Components
} }
} }
void AssetHandler::On(Game::XAssetType type, AssetHandler::Callback callback) void AssetHandler::OnFind(Game::XAssetType type, AssetHandler::Callback callback)
{ {
AssetHandler::TypeCallbacks[type] = callback; AssetHandler::TypeCallbacks[type] = callback;
} }
void AssetHandler::Restrict(RestrictCallback callback) void AssetHandler::OnLoad(RestrictCallback callback)
{ {
AssetHandler::RestrictCallbacks.push_back(callback); AssetHandler::RestrictCallbacks.push_back(callback);
} }

View File

@ -10,8 +10,11 @@ namespace Components
~AssetHandler(); ~AssetHandler();
const char* GetName() { return "AssetHandler"; }; const char* GetName() { return "AssetHandler"; };
static void On(Game::XAssetType type, Callback callback); static void OnFind(Game::XAssetType type, Callback callback);
static void Restrict(RestrictCallback callback); static void OnLoad(RestrictCallback callback);
static const bool Restrict;
static const bool Load;
private: private:
static bool BypassState; static bool BypassState;

View File

@ -5,60 +5,142 @@ namespace Components
void* Maps::WorldMP = 0; void* Maps::WorldMP = 0;
void* Maps::WorldSP = 0; void* Maps::WorldSP = 0;
std::map<std::string, std::string> Maps::DependencyList;
std::vector<std::string> Maps::CurrentDependencies;
std::vector<Game::XAssetEntry> Maps::EntryPool;
void Maps::LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync)
{
Maps::CurrentDependencies.clear();
for (auto i = Maps::DependencyList.begin(); i != Maps::DependencyList.end(); i++)
{
if (std::regex_match(zoneInfo->name, std::regex(i->first)))
{
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), i->second) == Maps::CurrentDependencies.end())
{
Maps::CurrentDependencies.push_back(i->second);
}
}
}
Game::XZoneInfo* data = new Game::XZoneInfo[zoneCount + Maps::CurrentDependencies.size()];
memcpy(data, zoneInfo, sizeof(Game::XZoneInfo) * zoneCount);
for (unsigned int i = 0; i < Maps::CurrentDependencies.size(); i++)
{
data[zoneCount + i].name = (&Maps::CurrentDependencies[i])->data();
data[zoneCount + i].allocFlags = data->allocFlags;
data[zoneCount + i].freeFlags = data->freeFlags;
}
Game::DB_LoadXAssets(data, zoneCount + Maps::CurrentDependencies.size(), sync);
delete[] data;
}
bool Maps::LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const char* name)
{
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end())
{
if (type == Game::XAssetType::ASSET_TYPE_GAME_MAP_MP || type == Game::XAssetType::ASSET_TYPE_COL_MAP_MP || type == Game::XAssetType::ASSET_TYPE_GFX_MAP || type == Game::XAssetType::ASSET_TYPE_MAP_ENTS || type == Game::XAssetType::ASSET_TYPE_COM_MAP || type == Game::XAssetType::ASSET_TYPE_FX_MAP)
{
return false;
}
}
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;
}
void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname) void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname)
{ {
if (_strnicmp("mp_", mapname, 3)) if (_strnicmp("mp_", mapname, 3))
{ {
format = "maps/%s.d3dbsp"; format = "maps/%s.d3dbsp";
Utils::Hook::Set<void*>(0x4D90B7, (char*)Maps::WorldSP + 52); // Adjust pointer to GameMap_Data
Utils::Hook::Set<void*>(0x4D90B7, Maps::WorldSP);
} }
else else
{ {
Utils::Hook::Set<void*>(0x4D90B7, (char*)Maps::WorldMP + 4); // Adjust pointer to GameMap_Data
Utils::Hook::Set<void*>(0x4D90B7, Maps::WorldMP);
} }
_snprintf(buffer, size, format, mapname); _snprintf(buffer, size, format, mapname);
} }
typedef struct void Maps::AddDependency(std::string expression, std::string zone)
{ {
char unknown[16]; // Test expression before adding it
} xAssetEntry_t; try
static xAssetEntry_t xEntries[789312];
void ReallocXAssetEntries()
{ {
int newsize = 516 * 2048; std::regex _(expression);
//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;
} }
catch (std::exception e)
{
MessageBoxA(0, Utils::VA("Invalid regular expression: %s", expression.data()), "Warning", MB_ICONEXCLAMATION);
return;
} }
*(DWORD*)0x5BAEB0 = 789312; Maps::DependencyList[expression] = zone;
}
void Maps::ReallocateEntryPool()
{
static_assert(sizeof(Game::XAssetEntry) == 16, "XAssetEntry size mismatch");
Maps::EntryPool.clear();
Maps::EntryPool.resize(789312);
// Apply new size
Utils::Hook::Set<DWORD>(0x5BAEB0, Maps::EntryPool.size());
// Apply new pool
Utils::Hook::Set<Game::XAssetEntry*>(0x48E6F4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x4C67E4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x4C8584, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA8, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0C4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB0F5, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB1D4, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB235, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB278, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB34C, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB484, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB570, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB6B7, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB844, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BB98D, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBA66, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBB8D, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBCB1, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBD9B, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBE4C, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF14, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBF54, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BBFB8, Maps::EntryPool.data());
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAE91, Maps::EntryPool.data() + 1);
Utils::Hook::Set<Game::XAssetEntry*>(0x5BAEA2, Maps::EntryPool.data() + 1);
} }
Maps::Maps() Maps::Maps()
{ {
// Restrict asset loading
AssetHandler::OnLoad(Maps::LoadAssetRestrict);
// hunk size (was 300 MiB) // hunk size (was 300 MiB)
Utils::Hook::Set<DWORD>(0x64A029, 0x1C200000); // 450 MiB Utils::Hook::Set<DWORD>(0x64A029, 0x1C200000); // 450 MiB
Utils::Hook::Set<DWORD>(0x64A057, 0x1C200000); Utils::Hook::Set<DWORD>(0x64A057, 0x1C200000);
@ -66,8 +148,11 @@ namespace Components
// Intercept BSP name resolving // Intercept BSP name resolving
Utils::Hook(0x4C5979, Maps::GetBSPName, HOOK_CALL).Install()->Quick(); Utils::Hook(0x4C5979, Maps::GetBSPName, HOOK_CALL).Install()->Quick();
Maps::WorldSP = Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAME_MAP_SP, 1); // Intercept map zone loading
Maps::WorldMP = Utils::Hook::Get<char*>(0x4D90B7) - 4; Utils::Hook(0x42C2AF, Maps::LoadMapZones, HOOK_CALL).Install()->Quick();
Maps::WorldSP = reinterpret_cast<char*>(Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAME_MAP_SP, 1)) + 52; // Skip name and other padding to reach world data
Maps::WorldMP = Utils::Hook::Get<char*>(0x4D90B7);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168); Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700); Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700);
@ -83,22 +168,16 @@ namespace Components
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, 2400); Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, 2400);
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_STRINGTABLE, 800); Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_STRINGTABLE, 800);
ReallocXAssetEntries(); Maps::ReallocateEntryPool();
AssetHandler::Restrict([] (Game::XAssetType type, Game::XAssetHeader asset, const char* name) -> bool // Dependencies
{ Maps::AddDependency("oilrig", "mp_subbase");
if (type == Game::XAssetType::ASSET_TYPE_MAP_ENTS) Maps::AddDependency("gulag", "mp_subbase");
{ Maps::AddDependency("^(?!mp_).*", "mp_subbase"); // All maps not starting with "mp_"
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; Maps::~Maps()
}); {
Maps::EntryPool.clear();
} }
} }

View File

@ -4,12 +4,24 @@ namespace Components
{ {
public: public:
Maps(); Maps();
~Maps();
const char* GetName() { return "Maps"; }; const char* GetName() { return "Maps"; };
static void AddDependency(std::string expression, std::string zone);
private: private:
static void* WorldMP; static void* WorldMP;
static void* WorldSP; static void* WorldSP;
static std::vector<Game::XAssetEntry> EntryPool;
static std::map<std::string, std::string> DependencyList;
static std::vector<std::string> CurrentDependencies;
static void GetBSPName(char* buffer, size_t size, const char* format, const char* mapname); static void GetBSPName(char* buffer, size_t size, const char* format, const char* mapname);
static bool LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const char* name);
static void LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);
void ReallocateEntryPool();
}; };
} }

View File

@ -442,7 +442,7 @@ namespace Components
Menus::Menus() Menus::Menus()
{ {
AssetHandler::On(Game::XAssetType::ASSET_TYPE_MENUFILE, Menus::MenuFileLoad); AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_MENUFILE, Menus::MenuFileLoad);
//Utils::Hook(0x63FE80, Menus::MenuFileLoad, HOOK_JUMP).Install()->Quick(); //Utils::Hook(0x63FE80, Menus::MenuFileLoad, HOOK_JUMP).Install()->Quick();
// Custom Menus_FindByName // Custom Menus_FindByName

View File

@ -33,7 +33,7 @@ namespace Components
MusicalTalent::MusicalTalent() MusicalTalent::MusicalTalent()
{ {
AssetHandler::On(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ManipulateAliases); AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ManipulateAliases);
MusicalTalent::Replace("music_mainmenu_mp", "hz_boneyard_intro_LR_1.mp3"); MusicalTalent::Replace("music_mainmenu_mp", "hz_boneyard_intro_LR_1.mp3");
} }

View File

@ -880,4 +880,14 @@ namespace Game
XAssetType type; XAssetType type;
XAssetHeader header; XAssetHeader header;
}; };
struct XAssetEntry
{
XAsset asset;
char zoneIndex;
bool inuse;
unsigned __int16 nextHash;
unsigned __int16 nextOverride;
unsigned __int16 usageFrame;
};
} }

View File

@ -16,9 +16,10 @@
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <vector> #include <vector>
#include <algorithm>
#include <sstream> #include <sstream>
#include <utility> #include <utility>
#include <algorithm>
#include <regex>
#include "Game\Structs.hpp" #include "Game\Structs.hpp"
#include "Game\Functions.hpp" #include "Game\Functions.hpp"