Dump and load iw4 physpresets

This commit is contained in:
Jan 2022-01-02 10:25:48 +01:00
parent 87c2e58c4b
commit bcafddd83a
9 changed files with 496 additions and 3 deletions

View File

@ -181,6 +181,21 @@ namespace IW4
bool perSurfaceSndAlias;
};
struct PhysPresetInfo
{
float mass;
float bounce;
float friction;
int isFrictionInfinity;
float bulletForceScale;
float explosiveForceScale;
const char* sndAliasPrefix;
float piecesSpreadFraction;
float piecesUpwardVelocity;
int tempDefaultToCylinder;
int perSurfaceSndAlias;
};
struct Bounds
{
float midPoint[3];

View File

@ -0,0 +1,20 @@
#pragma once
#include "Game/IW4/IW4.h"
namespace IW4
{
inline cspField_t phys_preset_fields[]
{
{ "mass", offsetof(PhysPresetInfo, mass), CSPFT_FLOAT },
{ "bounce", offsetof(PhysPresetInfo, bounce), CSPFT_FLOAT },
{ "friction", offsetof(PhysPresetInfo, friction), CSPFT_FLOAT },
{ "isFrictionInfinity", offsetof(PhysPresetInfo, isFrictionInfinity), CSPFT_QBOOLEAN },
{ "bulletForceScale", offsetof(PhysPresetInfo, bulletForceScale), CSPFT_FLOAT },
{ "explosiveForceScale", offsetof(PhysPresetInfo, explosiveForceScale), CSPFT_FLOAT },
{ "sndAliasPrefix", offsetof(PhysPresetInfo, sndAliasPrefix), CSPFT_STRING },
{ "piecesSpreadFraction", offsetof(PhysPresetInfo, piecesSpreadFraction), CSPFT_FLOAT },
{ "piecesUpwardVelocity", offsetof(PhysPresetInfo, piecesUpwardVelocity), CSPFT_FLOAT },
{ "tempDefaultToCylinder", offsetof(PhysPresetInfo, tempDefaultToCylinder), CSPFT_QBOOLEAN },
{ "perSurfaceSndAlias", offsetof(PhysPresetInfo, perSurfaceSndAlias), CSPFT_QBOOLEAN },
};
}

View File

@ -1,13 +1,77 @@
#include "AssetLoaderPhysPreset.h"
#include <cstring>
#include <iostream>
#include "ObjLoading.h"
#include "Game/IW4/IW4.h"
#include "Game/IW4/ObjConstantsIW4.h"
#include "Game/IW4/InfoString/InfoStringToStructConverter.h"
#include "Game/IW4/InfoString/PhysPresetFields.h"
#include "Pool/GlobalAssetPool.h"
using namespace IW4;
namespace IW4
{
class InfoStringToPhysPresetConverter final : public InfoStringToStructConverter
{
protected:
bool ConvertExtensionField(const cspField_t& field, const std::string& value) override
{
assert(false);
return false;
}
public:
InfoStringToPhysPresetConverter(const InfoString& infoString, PhysPresetInfo* physPreset, ZoneScriptStrings& zoneScriptStrings, MemoryManager* memory, IAssetLoadingManager* manager,
const cspField_t* fields, const size_t fieldCount)
: InfoStringToStructConverter(infoString, physPreset, zoneScriptStrings, memory, manager, fields, fieldCount)
{
}
};
}
void AssetLoaderPhysPreset::CopyFromPhysPresetInfo(const PhysPresetInfo* physPresetInfo, PhysPreset* physPreset)
{
physPreset->mass = std::clamp(physPresetInfo->mass, 1.0f, 2000.0f) * 0.001f;
physPreset->bounce = physPresetInfo->bounce;
if (physPresetInfo->isFrictionInfinity != 0)
physPreset->friction = std::numeric_limits<float>::infinity();
else
physPreset->friction = physPresetInfo->friction;
physPreset->bulletForceScale = physPresetInfo->bulletForceScale;
physPreset->explosiveForceScale = physPresetInfo->explosiveForceScale;
physPreset->sndAliasPrefix = physPresetInfo->sndAliasPrefix;
physPreset->piecesSpreadFraction = physPresetInfo->piecesSpreadFraction;
physPreset->piecesUpwardVelocity = physPresetInfo->piecesUpwardVelocity;
physPreset->tempDefaultToCylinder = physPresetInfo->tempDefaultToCylinder != 0;
physPreset->perSurfaceSndAlias = physPresetInfo->perSurfaceSndAlias != 0;
}
bool AssetLoaderPhysPreset::LoadFromInfoString(const InfoString& infoString, const std::string& assetName, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone)
{
const auto presetInfo = std::make_unique<PhysPresetInfo>();
memset(presetInfo.get(), 0, sizeof(PhysPresetInfo));
InfoStringToPhysPresetConverter converter(infoString, presetInfo.get(), zone->m_script_strings, memory, manager, phys_preset_fields, std::extent<decltype(phys_preset_fields)>::value);
if (!converter.Convert())
{
std::cout << "Failed to parse phys preset: \"" << assetName << "\"" << std::endl;
return true;
}
auto* physPreset = memory->Create<PhysPreset>();
CopyFromPhysPresetInfo(presetInfo.get(), physPreset);
physPreset->name = memory->Dup(assetName.c_str());
manager->AddAsset(ASSET_TYPE_PHYSPRESET, assetName, physPreset, converter.GetDependencies(), converter.GetUsedScriptStrings());
return true;
}
void* AssetLoaderPhysPreset::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory)
{
auto* physPreset = memory->Create<PhysPreset>();
@ -15,3 +79,47 @@ void* AssetLoaderPhysPreset::CreateEmptyAsset(const std::string& assetName, Memo
physPreset->name = memory->Dup(assetName.c_str());
return physPreset;
}
bool AssetLoaderPhysPreset::CanLoadFromGdt() const
{
return true;
}
bool AssetLoaderPhysPreset::LoadFromGdt(const std::string& assetName, IGdtQueryable* gdtQueryable, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
{
auto* gdtEntry = gdtQueryable->GetGdtEntryByGdfAndName(ObjConstants::GDF_FILENAME_PHYS_PRESET, assetName);
if (gdtEntry == nullptr)
return false;
InfoString infoString;
if (!infoString.FromGdtProperties(*gdtEntry))
{
std::cout << "Failed to read phys preset gdt entry: \"" << assetName << "\"" << std::endl;
return true;
}
return LoadFromInfoString(infoString, assetName, memory, manager, zone);
}
bool AssetLoaderPhysPreset::CanLoadFromRaw() const
{
return true;
}
bool AssetLoaderPhysPreset::LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const
{
const auto fileName = "physic/" + assetName;
const auto file = searchPath->Open(fileName);
if (!file.IsOpen())
return false;
InfoString infoString;
if (!infoString.FromStream(ObjConstants::INFO_STRING_PREFIX_PHYS_PRESET, *file.m_stream))
{
std::cout << "Failed to read phys preset raw file: \"" << fileName << "\"" << std::endl;
return true;
}
return LoadFromInfoString(infoString, assetName, memory, manager, zone);
}

View File

@ -2,13 +2,22 @@
#include "Game/IW4/IW4.h"
#include "AssetLoading/BasicAssetLoader.h"
#include "InfoString/InfoString.h"
#include "SearchPath/ISearchPath.h"
namespace IW4
{
class AssetLoaderPhysPreset final : public BasicAssetLoader<ASSET_TYPE_PHYSPRESET, PhysPreset>
{
static void CopyFromPhysPresetInfo(const PhysPresetInfo* physPresetInfo, PhysPreset* physPreset);
static bool LoadFromInfoString(const InfoString& infoString, const std::string& assetName, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone);
public:
_NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override;
_NODISCARD bool CanLoadFromGdt() const override;
bool LoadFromGdt(const std::string& assetName, IGdtQueryable* gdtQueryable, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override;
_NODISCARD bool CanLoadFromRaw() const override;
bool LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override;
};
}

View File

@ -1,4 +1,227 @@
#include "InfoStringToStructConverter.h"
#include <cassert>
#include <iostream>
using namespace IW4;
InfoStringToStructConverter::InfoStringToStructConverter(const InfoString& infoString, void* structure, ZoneScriptStrings& zoneScriptStrings, MemoryManager* memory, IAssetLoadingManager* manager,
const cspField_t* fields, const size_t fieldCount)
: InfoStringToStructConverterBase(infoString, structure, zoneScriptStrings, memory),
m_loading_manager(manager),
m_fields(fields),
m_field_count(fieldCount)
{
}
bool InfoStringToStructConverter::ConvertBaseField(const cspField_t& field, const std::string& value)
{
switch (static_cast<csParseFieldType_t>(field.iFieldType))
{
case CSPFT_STRING:
return ConvertString(value, field.iOffset);
case CSPFT_STRING_MAX_STRING_CHARS:
return ConvertStringBuffer(value, field.iOffset, 1024);
case CSPFT_STRING_MAX_QPATH:
return ConvertStringBuffer(value, field.iOffset, 64);
case CSPFT_STRING_MAX_OSPATH:
return ConvertStringBuffer(value, field.iOffset, 256);
case CSPFT_INT:
return ConvertInt(value, field.iOffset);
case CSPFT_BOOL:
return ConvertBool(value, field.iOffset);
case CSPFT_QBOOLEAN:
return ConvertQBoolean(value, field.iOffset);
case CSPFT_FLOAT:
return ConvertFloat(value, field.iOffset);
case CSPFT_MILLISECONDS:
return ConvertMilliseconds(value, field.iOffset);
case CSPFT_FX:
{
if (value.empty())
{
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
return true;
}
auto* fx = m_loading_manager->LoadDependency(ASSET_TYPE_FX, value);
if (fx == nullptr)
{
std::cout << "Failed to load fx asset \"" << value << "\"" << std::endl;
return false;
}
m_dependencies.emplace(fx);
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = fx->m_ptr;
return true;
}
case CSPFT_XMODEL:
{
if (value.empty())
{
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
return true;
}
auto* xmodel = m_loading_manager->LoadDependency(ASSET_TYPE_XMODEL, value);
if (xmodel == nullptr)
{
std::cout << "Failed to load xmodel asset \"" << value << "\"" << std::endl;
return false;
}
m_dependencies.emplace(xmodel);
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = xmodel->m_ptr;
return true;
}
case CSPFT_MATERIAL:
{
if (value.empty())
{
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
return true;
}
auto* material = m_loading_manager->LoadDependency(ASSET_TYPE_MATERIAL, value);
if (material == nullptr)
{
std::cout << "Failed to load material asset \"" << value << "\"" << std::endl;
return false;
}
m_dependencies.emplace(material);
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = material->m_ptr;
return true;
}
case CSPFT_TRACER:
{
if (value.empty())
{
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
return true;
}
auto* tracer = m_loading_manager->LoadDependency(ASSET_TYPE_TRACER, value);
if (tracer == nullptr)
{
std::cout << "Failed to load tracer asset \"" << value << "\"" << std::endl;
return false;
}
m_dependencies.emplace(tracer);
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = tracer->m_ptr;
return true;
}
case CSPFT_MPH_TO_INCHES_PER_SEC:
{
char* endPtr;
*reinterpret_cast<float*>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = strtof(value.c_str(), &endPtr) * 17.6f;
if (endPtr != &value[value.size()])
{
std::cout << "Failed to parse value \"" << value << "\" as mph" << std::endl;
return false;
}
return true;
}
case CSPFT_PHYS_COLLMAP:
{
if (value.empty())
{
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
return true;
}
auto* collmap = m_loading_manager->LoadDependency(ASSET_TYPE_PHYSCOLLMAP, value);
if (collmap == nullptr)
{
std::cout << "Failed to load collmap asset \"" << value << "\"" << std::endl;
return false;
}
m_dependencies.emplace(collmap);
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = collmap->m_ptr;
return true;
}
case CSPFT_SOUND:
{
if (value.empty())
{
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = nullptr;
return true;
}
auto* sound = m_loading_manager->LoadDependency(ASSET_TYPE_SOUND, value);
if (sound == nullptr)
{
std::cout << "Failed to load sound asset \"" << value << "\"" << std::endl;
return false;
}
m_dependencies.emplace(sound);
*reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(m_structure) + field.iOffset) = sound->m_ptr;
return true;
}
case CSPFT_NUM_BASE_FIELD_TYPES:
default:
assert(false);
return false;
}
}
bool InfoStringToStructConverter::Convert()
{
for (auto fieldIndex = 0u; fieldIndex < m_field_count; fieldIndex++)
{
const auto& field = m_fields[fieldIndex];
assert(field.iFieldType >= 0);
auto foundValue = false;
const auto& value = m_info_string.GetValueForKey(std::string(field.szName), &foundValue);
if (foundValue)
{
if (field.iFieldType < CSPFT_NUM_BASE_FIELD_TYPES)
{
if (!ConvertBaseField(field, value))
return false;
}
else
{
if (!ConvertExtensionField(field, value))
return false;
}
}
}
return true;
}

View File

@ -12,8 +12,6 @@ namespace IW4
const cspField_t* m_fields;
size_t m_field_count;
static bool GetHashValue(const std::string& value, unsigned int& hash);
virtual bool ConvertExtensionField(const cspField_t& field, const std::string& value) = 0;
bool ConvertBaseField(const cspField_t& field, const std::string& value);

View File

@ -0,0 +1,101 @@
#include "AssetDumperPhysPreset.h"
#include <algorithm>
#include <cassert>
#include <cmath>
#include <type_traits>
#include "Game/IW4/ObjConstantsIW4.h"
#include "Game/IW4/InfoString/InfoStringFromStructConverter.h"
#include "Game/IW4/InfoString/PhysPresetFields.h"
using namespace IW4;
namespace IW4
{
class InfoStringFromPhysPresetConverter final : public InfoStringFromStructConverter
{
protected:
void FillFromExtensionField(const cspField_t& field) override
{
assert(false);
}
public:
InfoStringFromPhysPresetConverter(const PhysPresetInfo* structure, const cspField_t* fields, const size_t fieldCount, std::function<std::string(scr_string_t)> scriptStringValueCallback)
: InfoStringFromStructConverter(structure, fields, fieldCount, std::move(scriptStringValueCallback))
{
}
};
}
void AssetDumperPhysPreset::CopyToPhysPresetInfo(const PhysPreset* physPreset, PhysPresetInfo* physPresetInfo)
{
physPresetInfo->mass = std::clamp(physPreset->mass * 1000.0f, 1.0f, 2000.0f);
physPresetInfo->bounce = physPreset->bounce;
if (std::isinf(physPreset->friction))
{
physPresetInfo->isFrictionInfinity = 1;
physPresetInfo->friction = 0;
}
else
{
physPresetInfo->isFrictionInfinity = 0;
physPresetInfo->friction = physPreset->friction;
}
physPresetInfo->bulletForceScale = physPreset->bulletForceScale;
physPresetInfo->explosiveForceScale = physPreset->explosiveForceScale;
physPresetInfo->sndAliasPrefix = physPreset->sndAliasPrefix;
physPresetInfo->piecesSpreadFraction = physPreset->piecesSpreadFraction;
physPresetInfo->piecesUpwardVelocity = physPreset->piecesUpwardVelocity;
physPresetInfo->tempDefaultToCylinder = physPreset->tempDefaultToCylinder ? 1 : 0;
physPresetInfo->perSurfaceSndAlias = physPreset->perSurfaceSndAlias ? 1 : 0;
}
InfoString AssetDumperPhysPreset::CreateInfoString(XAssetInfo<PhysPreset>* asset)
{
auto* physPresetInfo = new PhysPresetInfo;
CopyToPhysPresetInfo(asset->Asset(), physPresetInfo);
InfoStringFromPhysPresetConverter converter(physPresetInfo, phys_preset_fields, std::extent<decltype(phys_preset_fields)>::value, [asset](const scr_string_t scrStr) -> std::string
{
assert(scrStr < asset->m_zone->m_script_strings.Count());
if (scrStr >= asset->m_zone->m_script_strings.Count())
return "";
return asset->m_zone->m_script_strings[scrStr];
});
return converter.Convert();
}
bool AssetDumperPhysPreset::ShouldDump(XAssetInfo<PhysPreset>* asset)
{
return true;
}
void AssetDumperPhysPreset::DumpAsset(AssetDumpingContext& context, XAssetInfo<PhysPreset>* asset)
{
// Only dump raw when no gdt available
if (context.m_gdt)
{
const auto infoString = CreateInfoString(asset);
GdtEntry gdtEntry(asset->m_name, ObjConstants::GDF_FILENAME_PHYS_PRESET);
infoString.ToGdtProperties(ObjConstants::INFO_STRING_PREFIX_PHYS_PRESET, gdtEntry);
context.m_gdt->WriteEntry(gdtEntry);
}
else
{
const auto assetFile = context.OpenAssetFile("physic/" + asset->m_name);
if (!assetFile)
return;
auto& stream = *assetFile;
const auto infoString = CreateInfoString(asset);
const auto stringValue = infoString.ToString(ObjConstants::INFO_STRING_PREFIX_PHYS_PRESET);
stream.write(stringValue.c_str(), stringValue.size());
}
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW4/IW4.h"
#include "InfoString/InfoString.h"
namespace IW4
{
class AssetDumperPhysPreset final : public AbstractAssetDumper<PhysPreset>
{
static void CopyToPhysPresetInfo(const PhysPreset* physPreset, PhysPresetInfo* physPresetInfo);
static InfoString CreateInfoString(XAssetInfo<PhysPreset>* asset);
protected:
bool ShouldDump(XAssetInfo<PhysPreset>* asset) override;
void DumpAsset(AssetDumpingContext& context, XAssetInfo<PhysPreset>* asset) override;
};
}

View File

@ -10,6 +10,7 @@
#include "AssetDumpers/AssetDumperLocalizeEntry.h"
#include "AssetDumpers/AssetDumperMenuDef.h"
#include "AssetDumpers/AssetDumperMenuList.h"
#include "AssetDumpers/AssetDumperPhysPreset.h"
#include "AssetDumpers/AssetDumperRawFile.h"
#include "AssetDumpers/AssetDumperStringTable.h"
#include "AssetDumpers/AssetDumperVehicle.h"
@ -34,7 +35,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const
const auto* assetPools = dynamic_cast<GameAssetPoolIW4*>(context.m_zone->m_pools.get());
// DUMP_ASSET_POOL(AssetDumperPhysPreset, m_phys_preset, ASSET_TYPE_PHYSPRESET)
DUMP_ASSET_POOL(AssetDumperPhysPreset, m_phys_preset, ASSET_TYPE_PHYSPRESET)
// DUMP_ASSET_POOL(AssetDumperPhysCollmap, m_phys_collmap, ASSET_TYPE_PHYSCOLLMAP)
// DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts, ASSET_TYPE_XANIMPARTS)
DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel, ASSET_TYPE_XMODEL)