From bcafddd83a0a57c807eba02776852f8fe7f4e115 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 2 Jan 2022 10:25:48 +0100 Subject: [PATCH] Dump and load iw4 physpresets --- src/Common/Game/IW4/IW4_Assets.h | 15 ++ .../Game/IW4/InfoString/PhysPresetFields.h | 20 ++ .../AssetLoaders/AssetLoaderPhysPreset.cpp | 108 +++++++++ .../IW4/AssetLoaders/AssetLoaderPhysPreset.h | 9 + .../InfoStringToStructConverter.cpp | 223 ++++++++++++++++++ .../InfoString/InfoStringToStructConverter.h | 2 - .../AssetDumpers/AssetDumperPhysPreset.cpp | 101 ++++++++ .../IW4/AssetDumpers/AssetDumperPhysPreset.h | 18 ++ src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp | 3 +- 9 files changed, 496 insertions(+), 3 deletions(-) create mode 100644 src/ObjCommon/Game/IW4/InfoString/PhysPresetFields.h create mode 100644 src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysPreset.cpp create mode 100644 src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysPreset.h diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index 5fc75af4..4406002e 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -181,6 +181,21 @@ namespace IW4 bool perSurfaceSndAlias; }; + struct PhysPresetInfo + { + float mass; + float bounce; + float friction; + int isFrictionInfinity; + float bulletForceScale; + float explosiveForceScale; + const char* sndAliasPrefix; + float piecesSpreadFraction; + float piecesUpwardVelocity; + int tempDefaultToCylinder; + int perSurfaceSndAlias; + }; + struct Bounds { float midPoint[3]; diff --git a/src/ObjCommon/Game/IW4/InfoString/PhysPresetFields.h b/src/ObjCommon/Game/IW4/InfoString/PhysPresetFields.h new file mode 100644 index 00000000..be5a6f7b --- /dev/null +++ b/src/ObjCommon/Game/IW4/InfoString/PhysPresetFields.h @@ -0,0 +1,20 @@ +#pragma once +#include "Game/IW4/IW4.h" + +namespace IW4 +{ + inline cspField_t phys_preset_fields[] + { + { "mass", offsetof(PhysPresetInfo, mass), CSPFT_FLOAT }, + { "bounce", offsetof(PhysPresetInfo, bounce), CSPFT_FLOAT }, + { "friction", offsetof(PhysPresetInfo, friction), CSPFT_FLOAT }, + { "isFrictionInfinity", offsetof(PhysPresetInfo, isFrictionInfinity), CSPFT_QBOOLEAN }, + { "bulletForceScale", offsetof(PhysPresetInfo, bulletForceScale), CSPFT_FLOAT }, + { "explosiveForceScale", offsetof(PhysPresetInfo, explosiveForceScale), CSPFT_FLOAT }, + { "sndAliasPrefix", offsetof(PhysPresetInfo, sndAliasPrefix), CSPFT_STRING }, + { "piecesSpreadFraction", offsetof(PhysPresetInfo, piecesSpreadFraction), CSPFT_FLOAT }, + { "piecesUpwardVelocity", offsetof(PhysPresetInfo, piecesUpwardVelocity), CSPFT_FLOAT }, + { "tempDefaultToCylinder", offsetof(PhysPresetInfo, tempDefaultToCylinder), CSPFT_QBOOLEAN }, + { "perSurfaceSndAlias", offsetof(PhysPresetInfo, perSurfaceSndAlias), CSPFT_QBOOLEAN }, + }; +} \ No newline at end of file diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderPhysPreset.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderPhysPreset.cpp index fff18b2a..571bddd4 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderPhysPreset.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderPhysPreset.cpp @@ -1,13 +1,77 @@ #include "AssetLoaderPhysPreset.h" #include +#include #include "ObjLoading.h" #include "Game/IW4/IW4.h" +#include "Game/IW4/ObjConstantsIW4.h" +#include "Game/IW4/InfoString/InfoStringToStructConverter.h" +#include "Game/IW4/InfoString/PhysPresetFields.h" #include "Pool/GlobalAssetPool.h" using namespace IW4; +namespace IW4 +{ + class InfoStringToPhysPresetConverter final : public InfoStringToStructConverter + { + protected: + bool ConvertExtensionField(const cspField_t& field, const std::string& value) override + { + assert(false); + return false; + } + + public: + InfoStringToPhysPresetConverter(const InfoString& infoString, PhysPresetInfo* physPreset, ZoneScriptStrings& zoneScriptStrings, MemoryManager* memory, IAssetLoadingManager* manager, + const cspField_t* fields, const size_t fieldCount) + : InfoStringToStructConverter(infoString, physPreset, zoneScriptStrings, memory, manager, fields, fieldCount) + { + } + }; +} + +void AssetLoaderPhysPreset::CopyFromPhysPresetInfo(const PhysPresetInfo* physPresetInfo, PhysPreset* physPreset) +{ + physPreset->mass = std::clamp(physPresetInfo->mass, 1.0f, 2000.0f) * 0.001f; + physPreset->bounce = physPresetInfo->bounce; + + if (physPresetInfo->isFrictionInfinity != 0) + physPreset->friction = std::numeric_limits::infinity(); + else + physPreset->friction = physPresetInfo->friction; + + physPreset->bulletForceScale = physPresetInfo->bulletForceScale; + physPreset->explosiveForceScale = physPresetInfo->explosiveForceScale; + physPreset->sndAliasPrefix = physPresetInfo->sndAliasPrefix; + physPreset->piecesSpreadFraction = physPresetInfo->piecesSpreadFraction; + physPreset->piecesUpwardVelocity = physPresetInfo->piecesUpwardVelocity; + physPreset->tempDefaultToCylinder = physPresetInfo->tempDefaultToCylinder != 0; + physPreset->perSurfaceSndAlias = physPresetInfo->perSurfaceSndAlias != 0; +} + +bool AssetLoaderPhysPreset::LoadFromInfoString(const InfoString& infoString, const std::string& assetName, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) +{ + const auto presetInfo = std::make_unique(); + memset(presetInfo.get(), 0, sizeof(PhysPresetInfo)); + InfoStringToPhysPresetConverter converter(infoString, presetInfo.get(), zone->m_script_strings, memory, manager, phys_preset_fields, std::extent::value); + if (!converter.Convert()) + { + std::cout << "Failed to parse phys preset: \"" << assetName << "\"" << std::endl; + return true; + } + + auto* physPreset = memory->Create(); + + CopyFromPhysPresetInfo(presetInfo.get(), physPreset); + physPreset->name = memory->Dup(assetName.c_str()); + + manager->AddAsset(ASSET_TYPE_PHYSPRESET, assetName, physPreset, converter.GetDependencies(), converter.GetUsedScriptStrings()); + + return true; +} + void* AssetLoaderPhysPreset::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) { auto* physPreset = memory->Create(); @@ -15,3 +79,47 @@ void* AssetLoaderPhysPreset::CreateEmptyAsset(const std::string& assetName, Memo physPreset->name = memory->Dup(assetName.c_str()); return physPreset; } + +bool AssetLoaderPhysPreset::CanLoadFromGdt() const +{ + return true; +} + +bool AssetLoaderPhysPreset::LoadFromGdt(const std::string& assetName, IGdtQueryable* gdtQueryable, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + auto* gdtEntry = gdtQueryable->GetGdtEntryByGdfAndName(ObjConstants::GDF_FILENAME_PHYS_PRESET, assetName); + if (gdtEntry == nullptr) + return false; + + InfoString infoString; + if (!infoString.FromGdtProperties(*gdtEntry)) + { + std::cout << "Failed to read phys preset gdt entry: \"" << assetName << "\"" << std::endl; + return true; + } + + return LoadFromInfoString(infoString, assetName, memory, manager, zone); +} + +bool AssetLoaderPhysPreset::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderPhysPreset::LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto fileName = "physic/" + assetName; + const auto file = searchPath->Open(fileName); + if (!file.IsOpen()) + return false; + + InfoString infoString; + if (!infoString.FromStream(ObjConstants::INFO_STRING_PREFIX_PHYS_PRESET, *file.m_stream)) + { + std::cout << "Failed to read phys preset raw file: \"" << fileName << "\"" << std::endl; + return true; + } + + return LoadFromInfoString(infoString, assetName, memory, manager, zone); +} + diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderPhysPreset.h b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderPhysPreset.h index 277a63c9..ec73fb70 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderPhysPreset.h +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderPhysPreset.h @@ -2,13 +2,22 @@ #include "Game/IW4/IW4.h" #include "AssetLoading/BasicAssetLoader.h" +#include "InfoString/InfoString.h" #include "SearchPath/ISearchPath.h" namespace IW4 { class AssetLoaderPhysPreset final : public BasicAssetLoader { + static void CopyFromPhysPresetInfo(const PhysPresetInfo* physPresetInfo, PhysPreset* physPreset); + + static bool LoadFromInfoString(const InfoString& infoString, const std::string& assetName, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone); + public: _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromGdt() const override; + bool LoadFromGdt(const std::string& assetName, IGdtQueryable* gdtQueryable, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; + _NODISCARD bool CanLoadFromRaw() const override; + bool LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; }; } diff --git a/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.cpp b/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.cpp index ff2adce4..df9b5dd2 100644 --- a/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.cpp +++ b/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.cpp @@ -1,4 +1,227 @@ #include "InfoStringToStructConverter.h" +#include +#include + using namespace IW4; +InfoStringToStructConverter::InfoStringToStructConverter(const InfoString& infoString, void* structure, ZoneScriptStrings& zoneScriptStrings, MemoryManager* memory, IAssetLoadingManager* manager, + const cspField_t* fields, const size_t fieldCount) + : InfoStringToStructConverterBase(infoString, structure, zoneScriptStrings, memory), + m_loading_manager(manager), + m_fields(fields), + m_field_count(fieldCount) +{ +} + +bool InfoStringToStructConverter::ConvertBaseField(const cspField_t& field, const std::string& value) +{ + switch (static_cast(field.iFieldType)) + { + case CSPFT_STRING: + return ConvertString(value, field.iOffset); + + case CSPFT_STRING_MAX_STRING_CHARS: + return ConvertStringBuffer(value, field.iOffset, 1024); + + case CSPFT_STRING_MAX_QPATH: + return ConvertStringBuffer(value, field.iOffset, 64); + + case CSPFT_STRING_MAX_OSPATH: + return ConvertStringBuffer(value, field.iOffset, 256); + + case CSPFT_INT: + return ConvertInt(value, field.iOffset); + + case CSPFT_BOOL: + return ConvertBool(value, field.iOffset); + + case CSPFT_QBOOLEAN: + return ConvertQBoolean(value, field.iOffset); + + case CSPFT_FLOAT: + return ConvertFloat(value, field.iOffset); + + case CSPFT_MILLISECONDS: + return ConvertMilliseconds(value, field.iOffset); + + case CSPFT_FX: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* fx = m_loading_manager->LoadDependency(ASSET_TYPE_FX, value); + + if (fx == nullptr) + { + std::cout << "Failed to load fx asset \"" << value << "\"" << std::endl; + return false; + } + + m_dependencies.emplace(fx); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = fx->m_ptr; + + return true; + } + + case CSPFT_XMODEL: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* xmodel = m_loading_manager->LoadDependency(ASSET_TYPE_XMODEL, value); + + if (xmodel == nullptr) + { + std::cout << "Failed to load xmodel asset \"" << value << "\"" << std::endl; + return false; + } + + m_dependencies.emplace(xmodel); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = xmodel->m_ptr; + + return true; + } + + case CSPFT_MATERIAL: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* material = m_loading_manager->LoadDependency(ASSET_TYPE_MATERIAL, value); + + if (material == nullptr) + { + std::cout << "Failed to load material asset \"" << value << "\"" << std::endl; + return false; + } + + m_dependencies.emplace(material); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = material->m_ptr; + + return true; + } + + case CSPFT_TRACER: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* tracer = m_loading_manager->LoadDependency(ASSET_TYPE_TRACER, value); + + if (tracer == nullptr) + { + std::cout << "Failed to load tracer asset \"" << value << "\"" << std::endl; + return false; + } + + m_dependencies.emplace(tracer); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = tracer->m_ptr; + + return true; + } + + case CSPFT_MPH_TO_INCHES_PER_SEC: + { + char* endPtr; + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = strtof(value.c_str(), &endPtr) * 17.6f; + + if (endPtr != &value[value.size()]) + { + std::cout << "Failed to parse value \"" << value << "\" as mph" << std::endl; + return false; + } + + return true; + } + + case CSPFT_PHYS_COLLMAP: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* collmap = m_loading_manager->LoadDependency(ASSET_TYPE_PHYSCOLLMAP, value); + + if (collmap == nullptr) + { + std::cout << "Failed to load collmap asset \"" << value << "\"" << std::endl; + return false; + } + + m_dependencies.emplace(collmap); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = collmap->m_ptr; + + return true; + } + + case CSPFT_SOUND: + { + if (value.empty()) + { + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = nullptr; + return true; + } + + auto* sound = m_loading_manager->LoadDependency(ASSET_TYPE_SOUND, value); + + if (sound == nullptr) + { + std::cout << "Failed to load sound asset \"" << value << "\"" << std::endl; + return false; + } + + m_dependencies.emplace(sound); + *reinterpret_cast(reinterpret_cast(m_structure) + field.iOffset) = sound->m_ptr; + + return true; + } + + case CSPFT_NUM_BASE_FIELD_TYPES: + default: + assert(false); + return false; + } +} + +bool InfoStringToStructConverter::Convert() +{ + for (auto fieldIndex = 0u; fieldIndex < m_field_count; fieldIndex++) + { + const auto& field = m_fields[fieldIndex]; + assert(field.iFieldType >= 0); + + auto foundValue = false; + const auto& value = m_info_string.GetValueForKey(std::string(field.szName), &foundValue); + + if (foundValue) + { + if (field.iFieldType < CSPFT_NUM_BASE_FIELD_TYPES) + { + if (!ConvertBaseField(field, value)) + return false; + } + else + { + if (!ConvertExtensionField(field, value)) + return false; + } + } + } + + return true; +} diff --git a/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.h b/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.h index 1a8d0bc3..672af897 100644 --- a/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.h +++ b/src/ObjLoading/Game/IW4/InfoString/InfoStringToStructConverter.h @@ -12,8 +12,6 @@ namespace IW4 const cspField_t* m_fields; size_t m_field_count; - static bool GetHashValue(const std::string& value, unsigned int& hash); - virtual bool ConvertExtensionField(const cspField_t& field, const std::string& value) = 0; bool ConvertBaseField(const cspField_t& field, const std::string& value); diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysPreset.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysPreset.cpp new file mode 100644 index 00000000..c673c114 --- /dev/null +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysPreset.cpp @@ -0,0 +1,101 @@ +#include "AssetDumperPhysPreset.h" + +#include +#include +#include +#include + +#include "Game/IW4/ObjConstantsIW4.h" +#include "Game/IW4/InfoString/InfoStringFromStructConverter.h" +#include "Game/IW4/InfoString/PhysPresetFields.h" + +using namespace IW4; + +namespace IW4 +{ + class InfoStringFromPhysPresetConverter final : public InfoStringFromStructConverter + { + protected: + void FillFromExtensionField(const cspField_t& field) override + { + assert(false); + } + + public: + InfoStringFromPhysPresetConverter(const PhysPresetInfo* structure, const cspField_t* fields, const size_t fieldCount, std::function scriptStringValueCallback) + : InfoStringFromStructConverter(structure, fields, fieldCount, std::move(scriptStringValueCallback)) + { + } + }; +} + +void AssetDumperPhysPreset::CopyToPhysPresetInfo(const PhysPreset* physPreset, PhysPresetInfo* physPresetInfo) +{ + physPresetInfo->mass = std::clamp(physPreset->mass * 1000.0f, 1.0f, 2000.0f); + physPresetInfo->bounce = physPreset->bounce; + + if (std::isinf(physPreset->friction)) + { + physPresetInfo->isFrictionInfinity = 1; + physPresetInfo->friction = 0; + } + else + { + physPresetInfo->isFrictionInfinity = 0; + physPresetInfo->friction = physPreset->friction; + } + + physPresetInfo->bulletForceScale = physPreset->bulletForceScale; + physPresetInfo->explosiveForceScale = physPreset->explosiveForceScale; + physPresetInfo->sndAliasPrefix = physPreset->sndAliasPrefix; + physPresetInfo->piecesSpreadFraction = physPreset->piecesSpreadFraction; + physPresetInfo->piecesUpwardVelocity = physPreset->piecesUpwardVelocity; + physPresetInfo->tempDefaultToCylinder = physPreset->tempDefaultToCylinder ? 1 : 0; + physPresetInfo->perSurfaceSndAlias = physPreset->perSurfaceSndAlias ? 1 : 0; +} + +InfoString AssetDumperPhysPreset::CreateInfoString(XAssetInfo* asset) +{ + auto* physPresetInfo = new PhysPresetInfo; + CopyToPhysPresetInfo(asset->Asset(), physPresetInfo); + + InfoStringFromPhysPresetConverter converter(physPresetInfo, phys_preset_fields, std::extent::value, [asset](const scr_string_t scrStr) -> std::string + { + assert(scrStr < asset->m_zone->m_script_strings.Count()); + if (scrStr >= asset->m_zone->m_script_strings.Count()) + return ""; + + return asset->m_zone->m_script_strings[scrStr]; + }); + + return converter.Convert(); +} + +bool AssetDumperPhysPreset::ShouldDump(XAssetInfo* asset) +{ + return true; +} + +void AssetDumperPhysPreset::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) +{ + // Only dump raw when no gdt available + if (context.m_gdt) + { + const auto infoString = CreateInfoString(asset); + GdtEntry gdtEntry(asset->m_name, ObjConstants::GDF_FILENAME_PHYS_PRESET); + infoString.ToGdtProperties(ObjConstants::INFO_STRING_PREFIX_PHYS_PRESET, gdtEntry); + context.m_gdt->WriteEntry(gdtEntry); + } + else + { + const auto assetFile = context.OpenAssetFile("physic/" + asset->m_name); + + if (!assetFile) + return; + + auto& stream = *assetFile; + const auto infoString = CreateInfoString(asset); + const auto stringValue = infoString.ToString(ObjConstants::INFO_STRING_PREFIX_PHYS_PRESET); + stream.write(stringValue.c_str(), stringValue.size()); + } +} \ No newline at end of file diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysPreset.h b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysPreset.h new file mode 100644 index 00000000..6db3528e --- /dev/null +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperPhysPreset.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/IW4/IW4.h" +#include "InfoString/InfoString.h" + +namespace IW4 +{ + class AssetDumperPhysPreset final : public AbstractAssetDumper + { + static void CopyToPhysPresetInfo(const PhysPreset* physPreset, PhysPresetInfo* physPresetInfo); + static InfoString CreateInfoString(XAssetInfo* asset); + + protected: + bool ShouldDump(XAssetInfo* asset) override; + void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; + }; +} diff --git a/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp b/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp index cedb0d2b..d858b177 100644 --- a/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp +++ b/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp @@ -10,6 +10,7 @@ #include "AssetDumpers/AssetDumperLocalizeEntry.h" #include "AssetDumpers/AssetDumperMenuDef.h" #include "AssetDumpers/AssetDumperMenuList.h" +#include "AssetDumpers/AssetDumperPhysPreset.h" #include "AssetDumpers/AssetDumperRawFile.h" #include "AssetDumpers/AssetDumperStringTable.h" #include "AssetDumpers/AssetDumperVehicle.h" @@ -34,7 +35,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const const auto* assetPools = dynamic_cast(context.m_zone->m_pools.get()); - // DUMP_ASSET_POOL(AssetDumperPhysPreset, m_phys_preset, ASSET_TYPE_PHYSPRESET) + DUMP_ASSET_POOL(AssetDumperPhysPreset, m_phys_preset, ASSET_TYPE_PHYSPRESET) // DUMP_ASSET_POOL(AssetDumperPhysCollmap, m_phys_collmap, ASSET_TYPE_PHYSCOLLMAP) // DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts, ASSET_TYPE_XANIMPARTS) DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel, ASSET_TYPE_XMODEL)