diff --git a/README.md b/README.md index ca6512508..a883d1ee7 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ It currently offers support for the PC versions of: - [IW3 (COD4: Modern Warfare - 2007)](https://en.wikipedia.org/wiki/Call_of_Duty_4:_Modern_Warfare) - [IW4 (Modern Warfare 2 - 2009)](https://en.wikipedia.org/wiki/Call_of_Duty:_Modern_Warfare_2) - [IW5 (Modern Warfare 3 - 2011)](https://en.wikipedia.org/wiki/Call_of_Duty:_Modern_Warfare_3) +- [QOS (007: Quantum of Solace - 2008)](https://en.wikipedia.org/wiki/007:_Quantum_of_Solace) - [T4 (World at War - 2008)](https://en.wikipedia.org/wiki/Call_of_Duty:_World_at_War) - [T5 (Black Ops - 2010)](https://en.wikipedia.org/wiki/Call_of_Duty:_Black_Ops) - [T6 (Black Ops II - 2012)](https://en.wikipedia.org/wiki/Call_of_Duty:_Black_Ops_II) diff --git a/docs/SupportedAssetTypes.md b/docs/SupportedAssetTypes.md index e268bdcd9..ac1124510 100644 --- a/docs/SupportedAssetTypes.md +++ b/docs/SupportedAssetTypes.md @@ -123,6 +123,42 @@ using `Linker`): | VehicleDef | ✅ | ✅ | | | AddonMapEnts | ⁉️ | ❌ | MapEnts String can be exported. Binary data currently not. | +## QOS (007: Quantum of Solace) + +| Asset Type | Dumping Support | Loading Support | Notes | +|----------------------|-----------------|-----------------|------------------------------------------------------------------------------| +| PhysPreset | ❌ | ❌ | | +| PhysConstraints | ❌ | ❌ | | +| DestructibleDef | ❌ | ❌ | | +| XAnimParts | ❌ | ❌ | | +| XModel | ✅ | ❌ | Model data can be exported to `XMODEL_EXPORT/XMODEL_BIN`, `OBJ`, `GLB/GLTF`. | +| Material | ❌ | ❌ | | +| MaterialTechniqueSet | ❌ | ❌ | | +| GfxImage | ✅ | ❌ | | +| snd_alias_list_t | ❌ | ❌ | | +| SndCurve | ❌ | ❌ | | +| clipMap_t | ❌ | ❌ | | +| ComWorld | ❌ | ❌ | | +| GameWorldSp | ❌ | ❌ | | +| GameWorldMp | ❌ | ❌ | | +| MapEnts | ✅ | ❌ | | +| GfxWorld | ❌ | ❌ | | +| GfxLightDef | ❌ | ❌ | | +| Font_s | ✅ | ❌ | | +| MenuList | ❌ | ❌ | | +| menuDef_t | ❌ | ❌ | | +| LocalizeEntry | ✅ | ✅ | | +| WeaponDef | ❌ | ❌ | | +| SndDriverGlobals | ❌ | ❌ | | +| FxEffectDef | ❌ | ❌ | | +| FxImpactTable | ❌ | ❌ | | +| RawFile | ✅ | ✅ | | +| StringTable | ✅ | ✅ | | +| XmlTree | ❌ | ❌ | | +| SceneAnimation | ❌ | ❌ | | +| Cutscene | ❌ | ❌ | | +| CustomCamera | ❌ | ❌ | | + ## T4 (Call of Duty: World at War) | Asset Type | Dumping Support | Loading Support | Notes | diff --git a/src/Common/Game/CommonAsset.cpp b/src/Common/Game/CommonAsset.cpp index 4351ba915..1ee633653 100644 --- a/src/Common/Game/CommonAsset.cpp +++ b/src/Common/Game/CommonAsset.cpp @@ -3,6 +3,7 @@ #include "IW3/CommonAssetIW3.h" #include "IW4/CommonAssetIW4.h" #include "IW5/CommonAssetIW5.h" +#include "QOS/CommonAssetQOS.h" #include "T4/CommonAssetT4.h" #include "T5/CommonAssetT5.h" #include "T6/CommonAssetT6.h" @@ -15,6 +16,7 @@ ICommonAssetTypeMapper* ICommonAssetTypeMapper::GetCommonAssetMapperByGame(GameI new IW3::CommonAssetTypeMapper(), new IW4::CommonAssetTypeMapper(), new IW5::CommonAssetTypeMapper(), + new QOS::CommonAssetTypeMapper(), new T4::CommonAssetTypeMapper(), new T5::CommonAssetTypeMapper(), new T6::CommonAssetTypeMapper(), diff --git a/src/Common/Game/CommonAsset.h b/src/Common/Game/CommonAsset.h index 24371e491..2594ccee8 100644 --- a/src/Common/Game/CommonAsset.h +++ b/src/Common/Game/CommonAsset.h @@ -160,6 +160,12 @@ enum class CommonAssetType : std::uint8_t // T6 ZBARRIER, + // QOS + XML_TREE, + SCENE_ANIMATION, + CUTSCENE, + CUSTOM_CAMERA, + COUNT, }; diff --git a/src/Common/Game/IGame.cpp b/src/Common/Game/IGame.cpp index 368a2e120..03211034e 100644 --- a/src/Common/Game/IGame.cpp +++ b/src/Common/Game/IGame.cpp @@ -3,6 +3,7 @@ #include "IW3/GameIW3.h" #include "IW4/GameIW4.h" #include "IW5/GameIW5.h" +#include "QOS/GameQOS.h" #include "T4/GameT4.h" #include "T5/GameT5.h" #include "T6/GameT6.h" @@ -16,6 +17,7 @@ IGame* IGame::GetGameById(GameId gameId) new IW3::Game(), new IW4::Game(), new IW5::Game(), + new QOS::Game(), new T4::Game(), new T5::Game(), new T6::Game(), diff --git a/src/Common/Game/IGame.h b/src/Common/Game/IGame.h index d51d282b5..642ce8dd6 100644 --- a/src/Common/Game/IGame.h +++ b/src/Common/Game/IGame.h @@ -15,6 +15,7 @@ enum class GameId : std::uint8_t IW3, IW4, IW5, + QOS, T4, T5, T6, @@ -50,6 +51,7 @@ static constexpr const char* GameId_Names[]{ "IW3", "IW4", "IW5", + "QOS", "T4", "T5", "T6", diff --git a/src/Common/Game/QOS/CommonAssetQOS.cpp b/src/Common/Game/QOS/CommonAssetQOS.cpp new file mode 100644 index 000000000..aa530b51f --- /dev/null +++ b/src/Common/Game/QOS/CommonAssetQOS.cpp @@ -0,0 +1,110 @@ +#include "CommonAssetQOS.h" + +#include "QOS.h" + +#include + +namespace QOS +{ + CommonAssetTypeMapper::CommonAssetTypeMapper() = default; + + CommonAssetType CommonAssetTypeMapper::GameToCommonAssetType(const asset_type_t gameAssetType) const + { + static CommonAssetType lookupTable[static_cast(ASSET_TYPE_COUNT)]{ + CommonAssetType::XMODEL_PIECES, // ASSET_TYPE_XMODELPIECES + CommonAssetType::PHYS_PRESET, // ASSET_TYPE_PHYSPRESET + CommonAssetType::PHYS_CONSTRAINTS, // ASSET_TYPE_PHYSCONSTRAINTS + CommonAssetType::DESTRUCTIBLE_DEF, // ASSET_TYPE_DESTRUCTIBLEDEF + CommonAssetType::XANIM, // ASSET_TYPE_XANIMPARTS + CommonAssetType::XMODEL, // ASSET_TYPE_XMODEL + CommonAssetType::MATERIAL, // ASSET_TYPE_MATERIAL + CommonAssetType::TECHNIQUE_SET, // ASSET_TYPE_TECHNIQUE_SET + CommonAssetType::IMAGE, // ASSET_TYPE_IMAGE + CommonAssetType::SOUND, // ASSET_TYPE_SOUND + CommonAssetType::SOUND_CURVE, // ASSET_TYPE_SND_CURVE + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP_SP + CommonAssetType::CLIP_MAP, // ASSET_TYPE_CLIPMAP_MP + CommonAssetType::COM_WORLD, // ASSET_TYPE_COMWORLD + CommonAssetType::GAME_WORLD_SP, // ASSET_TYPE_GAMEWORLD_SP + CommonAssetType::GAME_WORLD_MP, // ASSET_TYPE_GAMEWORLD_MP + CommonAssetType::MAP_ENTS, // ASSET_TYPE_MAP_ENTS + CommonAssetType::GFX_WORLD, // ASSET_TYPE_GFXWORLD + CommonAssetType::LIGHT_DEF, // ASSET_TYPE_LIGHT_DEF + CommonAssetType::UI_MAP, // ASSET_TYPE_UI_MAP + CommonAssetType::FONT, // ASSET_TYPE_FONT + CommonAssetType::MENU_LIST, // ASSET_TYPE_MENUFILE + CommonAssetType::MENU, // ASSET_TYPE_MENU + CommonAssetType::LOCALIZE_ENTRY, // ASSET_TYPE_LOCALIZE_ENTRY + CommonAssetType::WEAPON, // ASSET_TYPE_WEAPON + CommonAssetType::SOUND_DRIVER_GLOBALS, // ASSET_TYPE_SNDDRIVER_GLOBALS + CommonAssetType::FX, // ASSET_TYPE_FX + CommonAssetType::IMPACT_FX, // ASSET_TYPE_IMPACT_FX + CommonAssetType::AI_TYPE, // ASSET_TYPE_AITYPE + CommonAssetType::MP_TYPE, // ASSET_TYPE_MPTYPE + CommonAssetType::CHARACTER, // ASSET_TYPE_CHARACTER + CommonAssetType::XMODEL_ALIAS, // ASSET_TYPE_XMODELALIAS + CommonAssetType::RAW_FILE, // ASSET_TYPE_RAWFILE + CommonAssetType::STRING_TABLE, // ASSET_TYPE_STRINGTABLE + CommonAssetType::XML_TREE, // ASSET_TYPE_XMLTREE + CommonAssetType::SCENE_ANIMATION, // ASSET_TYPE_SCENE_ANIMATION + CommonAssetType::CUTSCENE, // ASSET_TYPE_CUTSCENE + CommonAssetType::CUSTOM_CAMERA, // ASSET_TYPE_CUSTOM_CAMERA + }; + + assert(gameAssetType < ASSET_TYPE_COUNT); + return lookupTable[gameAssetType]; + } + + std::optional CommonAssetTypeMapper::CommonToGameAssetType(const CommonAssetType commonAssetType) const + { +#define MAP_COMMON(common, game) \ + case common: \ + return game; + + switch (commonAssetType) + { + MAP_COMMON(CommonAssetType::XMODEL_PIECES, ASSET_TYPE_XMODELPIECES) + MAP_COMMON(CommonAssetType::PHYS_PRESET, ASSET_TYPE_PHYSPRESET) + MAP_COMMON(CommonAssetType::PHYS_CONSTRAINTS, ASSET_TYPE_PHYSCONSTRAINTS) + MAP_COMMON(CommonAssetType::DESTRUCTIBLE_DEF, ASSET_TYPE_DESTRUCTIBLEDEF) + MAP_COMMON(CommonAssetType::XANIM, ASSET_TYPE_XANIMPARTS) + MAP_COMMON(CommonAssetType::XMODEL, ASSET_TYPE_XMODEL) + MAP_COMMON(CommonAssetType::MATERIAL, ASSET_TYPE_MATERIAL) + MAP_COMMON(CommonAssetType::TECHNIQUE_SET, ASSET_TYPE_TECHNIQUE_SET) + MAP_COMMON(CommonAssetType::IMAGE, ASSET_TYPE_IMAGE) + MAP_COMMON(CommonAssetType::SOUND, ASSET_TYPE_SOUND) + MAP_COMMON(CommonAssetType::SOUND_CURVE, ASSET_TYPE_SND_CURVE) + MAP_COMMON(CommonAssetType::CLIP_MAP, ASSET_TYPE_CLIPMAP_MP) + MAP_COMMON(CommonAssetType::COM_WORLD, ASSET_TYPE_COMWORLD) + MAP_COMMON(CommonAssetType::GAME_WORLD_SP, ASSET_TYPE_GAMEWORLD_SP) + MAP_COMMON(CommonAssetType::GAME_WORLD_MP, ASSET_TYPE_GAMEWORLD_MP) + MAP_COMMON(CommonAssetType::MAP_ENTS, ASSET_TYPE_MAP_ENTS) + MAP_COMMON(CommonAssetType::GFX_WORLD, ASSET_TYPE_GFXWORLD) + MAP_COMMON(CommonAssetType::LIGHT_DEF, ASSET_TYPE_LIGHT_DEF) + MAP_COMMON(CommonAssetType::UI_MAP, ASSET_TYPE_UI_MAP) + MAP_COMMON(CommonAssetType::FONT, ASSET_TYPE_FONT) + MAP_COMMON(CommonAssetType::MENU_LIST, ASSET_TYPE_MENUFILE) + MAP_COMMON(CommonAssetType::MENU, ASSET_TYPE_MENU) + MAP_COMMON(CommonAssetType::LOCALIZE_ENTRY, ASSET_TYPE_LOCALIZE_ENTRY) + MAP_COMMON(CommonAssetType::WEAPON, ASSET_TYPE_WEAPON) + MAP_COMMON(CommonAssetType::SOUND_DRIVER_GLOBALS, ASSET_TYPE_SNDDRIVER_GLOBALS) + MAP_COMMON(CommonAssetType::FX, ASSET_TYPE_FX) + MAP_COMMON(CommonAssetType::IMPACT_FX, ASSET_TYPE_IMPACT_FX) + MAP_COMMON(CommonAssetType::AI_TYPE, ASSET_TYPE_AITYPE) + MAP_COMMON(CommonAssetType::MP_TYPE, ASSET_TYPE_MPTYPE) + MAP_COMMON(CommonAssetType::CHARACTER, ASSET_TYPE_CHARACTER) + MAP_COMMON(CommonAssetType::XMODEL_ALIAS, ASSET_TYPE_XMODELALIAS) + MAP_COMMON(CommonAssetType::RAW_FILE, ASSET_TYPE_RAWFILE) + MAP_COMMON(CommonAssetType::STRING_TABLE, ASSET_TYPE_STRINGTABLE) + MAP_COMMON(CommonAssetType::XML_TREE, ASSET_TYPE_XMLTREE) + MAP_COMMON(CommonAssetType::SCENE_ANIMATION, ASSET_TYPE_SCENE_ANIMATION) + MAP_COMMON(CommonAssetType::CUTSCENE, ASSET_TYPE_CUTSCENE) + MAP_COMMON(CommonAssetType::CUSTOM_CAMERA, ASSET_TYPE_CUSTOM_CAMERA) + + default: + return std::nullopt; + } + +#undef MAP_COMMON + } +} // namespace QOS diff --git a/src/Common/Game/QOS/CommonAssetQOS.h b/src/Common/Game/QOS/CommonAssetQOS.h new file mode 100644 index 000000000..4bd6a13c2 --- /dev/null +++ b/src/Common/Game/QOS/CommonAssetQOS.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Game/CommonAsset.h" + +namespace QOS +{ + class CommonAssetTypeMapper final : public ICommonAssetTypeMapper + { + public: + CommonAssetTypeMapper(); + + [[nodiscard]] CommonAssetType GameToCommonAssetType(asset_type_t gameAssetType) const override; + [[nodiscard]] std::optional CommonToGameAssetType(CommonAssetType commonAssetType) const override; + }; +} // namespace QOS diff --git a/src/Common/Game/QOS/CommonQOS.cpp b/src/Common/Game/QOS/CommonQOS.cpp new file mode 100644 index 000000000..16e3d789e --- /dev/null +++ b/src/Common/Game/QOS/CommonQOS.cpp @@ -0,0 +1,37 @@ +#include "CommonQOS.h" + +#include "Utils/Pack.h" + +#include + +using namespace QOS; + +PackedTexCoords Common::Vec2PackTexCoords(const float (&in)[2]) +{ + return PackedTexCoords{pack32::Vec2PackTexCoordsVU(in)}; +} + +PackedUnitVec Common::Vec3PackUnitVec(const float (&in)[3]) +{ + return PackedUnitVec{pack32::Vec3PackUnitVecScaleBased(in)}; +} + +GfxColor Common::Vec4PackGfxColor(const float (&in)[4]) +{ + return GfxColor{pack32::Vec4PackGfxColor(in)}; +} + +void Common::Vec2UnpackTexCoords(const PackedTexCoords& in, float (&out)[2]) +{ + pack32::Vec2UnpackTexCoordsVU(in.packed, out); +} + +void Common::Vec3UnpackUnitVec(const PackedUnitVec& in, float (&out)[3]) +{ + pack32::Vec3UnpackUnitVecScaleBased(in.packed, out); +} + +void Common::Vec4UnpackGfxColor(const GfxColor& in, float (&out)[4]) +{ + pack32::Vec4UnpackGfxColor(in.packed, out); +} diff --git a/src/Common/Game/QOS/CommonQOS.h b/src/Common/Game/QOS/CommonQOS.h new file mode 100644 index 000000000..226efa814 --- /dev/null +++ b/src/Common/Game/QOS/CommonQOS.h @@ -0,0 +1,30 @@ +#pragma once + +#include "QOS.h" +#include "Utils/Djb2.h" + +#include + +namespace QOS +{ + class Common + { + public: + static constexpr uint32_t R_HashString(const char* str, const uint32_t hash) + { + return djb2_xor_nocase(str, hash); + } + + static constexpr uint32_t R_HashString(const char* string) + { + return R_HashString(string, 0u); + } + + static PackedTexCoords Vec2PackTexCoords(const float (&in)[2]); + static PackedUnitVec Vec3PackUnitVec(const float (&in)[3]); + static GfxColor Vec4PackGfxColor(const float (&in)[4]); + static void Vec2UnpackTexCoords(const PackedTexCoords& in, float (&out)[2]); + static void Vec3UnpackUnitVec(const PackedUnitVec& in, float (&out)[3]); + static void Vec4UnpackGfxColor(const GfxColor& in, float (&out)[4]); + }; +} // namespace QOS diff --git a/src/Common/Game/QOS/GameQOS.cpp b/src/Common/Game/QOS/GameQOS.cpp new file mode 100644 index 000000000..b15be6d5d --- /dev/null +++ b/src/Common/Game/QOS/GameQOS.cpp @@ -0,0 +1,98 @@ +#include "GameQOS.h" + +#include "QOS.h" + +#include + +using namespace QOS; + +namespace +{ + constexpr const char* ASSET_TYPE_NAMES[]{ + "xmodelpieces", + "physpreset", + "physconstraints", + "destructibledef", + "xanim", + "xmodel", + "material", + "techset", + "image", + "sound", + "sndcurve", + "col_map_sp", + "col_map_mp", + "com_map", + "game_map_sp", + "game_map_mp", + "map_ents", + "gfx_map", + "lightdef", + "ui_map", + "font", + "menufile", + "menu", + "localize", + "weapon", + "snddriverglobals", + "fx", + "impactfx", + "aitype", + "mptype", + "character", + "xmodelalias", + "rawfile", + "stringtable", + "xmltree", + "scene_animation", + "cutscene", + "custom_camera", + }; + static_assert(std::extent_v == ASSET_TYPE_COUNT); + + constexpr const char* SUB_ASSET_TYPE_NAMES[]{ + "technique", + "vertexdecl", + "vertexshader", + "pixelshader", + "accuracygraph", + }; + static_assert(std::extent_v == SUB_ASSET_TYPE_COUNT); +} // namespace + +namespace QOS +{ + Game::Game() + : AbstractGame(ASSET_TYPE_NAMES, std::extent_v, SUB_ASSET_TYPE_NAMES, std::extent_v) + { + AddAssetTypeNameAlias("techniqueset"); + AddAssetTypeNameAlias("clipmap_sp"); + AddAssetTypeNameAlias("clipmap_mp"); + AddAssetTypeNameAlias("clipmap"); + AddAssetTypeNameAlias("comworld"); + AddAssetTypeNameAlias("gameworldsp"); + AddAssetTypeNameAlias("gameworldmp"); + AddAssetTypeNameAlias("mapents"); + AddAssetTypeNameAlias("gfxworld"); + AddAssetTypeNameAlias("gfxlightdef"); + AddAssetTypeNameAlias("menulist"); + AddAssetTypeNameAlias("localizeentry"); + } + + GameId Game::GetId() const + { + return GameId::QOS; + } + + const std::string& Game::GetFullName() const + { + static std::string fullName = "007: Quantum of Solace"; + return fullName; + } + + const std::string& Game::GetShortName() const + { + static std::string shortName = "QOS"; + return shortName; + } +} // namespace QOS diff --git a/src/Common/Game/QOS/GameQOS.h b/src/Common/Game/QOS/GameQOS.h new file mode 100644 index 000000000..6314e00ec --- /dev/null +++ b/src/Common/Game/QOS/GameQOS.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Game/IGame.h" + +namespace QOS +{ + class Game final : public AbstractGame + { + public: + Game(); + + [[nodiscard]] GameId GetId() const override; + [[nodiscard]] const std::string& GetFullName() const override; + [[nodiscard]] const std::string& GetShortName() const override; + }; +} // namespace QOS diff --git a/src/Common/Game/QOS/QOS.h b/src/Common/Game/QOS/QOS.h new file mode 100644 index 000000000..7fb4d3910 --- /dev/null +++ b/src/Common/Game/QOS/QOS.h @@ -0,0 +1,170 @@ +#pragma once + +// clang-format off: Order of includes matters here + +#include "Game/IAsset.h" + +#include "QOS_Assets.h" + +// clang-format on + +namespace QOS +{ + enum XAssetType + { + ASSET_TYPE_XMODELPIECES, + ASSET_TYPE_PHYSPRESET, + ASSET_TYPE_PHYSCONSTRAINTS, + ASSET_TYPE_DESTRUCTIBLEDEF, + ASSET_TYPE_XANIMPARTS, + ASSET_TYPE_XMODEL, + ASSET_TYPE_MATERIAL, + ASSET_TYPE_TECHNIQUE_SET, + ASSET_TYPE_IMAGE, + ASSET_TYPE_SOUND, + ASSET_TYPE_SND_CURVE, + ASSET_TYPE_CLIPMAP_SP, + ASSET_TYPE_CLIPMAP_MP, + ASSET_TYPE_COMWORLD, + ASSET_TYPE_GAMEWORLD_SP, + ASSET_TYPE_GAMEWORLD_MP, + ASSET_TYPE_MAP_ENTS, + ASSET_TYPE_GFXWORLD, + ASSET_TYPE_LIGHT_DEF, + ASSET_TYPE_UI_MAP, + ASSET_TYPE_FONT, + ASSET_TYPE_MENUFILE, + ASSET_TYPE_MENU, + ASSET_TYPE_LOCALIZE_ENTRY, + ASSET_TYPE_WEAPON, + ASSET_TYPE_SNDDRIVER_GLOBALS, + ASSET_TYPE_FX, + ASSET_TYPE_IMPACT_FX, + ASSET_TYPE_AITYPE, + ASSET_TYPE_MPTYPE, + ASSET_TYPE_CHARACTER, + ASSET_TYPE_XMODELALIAS, + ASSET_TYPE_RAWFILE, + ASSET_TYPE_STRINGTABLE, + ASSET_TYPE_XMLTREE, + ASSET_TYPE_SCENE_ANIMATION, + ASSET_TYPE_CUTSCENE, + ASSET_TYPE_CUSTOM_CAMERA, + + ASSET_TYPE_COUNT, + + ASSET_TYPE_STRING = ASSET_TYPE_COUNT, + ASSET_TYPE_ASSETLIST + }; + + enum SubAssetType + { + SUB_ASSET_TYPE_TECHNIQUE, + SUB_ASSET_TYPE_VERTEX_DECL, + SUB_ASSET_TYPE_VERTEX_SHADER, + SUB_ASSET_TYPE_PIXEL_SHADER, + SUB_ASSET_TYPE_ACCURACY_GRAPH, + + SUB_ASSET_TYPE_COUNT + }; + + struct ScriptStringList + { + int count; + const char** strings; + }; + + struct XAsset + { + XAssetType type; + XAssetHeader header; + }; + + struct XAssetList + { + ScriptStringList stringList; + int assetCount; + XAsset* assets; + }; + + using AssetXModelPieces = Asset; + using AssetPhysPreset = Asset; + using AssetPhysConstraints = Asset; + using AssetDestructibleDef = Asset; + using AssetXAnim = Asset; + using AssetXModel = Asset; + using AssetMaterial = Asset; + using AssetTechniqueSet = Asset; + using AssetImage = Asset; + using AssetSound = Asset; + using AssetSndCurve = Asset; + using AssetClipMapSp = Asset; + using AssetClipMapMp = Asset; + using AssetComWorld = Asset; + using AssetGameWorldSp = Asset; + using AssetGameWorldMp = Asset; + using AssetMapEnts = Asset; + using AssetGfxWorld = Asset; + using AssetLightDef = Asset; + using AssetFont = Asset; + using AssetMenuFile = Asset; + using AssetMenu = Asset; + using AssetLocalize = Asset; + using AssetWeapon = Asset; + using AssetSoundDriverGlobals = Asset; + using AssetFx = Asset; + using AssetImpactFx = Asset; + using AssetAiType = Asset; + using AssetMpType = Asset; + using AssetCharacter = Asset; + using AssetXModelAlias = Asset; + using AssetRawFile = Asset; + using AssetStringTable = Asset; + using AssetXmlTree = Asset; + using AssetSceneAnimation = Asset; + using AssetCutscene = Asset; + using AssetCustomCamera = Asset; + + using SubAssetTechnique = SubAsset; + using SubAssetVertexDecl = SubAsset; + using SubAssetVertexShader = SubAsset; + using SubAssetPixelShader = SubAsset; +} // namespace QOS + +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetXModelPieces, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetPhysPreset, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetPhysConstraints, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetDestructibleDef, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetXAnim, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetXModel, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetMaterial, info.name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetTechniqueSet, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetImage, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetSound, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetSndCurve, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetClipMapSp, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetClipMapMp, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetComWorld, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetGameWorldSp, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetGameWorldMp, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetMapEnts, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetGfxWorld, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetLightDef, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetFont, fontName); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetMenuFile, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetMenu, window.name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetLocalize, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetWeapon, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetSoundDriverGlobals, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetFx, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetImpactFx, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetAiType, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetMpType, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetCharacter, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetXModelAlias, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetRawFile, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetStringTable, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetXmlTree, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetSceneAnimation, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetCutscene, name); +DEFINE_ASSET_NAME_ACCESSOR(QOS::AssetCustomCamera, name); diff --git a/src/Common/Game/QOS/QOS_Assets.h b/src/Common/Game/QOS/QOS_Assets.h new file mode 100644 index 000000000..1ff609821 --- /dev/null +++ b/src/Common/Game/QOS/QOS_Assets.h @@ -0,0 +1,2478 @@ +#pragma once + +#ifndef __QOS_ASSETS_H +#define __QOS_ASSETS_H + +#include "../../Utils/TypeAlignment.h" + +#ifndef __zonecodegenerator +namespace QOS +{ +#endif + enum XFileBlock + { + XFILE_BLOCK_TEMP, + XFILE_BLOCK_RUNTIME, + XFILE_BLOCK_VIRTUAL, + XFILE_BLOCK_LARGE, + XFILE_BLOCK_PHYSICAL, + + MAX_XFILE_COUNT + }; + + struct XModelPieces; + struct PhysPreset; + struct PhysConstraints; + struct DestructibleDef; + struct XAnimParts; + struct XModel; + struct Material; + struct MaterialTechniqueSet; + struct GfxImage; + struct snd_alias_list_t; + struct SndCurve; + struct clipMap_t; + struct ComWorld; + struct GameWorldSp; + struct GameWorldMp; + struct MapEnts; + struct GfxWorld; + struct GfxLightDef; + struct Font_s; + struct MenuList; + struct menuDef_t; + struct LocalizeEntry; + struct WeaponDef; + struct SndDriverGlobals; + struct FxEffectDef; + struct FxImpactTable; + struct AiType; + struct MpType; + struct Character; + struct XModelAlias; + struct RawFile; + struct StringTable; + struct XmlTree; + struct SceneAnimation; + struct Cutscene; + struct CustomCamera; + + union XAssetHeader + { + XModelPieces* xmodelPieces; + PhysPreset* physPreset; + PhysConstraints* physConstraints; + DestructibleDef* destructibleDef; + XAnimParts* parts; + XModel* model; + Material* material; + MaterialTechniqueSet* techniqueSet; + GfxImage* image; + snd_alias_list_t* sound; + SndCurve* sndCurve; + clipMap_t* clipMap; + ComWorld* comWorld; + GameWorldSp* gameWorldSp; + GameWorldMp* gameWorldMp; + MapEnts* mapEnts; + GfxWorld* gfxWorld; + GfxLightDef* lightDef; + Font_s* font; + MenuList* menuList; + menuDef_t* menu; + LocalizeEntry* localize; + WeaponDef* weapon; + SndDriverGlobals* sndDriverGlobals; + FxEffectDef* fx; + FxImpactTable* impactFx; + AiType* aiType; + MpType* mpType; + Character* character; + XModelAlias* xmodelAlias; + RawFile* rawfile; + StringTable* stringTable; + XmlTree* xmlTree; + SceneAnimation* sceneAnimation; + Cutscene* cutscene; + CustomCamera* customCamera; + void* data; + }; + + union vec2_t + { + float v[2]; + + struct + { + float x; + float y; + }; + }; + + union vec3_t + { + float v[3]; + + struct + { + float x; + float y; + float z; + }; + }; + + union vec4_t + { + float v[4]; + + struct + { + float x; + float y; + float z; + float w; + }; + + struct + { + float r; + float g; + float b; + float a; + }; + }; + + typedef unsigned short ScriptString; + typedef unsigned char raw_byte; + typedef unsigned int raw_uint; + + struct XModelPiece + { + XModel* model; + float offset[3]; + }; + + struct XModelPieces + { + const char* name; + int numpieces; + XModelPiece* pieces; + }; + + struct PhysPreset + { + const char* name; + char unknown0[24]; + const char* unknownString; + char unknown1[16]; + }; + + struct PhysConstraint + { + char unknown0[4]; + const char* target_bone1; + const char* target_bone2; + char unknown1[56]; + }; + + struct PhysConstraints + { + const char* name; + unsigned int count; + PhysConstraint data[16]; + }; + + struct DestructibleDef; + struct FxImpactEntry; + + union XAnimIndices + { + unsigned char* _1; + uint16_t* _2; + void* data; + }; + + struct XAnimNotifyInfo + { + ScriptString name; + float time; + }; + + typedef unsigned char ByteVec[3]; + typedef tdef_align32(4) unsigned short UShortVec[3]; + + union XAnimDynamicIndicesTrans + { + unsigned char _1[1]; + uint16_t _2[1]; + }; + + union XAnimDynamicFrames + { + ByteVec* _1; + UShortVec* _2; + }; + + struct XAnimPartTransFrames + { + vec3_t mins; + vec3_t size; + XAnimDynamicFrames frames; + XAnimDynamicIndicesTrans indices; + }; + + union XAnimPartTransData + { + XAnimPartTransFrames frames; + vec3_t frame0; + }; + + struct XAnimPartTrans + { + uint16_t size; + unsigned char smallTrans; + XAnimPartTransData u; + }; + + struct type_align(4) XQuat + { + int16_t value[4]; + }; + + struct type_align(4) XQuat2 + { + int16_t value[2]; + }; + + union XAnimDynamicIndicesQuat + { + unsigned char _1[1]; + uint16_t _2[1]; + }; + + struct XAnimDeltaPartQuatDataFrames + { + XQuat2* frames; + XAnimDynamicIndicesQuat indices; + }; + + union XAnimDeltaPartQuatData + { + XAnimDeltaPartQuatDataFrames frames; + XQuat2 frame0; + }; + + struct XAnimDeltaPartQuat + { + uint16_t size; + XAnimDeltaPartQuatData u; + }; + + struct XAnimDeltaPart + { + XAnimPartTrans* trans; + XAnimDeltaPartQuat* quat; + }; + + enum XAnimPartType + { + PART_TYPE_NO_QUAT = 0x0, + PART_TYPE_HALF_QUAT = 0x1, + PART_TYPE_FULL_QUAT = 0x2, + PART_TYPE_HALF_QUAT_NO_SIZE = 0x3, + PART_TYPE_FULL_QUAT_NO_SIZE = 0x4, + PART_TYPE_SMALL_TRANS = 0x5, + PART_TYPE_TRANS = 0x6, + PART_TYPE_TRANS_NO_SIZE = 0x7, + PART_TYPE_NO_TRANS = 0x8, + PART_TYPE_ALL = 0x9, + + PART_TYPE_COUNT + }; + + struct XAnimParts + { + const char* name; + const char* unknownString; + uint16_t dataByteCount; + uint16_t dataShortCount; + uint16_t dataIntCount; + uint16_t randomDataByteCount; + uint16_t randomDataIntCount; + uint16_t numframes; + bool bLoop; + bool bDelta; + unsigned char boneCount[PART_TYPE_COUNT]; + unsigned char notifyCount; + unsigned char assetType; + bool isDefault; + // Keeps randomDataShortCount at offset 36. + unsigned char pad; + unsigned int randomDataShortCount; + unsigned int indexCount; + float framerate; + float frequency; + ScriptString* names; + unsigned char* dataByte; + int16_t* dataShort; + int* dataInt; + int16_t* randomDataShort; + unsigned char* randomDataByte; + int* randomDataInt; + XAnimIndices indices; + XAnimNotifyInfo* notify; + XAnimDeltaPart* deltaPart; + }; + + struct DObjSkelMat + { + float axis[3][4]; + float origin[4]; + }; + + struct DObjAnimMat + { + vec4_t quat; + vec3_t trans; + float transWeight; + }; + + struct XSurfaceTri + { + unsigned short i[3]; + }; + + union GfxColor + { + unsigned int packed; + unsigned char array[4]; + }; + + union PackedTexCoords + { + unsigned int packed; + }; + + union PackedUnitVec + { + unsigned int packed; + unsigned char array[4]; + }; + + struct GfxPackedVertex + { + vec3_t xyz; + float binormalSign; + GfxColor color; + unsigned int unknown0; // Offset 20; Greyhound treats this as padding. + vec2_t texCoord; // QOS stores model UVs as two full floats at offsets 24 and 28. + PackedUnitVec normal; + PackedUnitVec tangent; // Likely the second tangent-space vector at offset 36. + }; + + struct GfxPackedVertex16 + { + unsigned int data[4]; + }; + + struct XSurfaceVertexInfo + { + short vertCount[4]; + unsigned short* vertsBlend; + float* tensionData; + }; + + struct XRigidVertList + { + unsigned short boneOffset; + unsigned short vertCount; + unsigned short triOffset; + unsigned short triCount; + }; + + struct XSurface + { + char tileMode; + bool deformed; + unsigned short vertCount; + unsigned short triCount; + char unknown0[2]; + XSurfaceTri* triIndices; + XSurfaceVertexInfo vertInfo; + GfxPackedVertex* verts0; + void* vb0; + GfxPackedVertex16* verts1; + void* vb1; + unsigned int vertListCount; + XRigidVertList* vertList; + void* indexBuffer; + int partBits[6]; + }; + + struct XModelLodInfo + { + float dist; + unsigned short numsurfs; + unsigned short surfIndex; + int partBits[5]; + char lod; + char smcIndexPlusOne; + char smcAllocBits; + char unused; + }; + + struct XModelCollTri_s + { + float plane[4]; + float svec[4]; + float tvec[4]; + }; + + struct XModelCollSurf_s + { + XModelCollTri_s* collTris; + int numCollTris; + float mins[3]; + float maxs[3]; + int boneIdx; + int contents; + int surfFlags; + }; + + struct XBoneInfo + { + vec3_t bounds[2]; + vec3_t offset; + float radiusSquared; + }; + + struct cplane_s + { + float normal[3]; + float dist; + char type; + char signbits; + char pad[2]; + }; + + struct cbrushside_t + { + cplane_s* plane; + unsigned int materialNum; + short firstAdjacentSideOffset; + char edgeCount; + char pad; + }; + + typedef unsigned char cbrushedge_t; + + struct BrushWrapper + { + float mins[3]; + int contents; + float maxs[3]; + unsigned int numsides; + cbrushside_t* sides; + short axialMaterialNum[2][3]; + cbrushedge_t* baseAdjacentSide; + short firstAdjacentSideOffsets[2][3]; + char edgeCount[2][3]; + unsigned int numverts; + vec3_t* verts; + int totalEdgeCount; + cplane_s* planes; + char unknown[8]; + }; + + struct PhysGeomInfo + { + BrushWrapper* brush; + int type; + vec3_t orientation[3]; + vec3_t offset; + vec3_t halfLengths; + }; + + struct PhysGeomList + { + unsigned int count; + PhysGeomInfo* geoms; + float mass[3]; + }; + + struct XModelStreamInfo + { + char pad; + }; + + struct XModelQuat + { + short v[4]; + }; + + struct XModel + { + const char* name; + unsigned char numBones; + unsigned char numRootBones; + unsigned char numsurfs; + unsigned char lodRampType; + ScriptString* boneNames; + unsigned char* parentList; + XModelQuat* quats; + float* trans; + unsigned char* partClassification; + DObjAnimMat* baseMat; + XSurface* surfs; + Material** materialHandles; + XModelLodInfo lodInfo[4]; + XModelCollSurf_s* collSurfs; + int numCollSurfs; + int contents; + XBoneInfo* boneInfo; + float radius; + vec3_t mins; + vec3_t maxs; + unsigned short numLods; + short collLod; + XModelStreamInfo streamInfo; + int memUsage; + unsigned char flags; + bool bad; + PhysPreset* physPreset; + PhysGeomList* physGeoms; + PhysConstraints* physConstraints; + }; + + struct MaterialVertexDeclaration + { + unsigned int data[28]; + }; + + struct GfxVertexShaderLoadDef + { + unsigned int* program; + unsigned short programSize; + unsigned short loadForRenderer; + }; + + struct MaterialVertexShader + { + const char* name; + GfxVertexShaderLoadDef loadDef; + }; + + struct GfxPixelShaderLoadDef + { + unsigned int* program; + unsigned short programSize; + unsigned short loadForRenderer; + }; + + struct MaterialPixelShader + { + const char* name; + GfxPixelShaderLoadDef loadDef; + }; + + enum MaterialShaderArgumentType + { + MTL_ARG_MATERIAL_VERTEX_CONST = 0, + MTL_ARG_LITERAL_VERTEX_CONST = 1, + MTL_ARG_MATERIAL_PIXEL_SAMPLER = 2, + MTL_ARG_CODE_VERTEX_CONST = 3, + MTL_ARG_CODE_PIXEL_SAMPLER = 4, + MTL_ARG_CODE_PIXEL_CONST = 5, + MTL_ARG_MATERIAL_PIXEL_CONST = 6, + MTL_ARG_LITERAL_PIXEL_CONST = 7, + }; + + struct MaterialArgumentCodeConst + { + unsigned short index; + unsigned char firstRow; + unsigned char rowCount; + }; + + union MaterialArgumentDef + { + const float (*literalConst)[4]; + MaterialArgumentCodeConst codeConst; + unsigned int codeSampler; + unsigned int nameHash; + }; + + struct MaterialShaderArgument + { + unsigned short type; + unsigned short dest; + MaterialArgumentDef u; + }; + + struct MaterialPass + { + MaterialVertexDeclaration* vertexDecl; + MaterialVertexShader* vertexShader; + MaterialPixelShader* pixelShader; + unsigned char perPrimArgCount; + unsigned char perObjArgCount; + unsigned char stableArgCount; + unsigned char customSamplerFlags; + MaterialShaderArgument* args; + }; + + struct MaterialTechnique + { + const char* name; + unsigned short flags; + unsigned short passCount; + MaterialPass passArray[1]; + }; + + struct MaterialTechniqueSet + { + const char* name; + char unknown[8]; + MaterialTechnique* techniques[43]; + }; + + struct complex_s + { + float real; + float imag; + }; + + struct WaterWritable + { + float floatTime; + }; + + struct water_t + { + WaterWritable writable; + complex_s* H0; + float* wTerm; + int M; + int N; + float Lx; + float Lz; + float gravity; + float windvel; + float winddir[2]; + float amplitude; + float codeConstant[4]; + GfxImage* image; + }; + + struct MaterialWaterDef + { + char unknown[28]; + water_t* water; + }; + + union MaterialTextureDefInfo + { + GfxImage* image; + MaterialWaterDef* water; + }; + + enum TextureSemantic + { + TS_2D = 0x0, + TS_FUNCTION = 0x1, + TS_COLOR_MAP = 0x2, + TS_UNUSED_1 = 0x3, + TS_UNUSED_2 = 0x4, + TS_NORMAL_MAP = 0x5, + TS_UNUSED_3 = 0x6, + TS_UNUSED_4 = 0x7, + TS_SPECULAR_MAP = 0x8, + TS_UNUSED_5 = 0x9, + TS_UNUSED_6 = 0xA, + TS_WATER_MAP = 0xB, + }; + + struct MaterialTextureDef + { + unsigned int nameHash; + unsigned char nameStart; + unsigned char nameEnd; + unsigned char samplerState; + unsigned char semantic; + MaterialTextureDefInfo u; + }; + + struct MaterialConstantDef + { + unsigned int data[8]; + }; + + struct GfxStateBits + { + unsigned int loadBits[2]; + }; + + struct GfxImageLoadDef + { + char levelCount; + char flags; + unsigned short dimensions[3]; + int format; + unsigned int resourceSize; + // Embedded mip data is stored smallest-to-largest, matching IWI file order. + char data[1]; + }; + + union GfxTexture + { + GfxImageLoadDef* loadDef; + }; + + struct Picmip + { + char platform[2]; + }; + + struct CardMemory + { + int platform[2]; + }; + + enum MapType + { + MAPTYPE_NONE = 0x0, + MAPTYPE_INVALID1 = 0x1, + MAPTYPE_INVALID2 = 0x2, + MAPTYPE_2D = 0x3, + MAPTYPE_3D = 0x4, + MAPTYPE_CUBE = 0x5, + + MAPTYPE_COUNT + }; + + enum ImageCategory + { + IMG_CATEGORY_UNKNOWN = 0x0, + IMG_CATEGORY_AUTO_GENERATED = 0x1, + IMG_CATEGORY_LIGHTMAP = 0x2, + IMG_CATEGORY_LOAD_FROM_FILE = 0x3, + IMG_CATEGORY_RAW = 0x4, + IMG_CATEGORY_FIRST_UNMANAGED = 0x5, + IMG_CATEGORY_WATER = 0x5, + IMG_CATEGORY_RENDERTARGET = 0x6, + IMG_CATEGORY_TEMP = 0x7, + }; + + struct GfxImage + { + MapType mapType; + GfxTexture texture; + Picmip picmip; + bool noPicmip; + char semantic; + char track; + CardMemory cardMemory; + unsigned short width; + unsigned short height; + unsigned short depth; + char category; + bool delayLoadPixels; + const char* name; + }; + + struct gcc_align32(8) GfxDrawSurfFields + { + uint64_t objectId : 16; + uint64_t reflectionProbeIndex : 8; + uint64_t customIndex : 5; + uint64_t materialSortedIndex : 11; + uint64_t prepass : 2; + uint64_t primaryLightIndex : 8; + uint64_t surfType : 4; + uint64_t primarySortKey : 6; + uint64_t unused : 4; + }; + + union GfxDrawSurf + { + gcc_align32(8) GfxDrawSurfFields fields; + gcc_align32(8) uint64_t packed; + }; + + struct MaterialInfo + { + const char* name; + unsigned char gameFlags; + unsigned char sortKey; + unsigned char textureAtlasRowCount; + unsigned char textureAtlasColumnCount; + GfxDrawSurf drawSurf; + unsigned int surfaceTypeBits; + uint16_t hashIndex; + }; + + struct Material + { + MaterialInfo info; + char stateBitsEntry[43]; + unsigned char textureCount; + unsigned char constantCount; + unsigned char stateBitsCount; + char unknown0[14]; + MaterialTechniqueSet* techniqueSet; + MaterialTextureDef* textureTable; + MaterialConstantDef* constantTable; + GfxStateBits* stateBitsTable; + }; + + struct SndCurve + { + const char* name; + char unknown0[68]; + }; + + enum QosSoundFileType + { + // Only the primed branch is identified so far. Other values use the inline MssSound branch. + QOS_SOUND_FILE_TYPE_PRIMED = 3, + }; + + struct QosMssSound + { + // Largely matches an MSS sound info block, but only the embedded data size is confirmed. + int unknown0; + raw_uint unknownDataPtr0; + unsigned int dataSize; + char unknown1[24]; + raw_uint unknownDataPtr1; + raw_byte data[1]; + }; + + struct QosPrimedSound + { + const char* name; + raw_byte* buffer; + unsigned int size; + }; + + union QosSoundFileRef + { + QosMssSound* mssSound; + QosPrimedSound* primeSnd; + }; + + struct SoundFile + { + const char* unknownString0; + const char* unknownString1; + QosSoundFileRef u; + // Scalar fields between the file reference and the type discriminator. + char unknown0[184]; + QosSoundFileType type; + }; + + struct snd_alias_t + { + const char* aliasName; + const char* subtitle; + const char* secondaryAliasName; + const char* chainAliasName; + SoundFile* soundFile; + char unknown0[56]; + SndCurve* volumeFalloffCurve; + }; + + struct snd_alias_list_t + { + const char* name; + snd_alias_t* head; + int count; + }; + + struct MapEnts + { + const char* name; + char* entityString; + int numEntityChars; + }; + + struct cStaticModel_t + { + char unknown0[4]; + XModel* xmodel; + float origin[3]; + float invScaledAxis[3][3]; + float absmin[3]; + float absmax[3]; + }; + + struct dmaterial_t + { + char material[64]; + int surfaceFlags; + int contentFlags; + }; + + struct cNode_t + { + cplane_s* plane; + int16_t children[2]; + }; + + struct cLeaf_t + { + uint16_t firstCollAabbIndex; + uint16_t collAabbCount; + int brushContents; + int terrainContents; + float mins[3]; + float maxs[3]; + int leafBrushNode; + int16_t cluster; + }; + + struct cLeafBrushNodeLeaf_t + { + uint16_t* brushes; + }; + + struct cLeafBrushNodeChildren_t + { + float dist; + float range; + uint16_t childOffset[2]; + }; + + union cLeafBrushNodeData_t + { + cLeafBrushNodeLeaf_t leaf; + cLeafBrushNodeChildren_t children; + }; + + struct cLeafBrushNode_s + { + char axis; + int16_t leafBrushCount; + int contents; + cLeafBrushNodeData_t data; + }; + + struct CollisionBorder + { + float distEq[3]; + float zBase; + float zSlope; + float start; + float length; + }; + + struct CollisionPartition + { + unsigned char triCount; + unsigned char borderCount; + char unknown0[2]; + int firstTri; + int unknown1; + int unknown2; + CollisionBorder* borders; + }; + + union CollisionAabbTreeIndex + { + int firstChildIndex; + int partitionIndex; + }; + + struct CollisionAabbTree + { + float origin[3]; + uint16_t materialIndex; + uint16_t childCount; + float halfSize[3]; + CollisionAabbTreeIndex u; + }; + + struct cmodel_t + { + float mins[3]; + float maxs[3]; + float radius; + cLeaf_t leaf; + }; + + struct type_align32(16) cbrush_t + { + float mins[3]; + int contents; + float maxs[3]; + unsigned int numsides; + cbrushside_t* sides; + int16_t axialMaterialNum[2][3]; + cbrushedge_t* baseAdjacentSide; + int16_t firstAdjacentSideOffsets[2][3]; + char edgeCount[2][3]; + char unknown0[2]; + unsigned int unknown1; // PC loader does not use this word while streaming; likely related to verts. + vec3_t* verts; + }; + + struct DynEntityDef + { + char unknown0[32]; // Includes type and placement data. + XModel* xModel; + char unknown1[4]; // Matches IW-era brushModel/physicsBrushModel area. + FxEffectDef* destroyFx; + XModelPieces* destroyPieces; + PhysPreset* physPreset; + char unknown2[36]; + }; + + struct DynEntityClient + { + char unknown[52]; + }; + + struct DynEntityServer + { + char unknown[36]; + }; + + struct DynEntityColl + { + char unknown[32]; + }; + + struct DynEntityPhysConstraint + { + char unknown[72]; + }; + + struct clipMap_t + { + const char* name; + int isInUse; + int planeCount; + cplane_s* planes; + unsigned int numStaticModels; + cStaticModel_t* staticModelList; + unsigned int numMaterials; + dmaterial_t* materials; + unsigned int numBrushSides; + cbrushside_t* brushsides; + unsigned int numBrushEdges; + cbrushedge_t* brushEdges; + unsigned int numNodes; + cNode_t* nodes; + unsigned int numLeafs; + cLeaf_t* leafs; + unsigned int leafbrushNodesCount; + cLeafBrushNode_s* leafbrushNodes; + unsigned int numLeafBrushes; + uint16_t* leafbrushes; + unsigned int numLeafSurfaces; + unsigned int* leafsurfaces; + unsigned int vertCount; + vec3_t* verts; + unsigned int numBrushVerts; + vec3_t* brushVerts; + unsigned int nuinds; + uint16_t* uinds; + int triCount; + uint16_t* triIndices; + char* triEdgeIsWalkable; + int borderCount; + CollisionBorder* borders; + int partitionCount; + CollisionPartition* partitions; + int aabbTreeCount; + CollisionAabbTree* aabbTrees; + unsigned int numSubModels; + cmodel_t* cmodels; + uint16_t numBrushes; + uint16_t unknown0; + cbrush_t* brushes; + int numClusters; + int clusterBytes; + char* visibility; + int unknown2; + MapEnts* mapEnts; + cbrush_t* box_brush; + char unknown1[74]; + uint16_t dynEntCount[4]; + DynEntityDef* dynEntDefList[2]; + DynEntityClient* dynEntClientList[2]; + DynEntityServer* dynEntServerList[2]; + DynEntityColl* dynEntCollList[4]; + int num_constraints; + DynEntityPhysConstraint* constraints; + int unknown3; + }; + + struct ComPrimaryLight + { + unsigned char type; + unsigned char canUseShadowMap; + unsigned char exponent; + unsigned char unused; + vec3_t color; + vec3_t dir; + vec3_t origin; + float radius; + float cosHalfFovOuter; + float cosHalfFovInner; + float cosHalfFovExpanded; + float rotationLimit; + float translationLimit; + const char* defName; + }; + + struct ComWorldUnknownCell + { + char unknown[32]; + unsigned char* data; + }; + + struct ComWorld + { + const char* name; + int isInUse; + int unknown0; + unsigned int primaryLightCount; + ComPrimaryLight* primaryLights; + char unknown1[16]; + unsigned int unknownCellCount; + ComWorldUnknownCell* unknownCells; + }; + + struct pathnode_t; + struct pathnode_tree_t; + + struct pathnode_tree_nodes_t + { + int nodeCount; + pathnode_t** nodes; + }; + + union pathnode_tree_info_t + { + pathnode_tree_t* child[2]; + pathnode_tree_nodes_t s; + }; + + struct pathnode_tree_t + { + int axis; + float dist; + pathnode_tree_info_t u; + }; + + struct type_align(16) pathbasenode_t + { + float vOrigin[3]; + unsigned int type; + }; + + struct pathnode_transient_t + { + int iSearchFrame; + pathnode_t* pNextOpen; + pathnode_t* pPrevOpen; + pathnode_t* pParent; + float fCost; + float fHeuristic; + float costFactor; + int unknown0; + }; + + struct pathnode_dynamic_t + { + void* pOwner; + int iFreeTime; + int iValidTime[3]; + int inPlayerLOSTime; + int16_t wLinkCount; + int16_t wOverlapCount; + int16_t turretEntNumber; + int16_t userCount; + }; + + struct pathlink_s + { + float fDist; + uint16_t nodeNum; + char disconnectCount; + char negotiationLink; + char ubBadPlaceCount[4]; + }; + + enum nodeType + { + NODE_BADNODE = 0x0, + NODE_PATHNODE = 0x1, + NODE_COVER_STAND = 0x2, + NODE_COVER_CROUCH = 0x3, + NODE_COVER_CROUCH_WINDOW = 0x4, + NODE_COVER_PRONE = 0x5, + NODE_COVER_RIGHT = 0x6, + NODE_COVER_LEFT = 0x7, + NODE_COVER_WIDE_RIGHT = 0x8, + NODE_COVER_WIDE_LEFT = 0x9, + NODE_CONCEALMENT_STAND = 0xA, + NODE_CONCEALMENT_CROUCH = 0xB, + NODE_CONCEALMENT_PRONE = 0xC, + NODE_REACQUIRE = 0xD, + NODE_BALCONY = 0xE, + NODE_SCRIPTED = 0xF, + NODE_NEGOTIATION_BEGIN = 0x10, + NODE_NEGOTIATION_END = 0x11, + NODE_TURRET = 0x12, + NODE_GUARD = 0x13, + NODE_NUMTYPES = 0x14, + NODE_DONTLINK = 0x14, + }; + + struct pathnode_constant_t + { + nodeType type; + uint16_t spawnflags; + ScriptString targetname; + ScriptString script_linkName; + ScriptString script_noteworthy; + ScriptString target; + ScriptString animscript; + int animscriptfunc; + float vOrigin[3]; + float fAngle; + float forward[2]; + float fRadius; + float minUseDistSq; + int16_t wOverlapNode[2]; + int16_t wChainId; + int16_t wChainDepth; + int16_t wChainParent; + uint16_t totalLinkCount; + pathlink_s* Links; + }; + + struct pathnode_t + { + pathnode_constant_t constant; + pathnode_dynamic_t dynamic; + pathnode_transient_t transient; + }; + + // QOS PC/Wii loaders confirm this byte layout. Semantic field names are inherited from matching IW3/T4 path data. + struct PathData + { + unsigned int nodeCount; + pathnode_t* nodes; + pathbasenode_t* basenodes; + uint16_t* chainNodeForNode; + uint16_t* nodeForChainNode; + int visBytes; + char* pathVis; + int nodeTreeCount; + pathnode_tree_t* nodeTree; + }; + + struct GameWorldSp + { + const char* name; + PathData path; + }; + + struct GameWorldMp + { + const char* name; + }; + + struct GfxWorldVertex + { + float xyz[3]; + float binormalSign; + GfxColor color; + float texCoord[2]; + float lmapCoord[2]; + PackedUnitVec normal; + PackedUnitVec tangent; + }; + + struct GfxWorldVertexData + { + GfxWorldVertex* vertices; + void* worldVb; + }; + + struct GfxWorldVertexLayerData + { + raw_byte* data; + void* layerVb; + }; + + struct GfxLight + { + unsigned char type; + unsigned char canUseShadowMap; + char unused[2]; + float color[3]; + float dir[3]; + float origin[3]; + float radius; + float cosHalfFovOuter; + float cosHalfFovInner; + int exponent; + unsigned int spotShadowIndex; + unsigned int unknown; + GfxLightDef* def; + }; + + struct GfxReflectionProbe + { + float origin[3]; + GfxImage* reflectionImage; + }; + + struct srfTriangles_t + { + int vertexLayerData; + int firstVertex; + unsigned short vertexCount; + unsigned short triCount; + int baseIndex; + }; + + struct GfxSurface + { + srfTriangles_t tris; + Material* material; + char lightmapIndex; + char reflectionProbeIndex; + char primaryLightIndex; + char flags; + float bounds[2][3]; + }; + + struct GfxCullGroup + { + float mins[3]; + float maxs[3]; + int surfaceCount; + int startSurfIndex; + }; + + struct GfxStaticModelDrawInst + { + char unknown[56]; + XModel* model; + unsigned int unknown2; + }; + + struct GfxStaticModelInst + { + float mins[3]; + float maxs[3]; + GfxColor groundLighting; + unsigned int unknown; + }; + + struct GfxAabbTreeChildren; + + struct GfxAabbTree + { + char unknown[32]; + unsigned int smodelIndexCount; + raw_uint* smodelIndexes; + unsigned int childCount; + GfxAabbTreeChildren* children; + }; + + struct GfxAabbTreeChildren + { + GfxAabbTree child; + }; + + struct GfxCell; + + struct GfxPortal + { + char unknown[32]; + GfxCell* cell; + vec3_t* vertices; + unsigned char vertexCount; + char unknown2[27]; + }; + + struct GfxCell + { + float mins[3]; + float maxs[3]; + GfxAabbTree* aabbTree; + int portalCount; + GfxPortal* portals; + int cullGroupCount; + int* cullGroups; + unsigned char reflectionProbeCount; + char pad[3]; + raw_byte* reflectionProbes; + }; + + struct GfxLightmapArray + { + GfxImage* primary; + GfxImage* secondary; + }; + + struct GfxLightGridEntry + { + unsigned short colorsIndex; + unsigned char primaryLightIndex; + unsigned char needsTrace; + }; + + struct GfxLightGridColors + { + unsigned char rgb[56][3]; + }; + + struct GfxLightGrid + { + unsigned char hasLightRegions; + unsigned char pad[3]; + unsigned short mins[3]; + unsigned short maxs[3]; + unsigned int rowAxis; + unsigned int colAxis; + unsigned short* rowDataStart; + unsigned int rawRowDataSize; + raw_byte* rawRowData; + unsigned int entryCount; + GfxLightGridEntry* entries; + unsigned int colorCount; + GfxLightGridColors* colors; + }; + + struct GfxBrushModel + { + char unknown[48]; + unsigned int surfaceCount; + unsigned int startSurfIndex; + unsigned int unknown2; + }; + + struct MaterialMemory + { + Material* material; + int memory; + }; + + struct sunflare_t + { + char hasValidData; + char unknown0[3]; + Material* spriteMaterial; + Material* flareMaterial; + float spriteSize; + float flareMinSize; + float flareMinDot; + float flareMaxSize; + float flareMaxDot; + float flareMaxAlpha; + int flareFadeInTime; + int flareFadeOutTime; + float blindMinDot; + float blindMaxDot; + float blindMaxDarken; + int blindFadeInTime; + int blindFadeOutTime; + float glareMinDot; + float glareMaxDot; + float glareMaxLighten; + int glareFadeInTime; + int glareFadeOutTime; + float sunFxPosition[3]; + }; + + struct GfxSceneDynModel + { + char unknown[8]; + }; + + struct GfxSceneDynBrush + { + char unknown[8]; + }; + + struct GfxDynEntCellRef + { + unsigned short dynEntIndex; + unsigned short cellIndex; + unsigned short nextIndex; + }; + + struct GfxShadowGeometry + { + unsigned short surfaceCount; + unsigned short smodelCount; + unsigned short* sortedSurfIndex; + unsigned short* smodelIndex; + }; + + struct GfxLightRegion + { + char unknown[24]; + }; + + struct GfxWorld + { + const char* name; + const char* baseName; + unsigned int planeCount; + cplane_s* planes; + unsigned int nodeCount; + unsigned short* nodes; + unsigned int indexCount; + unsigned short* indices; + unsigned int surfaceCount; + GfxSurface* surfaces; + char unknown0[20]; + unsigned int skySurfCount; + int* skyStartSurfs; + GfxImage* skyImage; + unsigned char skySamplerState; + char unknown1[3]; + const char* skyBoxModel; + unsigned int vertexCount; + GfxWorldVertexData vd; + unsigned int vertexLayerDataSize; + GfxWorldVertexLayerData vld; + char unknown2[128]; + GfxLight* sunLight; + char unknown3[12]; + unsigned int sunPrimaryLightIndex; + unsigned int primaryLightCount; + char unknown4[4]; + unsigned int cullGroupCount; + unsigned int reflectionProbeCount; + GfxReflectionProbe* reflectionProbes; + GfxCullGroup* cullGroups; + unsigned int smodelCount; + GfxStaticModelDrawInst* smodelDrawInsts; + GfxStaticModelInst* smodelInsts; + unsigned int cellCount; + unsigned int cellBitsCount; + GfxCell* cells; + unsigned int lightmapCount; + GfxLightmapArray* lightmaps; + GfxLightGrid lightGrid; + unsigned int modelCount; + GfxBrushModel* models; + char unknown5[28]; + unsigned int materialMemoryCount; + MaterialMemory* materialMemory; + sunflare_t sun; + float outdoorLookupMatrix[4][4]; + GfxImage* outdoorImage; + unsigned int dynEntDataSize0; + unsigned int dynEntDataSize1; + unsigned int sceneDynModelCount; + unsigned int sceneDynBrushCount; + raw_byte* smodelVisData0; + raw_byte* smodelVisData1; + raw_byte* smodelVisData2; + raw_byte* smodelVisData3; + raw_byte* surfaceVisData0; + raw_byte* surfaceVisData1; + raw_byte* surfaceVisData2; + raw_byte* surfaceVisData3; + GfxDrawSurf* surfaceMaterials; + raw_uint* surfaceCastsSunShadow; + raw_uint* cellCasterBits; + raw_byte* cellHasSunLitSurfsBits; + raw_byte* dynEntVisData0_0; + raw_byte* dynEntVisData0_1; + raw_byte* dynEntVisData0_2; + raw_byte* dynEntVisData0_3; + raw_byte* dynEntVisData1_0; + raw_byte* dynEntVisData1_1; + raw_byte* dynEntVisData1_2; + raw_byte* dynEntVisData1_3; + raw_byte* dynEntCellBits0; + raw_byte* dynEntCellBits1; + unsigned short* dynEntSortList0; + unsigned short* dynEntSortList1; + GfxSceneDynModel* sceneDynModel; + GfxSceneDynBrush* sceneDynBrush; + GfxDynEntCellRef* dynEntCellRefs; + raw_uint* dynEntUnknown; + unsigned short* sortedSurfIndex; + raw_uint* primaryLightEntityShadowVis; + raw_uint* primaryLightDynEntShadowVis0; + raw_uint* primaryLightDynEntShadowVis1; + GfxShadowGeometry* shadowGeom; + unsigned int lightRegionCount; + GfxLightRegion* lightRegion; + Material* unknownMaterial; + }; + + struct GfxLightImage + { + GfxImage* image; + char samplerState; + }; + + struct GfxLightDef + { + const char* name; + GfxLightImage attenuation; + int lmapLookupStart; + }; + + struct Glyph + { + unsigned short letter; + char x0; + char y0; + unsigned char dx; + unsigned char pixelWidth; + unsigned char pixelHeight; + unsigned char unknown0; + float s0; + float t0; + float s1; + float t1; + }; + + struct Font_s + { + const char* fontName; + int pixelHeight; + int glyphCount; + Material* material; + Material* glowMaterial; + Glyph* glyphs; + }; + + struct menuDef_t; + + struct MenuList + { + const char* name; + int menuCount; + menuDef_t** menus; + }; + + struct rectDef_s + { + float x; + float y; + float w; + float h; + int horzAlign; + int vertAlign; + }; + + struct windowDef_t + { + const char* name; + rectDef_s rect; + rectDef_s rectClient; + const char* group; + int style; + int border; + int ownerDraw; + int ownerDrawFlags; + float borderSize; + int staticFlags; + int dynamicFlags[4]; // QoS loader confirms four entries; IW3/T4 only use one. + int nextTime; + float foreColor[4]; + float backColor[4]; + float borderColor[4]; + float outlineColor[4]; + Material* background; + }; + + struct ItemKeyHandler + { + int key; + const char* action; + ItemKeyHandler* next; + }; + + union operandInternalDataUnion + { + int intVal; + float floatVal; + const char* string; + }; + + enum expDataType + { + VAL_INT = 0x0, + VAL_FLOAT = 0x1, + VAL_STRING = 0x2, + }; + + enum operationEnum + { + OP_NOOP = 0x0, + OP_RIGHTPAREN = 0x1, + OP_MULTIPLY = 0x2, + OP_DIVIDE = 0x3, + OP_MODULUS = 0x4, + OP_ADD = 0x5, + OP_SUBTRACT = 0x6, + OP_NOT = 0x7, + OP_LESSTHAN = 0x8, + OP_LESSTHANEQUALTO = 0x9, + OP_GREATERTHAN = 0xA, + OP_GREATERTHANEQUALTO = 0xB, + OP_EQUALS = 0xC, + OP_NOTEQUAL = 0xD, + OP_AND = 0xE, + OP_OR = 0xF, + OP_LEFTPAREN = 0x10, + OP_COMMA = 0x11, + OP_BITWISEAND = 0x12, + OP_BITWISEOR = 0x13, + OP_BITWISENOT = 0x14, + OP_BITSHIFTLEFT = 0x15, + OP_BITSHIFTRIGHT = 0x16, + OP_SIN = 0x17, + OP_FIRSTFUNCTIONCALL = OP_SIN, + OP_COS = 0x18, + OP_MIN = 0x19, + OP_MAX = 0x1A, + OP_MILLISECONDS = 0x1B, + OP_DVARINT = 0x1C, + OP_DVARBOOL = 0x1D, + OP_DVARFLOAT = 0x1E, + OP_DVARSTRING = 0x1F, + OP_STAT = 0x20, + OP_UIACTIVE = 0x21, + OP_FLASHBANGED = 0x22, + OP_SCOPED = 0x23, + OP_SCOREBOARDVISIBLE = 0x24, + OP_INKILLCAM = 0x25, + OP_PLAYERFIELD = 0x26, + OP_SELECTINGLOCATION = 0x27, + OP_TEAMFIELD = 0x28, + OP_OTHERTEAMFIELD = 0x29, + OP_MARINESFIELD = 0x2A, + OP_OPFORFIELD = 0x2B, + OP_MENUISOPEN = 0x2C, + OP_WRITINGDATA = 0x2D, + OP_INLOBBY = 0x2E, + OP_INPRIVATEPARTY = 0x2F, + OP_PRIVATEPARTYHOST = 0x30, + OP_PRIVATEPARTYHOSTINLOBBY = 0x31, + OP_ALONEINPARTY = 0x32, + OP_ADSJAVELIN = 0x33, + OP_WEAPLOCKBLINK = 0x34, + OP_WEAPATTACKTOP = 0x35, + OP_WEAPATTACKDIRECT = 0x36, + OP_SECONDSASTIME = 0x37, + OP_TABLELOOKUP = 0x38, + OP_LOCALIZESTRING = 0x39, + OP_LOCALVARINT = 0x3A, + OP_LOCALVARBOOL = 0x3B, + OP_LOCALVARFLOAT = 0x3C, + OP_LOCALVARSTRING = 0x3D, + OP_TIMELEFT = 0x3E, + OP_SECONDSASCOUNTDOWN = 0x3F, + OP_TOINT = 0x40, + OP_TOSTRING = 0x41, + OP_TOFLOAT = 0x42, + OP_GAMETYPENAME = 0x43, + OP_GAMETYPE = 0x44, + OP_GAMETYPEDESCRIPTION = 0x45, + OP_SCORE = 0x46, + OP_FRIENDSONLINE = 0x47, + OP_FOLLOWING = 0x48, + OP_STATRANGEBITSSET = 0x49, + NUM_OPERATORS = 0x4A, + }; + + struct Operand + { + expDataType dataType; + operandInternalDataUnion internals; + }; + + union entryInternalData + { + Operand operand; + operationEnum op; + }; + + enum expressionEntryType : int + { + EET_OPERATOR = 0x0, + EET_OPERAND = 0x1, + }; + + struct expressionEntry + { + expressionEntryType type; + entryInternalData data; + }; + + struct statement_s + { + int numEntries; + expressionEntry** entries; + }; + + struct columnInfo_s + { + int pos; + int width; + int maxChars; + int alignment; + }; + + struct listBoxDef_s + { + int mousePos; + int startPos[4]; + int endPos[4]; + int drawPadding; + float elementWidth; + float elementHeight; + int elementStyle; + int numColumns; + columnInfo_s columnInfo[16]; + const char* doubleClick; + int notselectable; + int noScrollBars; + int usePaging; + float selectBorder[4]; + float disableColor[4]; + Material* selectIcon; + }; + + struct editFieldDef_s + { + float minVal; + float maxVal; + float defVal; + float range; + int maxChars; + int maxCharsGotoNext; + int maxPaintChars; + int paintOffset; + }; + + struct multiDef_s + { + const char* dvarList[32]; + const char* dvarStr[32]; + float dvarValue[32]; + int count; + int strDef; + }; + + union itemDefData_t + { + listBoxDef_s* listBox; + editFieldDef_s* editField; + multiDef_s* multi; + const char* enumDvarName; + void* data; + }; + + enum ItemDefType + { + ITEM_TYPE_TEXT = 0x0, + ITEM_TYPE_BUTTON = 0x1, + ITEM_TYPE_RADIOBUTTON = 0x2, + ITEM_TYPE_CHECKBOX = 0x3, + ITEM_TYPE_EDITFIELD = 0x4, + ITEM_TYPE_COMBO = 0x5, + ITEM_TYPE_LISTBOX = 0x6, + ITEM_TYPE_MODEL = 0x7, + ITEM_TYPE_OWNERDRAW = 0x8, + ITEM_TYPE_NUMERICFIELD = 0x9, + ITEM_TYPE_SLIDER = 0xA, + ITEM_TYPE_YESNO = 0xB, + ITEM_TYPE_MULTI = 0xC, + ITEM_TYPE_DVARENUM = 0xD, + ITEM_TYPE_BIND = 0xE, + ITEM_TYPE_MENUMODEL = 0xF, + ITEM_TYPE_VALIDFILEFIELD = 0x10, + ITEM_TYPE_DECIMALFIELD = 0x11, + ITEM_TYPE_UPREDITFIELD = 0x12, + ITEM_TYPE_GAME_MESSAGE_WINDOW = 0x13, + }; + + struct itemDef_s + { + windowDef_t window; + rectDef_s textRect[4]; + int type; + int dataType; + int alignment; + int fontEnum; + int textAlignMode; + float textalignx; + float textaligny; + float textscale; + int textStyle; + int gameMsgWindowIndex; + int gameMsgWindowMode; + const char* text; + int textSavegameInfo; // qos-xport name; loader only confirms this as an int at offset 312. + menuDef_t* parent; + const char* mouseEnterText; + const char* mouseExitText; + const char* mouseEnter; + const char* mouseExit; + const char* action; + const char* onAccept; + const char* onFocus; + const char* leaveFocus; + const char* dvar; + const char* dvarTest; + ItemKeyHandler* onKey; + const char* enableDvar; + int dvarFlags; + snd_alias_list_t* focusSound; + int feeder; // qos-xport identifies this as feeder; structurally equivalent to IW3/T4 special. + int cursorPos[4]; + itemDefData_t typeData; + int imageTrack; + statement_s visibleExp; + statement_s textExp; + statement_s materialExp; + statement_s rectXExp; + statement_s rectYExp; + statement_s rectWExp; + statement_s rectHExp; + statement_s unknownStatement0; // Loader confirms one additional statement at offset 460. + }; + + struct menuDef_t + { + windowDef_t window; + const char* font; + int fullScreen; + int itemCount; + int fontIndex; + int cursorItem[4]; + int fadeCycle; + float fadeClamp; + float fadeAmount; + float fadeInAmount; + float blurRadius; + const char* onOpen; + const char* onClose; + const char* onESC; + ItemKeyHandler* onKey; + statement_s visibleExp; + const char* allowedBinding; + const char* soundName; + int imageTrack; + float focusColor[4]; + float disableColor[4]; + statement_s rectXExp; + statement_s rectYExp; + itemDef_s** items; + }; + + struct LocalizeEntry + { + const char* value; + const char* name; + }; + + struct snd_alias_list_name + { + const char* soundName; + }; + + union SndAliasCustom + { + snd_alias_list_name* name; + snd_alias_list_t* sound; + }; + + struct WeaponDef + { + const char* name; + const char* displayName; + const char* overlayName; + XModel* unknownModel12; + XModel* unknownModel16; + const char* xanimNames[35]; + const char* modeName; + char unknownData164[32]; + const char* unknownString196; + char unknownData200[4]; + FxEffectDef* unknownFx204; + FxEffectDef* unknownFx208; + SndAliasCustom unknownSoundAliases[53]; + SndAliasCustom* bounceSound; + FxEffectDef* unknownFx428; + FxEffectDef* unknownFx432; + FxEffectDef* unknownFx436; + FxEffectDef* unknownFx440; + Material* unknownMaterial444; + Material* unknownMaterial448; + char unknownData452[152]; + XModel* unknownModels604[3]; + const char* unknownString616; + const char* unknownString620; + XModel* unknownModel624; + Material* unknownMaterial628; + char unknownData632[4]; + Material* unknownMaterial636; + char unknownData640[12]; + const char* unknownString652; + char unknownData656[4]; + const char* unknownString660; + char unknownData664[16]; + const char* unknownString680; + char unknownData684[280]; + Material* unknownMaterial964; + char unknownData968[24]; + const char* unknownString992; + char unknownData996[224]; + const char* unknownString1220; + char unknownData1224[40]; + Material* unknownMaterial1264; + char unknownData1268[8]; + Material* unknownMaterial1276; + char unknownData1280[20]; + const char* unknownString1300; + char unknownData1304[4]; + const char* unknownString1308; + char unknownData1312[4]; + XModel* unknownModels1316[16]; + const char* unknownStrings1380[16]; + char unknownData1444[80]; + XModel* unknownModel1524; + char unknownData1528[4]; + FxEffectDef* unknownFx1532; + char unknownData1536[4]; + FxEffectDef* unknownFx1540; + SndAliasCustom unknownSound1544; + SndAliasCustom unknownSound1548; + char unknownData1552[32]; + FxEffectDef* unknownFx1584; + FxEffectDef* unknownFx1588; + SndAliasCustom unknownSound1592; + char unknownData1596[240]; + FxEffectDef* unknownFx1836; + char unknownData1840[24]; + FxEffectDef* unknownFx1864; + SndAliasCustom unknownSound1868; + char unknownData1872[208]; + // Offset 2080..2108: names/counts inferred from IW3/T4 accuracy graph layout and QoS loader ordering. + const char* aiVsAiAccuracyGraphName; + const char* aiVsPlayerAccuracyGraphName; + vec2_t* aiVsAiAccuracyGraphKnots; + vec2_t* aiVsPlayerAccuracyGraphKnots; + vec2_t* originalAiVsAiAccuracyGraphKnots; + vec2_t* originalAiVsPlayerAccuracyGraphKnots; + int aiVsAiAccuracyGraphKnotCount; + int aiVsPlayerAccuracyGraphKnotCount; + char unknownData2112[80]; + const char* unknownString2192; + const char* unknownString2196; + char unknownData2200[16]; + const char* unknownString2216; + char unknownData2220[112]; + const char* unknownString2332; + const char* unknownString2336; + char unknownData2340[424]; + }; + + struct SndDriverGlobals + { + const char* name; + }; + + struct FxIntRange + { + int base; + int amplitude; + }; + + struct FxFloatRange + { + float base; + float amplitude; + }; + + struct FxSpawnDefOneShot + { + FxIntRange count; + }; + + struct FxSpawnDefLooping + { + int intervalMsec; + int count; + }; + + union FxSpawnDef + { + FxSpawnDefLooping looping; + FxSpawnDefOneShot oneShot; + }; + + struct FxElemAtlas + { + char behavior; + char index; + char fps; + char loopCount; + char colIndexBits; + char rowIndexBits; + short entryCount; + }; + + struct FxElemVec3Range + { + float base[3]; + float amplitude[3]; + }; + + struct FxElemVelStateInFrame + { + FxElemVec3Range velocity; + FxElemVec3Range totalDelta; + }; + + struct FxElemVelStateSample + { + FxElemVelStateInFrame local; + FxElemVelStateInFrame world; + }; + + struct FxElemVisualState + { + char color[4]; + float rotationDelta; + float rotationTotal; + float size[2]; + float scale; + }; + + struct FxElemVisStateSample + { + FxElemVisualState base; + FxElemVisualState amplitude; + }; + + union FxEffectDefRef + { + FxEffectDef* handle; + const char* name; + }; + + enum FxElemType + { + FX_ELEM_TYPE_SPRITE_BILLBOARD = 0x0, + FX_ELEM_TYPE_SPRITE_ORIENTED = 0x1, + FX_ELEM_TYPE_TAIL = 0x2, + FX_ELEM_TYPE_TRAIL = 0x3, + FX_ELEM_TYPE_CLOUD = 0x4, + FX_ELEM_TYPE_MODEL = 0x5, + FX_ELEM_TYPE_OMNI_LIGHT = 0x6, + FX_ELEM_TYPE_SPOT_LIGHT = 0x7, + FX_ELEM_TYPE_SOUND = 0x8, + FX_ELEM_TYPE_DECAL = 0x9, + FX_ELEM_TYPE_RUNNER = 0xA, + FX_ELEM_TYPE_COUNT = 0xB, + FX_ELEM_TYPE_LAST_SPRITE = 0x3, + FX_ELEM_TYPE_LAST_DRAWN = 0x7, + }; + + union FxElemVisuals + { + const void* anonymous; + Material* material; + XModel* model; + FxEffectDefRef effectDef; + const char* soundName; + }; + + struct FxElemMarkVisuals + { + Material* materials[2]; + }; + + union FxElemDefVisuals + { + FxElemMarkVisuals* markArray; + FxElemVisuals* array; + FxElemVisuals instance; + }; + + struct FxTrailVertex + { + float pos[2]; + float normal[2]; + float texCoord; + }; + + struct FxTrailDef + { + int scrollTimeMsec; + int repeatDist; + int splitDist; + int vertCount; + FxTrailVertex* verts; + int indCount; + unsigned short* inds; + }; + + struct FxElemDef + { + int flags; + FxSpawnDef spawn; + FxFloatRange spawnRange; + FxFloatRange fadeInRange; + FxFloatRange fadeOutRange; + float spawnFrustumCullRadius; + FxIntRange spawnDelayMsec; + FxIntRange lifeSpanMsec; + FxFloatRange spawnOrigin[3]; + FxFloatRange spawnOffsetRadius; + FxFloatRange spawnOffsetHeight; + FxFloatRange spawnAngles[3]; + FxFloatRange angularVelocity[3]; + FxFloatRange initialRotation; + FxFloatRange gravity; + FxFloatRange reflectionFactor; + FxElemAtlas atlas; + char elemType; + char visualCount; + char velIntervalCount; + char visStateIntervalCount; + FxElemVelStateSample* velSamples; + FxElemVisStateSample* visSamples; + FxElemDefVisuals visuals; + float collMins[3]; + float collMaxs[3]; + FxEffectDefRef effectOnImpact; + FxEffectDefRef effectOnDeath; + FxEffectDefRef effectEmitted; + FxFloatRange emitDist; + FxFloatRange emitDistVariance; + FxTrailDef* trailDef; + char sortOrder; + char lightingFrac; + char useItemClip; + char unused[1]; + }; + + struct FxEffectDef + { + const char* name; + int flags; + int totalSize; + int msecLoopingLife; + int elemDefCountLooping; + int elemDefCountOneShot; + int elemDefCountEmission; + FxElemDef* elemDefs; + }; + + struct DestructibleModel + { + XModel* model; + float breakHealth; + FxEffectDef* breakEffect; + SndAliasCustom breakSound; + const char* breakNotify; + XModel* spawnModel[3]; + }; + + struct DestructiblePiece + { + DestructibleModel dmodels[5]; + const char* attachBone; + ScriptString attachBoneHash; + unsigned char parentPiece; + unsigned char unused[1]; + float parentDamagePercent; + float bulletDamageScale; + float explosiveDamageScale; + PhysConstraints* physConstraints; + int health; + FxEffectDef* burnEffect; + SndAliasCustom burnSound; + }; + + struct DestructibleDef + { + const char* name; + int unknown0; + int numPieces; + DestructiblePiece* pieces; + }; + + struct FxImpactEntry + { + FxEffectDef* nonflesh[30]; + FxEffectDef* flesh[4]; + }; + + struct FxImpactTable + { + const char* name; + FxImpactEntry* table; + }; + + struct AiType + { + const char* name; + }; + + struct MpType + { + const char* name; + }; + + struct Character + { + const char* name; + }; + + struct XModelAlias + { + const char* name; + }; + + struct RawFile + { + const char* name; + int len; + const char* buffer; + }; + + struct StringTable + { + const char* name; + int columnCount; + int rowCount; + const char** values; + }; + + struct xmlAttribute + { + const char* name; + const char* value; + int unknown0; + }; + + struct xmlNode; + + struct xmlNodeList + { + int nodeCount; + xmlNode** nodes; + }; + + struct xmlAttribList + { + int unknown0; + xmlAttribute* attributes[8]; + }; + + struct xmlNodeComplex + { + const char* name; + xmlAttribList attribList; + xmlNodeList childList; + }; + + struct xmlNode + { + const char* name; + int unknown0; + xmlNodeComplex* complex; + }; + + struct XmlTree + { + xmlNodeList nodeList; + const char* name; + }; + + struct AnimReference + { + const char* unknownString0; + ScriptString unknownScriptString0; + char unknown0[6]; + XAnimParts* animation; + }; + + struct SceneAnimation + { + const char* name; + unsigned int animReferenceCount; + unsigned int unknown0; + AnimReference* animReferences; + }; + + struct CutsceneModelAttachment + { + const char* unknownString0; + const char* unknownString1; + }; + + struct CutsceneEntityDef + { + const char* unknownString0; + char unknown0[8]; + const char* unknownString1; + char unknown1[2]; + ScriptString unknownScriptString0; + unsigned int modelAttachmentCount; + CutsceneModelAttachment* modelAttachments; + }; + + struct CutsceneSectionDef + { + unsigned int entityCount; + CutsceneEntityDef* entities; + unsigned int sceneAnimationCount; + SceneAnimation** sceneAnimations; + }; + + struct Cutscene + { + const char* name; + char unknown0[12]; + unsigned int entityCount; + CutsceneEntityDef* entities; + unsigned int sectionCount; + CutsceneSectionDef* sections; + }; + + struct CustomCameraDef + { + const char* name; + int unknown4; + const char* unknownString0; + const char* unknownString1; + char unknown16[100]; + }; + + struct CustomCamera + { + const char* name; + int cameraCount; + CustomCameraDef* cameras; + }; + +#ifndef __zonecodegenerator +} +#endif + +#endif + +// EOF diff --git a/src/Common/Game/T4/T4_Assets.h b/src/Common/Game/T4/T4_Assets.h index 30c0d4280..892e8260d 100644 --- a/src/Common/Game/T4/T4_Assets.h +++ b/src/Common/Game/T4/T4_Assets.h @@ -448,8 +448,8 @@ namespace T4 void /*IDirect3DVertexBuffer9*/* vb0; unsigned int vertListCount; XRigidVertList* vertList; - int partBits[4]; void /*IDirect3DIndexBuffer9*/* indexBuffer; + int partBits[4]; }; struct XModelLodInfo diff --git a/src/ModMan/Web/Binds/AssetBinds.cpp b/src/ModMan/Web/Binds/AssetBinds.cpp index bc5a5af25..d81b96f4d 100644 --- a/src/ModMan/Web/Binds/AssetBinds.cpp +++ b/src/ModMan/Web/Binds/AssetBinds.cpp @@ -82,6 +82,10 @@ NLOHMANN_JSON_SERIALIZE_ENUM(CommonAssetType, {CommonAssetType::FOOTSTEP_TABLE, "footstep_table" }, {CommonAssetType::FOOTSTEP_FX_TABLE, "footstep_fx_table" }, {CommonAssetType::ZBARRIER, "zbarrier" }, + {CommonAssetType::XML_TREE, "xml_tree" }, + {CommonAssetType::SCENE_ANIMATION, "scene_animation" }, + {CommonAssetType::CUTSCENE, "cutscene" }, + {CommonAssetType::CUSTOM_CAMERA, "custom_camera" }, }); namespace diff --git a/src/ModMan/Web/Binds/ZoneBinds.cpp b/src/ModMan/Web/Binds/ZoneBinds.cpp index c6a94f3c1..3b1f4a1a4 100644 --- a/src/ModMan/Web/Binds/ZoneBinds.cpp +++ b/src/ModMan/Web/Binds/ZoneBinds.cpp @@ -10,6 +10,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(GameId, {GameId::IW3, "iw3"}, {GameId::IW4, "iw4"}, {GameId::IW5, "iw5"}, + {GameId::QOS, "qos"}, {GameId::T4, "t4" }, {GameId::T5, "t5" }, {GameId::T6, "t6" }, diff --git a/src/ModManUi/src/i18n/i18n.ts b/src/ModManUi/src/i18n/i18n.ts index 4f9aed026..67204c108 100644 --- a/src/ModManUi/src/i18n/i18n.ts +++ b/src/ModManUi/src/i18n/i18n.ts @@ -89,6 +89,10 @@ const ASSET_TYPE_LOOKUP: Record = { footstep_table: "Footstep table", footstep_fx_table: "Footstep FX table", zbarrier: "ZBarrier", + xml_tree: "XML tree", + scene_animation: "Scene animation", + cutscene: "Cutscene", + custom_camera: "Custom camera", }; export function localizeAssetType(assetType: CommonAssetType): string { diff --git a/src/ModManUi/src/meta/GameAssetTypes.ts b/src/ModManUi/src/meta/GameAssetTypes.ts index 51919ada5..f1019d6bc 100644 --- a/src/ModManUi/src/meta/GameAssetTypes.ts +++ b/src/ModManUi/src/meta/GameAssetTypes.ts @@ -130,6 +130,46 @@ const ASSET_TYPES_BY_GAME: Record = { "vehicle", "addon_map_ents", ], + qos: [ + "xmodel_pieces", + "phys_preset", + "phys_constraints", + "destructible_def", + "xanim", + "xmodel", + "material", + "technique_set", + "image", + "sound", + "sound_curve", + "clip_map", + "clip_map", + "com_world", + "game_world_sp", + "game_world_mp", + "map_ents", + "gfx_world", + "light_def", + "ui_map", + "font", + "menu_list", + "menu", + "localize_entry", + "weapon", + "sound_driver_globals", + "fx", + "impact_fx", + "ai_type", + "mp_type", + "character", + "xmodel_alias", + "raw_file", + "string_table", + "xml_tree", + "scene_animation", + "cutscene", + "custom_camera", + ], t4: [ "xmodel_pieces", "phys_preset", diff --git a/src/ModManUi/src/native/AssetBinds.ts b/src/ModManUi/src/native/AssetBinds.ts index 2e0f9fee5..d59b7a835 100644 --- a/src/ModManUi/src/native/AssetBinds.ts +++ b/src/ModManUi/src/native/AssetBinds.ts @@ -73,7 +73,11 @@ export type CommonAssetType = | "slug" | "footstep_table" | "footstep_fx_table" - | "zbarrier"; + | "zbarrier" + | "xml_tree" + | "scene_animation" + | "cutscene" + | "custom_camera"; export interface AssetDto { type: CommonAssetType; diff --git a/src/ModManUi/src/native/ZoneBinds.ts b/src/ModManUi/src/native/ZoneBinds.ts index 111c54d6f..0b9ae5d73 100644 --- a/src/ModManUi/src/native/ZoneBinds.ts +++ b/src/ModManUi/src/native/ZoneBinds.ts @@ -1,6 +1,6 @@ import { getBinds } from "@webwindowed/web-api"; -export type GameId = "iw3" | "iw4" | "iw5" | "t4" | "t5" | "t6"; +export type GameId = "iw3" | "iw4" | "iw5" | "qos" | "t4" | "t5" | "t6"; export type GamePlatform = "pc" | "xbox" | "ps3" | "wiiu"; diff --git a/src/ObjCommon/Font/JsonFont.h.template b/src/ObjCommon/Font/JsonFont.h.template index ce974fec5..5ee64fb35 100644 --- a/src/ObjCommon/Font/JsonFont.h.template +++ b/src/ObjCommon/Font/JsonFont.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/Font/JsonFont" + GAME + ".h" diff --git a/src/ObjCommon/InfoString/InfoString.h b/src/ObjCommon/InfoString/InfoString.h index 9d45d08c9..8642ee4a4 100644 --- a/src/ObjCommon/InfoString/InfoString.h +++ b/src/ObjCommon/InfoString/InfoString.h @@ -43,7 +43,7 @@ class InfoString class EqualValue { public: - constexpr bool operator()(const std::string& lhs, const std::string& rhs) const + bool operator()(const std::string& lhs, const std::string& rhs) const { return utils::StringEqualsIgnoreCase(lhs, rhs); } diff --git a/src/ObjCommon/XModel/JsonXModel.h.template b/src/ObjCommon/XModel/JsonXModel.h.template index 4fed72ef5..9039a3f8c 100644 --- a/src/ObjCommon/XModel/JsonXModel.h.template +++ b/src/ObjCommon/XModel/JsonXModel.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/XModel/JsonXModel" + GAME + ".h" @@ -16,6 +16,8 @@ #define FEATURE_T5 #elif GAME == "T6" #define FEATURE_T6 +#elif GAME == "QOS" +#define FEATURE_QOS #endif // This file was templated. @@ -63,7 +65,7 @@ namespace GAME std::optional physPreset; #if defined(FEATURE_IW4) || defined(FEATURE_IW5) std::optional physCollmap; -#elif defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) +#elif defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) || defined(FEATURE_QOS) std::optional physConstraints; #endif #if defined(FEATURE_T6) @@ -82,7 +84,7 @@ namespace GAME physPreset, #if defined(FEATURE_IW4) || defined(FEATURE_IW5) physCollmap, -#elif defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) +#elif defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) || defined(FEATURE_QOS) physConstraints, #endif #if defined(FEATURE_T6) diff --git a/src/ObjCompiling/Game/QOS/ObjCompilerQOS.cpp b/src/ObjCompiling/Game/QOS/ObjCompilerQOS.cpp new file mode 100644 index 000000000..90fcde966 --- /dev/null +++ b/src/ObjCompiling/Game/QOS/ObjCompilerQOS.cpp @@ -0,0 +1,22 @@ +#include "ObjCompilerQOS.h" + +using namespace QOS; + +void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection, + Zone& zone, + const ZoneDefinitionContext& zoneDefinition, + ISearchPath& searchPath, + IGdtQueryable& gdt, + ZoneAssetCreationStateContainer& zoneStates, + IOutputPath& outDir, + IOutputPath& cacheDir) const +{ + (void)collection; + (void)zone; + (void)zoneDefinition; + (void)searchPath; + (void)gdt; + (void)zoneStates; + (void)outDir; + (void)cacheDir; +} diff --git a/src/ObjCompiling/Game/QOS/ObjCompilerQOS.h b/src/ObjCompiling/Game/QOS/ObjCompilerQOS.h new file mode 100644 index 000000000..a843b421c --- /dev/null +++ b/src/ObjCompiling/Game/QOS/ObjCompilerQOS.h @@ -0,0 +1,19 @@ +#pragma once + +#include "IObjCompiler.h" + +namespace QOS +{ + class ObjCompiler final : public IObjCompiler + { + public: + void ConfigureCreatorCollection(AssetCreatorCollection& collection, + Zone& zone, + const ZoneDefinitionContext& zoneDefinition, + ISearchPath& searchPath, + IGdtQueryable& gdt, + ZoneAssetCreationStateContainer& zoneStates, + IOutputPath& outDir, + IOutputPath& cacheDir) const override; + }; +} // namespace QOS diff --git a/src/ObjCompiling/IObjCompiler.cpp b/src/ObjCompiling/IObjCompiler.cpp index f3632f464..9f8965869 100644 --- a/src/ObjCompiling/IObjCompiler.cpp +++ b/src/ObjCompiling/IObjCompiler.cpp @@ -3,6 +3,7 @@ #include "Game/IW3/ObjCompilerIW3.h" #include "Game/IW4/ObjCompilerIW4.h" #include "Game/IW5/ObjCompilerIW5.h" +#include "Game/QOS/ObjCompilerQOS.h" #include "Game/T4/ObjCompilerT4.h" #include "Game/T5/ObjCompilerT5.h" #include "Game/T6/ObjCompilerT6.h" @@ -15,6 +16,7 @@ const IObjCompiler* IObjCompiler::GetObjCompilerForGame(GameId game) new IW3::ObjCompiler(), new IW4::ObjCompiler(), new IW5::ObjCompiler(), + new QOS::ObjCompiler(), new T4::ObjCompiler(), new T5::ObjCompiler(), new T6::ObjCompiler(), diff --git a/src/ObjImage/Image/Dx9TextureLoader.cpp b/src/ObjImage/Image/Dx9TextureLoader.cpp index 7c57d0c5b..76446f72f 100644 --- a/src/ObjImage/Image/Dx9TextureLoader.cpp +++ b/src/ObjImage/Image/Dx9TextureLoader.cpp @@ -8,6 +8,7 @@ namespace image : m_format(oat::D3DFMT_UNKNOWN), m_type(TextureType::T_2D), m_has_mip_maps(false), + m_mip_map_order(MipMapDataOrder::LargestToSmallest), m_width(1u), m_height(1u), m_depth(1u) @@ -43,6 +44,12 @@ namespace image return *this; } + Dx9TextureLoader& Dx9TextureLoader::MipMapOrder(const MipMapDataOrder mipMapOrder) + { + m_mip_map_order = mipMapOrder; + return *this; + } + Dx9TextureLoader& Dx9TextureLoader::Width(const unsigned width) { m_width = width; @@ -90,16 +97,27 @@ namespace image texture->Allocate(); const auto mipMapCount = m_has_mip_maps ? texture->GetMipMapCount() : 1; const auto faceCount = m_type == TextureType::T_CUBE ? 6 : 1; - const void* currentDataOffset = data; + auto* currentDataOffset = static_cast(data); - for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++) + const auto copyMipLevel = [&](const int currentMipLevel) { for (auto currentFace = 0; currentFace < faceCount; currentFace++) { const auto mipSize = texture->GetSizeOfMipLevel(currentMipLevel); memcpy(texture->GetBufferForMipLevel(currentMipLevel, currentFace), currentDataOffset, mipSize); - currentDataOffset = reinterpret_cast(reinterpret_cast(currentDataOffset) + mipSize); + currentDataOffset += mipSize; } + }; + + if (m_mip_map_order == MipMapDataOrder::LargestToSmallest) + { + for (auto currentMipLevel = 0; currentMipLevel < mipMapCount; currentMipLevel++) + copyMipLevel(currentMipLevel); + } + else + { + for (auto currentMipLevel = mipMapCount - 1; currentMipLevel >= 0; currentMipLevel--) + copyMipLevel(currentMipLevel); } return texture; diff --git a/src/ObjImage/Image/Dx9TextureLoader.h b/src/ObjImage/Image/Dx9TextureLoader.h index 48ff5e5c8..316c7f0f7 100644 --- a/src/ObjImage/Image/Dx9TextureLoader.h +++ b/src/ObjImage/Image/Dx9TextureLoader.h @@ -10,11 +10,18 @@ namespace image class Dx9TextureLoader { public: + enum class MipMapDataOrder + { + LargestToSmallest, + SmallestToLargest, + }; + Dx9TextureLoader(); Dx9TextureLoader& Format(oat::D3DFORMAT format); Dx9TextureLoader& Type(TextureType textureType); Dx9TextureLoader& HasMipMaps(bool hasMipMaps); + Dx9TextureLoader& MipMapOrder(MipMapDataOrder mipMapOrder); Dx9TextureLoader& Width(unsigned width); Dx9TextureLoader& Height(unsigned height); Dx9TextureLoader& Depth(unsigned depth); @@ -27,6 +34,7 @@ namespace image oat::D3DFORMAT m_format; TextureType m_type; bool m_has_mip_maps; + MipMapDataOrder m_mip_map_order; unsigned m_width; unsigned m_height; unsigned m_depth; diff --git a/src/ObjLoading/Game/AutoSearchPaths.cpp b/src/ObjLoading/Game/AutoSearchPaths.cpp index dc5dc5c4a..08ec64518 100644 --- a/src/ObjLoading/Game/AutoSearchPaths.cpp +++ b/src/ObjLoading/Game/AutoSearchPaths.cpp @@ -4,6 +4,7 @@ #include "IW4/AutoSearchPathsIW4.h" #include "IW4/InfoString/InfoStringToStructConverter.h" #include "IW5/AutoSearchPathsIW5.h" +#include "QOS/AutoSearchPathsQOS.h" #include "T4/AutoSearchPathsT4.h" #include "T5/AutoSearchPathsT5.h" #include "T6/AutoSearchPathsT6.h" @@ -76,6 +77,7 @@ AutoSearchPaths* AutoSearchPaths::GetForGame(GameId gameId) new AutoSearchPathsIW3(), new AutoSearchPathsIW4(), new AutoSearchPathsIW5(), + new AutoSearchPathsQOS(), new AutoSearchPathsT4(), new AutoSearchPathsT5(), new AutoSearchPathsT6(), diff --git a/src/ObjLoading/Game/QOS/AutoSearchPathsQOS.cpp b/src/ObjLoading/Game/QOS/AutoSearchPathsQOS.cpp new file mode 100644 index 000000000..673b0d2d9 --- /dev/null +++ b/src/ObjLoading/Game/QOS/AutoSearchPathsQOS.cpp @@ -0,0 +1,22 @@ +#include "AutoSearchPathsQOS.h" + +const std::vector& AutoSearchPathsQOS::RecognizedZoneDirs() const +{ + static std::vector recognizedZoneDirs = { + "zone", + "zone/english", + "zone/french", + "zone/german", + "zone/italian", + "zone/spanish", + }; + return recognizedZoneDirs; +} + +const std::vector& AutoSearchPathsQOS::AdditionalSearchPaths() const +{ + static std::vector additionalSearchPaths = { + "main", + }; + return additionalSearchPaths; +} diff --git a/src/ObjLoading/Game/QOS/AutoSearchPathsQOS.h b/src/ObjLoading/Game/QOS/AutoSearchPathsQOS.h new file mode 100644 index 000000000..d35f2a76c --- /dev/null +++ b/src/ObjLoading/Game/QOS/AutoSearchPathsQOS.h @@ -0,0 +1,10 @@ +#pragma once + +#include "Game/AutoSearchPaths.h" + +class AutoSearchPathsQOS final : public AutoSearchPaths +{ +protected: + [[nodiscard]] const std::vector& RecognizedZoneDirs() const override; + [[nodiscard]] const std::vector& AdditionalSearchPaths() const override; +}; diff --git a/src/ObjLoading/Game/QOS/Localize/AssetLoaderLocalizeQOS.cpp b/src/ObjLoading/Game/QOS/Localize/AssetLoaderLocalizeQOS.cpp new file mode 100644 index 000000000..1e3b942b1 --- /dev/null +++ b/src/ObjLoading/Game/QOS/Localize/AssetLoaderLocalizeQOS.cpp @@ -0,0 +1,44 @@ +#include "AssetLoaderLocalizeQOS.h" + +#include "Localize/CommonLocalizeLoader.h" + +using namespace QOS; + +namespace +{ + class LocalizeLoader final : public AssetCreator, public CommonLocalizeLoader + { + public: + LocalizeLoader(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + : CommonLocalizeLoader(searchPath, zone), + m_memory(memory) + { + } + + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + return CreateLocalizeAsset(assetName, context); + } + + protected: + AssetCreationResult CreateAssetFromCommonAsset(const CommonLocalizeEntry& localizeEntry, AssetCreationContext& context) override + { + auto* asset = m_memory.Alloc(); + asset->name = m_memory.Dup(localizeEntry.m_key.c_str()); + asset->value = m_memory.Dup(localizeEntry.m_value.c_str()); + + return AssetCreationResult::Success(context.AddAsset(localizeEntry.m_key, asset)); + } + + private: + MemoryManager& m_memory; + }; +} // namespace + +namespace localize +{ + std::unique_ptr> CreateLoaderQOS(MemoryManager& memory, ISearchPath& searchPath, Zone& zone) + { + return std::make_unique(memory, searchPath, zone); + } +} // namespace localize diff --git a/src/ObjLoading/Game/QOS/Localize/AssetLoaderLocalizeQOS.h b/src/ObjLoading/Game/QOS/Localize/AssetLoaderLocalizeQOS.h new file mode 100644 index 000000000..afe13e9f9 --- /dev/null +++ b/src/ObjLoading/Game/QOS/Localize/AssetLoaderLocalizeQOS.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/QOS/QOS.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" +#include "Zone/Zone.h" + +#include + +namespace localize +{ + std::unique_ptr> CreateLoaderQOS(MemoryManager& memory, ISearchPath& searchPath, Zone& zone); +} // namespace localize diff --git a/src/ObjLoading/Game/QOS/ObjLoaderQOS.cpp b/src/ObjLoading/Game/QOS/ObjLoaderQOS.cpp new file mode 100644 index 000000000..3cbd9dc66 --- /dev/null +++ b/src/ObjLoading/Game/QOS/ObjLoaderQOS.cpp @@ -0,0 +1,112 @@ +#include "ObjLoaderQOS.h" + +#include "Asset/GlobalAssetPoolsLoader.h" +#include "Game/QOS/AssetMarkerQOS.h" +#include "Game/QOS/QOS.h" +#include "Localize/AssetLoaderLocalizeQOS.h" +#include "RawFile/AssetLoaderRawFileQOS.h" +#include "StringTable/AssetLoaderStringTableQOS.h" + +using namespace QOS; + +void ObjLoader::LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const +{ + (void)searchPath; + (void)zone; +} + +void ObjLoader::UnloadContainersOfZone(Zone& zone) const +{ + (void)zone; +} + +namespace +{ + void ConfigureDefaultCreators(AssetCreatorCollection& collection, Zone& zone) + { + auto& memory = zone.Memory(); + + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + collection.AddDefaultAssetCreator(std::make_unique>(memory)); + } + + void ConfigureGlobalAssetPoolsLoaders(AssetCreatorCollection& collection, Zone& zone) + { + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + collection.AddAssetCreator(std::make_unique>(zone)); + } + + void ConfigureLoaders(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath) + { + auto& memory = zone.Memory(); + + collection.AddAssetCreator(localize::CreateLoaderQOS(memory, searchPath, zone)); + collection.AddAssetCreator(raw_file::CreateLoaderQOS(memory, searchPath)); + collection.AddAssetCreator(string_table::CreateLoaderQOS(memory, searchPath)); + } +} // namespace + +void ObjLoader::ConfigureCreatorCollection(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath, IGdtQueryable& gdt) const +{ + (void)gdt; + + ConfigureDefaultCreators(collection, zone); + ConfigureLoaders(collection, zone, searchPath); + ConfigureGlobalAssetPoolsLoaders(collection, zone); +} diff --git a/src/ObjLoading/Game/QOS/ObjLoaderQOS.h b/src/ObjLoading/Game/QOS/ObjLoaderQOS.h new file mode 100644 index 000000000..2cde6a5fd --- /dev/null +++ b/src/ObjLoading/Game/QOS/ObjLoaderQOS.h @@ -0,0 +1,16 @@ +#pragma once + +#include "IObjLoader.h" +#include "SearchPath/ISearchPath.h" + +namespace QOS +{ + class ObjLoader final : public IObjLoader + { + public: + void LoadReferencedContainersForZone(ISearchPath& searchPath, Zone& zone) const override; + void UnloadContainersOfZone(Zone& zone) const override; + + void ConfigureCreatorCollection(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath, IGdtQueryable& gdt) const override; + }; +} // namespace QOS diff --git a/src/ObjLoading/Game/QOS/RawFile/AssetLoaderRawFileQOS.cpp b/src/ObjLoading/Game/QOS/RawFile/AssetLoaderRawFileQOS.cpp new file mode 100644 index 000000000..a253167fc --- /dev/null +++ b/src/ObjLoading/Game/QOS/RawFile/AssetLoaderRawFileQOS.cpp @@ -0,0 +1,51 @@ +#include "AssetLoaderRawFileQOS.h" + +#include "Game/QOS/QOS.h" + +using namespace QOS; + +namespace +{ + class RawFileLoader final : public AssetCreator + { + public: + RawFileLoader(MemoryManager& memory, ISearchPath& searchPath) + : m_memory(memory), + m_search_path(searchPath) + { + } + + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + const auto file = m_search_path.Open(assetName); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + + auto* rawFile = m_memory.Alloc(); + rawFile->name = m_memory.Dup(assetName.c_str()); + rawFile->len = static_cast(file.m_length); + + auto* fileBuffer = m_memory.Alloc(static_cast(file.m_length + 1)); + file.m_stream->read(fileBuffer, file.m_length); + if (file.m_stream->gcount() != file.m_length) + return AssetCreationResult::Failure(); + fileBuffer[rawFile->len] = '\0'; + + rawFile->buffer = fileBuffer; + + return AssetCreationResult::Success(context.AddAsset(assetName, rawFile)); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace raw_file +{ + std::unique_ptr> CreateLoaderQOS(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace raw_file diff --git a/src/ObjLoading/Game/QOS/RawFile/AssetLoaderRawFileQOS.h b/src/ObjLoading/Game/QOS/RawFile/AssetLoaderRawFileQOS.h new file mode 100644 index 000000000..707ef3903 --- /dev/null +++ b/src/ObjLoading/Game/QOS/RawFile/AssetLoaderRawFileQOS.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/QOS/QOS.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace raw_file +{ + std::unique_ptr> CreateLoaderQOS(MemoryManager& memory, ISearchPath& searchPath); +} // namespace raw_file diff --git a/src/ObjLoading/Game/QOS/StringTable/AssetLoaderStringTableQOS.cpp b/src/ObjLoading/Game/QOS/StringTable/AssetLoaderStringTableQOS.cpp new file mode 100644 index 000000000..ec9b9687f --- /dev/null +++ b/src/ObjLoading/Game/QOS/StringTable/AssetLoaderStringTableQOS.cpp @@ -0,0 +1,45 @@ +#include "AssetLoaderStringTableQOS.h" + +#include "Game/QOS/QOS.h" +#include "StringTable/StringTableLoader.h" + +using namespace QOS; + +namespace +{ + class StringTableLoader final : public AssetCreator + { + public: + StringTableLoader(MemoryManager& memory, ISearchPath& searchPath) + : m_memory(memory), + m_search_path(searchPath) + { + } + + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + const auto file = m_search_path.Open(assetName); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + + string_table::StringTableLoaderV1 loader; + auto* stringTable = loader.LoadFromStream(assetName, m_memory, *file.m_stream); + if (!stringTable) + return AssetCreationResult::Failure(); + + return AssetCreationResult::Success(context.AddAsset(assetName, stringTable)); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace string_table +{ + std::unique_ptr> CreateLoaderQOS(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace string_table diff --git a/src/ObjLoading/Game/QOS/StringTable/AssetLoaderStringTableQOS.h b/src/ObjLoading/Game/QOS/StringTable/AssetLoaderStringTableQOS.h new file mode 100644 index 000000000..439228871 --- /dev/null +++ b/src/ObjLoading/Game/QOS/StringTable/AssetLoaderStringTableQOS.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/QOS/QOS.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace string_table +{ + std::unique_ptr> CreateLoaderQOS(MemoryManager& memory, ISearchPath& searchPath); +} // namespace string_table diff --git a/src/ObjLoading/IObjLoader.cpp b/src/ObjLoading/IObjLoader.cpp index 334f707b5..80bca18a3 100644 --- a/src/ObjLoading/IObjLoader.cpp +++ b/src/ObjLoading/IObjLoader.cpp @@ -3,6 +3,7 @@ #include "Game/IW3/ObjLoaderIW3.h" #include "Game/IW4/ObjLoaderIW4.h" #include "Game/IW5/ObjLoaderIW5.h" +#include "Game/QOS/ObjLoaderQOS.h" #include "Game/T4/ObjLoaderT4.h" #include "Game/T5/ObjLoaderT5.h" #include "Game/T6/ObjLoaderT6.h" @@ -15,6 +16,7 @@ const IObjLoader* IObjLoader::GetObjLoaderForGame(GameId game) new IW3::ObjLoader(), new IW4::ObjLoader(), new IW5::ObjLoader(), + new QOS::ObjLoader(), new T4::ObjLoader(), new T5::ObjLoader(), new T6::ObjLoader(), diff --git a/src/ObjWriting/Font/FontDumper.cpp.template b/src/ObjWriting/Font/FontDumper.cpp.template index 427d3f997..e46a9b4a3 100644 --- a/src/ObjWriting/Font/FontDumper.cpp.template +++ b/src/ObjWriting/Font/FontDumper.cpp.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/Font/FontDumper" + GAME + ".cpp" @@ -15,6 +15,9 @@ #elif GAME == "T6" #define FEATURE_T6 #define GAME_LOWER "t6" +#elif GAME == "QOS" +#define FEATURE_QOS +#define GAME_LOWER "qos" #endif // This file was templated. diff --git a/src/ObjWriting/Font/FontDumper.h.template b/src/ObjWriting/Font/FontDumper.h.template index cb7bee595..99f363b5f 100644 --- a/src/ObjWriting/Font/FontDumper.h.template +++ b/src/ObjWriting/Font/FontDumper.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/Font/FontDumper" + GAME + ".h" diff --git a/src/ObjWriting/Game/QOS/Localize/LocalizeDumperQOS.cpp b/src/ObjWriting/Game/QOS/Localize/LocalizeDumperQOS.cpp new file mode 100644 index 000000000..2bd518544 --- /dev/null +++ b/src/ObjWriting/Game/QOS/Localize/LocalizeDumperQOS.cpp @@ -0,0 +1,42 @@ +#include "LocalizeDumperQOS.h" + +#include "Dumping/Localize/StringFileDumper.h" +#include "Localize/LocalizeCommon.h" +#include "Utils/Logging/Log.h" + +#include + +using namespace QOS; + +namespace localize +{ + void DumperQOS::Dump(AssetDumpingContext& context) + { + auto localizeAssets = context.m_zone.m_pools.PoolAssets(); + if (localizeAssets.empty()) + return; + + const auto language = LocalizeCommon::GetNameOfLanguage(context.m_zone.m_language); + const auto assetFile = context.OpenAssetFile(std::format("{}/localizedstrings/{}.str", language, context.m_zone.m_name)); + + if (assetFile) + { + StringFileDumper stringFileDumper(context.m_zone, *assetFile); + + stringFileDumper.SetLanguageName(language); + stringFileDumper.SetConfigFile(R"(C:/trees/cod3/cod3/bin/StringEd.cfg)"); + stringFileDumper.SetNotes(""); + + for (const auto* localizeEntry : localizeAssets) + stringFileDumper.WriteLocalizeEntry(localizeEntry->m_name, localizeEntry->Asset()->value); + + stringFileDumper.Finalize(); + } + else + { + con::error("Could not create string file for dumping localized strings of zone '{}'", context.m_zone.m_name); + } + + context.IncrementProgress(); + } +} // namespace localize diff --git a/src/ObjWriting/Game/QOS/Localize/LocalizeDumperQOS.h b/src/ObjWriting/Game/QOS/Localize/LocalizeDumperQOS.h new file mode 100644 index 000000000..152ced3c6 --- /dev/null +++ b/src/ObjWriting/Game/QOS/Localize/LocalizeDumperQOS.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/QOS/QOS.h" + +namespace localize +{ + class DumperQOS final : public AbstractSingleProgressAssetDumper + { + public: + void Dump(AssetDumpingContext& context) override; + }; +} // namespace localize diff --git a/src/ObjWriting/Game/QOS/Maps/MapEntsDumperQOS.cpp b/src/ObjWriting/Game/QOS/Maps/MapEntsDumperQOS.cpp new file mode 100644 index 000000000..6a3b04213 --- /dev/null +++ b/src/ObjWriting/Game/QOS/Maps/MapEntsDumperQOS.cpp @@ -0,0 +1,22 @@ +#include "MapEntsDumperQOS.h" + +#include "Maps/MapEntsCommon.h" + +#include + +using namespace QOS; + +namespace map_ents +{ + void DumperQOS::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/QOS/Maps/MapEntsDumperQOS.h b/src/ObjWriting/Game/QOS/Maps/MapEntsDumperQOS.h new file mode 100644 index 000000000..c5f64ff5f --- /dev/null +++ b/src/ObjWriting/Game/QOS/Maps/MapEntsDumperQOS.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/QOS/QOS.h" + +namespace map_ents +{ + class DumperQOS final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace map_ents diff --git a/src/ObjWriting/Game/QOS/ObjWriterQOS.cpp b/src/ObjWriting/Game/QOS/ObjWriterQOS.cpp new file mode 100644 index 000000000..58dae4274 --- /dev/null +++ b/src/ObjWriting/Game/QOS/ObjWriterQOS.cpp @@ -0,0 +1,22 @@ +#include "ObjWriterQOS.h" + +#include "Game/QOS/Font/FontDumperQOS.h" +#include "Game/QOS/Image/ImageDumperQOS.h" +#include "Game/QOS/XModel/XModelDumperQOS.h" +#include "Localize/LocalizeDumperQOS.h" +#include "Maps/MapEntsDumperQOS.h" +#include "RawFile/RawFileDumperQOS.h" +#include "StringTable/StringTableDumperQOS.h" + +using namespace QOS; + +void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) +{ + RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); +} diff --git a/src/ObjWriting/Game/QOS/ObjWriterQOS.h b/src/ObjWriting/Game/QOS/ObjWriterQOS.h new file mode 100644 index 000000000..c7c5c2708 --- /dev/null +++ b/src/ObjWriting/Game/QOS/ObjWriterQOS.h @@ -0,0 +1,12 @@ +#pragma once + +#include "ObjWriter.h" + +namespace QOS +{ + class ObjWriter final : public IObjWriter + { + protected: + void RegisterAssetDumpers(AssetDumpingContext& context) override; + }; +} // namespace QOS diff --git a/src/ObjWriting/Game/QOS/RawFile/RawFileDumperQOS.cpp b/src/ObjWriting/Game/QOS/RawFile/RawFileDumperQOS.cpp new file mode 100644 index 000000000..60723453b --- /dev/null +++ b/src/ObjWriting/Game/QOS/RawFile/RawFileDumperQOS.cpp @@ -0,0 +1,18 @@ +#include "RawFileDumperQOS.h" + +using namespace QOS; + +namespace raw_file +{ + void DumperQOS::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) + { + const auto* rawFile = asset.Asset(); + const auto assetFile = context.OpenAssetFile(asset.m_name); + + if (!assetFile) + return; + + auto& stream = *assetFile; + stream.write(rawFile->buffer, rawFile->len); + } +} // namespace raw_file diff --git a/src/ObjWriting/Game/QOS/RawFile/RawFileDumperQOS.h b/src/ObjWriting/Game/QOS/RawFile/RawFileDumperQOS.h new file mode 100644 index 000000000..13cceaa9c --- /dev/null +++ b/src/ObjWriting/Game/QOS/RawFile/RawFileDumperQOS.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/QOS/QOS.h" + +namespace raw_file +{ + class DumperQOS final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace raw_file diff --git a/src/ObjWriting/Game/QOS/StringTable/StringTableDumperQOS.cpp b/src/ObjWriting/Game/QOS/StringTable/StringTableDumperQOS.cpp new file mode 100644 index 000000000..567381ea2 --- /dev/null +++ b/src/ObjWriting/Game/QOS/StringTable/StringTableDumperQOS.cpp @@ -0,0 +1,29 @@ +#include "StringTableDumperQOS.h" + +#include "Csv/CsvStream.h" + +using namespace QOS; + +namespace string_table +{ + void DumperQOS::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) + { + const auto* stringTable = asset.Asset(); + const auto assetFile = context.OpenAssetFile(asset.m_name); + + if (!assetFile) + return; + + CsvOutputStream csv(*assetFile); + + for (auto row = 0; row < stringTable->rowCount; row++) + { + for (auto column = 0; column < stringTable->columnCount; column++) + { + csv.WriteColumn(stringTable->values[column + row * stringTable->columnCount]); + } + + csv.NextRow(); + } + } +} // namespace string_table diff --git a/src/ObjWriting/Game/QOS/StringTable/StringTableDumperQOS.h b/src/ObjWriting/Game/QOS/StringTable/StringTableDumperQOS.h new file mode 100644 index 000000000..e081a9270 --- /dev/null +++ b/src/ObjWriting/Game/QOS/StringTable/StringTableDumperQOS.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/QOS/QOS.h" + +namespace string_table +{ + class DumperQOS final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace string_table diff --git a/src/ObjWriting/Image/ImageDumper.cpp.template b/src/ObjWriting/Image/ImageDumper.cpp.template index bd0e86ed7..7c95bd65f 100644 --- a/src/ObjWriting/Image/ImageDumper.cpp.template +++ b/src/ObjWriting/Image/ImageDumper.cpp.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/Image/ImageDumper" + GAME + ".cpp" @@ -30,6 +30,10 @@ #define FEATURE_T6 #define DX11 #define IWI27 +#elif GAME == "QOS" +#define FEATURE_QOS +#define DX9 +#define IWI6 #endif // This file was templated. diff --git a/src/ObjWriting/Image/ImageDumper.h.template b/src/ObjWriting/Image/ImageDumper.h.template index 9755553c3..1f14f4b5c 100644 --- a/src/ObjWriting/Image/ImageDumper.h.template +++ b/src/ObjWriting/Image/ImageDumper.h.template @@ -1,4 +1,4 @@ -#options GAME(IW3, IW4, IW5, T4, T5, T6) +#options GAME(IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/Image/ImageDumper" + GAME + ".h" diff --git a/src/ObjWriting/Image/ImageToCommonConverter.cpp b/src/ObjWriting/Image/ImageToCommonConverter.cpp index 72696d9a9..2dc744897 100644 --- a/src/ObjWriting/Image/ImageToCommonConverter.cpp +++ b/src/ObjWriting/Image/ImageToCommonConverter.cpp @@ -3,6 +3,7 @@ #include "Game/IW3/Image/ImageToCommonConverterIW3.h" #include "Game/IW4/Image/ImageToCommonConverterIW4.h" #include "Game/IW5/Image/ImageToCommonConverterIW5.h" +#include "Game/QOS/Image/ImageToCommonConverterQOS.h" #include "Game/T4/Image/ImageToCommonConverterT4.h" #include "Game/T5/Image/ImageToCommonConverterT5.h" #include "Game/T6/Image/ImageToCommonConverterT6.h" @@ -17,6 +18,7 @@ namespace image new ToCommonConverterIW3(), new ToCommonConverterIW4(), new ToCommonConverterIW5(), + new ToCommonConverterQOS(), new ToCommonConverterT4(), new ToCommonConverterT5(), new ToCommonConverterT6(), diff --git a/src/ObjWriting/Image/ImageToCommonConverter.cpp.template b/src/ObjWriting/Image/ImageToCommonConverter.cpp.template index 3200ebe2d..7bd251083 100644 --- a/src/ObjWriting/Image/ImageToCommonConverter.cpp.template +++ b/src/ObjWriting/Image/ImageToCommonConverter.cpp.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/Image/ImageToCommonConverter" + GAME + ".cpp" @@ -28,6 +28,10 @@ #define FEATURE_T6 #define DX11 #define IWI27 +#elif GAME == "QOS" +#define FEATURE_QOS +#define DX9 +#define IWI6 #endif // This file was templated. @@ -82,7 +86,7 @@ namespace #endif const auto& loadDef = *image.texture.loadDef; -#if defined(FEATURE_IW3) || defined(FEATURE_T4) +#if defined(FEATURE_IW3) || defined(FEATURE_T4) || defined(FEATURE_QOS) textureLoader.Width(loadDef.dimensions[0]).Height(loadDef.dimensions[1]).Depth(loadDef.dimensions[2]); #else textureLoader.Width(image.width).Height(image.height).Depth(image.depth); @@ -106,6 +110,10 @@ namespace #ifdef DX9 textureLoader.Format(static_cast(loadDef.format)); +#ifdef FEATURE_QOS + // The QOS executable uploads embedded load-def mip data from the smallest mip to the largest. + textureLoader.MipMapOrder(Dx9TextureLoader::MipMapDataOrder::SmallestToLargest); +#endif #else textureLoader.Format(static_cast(loadDef.format)); #endif diff --git a/src/ObjWriting/Image/ImageToCommonConverter.h.template b/src/ObjWriting/Image/ImageToCommonConverter.h.template index 2fa2de37d..1c87801b3 100644 --- a/src/ObjWriting/Image/ImageToCommonConverter.h.template +++ b/src/ObjWriting/Image/ImageToCommonConverter.h.template @@ -1,4 +1,4 @@ -#options GAME(IW3, IW4, IW5, T4, T5, T6) +#options GAME(IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/Image/ImageToCommonConverter" + GAME + ".h" diff --git a/src/ObjWriting/ObjWriter.cpp b/src/ObjWriting/ObjWriter.cpp index 8059a3654..4def0e28a 100644 --- a/src/ObjWriting/ObjWriter.cpp +++ b/src/ObjWriting/ObjWriter.cpp @@ -3,6 +3,7 @@ #include "Game/IW3/ObjWriterIW3.h" #include "Game/IW4/ObjWriterIW4.h" #include "Game/IW5/ObjWriterIW5.h" +#include "Game/QOS/ObjWriterQOS.h" #include "Game/T4/ObjWriterT4.h" #include "Game/T5/ObjWriterT5.h" #include "Game/T6/ObjWriterT6.h" @@ -45,6 +46,7 @@ IObjWriter* IObjWriter::GetObjWriterForGame(GameId game) new IW3::ObjWriter(), new IW4::ObjWriter(), new IW5::ObjWriter(), + new QOS::ObjWriter(), new T4::ObjWriter(), new T5::ObjWriter(), new T6::ObjWriter(), diff --git a/src/ObjWriting/XModel/XModelDumper.cpp.template b/src/ObjWriting/XModel/XModelDumper.cpp.template index c23043950..e3d924187 100644 --- a/src/ObjWriting/XModel/XModelDumper.cpp.template +++ b/src/ObjWriting/XModel/XModelDumper.cpp.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/XModel/XModelDumper" + GAME + ".cpp" @@ -25,6 +25,9 @@ #elif GAME == "T6" #define FEATURE_T6 #define GAME_LOWER "t6" +#elif GAME == "QOS" +#define FEATURE_QOS +#define GAME_LOWER "qos" #endif // This file was templated. @@ -334,7 +337,7 @@ namespace return false; const auto& vertList = surface.vertList[0]; -#if defined(FEATURE_IW3) || defined(FEATURE_T4) +#if defined(FEATURE_IW3) || defined(FEATURE_T4) || defined(FEATURE_QOS) // IW3 has some models that are missing 1 (a single) tri in its first lod. // It is not contained in any vert list or blend // I think this is a bug (?), so omit anyway. @@ -398,7 +401,7 @@ namespace jXModel.physCollmap = AssetName(model.physCollmap->name); #endif -#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) || defined(FEATURE_QOS) if (model.physConstraints && model.physConstraints->name) jXModel.physConstraints = AssetName(model.physConstraints->name); #endif diff --git a/src/ObjWriting/XModel/XModelDumper.h.template b/src/ObjWriting/XModel/XModelDumper.h.template index 1beb04054..35f34b987 100644 --- a/src/ObjWriting/XModel/XModelDumper.h.template +++ b/src/ObjWriting/XModel/XModelDumper.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/XModel/XModelDumper" + GAME + ".h" diff --git a/src/ObjWriting/XModel/XModelToCommonConverter.cpp b/src/ObjWriting/XModel/XModelToCommonConverter.cpp index 3475675ee..5e62b10fd 100644 --- a/src/ObjWriting/XModel/XModelToCommonConverter.cpp +++ b/src/ObjWriting/XModel/XModelToCommonConverter.cpp @@ -3,6 +3,7 @@ #include "Game/IW3/XModel/XModelToCommonConverterIW3.h" #include "Game/IW4/XModel/XModelToCommonConverterIW4.h" #include "Game/IW5/XModel/XModelToCommonConverterIW5.h" +#include "Game/QOS/XModel/XModelToCommonConverterQOS.h" #include "Game/T4/XModel/XModelToCommonConverterT4.h" #include "Game/T5/XModel/XModelToCommonConverterT5.h" #include "Game/T6/XModel/XModelToCommonConverterT6.h" @@ -17,6 +18,7 @@ namespace xmodel new ToCommonConverterIW3(), new ToCommonConverterIW4(), new ToCommonConverterIW5(), + new ToCommonConverterQOS(), new ToCommonConverterT4(), new ToCommonConverterT5(), new ToCommonConverterT6(), diff --git a/src/ObjWriting/XModel/XModelToCommonConverter.cpp.template b/src/ObjWriting/XModel/XModelToCommonConverter.cpp.template index 259960788..a666795e3 100644 --- a/src/ObjWriting/XModel/XModelToCommonConverter.cpp.template +++ b/src/ObjWriting/XModel/XModelToCommonConverter.cpp.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/XModel/XModelToCommonConverter" + GAME + ".cpp" @@ -17,6 +17,8 @@ #define FEATURE_T5 #elif GAME == "T6" #define FEATURE_T6 +#elif GAME == "QOS" +#define FEATURE_QOS #endif // This file was templated. @@ -34,6 +36,7 @@ #include #include +#include using namespace GAME; @@ -56,7 +59,7 @@ namespace { MaterialTextureDef* def = &material->textureTable[textureIndex]; -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T4) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T4) || defined(FEATURE_QOS) if (def->semantic == TS_COLOR_MAP) potentialTextureDefs.push_back(def); #else @@ -70,6 +73,30 @@ namespace if (potentialTextureDefs.size() == 1) return GetImageFromTextureDef(*potentialTextureDefs[0]); +#ifdef FEATURE_QOS + // QoS can tag helper maps like *_edge as TS_COLOR_MAP; prefer diffuse-style names when several candidates exist. + GfxImage* qosFallback = nullptr; + for (const auto* def : potentialTextureDefs) + { + auto* image = GetImageFromTextureDef(*def); + if (!image || !image->name) + continue; + + auto name = std::string_view(image->name); + while (!name.empty() && (name.front() == ',' || name.front() == '*')) + name.remove_prefix(1); + + if (name.ends_with("_c") || name.ends_with("_col") || name.ends_with("_color") || name.ends_with("_diff")) + return image; + + if (!qosFallback && !name.ends_with("_edge") && !name.ends_with("_print") && !name.ends_with("_prsz") + && name.find("_edge_") == std::string_view::npos) + qosFallback = image; + } + if (qosFallback) + return qosFallback; +#endif + for (const auto* def : potentialTextureDefs) { if (tolower(def->nameStart) == 'c' && tolower(def->nameEnd) == 'p') @@ -180,7 +207,7 @@ namespace return false; const auto& vertList = surface.vertList[0]; -#if defined(FEATURE_IW3) || defined(FEATURE_T4) +#if defined(FEATURE_IW3) || defined(FEATURE_T4) || defined(FEATURE_QOS) // IW3 has some models that are missing 1 (a single) tri in its first lod. // It is not contained in any vert list or blend // I think this is a bug (?), so omit anyway. @@ -298,9 +325,12 @@ namespace if (colorMap) xMaterial.colorMapName = AssetName(colorMap->name); +#ifndef FEATURE_QOS + // QoS normal map decoding/selection is not verified yet; exporting them makes the preview shading misleading. const auto* normalMap = GetMaterialNormalMap(material); if (normalMap) xMaterial.normalMapName = AssetName(normalMap->name); +#endif const auto* specularMap = GetMaterialSpecularMap(material); if (specularMap) @@ -346,8 +376,17 @@ namespace vertex.coordinates[1] = v.xyz.y; vertex.coordinates[2] = v.xyz.z; Common::Vec3UnpackUnitVec(v.normal, vertex.normal); +#ifdef FEATURE_QOS + vertex.color[0] = 1.0f; + vertex.color[1] = 1.0f; + vertex.color[2] = 1.0f; + vertex.color[3] = 1.0f; + vertex.uv[0] = v.texCoord.x; + vertex.uv[1] = v.texCoord.y; +#else Common::Vec4UnpackGfxColor(v.color, vertex.color); Common::Vec2UnpackTexCoords(v.texCoord, vertex.uv); +#endif out.m_vertices.emplace_back(vertex); } @@ -405,7 +444,7 @@ namespace if (surface.vertList) { -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_T4) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_T4) || defined(FEATURE_QOS) assert(!surface.deformed); #else assert((surface.flags & XSURFACE_FLAG_DEFORMED) == 0); @@ -430,7 +469,7 @@ namespace auto vertsBlendOffset = 0u; if (surface.vertInfo.vertsBlend) { -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_T4) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_T4) || defined(FEATURE_QOS) assert(surface.deformed); #else assert((surface.flags & XSURFACE_FLAG_DEFORMED) > 0); @@ -532,7 +571,7 @@ namespace auto& object = out.m_objects[surfIndex]; object.m_faces.reserve(surface.triCount); -#ifdef FEATURE_T4 +#if defined(FEATURE_T4) || defined(FEATURE_QOS) // T4 tri indices are local to the surface, while baseVertIndex does not match // the flattened common vertex buffer we build here. auto surfaceVertexOffset = 0u; diff --git a/src/ObjWriting/XModel/XModelToCommonConverter.h.template b/src/ObjWriting/XModel/XModelToCommonConverter.h.template index 1a7ef87a6..3292713e9 100644 --- a/src/ObjWriting/XModel/XModelToCommonConverter.h.template +++ b/src/ObjWriting/XModel/XModelToCommonConverter.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T4, T5, T6) +#options GAME (IW3, IW4, IW5, QOS, T4, T5, T6) #filename "Game/" + GAME + "/XModel/XModelToCommonConverter" + GAME + ".h" diff --git a/src/ZoneCode.lua b/src/ZoneCode.lua index 7a45683f5..816bb7a7f 100644 --- a/src/ZoneCode.lua +++ b/src/ZoneCode.lua @@ -110,6 +110,39 @@ ZoneCode.Assets = { "AddonMapEnts", }, + QOS = { + "PhysPreset", + "PhysConstraints", + "DestructibleDef", + "XAnimParts", + "XModel", + "Material", + "MaterialTechniqueSet", + "GfxImage", + "snd_alias_list_t", + "SndCurve", + "clipMap_t", + "ComWorld", + "GameWorldSp", + "GameWorldMp", + "MapEnts", + "GfxWorld", + "GfxLightDef", + "Font_s", + "MenuList", + "menuDef_t", + "LocalizeEntry", + "WeaponDef", + "FxEffectDef", + "FxImpactTable", + "SceneAnimation", + "Cutscene", + "CustomCamera", + "RawFile", + "StringTable", + "XmlTree", + }, + T4 = { "PhysPreset", "PhysConstraints", diff --git a/src/ZoneCode/Game/QOS/QOS.gen b/src/ZoneCode/Game/QOS/QOS.gen new file mode 100644 index 000000000..4f9d073ee --- /dev/null +++ b/src/ZoneCode/Game/QOS/QOS.gen @@ -0,0 +1 @@ +// Game: 007 Quantum of Solace (QOS) diff --git a/src/ZoneCode/Game/QOS/QOS_Commands.txt b/src/ZoneCode/Game/QOS/QOS_Commands.txt new file mode 100644 index 000000000..a45dfc8de --- /dev/null +++ b/src/ZoneCode/Game/QOS/QOS_Commands.txt @@ -0,0 +1,73 @@ +// Game: 007 Quantum of Solace (QOS) +game QOS; +wordsize 32; + +// Game Assets +asset PhysPreset AssetPhysPreset; +asset PhysConstraints AssetPhysConstraints; +asset DestructibleDef AssetDestructibleDef; +asset XAnimParts AssetXAnim; +asset XModel AssetXModel; +asset Material AssetMaterial; +asset MaterialTechniqueSet AssetTechniqueSet; +asset GfxImage AssetImage; +asset snd_alias_list_t AssetSound; +asset SndCurve AssetSndCurve; +asset clipMap_t AssetClipMapSp; +asset ComWorld AssetComWorld; +asset GameWorldSp AssetGameWorldSp; +asset GameWorldMp AssetGameWorldMp; +asset MapEnts AssetMapEnts; +asset GfxWorld AssetGfxWorld; +asset GfxLightDef AssetLightDef; +asset Font_s AssetFont; +asset MenuList AssetMenuFile; +asset menuDef_t AssetMenu; +asset LocalizeEntry AssetLocalize; +asset WeaponDef AssetWeapon; +asset FxEffectDef AssetFx; +asset FxImpactTable AssetImpactFx; +asset RawFile AssetRawFile; +asset StringTable AssetStringTable; +asset XmlTree AssetXmlTree; +asset SceneAnimation AssetSceneAnimation; +asset Cutscene AssetCutscene; +asset CustomCamera AssetCustomCamera; + +// Setup blocks +block temp XFILE_BLOCK_TEMP default; +block runtime XFILE_BLOCK_RUNTIME default; +block normal XFILE_BLOCK_VIRTUAL default; +block normal XFILE_BLOCK_LARGE; +block normal XFILE_BLOCK_PHYSICAL; + +#include "XAssets/PhysPreset.txt" +#include "XAssets/PhysConstraints.txt" +#include "XAssets/DestructibleDef.txt" +#include "XAssets/XAnimParts.txt" +#include "XAssets/XModel.txt" +#include "XAssets/Material.txt" +#include "XAssets/MaterialTechniqueSet.txt" +#include "XAssets/GfxImage.txt" +#include "XAssets/snd_alias_list_t.txt" +#include "XAssets/SndCurve.txt" +#include "XAssets/clipMap_t.txt" +#include "XAssets/ComWorld.txt" +#include "XAssets/GameWorldSp.txt" +#include "XAssets/GameWorldMp.txt" +#include "XAssets/MapEnts.txt" +#include "XAssets/GfxWorld.txt" +#include "XAssets/GfxLightDef.txt" +#include "XAssets/Font_s.txt" +#include "XAssets/MenuList.txt" +#include "XAssets/menuDef_t.txt" +#include "XAssets/LocalizeEntry.txt" +#include "XAssets/WeaponDef.txt" +#include "XAssets/FxEffectDef.txt" +#include "XAssets/FxImpactTable.txt" +#include "XAssets/RawFile.txt" +#include "XAssets/StringTable.txt" +#include "XAssets/XmlTree.txt" +#include "XAssets/SceneAnimation.txt" +#include "XAssets/Cutscene.txt" +#include "XAssets/CustomCamera.txt" diff --git a/src/ZoneCode/Game/QOS/QOS_ZoneCode.h b/src/ZoneCode/Game/QOS/QOS_ZoneCode.h new file mode 100644 index 000000000..824b34a15 --- /dev/null +++ b/src/ZoneCode/Game/QOS/QOS_ZoneCode.h @@ -0,0 +1,12 @@ +#pragma once + +// Entry point for QOS code generation + +// clang-format off: Order of includes matters here + +#include "../Common.h" +#include "../../../Common/Game/QOS/QOS_Assets.h" + +// clang-format on + +// EOF diff --git a/src/ZoneCode/Game/QOS/XAssets/ComWorld.txt b/src/ZoneCode/Game/QOS/XAssets/ComWorld.txt new file mode 100644 index 000000000..63a0888fa --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/ComWorld.txt @@ -0,0 +1,16 @@ +// ========================================= +// ComWorld +// ========================================= +use ComWorld; +set block XFILE_BLOCK_TEMP; +set string name; +set count primaryLights primaryLightCount; +set count unknownCells unknownCellCount; + +// ComPrimaryLight +use ComPrimaryLight; +set string defName; + +// ComWorldUnknownCell +use ComWorldUnknownCell; +set count data 5120; diff --git a/src/ZoneCode/Game/QOS/XAssets/CustomCamera.txt b/src/ZoneCode/Game/QOS/XAssets/CustomCamera.txt new file mode 100644 index 000000000..45b381070 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/CustomCamera.txt @@ -0,0 +1,13 @@ +// ========================================= +// CustomCamera +// ========================================= +use CustomCamera; +set block XFILE_BLOCK_TEMP; +set string name; +set count cameras cameraCount; + +// CustomCameraDef +use CustomCameraDef; +set string name; +set string unknownString0; +set string unknownString1; diff --git a/src/ZoneCode/Game/QOS/XAssets/Cutscene.txt b/src/ZoneCode/Game/QOS/XAssets/Cutscene.txt new file mode 100644 index 000000000..ca4e34226 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/Cutscene.txt @@ -0,0 +1,25 @@ +// ========================================= +// Cutscene +// ========================================= +use Cutscene; +set block XFILE_BLOCK_TEMP; +set string name; +set count entities entityCount; +set count sections sectionCount; + +// CutsceneEntityDef +use CutsceneEntityDef; +set string unknownString0; +set string unknownString1; +set scriptstring unknownScriptString0; +set count modelAttachments modelAttachmentCount; + +// CutsceneModelAttachment +use CutsceneModelAttachment; +set string unknownString0; +set string unknownString1; + +// CutsceneSectionDef +use CutsceneSectionDef; +set count entities entityCount; +set count sceneAnimations sceneAnimationCount; diff --git a/src/ZoneCode/Game/QOS/XAssets/DestructibleDef.txt b/src/ZoneCode/Game/QOS/XAssets/DestructibleDef.txt new file mode 100644 index 000000000..50144dff6 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/DestructibleDef.txt @@ -0,0 +1,25 @@ +// ========================================= +// DestructibleDef +// ========================================= +use DestructibleDef; +set block XFILE_BLOCK_TEMP; +set string name; +set count pieces numPieces; + +// DestructiblePiece +use DestructiblePiece; +set string attachBone; +set scriptstring attachBoneHash; + +// DestructibleModel +use DestructibleModel; +set string breakNotify; + +// SndAliasCustom +use SndAliasCustom; +set count name 1; +set reusable name; +set condition sound never; + +// snd_alias_list_name +set string snd_alias_list_name::soundName; diff --git a/src/ZoneCode/Game/QOS/XAssets/Font_s.txt b/src/ZoneCode/Game/QOS/XAssets/Font_s.txt new file mode 100644 index 000000000..a1d02f1ea --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/Font_s.txt @@ -0,0 +1,8 @@ +// ========================================= +// Font_s +// ========================================= +use Font_s; +set block XFILE_BLOCK_TEMP; +set string fontName; +set reusable glyphs; +set count glyphs glyphCount; diff --git a/src/ZoneCode/Game/QOS/XAssets/FxEffectDef.txt b/src/ZoneCode/Game/QOS/XAssets/FxEffectDef.txt new file mode 100644 index 000000000..883137fb7 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/FxEffectDef.txt @@ -0,0 +1,43 @@ +// ========================================= +// FxEffectDef +// ========================================= +use FxEffectDef; +set block XFILE_BLOCK_TEMP; +set string name; +set count elemDefs elemDefCountEmission + elemDefCountLooping + elemDefCountOneShot; + +// FxElemDef +use FxElemDef; +set count velSamples velIntervalCount + 1; +set count visSamples visStateIntervalCount + 1; + +// FxElemDefVisuals +use FxElemDefVisuals; +set condition markArray FxElemDef::elemType == FX_ELEM_TYPE_DECAL; +set count markArray FxElemDef::visualCount; +set condition array FxElemDef::visualCount > 1; +set count array FxElemDef::visualCount; + +// FxElemVisuals +use FxElemVisuals; +set condition anonymous never; +set condition model FxElemDef::elemType == FX_ELEM_TYPE_MODEL; +set condition effectDef FxElemDef::elemType == FX_ELEM_TYPE_RUNNER; +set condition soundName FxElemDef::elemType == FX_ELEM_TYPE_SOUND; +set string soundName; +set condition material FxElemDef::elemType == FX_ELEM_TYPE_SPRITE_BILLBOARD +|| FxElemDef::elemType == FX_ELEM_TYPE_SPRITE_ORIENTED +|| FxElemDef::elemType == FX_ELEM_TYPE_TAIL +|| FxElemDef::elemType == FX_ELEM_TYPE_TRAIL +|| FxElemDef::elemType == FX_ELEM_TYPE_CLOUD; + +// FxEffectDefRef +use FxEffectDefRef; +set condition handle never; +set string name; +set assetref name AssetFx; + +// FxTrailDef +use FxTrailDef; +set count verts vertCount; +set count inds indCount; diff --git a/src/ZoneCode/Game/QOS/XAssets/FxImpactTable.txt b/src/ZoneCode/Game/QOS/XAssets/FxImpactTable.txt new file mode 100644 index 000000000..cc70320b9 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/FxImpactTable.txt @@ -0,0 +1,7 @@ +// ========================================= +// FxImpactTable +// ========================================= +use FxImpactTable; +set block XFILE_BLOCK_TEMP; +set string name; +set count table 13; diff --git a/src/ZoneCode/Game/QOS/XAssets/GameWorldMp.txt b/src/ZoneCode/Game/QOS/XAssets/GameWorldMp.txt new file mode 100644 index 000000000..4fad717e2 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/GameWorldMp.txt @@ -0,0 +1,6 @@ +// ========================================= +// GameWorldMp +// ========================================= +use GameWorldMp; +set block XFILE_BLOCK_TEMP; +set string name; diff --git a/src/ZoneCode/Game/QOS/XAssets/GameWorldSp.txt b/src/ZoneCode/Game/QOS/XAssets/GameWorldSp.txt new file mode 100644 index 000000000..cf0a77a25 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/GameWorldSp.txt @@ -0,0 +1,39 @@ +// ========================================= +// GameWorldSp +// ========================================= +use GameWorldSp; +set block XFILE_BLOCK_TEMP; +set string name; + +// PathData +use PathData; +set count nodes nodeCount; +set condition basenodes never; +set count chainNodeForNode nodeCount; +set count nodeForChainNode nodeCount; +set count pathVis visBytes; +set count nodeTree nodeTreeCount; + +// pathnode_t +set condition pathnode_t::transient never; + +// pathnode_constant_t +use pathnode_constant_t; +set scriptstring targetname; +set scriptstring script_linkName; +set scriptstring script_noteworthy; +set scriptstring target; +set scriptstring animscript; +set count Links totalLinkCount; + +// pathnode_dynamic_t +set condition pathnode_dynamic_t::pOwner never; + +// pathnode_tree_t +use pathnode_tree_t; +set condition u::child axis >= 0; +set reusable u::child; + +// pathnode_tree_nodes_t +set count pathnode_tree_nodes_t::nodes nodeCount; +set reusable pathnode_tree_nodes_t::nodes; diff --git a/src/ZoneCode/Game/QOS/XAssets/GfxImage.txt b/src/ZoneCode/Game/QOS/XAssets/GfxImage.txt new file mode 100644 index 000000000..cf1acfe08 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/GfxImage.txt @@ -0,0 +1,21 @@ +// ========================================= +// GfxImage +// ========================================= +use GfxImage; +set block XFILE_BLOCK_TEMP; +set allocalign GfxImage 4; +set action OnImageLoaded(GfxImage); +set string name; +reorder: + name + texture; + +// GfxTexture +use GfxTexture; +set reusable loadDef; +set block loadDef XFILE_BLOCK_TEMP; + +// GfxImageLoadDef +use GfxImageLoadDef; +set action LoadImageData(GfxImageLoadDef, GfxImage); +set arraysize data resourceSize; diff --git a/src/ZoneCode/Game/QOS/XAssets/GfxLightDef.txt b/src/ZoneCode/Game/QOS/XAssets/GfxLightDef.txt new file mode 100644 index 000000000..198345876 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/GfxLightDef.txt @@ -0,0 +1,6 @@ +// ========================================= +// GfxLightDef +// ========================================= +use GfxLightDef; +set block XFILE_BLOCK_TEMP; +set string name; diff --git a/src/ZoneCode/Game/QOS/XAssets/GfxWorld.txt b/src/ZoneCode/Game/QOS/XAssets/GfxWorld.txt new file mode 100644 index 000000000..1b2963e95 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/GfxWorld.txt @@ -0,0 +1,194 @@ +// ========================================= +// GfxWorld +// ========================================= +use GfxWorld; +set block XFILE_BLOCK_TEMP; +set allocalign GfxWorld 4; +set string name; +set string baseName; +set reusable planes; +set count planes planeCount; +set count nodes nodeCount; +set count indices indexCount; +set count surfaces surfaceCount; +set count skyStartSurfs skySurfCount; +set string skyBoxModel; +set reusable sunLight; +set count reflectionProbes reflectionProbeCount; +set count cullGroups cullGroupCount; +set count smodelDrawInsts smodelCount; +set count smodelInsts smodelCount; +set count cells cellCount; +set count lightmaps lightmapCount; +set count models modelCount; +set count materialMemory materialMemoryCount; +set block smodelVisData0 XFILE_BLOCK_RUNTIME; +set count smodelVisData0 smodelCount; +set block smodelVisData1 XFILE_BLOCK_RUNTIME; +set count smodelVisData1 smodelCount; +set block smodelVisData2 XFILE_BLOCK_RUNTIME; +set count smodelVisData2 smodelCount; +set block smodelVisData3 XFILE_BLOCK_RUNTIME; +set count smodelVisData3 smodelCount; +set block surfaceVisData0 XFILE_BLOCK_RUNTIME; +set count surfaceVisData0 models::surfaceCount; +set block surfaceVisData1 XFILE_BLOCK_RUNTIME; +set count surfaceVisData1 models::surfaceCount; +set block surfaceVisData2 XFILE_BLOCK_RUNTIME; +set count surfaceVisData2 models::surfaceCount; +set block surfaceVisData3 XFILE_BLOCK_RUNTIME; +set count surfaceVisData3 models::surfaceCount; +set block surfaceMaterials XFILE_BLOCK_RUNTIME; +set count surfaceMaterials models::surfaceCount; +set allocalign surfaceMaterials 4; +set block surfaceCastsSunShadow XFILE_BLOCK_RUNTIME; +set count surfaceCastsSunShadow (models::surfaceCount / 32) + 1; +set block cellCasterBits XFILE_BLOCK_RUNTIME; +set count cellCasterBits cellCount * ((cellCount + 31) / 32); +set block cellHasSunLitSurfsBits XFILE_BLOCK_RUNTIME; +set count cellHasSunLitSurfsBits (cellCount * 512) + 1; +set block dynEntVisData0_0 XFILE_BLOCK_RUNTIME; +set count dynEntVisData0_0 dynEntDataSize0; +set block dynEntVisData0_1 XFILE_BLOCK_RUNTIME; +set count dynEntVisData0_1 dynEntDataSize0; +set block dynEntVisData0_2 XFILE_BLOCK_RUNTIME; +set count dynEntVisData0_2 dynEntDataSize0; +set block dynEntVisData0_3 XFILE_BLOCK_RUNTIME; +set count dynEntVisData0_3 dynEntDataSize0; +set block dynEntVisData1_0 XFILE_BLOCK_RUNTIME; +set count dynEntVisData1_0 dynEntDataSize1; +set block dynEntVisData1_1 XFILE_BLOCK_RUNTIME; +set count dynEntVisData1_1 dynEntDataSize1; +set block dynEntVisData1_2 XFILE_BLOCK_RUNTIME; +set count dynEntVisData1_2 dynEntDataSize1; +set block dynEntVisData1_3 XFILE_BLOCK_RUNTIME; +set count dynEntVisData1_3 dynEntDataSize1; +set block dynEntCellBits0 XFILE_BLOCK_RUNTIME; +set count dynEntCellBits0 (cellCount * dynEntDataSize0 / 8) + 1; +set block dynEntCellBits1 XFILE_BLOCK_RUNTIME; +set count dynEntCellBits1 (cellCount * dynEntDataSize1 / 8) + 1; +set block dynEntSortList0 XFILE_BLOCK_RUNTIME; +set count dynEntSortList0 dynEntDataSize0; +set block dynEntSortList1 XFILE_BLOCK_RUNTIME; +set count dynEntSortList1 dynEntDataSize1; +set block sceneDynModel XFILE_BLOCK_RUNTIME; +set count sceneDynModel sceneDynModelCount; +set block sceneDynBrush XFILE_BLOCK_RUNTIME; +set count sceneDynBrush sceneDynBrushCount; +set block dynEntCellRefs XFILE_BLOCK_RUNTIME; +set count dynEntCellRefs dynEntDataSize0; +set block dynEntUnknown XFILE_BLOCK_RUNTIME; +set count dynEntUnknown dynEntDataSize1; +set count sortedSurfIndex models::surfaceCount; +set block primaryLightEntityShadowVis XFILE_BLOCK_RUNTIME; +set count primaryLightEntityShadowVis (primaryLightCount - sunPrimaryLightIndex - 1) * 0x1000; +set block primaryLightDynEntShadowVis0 XFILE_BLOCK_RUNTIME; +set count primaryLightDynEntShadowVis0 dynEntDataSize0 * (primaryLightCount - sunPrimaryLightIndex - 1); +set block primaryLightDynEntShadowVis1 XFILE_BLOCK_RUNTIME; +set count primaryLightDynEntShadowVis1 dynEntDataSize1 * (primaryLightCount - sunPrimaryLightIndex - 1); +set count shadowGeom primaryLightCount; +set count lightRegion lightRegionCount; +set allocalign lightRegion 4; +reorder: + name + baseName + planes + nodes + indices + surfaces + skyStartSurfs + skyImage + skyBoxModel + sunLight + reflectionProbes + cullGroups + smodelDrawInsts + smodelInsts + cells + lightmaps + lightGrid + models + materialMemory + vd + vld + sun + outdoorImage + smodelVisData0 + smodelVisData1 + smodelVisData2 + smodelVisData3 + surfaceVisData0 + surfaceVisData1 + surfaceVisData2 + surfaceVisData3 + surfaceMaterials + surfaceCastsSunShadow + cellCasterBits + cellHasSunLitSurfsBits + dynEntVisData0_0 + dynEntVisData1_0 + dynEntVisData0_1 + dynEntVisData1_1 + dynEntVisData0_2 + dynEntVisData1_2 + dynEntVisData0_3 + dynEntVisData1_3 + dynEntCellBits0 + dynEntCellBits1 + dynEntSortList0 + dynEntSortList1 + sceneDynModel + sceneDynBrush + dynEntCellRefs + dynEntUnknown + primaryLightEntityShadowVis + primaryLightDynEntShadowVis0 + primaryLightDynEntShadowVis1 + sortedSurfIndex + shadowGeom + lightRegion + unknownMaterial; + +// GfxWorldVertexData +use GfxWorldVertexData; +set count vertices GfxWorld::vertexCount; +set condition worldVb never; + +// GfxWorldVertexLayerData +use GfxWorldVertexLayerData; +set count data GfxWorld::vertexLayerDataSize; +set condition layerVb never; + +// GfxCell +use GfxCell; +set count portals portalCount; +set count cullGroups cullGroupCount; +set count reflectionProbes reflectionProbeCount; + +// GfxAabbTree +use GfxAabbTree; +set reusable smodelIndexes; +set count smodelIndexes smodelIndexCount; +set count children childCount; + +// GfxAabbTreeChildren +use GfxAabbTreeChildren; + +// GfxPortal +use GfxPortal; +set reusable cell; +set count vertices vertexCount; + +// GfxLightGrid +use GfxLightGrid; +set count rowDataStart maxs[rowAxis] - mins[rowAxis] + 1; +set count rawRowData rawRowDataSize; +set allocalign entries 4; +set count entries entryCount; +set allocalign colors 4; +set count colors colorCount; + +// GfxShadowGeometry +use GfxShadowGeometry; +set count sortedSurfIndex surfaceCount; +set count smodelIndex smodelCount; diff --git a/src/ZoneCode/Game/QOS/XAssets/LocalizeEntry.txt b/src/ZoneCode/Game/QOS/XAssets/LocalizeEntry.txt new file mode 100644 index 000000000..ffcbbd804 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/LocalizeEntry.txt @@ -0,0 +1,7 @@ +// ========================================= +// LocalizeEntry +// ========================================= +use LocalizeEntry; +set block XFILE_BLOCK_TEMP; +set string name; +set string value; diff --git a/src/ZoneCode/Game/QOS/XAssets/MapEnts.txt b/src/ZoneCode/Game/QOS/XAssets/MapEnts.txt new file mode 100644 index 000000000..840e751c0 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/MapEnts.txt @@ -0,0 +1,7 @@ +// ========================================= +// MapEnts +// ========================================= +use MapEnts; +set block XFILE_BLOCK_TEMP; +set string name; +set count entityString numEntityChars; diff --git a/src/ZoneCode/Game/QOS/XAssets/Material.txt b/src/ZoneCode/Game/QOS/XAssets/Material.txt new file mode 100644 index 000000000..2c8ba1d6e --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/Material.txt @@ -0,0 +1,29 @@ +// ========================================= +// Material +// ========================================= +use Material; +set block XFILE_BLOCK_TEMP; +set allocalign Material 4; +set string info::name; +set reusable textureTable; +set count textureTable textureCount; +set reusable constantTable; +set block constantTable XFILE_BLOCK_VIRTUAL; +set allocalign constantTable 16; +set count constantTable constantCount; +set reusable stateBitsTable; +set count stateBitsTable stateBitsCount; + +// MaterialTextureDef +use MaterialTextureDef; +set condition u::water semantic == TS_WATER_MAP; +set reusable u::water; + +// MaterialWaterDef +use MaterialWaterDef; +set reusable water; + +// water_t +use water_t; +set count H0 N * M; +set count wTerm N * M; diff --git a/src/ZoneCode/Game/QOS/XAssets/MaterialTechniqueSet.txt b/src/ZoneCode/Game/QOS/XAssets/MaterialTechniqueSet.txt new file mode 100644 index 000000000..68430c3e0 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/MaterialTechniqueSet.txt @@ -0,0 +1,49 @@ +// ========================================= +// MaterialTechniqueSet +// ========================================= +use MaterialTechniqueSet; +set block XFILE_BLOCK_TEMP; +set string name; +set reusable techniques; + +// MaterialTechnique +use MaterialTechnique; +set string name; +set arraysize passArray passCount; +reorder: + passArray + name; + +// MaterialPass +use MaterialPass; +set count args perPrimArgCount + perObjArgCount + stableArgCount; +set reusable vertexDecl; +set reusable vertexShader; +set reusable pixelShader; + +// MaterialShaderArgument +use MaterialShaderArgument; +set condition u::literalConst type == MTL_ARG_LITERAL_VERTEX_CONST +|| type == MTL_ARG_LITERAL_PIXEL_CONST; +set reusable u::literalConst; +set condition u::codeConst type == MTL_ARG_CODE_VERTEX_CONST +|| type == MTL_ARG_CODE_PIXEL_CONST; +set condition u::codeSampler type == MTL_ARG_CODE_PIXEL_SAMPLER; +set condition u::nameHash type == MTL_ARG_MATERIAL_VERTEX_CONST +|| type == MTL_ARG_MATERIAL_PIXEL_CONST || type == MTL_ARG_MATERIAL_PIXEL_SAMPLER; + +// MaterialVertexShader +use MaterialVertexShader; +set string name; + +// GfxVertexShaderLoadDef +use GfxVertexShaderLoadDef; +set count program programSize; + +// MaterialPixelShader +use MaterialPixelShader; +set string name; + +// GfxPixelShaderLoadDef +use GfxPixelShaderLoadDef; +set count program programSize; diff --git a/src/ZoneCode/Game/QOS/XAssets/MenuList.txt b/src/ZoneCode/Game/QOS/XAssets/MenuList.txt new file mode 100644 index 000000000..2a3ddb30b --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/MenuList.txt @@ -0,0 +1,7 @@ +// ========================================= +// MenuList +// ========================================= +use MenuList; +set block XFILE_BLOCK_TEMP; +set string name; +set count menus menuCount; diff --git a/src/ZoneCode/Game/QOS/XAssets/PhysConstraints.txt b/src/ZoneCode/Game/QOS/XAssets/PhysConstraints.txt new file mode 100644 index 000000000..533a223fd --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/PhysConstraints.txt @@ -0,0 +1,11 @@ +// ========================================= +// PhysConstraints +// ========================================= +use PhysConstraints; +set block XFILE_BLOCK_TEMP; +set string name; + +// PhysConstraint +use PhysConstraint; +set string target_bone1; +set string target_bone2; diff --git a/src/ZoneCode/Game/QOS/XAssets/PhysPreset.txt b/src/ZoneCode/Game/QOS/XAssets/PhysPreset.txt new file mode 100644 index 000000000..ec6331d5b --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/PhysPreset.txt @@ -0,0 +1,7 @@ +// ========================================= +// PhysPreset +// ========================================= +use PhysPreset; +set block XFILE_BLOCK_TEMP; +set string name; +set string unknownString; diff --git a/src/ZoneCode/Game/QOS/XAssets/RawFile.txt b/src/ZoneCode/Game/QOS/XAssets/RawFile.txt new file mode 100644 index 000000000..df52b888d --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/RawFile.txt @@ -0,0 +1,7 @@ +// ========================================= +// RawFile +// ========================================= +use RawFile; +set block XFILE_BLOCK_TEMP; +set string name; +set count buffer len + 1; diff --git a/src/ZoneCode/Game/QOS/XAssets/SceneAnimation.txt b/src/ZoneCode/Game/QOS/XAssets/SceneAnimation.txt new file mode 100644 index 000000000..54b8302d6 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/SceneAnimation.txt @@ -0,0 +1,12 @@ +// ========================================= +// SceneAnimation +// ========================================= +use SceneAnimation; +set block XFILE_BLOCK_TEMP; +set string name; +set count animReferences animReferenceCount; + +// AnimReference +use AnimReference; +set string unknownString0; +set scriptstring unknownScriptString0; diff --git a/src/ZoneCode/Game/QOS/XAssets/SndCurve.txt b/src/ZoneCode/Game/QOS/XAssets/SndCurve.txt new file mode 100644 index 000000000..5b28fa632 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/SndCurve.txt @@ -0,0 +1,6 @@ +// ========================================= +// SndCurve +// ========================================= +use SndCurve; +set block XFILE_BLOCK_TEMP; +set string name; diff --git a/src/ZoneCode/Game/QOS/XAssets/StringTable.txt b/src/ZoneCode/Game/QOS/XAssets/StringTable.txt new file mode 100644 index 000000000..dda10b5fc --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/StringTable.txt @@ -0,0 +1,7 @@ +// ========================================= +// StringTable +// ========================================= +use StringTable; +set string name; +set string values; +set count values columnCount * rowCount; diff --git a/src/ZoneCode/Game/QOS/XAssets/WeaponDef.txt b/src/ZoneCode/Game/QOS/XAssets/WeaponDef.txt new file mode 100644 index 000000000..bca1eb957 --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/WeaponDef.txt @@ -0,0 +1,48 @@ +// ========================================= +// WeaponDef +// ========================================= +use WeaponDef; +set block XFILE_BLOCK_TEMP; +set string name; +set string displayName; +set string overlayName; +set string xanimNames; +set assetref xanimNames AssetXAnim; +set string modeName; +set string unknownString196; +set reusable bounceSound; +set count bounceSound 30; +set string unknownString616; +set string unknownString620; +set string unknownString652; +set string unknownString660; +set string unknownString680; +set string unknownString992; +set string unknownString1220; +set string unknownString1300; +set string unknownString1308; +set string unknownStrings1380; +set string aiVsAiAccuracyGraphName; +set string aiVsPlayerAccuracyGraphName; +set reusable aiVsAiAccuracyGraphKnots; +set count aiVsAiAccuracyGraphKnots aiVsAiAccuracyGraphKnotCount; +set reusable aiVsPlayerAccuracyGraphKnots; +set count aiVsPlayerAccuracyGraphKnots aiVsPlayerAccuracyGraphKnotCount; +set reusable originalAiVsAiAccuracyGraphKnots; +set count originalAiVsAiAccuracyGraphKnots aiVsAiAccuracyGraphKnotCount; +set reusable originalAiVsPlayerAccuracyGraphKnots; +set count originalAiVsPlayerAccuracyGraphKnots aiVsPlayerAccuracyGraphKnotCount; +set string unknownString2192; +set string unknownString2196; +set string unknownString2216; +set string unknownString2332; +set string unknownString2336; + +reorder: +... +aiVsAiAccuracyGraphName +aiVsAiAccuracyGraphKnots +originalAiVsAiAccuracyGraphKnots +aiVsPlayerAccuracyGraphName +aiVsPlayerAccuracyGraphKnots +originalAiVsPlayerAccuracyGraphKnots; diff --git a/src/ZoneCode/Game/QOS/XAssets/XAnimParts.txt b/src/ZoneCode/Game/QOS/XAssets/XAnimParts.txt new file mode 100644 index 000000000..cd6f9100f --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/XAnimParts.txt @@ -0,0 +1,70 @@ +// ========================================= +// XAnimParts +// ========================================= +use XAnimParts; +set block XFILE_BLOCK_TEMP; +set string name; +set string unknownString; +set scriptstring names; +set count names boneCount[9]; +set count notify notifyCount; +set count deltaPart 1; +set count dataByte dataByteCount; +set count dataShort dataShortCount; +set count dataInt dataIntCount; +set count randomDataShort randomDataShortCount; +set count randomDataByte randomDataByteCount; +set count randomDataInt randomDataIntCount; +set count indices::_1 indexCount; +set count indices::_2 indexCount; +set condition indices::_1 numframes < 256; +set condition indices::data never; +reorder: + name + unknownString + names + notify + deltaPart + dataByte + dataShort + dataInt + randomDataShort + randomDataByte + randomDataInt + indices; + +// XAnimNotifyInfo +set scriptstring XAnimNotifyInfo::name; + +// XAnimDeltaPart +use XAnimDeltaPart; +set count trans 1; +set count quat 1; + +// XAnimPartTrans +use XAnimPartTrans; +set condition u::frames size > 0; +set condition u::frames::indices::_1 XAnimParts::numframes < 256; +set arraysize u::frames::indices::_1 size + 1; +set arraysize u::frames::indices::_2 size + 1; +set condition u::frames::frames::_1 smallTrans; +set count u::frames::frames::_1 size + 1; +set count u::frames::frames::_2 size + 1; + +// XAnimPartTransFrames +reorder XAnimPartTransFrames: + indices + frames; + +// XAnimDeltaPartQuat +use XAnimDeltaPartQuat; +set condition u::frames size > 0; +set condition u::frames::indices::_1 XAnimParts::numframes < 256; +set arraysize u::frames::indices::_1 size + 1; +set arraysize u::frames::indices::_2 size + 1; +set count u::frames::frames size + 1; + +// XAnimDeltaPartQuatDataFrames +reorder XAnimDeltaPartQuatDataFrames: + indices + frames; diff --git a/src/ZoneCode/Game/QOS/XAssets/XModel.txt b/src/ZoneCode/Game/QOS/XAssets/XModel.txt new file mode 100644 index 000000000..c1418607d --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/XModel.txt @@ -0,0 +1,89 @@ +// ========================================= +// XModel +// ========================================= +use XModel; +set block XFILE_BLOCK_TEMP; +set string name; +set scriptstring boneNames; +set reusable boneNames; +set count boneNames numBones; +set reusable parentList; +set count parentList numBones - numRootBones; +set reusable quats; +set count quats numBones - numRootBones; +set reusable trans; +set count trans (numBones - numRootBones) * 4; +set reusable partClassification; +set count partClassification numBones; +set reusable baseMat; +set allocalign baseMat 16; +set count baseMat numBones; +set count surfs numsurfs; +set count materialHandles numsurfs; +set count collSurfs numCollSurfs; +set count boneInfo numBones; +set reusable physGeoms; +set count physGeoms 1; + +// PhysGeomList +use PhysGeomList; +set reusable geoms; +set count geoms count; + +// PhysGeomInfo +use PhysGeomInfo; +set reusable brush; +set allocalign brush 4; + +// BrushWrapper +use BrushWrapper; +set count sides numsides; +set count baseAdjacentSide totalEdgeCount; +set reusable verts; +set count verts numverts; +set reusable planes; +set count planes numsides; + +// cbrushside_t +use cbrushside_t; +set reusable plane; + +// XSurface +use XSurface; +set reusable verts0; +set allocalign verts0 16; +set count verts0 vertCount; +set condition vb0 never; +set reusable verts1; +set allocalign verts1 16; +set count verts1 vertCount; +set condition vb1 never; +set reusable vertList; +set allocalign vertList 4; +set count vertList vertListCount; +set reusable triIndices; +set count triIndices triCount; +set condition indexBuffer never; +reorder: + vertInfo + verts0 + verts1 + vertList + triIndices; + +// XSurfaceVertexInfo +use XSurfaceVertexInfo; +set reusable vertsBlend; +set count vertsBlend vertCount[0] + + 3 * vertCount[1] + + 5 * vertCount[2] + + 7 * vertCount[3]; +set reusable tensionData; +set count tensionData 12 * (vertCount[0] + + vertCount[1] + + vertCount[2] + + vertCount[3]); + +// XModelCollSurf_s +use XModelCollSurf_s; +set count collTris numCollTris; diff --git a/src/ZoneCode/Game/QOS/XAssets/XmlTree.txt b/src/ZoneCode/Game/QOS/XAssets/XmlTree.txt new file mode 100644 index 000000000..029a89d0e --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/XmlTree.txt @@ -0,0 +1,23 @@ +// ========================================= +// XmlTree +// ========================================= +use XmlTree; +set block XFILE_BLOCK_TEMP; +set string name; + +// xmlNodeList +use xmlNodeList; +set count nodes nodeCount; + +// xmlNode +use xmlNode; +set string name; + +// xmlNodeComplex +use xmlNodeComplex; +set string name; + +// xmlAttribute +use xmlAttribute; +set string name; +set string value; diff --git a/src/ZoneCode/Game/QOS/XAssets/clipMap_t.txt b/src/ZoneCode/Game/QOS/XAssets/clipMap_t.txt new file mode 100644 index 000000000..232def5ab --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/clipMap_t.txt @@ -0,0 +1,82 @@ +// ========================================= +// clipMap_t +// ========================================= +use clipMap_t; +set block XFILE_BLOCK_TEMP; +set string name; +set reusable planes; +set count planes planeCount; +set count staticModelList numStaticModels; +set count materials numMaterials; +set count brushsides numBrushSides; +set count brushEdges numBrushEdges; +set count nodes numNodes; +set count leafs numLeafs; +set count leafbrushNodes leafbrushNodesCount; +set count leafbrushes numLeafBrushes; +set count leafsurfaces numLeafSurfaces; +set count verts vertCount; +set count brushVerts numBrushVerts; +set count uinds nuinds; +set count triIndices 3 * triCount; +set count triEdgeIsWalkable ((3 * triCount + 31) / 32) * 4; +set count borders borderCount; +set count partitions partitionCount; +set count aabbTrees aabbTreeCount; +set count cmodels numSubModels; +set allocalign brushes 16; +set count brushes numBrushes; +set count visibility numClusters * clusterBytes; +set allocalign box_brush 16; +set reusable box_brush; +set count dynEntDefList[0] dynEntCount[0]; +set count dynEntDefList[1] dynEntCount[1]; +set block dynEntClientList XFILE_BLOCK_RUNTIME; +set count dynEntClientList[0] dynEntCount[0]; +set count dynEntClientList[1] dynEntCount[1]; +set block dynEntServerList XFILE_BLOCK_RUNTIME; +set count dynEntServerList[0] dynEntCount[2]; +set count dynEntServerList[1] dynEntCount[3]; +set block dynEntCollList XFILE_BLOCK_RUNTIME; +set count dynEntCollList[0] dynEntCount[0]; +set count dynEntCollList[1] dynEntCount[1]; +set count dynEntCollList[2] dynEntCount[2]; +set count dynEntCollList[3] dynEntCount[3]; +set count constraints num_constraints; +reorder: + ... + leafs + leafbrushes + leafbrushNodes + leafsurfaces; + +// cbrushside_t +set reusable cbrushside_t::plane; + +// cNode_t +set reusable cNode_t::plane; + +// cLeafBrushNode_s +use cLeafBrushNode_s; +set condition data::leaf leafBrushCount > 0; +set reusable data::leaf::brushes; +set count data::leaf::brushes leafBrushCount; + +// CollisionPartition +use CollisionPartition; +set reusable borders; + +// cbrush_t +use cbrush_t; +set reusable sides; +set reusable baseAdjacentSide; +set reusable verts; + +// DynEntityDef +use DynEntityDef; +set reusable destroyPieces; + +// XModelPieces +use XModelPieces; +set string name; +set count pieces numpieces; diff --git a/src/ZoneCode/Game/QOS/XAssets/menuDef_t.txt b/src/ZoneCode/Game/QOS/XAssets/menuDef_t.txt new file mode 100644 index 000000000..0782f5e9a --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/menuDef_t.txt @@ -0,0 +1,86 @@ +// ========================================= +// menuDef_t +// ========================================= +use menuDef_t; +set block XFILE_BLOCK_TEMP; +set string window::name; +set string font; +set string onOpen; +set string onClose; +set string onESC; +set reusable visibleExp; +set string allowedBinding; +set string soundName; +set reusable rectXExp; +set reusable rectYExp; +set count items itemCount; + +// windowDef_t +use windowDef_t; +set string name; +set string group; + +// ItemKeyHandler +set string ItemKeyHandler::action; + +// statement_s +set count statement_s::entries numEntries; + +// expressionEntry +set condition expressionEntry::data::operand type == EET_OPERAND; + +// Operand +use Operand; +set condition internals::intVal dataType == VAL_INT; +set condition internals::floatVal dataType == VAL_FLOAT; +set condition internals::string dataType == VAL_STRING; +set string internals::string; + +// itemDef_s +use itemDef_s; +set string text; +set condition parent never; +set string mouseEnterText; +set string mouseExitText; +set string mouseEnter; +set string mouseExit; +set string action; +set string onAccept; +set string onFocus; +set string leaveFocus; +set string dvar; +set string dvarTest; +set string enableDvar; +set reusable visibleExp; +set reusable textExp; +set reusable materialExp; +set reusable rectXExp; +set reusable rectYExp; +set reusable rectWExp; +set reusable rectHExp; +set reusable unknownStatement0; + +// itemDefData_t +use itemDefData_t; +set string enumDvarName; +set condition data never; +set condition listBox itemDef_s::type == ITEM_TYPE_LISTBOX; +set condition editField itemDef_s::type == ITEM_TYPE_TEXT + || itemDef_s::type == ITEM_TYPE_EDITFIELD + || itemDef_s::type == ITEM_TYPE_NUMERICFIELD + || itemDef_s::type == ITEM_TYPE_SLIDER + || itemDef_s::type == ITEM_TYPE_YESNO + || itemDef_s::type == ITEM_TYPE_BIND + || itemDef_s::type == ITEM_TYPE_VALIDFILEFIELD + || itemDef_s::type == ITEM_TYPE_DECIMALFIELD + || itemDef_s::type == ITEM_TYPE_UPREDITFIELD; +set condition multi itemDef_s::type == ITEM_TYPE_MULTI; +set condition enumDvarName itemDef_s::type == ITEM_TYPE_DVARENUM; + +// listBoxDef_s +set string listBoxDef_s::doubleClick; + +// multiDef_s +use multiDef_s; +set string dvarList; +set string dvarStr; diff --git a/src/ZoneCode/Game/QOS/XAssets/snd_alias_list_t.txt b/src/ZoneCode/Game/QOS/XAssets/snd_alias_list_t.txt new file mode 100644 index 000000000..614de2fdc --- /dev/null +++ b/src/ZoneCode/Game/QOS/XAssets/snd_alias_list_t.txt @@ -0,0 +1,34 @@ +// ========================================= +// snd_alias_list_t +// ========================================= +use snd_alias_list_t; +set block XFILE_BLOCK_TEMP; +set string name; +set reusable head; +set count head count; + +// snd_alias_t +use snd_alias_t; +set string aliasName; +set string subtitle; +set string secondaryAliasName; +set string chainAliasName; +set reusable soundFile; + +// SoundFile +use SoundFile; +set string unknownString0; +set string unknownString1; +set condition u::primeSnd type == QOS_SOUND_FILE_TYPE_PRIMED; +set reusable u::primeSnd; + +// QosMssSound +use QosMssSound; +set arraysize data dataSize; + +// QosPrimedSound +use QosPrimedSound; +set string name; +set count buffer size; +set block buffer XFILE_BLOCK_LARGE; +set allocalign buffer 2048; diff --git a/src/ZoneCommon/Game/QOS/Zone/Definition/ZoneDefWriterQOS.cpp b/src/ZoneCommon/Game/QOS/Zone/Definition/ZoneDefWriterQOS.cpp new file mode 100644 index 000000000..5b39ca145 --- /dev/null +++ b/src/ZoneCommon/Game/QOS/Zone/Definition/ZoneDefWriterQOS.cpp @@ -0,0 +1,24 @@ +#include "ZoneDefWriterQOS.h" + +#include "Game/QOS/QOS.h" + +using namespace QOS; + +void ZoneDefWriter::WriteMetaData(ZoneDefinitionOutputStream& stream, const Zone& zone) const +{ + (void)stream; + (void)zone; +} + +void ZoneDefWriter::WriteContent(ZoneDefinitionOutputStream& stream, const Zone& zone, const ZoneDefFilter& filter) const +{ + const auto* game = IGame::GetGameById(zone.m_game_id); + + for (const auto& asset : zone.m_pools) + { + if (!filter.ShouldWriteAsset(*asset)) + continue; + + stream.WriteEntry(*game->GetAssetTypeName(asset->m_type), asset->m_name); + } +} diff --git a/src/ZoneCommon/Game/QOS/Zone/Definition/ZoneDefWriterQOS.h b/src/ZoneCommon/Game/QOS/Zone/Definition/ZoneDefWriterQOS.h new file mode 100644 index 000000000..9d2506f79 --- /dev/null +++ b/src/ZoneCommon/Game/QOS/Zone/Definition/ZoneDefWriterQOS.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Zone/Definition/ZoneDefWriter.h" + +namespace QOS +{ + class ZoneDefWriter final : public AbstractZoneDefWriter + { + protected: + void WriteMetaData(ZoneDefinitionOutputStream& stream, const Zone& zone) const override; + void WriteContent(ZoneDefinitionOutputStream& stream, const Zone& zone, const ZoneDefFilter& filter) const override; + }; +} // namespace QOS diff --git a/src/ZoneCommon/Game/QOS/ZoneConstantsQOS.h b/src/ZoneCommon/Game/QOS/ZoneConstantsQOS.h new file mode 100644 index 000000000..59d6dd342 --- /dev/null +++ b/src/ZoneCommon/Game/QOS/ZoneConstantsQOS.h @@ -0,0 +1,22 @@ +#pragma once +#include "Game/QOS/QOS.h" +#include "Zone/ZoneTypes.h" + +#include +#include + +namespace QOS +{ + class ZoneConstants final + { + ZoneConstants() = default; + + public: + static constexpr int ZONE_VERSION_PC = 470; + static constexpr size_t FILE_HEADER_SIZE = 28; + static constexpr size_t AUTHED_CHUNK_SIZE = 0x20000; + + static constexpr unsigned OFFSET_BLOCK_BIT_COUNT = 3u; + static constexpr block_t INSERT_BLOCK = XFILE_BLOCK_VIRTUAL; + }; +} // namespace QOS diff --git a/src/ZoneCommon/Pool/GlobalAssetPool.cpp b/src/ZoneCommon/Pool/GlobalAssetPool.cpp index a7a0027d1..d9aed036e 100644 --- a/src/ZoneCommon/Pool/GlobalAssetPool.cpp +++ b/src/ZoneCommon/Pool/GlobalAssetPool.cpp @@ -200,6 +200,7 @@ GameGlobalAssetPools* GameGlobalAssetPools::GetGlobalPoolsForGame(GameId gameId) new GameGlobalAssetPools(GameId::IW3), new GameGlobalAssetPools(GameId::IW4), new GameGlobalAssetPools(GameId::IW5), + new GameGlobalAssetPools(GameId::QOS), new GameGlobalAssetPools(GameId::T4), new GameGlobalAssetPools(GameId::T5), new GameGlobalAssetPools(GameId::T6), diff --git a/src/ZoneCommon/Zone/Definition/ZoneDefWriter.cpp b/src/ZoneCommon/Zone/Definition/ZoneDefWriter.cpp index 7c164ca88..5be21be38 100644 --- a/src/ZoneCommon/Zone/Definition/ZoneDefWriter.cpp +++ b/src/ZoneCommon/Zone/Definition/ZoneDefWriter.cpp @@ -3,6 +3,7 @@ #include "Game/IW3/Zone/Definition/ZoneDefWriterIW3.h" #include "Game/IW4/Zone/Definition/ZoneDefWriterIW4.h" #include "Game/IW5/Zone/Definition/ZoneDefWriterIW5.h" +#include "Game/QOS/Zone/Definition/ZoneDefWriterQOS.h" #include "Game/T4/Zone/Definition/ZoneDefWriterT4.h" #include "Game/T5/Zone/Definition/ZoneDefWriterT5.h" #include "Game/T6/Zone/Definition/ZoneDefWriterT6.h" @@ -48,6 +49,7 @@ const IZoneDefWriter* IZoneDefWriter::GetZoneDefWriterForGame(GameId game) new IW3::ZoneDefWriter(), new IW4::ZoneDefWriter(), new IW5::ZoneDefWriter(), + new QOS::ZoneDefWriter(), new T4::ZoneDefWriter(), new T5::ZoneDefWriter(), new T6::ZoneDefWriter(), diff --git a/src/ZoneLoading/Game/QOS/ContentLoaderQOS.cpp b/src/ZoneLoading/Game/QOS/ContentLoaderQOS.cpp new file mode 100644 index 000000000..f07af351b --- /dev/null +++ b/src/ZoneLoading/Game/QOS/ContentLoaderQOS.cpp @@ -0,0 +1,166 @@ +#include "ContentLoaderQOS.h" + +#include "Game/QOS/AssetLoaderQOS.h" +#include "Loading/Exception/UnsupportedAssetTypeException.h" + +#include + +using namespace QOS; + +ContentLoader::ContentLoader(Zone& zone, ZoneInputStream& stream) + : ContentLoaderBase(zone, stream), + varXAssetList(nullptr), + varXAsset(nullptr), + varScriptStringList(nullptr) +{ +} + +void ContentLoader::LoadScriptStringList(const bool atStreamStart) +{ + assert(!atStreamStart); + + if (varScriptStringList->strings != nullptr) + { + assert(GetZonePointerType(varScriptStringList->strings) == ZonePointerType::FOLLOWING); + +#ifdef ARCH_x86 + varScriptStringList->strings = m_stream.Alloc(4); +#else + varScriptStringList->strings = m_stream.AllocOutOfBlock(4, varScriptStringList->count); +#endif + varXString = varScriptStringList->strings; + LoadXStringArray(true, varScriptStringList->count); + + if (varScriptStringList->strings && varScriptStringList->count > 0) + m_zone.m_script_strings.InitializeForExistingZone(varScriptStringList->strings, static_cast(varScriptStringList->count)); + } + + assert(m_zone.m_script_strings.Count() <= SCR_STRING_MAX + 1); +} + +void ContentLoader::LoadXAsset(const bool atStreamStart) const +{ +#define LOAD_ASSET(type_index, typeName, headerEntry) \ + case type_index: \ + { \ + Loader_##typeName loader(m_zone, m_stream); \ + loader.Load(&varXAsset->header.headerEntry); \ + break; \ + } + + assert(varXAsset != nullptr); + + if (atStreamStart) + m_stream.Load(varXAsset); + + switch (varXAsset->type) + { + LOAD_ASSET(ASSET_TYPE_PHYSPRESET, PhysPreset, physPreset) + LOAD_ASSET(ASSET_TYPE_PHYSCONSTRAINTS, PhysConstraints, physConstraints) + LOAD_ASSET(ASSET_TYPE_DESTRUCTIBLEDEF, DestructibleDef, destructibleDef) + LOAD_ASSET(ASSET_TYPE_XANIMPARTS, XAnimParts, parts) + LOAD_ASSET(ASSET_TYPE_XMODEL, XModel, model) + LOAD_ASSET(ASSET_TYPE_MATERIAL, Material, material) + LOAD_ASSET(ASSET_TYPE_TECHNIQUE_SET, MaterialTechniqueSet, techniqueSet) + LOAD_ASSET(ASSET_TYPE_IMAGE, GfxImage, image) + LOAD_ASSET(ASSET_TYPE_SOUND, snd_alias_list_t, sound) + LOAD_ASSET(ASSET_TYPE_SND_CURVE, SndCurve, sndCurve) + LOAD_ASSET(ASSET_TYPE_CLIPMAP_SP, clipMap_t, clipMap) + LOAD_ASSET(ASSET_TYPE_CLIPMAP_MP, clipMap_t, clipMap) + LOAD_ASSET(ASSET_TYPE_COMWORLD, ComWorld, comWorld) + LOAD_ASSET(ASSET_TYPE_GAMEWORLD_SP, GameWorldSp, gameWorldSp) + LOAD_ASSET(ASSET_TYPE_GAMEWORLD_MP, GameWorldMp, gameWorldMp) + LOAD_ASSET(ASSET_TYPE_MAP_ENTS, MapEnts, mapEnts) + LOAD_ASSET(ASSET_TYPE_GFXWORLD, GfxWorld, gfxWorld) + LOAD_ASSET(ASSET_TYPE_LIGHT_DEF, GfxLightDef, lightDef) + LOAD_ASSET(ASSET_TYPE_FONT, Font_s, font) + LOAD_ASSET(ASSET_TYPE_MENUFILE, MenuList, menuList) + LOAD_ASSET(ASSET_TYPE_MENU, menuDef_t, menu) + LOAD_ASSET(ASSET_TYPE_LOCALIZE_ENTRY, LocalizeEntry, localize) + LOAD_ASSET(ASSET_TYPE_WEAPON, WeaponDef, weapon) + LOAD_ASSET(ASSET_TYPE_FX, FxEffectDef, fx) + LOAD_ASSET(ASSET_TYPE_IMPACT_FX, FxImpactTable, impactFx) + LOAD_ASSET(ASSET_TYPE_RAWFILE, RawFile, rawfile) + LOAD_ASSET(ASSET_TYPE_STRINGTABLE, StringTable, stringTable) + LOAD_ASSET(ASSET_TYPE_XMLTREE, XmlTree, xmlTree) + LOAD_ASSET(ASSET_TYPE_SCENE_ANIMATION, SceneAnimation, sceneAnimation) + LOAD_ASSET(ASSET_TYPE_CUTSCENE, Cutscene, cutscene) + LOAD_ASSET(ASSET_TYPE_CUSTOM_CAMERA, CustomCamera, customCamera) + + default: + { + throw UnsupportedAssetTypeException(varXAsset->type); + } + } + +#undef LOAD_ASSET +} + +void ContentLoader::LoadXAssetArray(const bool atStreamStart, const size_t count) +{ + assert(varXAsset != nullptr); + + if (atStreamStart) + { +#ifdef ARCH_x86 + m_stream.Load(varXAsset, count); +#else + const auto fill = m_stream.LoadWithFill(8u * count); + + for (size_t index = 0; index < count; index++) + { + fill.Fill(varXAsset[index].type, 8u * index); + fill.FillPtr(varXAsset[index].header.data, 8u * index + 4u); + m_stream.AddPointerLookup(&varXAsset[index].header.data, fill.BlockBuffer(8u * index + 4u)); + } +#endif + } + + for (size_t index = 0; index < count; index++) + { + LoadXAsset(false); + varXAsset++; + +#ifdef DEBUG_OFFSETS + m_stream.DebugOffsets(index); +#endif + } +} + +void ContentLoader::Load() +{ + XAssetList assetList{}; + varXAssetList = &assetList; + +#ifdef ARCH_x86 + m_stream.LoadDataRaw(&assetList, sizeof(assetList)); +#else + const auto fillAccessor = m_stream.LoadWithFill(16u); + varScriptStringList = &varXAssetList->stringList; + fillAccessor.Fill(varScriptStringList->count, 0u); + fillAccessor.FillPtr(varScriptStringList->strings, 4u); + + fillAccessor.Fill(varXAssetList->assetCount, 8u); + fillAccessor.FillPtr(varXAssetList->assets, 12u); +#endif + + m_stream.PushBlock(XFILE_BLOCK_VIRTUAL); + + varScriptStringList = &assetList.stringList; + LoadScriptStringList(false); + + if (assetList.assets != nullptr) + { + assert(GetZonePointerType(assetList.assets) == ZonePointerType::FOLLOWING); + +#ifdef ARCH_x86 + assetList.assets = m_stream.Alloc(4); +#else + assetList.assets = m_stream.AllocOutOfBlock(4, assetList.assetCount); +#endif + varXAsset = assetList.assets; + LoadXAssetArray(true, assetList.assetCount); + } + + m_stream.PopBlock(); +} diff --git a/src/ZoneLoading/Game/QOS/ContentLoaderQOS.h b/src/ZoneLoading/Game/QOS/ContentLoaderQOS.h new file mode 100644 index 000000000..fe0206c36 --- /dev/null +++ b/src/ZoneLoading/Game/QOS/ContentLoaderQOS.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Game/QOS/QOS.h" +#include "Loading/ContentLoaderBase.h" +#include "Loading/IContentLoadingEntryPoint.h" + +namespace QOS +{ + class ContentLoader final : public ContentLoaderBase, public IContentLoadingEntryPoint + { + public: + ContentLoader(Zone& zone, ZoneInputStream& stream); + void Load() override; + + private: + void LoadScriptStringList(bool atStreamStart); + + void LoadXAsset(bool atStreamStart) const; + void LoadXAssetArray(bool atStreamStart, size_t count); + + XAssetList* varXAssetList; + XAsset* varXAsset; + ScriptStringList* varScriptStringList; + }; +} // namespace QOS diff --git a/src/ZoneLoading/Game/QOS/XAssets/gfximage/gfximage_actions.cpp b/src/ZoneLoading/Game/QOS/XAssets/gfximage/gfximage_actions.cpp new file mode 100644 index 000000000..23e67fb4a --- /dev/null +++ b/src/ZoneLoading/Game/QOS/XAssets/gfximage/gfximage_actions.cpp @@ -0,0 +1,23 @@ +#include "gfximage_actions.h" + +#include + +using namespace QOS; + +Actions_GfxImage::Actions_GfxImage(Zone& zone) + : AssetLoadingActions(zone) +{ +} + +void Actions_GfxImage::OnImageLoaded(GfxImage* image) const +{ + image->cardMemory.platform[0] = 0; +} + +void Actions_GfxImage::LoadImageData(GfxImageLoadDef* loadDef, GfxImage* image) const +{ + const size_t loadDefSize = offsetof(GfxImageLoadDef, data) + loadDef->resourceSize; + + image->texture.loadDef = static_cast(m_zone.Memory().AllocRaw(loadDefSize)); + memcpy(image->texture.loadDef, loadDef, loadDefSize); +} diff --git a/src/ZoneLoading/Game/QOS/XAssets/gfximage/gfximage_actions.h b/src/ZoneLoading/Game/QOS/XAssets/gfximage/gfximage_actions.h new file mode 100644 index 000000000..c15b861da --- /dev/null +++ b/src/ZoneLoading/Game/QOS/XAssets/gfximage/gfximage_actions.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Game/QOS/QOS.h" +#include "Loading/AssetLoadingActions.h" + +namespace QOS +{ + class Actions_GfxImage final : public AssetLoadingActions + { + public: + explicit Actions_GfxImage(Zone& zone); + + void OnImageLoaded(GfxImage* image) const; + void LoadImageData(GfxImageLoadDef* loadDef, GfxImage* image) const; + }; +} // namespace QOS diff --git a/src/ZoneLoading/Game/QOS/ZoneLoaderFactoryQOS.cpp b/src/ZoneLoading/Game/QOS/ZoneLoaderFactoryQOS.cpp new file mode 100644 index 000000000..d52ba488d --- /dev/null +++ b/src/ZoneLoading/Game/QOS/ZoneLoaderFactoryQOS.cpp @@ -0,0 +1,142 @@ +#include "ZoneLoaderFactoryQOS.h" + +#include "ContentLoaderQOS.h" +#include "Game/GameLanguage.h" +#include "Game/QOS/QOS.h" +#include "Game/QOS/ZoneConstantsQOS.h" +#include "Loading/Exception/InvalidXBlockSizeException.h" +#include "Loading/Exception/UnexpectedEndOfFileException.h" +#include "Loading/ILoadingStep.h" +#include "Loading/Processor/ProcessorInflate.h" +#include "Loading/Steps/StepAddProcessor.h" +#include "Loading/Steps/StepLoadZoneContent.h" +#include "Utils/ClassUtils.h" +#include "Utils/Endianness.h" + +#include +#include +#include + +using namespace QOS; + +namespace +{ + constexpr uint64_t MAX_XBLOCK_SIZE = 0x3C000000; // ~1GB + constexpr size_t REMAINING_FILE_HEADER_SIZE = ZoneConstants::FILE_HEADER_SIZE - sizeof(ZoneHeader); + + static_assert(REMAINING_FILE_HEADER_SIZE == sizeof(uint32_t) * 4u); + + void SetupBlock(ZoneLoader& zoneLoader) + { +#define XBLOCK_DEF(name, type) std::make_unique(STR(name), name, type) + + zoneLoader.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_TEMP, XBlockType::BLOCK_TYPE_TEMP)); + zoneLoader.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_RUNTIME, XBlockType::BLOCK_TYPE_RUNTIME)); + zoneLoader.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_VIRTUAL, XBlockType::BLOCK_TYPE_NORMAL)); + zoneLoader.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_LARGE, XBlockType::BLOCK_TYPE_NORMAL)); + zoneLoader.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_PHYSICAL, XBlockType::BLOCK_TYPE_NORMAL)); + +#undef XBLOCK_DEF + } + + uint32_t GetQosVersion(const ZoneHeader& header) + { + uint32_t version; + static_assert(sizeof(version) <= sizeof(header.m_magic)); + std::memcpy(&version, header.m_magic, sizeof(version)); + return endianness::FromLittleEndian(version); + } + + uint32_t GetFirstBlockSize(const ZoneHeader& header) + { + return endianness::FromLittleEndian(header.m_version); + } + + class StepAllocQosXBlocks final : public ILoadingStep + { + public: + explicit StepAllocQosXBlocks(const ZoneHeader& header) + : m_first_block_size(GetFirstBlockSize(header)) + { + } + + void PerformStep(ZoneLoader& zoneLoader, ILoadingStream& stream) override + { + std::array remainingBlockSizes{}; + if (stream.Load(remainingBlockSizes.data(), sizeof(remainingBlockSizes)) != sizeof(remainingBlockSizes)) + throw UnexpectedEndOfFileException(); + + std::array blockSizes{ + m_first_block_size, + endianness::FromLittleEndian(remainingBlockSizes[0]), + endianness::FromLittleEndian(remainingBlockSizes[1]), + endianness::FromLittleEndian(remainingBlockSizes[2]), + endianness::FromLittleEndian(remainingBlockSizes[3]), + }; + + uint64_t totalMemory = 0; + for (const auto blockSize : blockSizes) + totalMemory += blockSize; + + if (totalMemory > MAX_XBLOCK_SIZE) + throw InvalidXBlockSizeException(totalMemory, MAX_XBLOCK_SIZE); + + assert(zoneLoader.m_blocks.size() == blockSizes.size()); + + for (auto blockIndex = 0u; blockIndex < blockSizes.size(); blockIndex++) + zoneLoader.m_blocks[blockIndex]->Alloc(blockSizes[blockIndex]); + } + + private: + uint32_t m_first_block_size; + }; +} // namespace + +std::optional ZoneLoaderFactory::InspectZoneHeader(const ZoneHeader& header) const +{ + if (GetQosVersion(header) == ZoneConstants::ZONE_VERSION_PC) + { + return ZoneLoaderInspectionResult{ + .m_game_id = GameId::QOS, + .m_endianness = GameEndianness::LE, + .m_word_size = GameWordSize::ARCH_32, + .m_platform = GamePlatform::PC, + // There is no way to know whether unsigned zones are official. + .m_is_official = false, + .m_is_signed = false, + .m_is_encrypted = false, + }; + } + + return std::nullopt; +} + +std::unique_ptr ZoneLoaderFactory::CreateLoaderForHeader(const ZoneHeader& header, + const std::string& fileName, + std::optional> progressCallback) const +{ + const auto inspectResult = InspectZoneHeader(header); + if (!inspectResult) + return nullptr; + + auto zone = std::make_unique(fileName, 0, GameId::QOS, inspectResult->m_platform); + auto* zonePtr = zone.get(); + zone->m_language = GameLanguage::LANGUAGE_NONE; + + auto zoneLoader = std::make_unique(std::move(zone)); + SetupBlock(*zoneLoader); + zoneLoader->AddLoadingStep(std::make_unique(header)); + zoneLoader->AddLoadingStep(step::CreateStepAddProcessor(processor::CreateProcessorInflate(ZoneConstants::AUTHED_CHUNK_SIZE))); + zoneLoader->AddLoadingStep(step::CreateStepLoadZoneContent( + [zonePtr](ZoneInputStream& stream) + { + return std::make_unique(*zonePtr, stream); + }, + 32u, + ZoneConstants::OFFSET_BLOCK_BIT_COUNT, + ZoneConstants::INSERT_BLOCK, + zonePtr->Memory(), + std::move(progressCallback))); + + return zoneLoader; +} diff --git a/src/ZoneLoading/Game/QOS/ZoneLoaderFactoryQOS.h b/src/ZoneLoading/Game/QOS/ZoneLoaderFactoryQOS.h new file mode 100644 index 000000000..491f83cad --- /dev/null +++ b/src/ZoneLoading/Game/QOS/ZoneLoaderFactoryQOS.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Loading/IZoneLoaderFactory.h" + +#include + +namespace QOS +{ + class ZoneLoaderFactory final : public IZoneLoaderFactory + { + public: + [[nodiscard]] std::optional InspectZoneHeader(const ZoneHeader& header) const override; + [[nodiscard]] std::unique_ptr CreateLoaderForHeader(const ZoneHeader& header, + const std::string& fileName, + std::optional> progressCallback) const override; + }; +} // namespace QOS diff --git a/src/ZoneLoading/Loading/IZoneLoaderFactory.cpp b/src/ZoneLoading/Loading/IZoneLoaderFactory.cpp index c9636197d..5b3f34328 100644 --- a/src/ZoneLoading/Loading/IZoneLoaderFactory.cpp +++ b/src/ZoneLoading/Loading/IZoneLoaderFactory.cpp @@ -3,6 +3,7 @@ #include "Game/IW3/ZoneLoaderFactoryIW3.h" #include "Game/IW4/ZoneLoaderFactoryIW4.h" #include "Game/IW5/ZoneLoaderFactoryIW5.h" +#include "Game/QOS/ZoneLoaderFactoryQOS.h" #include "Game/T4/ZoneLoaderFactoryT4.h" #include "Game/T5/ZoneLoaderFactoryT5.h" #include "Game/T6/ZoneLoaderFactoryT6.h" @@ -15,6 +16,7 @@ const IZoneLoaderFactory* IZoneLoaderFactory::GetZoneLoaderFactoryForGame(GameId new IW3::ZoneLoaderFactory(), new IW4::ZoneLoaderFactory(), new IW5::ZoneLoaderFactory(), + new QOS::ZoneLoaderFactory(), new T4::ZoneLoaderFactory(), new T5::ZoneLoaderFactory(), new T6::ZoneLoaderFactory(), diff --git a/src/ZoneWriting/Game/QOS/ContentWriterQOS.cpp b/src/ZoneWriting/Game/QOS/ContentWriterQOS.cpp new file mode 100644 index 000000000..9f46a7842 --- /dev/null +++ b/src/ZoneWriting/Game/QOS/ContentWriterQOS.cpp @@ -0,0 +1,211 @@ +#include "ContentWriterQOS.h" + +#include "Game/QOS/AssetWriterQOS.h" +#include "Writing/WritingException.h" + +#include +#include + +using namespace QOS; + +ContentWriter::ContentWriter(const Zone& zone) + : ContentWriterBase(zone), + varXAssetList(nullptr), + varXAsset(nullptr), + varScriptStringList(nullptr) +{ +} + +void ContentWriter::CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const +{ + if (!m_zone.m_script_strings.Empty()) + { + assert(m_zone.m_script_strings.Count() <= SCR_STRING_MAX + 1); + xAssetList.stringList.count = static_cast(m_zone.m_script_strings.Count()); + xAssetList.stringList.strings = memory.Alloc(m_zone.m_script_strings.Count()); + + for (auto i = 0u; i < m_zone.m_script_strings.Count(); i++) + xAssetList.stringList.strings[i] = m_zone.m_script_strings.CValue(i); + } + else + { + xAssetList.stringList.count = 0; + xAssetList.stringList.strings = nullptr; + } + + const auto assetCount = m_zone.m_pools.GetTotalAssetCount(); + if (assetCount > 0) + { + xAssetList.assetCount = static_cast(assetCount); + xAssetList.assets = memory.Alloc(assetCount); + + const auto end = m_zone.m_pools.end(); + auto index = 0u; + for (auto i = m_zone.m_pools.begin(); i != end; ++i) + { + auto& asset = xAssetList.assets[index++]; + asset.type = static_cast((*i)->m_type); + asset.header.data = (*i)->m_ptr; + } + } + else + { + xAssetList.assetCount = 0; + xAssetList.assets = nullptr; + } +} + +void ContentWriter::WriteScriptStringList(const bool atStreamStart) +{ + assert(!atStreamStart); + + if (varScriptStringList->strings != nullptr) + { + m_stream->Align(4); + varXString = varScriptStringList->strings; + WriteXStringArray(true, varScriptStringList->count); + +#ifdef ARCH_x86 + static_assert(offsetof(ScriptStringList, strings) == 4u); +#endif + m_stream->MarkFollowing(varScriptStringListWritten.AtOffset(4)); + } +} + +void ContentWriter::WriteXAsset(const bool atStreamStart) +{ +#ifdef ARCH_x86 + static_assert(offsetof(XAsset, header.data) == 4u); +#endif +#define WRITE_ASSET(type_index, typeName, headerEntry) \ + case type_index: \ + { \ + Writer_##typeName writer(varXAsset->header.headerEntry, m_zone, *m_stream); \ + writer.Write(varXAsset->header.headerEntry, varXAssetWritten.AtOffset(4)); \ + break; \ + } + + assert(varXAsset != nullptr); + + if (atStreamStart) + varXAssetWritten = m_stream->Write(varXAsset); + + switch (varXAsset->type) + { + WRITE_ASSET(ASSET_TYPE_PHYSPRESET, PhysPreset, physPreset) + WRITE_ASSET(ASSET_TYPE_PHYSCONSTRAINTS, PhysConstraints, physConstraints) + WRITE_ASSET(ASSET_TYPE_DESTRUCTIBLEDEF, DestructibleDef, destructibleDef) + WRITE_ASSET(ASSET_TYPE_XANIMPARTS, XAnimParts, parts) + WRITE_ASSET(ASSET_TYPE_XMODEL, XModel, model) + WRITE_ASSET(ASSET_TYPE_MATERIAL, Material, material) + WRITE_ASSET(ASSET_TYPE_TECHNIQUE_SET, MaterialTechniqueSet, techniqueSet) + WRITE_ASSET(ASSET_TYPE_IMAGE, GfxImage, image) + WRITE_ASSET(ASSET_TYPE_SOUND, snd_alias_list_t, sound) + WRITE_ASSET(ASSET_TYPE_SND_CURVE, SndCurve, sndCurve) + WRITE_ASSET(ASSET_TYPE_CLIPMAP_SP, clipMap_t, clipMap) + WRITE_ASSET(ASSET_TYPE_COMWORLD, ComWorld, comWorld) + WRITE_ASSET(ASSET_TYPE_GAMEWORLD_SP, GameWorldSp, gameWorldSp) + WRITE_ASSET(ASSET_TYPE_GAMEWORLD_MP, GameWorldMp, gameWorldMp) + WRITE_ASSET(ASSET_TYPE_MAP_ENTS, MapEnts, mapEnts) + WRITE_ASSET(ASSET_TYPE_GFXWORLD, GfxWorld, gfxWorld) + WRITE_ASSET(ASSET_TYPE_LIGHT_DEF, GfxLightDef, lightDef) + WRITE_ASSET(ASSET_TYPE_FONT, Font_s, font) + WRITE_ASSET(ASSET_TYPE_MENUFILE, MenuList, menuList) + WRITE_ASSET(ASSET_TYPE_MENU, menuDef_t, menu) + WRITE_ASSET(ASSET_TYPE_LOCALIZE_ENTRY, LocalizeEntry, localize) + WRITE_ASSET(ASSET_TYPE_WEAPON, WeaponDef, weapon) + WRITE_ASSET(ASSET_TYPE_FX, FxEffectDef, fx) + WRITE_ASSET(ASSET_TYPE_IMPACT_FX, FxImpactTable, impactFx) + WRITE_ASSET(ASSET_TYPE_RAWFILE, RawFile, rawfile) + WRITE_ASSET(ASSET_TYPE_STRINGTABLE, StringTable, stringTable) + WRITE_ASSET(ASSET_TYPE_XMLTREE, XmlTree, xmlTree) + WRITE_ASSET(ASSET_TYPE_SCENE_ANIMATION, SceneAnimation, sceneAnimation) + WRITE_ASSET(ASSET_TYPE_CUTSCENE, Cutscene, cutscene) + WRITE_ASSET(ASSET_TYPE_CUSTOM_CAMERA, CustomCamera, customCamera) + + default: + { + throw WritingException(std::format("Unsupported asset type: {}.", static_cast(varXAsset->type))); + } + } + +#undef WRITE_ASSET +} + +void ContentWriter::WriteXAssetArray(const bool atStreamStart, const size_t count) +{ + assert(varXAsset != nullptr); + +#ifdef ARCH_x86 + static_assert(sizeof(XAsset) == 8u); +#endif + + if (atStreamStart) + { +#ifdef ARCH_x86 + varXAssetWritten = m_stream->Write(varXAsset, count); +#else + const auto fill = m_stream->WriteWithFill(8u * count); + varXAssetWritten = fill.Offset(); + + for (size_t index = 0; index < count; index++) + fill.Fill(varXAsset[index].type, 8u * index); +#endif + } + + for (size_t index = 0; index < count; index++) + { + WriteXAsset(false); + varXAsset++; + varXAssetWritten.Inc(8u); + } +} + +void ContentWriter::WriteContent(ZoneOutputStream& stream) +{ + m_stream = &stream; + + MemoryManager memory; + XAssetList assetList{}; + + CreateXAssetList(assetList, memory); + + varXAssetList = &assetList; + +#ifdef ARCH_x86 + static_assert(sizeof(XAssetList) == 16); + static_assert(offsetof(XAssetList, assetCount) == 8u); + varXAssetListWritten = m_stream->WriteDataRaw(&assetList, sizeof(assetList)); +#else + const auto fillAccessor = m_stream->WriteWithFill(16u); + varXAssetListWritten = fillAccessor.Offset(); + + varScriptStringList = &varXAssetList->stringList; + fillAccessor.Fill(varScriptStringList->count, 0u); + + fillAccessor.Fill(varXAssetList->assetCount, 8u); +#endif + + m_stream->PushBlock(XFILE_BLOCK_VIRTUAL); + +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, stringList) == 0u); +#endif + varScriptStringList = &varXAssetList->stringList; + varScriptStringListWritten = varXAssetListWritten.AtOffset(0); + WriteScriptStringList(false); + + if (varXAssetList->assets != nullptr) + { + m_stream->Align(4); + varXAsset = varXAssetList->assets; + WriteXAssetArray(true, varXAssetList->assetCount); + +#ifdef ARCH_x86 + static_assert(offsetof(XAssetList, assets) == 12u); +#endif + m_stream->MarkFollowing(varXAssetListWritten.AtOffset(12)); + } + + m_stream->PopBlock(); +} diff --git a/src/ZoneWriting/Game/QOS/ContentWriterQOS.h b/src/ZoneWriting/Game/QOS/ContentWriterQOS.h new file mode 100644 index 000000000..a596e4660 --- /dev/null +++ b/src/ZoneWriting/Game/QOS/ContentWriterQOS.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Game/QOS/QOS.h" +#include "Writing/ContentWriterBase.h" +#include "Writing/IContentWritingEntryPoint.h" + +namespace QOS +{ + class ContentWriter final : public ContentWriterBase, public IContentWritingEntryPoint + { + public: + explicit ContentWriter(const Zone& zone); + + void WriteContent(ZoneOutputStream& stream) override; + + private: + void CreateXAssetList(XAssetList& xAssetList, MemoryManager& memory) const; + + void WriteScriptStringList(bool atStreamStart); + + void WriteXAsset(bool atStreamStart); + void WriteXAssetArray(bool atStreamStart, size_t count); + + XAssetList* varXAssetList; + XAsset* varXAsset; + ScriptStringList* varScriptStringList; + + ZoneOutputOffset varXAssetListWritten; + ZoneOutputOffset varXAssetWritten; + ZoneOutputOffset varScriptStringListWritten; + }; +} // namespace QOS diff --git a/src/ZoneWriting/Game/QOS/ZoneWriterFactoryQOS.cpp b/src/ZoneWriting/Game/QOS/ZoneWriterFactoryQOS.cpp new file mode 100644 index 000000000..b04774dbd --- /dev/null +++ b/src/ZoneWriting/Game/QOS/ZoneWriterFactoryQOS.cpp @@ -0,0 +1,76 @@ +#include "ZoneWriterFactoryQOS.h" + +#include "ContentWriterQOS.h" +#include "Game/QOS/QOS.h" +#include "Game/QOS/ZoneConstantsQOS.h" +#include "Utils/ClassUtils.h" +#include "Writing/IWritingStep.h" +#include "Writing/Processor/OutputProcessorDeflate.h" +#include "Writing/Steps/StepAddOutputProcessor.h" +#include "Writing/Steps/StepWriteZoneContentToFile.h" +#include "Writing/Steps/StepWriteZoneContentToMemory.h" + +#include +#include +#include +#include + +using namespace QOS; + +namespace +{ + void SetupBlocks(ZoneWriter& writer) + { +#define XBLOCK_DEF(name, type) std::make_unique(STR(name), name, type) + + writer.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_TEMP, XBlockType::BLOCK_TYPE_TEMP)); + writer.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_RUNTIME, XBlockType::BLOCK_TYPE_RUNTIME)); + writer.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_VIRTUAL, XBlockType::BLOCK_TYPE_NORMAL)); + writer.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_LARGE, XBlockType::BLOCK_TYPE_NORMAL)); + writer.AddXBlock(XBLOCK_DEF(QOS::XFILE_BLOCK_PHYSICAL, XBlockType::BLOCK_TYPE_NORMAL)); + +#undef XBLOCK_DEF + } + + class StepWriteQosHeader final : public IWritingStep + { + public: + void PerformStep(ZoneWriter* zoneWriter, IWritingStream* stream) override + { + assert(zoneWriter->m_blocks.size() == QOS::MAX_XFILE_COUNT); + + ZoneHeader header{}; + + const auto version = static_cast(ZoneConstants::ZONE_VERSION_PC); + static_assert(sizeof(version) <= sizeof(header.m_magic)); + std::memcpy(header.m_magic, &version, sizeof(version)); + header.m_version = static_cast(zoneWriter->m_blocks[QOS::XFILE_BLOCK_TEMP]->m_buffer_size); + + stream->Write(&header, sizeof(header)); + + std::array remainingBlockSizes{}; + for (auto blockIndex = 1u; blockIndex < QOS::MAX_XFILE_COUNT; blockIndex++) + remainingBlockSizes[blockIndex - 1u] = static_cast(zoneWriter->m_blocks[blockIndex]->m_buffer_size); + + stream->Write(remainingBlockSizes.data(), sizeof(remainingBlockSizes)); + } + }; +} // namespace + +std::unique_ptr ZoneWriterFactory::CreateWriter(const Zone& zone) const +{ + auto writer = std::make_unique(); + + SetupBlocks(*writer); + + auto contentInMemory = std::make_unique( + std::make_unique(zone), zone, 32u, ZoneConstants::OFFSET_BLOCK_BIT_COUNT, ZoneConstants::INSERT_BLOCK); + auto* contentInMemoryPtr = contentInMemory.get(); + writer->AddWritingStep(std::move(contentInMemory)); + + writer->AddWritingStep(std::make_unique()); + writer->AddWritingStep(std::make_unique(std::make_unique(ZoneConstants::AUTHED_CHUNK_SIZE))); + writer->AddWritingStep(std::make_unique(contentInMemoryPtr)); + + return writer; +} diff --git a/src/ZoneWriting/Game/QOS/ZoneWriterFactoryQOS.h b/src/ZoneWriting/Game/QOS/ZoneWriterFactoryQOS.h new file mode 100644 index 000000000..780a75bca --- /dev/null +++ b/src/ZoneWriting/Game/QOS/ZoneWriterFactoryQOS.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Writing/IZoneWriterFactory.h" + +#include + +namespace QOS +{ + class ZoneWriterFactory final : public IZoneWriterFactory + { + public: + [[nodiscard]] std::unique_ptr CreateWriter(const Zone& zone) const override; + }; +} // namespace QOS diff --git a/src/ZoneWriting/Writing/IZoneWriterFactory.cpp b/src/ZoneWriting/Writing/IZoneWriterFactory.cpp index d01aa6135..f3cb05151 100644 --- a/src/ZoneWriting/Writing/IZoneWriterFactory.cpp +++ b/src/ZoneWriting/Writing/IZoneWriterFactory.cpp @@ -3,6 +3,7 @@ #include "Game/IW3/ZoneWriterFactoryIW3.h" #include "Game/IW4/ZoneWriterFactoryIW4.h" #include "Game/IW5/ZoneWriterFactoryIW5.h" +#include "Game/QOS/ZoneWriterFactoryQOS.h" #include "Game/T4/ZoneWriterFactoryT4.h" #include "Game/T5/ZoneWriterFactoryT5.h" #include "Game/T6/ZoneWriterFactoryT6.h" @@ -15,6 +16,7 @@ const IZoneWriterFactory* IZoneWriterFactory::GetZoneWriterFactoryForGame(GameId new IW3::ZoneWriterFactory(), new IW4::ZoneWriterFactory(), new IW5::ZoneWriterFactory(), + new QOS::ZoneWriterFactory(), new T4::ZoneWriterFactory(), new T5::ZoneWriterFactory(), new T6::ZoneWriterFactory(),