diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index e12506aa..b4d461db 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -384,6 +384,7 @@ namespace Components if (ZoneBuilder::IsEnabled()) { AssetHandler::RegisterInterface(new Assets::IXModel()); + AssetHandler::RegisterInterface(new Assets::IFxWorld()); AssetHandler::RegisterInterface(new Assets::IMapEnts()); AssetHandler::RegisterInterface(new Assets::IRawFile()); AssetHandler::RegisterInterface(new Assets::IComWorld()); diff --git a/src/Components/Modules/AssetHandler.hpp b/src/Components/Modules/AssetHandler.hpp index ff7e4522..5d335f7d 100644 --- a/src/Components/Modules/AssetHandler.hpp +++ b/src/Components/Modules/AssetHandler.hpp @@ -71,6 +71,7 @@ namespace Components } #include "AssetInterfaces\IXModel.hpp" +#include "AssetInterfaces\IFxWorld.hpp" #include "AssetInterfaces\IMapEnts.hpp" #include "AssetInterfaces\IRawFile.hpp" #include "AssetInterfaces\IComWorld.hpp" diff --git a/src/Components/Modules/AssetInterfaces/IFxWorld.cpp b/src/Components/Modules/AssetInterfaces/IFxWorld.cpp new file mode 100644 index 00000000..af7384a8 --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IFxWorld.cpp @@ -0,0 +1,177 @@ +#include + +namespace Assets +{ + void IFxWorld::save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) + { + AssertSize(Game::FxWorld, 116); + + Utils::Stream* buffer = builder->getBuffer(); + SAVE_LOG_ENTER("FxWorld"); + Game::FxWorld* asset = header.fxWorld; + Game::FxWorld* 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); + } + + // saveFxGlassSystem + { + AssertSize(Game::FxGlassSystem, 112); + if(asset->glassSys.defs) + { + AssertSize(Game::FxGlassDef, 36); + + buffer->align(Utils::Stream::ALIGN_4); + Game::FxGlassDef* glassDefTable = buffer->dest(); + buffer->saveArray(asset->glassSys.defs, asset->glassSys.defCount); + + for (unsigned int i = 0; i < asset->glassSys.defCount; ++i) + { + Game::FxGlassDef* glassDef = &asset->glassSys.defs[i]; + Game::FxGlassDef* destGlassDef = &glassDefTable[i]; + + if (glassDef->physPreset) + { + destGlassDef->physPreset = builder->requireAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, glassDef->physPreset->name).physPreset; + } + + if (glassDef->material) + { + destGlassDef->material = builder->requireAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, glassDef->material->name).material; + } + + if (glassDef->materialShattered) + { + destGlassDef->materialShattered = builder->requireAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, glassDef->materialShattered->name).material; + } + } + + } + + buffer->pushBlock(Game::XFILE_BLOCK_RUNTIME); + + if (asset->glassSys.piecePlaces) + { + AssertSize(Game::FxGlassPiecePlace, 32); + + buffer->align(Utils::Stream::ALIGN_4); + buffer->saveArray(asset->glassSys.piecePlaces, asset->glassSys.pieceLimit); + Utils::Stream::ClearPointer(&dest->glassSys.piecePlaces); + } + + if (asset->glassSys.pieceStates) + { + AssertSize(Game::FxGlassPieceState, 32); + + buffer->align(Utils::Stream::ALIGN_4); + buffer->saveArray(asset->glassSys.pieceStates, asset->glassSys.pieceLimit); + Utils::Stream::ClearPointer(&dest->glassSys.pieceStates); + } + + if (asset->glassSys.pieceDynamics) + { + AssertSize(Game::FxGlassPieceDynamics, 36); + + buffer->align(Utils::Stream::ALIGN_4); + buffer->saveArray(asset->glassSys.pieceDynamics, asset->glassSys.pieceLimit); + Utils::Stream::ClearPointer(&dest->glassSys.pieceDynamics); + } + + if (asset->glassSys.geoData) + { + AssertSize(Game::FxGlassGeometryData, 4); + + buffer->align(Utils::Stream::ALIGN_4); + buffer->saveArray(asset->glassSys.geoData, asset->glassSys.geoDataLimit); + Utils::Stream::ClearPointer(&dest->glassSys.geoData); + } + + if (asset->glassSys.isInUse) + { + buffer->align(Utils::Stream::ALIGN_4); + buffer->saveArray(asset->glassSys.isInUse, asset->glassSys.pieceWordCount); + Utils::Stream::ClearPointer(&dest->glassSys.isInUse); + } + + if (asset->glassSys.cellBits) + { + buffer->align(Utils::Stream::ALIGN_4); + buffer->saveArray(asset->glassSys.cellBits, asset->glassSys.pieceWordCount * asset->glassSys.cellCount); + Utils::Stream::ClearPointer(&dest->glassSys.cellBits); + } + + if (asset->glassSys.visData) + { + buffer->align(Utils::Stream::ALIGN_16); + buffer->save(asset->glassSys.visData, 1, (asset->glassSys.pieceLimit + 15) & 0xFFFFFFF0); + Utils::Stream::ClearPointer(&dest->glassSys.visData); + } + + if (asset->glassSys.linkOrg) + { + buffer->align(Utils::Stream::ALIGN_4); + buffer->saveArray(asset->glassSys.linkOrg, asset->glassSys.pieceLimit); + Utils::Stream::ClearPointer(&dest->glassSys.linkOrg); + } + + if (asset->glassSys.halfThickness) + { + buffer->align(Utils::Stream::ALIGN_16); + buffer->save(asset->glassSys.halfThickness, 1, ((4 * asset->glassSys.pieceLimit) + 12) & 0xFFFFFFF0); + Utils::Stream::ClearPointer(&dest->glassSys.halfThickness); + } + + buffer->popBlock(); + + if (asset->glassSys.lightingHandles) + { + buffer->align(Utils::Stream::ALIGN_2); + buffer->saveArray(asset->glassSys.lightingHandles, asset->glassSys.initPieceCount); + Utils::Stream::ClearPointer(&dest->glassSys.lightingHandles); + } + + if (asset->glassSys.initPieceStates) + { + AssertSize(Game::FxGlassInitPieceState, 52); + + buffer->align(Utils::Stream::ALIGN_4); + buffer->saveArray(asset->glassSys.initPieceStates, asset->glassSys.initPieceCount); + Utils::Stream::ClearPointer(&dest->glassSys.initPieceStates); + } + + if (asset->glassSys.initGeoData) + { + buffer->align(Utils::Stream::ALIGN_4); + buffer->saveArray(asset->glassSys.initGeoData, asset->glassSys.initGeoDataCount); + Utils::Stream::ClearPointer(&dest->glassSys.initGeoData); + } + } + } + void IFxWorld::mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) + { + Game::FxWorld* asset = header.fxWorld; + + if (asset->glassSys.defs) + { + for (unsigned int i = 0; i < asset->glassSys.defCount; ++i) + { + builder->loadAsset(Game::XAssetType::ASSET_TYPE_PHYSPRESET, asset->glassSys.defs[i].physPreset->name); + builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->glassSys.defs[i].material->name); + builder->loadAsset(Game::XAssetType::ASSET_TYPE_MATERIAL, asset->glassSys.defs[i].materialShattered->name); + } + } + } + void IFxWorld::load(Game::XAssetHeader* /*header*/, std::string name, Components::ZoneBuilder::Zone* /*builder*/) + { + Game::FxWorld* map = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_FX_MAP, name.data()).fxWorld; + if (map) return; + + Components::Logger::Error("Missing fx_map %s... you can't make them yet you idiot.", name.data()); + } +} diff --git a/src/Components/Modules/AssetInterfaces/IFxWorld.hpp b/src/Components/Modules/AssetInterfaces/IFxWorld.hpp new file mode 100644 index 00000000..588a737b --- /dev/null +++ b/src/Components/Modules/AssetInterfaces/IFxWorld.hpp @@ -0,0 +1,12 @@ +namespace Assets +{ + class IFxWorld : public Components::AssetHandler::IAsset + { + public: + virtual Game::XAssetType getType() override { return Game::XAssetType::ASSET_TYPE_FX_MAP; }; + + virtual void save(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + virtual void mark(Game::XAssetHeader header, Components::ZoneBuilder::Zone* builder) override; + virtual void load(Game::XAssetHeader* header, std::string name, Components::ZoneBuilder::Zone* builder) override; + }; +} diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index f369ed64..be10fdcc 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -3211,6 +3211,144 @@ namespace Game ComPrimaryLight* lights; }; +#pragma pack(push, 4) + struct FxGlassDef + { + float halfThickness; + float texVecs[2][2]; + GfxColor color; + Material *material; + Material *materialShattered; + PhysPreset *physPreset; + }; +#pragma pack(pop) + + struct FxSpatialFrame + { + float quat[4]; + float origin[3]; + }; + + union FxGlassPiecePlace + { + struct + { + FxSpatialFrame frame; + float radius; + }; + unsigned int nextFree; + }; + + struct FxGlassPieceState + { + float texCoordOrigin[2]; + unsigned int supportMask; + unsigned __int16 initIndex; + unsigned __int16 geoDataStart; + unsigned __int16 lightingIndex; + char defIndex; + char pad[3]; + char vertCount; + char holeDataCount; + char crackDataCount; + char fanDataCount; + unsigned __int16 flags; + float areaX2; + }; + + struct FxGlassPieceDynamics + { + char pad[36]; + }; + + struct FxGlassVertex + { + __int16 x; + __int16 y; + }; + + struct FxGlassHoleHeader + { + unsigned __int16 uniqueVertCount; + char touchVert; + char pad[1]; + }; + + struct FxGlassCrackHeader + { + unsigned __int16 uniqueVertCount; + char beginVertIndex; + char endVertIndex; + }; + + union FxGlassGeometryData + { + FxGlassVertex vert; + FxGlassHoleHeader hole; + FxGlassCrackHeader crack; + char asBytes[4]; + __int16 anonymous[2]; + }; + +#pragma pack(push, 4) + struct FxGlassInitPieceState //Note, on MW3 this is missing 4 bytes, just not sure whats missing yet + { + /* + FxSpatialFrame frame; + float radius; + float texCoordOrigin[2]; + unsigned int supportMask; + float areaX2; + unsigned __int16 lightingIndex; + char defIndex; + char vertCount; + char fanDataCount; + */ + char pad[52]; + }; +#pragma pack(pop) + +#pragma pack(push, 8) + struct FxGlassSystem + { + int time; + int prevTime; + unsigned int defCount; + unsigned int pieceLimit; + unsigned int pieceWordCount; + unsigned int initPieceCount; + unsigned int cellCount; + unsigned int activePieceCount; + unsigned int firstFreePiece; + unsigned int geoDataLimit; + unsigned int geoDataCount; + unsigned int initGeoDataCount; + FxGlassDef *defs; + FxGlassPiecePlace *piecePlaces; + FxGlassPieceState *pieceStates; + FxGlassPieceDynamics *pieceDynamics; + FxGlassGeometryData *geoData; + unsigned int *isInUse; + unsigned int *cellBits; + char *visData; + float (*linkOrg)[3]; + float *halfThickness; + unsigned __int16 *lightingHandles; + FxGlassInitPieceState *initPieceStates; + FxGlassGeometryData *initGeoData; + bool needToCompactData; + char initCount; + float effectChanceAccum; + int lastPieceDeletionTime; + }; +#pragma pack(pop) + + struct FxWorld + { + const char * name; + FxGlassSystem glassSys; + }; + union XAssetHeader { void *data; @@ -3241,6 +3379,7 @@ namespace Game GameWorldSp* gameWorldSp; TracerDef* tracer; VehicleDef* vehicle; + FxWorld* fxWorld; GfxWorld* gfxWorld; GfxLightDef* lightDef; SndCurve* sndCurve; diff --git a/src/Utils/Stream.cpp b/src/Utils/Stream.cpp index 0cb6c995..4f2c7f24 100644 --- a/src/Utils/Stream.cpp +++ b/src/Utils/Stream.cpp @@ -112,8 +112,8 @@ namespace Utils char* Stream::save(Game::XFILE_BLOCK_TYPES stream, const void * _str, size_t size, size_t count) { // Only those seem to actually write data. - // As I'm not sure though, I'll still write the data - // Use IncreaseBlockSize to fill virtual streams + // everything else is allocated at runtime but XFILE_BLOCK_RUNTIME is the only one that actually allocates anything + // clearly half of this stuff is unused if (stream != Game::XFILE_BLOCK_TEMP && stream != Game::XFILE_BLOCK_VIRTUAL && stream != Game::XFILE_BLOCK_PHYSICAL && stream != Game::XFILE_BLOCK_INVALID) { this->increaseBlockSize(stream, size * count);