From 572965844ef7c87b22f914e1cfba7a70b84a9112 Mon Sep 17 00:00:00 2001 From: mo Date: Tue, 21 Jul 2026 18:55:40 +0100 Subject: [PATCH] feat: templated MapEnts dumper (#923) Relates to https://github.com/Laupetin/OpenAssetTools/issues/626 --- docs/SupportedAssetTypes.md | 6 +-- .../Game/IW3/Maps/MapEntsDumperIW3.cpp | 20 -------- .../Game/IW3/Maps/MapEntsDumperIW3.h | 13 ----- src/ObjWriting/Game/IW3/ObjWriterIW3.cpp | 2 +- src/ObjWriting/Game/IW4/ObjWriterIW4.cpp | 3 +- src/ObjWriting/Game/IW5/ObjWriterIW5.cpp | 3 +- .../Game/T4/Maps/MapEntsDumperT4.cpp | 20 -------- src/ObjWriting/Game/T4/Maps/MapEntsDumperT4.h | 13 ----- src/ObjWriting/Game/T4/ObjWriterT4.cpp | 2 +- .../Game/T5/Maps/MapEntsDumperT5.cpp | 20 -------- src/ObjWriting/Game/T5/Maps/MapEntsDumperT5.h | 13 ----- src/ObjWriting/Game/T5/ObjWriterT5.cpp | 2 +- .../Game/T6/Maps/MapEntsDumperT6.cpp | 20 -------- src/ObjWriting/Game/T6/Maps/MapEntsDumperT6.h | 13 ----- src/ObjWriting/Game/T6/ObjWriterT6.cpp | 2 +- .../Maps/MapEntsDumper.cpp.template | 33 +++++++++++++ src/ObjWriting/Maps/MapEntsDumper.h.template | 24 ++++++++++ test/SystemTests/Game/IW4/MapEntsIW4.cpp | 47 +++++++++++++++++++ 18 files changed, 115 insertions(+), 141 deletions(-) delete mode 100644 src/ObjWriting/Game/IW3/Maps/MapEntsDumperIW3.cpp delete mode 100644 src/ObjWriting/Game/IW3/Maps/MapEntsDumperIW3.h delete mode 100644 src/ObjWriting/Game/T4/Maps/MapEntsDumperT4.cpp delete mode 100644 src/ObjWriting/Game/T4/Maps/MapEntsDumperT4.h delete mode 100644 src/ObjWriting/Game/T5/Maps/MapEntsDumperT5.cpp delete mode 100644 src/ObjWriting/Game/T5/Maps/MapEntsDumperT5.h delete mode 100644 src/ObjWriting/Game/T6/Maps/MapEntsDumperT6.cpp delete mode 100644 src/ObjWriting/Game/T6/Maps/MapEntsDumperT6.h create mode 100644 src/ObjWriting/Maps/MapEntsDumper.cpp.template create mode 100644 src/ObjWriting/Maps/MapEntsDumper.h.template create mode 100644 test/SystemTests/Game/IW4/MapEntsIW4.cpp diff --git a/docs/SupportedAssetTypes.md b/docs/SupportedAssetTypes.md index 8fae0883..3d51b23b 100644 --- a/docs/SupportedAssetTypes.md +++ b/docs/SupportedAssetTypes.md @@ -59,7 +59,7 @@ using `Linker`): | ComWorld | ❌ | ❌ | | | GameWorldSp | ❌ | ❌ | | | GameWorldMp | ❌ | ❌ | | -| MapEnts | ❌ | ❌ | | +| MapEnts | ⁉️ | ❌ | Entity string can be exported. Binary data currently not. | | FxWorld | ❌ | ❌ | | | GfxWorld | ❌ | ❌ | | | GfxLightDef | ✅ | ✅ | | @@ -101,7 +101,7 @@ using `Linker`): | GlassWorld | ❌ | ❌ | | | PathData | ❌ | ❌ | | | VehicleTrack | ❌ | ❌ | | -| MapEnts | ❌ | ❌ | | +| MapEnts | ⁉️ | ❌ | Entity string can be exported. Binary data currently not. | | FxWorld | ❌ | ❌ | | | GfxWorld | ❌ | ❌ | | | GfxLightDef | ✅ | ✅ | | @@ -211,7 +211,7 @@ using `Linker`): | ComWorld | ❌ | ❌ | | | GameWorldSp | ❌ | ❌ | | | GameWorldMp | ❌ | ❌ | | -| MapEnts | ✅ | ❌ | | +| MapEnts | ⁉️ | ❌ | Entity string can be exported. Binary data currently not. | | GfxWorld | ❌ | ❌ | | | GfxLightDef | ✅ | ✅ | | | Font_s | ✅ | ✅ | | diff --git a/src/ObjWriting/Game/IW3/Maps/MapEntsDumperIW3.cpp b/src/ObjWriting/Game/IW3/Maps/MapEntsDumperIW3.cpp deleted file mode 100644 index 930f8415..00000000 --- a/src/ObjWriting/Game/IW3/Maps/MapEntsDumperIW3.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "MapEntsDumperIW3.h" - -#include "Maps/MapEntsCommon.h" - -using namespace IW3; - -namespace map_ents -{ - void DumperIW3::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) - { - const auto* mapEnts = asset.Asset(); - const auto assetFile = context.OpenAssetFile(GetEntsFileNameForAssetName(asset.m_name)); - - if (!assetFile) - return; - - auto& stream = *assetFile; - stream.write(mapEnts->entityString, std::max(mapEnts->numEntityChars - 1, 0)); - } -} // namespace map_ents diff --git a/src/ObjWriting/Game/IW3/Maps/MapEntsDumperIW3.h b/src/ObjWriting/Game/IW3/Maps/MapEntsDumperIW3.h deleted file mode 100644 index 06386c20..00000000 --- a/src/ObjWriting/Game/IW3/Maps/MapEntsDumperIW3.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Dumping/AbstractAssetDumper.h" -#include "Game/IW3/IW3.h" - -namespace map_ents -{ - class DumperIW3 final : public AbstractAssetDumper - { - protected: - void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; - }; -} // namespace map_ents diff --git a/src/ObjWriting/Game/IW3/ObjWriterIW3.cpp b/src/ObjWriting/Game/IW3/ObjWriterIW3.cpp index 0817aca3..2c7af7a9 100644 --- a/src/ObjWriting/Game/IW3/ObjWriterIW3.cpp +++ b/src/ObjWriting/Game/IW3/ObjWriterIW3.cpp @@ -2,13 +2,13 @@ #include "Game/IW3/Font/FontDumperIW3.h" #include "Game/IW3/Image/ImageDumperIW3.h" +#include "Game/IW3/Maps/MapEntsDumperIW3.h" #include "Game/IW3/Material/MaterialJsonDumperIW3.h" #include "Game/IW3/Techset/TechsetDumperIW3.h" #include "Game/IW3/XAnim/XAnimDumperIW3.h" #include "Game/IW3/XModel/XModelDumperIW3.h" #include "LightDef/LightDefDumperIW3.h" #include "Localize/LocalizeDumperIW3.h" -#include "Maps/MapEntsDumperIW3.h" #include "PhysPreset/PhysPresetInfoStringDumperIW3.h" #include "RawFile/RawFileDumperIW3.h" #include "Sound/LoadedSoundDumperIW3.h" diff --git a/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp b/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp index 97873a28..28626bff 100644 --- a/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp +++ b/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp @@ -2,6 +2,7 @@ #include "Game/IW4/Font/FontDumperIW4.h" #include "Game/IW4/Image/ImageDumperIW4.h" +#include "Game/IW4/Maps/MapEntsDumperIW4.h" #include "Game/IW4/Material/MaterialJsonDumperIW4.h" #include "Game/IW4/Techset/PixelShaderDumperIW4.h" #include "Game/IW4/Techset/TechsetDumperIW4.h" @@ -55,7 +56,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) // REGISTER_DUMPER(AssetDumperComWorld) // REGISTER_DUMPER(AssetDumperGameWorldSp) // REGISTER_DUMPER(AssetDumperGameWorldMp) - // REGISTER_DUMPER(AssetDumperMapEnts) + RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumperFxWorld) // REGISTER_DUMPER(AssetDumperGfxWorld) RegisterAssetDumper(std::make_unique()); diff --git a/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp b/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp index 9100d546..14ff1d7f 100644 --- a/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp +++ b/src/ObjWriting/Game/IW5/ObjWriterIW5.cpp @@ -3,6 +3,7 @@ #include "Game/IW4/XAnim/XAnimDumperIW4.h" #include "Game/IW5/Font/FontDumperIW5.h" #include "Game/IW5/Image/ImageDumperIW5.h" +#include "Game/IW5/Maps/MapEntsDumperIW5.h" #include "Game/IW5/Material/MaterialJsonDumperIW5.h" #include "Game/IW5/Techset/PixelShaderDumperIW5.h" #include "Game/IW5/Techset/TechsetDumperIW5.h" @@ -51,7 +52,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) // REGISTER_DUMPER(AssetDumperGlassWorld) // REGISTER_DUMPER(AssetDumperPathData) // REGISTER_DUMPER(AssetDumperVehicleTrack) - // REGISTER_DUMPER(AssetDumperMapEnts) + RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumperFxWorld) // REGISTER_DUMPER(AssetDumperGfxWorld) RegisterAssetDumper(std::make_unique()); diff --git a/src/ObjWriting/Game/T4/Maps/MapEntsDumperT4.cpp b/src/ObjWriting/Game/T4/Maps/MapEntsDumperT4.cpp deleted file mode 100644 index d4e760d1..00000000 --- a/src/ObjWriting/Game/T4/Maps/MapEntsDumperT4.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "MapEntsDumperT4.h" - -#include "Maps/MapEntsCommon.h" - -using namespace T4; - -namespace map_ents -{ - void DumperT4::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) - { - const auto* mapEnts = asset.Asset(); - const auto assetFile = context.OpenAssetFile(GetEntsFileNameForAssetName(asset.m_name)); - - if (!assetFile) - return; - - auto& stream = *assetFile; - stream.write(mapEnts->entityString, std::max(mapEnts->numEntityChars - 1, 0)); - } -} // namespace map_ents diff --git a/src/ObjWriting/Game/T4/Maps/MapEntsDumperT4.h b/src/ObjWriting/Game/T4/Maps/MapEntsDumperT4.h deleted file mode 100644 index 6851a1f4..00000000 --- a/src/ObjWriting/Game/T4/Maps/MapEntsDumperT4.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Dumping/AbstractAssetDumper.h" -#include "Game/T4/T4.h" - -namespace map_ents -{ - class DumperT4 final : public AbstractAssetDumper - { - protected: - void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; - }; -} // namespace map_ents diff --git a/src/ObjWriting/Game/T4/ObjWriterT4.cpp b/src/ObjWriting/Game/T4/ObjWriterT4.cpp index ff466d2d..a9c6a3cc 100644 --- a/src/ObjWriting/Game/T4/ObjWriterT4.cpp +++ b/src/ObjWriting/Game/T4/ObjWriterT4.cpp @@ -2,11 +2,11 @@ #include "Game/T4/Font/FontDumperT4.h" #include "Game/T4/Image/ImageDumperT4.h" +#include "Game/T4/Maps/MapEntsDumperT4.h" #include "Game/T4/Material/MaterialJsonDumperT4.h" #include "Game/T4/XAnim/XAnimDumperT4.h" #include "Game/T4/XModel/XModelDumperT4.h" #include "Localize/LocalizeDumperT4.h" -#include "Maps/MapEntsDumperT4.h" #include "PhysConstraints/PhysConstraintsInfoStringDumperT4.h" #include "RawFile/RawFileDumperT4.h" #include "Sound/LoadedSoundDumperT4.h" diff --git a/src/ObjWriting/Game/T5/Maps/MapEntsDumperT5.cpp b/src/ObjWriting/Game/T5/Maps/MapEntsDumperT5.cpp deleted file mode 100644 index db84b9d3..00000000 --- a/src/ObjWriting/Game/T5/Maps/MapEntsDumperT5.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "MapEntsDumperT5.h" - -#include "Maps/MapEntsCommon.h" - -using namespace T5; - -namespace map_ents -{ - void DumperT5::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) - { - const auto* mapEnts = asset.Asset(); - const auto assetFile = context.OpenAssetFile(GetEntsFileNameForAssetName(asset.m_name)); - - if (!assetFile) - return; - - auto& stream = *assetFile; - stream.write(mapEnts->entityString, std::max(mapEnts->numEntityChars - 1, 0)); - } -} // namespace map_ents diff --git a/src/ObjWriting/Game/T5/Maps/MapEntsDumperT5.h b/src/ObjWriting/Game/T5/Maps/MapEntsDumperT5.h deleted file mode 100644 index 2af21d5e..00000000 --- a/src/ObjWriting/Game/T5/Maps/MapEntsDumperT5.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Dumping/AbstractAssetDumper.h" -#include "Game/T5/T5.h" - -namespace map_ents -{ - class DumperT5 final : public AbstractAssetDumper - { - protected: - void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; - }; -} // namespace map_ents diff --git a/src/ObjWriting/Game/T5/ObjWriterT5.cpp b/src/ObjWriting/Game/T5/ObjWriterT5.cpp index 6233c9b4..cd29a7fb 100644 --- a/src/ObjWriting/Game/T5/ObjWriterT5.cpp +++ b/src/ObjWriting/Game/T5/ObjWriterT5.cpp @@ -2,13 +2,13 @@ #include "Game/T5/Font/FontDumperT5.h" #include "Game/T5/Image/ImageDumperT5.h" +#include "Game/T5/Maps/MapEntsDumperT5.h" #include "Game/T5/Material/MaterialJsonDumperT5.h" #include "Game/T5/Techset/TechsetDumperT5.h" #include "Game/T5/XAnim/XAnimDumperT5.h" #include "Game/T5/XModel/XModelDumperT5.h" #include "LightDef/LightDefDumperT5.h" #include "Localize/LocalizeDumperT5.h" -#include "Maps/MapEntsDumperT5.h" #include "PhysConstraints/PhysConstraintsInfoStringDumperT5.h" #include "PhysPreset/PhysPresetInfoStringDumperT5.h" #include "RawFile/RawFileDumperT5.h" diff --git a/src/ObjWriting/Game/T6/Maps/MapEntsDumperT6.cpp b/src/ObjWriting/Game/T6/Maps/MapEntsDumperT6.cpp deleted file mode 100644 index aebc69a4..00000000 --- a/src/ObjWriting/Game/T6/Maps/MapEntsDumperT6.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "MapEntsDumperT6.h" - -#include "Maps/MapEntsCommon.h" - -using namespace T6; - -namespace map_ents -{ - void DumperT6::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) - { - const auto* mapEnts = asset.Asset(); - const auto assetFile = context.OpenAssetFile(GetEntsFileNameForAssetName(asset.m_name)); - - if (!assetFile) - return; - - auto& stream = *assetFile; - stream.write(mapEnts->entityString, std::max(mapEnts->numEntityChars - 1, 0)); - } -} // namespace map_ents diff --git a/src/ObjWriting/Game/T6/Maps/MapEntsDumperT6.h b/src/ObjWriting/Game/T6/Maps/MapEntsDumperT6.h deleted file mode 100644 index 1aa8520b..00000000 --- a/src/ObjWriting/Game/T6/Maps/MapEntsDumperT6.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Dumping/AbstractAssetDumper.h" -#include "Game/T6/T6.h" - -namespace map_ents -{ - class DumperT6 final : public AbstractAssetDumper - { - protected: - void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; - }; -} // namespace map_ents diff --git a/src/ObjWriting/Game/T6/ObjWriterT6.cpp b/src/ObjWriting/Game/T6/ObjWriterT6.cpp index ae264e1f..05a30c1f 100644 --- a/src/ObjWriting/Game/T6/ObjWriterT6.cpp +++ b/src/ObjWriting/Game/T6/ObjWriterT6.cpp @@ -3,6 +3,7 @@ #include "FontIcon/FontIconDumperT6.h" #include "Game/T6/Font/FontDumperT6.h" #include "Game/T6/Image/ImageDumperT6.h" +#include "Game/T6/Maps/MapEntsDumperT6.h" #include "Game/T6/Material/MaterialJsonDumperT6.h" #include "Game/T6/Techset/TechsetDumperT6.h" #include "Game/T6/XAnim/XAnimDumperT6.h" @@ -11,7 +12,6 @@ #include "LightDef/LightDefDumperT6.h" #include "Localize/LocalizeDumperT6.h" #include "Maps/AddonMapEntsDumperT6.h" -#include "Maps/MapEntsDumperT6.h" #include "PhysConstraints/PhysConstraintsInfoStringDumperT6.h" #include "PhysPreset/PhysPresetInfoStringDumperT6.h" #include "Qdb/QdbDumperT6.h" diff --git a/src/ObjWriting/Maps/MapEntsDumper.cpp.template b/src/ObjWriting/Maps/MapEntsDumper.cpp.template new file mode 100644 index 00000000..d7f03c36 --- /dev/null +++ b/src/ObjWriting/Maps/MapEntsDumper.cpp.template @@ -0,0 +1,33 @@ +#options GAME (IW3, IW4, IW5, T4, T5, T6) + +#filename "Game/" + GAME + "/Maps/MapEntsDumper" + GAME + ".cpp" + +// This file was templated. +// See MapEntsDumper.cpp.template. +// Do not modify, changes will be lost. + +#set DUMPER_HEADER "\"MapEntsDumper" + GAME + ".h\"" +#include DUMPER_HEADER + +#include "Maps/MapEntsCommon.h" + +#include + +using namespace GAME; + +#set CLASS_NAME "Dumper" + GAME + +namespace map_ents +{ + void CLASS_NAME::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) + { + const auto* mapEnts = asset.Asset(); + const auto assetFile = context.OpenAssetFile(GetEntsFileNameForAssetName(asset.m_name)); + + if (!assetFile) + return; + + auto& stream = *assetFile; + stream.write(mapEnts->entityString, std::max(mapEnts->numEntityChars - 1, 0)); + } +} // namespace map_ents diff --git a/src/ObjWriting/Maps/MapEntsDumper.h.template b/src/ObjWriting/Maps/MapEntsDumper.h.template new file mode 100644 index 00000000..a3af4e24 --- /dev/null +++ b/src/ObjWriting/Maps/MapEntsDumper.h.template @@ -0,0 +1,24 @@ +#options GAME (IW3, IW4, IW5, T4, T5, T6) + +#filename "Game/" + GAME + "/Maps/MapEntsDumper" + GAME + ".h" + +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" +#set CLASS_NAME "Dumper" + GAME + +// This file was templated. +// See MapEntsDumper.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include GAME_HEADER + +namespace map_ents +{ + class CLASS_NAME final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace map_ents diff --git a/test/SystemTests/Game/IW4/MapEntsIW4.cpp b/test/SystemTests/Game/IW4/MapEntsIW4.cpp new file mode 100644 index 00000000..b80a6a09 --- /dev/null +++ b/test/SystemTests/Game/IW4/MapEntsIW4.cpp @@ -0,0 +1,47 @@ +#include "Game/IW4/Maps/MapEntsDumperIW4.h" +#include "SearchPath/MockOutputPath.h" +#include "SearchPath/MockSearchPath.h" +#include "ZoneLoading.h" + +#include +#include +#include + +using namespace IW4; + +namespace +{ + TEST_CASE("MapEnts dumper writes entity string (IW4)", "[iw4][mapents][system]") + { + constexpr auto MAP_ENTS_NAME = "maps/mp/test_map.d3dbsp"; + char entityString[] = R"({ +"classname" "worldspawn" +} +)"; + + TriggerModel triggerModel{}; + Stage stage{}; + MapEnts mapEnts{}; + mapEnts.name = MAP_ENTS_NAME; + mapEnts.entityString = entityString; + mapEnts.numEntityChars = sizeof(entityString); + mapEnts.trigger.count = 1; + mapEnts.trigger.models = &triggerModel; + mapEnts.stages = &stage; + mapEnts.stageCount = 1; + + Zone zone("MockZone", 0, GameId::IW4, GamePlatform::PC); + zone.m_pools.AddAsset(std::make_unique>(ASSET_TYPE_MAP_ENTS, mapEnts.name, &mapEnts)); + + MockSearchPath mockObjPath; + MockOutputPath mockOutput; + AssetDumpingContext dumpingContext(zone, "", mockOutput, mockObjPath, std::nullopt); + map_ents::DumperIW4 dumper; + dumper.Dump(dumpingContext); + + const auto* dumpedFile = mockOutput.GetMockedFile("maps/mp/test_map.d3dbsp.ents"); + REQUIRE(dumpedFile != nullptr); + REQUIRE(dumpedFile->m_data.size() == sizeof(entityString) - 1); + REQUIRE(dumpedFile->AsString() == entityString); + } +} // namespace