From 8554939c91058d7f55c67f2ebb25c598559a92d6 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 7 Apr 2024 14:07:53 +0200 Subject: [PATCH] chore: dump iw5 weapon anim overrides --- src/Common/Game/IW5/IW5.h | 1 + src/Common/Game/IW5/IW5_Assets.h | 27 ++++- .../Game/IW5/InfoString/WeaponFields.h | 13 ++- .../IW5/AssetDumpers/AssetDumperWeapon.cpp | 98 +++++++++++++++++-- .../Game/IW5/XAssets/WeaponCompleteDef.txt | 6 +- 5 files changed, 130 insertions(+), 15 deletions(-) diff --git a/src/Common/Game/IW5/IW5.h b/src/Common/Game/IW5/IW5.h index a3cdbf2f..33f0f237 100644 --- a/src/Common/Game/IW5/IW5.h +++ b/src/Common/Game/IW5/IW5.h @@ -116,6 +116,7 @@ namespace IW5 // Custom WFT_ANIM_NAME, WFT_ATTACHMENT, + WFT_ANIM_OVERRIDES, WFT_NUM_FIELD_TYPES, }; diff --git a/src/Common/Game/IW5/IW5_Assets.h b/src/Common/Game/IW5/IW5_Assets.h index fed67893..cfaf08f8 100644 --- a/src/Common/Game/IW5/IW5_Assets.h +++ b/src/Common/Game/IW5/IW5_Assets.h @@ -3383,7 +3383,7 @@ namespace IW5 MISSILE_GUIDANCE_COUNT }; - enum weapAnimFiles_t + enum weapAnimFiles_t : unsigned int { WEAP_ANIM_ROOT = 0x0, WEAP_ANIM_IDLE = 0x1, @@ -3428,7 +3428,7 @@ namespace IW5 WEAP_ANIM_ADS_DOWN = 0x28, WEAP_ALT_ANIM_ADJUST = 0x29, - NUM_WEAP_ANIMS + WEAP_ANIM_COUNT }; enum hitLocation_t @@ -3895,13 +3895,30 @@ namespace IW5 XModel* stowOffsetModel; }; + union WeaponAttachmentCombination + { + struct + { + // Specifies the index as a number + // since there can only be one scope + unsigned short scope : 3; + // Specifies the index as a number + // since there can only be one under barrel + unsigned short underBarrel : 2; + // Specifies all other attachments as a bit array + unsigned short other : 4; + }; + + unsigned short fields; + }; + struct AnimOverrideEntry { - unsigned short attachment1; - unsigned short attachment2; + WeaponAttachmentCombination attachment1; + WeaponAttachmentCombination attachment2; const char* overrideAnim; const char* altmodeAnim; - unsigned int animTreeType; + weapAnimFiles_t animTreeType; int animTime; int altTime; }; diff --git a/src/ObjCommon/Game/IW5/InfoString/WeaponFields.h b/src/ObjCommon/Game/IW5/InfoString/WeaponFields.h index b1e7b837..97daf1e7 100644 --- a/src/ObjCommon/Game/IW5/InfoString/WeaponFields.h +++ b/src/ObjCommon/Game/IW5/InfoString/WeaponFields.h @@ -4,7 +4,6 @@ namespace IW5 { // WeaponCompleteDef: - // TODO: animOverrides // TODO: soundOverrides // TODO: fxOverrides // TODO: reloadOverrides @@ -734,6 +733,7 @@ namespace IW5 {"missileConeSoundCrossfadeTopSize", offsetof(WeaponFullDef, weapDef.missileConeSoundCrossfadeTopSize), CSPFT_FLOAT }, {"missileConeSoundCrossfadeBottomSize", offsetof(WeaponFullDef, weapDef.missileConeSoundCrossfadeBottomSize), CSPFT_FLOAT }, {"attachments", offsetof(WeaponFullDef, scopes), WFT_ATTACHMENT }, + {"animOverrides", offsetof(WeaponFullDef, weapCompleteDef.animOverrides), WFT_ANIM_OVERRIDES }, }; inline const char* szWeapTypeNames[]{ @@ -914,4 +914,15 @@ namespace IW5 "_gravel", "_ice", "_metal", "_mud", "_paper", "_plaster", "_rock", "_sand", "_snow", "_water", "_wood", "_asphalt", "_ceramic", "_plastic", "_rubber", "_cushion", "_fruit", "_painted_metal", "_riot_shield", "_slush", }; + static_assert(std::extent_v == SURF_TYPE_COUNT); + + inline const char* weapAnimFilesNames[]{ + "root", "idle", "empty_idle", "fire", "hold_fire", "lastshot", "rechamber", "melee", + "melee_charge", "reload", "reload_empty", "reload_start", "reload_end", "raise", "first_raise", "breach_raise", + "drop", "alt_raise", "alt_drop", "quick_raise", "quick_drop", "empty_raise", "empty_drop", "sprint_in", + "sprint_loop", "sprint_out", "stunned_start", "stunned_loop", "stunned_end", "detonate", "nightvision_wear", "nightvision_remove", + "ads_fire", "ads_lastshot", "ads_rechamber", "blast_front", "blast_right", "blast_back", "blast_left", "ads_up", + "ads_down", "alt_adjust", + }; + static_assert(std::extent_v == WEAP_ANIM_COUNT); } // namespace IW5 diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp index 4733ff99..04e217b9 100644 --- a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeapon.cpp @@ -5,6 +5,7 @@ #include "Game/IW5/InfoString/WeaponFields.h" #include "Game/IW5/ObjConstantsIW5.h" +#include #include #include #include @@ -216,6 +217,10 @@ namespace IW5 FillFromAttachments(std::string(field.szName)); break; + case WFT_ANIM_OVERRIDES: + FillFromAnimOverrides(std::string(field.szName)); + break; + case WFT_NUM_FIELD_TYPES: default: assert(false); @@ -271,6 +276,87 @@ namespace IW5 m_info_string.SetValueForKey(key, ss.str()); } + [[nodiscard]] std::string GetNameForSingleWeaponAttachment(const WeaponAttachmentCombination& combination) const + { + // Only one attachment type can be set + assert(combination.scope == 0 || (combination.underBarrel == 0 && combination.other == 0)); + assert(combination.underBarrel == 0 || (combination.scope == 0 && combination.other == 0)); + assert(combination.other == 0 || (combination.scope == 0 && std::popcount(combination.other) == 1)); + + if (combination.scope > 0 && m_weapon->weapCompleteDef.scopes) + { + const auto attachment = m_weapon->weapCompleteDef.scopes[combination.scope - 1]; + if (attachment && attachment->szInternalName) + return attachment->szInternalName; + } + else if (combination.underBarrel > 0 && m_weapon->weapCompleteDef.underBarrels) + { + const auto attachment = m_weapon->weapCompleteDef.underBarrels[combination.underBarrel - 1]; + if (attachment && attachment->szInternalName) + return attachment->szInternalName; + } + else if (combination.other > 0 && m_weapon->weapCompleteDef.others) + { + const auto attachment = m_weapon->weapCompleteDef.others[std::countr_zero(combination.other)]; + if (attachment && attachment->szInternalName) + return attachment->szInternalName; + } + + return {}; + } + + void FillFromAnimOverrides(const std::string& key) + { + std::stringstream ss; + bool first = true; + + for (auto i = 0u; i < m_weapon->weapCompleteDef.numAnimOverrides; i++) + { + const auto& animOverride = m_weapon->weapCompleteDef.animOverrides[i]; + + if (!first) + ss << "\n"; + else + first = false; + + assert(animOverride.attachment1.fields); + assert(animOverride.animTreeType < WEAP_ANIM_COUNT); + + if (animOverride.attachment1.fields) + ss << GetNameForSingleWeaponAttachment(animOverride.attachment1); + else + ss << "none"; + + ss << ' '; + + if (animOverride.attachment2.fields) + ss << GetNameForSingleWeaponAttachment(animOverride.attachment2); + else + ss << "none"; + + ss << ' '; + + if (animOverride.animTreeType < WEAP_ANIM_COUNT) + ss << weapAnimFilesNames[animOverride.animTreeType] << ' '; + + if (animOverride.overrideAnim && animOverride.overrideAnim[0]) + ss << animOverride.overrideAnim; + else + ss << "none"; + + ss << ' '; + + if (animOverride.altmodeAnim && animOverride.altmodeAnim[0]) + ss << animOverride.altmodeAnim; + else + ss << "none"; + + ss << ' ' << animOverride.animTime << ' ' << animOverride.altTime; + } + + m_info_string.SetValueForKey(key, ss.str()); + } + const WeaponFullDef* m_weapon; }; } // namespace IW5 @@ -293,8 +379,8 @@ void AssetDumperWeapon::CopyToFullDef(const WeaponCompleteDef* weapon, WeaponFul if (weapon->szXAnims) { - static_assert(std::extent_v == NUM_WEAP_ANIMS); - memcpy(fullDef->szXAnims, weapon->szXAnims, sizeof(void*) * NUM_WEAP_ANIMS); + static_assert(std::extent_v == WEAP_ANIM_COUNT); + memcpy(fullDef->szXAnims, weapon->szXAnims, sizeof(void*) * WEAP_ANIM_COUNT); fullDef->weapCompleteDef.szXAnims = fullDef->szXAnims; } @@ -306,15 +392,15 @@ void AssetDumperWeapon::CopyToFullDef(const WeaponCompleteDef* weapon, WeaponFul if (fullDef->weapDef.szXAnimsRightHanded) { - static_assert(std::extent_v == NUM_WEAP_ANIMS); - memcpy(fullDef->szXAnimsRightHanded, fullDef->weapDef.szXAnimsRightHanded, sizeof(void*) * NUM_WEAP_ANIMS); + static_assert(std::extent_v == WEAP_ANIM_COUNT); + memcpy(fullDef->szXAnimsRightHanded, fullDef->weapDef.szXAnimsRightHanded, sizeof(void*) * WEAP_ANIM_COUNT); fullDef->weapDef.szXAnimsRightHanded = fullDef->szXAnimsRightHanded; } if (fullDef->weapDef.szXAnimsLeftHanded) { - static_assert(std::extent_v == NUM_WEAP_ANIMS); - memcpy(fullDef->szXAnimsLeftHanded, fullDef->weapDef.szXAnimsLeftHanded, sizeof(void*) * NUM_WEAP_ANIMS); + static_assert(std::extent_v == WEAP_ANIM_COUNT); + memcpy(fullDef->szXAnimsLeftHanded, fullDef->weapDef.szXAnimsLeftHanded, sizeof(void*) * WEAP_ANIM_COUNT); fullDef->weapDef.szXAnimsLeftHanded = fullDef->szXAnimsLeftHanded; } diff --git a/src/ZoneCode/Game/IW5/XAssets/WeaponCompleteDef.txt b/src/ZoneCode/Game/IW5/XAssets/WeaponCompleteDef.txt index b06f4966..87af2e94 100644 --- a/src/ZoneCode/Game/IW5/XAssets/WeaponCompleteDef.txt +++ b/src/ZoneCode/Game/IW5/XAssets/WeaponCompleteDef.txt @@ -19,7 +19,7 @@ set count others 4; set string szXAnims; set assetref szXAnims ASSET_TYPE_XANIMPARTS; set reusable szXAnims; -set count szXAnims NUM_WEAP_ANIMS; +set count szXAnims WEAP_ANIM_COUNT; set reusable animOverrides; set count animOverrides numAnimOverrides; set reusable soundOverrides; @@ -59,11 +59,11 @@ set count gunXModel 16; set reusable szXAnimsRightHanded; set string szXAnimsRightHanded; set assetref szXAnimsRightHanded ASSET_TYPE_XANIMPARTS; -set count szXAnimsRightHanded NUM_WEAP_ANIMS; +set count szXAnimsRightHanded WEAP_ANIM_COUNT; set reusable szXAnimsLeftHanded; set string szXAnimsLeftHanded; set assetref szXAnimsLeftHanded ASSET_TYPE_XANIMPARTS; -set count szXAnimsLeftHanded NUM_WEAP_ANIMS; +set count szXAnimsLeftHanded WEAP_ANIM_COUNT; set string szModeName; set reusable notetrackSoundMapKeys; set scriptstring notetrackSoundMapKeys;