2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-06-26 10:58:04 +00:00

feat: t6 flametables (#845)

* feat: add flametable loading and dumping for T6

* chore: add additional validation logic of game for t6 weapon loading
This commit is contained in:
Jan
2026-06-20 13:50:43 +02:00
committed by GitHub
parent 5b11848f4d
commit c84e3076f1
9 changed files with 447 additions and 15 deletions
+1
View File
@@ -77,6 +77,7 @@ namespace
"vertexdecl", "vertexdecl",
"vertexshader", "vertexshader",
"pixelshader", "pixelshader",
"flametable",
}; };
static_assert(std::extent_v<decltype(SUB_ASSET_TYPE_NAMES)> == SUB_ASSET_TYPE_COUNT); static_assert(std::extent_v<decltype(SUB_ASSET_TYPE_NAMES)> == SUB_ASSET_TYPE_COUNT);
} // namespace } // namespace
+2
View File
@@ -86,6 +86,7 @@ namespace T6
SUB_ASSET_TYPE_VERTEX_DECL, SUB_ASSET_TYPE_VERTEX_DECL,
SUB_ASSET_TYPE_VERTEX_SHADER, SUB_ASSET_TYPE_VERTEX_SHADER,
SUB_ASSET_TYPE_PIXEL_SHADER, SUB_ASSET_TYPE_PIXEL_SHADER,
SUB_ASSET_TYPE_FLAME_TABLE,
SUB_ASSET_TYPE_COUNT SUB_ASSET_TYPE_COUNT
}; };
@@ -292,6 +293,7 @@ namespace T6
using SubAssetVertexDecl = SubAsset<SUB_ASSET_TYPE_VERTEX_DECL, MaterialVertexDeclaration>; using SubAssetVertexDecl = SubAsset<SUB_ASSET_TYPE_VERTEX_DECL, MaterialVertexDeclaration>;
using SubAssetVertexShader = SubAsset<SUB_ASSET_TYPE_VERTEX_SHADER, MaterialVertexShader>; using SubAssetVertexShader = SubAsset<SUB_ASSET_TYPE_VERTEX_SHADER, MaterialVertexShader>;
using SubAssetPixelShader = SubAsset<SUB_ASSET_TYPE_PIXEL_SHADER, MaterialPixelShader>; using SubAssetPixelShader = SubAsset<SUB_ASSET_TYPE_PIXEL_SHADER, MaterialPixelShader>;
using SubAssetFlameTable = SubAsset<SUB_ASSET_TYPE_FLAME_TABLE, FlameTable>;
} // namespace T6 } // namespace T6
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetPhysPreset, name); DEFINE_ASSET_NAME_ACCESSOR(T6::AssetPhysPreset, name);
+1
View File
@@ -2,6 +2,7 @@
namespace T6 namespace T6
{ {
static constexpr auto INFO_STRING_PREFIX_FLAME_TABLE = "FLAMETABLEFILE";
static constexpr auto INFO_STRING_PREFIX_PHYS_CONSTRAINTS = "PHYSCONSTRAINTS"; static constexpr auto INFO_STRING_PREFIX_PHYS_CONSTRAINTS = "PHYSCONSTRAINTS";
static constexpr auto INFO_STRING_PREFIX_PHYS_PRESET = "PHYSIC"; static constexpr auto INFO_STRING_PREFIX_PHYS_PRESET = "PHYSIC";
static constexpr auto INFO_STRING_PREFIX_TRACER = "TRACER"; static constexpr auto INFO_STRING_PREFIX_TRACER = "TRACER";
@@ -0,0 +1,130 @@
#pragma once
#include "Game/T6/T6.h"
namespace T6
{
inline cspField_t flameTableFields[]{
{"flameVar_streamChunkGravityStart", offsetof(FlameTable, flameVar_streamChunkGravityStart), CSPFT_FLOAT },
{"flameVar_streamChunkGravityEnd", offsetof(FlameTable, flameVar_streamChunkGravityEnd), CSPFT_FLOAT },
{"flameVar_streamChunkMaxSize", offsetof(FlameTable, flameVar_streamChunkMaxSize), CSPFT_FLOAT },
{"flameVar_streamChunkStartSize", offsetof(FlameTable, flameVar_streamChunkStartSize), CSPFT_FLOAT },
{"flameVar_streamChunkEndSize", offsetof(FlameTable, flameVar_streamChunkEndSize), CSPFT_FLOAT },
{"flameVar_streamChunkStartSizeRand", offsetof(FlameTable, flameVar_streamChunkStartSizeRand), CSPFT_FLOAT },
{"flameVar_streamChunkEndSizeRand", offsetof(FlameTable, flameVar_streamChunkEndSizeRand), CSPFT_FLOAT },
{"flameVar_streamChunkDistScalar", offsetof(FlameTable, flameVar_streamChunkDistScalar), CSPFT_FLOAT },
{"flameVar_streamChunkDistSwayScale", offsetof(FlameTable, flameVar_streamChunkDistSwayScale), CSPFT_FLOAT },
{"flameVar_streamChunkDistSwayVelMax", offsetof(FlameTable, flameVar_streamChunkDistSwayVelMax), CSPFT_FLOAT },
{"flameVar_streamChunkSpeed", offsetof(FlameTable, flameVar_streamChunkSpeed), CSPFT_FLOAT },
{"flameVar_streamChunkDecel", offsetof(FlameTable, flameVar_streamChunkDecel), CSPFT_FLOAT },
{"flameVar_streamChunkVelocityAddScale", offsetof(FlameTable, flameVar_streamChunkVelocityAddScale), CSPFT_FLOAT },
{"flameVar_streamChunkDuration", offsetof(FlameTable, flameVar_streamChunkDuration), CSPFT_FLOAT },
{"flameVar_streamChunkDurationScaleMaxVel", offsetof(FlameTable, flameVar_streamChunkDurationScaleMaxVel), CSPFT_FLOAT },
{"flameVar_streamChunkDurationVelScalar", offsetof(FlameTable, flameVar_streamChunkDurationVelScalar), CSPFT_FLOAT },
{"flameVar_streamChunkSizeSpeedScale", offsetof(FlameTable, flameVar_streamChunkSizeSpeedScale), CSPFT_FLOAT },
{"flameVar_streamChunkSizeAgeScale", offsetof(FlameTable, flameVar_streamChunkSizeAgeScale), CSPFT_FLOAT },
{"flameVar_streamChunkSpawnFireIntervalStart", offsetof(FlameTable, flameVar_streamChunkSpawnFireIntervalStart), CSPFT_FLOAT },
{"flameVar_streamChunkSpawnFireIntervalEnd", offsetof(FlameTable, flameVar_streamChunkSpawnFireIntervalEnd), CSPFT_FLOAT },
{"flameVar_streamChunkSpawnFireMinLifeFrac", offsetof(FlameTable, flameVar_streamChunkSpawnFireMinLifeFrac), CSPFT_FLOAT },
{"flameVar_streamChunkSpawnFireMaxLifeFrac", offsetof(FlameTable, flameVar_streamChunkSpawnFireMaxLifeFrac), CSPFT_FLOAT },
{"flameVar_streamChunkFireMinLifeFrac", offsetof(FlameTable, flameVar_streamChunkFireMinLifeFrac), CSPFT_FLOAT },
{"flameVar_streamChunkFireMinLifeFracStart", offsetof(FlameTable, flameVar_streamChunkFireMinLifeFracStart), CSPFT_FLOAT },
{"flameVar_streamChunkFireMinLifeFracEnd", offsetof(FlameTable, flameVar_streamChunkFireMinLifeFracEnd), CSPFT_FLOAT },
{"flameVar_streamChunkDripsMinLifeFrac", offsetof(FlameTable, flameVar_streamChunkDripsMinLifeFrac), CSPFT_FLOAT },
{"flameVar_streamChunkDripsMinLifeFracStart", offsetof(FlameTable, flameVar_streamChunkDripsMinLifeFracStart), CSPFT_FLOAT },
{"flameVar_streamChunkDripsMinLifeFracEnd", offsetof(FlameTable, flameVar_streamChunkDripsMinLifeFracEnd), CSPFT_FLOAT },
{"flameVar_streamChunkRotationRange", offsetof(FlameTable, flameVar_streamChunkRotationRange), CSPFT_FLOAT },
{"flameVar_streamSizeRandSinWave", offsetof(FlameTable, flameVar_streamSizeRandSinWave), CSPFT_FLOAT },
{"flameVar_streamSizeRandCosWave", offsetof(FlameTable, flameVar_streamSizeRandCosWave), CSPFT_FLOAT },
{"flameVar_streamDripsChunkInterval", offsetof(FlameTable, flameVar_streamDripsChunkInterval), CSPFT_FLOAT },
{"flameVar_streamDripsChunkMinFrac", offsetof(FlameTable, flameVar_streamDripsChunkMinFrac), CSPFT_FLOAT },
{"flameVar_streamDripsChunkRandFrac", offsetof(FlameTable, flameVar_streamDripsChunkRandFrac), CSPFT_FLOAT },
{"flameVar_streamSmokeChunkInterval", offsetof(FlameTable, flameVar_streamSmokeChunkInterval), CSPFT_FLOAT },
{"flameVar_streamSmokeChunkMinFrac", offsetof(FlameTable, flameVar_streamSmokeChunkMinFrac), CSPFT_FLOAT },
{"flameVar_streamSmokeChunkRandFrac", offsetof(FlameTable, flameVar_streamSmokeChunkRandFrac), CSPFT_FLOAT },
{"flameVar_streamChunkCullDistSizeFrac", offsetof(FlameTable, flameVar_streamChunkCullDistSizeFrac), CSPFT_FLOAT },
{"flameVar_streamChunkCullMinLife", offsetof(FlameTable, flameVar_streamChunkCullMinLife), CSPFT_FLOAT },
{"flameVar_streamChunkCullMaxLife", offsetof(FlameTable, flameVar_streamChunkCullMaxLife), CSPFT_FLOAT },
{"flameVar_streamFuelSizeStart", offsetof(FlameTable, flameVar_streamFuelSizeStart), CSPFT_FLOAT },
{"flameVar_streamFuelSizeEnd", offsetof(FlameTable, flameVar_streamFuelSizeEnd), CSPFT_FLOAT },
{"flameVar_streamFuelLength", offsetof(FlameTable, flameVar_streamFuelLength), CSPFT_FLOAT },
{"flameVar_streamFuelNumSegments", offsetof(FlameTable, flameVar_streamFuelNumSegments), CSPFT_FLOAT },
{"flameVar_streamFuelAnimLoopTime", offsetof(FlameTable, flameVar_streamFuelAnimLoopTime), CSPFT_FLOAT },
{"flameVar_streamFlameSizeStart", offsetof(FlameTable, flameVar_streamFlameSizeStart), CSPFT_FLOAT },
{"flameVar_streamFlameSizeEnd", offsetof(FlameTable, flameVar_streamFlameSizeEnd), CSPFT_FLOAT },
{"flameVar_streamFlameLength", offsetof(FlameTable, flameVar_streamFlameLength), CSPFT_FLOAT },
{"flameVar_streamFlameNumSegments", offsetof(FlameTable, flameVar_streamFlameNumSegments), CSPFT_FLOAT },
{"flameVar_streamFlameAnimLoopTime", offsetof(FlameTable, flameVar_streamFlameAnimLoopTime), CSPFT_FLOAT },
{"flameVar_streamPrimaryLightRadius", offsetof(FlameTable, flameVar_streamPrimaryLightRadius), CSPFT_FLOAT },
{"flameVar_streamPrimaryLightRadiusFlutter", offsetof(FlameTable, flameVar_streamPrimaryLightRadiusFlutter), CSPFT_FLOAT },
{"flameVar_streamPrimaryLightR", offsetof(FlameTable, flameVar_streamPrimaryLightR), CSPFT_FLOAT },
{"flameVar_streamPrimaryLightG", offsetof(FlameTable, flameVar_streamPrimaryLightG), CSPFT_FLOAT },
{"flameVar_streamPrimaryLightB", offsetof(FlameTable, flameVar_streamPrimaryLightB), CSPFT_FLOAT },
{"flameVar_streamPrimaryLightFlutterR", offsetof(FlameTable, flameVar_streamPrimaryLightFlutterR), CSPFT_FLOAT },
{"flameVar_streamPrimaryLightFlutterG", offsetof(FlameTable, flameVar_streamPrimaryLightFlutterG), CSPFT_FLOAT },
{"flameVar_streamPrimaryLightFlutterB", offsetof(FlameTable, flameVar_streamPrimaryLightFlutterB), CSPFT_FLOAT },
{"flameVar_fireLife", offsetof(FlameTable, flameVar_fireLife), CSPFT_FLOAT },
{"flameVar_fireLifeRand", offsetof(FlameTable, flameVar_fireLifeRand), CSPFT_FLOAT },
{"flameVar_fireSpeedScale", offsetof(FlameTable, flameVar_fireSpeedScale), CSPFT_FLOAT },
{"flameVar_fireSpeedScaleRand", offsetof(FlameTable, flameVar_fireSpeedScaleRand), CSPFT_FLOAT },
{"flameVar_fireVelocityAddZ", offsetof(FlameTable, flameVar_fireVelocityAddZ), CSPFT_FLOAT },
{"flameVar_fireVelocityAddZRand", offsetof(FlameTable, flameVar_fireVelocityAddZRand), CSPFT_FLOAT },
{"flameVar_fireVelocityAddSideways", offsetof(FlameTable, flameVar_fireVelocityAddSideways), CSPFT_FLOAT },
{"flameVar_fireGravity", offsetof(FlameTable, flameVar_fireGravity), CSPFT_FLOAT },
{"flameVar_fireGravityEnd", offsetof(FlameTable, flameVar_fireGravityEnd), CSPFT_FLOAT },
{"flameVar_fireMaxRotVel", offsetof(FlameTable, flameVar_fireMaxRotVel), CSPFT_FLOAT },
{"flameVar_fireFriction", offsetof(FlameTable, flameVar_fireFriction), CSPFT_FLOAT },
{"flameVar_fireEndSizeAdd", offsetof(FlameTable, flameVar_fireEndSizeAdd), CSPFT_FLOAT },
{"flameVar_fireStartSizeScale", offsetof(FlameTable, flameVar_fireStartSizeScale), CSPFT_FLOAT },
{"flameVar_fireEndSizeScale", offsetof(FlameTable, flameVar_fireEndSizeScale), CSPFT_FLOAT },
{"flameVar_fireBrightness", offsetof(FlameTable, flameVar_fireBrightness), CSPFT_FLOAT },
{"flameVar_dripsLife", offsetof(FlameTable, flameVar_dripsLife), CSPFT_FLOAT },
{"flameVar_dripsLifeRand", offsetof(FlameTable, flameVar_dripsLifeRand), CSPFT_FLOAT },
{"flameVar_dripsSpeedScale", offsetof(FlameTable, flameVar_dripsSpeedScale), CSPFT_FLOAT },
{"flameVar_dripsSpeedScaleRand", offsetof(FlameTable, flameVar_dripsSpeedScaleRand), CSPFT_FLOAT },
{"flameVar_dripsVelocityAddZ", offsetof(FlameTable, flameVar_dripsVelocityAddZ), CSPFT_FLOAT },
{"flameVar_dripsVelocityAddZRand", offsetof(FlameTable, flameVar_dripsVelocityAddZRand), CSPFT_FLOAT },
{"flameVar_dripsVelocityAddSideways", offsetof(FlameTable, flameVar_dripsVelocityAddSideways), CSPFT_FLOAT },
{"flameVar_dripsGravity", offsetof(FlameTable, flameVar_dripsGravity), CSPFT_FLOAT },
{"flameVar_dripsGravityEnd", offsetof(FlameTable, flameVar_dripsGravityEnd), CSPFT_FLOAT },
{"flameVar_dripsMaxRotVel", offsetof(FlameTable, flameVar_dripsMaxRotVel), CSPFT_FLOAT },
{"flameVar_dripsFriction", offsetof(FlameTable, flameVar_dripsFriction), CSPFT_FLOAT },
{"flameVar_dripsEndSizeAdd", offsetof(FlameTable, flameVar_dripsEndSizeAdd), CSPFT_FLOAT },
{"flameVar_dripsStartSizeScale", offsetof(FlameTable, flameVar_dripsStartSizeScale), CSPFT_FLOAT },
{"flameVar_dripsEndSizeScale", offsetof(FlameTable, flameVar_dripsEndSizeScale), CSPFT_FLOAT },
{"flameVar_dripsBrightness", offsetof(FlameTable, flameVar_dripsBrightness), CSPFT_FLOAT },
{"flameVar_smokeLife", offsetof(FlameTable, flameVar_smokeLife), CSPFT_FLOAT },
{"flameVar_smokeLifeRand", offsetof(FlameTable, flameVar_smokeLifeRand), CSPFT_FLOAT },
{"flameVar_smokeSpeedScale", offsetof(FlameTable, flameVar_smokeSpeedScale), CSPFT_FLOAT },
{"flameVar_smokeVelocityAddZ", offsetof(FlameTable, flameVar_smokeVelocityAddZ), CSPFT_FLOAT },
{"flameVar_smokeGravity", offsetof(FlameTable, flameVar_smokeGravity), CSPFT_FLOAT },
{"flameVar_smokeGravityEnd", offsetof(FlameTable, flameVar_smokeGravityEnd), CSPFT_FLOAT },
{"flameVar_smokeMaxRotation", offsetof(FlameTable, flameVar_smokeMaxRotation), CSPFT_FLOAT },
{"flameVar_smokeMaxRotVel", offsetof(FlameTable, flameVar_smokeMaxRotVel), CSPFT_FLOAT },
{"flameVar_smokeFriction", offsetof(FlameTable, flameVar_smokeFriction), CSPFT_FLOAT },
{"flameVar_smokeEndSizeAdd", offsetof(FlameTable, flameVar_smokeEndSizeAdd), CSPFT_FLOAT },
{"flameVar_smokeStartSizeAdd", offsetof(FlameTable, flameVar_smokeStartSizeAdd), CSPFT_FLOAT },
{"flameVar_smokeOriginSizeOfsZScale", offsetof(FlameTable, flameVar_smokeOriginSizeOfsZScale), CSPFT_FLOAT },
{"flameVar_smokeOriginOfsZ", offsetof(FlameTable, flameVar_smokeOriginOfsZ), CSPFT_FLOAT },
{"flameVar_smokeFadein", offsetof(FlameTable, flameVar_smokeFadein), CSPFT_FLOAT },
{"flameVar_smokeFadeout", offsetof(FlameTable, flameVar_smokeFadeout), CSPFT_FLOAT },
{"flameVar_smokeMaxAlpha", offsetof(FlameTable, flameVar_smokeMaxAlpha), CSPFT_FLOAT },
{"flameVar_smokeBrightness", offsetof(FlameTable, flameVar_smokeBrightness), CSPFT_FLOAT },
{"flameVar_smokeOriginOffset", offsetof(FlameTable, flameVar_smokeOriginOffset), CSPFT_FLOAT },
{"flameVar_collisionSpeedScale", offsetof(FlameTable, flameVar_collisionSpeedScale), CSPFT_FLOAT },
{"flameVar_collisionVolumeScale", offsetof(FlameTable, flameVar_collisionVolumeScale), CSPFT_FLOAT },
{"name", offsetof(FlameTable, name), CSPFT_STRING },
{"fire", offsetof(FlameTable, fire), CSPFT_MATERIAL},
{"smoke", offsetof(FlameTable, smoke), CSPFT_MATERIAL},
{"heat", offsetof(FlameTable, heat), CSPFT_MATERIAL},
{"drips", offsetof(FlameTable, drips), CSPFT_MATERIAL},
{"streamFuel", offsetof(FlameTable, streamFuel), CSPFT_MATERIAL},
{"streamFuel2", offsetof(FlameTable, streamFuel2), CSPFT_MATERIAL},
{"streamFlame", offsetof(FlameTable, streamFlame), CSPFT_MATERIAL},
{"streamFlame2", offsetof(FlameTable, streamFlame2), CSPFT_MATERIAL},
{"flameOffLoopSound", offsetof(FlameTable, flameOffLoopSound), CSPFT_STRING },
{"flameIgniteSound", offsetof(FlameTable, flameIgniteSound), CSPFT_STRING },
{"flameOnLoopSound", offsetof(FlameTable, flameOnLoopSound), CSPFT_STRING },
{"flameCooldownSound", offsetof(FlameTable, flameCooldownSound), CSPFT_STRING },
};
}
+2
View File
@@ -43,6 +43,7 @@
#include "Weapon/AttachmentUniqueGdtLoaderT6.h" #include "Weapon/AttachmentUniqueGdtLoaderT6.h"
#include "Weapon/AttachmentUniqueRawLoaderT6.h" #include "Weapon/AttachmentUniqueRawLoaderT6.h"
#include "Weapon/CamoJsonLoaderT6.h" #include "Weapon/CamoJsonLoaderT6.h"
#include "Weapon/FlameTableLoaderT6.h"
#include "Weapon/WeaponGdtLoaderT6.h" #include "Weapon/WeaponGdtLoaderT6.h"
#include "Weapon/WeaponRawLoaderT6.h" #include "Weapon/WeaponRawLoaderT6.h"
#include "ZBarrier/GdtLoaderZBarrierT6.h" #include "ZBarrier/GdtLoaderZBarrierT6.h"
@@ -441,6 +442,7 @@ namespace T6
collection.AddSubAssetCreator(techset::CreateVertexShaderLoaderT6(memory, searchPath)); collection.AddSubAssetCreator(techset::CreateVertexShaderLoaderT6(memory, searchPath));
collection.AddSubAssetCreator(techset::CreatePixelShaderLoaderT6(memory, searchPath)); collection.AddSubAssetCreator(techset::CreatePixelShaderLoaderT6(memory, searchPath));
collection.AddSubAssetCreator(weapon::CreateFlameTableLoaderT6(memory, searchPath, zone));
} }
} // namespace } // namespace
@@ -0,0 +1,93 @@
#include "FlameTableLoaderT6.h"
#include "Game/T6/InfoString/InfoStringToStructConverter.h"
#include "Game/T6/ObjConstantsT6.h"
#include "Game/T6/T6.h"
#include "Game/T6/Weapon/FlameTableFields.h"
#include "Weapon/WeaponCommon.h"
#include <cassert>
#include <format>
using namespace T6;
namespace
{
class InfoStringToFlameTableConverter final : public InfoStringToStructConverter
{
protected:
bool ConvertExtensionField(const cspField_t& field, const std::string& value) override
{
assert(false);
return false;
}
public:
InfoStringToFlameTableConverter(const InfoString& infoString,
FlameTable& flameTable,
ZoneScriptStrings& zoneScriptStrings,
MemoryManager& memory,
AssetCreationContext& context,
AssetRegistration<SubAssetFlameTable>& registration,
const cspField_t* fields,
const size_t fieldCount)
: InfoStringToStructConverter(infoString, &flameTable, zoneScriptStrings, memory, context, registration, fields, fieldCount)
{
}
};
class FlameTableLoaderT6 final : public SubAssetCreator<SubAssetFlameTable>
{
public:
FlameTableLoaderT6(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
: m_memory(memory),
m_search_path(searchPath),
m_zone(zone)
{
}
AssetCreationResult CreateSubAsset(const std::string& assetName, AssetCreationContext& context) override
{
const auto fileName = weapon::GetFileNameForFlameTable(assetName);
const auto file = m_search_path.Open(fileName);
if (!file.IsOpen())
return AssetCreationResult::NoAction();
InfoString infoString;
if (!infoString.FromStream(INFO_STRING_PREFIX_FLAME_TABLE, *file.m_stream))
{
con::error("Could not parse as info string file: \"{}\"", fileName);
return AssetCreationResult::Failure();
}
auto* flameTable = m_memory.Alloc<FlameTable>();
AssetRegistration<SubAssetFlameTable> registration(assetName, flameTable);
InfoStringToFlameTableConverter converter(
infoString, *flameTable, m_zone.m_script_strings, m_memory, context, registration, flameTableFields, std::extent_v<decltype(flameTableFields)>);
if (!converter.Convert())
{
con::error("Failed to parse flame table: \"{}\"", assetName);
return AssetCreationResult::Failure();
}
// The flametable infostring contains the name but we don't to use it from there
// It's kept to keep compatiblity with the official modtools and game
flameTable->name = m_memory.Dup(assetName.c_str());
return AssetCreationResult::Success(context.AddSubAsset(std::move(registration)));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
Zone& m_zone;
};
} // namespace
namespace weapon
{
std::unique_ptr<ISubAssetCreator> CreateFlameTableLoaderT6(MemoryManager& memory, ISearchPath& searchPath, Zone& zone)
{
return std::make_unique<FlameTableLoaderT6>(memory, searchPath, zone);
}
} // namespace weapon
@@ -0,0 +1,13 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include "Zone/Zone.h"
#include <memory>
namespace weapon
{
std::unique_ptr<ISubAssetCreator> CreateFlameTableLoaderT6(MemoryManager& memory, ISearchPath& searchPath, Zone& zone);
} // namespace weapon
@@ -6,6 +6,7 @@
#include "Game/T6/Weapon/WeaponFields.h" #include "Game/T6/Weapon/WeaponFields.h"
#include "Game/T6/Weapon/WeaponStrings.h" #include "Game/T6/Weapon/WeaponStrings.h"
#include "Utils/Logging/Log.h" #include "Utils/Logging/Log.h"
#include "Utils/StringUtils.h"
#include "Weapon/AccuracyGraphLoader.h" #include "Weapon/AccuracyGraphLoader.h"
#include <cassert> #include <cassert>
@@ -442,6 +443,32 @@ namespace
return true; return true;
} }
bool LoadFlameTable(const char* flameTableName, FlameTable*& flameTablePtr, AssetRegistration<AssetWeapon>& registration, AssetCreationContext& context)
{
if (flameTableName && flameTableName[0] != '\0')
{
auto* flameTableAsset = context.LoadSubAsset<SubAssetFlameTable>(flameTableName);
if (!flameTableAsset)
return false;
for (auto* dependency : flameTableAsset->m_dependencies)
registration.AddDependency(dependency);
assert(flameTableAsset->m_used_script_strings.empty());
assert(flameTableAsset->m_indirect_asset_references.empty());
flameTablePtr = flameTableAsset->Asset();
}
return true;
}
bool LoadFlameTables(WeaponFullDef& weaponFullDef, AssetRegistration<AssetWeapon>& registration, AssetCreationContext& context)
{
return LoadFlameTable(weaponFullDef.weapDef.flameTableFirstPerson, weaponFullDef.weapDef.flameTableFirstPersonPtr, registration, context)
&& LoadFlameTable(weaponFullDef.weapDef.flameTableThirdPerson, weaponFullDef.weapDef.flameTableThirdPersonPtr, registration, context);
}
void LinkWeaponFullDefSubStructs(WeaponFullDef& weapon) void LinkWeaponFullDefSubStructs(WeaponFullDef& weapon)
{ {
weapon.weapVariantDef.weapDef = &weapon.weapDef; weapon.weapVariantDef.weapDef = &weapon.weapDef;
@@ -462,25 +489,109 @@ namespace
weapon.weapDef.locationDamageMultipliers = weapon.locationDamageMultipliers; weapon.weapDef.locationDamageMultipliers = weapon.locationDamageMultipliers;
} }
void CalculateWeaponFields(WeaponFullDef& weapon) bool IsDefaultWeapon(const WeaponFullDef& weapon)
{
return strcmp(weapon.weapVariantDef.szInternalName, "defaultweapon") == 0 || strcmp(weapon.weapVariantDef.szInternalName, "defaultweapon_mp") == 0;
}
void SetWeaponDefaults(WeaponFullDef& weapon)
{
if (IsDefaultWeapon(weapon))
return;
if (!weapon.weapDef.viewLastShotEjectEffect)
weapon.weapDef.viewLastShotEjectEffect = weapon.weapDef.viewShellEjectEffect;
if (!weapon.weapDef.worldLastShotEjectEffect)
weapon.weapDef.worldLastShotEjectEffect = weapon.weapDef.worldShellEjectEffect;
if (!weapon.weapDef.raiseSound)
weapon.weapDef.raiseSound = "wpn_default_raise";
if (!weapon.weapDef.putawaySound)
weapon.weapDef.putawaySound = "wpn_default_putaway";
if (!weapon.weapDef.pickupSound)
weapon.weapDef.pickupSound = "wpn_default_pickup";
if (!weapon.weapDef.ammoPickupSound)
weapon.weapDef.ammoPickupSound = "wpn_default_ammo_pickup";
if (!weapon.weapDef.emptyFireSound)
weapon.weapDef.emptyFireSound = "wpn_default_no_ammo";
}
void SetupTransitionTimes(WeaponFullDef& weapon)
{
if (weapon.weapVariantDef.iAdsTransInTime <= 0)
weapon.weapVariantDef.fOOPosAnimLength[0] = 1.0f / 300.0f; // 0.0033333334f;
else
weapon.weapVariantDef.fOOPosAnimLength[0] = 1.0f / static_cast<float>(weapon.weapVariantDef.iAdsTransInTime);
if (weapon.weapVariantDef.iAdsTransOutTime <= 0)
weapon.weapVariantDef.fOOPosAnimLength[1] = 1.0f / 500.0f; // 0.0020000001f
else
weapon.weapVariantDef.fOOPosAnimLength[1] = 1.0f / static_cast<float>(weapon.weapVariantDef.iAdsTransOutTime);
}
void CheckWeaponDamageRanges(WeaponFullDef& weapon)
{
if (strcmp(weapon.weapVariantDef.szInternalName, "none") == 0)
return;
if (weapon.weapDef.damageRange[0] <= 0.0)
weapon.weapDef.damageRange[0] = 999999.0f;
if (weapon.weapDef.damageRange[5] <= 0.0)
weapon.weapDef.damageRange[5] = 999999.12f; // oddly specific number, no clue
}
void CheckCrosshairValues(WeaponFullDef& weapon)
{
if (weapon.weapDef.enemyCrosshairRange > 15000.0f)
con::warn("Weapon {}: Enemy crosshair ranges should be less than 15000", weapon.weapVariantDef.szInternalName);
}
void CheckProjectileValues(WeaponFullDef& weapon)
{
if (weapon.weapDef.weapType != WEAPTYPE_PROJECTILE)
return;
if (weapon.weapDef.iProjectileSpeed <= 0)
con::warn("Weapon {}: Projectile speed must be greater than 0.0", weapon.weapVariantDef.szDisplayName);
if (weapon.weapDef.destabilizationCurvatureMax >= 1000000000.0f || weapon.weapDef.destabilizationCurvatureMax < 0.0f)
con::warn("Weapon {}: Destabilization angle must be between 0 and 45 degrees", weapon.weapVariantDef.szDisplayName);
if (weapon.weapDef.destabilizationRateTime < 0.0f)
con::warn("Weapon {}: Destabilization rate time must be non-negative", weapon.weapVariantDef.szDisplayName);
}
void CheckSharedAmmoValues(const WeaponFullDef& weapon)
{
if (weapon.weapVariantDef.szAmmoName)
utils::MakeStringLowerCase(const_cast<char*>(weapon.weapVariantDef.szAmmoName));
if (weapon.weapVariantDef.szClipName)
utils::MakeStringLowerCase(const_cast<char*>(weapon.weapVariantDef.szClipName));
}
void CheckAttachModelTags(const WeaponFullDef& weapon)
{
for (auto* tag : weapon.attachViewModelTag)
{
if (tag)
utils::MakeStringLowerCase(const_cast<char*>(tag));
}
for (auto* tag : weapon.attachWorldModelTag)
{
if (tag)
utils::MakeStringLowerCase(const_cast<char*>(tag));
}
}
void SetupAttachmentField(WeaponFullDef& weapon)
{ {
// iAttachments
weapon.weapVariantDef.iAttachments = 0; weapon.weapVariantDef.iAttachments = 0;
for (auto i = 1u; i < sizeof(WeaponVariantDef::iAttachments) * 8; i++) // Bit for default attachment always 0 for (auto i = 1u; i < sizeof(WeaponVariantDef::iAttachments) * 8; i++) // Bit for default attachment always 0
{ {
if (weapon.attachments[i]) if (weapon.attachments[i])
weapon.weapVariantDef.iAttachments |= 1 << i; weapon.weapVariantDef.iAttachments |= 1 << i;
} }
if (weapon.weapVariantDef.iAdsTransInTime <= 0)
weapon.weapVariantDef.fOOPosAnimLength[0] = 0.0033333334f;
else
weapon.weapVariantDef.fOOPosAnimLength[0] = 1.0f / static_cast<float>(weapon.weapVariantDef.iAdsTransInTime);
if (weapon.weapVariantDef.iAdsTransOutTime <= 0)
weapon.weapVariantDef.fOOPosAnimLength[1] = 0.0020000001f;
else
weapon.weapVariantDef.fOOPosAnimLength[1] = 1.0f / static_cast<float>(weapon.weapVariantDef.iAdsTransOutTime);
} }
bool IsStringOverride(const char* baseString, const char* overrideString) bool IsStringOverride(const char* baseString, const char* overrideString)
@@ -625,10 +736,27 @@ namespace weapon
return AssetCreationResult::Failure(); return AssetCreationResult::Failure();
} }
CalculateWeaponFields(*weaponFullDef); if (!LoadAccuracyGraphs(*weaponFullDef, m_memory, m_search_path, context))
CalculateAttachmentFields(*weaponFullDef); {
con::error("Failed to load accuracy tables of weapon: \"{}\"", assetName);
return AssetCreationResult::Failure();
}
LoadAccuracyGraphs(*weaponFullDef, m_memory, m_search_path, context); if (!LoadFlameTables(*weaponFullDef, registration, context))
{
con::error("Failed to load flame tables of weapon: \"{}\"", assetName);
return AssetCreationResult::Failure();
}
SetWeaponDefaults(*weaponFullDef);
SetupTransitionTimes(*weaponFullDef);
CheckWeaponDamageRanges(*weaponFullDef);
SetupAttachmentField(*weaponFullDef);
CalculateAttachmentFields(*weaponFullDef);
CheckCrosshairValues(*weaponFullDef);
CheckProjectileValues(*weaponFullDef);
CheckSharedAmmoValues(*weaponFullDef);
CheckAttachModelTags(*weaponFullDef);
return AssetCreationResult::Success(context.AddAsset(std::move(registration))); return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
} }
@@ -1,7 +1,9 @@
#include "WeaponDumperT6.h" #include "WeaponDumperT6.h"
#include "Dumping/SubAssetDeduplicationDumperState.h"
#include "Game/T6/InfoString/InfoStringFromStructConverter.h" #include "Game/T6/InfoString/InfoStringFromStructConverter.h"
#include "Game/T6/ObjConstantsT6.h" #include "Game/T6/ObjConstantsT6.h"
#include "Game/T6/Weapon/FlameTableFields.h"
#include "Game/T6/Weapon/WeaponFields.h" #include "Game/T6/Weapon/WeaponFields.h"
#include "Game/T6/Weapon/WeaponStrings.h" #include "Game/T6/Weapon/WeaponStrings.h"
#include "InfoString/InfoString.h" #include "InfoString/InfoString.h"
@@ -267,6 +269,24 @@ namespace
} }
}; };
class InfoStringFromFlameTableConverter final : public InfoStringFromStructConverter
{
protected:
void FillFromExtensionField(const cspField_t& field) override
{
assert(false);
}
public:
InfoStringFromFlameTableConverter(const FlameTable* structure,
const cspField_t* fields,
const size_t fieldCount,
std::function<std::string(scr_string_t)> scriptStringValueCallback)
: InfoStringFromStructConverter(structure, fields, fieldCount, std::move(scriptStringValueCallback))
{
}
};
GenericGraph2D ConvertAccuracyGraph(const char* graphName, const vec2_t* originalKnots, const unsigned originalKnotCount) GenericGraph2D ConvertAccuracyGraph(const char* graphName, const vec2_t* originalKnots, const unsigned originalKnotCount)
{ {
GenericGraph2D graph; GenericGraph2D graph;
@@ -457,6 +477,47 @@ namespace
weapDef->originalAiVsPlayerAccuracyGraphKnotCount)); weapDef->originalAiVsPlayerAccuracyGraphKnotCount));
} }
} }
void DumpFlameTable(const AssetDumpingContext& context,
SubAssetDeduplicationDumperState<FlameTable>& deduplicator,
const char* flameTableName,
const FlameTable* flameTable)
{
if (!flameTable || !flameTableName || flameTableName[0] == '\0')
return;
if (!deduplicator.ShouldDumpSubAsset(flameTable))
return;
const auto assetFile = context.OpenAssetFile(weapon::GetFileNameForFlameTable(flameTableName));
if (!assetFile)
return;
auto& stream = *assetFile;
InfoStringFromFlameTableConverter converter(flameTable,
flameTableFields,
std::extent_v<decltype(flameTableFields)>,
[](const scr_string_t scrStr) -> std::string
{
assert(false);
return "";
});
const auto infoString = converter.Convert();
const auto stringValue = infoString.ToString(INFO_STRING_PREFIX_FLAME_TABLE);
stream.write(stringValue.c_str(), stringValue.size());
}
void DumpFlameTables(AssetDumpingContext& context, const XAssetInfo<WeaponVariantDef>& asset)
{
auto* deduplicator = context.GetZoneAssetDumperState<SubAssetDeduplicationDumperState<FlameTable>>();
const auto weapon = asset.Asset();
DumpFlameTable(context, *deduplicator, weapon->weapDef->flameTableFirstPerson, weapon->weapDef->flameTableFirstPersonPtr);
DumpFlameTable(context, *deduplicator, weapon->weapDef->flameTableThirdPerson, weapon->weapDef->flameTableThirdPersonPtr);
}
} // namespace } // namespace
namespace weapon namespace weapon
@@ -485,5 +546,6 @@ namespace weapon
} }
DumpAccuracyGraphs(context, asset); DumpAccuracyGraphs(context, asset);
DumpFlameTables(context, asset);
} }
} // namespace weapon } // namespace weapon