From 4103e4d174bc4c3fdb2c6fe95fa30ea031613681 Mon Sep 17 00:00:00 2001 From: Louve <33836535+Rackover@users.noreply.github.com> Date: Fri, 17 Feb 2023 12:26:40 +0100 Subject: [PATCH] IW4Of Fixes (#775) Co-authored-by: Louvenarde Co-authored-by: FutureRave --- deps/iw4-open-formats | 2 +- deps/premake/iw4-open-formats.lua | 3 +- .../AssetInterfaces/IMaterialTechniqueSet.cpp | 29 ++++++++++++++++- .../Modules/AssetInterfaces/IclipMap_t.cpp | 2 +- src/Components/Modules/Maps.cpp | 29 +++++++++++++---- src/Components/Modules/Maps.hpp | 2 +- src/Components/Modules/ZoneBuilder.cpp | 32 ++++++++++++------- src/Components/Modules/ZoneBuilder.hpp | 2 +- src/Game/Database.cpp | 3 ++ src/Game/Structs.hpp | 7 ++++ 10 files changed, 87 insertions(+), 24 deletions(-) diff --git a/deps/iw4-open-formats b/deps/iw4-open-formats index 2dde0c21..6ef68c85 160000 --- a/deps/iw4-open-formats +++ b/deps/iw4-open-formats @@ -1 +1 @@ -Subproject commit 2dde0c2103aab094f27b3c1daa790995df54faef +Subproject commit 6ef68c8535b60c681b179608f0c95fe0893e8937 diff --git a/deps/premake/iw4-open-formats.lua b/deps/premake/iw4-open-formats.lua index ebf18c32..e4d169b7 100644 --- a/deps/premake/iw4-open-formats.lua +++ b/deps/premake/iw4-open-formats.lua @@ -17,7 +17,8 @@ end function iw4_open_formats.project() project "iw4-open-formats" language "C++" - + cppdialect "C++latest" + iw4_open_formats.includes() pchheader "std_include.hpp" diff --git a/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp b/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp index 3329ac78..dc5ed039 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterialTechniqueSet.cpp @@ -22,7 +22,34 @@ namespace Assets void IMaterialTechniqueSet::loadFromDisk(Game::XAssetHeader* header, const std::string& name, Components::ZoneBuilder::Zone* builder) { - header->techniqueSet = builder->getIW4OfApi()->read(Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET, name); + header->techniqueSet = builder->getIW4OfApi()->read(Game::ASSET_TYPE_TECHNIQUE_SET, name); + + auto ptr = header->techniqueSet; + if (!ptr) + { + return; + } + + while (ptr->remappedTechniqueSet && ptr->remappedTechniqueSet != ptr) + { + ptr = ptr->remappedTechniqueSet; + builder->loadAsset(Game::ASSET_TYPE_TECHNIQUE_SET, ptr, false); + + for (size_t i = 0; i < Game::TECHNIQUE_COUNT; i++) + { + const auto technique = ptr->techniques[i]; + if (technique) + { + for (size_t j = 0; j < technique->passCount; j++) + { + const auto pass = &technique->passArray[j]; + builder->loadAsset(Game::ASSET_TYPE_VERTEXDECL, pass->vertexDecl, true); + builder->loadAsset(Game::ASSET_TYPE_PIXELSHADER, pass->pixelShader, true); + builder->loadAsset(Game::ASSET_TYPE_VERTEXSHADER, pass->vertexShader, true); + } + } + } + } } void IMaterialTechniqueSet::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) diff --git a/src/Components/Modules/AssetInterfaces/IclipMap_t.cpp b/src/Components/Modules/AssetInterfaces/IclipMap_t.cpp index 5d3ed66e..c6767261 100644 --- a/src/Components/Modules/AssetInterfaces/IclipMap_t.cpp +++ b/src/Components/Modules/AssetInterfaces/IclipMap_t.cpp @@ -572,7 +572,7 @@ namespace Assets } } - builder->loadAsset(Game::XAssetType::ASSET_TYPE_MAP_ENTS, asset); + builder->loadAsset(Game::XAssetType::ASSET_TYPE_MAP_ENTS, asset->mapEnts); } void IclipMap_t::load(Game::XAssetHeader* header, const std::string& _name, Components::ZoneBuilder::Zone* builder) diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index 7a6f26a3..e80f3984 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -666,12 +666,25 @@ namespace Components return Utils::Hook::Call(0x5050C0)(ent); } - int16 Maps::CM_TriggerModelBounds(int modelPointer, Game::Bounds* bounds) { -#ifdef DEBUG - Game::MapEnts* ents = *reinterpret_cast(0x1AA651C); // Use me for debugging - (void)ents; -#endif - return Utils::Hook::Call(0x4416C0)(modelPointer, bounds); + unsigned short Maps::CM_TriggerModelBounds_Hk(unsigned int triggerIndex, Game::Bounds* bounds) + { + + auto* ents = *reinterpret_cast(0x1AA651C); // Use me for debugging + + if (ents) + { + if (triggerIndex >= ents->trigger.count) + { + Logger::Error(Game::errorParm_t::ERR_DROP, "Invalid trigger index ({}) in entities exceeds the maximum trigger count ({}) defined in the clipmap. Check your map ents, or your clipmap!", triggerIndex, ents->trigger.count); + return 0; + } + else + { + return Utils::Hook::Call(0x4416C0)(triggerIndex, bounds); + } + } + + return 0; } Maps::Maps() @@ -714,11 +727,13 @@ namespace Components Utils::Hook(0x5EE577, Maps::G_SpawnTurretHook, HOOK_CALL).install()->quick(); Utils::Hook(0x44A4D5, Maps::G_SpawnTurretHook, HOOK_CALL).install()->quick(); + // Catch trigger errors before they're critical + Utils::Hook(0x5050D4, Maps::CM_TriggerModelBounds_Hk, HOOK_CALL).install()->quick(); + #ifdef DEBUG // Check trigger models Utils::Hook(0x5FC0F1, Maps::SV_SetTriggerModelHook, HOOK_CALL).install()->quick(); Utils::Hook(0x5FC2671, Maps::SV_SetTriggerModelHook, HOOK_CALL).install()->quick(); - Utils::Hook(0x5050D4, Maps::CM_TriggerModelBounds, HOOK_CALL).install()->quick(); #endif // diff --git a/src/Components/Modules/Maps.hpp b/src/Components/Modules/Maps.hpp index b5a6ef2a..28e1d89f 100644 --- a/src/Components/Modules/Maps.hpp +++ b/src/Components/Modules/Maps.hpp @@ -121,6 +121,6 @@ namespace Components static void G_SpawnTurretHook(Game::gentity_s* ent, int unk, int unk2); static bool SV_SetTriggerModelHook(Game::gentity_s* ent); - static int16 CM_TriggerModelBounds(int brushModelPointer, Game::Bounds* bounds); + static unsigned short CM_TriggerModelBounds_Hk(unsigned int brushModelPointer, Game::Bounds* bounds); }; } diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index db46346f..24a574b9 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -29,9 +29,9 @@ namespace Components zoneName(name), dataMap("zone_source/" + name + ".csv"), branding{nullptr}, - assetDepth(0) + assetDepth(0), + iw4ofApi(getIW4OfApiParams()) { - this->initializeIW4OfApi(); } ZoneBuilder::Zone::~Zone() @@ -535,18 +535,21 @@ namespace Components // Add branding asset void ZoneBuilder::Zone::addBranding() { - constexpr auto* data = "Built using the IW4x Zone:B:uilder Version 4"; - auto dataLen = std::strlen(data); // + 1 is added by the save code + static std::string zoneBranding; - this->branding = {this->zoneName.data(), 0, static_cast(dataLen), data}; + const auto now = std::chrono::system_clock::now(); + zoneBranding = std::format("Built using the IW4x ZoneBuilder! {:%d-%m-%Y %H:%M:%OS}", now); + auto brandingLen = zoneBranding.size(); // + 1 is added by the save code - if (this->findAsset(Game::XAssetType::ASSET_TYPE_RAWFILE, this->branding.name) != -1) + this->branding = {this->zoneName.data(), 0, static_cast(brandingLen), zoneBranding.data()}; + + if (this->findAsset(Game::ASSET_TYPE_RAWFILE, this->branding.name) != -1) { Logger::Error(Game::ERR_FATAL, "Unable to add branding. Asset '{}' already exists!", this->branding.name); } Game::XAssetHeader header = { &this->branding }; - Game::XAsset brandingAsset = { Game::XAssetType::ASSET_TYPE_RAWFILE, header }; + Game::XAsset brandingAsset = { Game::ASSET_TYPE_RAWFILE, header }; this->loadedAssets.push_back(brandingAsset); } @@ -757,7 +760,7 @@ namespace Components return header; } - void ZoneBuilder::Zone::initializeIW4OfApi() + iw4of::params_t ZoneBuilder::Zone::getIW4OfApiParams() { iw4of::params_t params; @@ -787,7 +790,7 @@ namespace Components switch (t) { case iw4of::params_t::P_ERR: - Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}", message); + Logger::Error(Game::ERR_FATAL, "{}", message); break; case iw4of::params_t::P_WARN: Logger::Print("{}", message); @@ -795,9 +798,16 @@ namespace Components } }; - params.work_directory = (*Game::fs_basepath)->current.string; + if (*Game::fs_basepath && *Game::fs_gameDirVar) + { + params.work_directory = std::format("{}/{}", (*Game::fs_basepath)->current.string, (*Game::fs_gameDirVar)->current.string); + } + else + { + Logger::Error(Game::ERR_FATAL, "Missing FS Game directory or basepath directory!"); + } - this->iw4ofApi = iw4of::api{ params }; + return params; } int ZoneBuilder::StoreTexture(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image) diff --git a/src/Components/Modules/ZoneBuilder.hpp b/src/Components/Modules/ZoneBuilder.hpp index 5bbc5359..2b5fe4de 100644 --- a/src/Components/Modules/ZoneBuilder.hpp +++ b/src/Components/Modules/ZoneBuilder.hpp @@ -90,7 +90,7 @@ namespace Components void addBranding(); - void initializeIW4OfApi(); + iw4of::params_t getIW4OfApiParams(); uint32_t safeGetPointer(const void* pointer); diff --git a/src/Game/Database.cpp b/src/Game/Database.cpp index 71e2926b..39c188b2 100644 --- a/src/Game/Database.cpp +++ b/src/Game/Database.cpp @@ -48,6 +48,9 @@ namespace Game const char* DB_GetXAssetName(XAsset* asset) { if (!asset) return ""; + + assert(asset->header.data); + return DB_GetXAssetNameHandlers[asset->type](&asset->header); } diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 15f0cc33..0f755fbf 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -7801,6 +7801,13 @@ namespace Game R_RENDERTARGET_NONE = 0xD, }; + struct GfxDrawPrimArgs + { + int vertexCount; + int triCount; + int baseIndex; + }; + struct GfxCmdBufState { char refSamplerState[16];