Map dependencies
This commit is contained in:
parent
18cc328efc
commit
ca9725e5a4
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user