From 9248cc323c294d300fef665dc3abd4982a3554f8 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 14 Apr 2024 12:34:18 +0200 Subject: [PATCH] feat: dump iw5 weapon attachments as json --- src/Common/Game/IW5/IW5.h | 12 + src/Common/Game/IW5/IW5_Assets.h | 2 +- .../Game/IW5/Weapon/JsonWeaponAttachment.h | 601 ++++++++++++++++++ .../AssetDumperWeaponAttachment.cpp | 22 + .../AssetDumperWeaponAttachment.h | 14 + .../IW5/Weapon/JsonWeaponAttachmentWriter.cpp | 401 ++++++++++++ .../IW5/Weapon/JsonWeaponAttachmentWriter.h | 11 + src/ObjWriting/Game/IW5/ZoneDumperIW5.cpp | 3 +- 8 files changed, 1064 insertions(+), 2 deletions(-) create mode 100644 src/ObjCommon/Game/IW5/Weapon/JsonWeaponAttachment.h create mode 100644 src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeaponAttachment.cpp create mode 100644 src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeaponAttachment.h create mode 100644 src/ObjWriting/Game/IW5/Weapon/JsonWeaponAttachmentWriter.cpp create mode 100644 src/ObjWriting/Game/IW5/Weapon/JsonWeaponAttachmentWriter.h diff --git a/src/Common/Game/IW5/IW5.h b/src/Common/Game/IW5/IW5.h index 06388124..40b98fac 100644 --- a/src/Common/Game/IW5/IW5.h +++ b/src/Common/Game/IW5/IW5.h @@ -125,4 +125,16 @@ namespace IW5 WFT_NUM_FIELD_TYPES, }; + + enum weaponAttachmentFieldType_t + { + WAFT_ATTACHMENT_TYPE = CSPFT_NUM_BASE_FIELD_TYPES, + WAFT_WEAPONTYPE, + WAFT_WEAPONCLASS, + WAFT_PENETRATE_TYPE, + WAFT_IMPACT_TYPE, + WAFT_FIRETYPE, + + WAFT_NUM_FIELD_TYPES, + }; } // namespace IW5 diff --git a/src/Common/Game/IW5/IW5_Assets.h b/src/Common/Game/IW5/IW5_Assets.h index 2ed9b192..08cc2db1 100644 --- a/src/Common/Game/IW5/IW5_Assets.h +++ b/src/Common/Game/IW5/IW5_Assets.h @@ -3219,7 +3219,7 @@ namespace IW5 XModel** worldModels; XModel** viewModels; XModel** reticleViewModels; - AttAmmoGeneral* ammogeneral; + AttAmmoGeneral* ammoGeneral; AttSight4* sight; AttReload* reload; AttAddOns* addOns; diff --git a/src/ObjCommon/Game/IW5/Weapon/JsonWeaponAttachment.h b/src/ObjCommon/Game/IW5/Weapon/JsonWeaponAttachment.h new file mode 100644 index 00000000..0c13e9a6 --- /dev/null +++ b/src/ObjCommon/Game/IW5/Weapon/JsonWeaponAttachment.h @@ -0,0 +1,601 @@ +#pragma once + +#include "Game/IW5/IW5.h" + +#include "Json/JsonCommon.h" +#include +#include +#include +#include +#include + +namespace IW5 +{ + NLOHMANN_JSON_SERIALIZE_ENUM(PenetrateType, + { + {PENETRATE_TYPE_NONE, "none" }, + {PENETRATE_TYPE_SMALL, "small" }, + {PENETRATE_TYPE_MEDIUM, "medium"}, + {PENETRATE_TYPE_LARGE, "large" }, + }); + + NLOHMANN_JSON_SERIALIZE_ENUM(ImpactType, + { + {IMPACT_TYPE_NONE, "none" }, + {IMPACT_TYPE_BULLET_SMALL, "bulletSmall" }, + {IMPACT_TYPE_BULLET_LARGE, "bulletLarge" }, + {IMPACT_TYPE_BULLET_AP, "bulletAp" }, + {IMPACT_TYPE_BULLET_EXPLODE, "bulletExplode" }, + {IMPACT_TYPE_SHOTGUN, "shotgun" }, + {IMPACT_TYPE_SHOTGUN_EXPLODE, "shotgunExplode"}, + {IMPACT_TYPE_GRENADE_BOUNCE, "grenadeBounce" }, + {IMPACT_TYPE_GRENADE_EXPLODE, "grenadeExplode"}, + {IMPACT_TYPE_ROCKET_EXPLODE, "rocketExplode" }, + {IMPACT_TYPE_PROJECTILE_DUD, "projectileDud" }, + }); + + NLOHMANN_JSON_SERIALIZE_ENUM(weapFireType_t, + { + {WEAPON_FIRETYPE_FULLAUTO, "fullauto" }, + {WEAPON_FIRETYPE_SINGLESHOT, "singleshot" }, + {WEAPON_FIRETYPE_BURSTFIRE2, "burstfire2" }, + {WEAPON_FIRETYPE_BURSTFIRE3, "burstfire3" }, + {WEAPON_FIRETYPE_BURSTFIRE4, "burstfire4" }, + {WEAPON_FIRETYPE_DOUBLEBARREL, "doublebarrel"}, + }); + + class JsonAttAmmoGeneral + { + public: + PenetrateType penetrateType; + float penetrateMultiplier; + ImpactType impactType; + weapFireType_t fireType; + std::optional tracerType; + bool rifleBullet; + bool armorPiercing; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttAmmoGeneral, penetrateType, penetrateMultiplier, impactType, fireType, tracerType, rifleBullet, armorPiercing); + + class JsonAttSight + { + public: + bool aimDownSight; + bool adsFire; + bool rechamberWhileAds; + bool noAdsWhenMagEmpty; + bool canHoldBreath; + bool canVariableZoom; + bool hideRailWithThisScope; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION( + JsonAttSight, aimDownSight, adsFire, rechamberWhileAds, noAdsWhenMagEmpty, canHoldBreath, canVariableZoom, hideRailWithThisScope); + + class JsonAttReload + { + public: + bool noPartialReload; + bool segmentedReload; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttReload, noPartialReload, segmentedReload); + + class JsonAttAddOns + { + public: + bool motionTracker; + bool silenced; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttAddOns, motionTracker, silenced); + + class JsonAttGeneral + { + public: + bool boltAction; + bool inheritsPerks; + float enemyCrosshairRange; + std::optional reticleCenter; + std::optional reticleSide; + int reticleCenterSize; + int reticleSideSize; + float moveSpeedScale; + float adsMoveSpeedScale; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttGeneral, + boltAction, + inheritsPerks, + enemyCrosshairRange, + reticleCenter, + reticleSide, + reticleCenterSize, + reticleSideSize, + moveSpeedScale, + adsMoveSpeedScale); + + class JsonAttAimAssist + { + public: + float autoAimRange; + float aimAssistRange; + float aimAssistRangeAds; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttAimAssist, autoAimRange, aimAssistRange, aimAssistRangeAds); + + class JsonAttAmmunition + { + public: + int maxAmmo; + int startAmmo; + int clipSize; + int shotCount; + int reloadAmmoAdd; + int reloadStartAdd; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttAmmunition, maxAmmo, startAmmo, clipSize, shotCount, reloadAmmoAdd, reloadStartAdd); + + class JsonAttDamage + { + public: + int damage; + int minDamage; + int meleeDamage; + float maxDamageRange; + float minDamageRange; + int playerDamage; + int minPlayerDamage; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttDamage, damage, minDamage, meleeDamage, maxDamageRange, minDamageRange, playerDamage, minPlayerDamage); + + class JsonAttLocationDamage + { + public: + float locNone; + float locHelmet; + float locHead; + float locNeck; + float locTorsoUpper; + float locTorsoLower; + float locRightArmUpper; + float locRightArmLower; + float locRightHand; + float locLeftArmUpper; + float locLeftArmLower; + float locLeftHand; + float locRightLegUpper; + float locRightLegLower; + float locRightFoot; + float locLeftLegUpper; + float locLeftLegLower; + float locLeftFoot; + float locGun; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttLocationDamage, + locNone, + locHelmet, + locHead, + locNeck, + locTorsoUpper, + locTorsoLower, + locRightArmUpper, + locRightArmLower, + locRightHand, + locLeftArmUpper, + locLeftArmLower, + locLeftHand, + locRightLegUpper, + locRightLegLower, + locRightFoot, + locLeftLegUpper, + locLeftLegLower, + locLeftFoot, + locGun); + + class JsonAttIdleSettings + { + public: + float hipIdleAmount; + float hipIdleSpeed; + float idleCrouchFactor; + float idleProneFactor; + float adsIdleLerpStartTime; + float adsIdleLerpTime; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttIdleSettings, hipIdleAmount, hipIdleSpeed, idleCrouchFactor, idleProneFactor, adsIdleLerpStartTime, adsIdleLerpTime); + + class JsonAttADSSettings + { + public: + float adsSpread; + float adsAimPitch; + float adsTransInTime; + float adsTransOutTime; + int adsReloadTransTime; + float adsCrosshairInFrac; + float adsCrosshairOutFrac; + float adsZoomFov; + float adsZoomInFrac; + float adsZoomOutFrac; + float adsBobFactor; + float adsViewBobMult; + float adsViewErrorMin; + float adsViewErrorMax; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttADSSettings, + adsSpread, + adsAimPitch, + adsTransInTime, + adsTransOutTime, + adsReloadTransTime, + adsCrosshairInFrac, + adsCrosshairOutFrac, + adsZoomFov, + adsZoomInFrac, + adsZoomOutFrac, + adsBobFactor, + adsViewBobMult, + adsViewErrorMin, + adsViewErrorMax); + + class JsonAttHipSpread + { + public: + float hipSpreadStandMin; + float hipSpreadDuckedMin; + float hipSpreadProneMin; + float hipSpreadMax; + float hipSpreadDuckedMax; + float hipSpreadProneMax; + float hipSpreadFireAdd; + float hipSpreadTurnAdd; + float hipSpreadMoveAdd; + float hipSpreadDecayRate; + float hipSpreadDuckedDecay; + float hipSpreadProneDecay; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttHipSpread, + hipSpreadStandMin, + hipSpreadDuckedMin, + hipSpreadProneMin, + hipSpreadMax, + hipSpreadDuckedMax, + hipSpreadProneMax, + hipSpreadFireAdd, + hipSpreadTurnAdd, + hipSpreadMoveAdd, + hipSpreadDecayRate, + hipSpreadDuckedDecay, + hipSpreadProneDecay); + + class JsonAttGunKick + { + public: + int hipGunKickReducedKickBullets; + float hipGunKickReducedKickPercent; + float hipGunKickPitchMin; + float hipGunKickPitchMax; + float hipGunKickYawMin; + float hipGunKickYawMax; + float hipGunKickAccel; + float hipGunKickSpeedMax; + float hipGunKickSpeedDecay; + float hipGunKickStaticDecay; + int adsGunKickReducedKickBullets; + float adsGunKickReducedKickPercent; + float adsGunKickPitchMin; + float adsGunKickPitchMax; + float adsGunKickYawMin; + float adsGunKickYawMax; + float adsGunKickAccel; + float adsGunKickSpeedMax; + float adsGunKickSpeedDecay; + float adsGunKickStaticDecay; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttGunKick, + hipGunKickReducedKickBullets, + hipGunKickReducedKickPercent, + hipGunKickPitchMin, + hipGunKickPitchMax, + hipGunKickYawMin, + hipGunKickYawMax, + hipGunKickAccel, + hipGunKickSpeedMax, + hipGunKickSpeedDecay, + hipGunKickStaticDecay, + adsGunKickReducedKickBullets, + adsGunKickReducedKickPercent, + adsGunKickPitchMin, + adsGunKickPitchMax, + adsGunKickYawMin, + adsGunKickYawMax, + adsGunKickAccel, + adsGunKickSpeedMax, + adsGunKickSpeedDecay, + adsGunKickStaticDecay); + + class JsonAttViewKick + { + public: + float hipViewKickPitchMin; + float hipViewKickPitchMax; + float hipViewKickYawMin; + float hipViewKickYawMax; + float hipViewKickCenterSpeed; + float adsViewKickPitchMin; + float adsViewKickPitchMax; + float adsViewKickYawMin; + float adsViewKickYawMax; + float adsViewKickCenterSpeed; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttViewKick, + hipViewKickPitchMin, + hipViewKickPitchMax, + hipViewKickYawMin, + hipViewKickYawMax, + hipViewKickCenterSpeed, + adsViewKickPitchMin, + adsViewKickPitchMax, + adsViewKickYawMin, + adsViewKickYawMax, + adsViewKickCenterSpeed); + + NLOHMANN_JSON_SERIALIZE_ENUM(weapOverlayReticle_t, + { + {WEAPOVERLAYRETICLE_NONE, "none" }, + {WEAPOVERLAYRETICLE_CROSSHAIR, "crosshair"}, + }); + + class JsonAttADSOverlay + { + public: + std::optional shader; + std::optional shaderLowRes; + std::optional shaderEMP; + std::optional shaderEMPLowRes; + weapOverlayReticle_t reticle; + float width; + float height; + float widthSplitscreen; + float heightSplitscreen; + bool thermalScope; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION( + JsonAttADSOverlay, shader, shaderLowRes, shaderEMP, shaderEMPLowRes, reticle, width, height, widthSplitscreen, heightSplitscreen, thermalScope); + + NLOHMANN_JSON_SERIALIZE_ENUM(weaponIconRatioType_t, + { + {WEAPON_ICON_RATIO_1TO1, "1:1"}, + {WEAPON_ICON_RATIO_2TO1, "2:1"}, + {WEAPON_ICON_RATIO_4TO1, "4:1"}, + }); + + NLOHMANN_JSON_SERIALIZE_ENUM(ammoCounterClipType_t, + { + {AMMO_COUNTER_CLIP_NONE, "none" }, + {AMMO_COUNTER_CLIP_MAGAZINE, "magazine" }, + {AMMO_COUNTER_CLIP_SHORTMAGAZINE, "shortmagazine"}, + {AMMO_COUNTER_CLIP_SHOTGUN, "shotgun" }, + {AMMO_COUNTER_CLIP_ROCKET, "rocket" }, + {AMMO_COUNTER_CLIP_BELTFED, "beltfed" }, + {AMMO_COUNTER_CLIP_ALTWEAPON, "altweapon" }, + }); + + class JsonAttUI + { + public: + std::optional dpadIcon; + std::optional ammoCounterIcon; + weaponIconRatioType_t dpadIconRatio; + weaponIconRatioType_t ammoCounterIconRatio; + ammoCounterClipType_t ammoCounterClip; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttUI, dpadIcon, ammoCounterIcon, dpadIconRatio, ammoCounterIconRatio, ammoCounterClip); + + class JsonAttRumbles + { + public: + std::optional fireRumble; + std::optional meleeImpactRumble; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttRumbles, fireRumble, meleeImpactRumble); + + NLOHMANN_JSON_SERIALIZE_ENUM(weapProjExposion_t, + { + {WEAPPROJEXP_GRENADE, "grenade" }, + {WEAPPROJEXP_ROCKET, "rocket" }, + {WEAPPROJEXP_FLASHBANG, "flashbang"}, + {WEAPPROJEXP_NONE, "none" }, + {WEAPPROJEXP_DUD, "dud" }, + {WEAPPROJEXP_SMOKE, "smoke" }, + {WEAPPROJEXP_HEAVY, "heavy" }, + }); + + class JsonAttProjectile + { + public: + int explosionRadius; + int explosionInnerDamage; + int explosionOuterDamage; + float damageConeAngle; + int projectileSpeed; + int projectileSpeedUp; + int projectileActivateDist; + float projectileLifetime; + std::optional projectileModel; + weapProjExposion_t projExplosionType; + std::optional projExplosionEffect; + bool projExplosionEffectForceNormalUp; + std::optional projExplosionSound; + std::optional projDudEffect; + std::optional projDudSound; + bool projImpactExplode; + float destabilizationRateTime; + float destabilizationCurvatureMax; + int destabilizeDistance; + std::optional projTrailEffect; + int projIgnitionDelay; + std::optional projIgnitionEffect; + std::optional projIgnitionSound; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonAttProjectile, + explosionRadius, + explosionInnerDamage, + explosionOuterDamage, + damageConeAngle, + projectileSpeed, + projectileSpeedUp, + projectileActivateDist, + projectileLifetime, + projectileModel, + projExplosionType, + projExplosionEffect, + projExplosionEffectForceNormalUp, + projExplosionSound, + projDudEffect, + projDudSound, + projImpactExplode, + destabilizationRateTime, + destabilizationCurvatureMax, + destabilizeDistance, + projTrailEffect, + projIgnitionDelay, + projIgnitionEffect, + projIgnitionSound); + + NLOHMANN_JSON_SERIALIZE_ENUM(AttachmentType, + { + {ATTACHMENT_SCOPE, "scope" }, + {ATTACHMENT_UNDERBARREL, "underbarrel"}, + {ATTACHMENT_OTHER, "other" }, + }); + + NLOHMANN_JSON_SERIALIZE_ENUM(weapType_t, + { + {WEAPTYPE_NONE, "none" }, + {WEAPTYPE_BULLET, "bullet" }, + {WEAPTYPE_GRENADE, "grenade" }, + {WEAPTYPE_PROJECTILE, "projectile"}, + {WEAPTYPE_RIOTSHIELD, "riotshield"}, + }); + + NLOHMANN_JSON_SERIALIZE_ENUM(weapClass_t, + { + {WEAPCLASS_RIFLE, "rifle" }, + {WEAPCLASS_SNIPER, "sniper" }, + {WEAPCLASS_MG, "mg" }, + {WEAPCLASS_SMG, "smg" }, + {WEAPCLASS_SPREAD, "spread" }, + {WEAPCLASS_PISTOL, "pistol" }, + {WEAPCLASS_GRENADE, "grenade" }, + {WEAPCLASS_ROCKETLAUNCHER, "rocketlauncher"}, + {WEAPCLASS_TURRET, "turret" }, + {WEAPCLASS_THROWINGKNIFE, "throwingknife" }, + {WEAPCLASS_NON_PLAYER, "nonPlayer" }, + {WEAPCLASS_ITEM, "item" }, + }); + + class JsonWeaponAttachment + { + public: + std::string displayName; + AttachmentType type; + weapType_t weaponType; + weapClass_t weapClass; + std::vector worldModels; + std::vector viewModels; + std::vector reticleViewModels; + std::optional ammoGeneral; + std::optional sight; + std::optional reload; + std::optional addOns; + std::optional general; + std::optional aimAssist; + std::optional ammunition; + std::optional damage; + std::optional locationDamage; + std::optional idleSettings; + std::optional adsSettings; + std::optional adsSettingsMain; + std::optional hipSpread; + std::optional gunKick; + std::optional viewKick; + std::optional adsOverlay; + std::optional ui; + std::optional rumbles; + std::optional projectile; + float ammunitionScale; + float damageScale; + float damageScaleMin; + float stateTimersScale; + float fireTimersScale; + float idleSettingsScale; + float adsSettingsScale; + float adsSettingsScaleMain; + float hipSpreadScale; + float gunKickScale; + float viewKickScale; + float viewCenterScale; + int loadIndex; + bool hideIronSightsWithThisAttachment; + bool shareAmmoWithAlt; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonWeaponAttachment, + displayName, + type, + weaponType, + weapClass, + worldModels, + viewModels, + reticleViewModels, + ammoGeneral, + sight, + reload, + addOns, + general, + aimAssist, + ammunition, + damage, + locationDamage, + idleSettings, + adsSettings, + adsSettingsMain, + hipSpread, + gunKick, + viewKick, + adsOverlay, + ui, + rumbles, + projectile, + ammunitionScale, + damageScale, + damageScaleMin, + stateTimersScale, + fireTimersScale, + idleSettingsScale, + adsSettingsScale, + adsSettingsScaleMain, + hipSpreadScale, + gunKickScale, + viewKickScale, + viewCenterScale, + loadIndex, + hideIronSightsWithThisAttachment, + shareAmmoWithAlt); +} // namespace IW5 diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeaponAttachment.cpp b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeaponAttachment.cpp new file mode 100644 index 00000000..d63e1649 --- /dev/null +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeaponAttachment.cpp @@ -0,0 +1,22 @@ +#include "AssetDumperWeaponAttachment.h" + +#include "Game/IW5/Weapon/JsonWeaponAttachmentWriter.h" + +#include + +using namespace IW5; + +bool AssetDumperWeaponAttachment::ShouldDump(XAssetInfo* asset) +{ + return true; +} + +void AssetDumperWeaponAttachment::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) +{ + const auto assetFile = context.OpenAssetFile(std::format("attachment/{}.json", asset->m_name)); + + if (!assetFile) + return; + + DumpWeaponAttachmentAsJson(*assetFile, asset->Asset(), context); +} diff --git a/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeaponAttachment.h b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeaponAttachment.h new file mode 100644 index 00000000..11f32004 --- /dev/null +++ b/src/ObjWriting/Game/IW5/AssetDumpers/AssetDumperWeaponAttachment.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/IW5/IW5.h" + +namespace IW5 +{ + class AssetDumperWeaponAttachment final : public AbstractAssetDumper + { + protected: + bool ShouldDump(XAssetInfo* asset) override; + void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; + }; +} // namespace IW5 diff --git a/src/ObjWriting/Game/IW5/Weapon/JsonWeaponAttachmentWriter.cpp b/src/ObjWriting/Game/IW5/Weapon/JsonWeaponAttachmentWriter.cpp new file mode 100644 index 00000000..86f0df79 --- /dev/null +++ b/src/ObjWriting/Game/IW5/Weapon/JsonWeaponAttachmentWriter.cpp @@ -0,0 +1,401 @@ +#include "JsonWeaponAttachmentWriter.h" + +#include "Game/IW5/CommonIW5.h" +#include "Game/IW5/Weapon/JsonWeaponAttachment.h" + +#include +#include + +using namespace nlohmann; +using namespace IW5; + +namespace +{ + class JsonDumper + { + public: + JsonDumper(AssetDumpingContext& context, std::ostream& stream) + : m_stream(stream) + { + } + + void Dump(const WeaponAttachment* attachment) const + { + JsonWeaponAttachment jsonWeaponAttachment; + CreateJsonAttachment(jsonWeaponAttachment, *attachment); + json jRoot = jsonWeaponAttachment; + + jRoot["_type"] = "attachment"; + jRoot["_version"] = 1; + + m_stream << std::setw(4) << jRoot << "\n"; + } + + private: + static const char* AssetName(const char* input) + { + if (input && input[0] == ',') + return &input[1]; + + return input; + } + + static void CreateJsonAttachment(JsonWeaponAttachment& jAttachment, const WeaponAttachment& attachment) + { +#define CONVERT_XMODEL_ARRAY(propertyName, count) \ + if (attachment.propertyName) \ + { \ + for (auto i = 0u; i < (count); i++) \ + { \ + const auto* model = attachment.propertyName[i]; \ + if (model && model->name) \ + jAttachment.propertyName.emplace_back(AssetName(model->name)); \ + } \ + } + +#define CONVERT_ATTRIBUTE(attributeJsonClass, attributeName) \ + if (attachment.attributeName) \ + { \ + attributeJsonClass attribute; \ + Convert##attributeJsonClass(attribute, *attachment.attributeName); \ + jAttachment.attributeName = std::move(attribute); \ + } + + if (attachment.szDisplayName) + jAttachment.displayName = attachment.szDisplayName; + + jAttachment.type = attachment.type; + jAttachment.weaponType = attachment.weaponType; + jAttachment.weapClass = attachment.weapClass; + + CONVERT_XMODEL_ARRAY(worldModels, 16u) + CONVERT_XMODEL_ARRAY(viewModels, 16u) + CONVERT_XMODEL_ARRAY(reticleViewModels, 8u) + + CONVERT_ATTRIBUTE(JsonAttAmmoGeneral, ammoGeneral) + CONVERT_ATTRIBUTE(JsonAttSight, sight) + CONVERT_ATTRIBUTE(JsonAttReload, reload) + CONVERT_ATTRIBUTE(JsonAttAddOns, addOns) + CONVERT_ATTRIBUTE(JsonAttGeneral, general) + CONVERT_ATTRIBUTE(JsonAttAimAssist, aimAssist) + CONVERT_ATTRIBUTE(JsonAttAmmunition, ammunition) + CONVERT_ATTRIBUTE(JsonAttDamage, damage) + CONVERT_ATTRIBUTE(JsonAttLocationDamage, locationDamage) + CONVERT_ATTRIBUTE(JsonAttIdleSettings, idleSettings) + CONVERT_ATTRIBUTE(JsonAttADSSettings, adsSettings) + CONVERT_ATTRIBUTE(JsonAttADSSettings, adsSettingsMain) + CONVERT_ATTRIBUTE(JsonAttHipSpread, hipSpread) + CONVERT_ATTRIBUTE(JsonAttGunKick, gunKick) + CONVERT_ATTRIBUTE(JsonAttViewKick, viewKick) + CONVERT_ATTRIBUTE(JsonAttADSOverlay, adsOverlay) + CONVERT_ATTRIBUTE(JsonAttUI, ui) + CONVERT_ATTRIBUTE(JsonAttRumbles, rumbles) + CONVERT_ATTRIBUTE(JsonAttProjectile, projectile) + + jAttachment.ammunitionScale = attachment.ammunitionScale; + jAttachment.damageScale = attachment.damageScale; + jAttachment.damageScaleMin = attachment.damageScaleMin; + jAttachment.stateTimersScale = attachment.stateTimersScale; + jAttachment.fireTimersScale = attachment.fireTimersScale; + jAttachment.idleSettingsScale = attachment.idleSettingsScale; + jAttachment.adsSettingsScale = attachment.adsSettingsScale; + jAttachment.adsSettingsScaleMain = attachment.adsSettingsScaleMain; + jAttachment.hipSpreadScale = attachment.hipSpreadScale; + jAttachment.gunKickScale = attachment.gunKickScale; + jAttachment.viewKickScale = attachment.viewKickScale; + jAttachment.viewCenterScale = attachment.viewCenterScale; + jAttachment.loadIndex = attachment.loadIndex; + jAttachment.hideIronSightsWithThisAttachment = attachment.hideIronSightsWithThisAttachment; + jAttachment.shareAmmoWithAlt = attachment.shareAmmoWithAlt; + } + + static void ConvertJsonAttAmmoGeneral(JsonAttAmmoGeneral& jAmmoGeneral, const AttAmmoGeneral& ammoGeneral) + { + jAmmoGeneral.penetrateType = ammoGeneral.penetrateType; + jAmmoGeneral.penetrateMultiplier = ammoGeneral.penetrateMultiplier; + jAmmoGeneral.impactType = ammoGeneral.impactType; + jAmmoGeneral.fireType = ammoGeneral.fireType; + + if (ammoGeneral.tracerType && ammoGeneral.tracerType->name) + jAmmoGeneral.tracerType = AssetName(ammoGeneral.tracerType->name); + + jAmmoGeneral.rifleBullet = ammoGeneral.rifleBullet; + jAmmoGeneral.armorPiercing = ammoGeneral.armorPiercing; + } + + static void ConvertJsonAttSight(JsonAttSight& jSight, const AttSight& sight) + { + jSight.aimDownSight = sight.aimDownSight; + jSight.adsFire = sight.adsFire; + jSight.rechamberWhileAds = sight.rechamberWhileAds; + jSight.noAdsWhenMagEmpty = sight.noAdsWhenMagEmpty; + jSight.canHoldBreath = sight.canHoldBreath; + jSight.canVariableZoom = sight.canVariableZoom; + jSight.hideRailWithThisScope = sight.hideRailWithThisScope; + } + + static void ConvertJsonAttReload(JsonAttReload& jAttReload, const AttReload& reload) + { + jAttReload.noPartialReload = reload.noPartialReload; + jAttReload.segmentedReload = reload.segmentedReload; + } + + static void ConvertJsonAttAddOns(JsonAttAddOns& jAddOns, const AttAddOns& addOns) + { + jAddOns.motionTracker = addOns.motionTracker; + jAddOns.silenced = addOns.silenced; + } + + static void ConvertJsonAttGeneral(JsonAttGeneral& jGeneral, const AttGeneral& general) + { + jGeneral.boltAction = general.boltAction; + jGeneral.inheritsPerks = general.inheritsPerks; + jGeneral.enemyCrosshairRange = general.enemyCrosshairRange; + + if (general.reticleCenter && general.reticleCenter->info.name) + jGeneral.reticleCenter = AssetName(general.reticleCenter->info.name); + + if (general.reticleSide && general.reticleSide->info.name) + jGeneral.reticleSide = AssetName(general.reticleSide->info.name); + + jGeneral.reticleCenterSize = general.reticleCenterSize; + jGeneral.reticleSideSize = general.reticleSideSize; + jGeneral.moveSpeedScale = general.moveSpeedScale; + jGeneral.adsMoveSpeedScale = general.adsMoveSpeedScale; + } + + static void ConvertJsonAttAimAssist(JsonAttAimAssist& jAimAssist, const AttAimAssist& aimAssist) + { + jAimAssist.autoAimRange = aimAssist.autoAimRange; + jAimAssist.aimAssistRange = aimAssist.aimAssistRange; + jAimAssist.aimAssistRangeAds = aimAssist.aimAssistRangeAds; + } + + static void ConvertJsonAttAmmunition(JsonAttAmmunition& jAmmunition, const AttAmmunition& ammunition) + { + jAmmunition.maxAmmo = ammunition.maxAmmo; + jAmmunition.startAmmo = ammunition.startAmmo; + jAmmunition.clipSize = ammunition.clipSize; + jAmmunition.shotCount = ammunition.shotCount; + jAmmunition.reloadAmmoAdd = ammunition.reloadAmmoAdd; + jAmmunition.reloadStartAdd = ammunition.reloadStartAdd; + } + + static void ConvertJsonAttDamage(JsonAttDamage& jDamage, const AttDamage& damage) + { + jDamage.damage = damage.damage; + jDamage.minDamage = damage.minDamage; + jDamage.meleeDamage = damage.meleeDamage; + jDamage.maxDamageRange = damage.maxDamageRange; + jDamage.minDamageRange = damage.minDamageRange; + jDamage.playerDamage = damage.playerDamage; + jDamage.minPlayerDamage = damage.minPlayerDamage; + } + + static void ConvertJsonAttLocationDamage(JsonAttLocationDamage& jLocationDamage, const AttLocationDamage& locationDamage) + { + jLocationDamage.locNone = locationDamage.locNone; + jLocationDamage.locHelmet = locationDamage.locHelmet; + jLocationDamage.locHead = locationDamage.locHead; + jLocationDamage.locNeck = locationDamage.locNeck; + jLocationDamage.locTorsoUpper = locationDamage.locTorsoUpper; + jLocationDamage.locTorsoLower = locationDamage.locTorsoLower; + jLocationDamage.locRightArmUpper = locationDamage.locRightArmUpper; + jLocationDamage.locRightArmLower = locationDamage.locRightArmLower; + jLocationDamage.locRightHand = locationDamage.locRightHand; + jLocationDamage.locLeftArmUpper = locationDamage.locLeftArmUpper; + jLocationDamage.locLeftArmLower = locationDamage.locLeftArmLower; + jLocationDamage.locLeftHand = locationDamage.locLeftHand; + jLocationDamage.locRightLegUpper = locationDamage.locRightLegUpper; + jLocationDamage.locRightLegLower = locationDamage.locRightLegLower; + jLocationDamage.locRightFoot = locationDamage.locRightFoot; + jLocationDamage.locLeftLegUpper = locationDamage.locLeftLegUpper; + jLocationDamage.locLeftLegLower = locationDamage.locLeftLegLower; + jLocationDamage.locLeftFoot = locationDamage.locLeftFoot; + jLocationDamage.locGun = locationDamage.locGun; + } + + static void ConvertJsonAttIdleSettings(JsonAttIdleSettings& jIdleSettings, const AttIdleSettings& idleSettings) + { + jIdleSettings.hipIdleAmount = idleSettings.hipIdleAmount; + jIdleSettings.hipIdleSpeed = idleSettings.hipIdleSpeed; + jIdleSettings.idleCrouchFactor = idleSettings.idleCrouchFactor; + jIdleSettings.idleProneFactor = idleSettings.idleProneFactor; + jIdleSettings.adsIdleLerpStartTime = idleSettings.adsIdleLerpStartTime; + jIdleSettings.adsIdleLerpTime = idleSettings.adsIdleLerpTime; + } + + static void ConvertJsonAttADSSettings(JsonAttADSSettings& jAdsSettings, const AttADSSettings& adsSettings) + { + jAdsSettings.adsSpread = adsSettings.adsSpread; + jAdsSettings.adsAimPitch = adsSettings.adsAimPitch; + jAdsSettings.adsTransInTime = adsSettings.adsTransInTime; + jAdsSettings.adsTransOutTime = adsSettings.adsTransOutTime; + jAdsSettings.adsReloadTransTime = adsSettings.adsReloadTransTime; + jAdsSettings.adsCrosshairInFrac = adsSettings.adsCrosshairInFrac; + jAdsSettings.adsCrosshairOutFrac = adsSettings.adsCrosshairOutFrac; + jAdsSettings.adsZoomFov = adsSettings.adsZoomFov; + jAdsSettings.adsZoomInFrac = adsSettings.adsZoomInFrac; + jAdsSettings.adsZoomOutFrac = adsSettings.adsZoomOutFrac; + jAdsSettings.adsBobFactor = adsSettings.adsBobFactor; + jAdsSettings.adsViewBobMult = adsSettings.adsViewBobMult; + jAdsSettings.adsViewErrorMin = adsSettings.adsViewErrorMin; + jAdsSettings.adsViewErrorMax = adsSettings.adsViewErrorMax; + } + + static void ConvertJsonAttHipSpread(JsonAttHipSpread& jHipSpread, const AttHipSpread& hipSpread) + { + jHipSpread.hipSpreadStandMin = hipSpread.hipSpreadStandMin; + jHipSpread.hipSpreadDuckedMin = hipSpread.hipSpreadDuckedMin; + jHipSpread.hipSpreadProneMin = hipSpread.hipSpreadProneMin; + jHipSpread.hipSpreadMax = hipSpread.hipSpreadMax; + jHipSpread.hipSpreadDuckedMax = hipSpread.hipSpreadDuckedMax; + jHipSpread.hipSpreadProneMax = hipSpread.hipSpreadProneMax; + jHipSpread.hipSpreadFireAdd = hipSpread.hipSpreadFireAdd; + jHipSpread.hipSpreadTurnAdd = hipSpread.hipSpreadTurnAdd; + jHipSpread.hipSpreadMoveAdd = hipSpread.hipSpreadMoveAdd; + jHipSpread.hipSpreadDecayRate = hipSpread.hipSpreadDecayRate; + jHipSpread.hipSpreadDuckedDecay = hipSpread.hipSpreadDuckedDecay; + jHipSpread.hipSpreadProneDecay = hipSpread.hipSpreadProneDecay; + } + + static void ConvertJsonAttGunKick(JsonAttGunKick& jGunKick, const AttGunKick& gunKick) + { + jGunKick.hipGunKickReducedKickBullets = gunKick.hipGunKickReducedKickBullets; + jGunKick.hipGunKickReducedKickPercent = gunKick.hipGunKickReducedKickPercent; + jGunKick.hipGunKickPitchMin = gunKick.hipGunKickPitchMin; + jGunKick.hipGunKickPitchMax = gunKick.hipGunKickPitchMax; + jGunKick.hipGunKickYawMin = gunKick.hipGunKickYawMin; + jGunKick.hipGunKickYawMax = gunKick.hipGunKickYawMax; + jGunKick.hipGunKickAccel = gunKick.hipGunKickAccel; + jGunKick.hipGunKickSpeedMax = gunKick.hipGunKickSpeedMax; + jGunKick.hipGunKickSpeedDecay = gunKick.hipGunKickSpeedDecay; + jGunKick.hipGunKickStaticDecay = gunKick.hipGunKickStaticDecay; + jGunKick.adsGunKickReducedKickBullets = gunKick.adsGunKickReducedKickBullets; + jGunKick.adsGunKickReducedKickPercent = gunKick.adsGunKickReducedKickPercent; + jGunKick.adsGunKickPitchMin = gunKick.adsGunKickPitchMin; + jGunKick.adsGunKickPitchMax = gunKick.adsGunKickPitchMax; + jGunKick.adsGunKickYawMin = gunKick.adsGunKickYawMin; + jGunKick.adsGunKickYawMax = gunKick.adsGunKickYawMax; + jGunKick.adsGunKickAccel = gunKick.adsGunKickAccel; + jGunKick.adsGunKickSpeedMax = gunKick.adsGunKickSpeedMax; + jGunKick.adsGunKickSpeedDecay = gunKick.adsGunKickSpeedDecay; + jGunKick.adsGunKickStaticDecay = gunKick.adsGunKickStaticDecay; + } + + static void ConvertJsonAttViewKick(JsonAttViewKick& jViewKick, const AttViewKick& viewKick) + { + jViewKick.hipViewKickPitchMin = viewKick.hipViewKickPitchMin; + jViewKick.hipViewKickPitchMax = viewKick.hipViewKickPitchMax; + jViewKick.hipViewKickYawMin = viewKick.hipViewKickYawMin; + jViewKick.hipViewKickYawMax = viewKick.hipViewKickYawMax; + jViewKick.hipViewKickCenterSpeed = viewKick.hipViewKickCenterSpeed; + jViewKick.adsViewKickPitchMin = viewKick.adsViewKickPitchMin; + jViewKick.adsViewKickPitchMax = viewKick.adsViewKickPitchMax; + jViewKick.adsViewKickYawMin = viewKick.adsViewKickYawMin; + jViewKick.adsViewKickYawMax = viewKick.adsViewKickYawMax; + jViewKick.adsViewKickCenterSpeed = viewKick.adsViewKickCenterSpeed; + } + + static void ConvertJsonAttADSOverlay(JsonAttADSOverlay& jAdsOverlay, const AttADSOverlay& adsOverlay) + { + if (adsOverlay.overlay.shader && adsOverlay.overlay.shader->info.name) + jAdsOverlay.shader = AssetName(adsOverlay.overlay.shader->info.name); + + if (adsOverlay.overlay.shaderLowRes && adsOverlay.overlay.shaderLowRes->info.name) + jAdsOverlay.shaderLowRes = AssetName(adsOverlay.overlay.shaderLowRes->info.name); + + if (adsOverlay.overlay.shaderEMP && adsOverlay.overlay.shaderEMP->info.name) + jAdsOverlay.shaderEMP = AssetName(adsOverlay.overlay.shaderEMP->info.name); + + if (adsOverlay.overlay.shaderEMPLowRes && adsOverlay.overlay.shaderEMPLowRes->info.name) + jAdsOverlay.shaderEMPLowRes = AssetName(adsOverlay.overlay.shaderEMPLowRes->info.name); + + jAdsOverlay.reticle = adsOverlay.overlay.reticle; + jAdsOverlay.width = adsOverlay.overlay.width; + jAdsOverlay.height = adsOverlay.overlay.height; + jAdsOverlay.widthSplitscreen = adsOverlay.overlay.widthSplitscreen; + jAdsOverlay.heightSplitscreen = adsOverlay.overlay.heightSplitscreen; + jAdsOverlay.thermalScope = adsOverlay.thermalScope; + } + + static void ConvertJsonAttUI(JsonAttUI& jUi, const AttUI& ui) + { + if (ui.dpadIcon && ui.dpadIcon->info.name) + jUi.dpadIcon = AssetName(ui.dpadIcon->info.name); + if (ui.ammoCounterIcon && ui.ammoCounterIcon->info.name) + jUi.ammoCounterIcon = AssetName(ui.ammoCounterIcon->info.name); + + jUi.dpadIconRatio = ui.dpadIconRatio; + jUi.ammoCounterIconRatio = ui.ammoCounterIconRatio; + jUi.ammoCounterClip = ui.ammoCounterClip; + } + + static void ConvertJsonAttRumbles(JsonAttRumbles& jRumbles, const AttRumbles& rumbles) + { + if (rumbles.fireRumble) + jRumbles.fireRumble = rumbles.fireRumble; + + if (rumbles.meleeImpactRumble) + jRumbles.meleeImpactRumble = rumbles.meleeImpactRumble; + } + + static void ConvertJsonAttProjectile(JsonAttProjectile& jProjectile, const AttProjectile& projectile) + { + jProjectile.explosionRadius = projectile.explosionRadius; + jProjectile.explosionInnerDamage = projectile.explosionInnerDamage; + jProjectile.explosionOuterDamage = projectile.explosionOuterDamage; + jProjectile.damageConeAngle = projectile.damageConeAngle; + jProjectile.projectileSpeed = projectile.projectileSpeed; + jProjectile.projectileSpeedUp = projectile.projectileSpeedUp; + jProjectile.projectileActivateDist = projectile.projectileActivateDist; + jProjectile.projectileLifetime = projectile.projectileLifetime; + + if (projectile.projectileModel && projectile.projectileModel->name) + jProjectile.projectileModel = AssetName(projectile.projectileModel->name); + + jProjectile.projExplosionType = projectile.projExplosionType; + + if (projectile.projExplosionEffect && projectile.projExplosionEffect->name) + jProjectile.projExplosionEffect = AssetName(projectile.projExplosionEffect->name); + + jProjectile.projExplosionEffectForceNormalUp = projectile.projExplosionEffectForceNormalUp; + + if (projectile.projExplosionSound.name && projectile.projExplosionSound.name->soundName) + jProjectile.projExplosionSound = projectile.projExplosionSound.name->soundName; + + if (projectile.projDudEffect && projectile.projDudEffect->name) + jProjectile.projDudEffect = AssetName(projectile.projDudEffect->name); + + if (projectile.projDudSound.name && projectile.projDudSound.name->soundName) + jProjectile.projDudSound = projectile.projDudSound.name->soundName; + + jProjectile.projImpactExplode = projectile.projImpactExplode; + jProjectile.destabilizationRateTime = projectile.destabilizationRateTime; + jProjectile.destabilizationCurvatureMax = projectile.destabilizationCurvatureMax; + jProjectile.destabilizeDistance = projectile.destabilizeDistance; + + if (projectile.projTrailEffect && projectile.projTrailEffect->name) + jProjectile.projTrailEffect = AssetName(projectile.projTrailEffect->name); + + jProjectile.projIgnitionDelay = projectile.projIgnitionDelay; + + if (projectile.projIgnitionEffect && projectile.projIgnitionEffect->name) + jProjectile.projIgnitionEffect = AssetName(projectile.projIgnitionEffect->name); + + if (projectile.projIgnitionSound.name && projectile.projIgnitionSound.name->soundName) + jProjectile.projIgnitionSound = projectile.projIgnitionSound.name->soundName; + } + + std::ostream& m_stream; + }; +} // namespace + +namespace IW5 +{ + void DumpWeaponAttachmentAsJson(std::ostream& stream, const WeaponAttachment* attachment, AssetDumpingContext& context) + { + const JsonDumper dumper(context, stream); + dumper.Dump(attachment); + } +} // namespace IW5 diff --git a/src/ObjWriting/Game/IW5/Weapon/JsonWeaponAttachmentWriter.h b/src/ObjWriting/Game/IW5/Weapon/JsonWeaponAttachmentWriter.h new file mode 100644 index 00000000..dc0a84c2 --- /dev/null +++ b/src/ObjWriting/Game/IW5/Weapon/JsonWeaponAttachmentWriter.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Dumping/AssetDumpingContext.h" +#include "Game/IW5/IW5.h" + +#include + +namespace IW5 +{ + void DumpWeaponAttachmentAsJson(std::ostream& stream, const WeaponAttachment* attachment, AssetDumpingContext& context); +} // namespace IW5 diff --git a/src/ObjWriting/Game/IW5/ZoneDumperIW5.cpp b/src/ObjWriting/Game/IW5/ZoneDumperIW5.cpp index f03d1db1..b3cc16d3 100644 --- a/src/ObjWriting/Game/IW5/ZoneDumperIW5.cpp +++ b/src/ObjWriting/Game/IW5/ZoneDumperIW5.cpp @@ -10,6 +10,7 @@ #include "AssetDumpers/AssetDumperScriptFile.h" #include "AssetDumpers/AssetDumperStringTable.h" #include "AssetDumpers/AssetDumperWeapon.h" +#include "AssetDumpers/AssetDumperWeaponAttachment.h" #include "AssetDumpers/AssetDumperXModel.h" #include "Game/IW5/GameAssetPoolIW5.h" #include "Game/IW5/GameIW5.h" @@ -59,7 +60,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const DUMP_ASSET_POOL(AssetDumperMenuList, m_menu_list, ASSET_TYPE_MENULIST) DUMP_ASSET_POOL(AssetDumperMenuDef, m_menu_def, ASSET_TYPE_MENU) DUMP_ASSET_POOL(AssetDumperLocalizeEntry, m_localize, ASSET_TYPE_LOCALIZE_ENTRY) - // DUMP_ASSET_POOL(AssetDumperWeaponAttachment, m_attachment, ASSET_TYPE_ATTACHMENT) + DUMP_ASSET_POOL(AssetDumperWeaponAttachment, m_attachment, ASSET_TYPE_ATTACHMENT) DUMP_ASSET_POOL(AssetDumperWeapon, m_weapon, ASSET_TYPE_WEAPON) // DUMP_ASSET_POOL(AssetDumperFxEffectDef, m_fx, ASSET_TYPE_FX) // DUMP_ASSET_POOL(AssetDumperFxImpactTable, m_fx_impact_table, ASSET_TYPE_IMPACT_FX)