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:
@@ -77,6 +77,7 @@ namespace
|
||||
"vertexdecl",
|
||||
"vertexshader",
|
||||
"pixelshader",
|
||||
"flametable",
|
||||
};
|
||||
static_assert(std::extent_v<decltype(SUB_ASSET_TYPE_NAMES)> == SUB_ASSET_TYPE_COUNT);
|
||||
} // namespace
|
||||
|
||||
@@ -86,6 +86,7 @@ namespace T6
|
||||
SUB_ASSET_TYPE_VERTEX_DECL,
|
||||
SUB_ASSET_TYPE_VERTEX_SHADER,
|
||||
SUB_ASSET_TYPE_PIXEL_SHADER,
|
||||
SUB_ASSET_TYPE_FLAME_TABLE,
|
||||
|
||||
SUB_ASSET_TYPE_COUNT
|
||||
};
|
||||
@@ -292,6 +293,7 @@ namespace T6
|
||||
using SubAssetVertexDecl = SubAsset<SUB_ASSET_TYPE_VERTEX_DECL, MaterialVertexDeclaration>;
|
||||
using SubAssetVertexShader = SubAsset<SUB_ASSET_TYPE_VERTEX_SHADER, MaterialVertexShader>;
|
||||
using SubAssetPixelShader = SubAsset<SUB_ASSET_TYPE_PIXEL_SHADER, MaterialPixelShader>;
|
||||
using SubAssetFlameTable = SubAsset<SUB_ASSET_TYPE_FLAME_TABLE, FlameTable>;
|
||||
} // namespace T6
|
||||
|
||||
DEFINE_ASSET_NAME_ACCESSOR(T6::AssetPhysPreset, name);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
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_PRESET = "PHYSIC";
|
||||
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 },
|
||||
};
|
||||
}
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "Weapon/AttachmentUniqueGdtLoaderT6.h"
|
||||
#include "Weapon/AttachmentUniqueRawLoaderT6.h"
|
||||
#include "Weapon/CamoJsonLoaderT6.h"
|
||||
#include "Weapon/FlameTableLoaderT6.h"
|
||||
#include "Weapon/WeaponGdtLoaderT6.h"
|
||||
#include "Weapon/WeaponRawLoaderT6.h"
|
||||
#include "ZBarrier/GdtLoaderZBarrierT6.h"
|
||||
@@ -441,6 +442,7 @@ namespace T6
|
||||
|
||||
collection.AddSubAssetCreator(techset::CreateVertexShaderLoaderT6(memory, searchPath));
|
||||
collection.AddSubAssetCreator(techset::CreatePixelShaderLoaderT6(memory, searchPath));
|
||||
collection.AddSubAssetCreator(weapon::CreateFlameTableLoaderT6(memory, searchPath, zone));
|
||||
}
|
||||
} // 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/WeaponStrings.h"
|
||||
#include "Utils/Logging/Log.h"
|
||||
#include "Utils/StringUtils.h"
|
||||
#include "Weapon/AccuracyGraphLoader.h"
|
||||
|
||||
#include <cassert>
|
||||
@@ -442,6 +443,32 @@ namespace
|
||||
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)
|
||||
{
|
||||
weapon.weapVariantDef.weapDef = &weapon.weapDef;
|
||||
@@ -462,25 +489,109 @@ namespace
|
||||
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;
|
||||
for (auto i = 1u; i < sizeof(WeaponVariantDef::iAttachments) * 8; i++) // Bit for default attachment always 0
|
||||
{
|
||||
if (weapon.attachments[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)
|
||||
@@ -625,10 +736,27 @@ namespace weapon
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
CalculateWeaponFields(*weaponFullDef);
|
||||
CalculateAttachmentFields(*weaponFullDef);
|
||||
if (!LoadAccuracyGraphs(*weaponFullDef, m_memory, m_search_path, context))
|
||||
{
|
||||
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)));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "WeaponDumperT6.h"
|
||||
|
||||
#include "Dumping/SubAssetDeduplicationDumperState.h"
|
||||
#include "Game/T6/InfoString/InfoStringFromStructConverter.h"
|
||||
#include "Game/T6/ObjConstantsT6.h"
|
||||
#include "Game/T6/Weapon/FlameTableFields.h"
|
||||
#include "Game/T6/Weapon/WeaponFields.h"
|
||||
#include "Game/T6/Weapon/WeaponStrings.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 graph;
|
||||
@@ -457,6 +477,47 @@ namespace
|
||||
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 weapon
|
||||
@@ -485,5 +546,6 @@ namespace weapon
|
||||
}
|
||||
|
||||
DumpAccuracyGraphs(context, asset);
|
||||
DumpFlameTables(context, asset);
|
||||
}
|
||||
} // namespace weapon
|
||||
|
||||
Reference in New Issue
Block a user