From b8aa24b19d2ec2c3b2efb511309b4e2aca28fa8e Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 13 Jan 2017 15:44:46 +0100 Subject: [PATCH] [ZoneBuilder] Add support for empty assets --- src/Components/Modules/AssetHandler.cpp | 7 ++- src/Components/Modules/AssetHandler.hpp | 2 +- .../Modules/AssetInterfaces/IMaterial.cpp | 5 +- src/Components/Modules/Materials.cpp | 4 +- src/Components/Modules/ZoneBuilder.cpp | 55 ++++++++++++++++++- src/Components/Modules/ZoneBuilder.hpp | 4 ++ src/Game/Functions.cpp | 2 + src/Game/Functions.hpp | 6 ++ 8 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index 6a38f45f..041c548c 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -274,7 +274,7 @@ namespace Components } } - Game::XAssetHeader AssetHandler::FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder) + Game::XAssetHeader AssetHandler::FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder, bool isSubAsset) { Game::XAssetHeader header = { 0 }; if (type >= Game::XAssetType::ASSET_TYPE_COUNT) return header; @@ -296,6 +296,11 @@ namespace Components } } + if (!header.data && isSubAsset) + { + header = ZoneBuilder::GetEmptyAssetIfCommon(type, filename, builder); + } + if (!header.data) { header = Game::DB_FindXAssetHeader(type, filename.data()); diff --git a/src/Components/Modules/AssetHandler.hpp b/src/Components/Modules/AssetHandler.hpp index 602c6c05..20705d77 100644 --- a/src/Components/Modules/AssetHandler.hpp +++ b/src/Components/Modules/AssetHandler.hpp @@ -34,7 +34,7 @@ namespace Components static void ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder); static Game::XAssetHeader FindOriginalAsset(Game::XAssetType type, const char* filename); - static Game::XAssetHeader FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder); + static Game::XAssetHeader FindAssetForZone(Game::XAssetType type, std::string filename, ZoneBuilder::Zone* builder, bool isSubAsset = true); static void ClearTemporaryAssets(); static void StoreTemporaryAsset(Game::XAssetType type, Game::XAssetHeader asset); diff --git a/src/Components/Modules/AssetInterfaces/IMaterial.cpp b/src/Components/Modules/AssetInterfaces/IMaterial.cpp index d8f1eaf7..85cd78da 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterial.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterial.cpp @@ -125,7 +125,10 @@ namespace Assets Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_MATERIAL, [](Game::XAssetHeader header, void* data) { Game::Material* material = reinterpret_cast(data); - if (std::string(material->techniqueSet->name) == header.material->techniqueSet->name) + const char* name = material->techniqueSet->name; + if (name[0] == ',') ++name; + + if (std::string(name) == header.material->techniqueSet->name) { material->sortKey = header.material->sortKey; diff --git a/src/Components/Modules/Materials.cpp b/src/Components/Modules/Materials.cpp index 91426328..8243877e 100644 --- a/src/Components/Modules/Materials.cpp +++ b/src/Components/Modules/Materials.cpp @@ -129,8 +129,8 @@ namespace Components int Materials::MaterialComparePrint(Game::Material* m1, Game::Material* m2) { - static Game::Material* a = m1; - static Game::Material* b = m2; + static Game::Material* a,* b; + a = m1, b = m2; return Utils::Hook::Call(0x5235B0)(m1, m2); } diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index b9cf3be6..c79834f3 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -7,6 +7,8 @@ namespace Components std::string ZoneBuilder::TraceZone; std::vector> ZoneBuilder::TraceAssets; + std::vector> ZoneBuilder::CommonAssets; + ZoneBuilder::Zone::Zone(std::string name) : dataMap("zone_source/" + name + ".csv"), zoneName(name), indexStart(0), externalSize(0), branding { 0 }, // Reserve 100MB by default. @@ -172,7 +174,11 @@ namespace Components bool ZoneBuilder::Zone::loadAsset(Game::XAssetType type, void* data, bool isSubAsset) { Game::XAsset asset{ type, { data } }; - return this->loadAsset(type, Game::DB_GetXAssetName(&asset), isSubAsset); + + const char* name = Game::DB_GetXAssetName(&asset); + + if (name) return this->loadAsset(type, std::string(name), isSubAsset); + else return false; } bool ZoneBuilder::Zone::loadAsset(Game::XAssetType type, std::string name, bool isSubAsset) @@ -184,6 +190,9 @@ namespace Components { Game::XAssetType type = Game::DB_GetXAssetNameType(typeName.data()); + // Sanitize name for empty assets + if (name[0] == ',') name.erase(name.begin()); + if (this->findAsset(type, name) != -1 || this->findSubAsset(type, name).data) return true; if (type == Game::XAssetType::ASSET_TYPE_INVALID || type >= Game::XAssetType::ASSET_TYPE_COUNT) @@ -192,7 +201,7 @@ namespace Components return false; } - Game::XAssetHeader assetHeader = AssetHandler::FindAssetForZone(type, name, this); + Game::XAssetHeader assetHeader = AssetHandler::FindAssetForZone(type, name, this, isSubAsset); if (!assetHeader.data) { Logger::Error("Error: Missing asset '%s' of type '%s'\n", name.data(), Game::DB_GetXAssetTypeName(type)); @@ -220,6 +229,8 @@ namespace Components int ZoneBuilder::Zone::findAsset(Game::XAssetType type, std::string name) { + if (name[0] == ',') name.erase(name.begin()); + for (unsigned int i = 0; i < this->loadedAssets.size(); ++i) { Game::XAsset* asset = &this->loadedAssets[i]; @@ -227,6 +238,7 @@ namespace Components if (asset->type != type) continue; const char* assetName = Game::DB_GetXAssetName(asset); + if (assetName[0] == ',') ++assetName; if (name == assetName) { @@ -239,6 +251,8 @@ namespace Components Game::XAssetHeader ZoneBuilder::Zone::findSubAsset(Game::XAssetType type, std::string name) { + if (name[0] == ',') name.erase(name.begin()); + for (unsigned int i = 0; i < this->loadedSubAssets.size(); ++i) { Game::XAsset* asset = &this->loadedSubAssets[i]; @@ -246,6 +260,7 @@ namespace Components if (asset->type != type) continue; const char* assetName = Game::DB_GetXAssetName(asset); + if (assetName[0] == ',') ++assetName; if (name == assetName) { @@ -298,7 +313,7 @@ namespace Components asset.header = this->findSubAsset(type, name); if (!asset.header.data) { - Logger::Error("Missing required asset '%s' (%s). Export failed!", name, Game::DB_GetXAssetTypeName(type)); + Logger::Error("Missing required asset '%s' (%s). Export failed!", name.data(), Game::DB_GetXAssetTypeName(type)); } #ifdef DEBUG @@ -635,6 +650,33 @@ namespace Components return AssetTrace; } + Game::XAssetHeader ZoneBuilder::GetEmptyAssetIfCommon(Game::XAssetType type, std::string name, ZoneBuilder::Zone* builder) + { + Game::XAssetHeader header = { 0 }; + + if (type >= 0 && type < Game::XAssetType::ASSET_TYPE_COUNT) + { + for (auto& asset : ZoneBuilder::CommonAssets) + { + if (asset.first == type && asset.second == name) + { + // Allocate an empty asset (filled with zeros), + header.data = builder->getAllocator()->allocate(Game::DB_GetXAssetSizeHandlers[type]()); + + // Set the name to the original name, so it can be stored + Game::DB_SetXAssetNameHandlers[type](&header, name.data()); + AssetHandler::StoreTemporaryAsset(type, header); + + // Set the name to the empty name + Game::DB_SetXAssetNameHandlers[type](&header, builder->getAllocator()->duplicateString("," + name)); + break; + } + } + } + + return header; + } + int ZoneBuilder::StoreTexture(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image) { size_t size = 16 + (*loadDef)->resourceSize; @@ -714,6 +756,12 @@ namespace Components AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader /*asset*/, std::string name, bool* /*restrict*/) { + // This is used to track which assets can be stored as empty assets + if (FastFiles::Current() == "common_mp") + { + ZoneBuilder::CommonAssets.push_back({ type, name }); + } + if (!ZoneBuilder::TraceZone.empty() && ZoneBuilder::TraceZone == FastFiles::Current()) { ZoneBuilder::TraceAssets.push_back({ type, name }); @@ -812,5 +860,6 @@ namespace Components ZoneBuilder::~ZoneBuilder() { assert(ZoneBuilder::MemAllocator.empty()); + ZoneBuilder::CommonAssets.clear(); } } diff --git a/src/Components/Modules/ZoneBuilder.hpp b/src/Components/Modules/ZoneBuilder.hpp index adddca6a..33684481 100644 --- a/src/Components/Modules/ZoneBuilder.hpp +++ b/src/Components/Modules/ZoneBuilder.hpp @@ -100,9 +100,13 @@ namespace Components static std::string TraceZone; static std::vector> TraceAssets; + static std::vector> CommonAssets; + static void BeginAssetTrace(std::string zone); static std::vector> EndAssetTrace(); + static Game::XAssetHeader GetEmptyAssetIfCommon(Game::XAssetType type, std::string name, Zone* builder); + private: static Utils::Memory::Allocator MemAllocator; static int StoreTexture(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 85b3dbcd..b59c0a3b 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -57,6 +57,8 @@ namespace Game DB_ReadXFile_t DB_ReadXFile = (DB_ReadXFile_t)0x445460; DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed = (DB_ReadXFileUncompressed_t)0x4705E0; DB_ReleaseXAssetHandler_t* DB_ReleaseXAssetHandlers = (DB_ReleaseXAssetHandler_t*)0x799AB8; + DB_SetXAssetName_t DB_SetXAssetName = (DB_SetXAssetName_t)0x453580; + DB_SetXAssetNameHandler_t* DB_SetXAssetNameHandlers = (DB_SetXAssetNameHandler_t*)0x7993D8; DB_XModelSurfsFixup_t DB_XModelSurfsFixup = (DB_XModelSurfsFixup_t)0x5BAC50; Dvar_RegisterBool_t Dvar_RegisterBool = (Dvar_RegisterBool_t)0x4CE1A0; diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 4a08c5e5..43e63a1b 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -138,6 +138,12 @@ namespace Game typedef void(__cdecl * DB_ReleaseXAssetHandler_t)(XAssetHeader header); extern DB_ReleaseXAssetHandler_t* DB_ReleaseXAssetHandlers; + typedef void(__cdecl * DB_SetXAssetName_t)(XAsset* asset, const char* name); + extern DB_SetXAssetName_t DB_SetXAssetName; + + typedef void(__cdecl * DB_SetXAssetNameHandler_t)(XAssetHeader* header, const char* name); + extern DB_SetXAssetNameHandler_t* DB_SetXAssetNameHandlers; + typedef void(__cdecl * DB_XModelSurfsFixup_t)(XModel* model); extern DB_XModelSurfsFixup_t DB_XModelSurfsFixup;