From d596cdc97b4b46c90210c22e929812ef4ec0d481 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 28 Nov 2016 21:18:14 +0100 Subject: [PATCH] [ZoneBuilder] Add interface for FxEffectDef Soundaliases are missing, so the game will complain about missing sounds! --- src/Components/Modules/AssetHandler.cpp | 1 + src/Components/Modules/AssetHandler.hpp | 1 + .../Modules/AssetInterfaces/IFxEffectDef.cpp | 343 ++++++++++++++++++ .../Modules/AssetInterfaces/IFxEffectDef.hpp | 15 + src/Game/Structs.hpp | 7 +- 5 files changed, 365 insertions(+), 2 deletions(-) create mode 100644 src/Components/Modules/AssetInterfaces/IFxEffectDef.cpp create mode 100644 src/Components/Modules/AssetInterfaces/IFxEffectDef.hpp diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index 2ab40fb9..3e7e9b90 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -391,6 +391,7 @@ namespace Components AssetHandler::RegisterInterface(new Assets::IMaterial()); AssetHandler::RegisterInterface(new Assets::IPhysPreset()); AssetHandler::RegisterInterface(new Assets::IXAnimParts()); + AssetHandler::RegisterInterface(new Assets::IFxEffectDef()); AssetHandler::RegisterInterface(new Assets::IPhysCollmap()); AssetHandler::RegisterInterface(new Assets::IStringTable()); //AssetHandler::RegisterInterface(new Assets::IXModelSurfs()); diff --git a/src/Components/Modules/AssetHandler.hpp b/src/Components/Modules/AssetHandler.hpp index e80ec0bd..ceb43cbb 100644 --- a/src/Components/Modules/AssetHandler.hpp +++ b/src/Components/Modules/AssetHandler.hpp @@ -75,6 +75,7 @@ namespace Components #include "AssetInterfaces\IMaterial.hpp" #include "AssetInterfaces\IPhysPreset.hpp" #include "AssetInterfaces\IXAnimParts.hpp" +#include "AssetInterfaces\IFxEffectDef.hpp" #include "AssetInterfaces\IPhysCollmap.hpp" #include "AssetInterfaces\IStringTable.hpp" #include "AssetInterfaces\IXModelSurfs.hpp" diff --git a/src/Components/Modules/AssetInterfaces/IFxEffectDef.cpp b/src/Components/Modules/AssetInterfaces/IFxEffectDef.cpp new file mode 100644 index 00000000..e13cf5b1 --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IFxEffectDef.cpp @@ -0,0 +1,343 @@ +#include + +namespace Assets +{ + void IFxEffectDef::markFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder) + { + switch (elemType) + { + case 7: + { + if (visuals->xmodel) + { + builder->loadAsset(Game::XAssetType::ASSET_TYPE_XMODEL, visuals->xmodel->name); + } + + break; + } + + case 8: + case 9: + break; + + case 0xA: + { + // TODO: Load sound here as soon as soundaliases are supported! + break; + } + + case 0xC: + { + if (visuals->effectDef) + { + builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, visuals->effectDef->name); + } + + break; + } + + default: + { + if (visuals->material) + { + builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, visuals->material->name); + } + + break; + } + } + } + + void IFxEffectDef::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) + { + Game::FxEffectDef* asset = header.fx; + + for (int i = 0; i < (asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot); ++i) + { + Game::FxElemDef* elemDef = &asset->elemDefs[i]; + + { + if (elemDef->elemType == 11) + { + if (elemDef->visuals.markArray) + { + for (char j = 0; j < elemDef->visualCount; ++j) + { + builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, elemDef->visuals.markArray[j].data[0]->name); + builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, elemDef->visuals.markArray[j].data[1]->name); + } + } + } + else if (elemDef->visualCount > 1) + { + if (elemDef->visuals.array) + { + for (char j = 0; j < elemDef->visualCount; ++j) + { + this->markFxElemVisuals(&elemDef->visuals.array[j], elemDef->elemType, builder); + } + } + } + else + { + this->markFxElemVisuals(&elemDef->visuals.instance, elemDef->elemType, builder); + } + } + + if (elemDef->effectOnImpact) + { + builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, elemDef->effectOnImpact->name); + } + + if (elemDef->effectOnDeath) + { + builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, elemDef->effectOnDeath->name); + } + + if (elemDef->effectEmitted) + { + builder->loadAsset(Game::XAssetType::ASSET_TYPE_FX, elemDef->effectEmitted->name); + } + } + } + + void IFxEffectDef::saveFxElemVisuals(Game::FxElemVisuals* visuals, Game::FxElemVisuals* destVisuals, char elemType, Components::ZoneBuilder::Zone* builder) + { + Utils::Stream* buffer = builder->getBuffer(); + + switch (elemType) + { + case 7: + { + if (visuals->xmodel) + { + destVisuals->xmodel = builder->requireAsset(Game::XAssetType::ASSET_TYPE_XMODEL, visuals->xmodel->name).model; + } + + break; + } + + case 8: + case 9: + break; + + case 0xA: + { + if (visuals->soundName) + { + buffer->saveString(visuals->soundName); + Utils::Stream::ClearPointer(&destVisuals->soundName); + } + + break; + } + + case 0xC: + { + if (visuals->effectDef) + { + buffer->saveString(visuals->effectDef->name); + Utils::Stream::ClearPointer(&destVisuals->effectDef); + } + + break; + } + + default: + { + if (visuals->material) + { + destVisuals->material = builder->requireAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, visuals->material->name).material; + } + + break; + } + } + } + + void IFxEffectDef::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) + { + AssertSize(Game::FxEffectDef, 32); + + Utils::Stream* buffer = builder->getBuffer(); + Game::FxEffectDef* asset = header.fx; + Game::FxEffectDef* dest = buffer->dest(); + buffer->save(asset); + + buffer->pushBlock(Game::XFILE_BLOCK_VIRTUAL); + + if (asset->name) + { + buffer->saveString(builder->getAssetName(this->getType(), asset->name)); + Utils::Stream::ClearPointer(&dest->name); + } + + if (asset->elemDefs) + { + AssertSize(Game::FxElemDef, 252); + buffer->align(Utils::Stream::ALIGN_4); + + Game::FxElemDef* destElemDefs = buffer->dest(); + buffer->saveArray(asset->elemDefs, asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot); + + for (int i = 0; i < (asset->elemDefCountEmission + asset->elemDefCountLooping + asset->elemDefCountOneShot); ++i) + { + Game::FxElemDef* destElemDef = &destElemDefs[i]; + Game::FxElemDef* elemDef = &asset->elemDefs[i]; + + if (elemDef->velSamples) + { + AssertSize(Game::FxElemVelStateSample, 96); + buffer->align(Utils::Stream::ALIGN_4); + + buffer->saveArray(elemDef->velSamples, elemDef->velIntervalCount + 1); + + Utils::Stream::ClearPointer(&destElemDef->velSamples); + } + + if (elemDef->visSamples) + { + AssertSize(Game::FxElemVisStateSample, 48); + buffer->align(Utils::Stream::ALIGN_4); + + buffer->saveArray(elemDef->visSamples, elemDef->visStateIntervalCount + 1); + + Utils::Stream::ClearPointer(&destElemDef->visSamples); + } + + // Save_FxElemDefVisuals + { + if (elemDef->elemType == 11) + { + if (elemDef->visuals.markArray) + { + AssertSize(Game::FxElemMarkVisuals, 8); + buffer->align(Utils::Stream::ALIGN_4); + + Game::FxElemMarkVisuals* destMarkArray = buffer->dest(); + buffer->saveArray(elemDef->visuals.markArray, elemDef->visualCount); + + for (char j = 0; j < elemDef->visualCount; ++j) + { + if (elemDef->visuals.markArray[j].data[0]) + { + destMarkArray[j].data[0] = builder->requireAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, elemDef->visuals.markArray[j].data[0]->name).material; + } + + if (elemDef->visuals.markArray[j].data[1]) + { + destMarkArray[j].data[1] = builder->requireAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, elemDef->visuals.markArray[j].data[1]->name).material; + } + } + + Utils::Stream::ClearPointer(&destElemDef->visuals.markArray); + } + } + else if(elemDef->visualCount > 1) + { + if (elemDef->visuals.array) + { + AssertSize(Game::FxElemVisuals, 4); + buffer->align(Utils::Stream::ALIGN_4); + + Game::FxElemVisuals* destVisuals = buffer->dest(); + buffer->saveArray(elemDef->visuals.array, elemDef->visualCount); + + for (char j = 0; j < elemDef->visualCount; ++j) + { + this->saveFxElemVisuals(&elemDef->visuals.array[j], &destVisuals[j], elemDef->elemType, builder); + } + + Utils::Stream::ClearPointer(&destElemDef->visuals.array); + } + } + else + { + this->saveFxElemVisuals(&elemDef->visuals.instance, &destElemDef->visuals.instance, elemDef->elemType, builder); + } + } + + if (elemDef->effectOnImpact) + { + buffer->saveString(elemDef->effectOnImpact->name); + Utils::Stream::ClearPointer(&destElemDef->effectOnImpact); + } + + if (elemDef->effectOnDeath) + { + buffer->saveString(elemDef->effectOnDeath->name); + Utils::Stream::ClearPointer(&destElemDef->effectOnDeath); + } + + if (elemDef->effectEmitted) + { + buffer->saveString(elemDef->effectEmitted->name); + Utils::Stream::ClearPointer(&destElemDef->effectEmitted); + } + + // Save_FxElemExtendedDefPtr + { + AssertSize(Game::FxElemExtendedDef, 4); + + if (elemDef->elemType == 3) + { + // Save_FxTrailDef + { + if (elemDef->extendedDef.trailDef) + { + AssertSize(Game::FxTrailDef, 36); + buffer->align(Utils::Stream::ALIGN_4); + + Game::FxTrailDef* trailDef = elemDef->extendedDef.trailDef; + Game::FxTrailDef* destTrailDef = buffer->dest(); + buffer->save(trailDef); + + if (trailDef->verts) + { + AssertSize(Game::FxTrailVertex, 20); + buffer->align(Utils::Stream::ALIGN_4); + + buffer->saveArray(trailDef->verts, trailDef->vertCount); + Utils::Stream::ClearPointer(&destTrailDef->verts); + } + + if (trailDef->inds) + { + buffer->align(Utils::Stream::ALIGN_2); + + buffer->saveArray(trailDef->inds, trailDef->indCount); + Utils::Stream::ClearPointer(&destTrailDef->inds); + } + + Utils::Stream::ClearPointer(&destElemDef->extendedDef.trailDef); + } + } + } + else if (elemDef->elemType == 6) + { + if (elemDef->extendedDef.sparkFountain) + { + AssertSize(Game::FxSparkFountain, 52); + buffer->align(Utils::Stream::ALIGN_4); + + buffer->save(elemDef->extendedDef.sparkFountain); + Utils::Stream::ClearPointer(&destElemDef->extendedDef.sparkFountain); + } + } + else + { + if (elemDef->extendedDef.unknownBytes) + { + buffer->save(elemDef->extendedDef.unknownBytes); + Utils::Stream::ClearPointer(&destElemDef->extendedDef.unknownBytes); + } + } + } + } + + Utils::Stream::ClearPointer(&dest->elemDefs); + } + + buffer->popBlock(); + } +} diff --git a/src/Components/Modules/AssetInterfaces/IFxEffectDef.hpp b/src/Components/Modules/AssetInterfaces/IFxEffectDef.hpp new file mode 100644 index 00000000..145aa339 --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IFxEffectDef.hpp @@ -0,0 +1,15 @@ +namespace Assets +{ + class IFxEffectDef : public Components::AssetHandler::IAsset + { + public: + virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FX; }; + + virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + + private: + void markFxElemVisuals(Game::FxElemVisuals* visuals, char elemType, Components::ZoneBuilder::Zone* builder); + void saveFxElemVisuals(Game::FxElemVisuals* visuals, Game::FxElemVisuals* destVisuals, char elemType, Components::ZoneBuilder::Zone* builder); + }; +} diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 25ddc485..78cd700d 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -1921,9 +1921,12 @@ namespace Game struct FxTrailVertex { + /* float pos[2]; float normal[2]; float texCoord[2]; + */ + char pad[20]; }; struct FxTrailDef @@ -1956,7 +1959,7 @@ namespace Game float sparkFountainBoostFactor; }; - union unknownFxUnion + union FxElemExtendedDef { char *unknownBytes; FxSparkFountain *sparkFountain; @@ -2037,7 +2040,7 @@ namespace Game FxEffectDefRef *effectEmitted; FxFloatRange emitDist; FxFloatRange emitDistVariance; - unknownFxUnion *trailDef; + FxElemExtendedDef extendedDef; //If elemType == 3, then use trailDef //If elemType == 6, then use sparkFountain //If elemType != 3 && elemType != 6 use unknownBytes (size = 1)