mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
757 lines
42 KiB
C++
757 lines
42 KiB
C++
#include "niffile.hpp"
|
|
|
|
#include <components/debug/debuglog.hpp>
|
|
#include <components/files/hash.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
|
|
#include "controller.hpp"
|
|
#include "data.hpp"
|
|
#include "effect.hpp"
|
|
#include "exception.hpp"
|
|
#include "extra.hpp"
|
|
#include "node.hpp"
|
|
#include "particle.hpp"
|
|
#include "physics.hpp"
|
|
#include "property.hpp"
|
|
#include "texture.hpp"
|
|
|
|
namespace Nif
|
|
{
|
|
|
|
Reader::Reader(NIFFile& file, const ToUTF8::StatelessUtf8Encoder* encoder)
|
|
: mVersion(file.mVersion)
|
|
, mUserVersion(file.mUserVersion)
|
|
, mBethVersion(file.mBethVersion)
|
|
, mFilename(file.mPath)
|
|
, mHash(file.mHash)
|
|
, mRecords(file.mRecords)
|
|
, mRoots(file.mRoots)
|
|
, mUseSkinning(file.mUseSkinning)
|
|
, mEncoder(encoder)
|
|
{
|
|
}
|
|
|
|
template <typename NodeType, RecordType recordType>
|
|
static std::unique_ptr<Record> construct()
|
|
{
|
|
auto result = std::make_unique<NodeType>();
|
|
result->recType = recordType;
|
|
return result;
|
|
}
|
|
|
|
using CreateRecord = std::unique_ptr<Record> (*)();
|
|
|
|
/// These are all the record types we know how to read.
|
|
static std::map<std::string, CreateRecord> makeFactory()
|
|
{
|
|
return {
|
|
// 4.0.0.2 refers to Bethesda variant of NetImmerse 4.0.0.2 file format
|
|
// Gamebryo refers to files newer than 4.0.0.2
|
|
// Bethesda refers to custom records Bethesda introduced post-4.0.0.2
|
|
|
|
// NODES
|
|
|
|
// NiNode-like nodes, 4.0.0.2
|
|
{ "NiNode", &construct<NiNode, RC_NiNode> },
|
|
{ "AvoidNode", &construct<NiNode, RC_AvoidNode> },
|
|
{ "NiBillboardNode", &construct<NiBillboardNode, RC_NiBillboardNode> },
|
|
{ "NiBSAnimationNode", &construct<NiNode, RC_NiBSAnimationNode> },
|
|
{ "NiBSParticleNode", &construct<NiNode, RC_NiBSParticleNode> },
|
|
{ "NiCollisionSwitch", &construct<NiNode, RC_NiCollisionSwitch> },
|
|
{ "NiSortAdjustNode", &construct<NiSortAdjustNode, RC_NiSortAdjustNode> },
|
|
{ "RootCollisionNode", &construct<NiNode, RC_RootCollisionNode> },
|
|
|
|
// NiNode-like nodes, Bethesda
|
|
{ "BSBlastNode", &construct<BSRangeNode, RC_NiNode> },
|
|
{ "BSDamageStage", &construct<BSRangeNode, RC_NiNode> },
|
|
{ "BSDebrisNode", &construct<BSRangeNode, RC_NiNode> },
|
|
{ "BSDistantObjectInstancedNode",
|
|
&construct<BSDistantObjectInstancedNode, RC_BSDistantObjectInstancedNode> },
|
|
{ "BSFadeNode", &construct<NiNode, RC_NiNode> },
|
|
{ "BSLeafAnimNode", &construct<NiNode, RC_NiNode> },
|
|
{ "BSMasterParticleSystem", &construct<BSMasterParticleSystem, RC_NiNode> },
|
|
{ "BSMultiBoundNode", &construct<BSMultiBoundNode, RC_NiNode> },
|
|
{ "BSOrderedNode", &construct<BSOrderedNode, RC_NiNode> },
|
|
{ "BSRangeNode", &construct<BSRangeNode, RC_NiNode> },
|
|
{ "BSTreeNode", &construct<BSTreeNode, RC_NiNode> },
|
|
{ "BSValueNode", &construct<BSValueNode, RC_NiNode> },
|
|
|
|
// Switch nodes, 4.0.0.2
|
|
{ "NiSwitchNode", &construct<NiSwitchNode, RC_NiSwitchNode> },
|
|
{ "NiFltAnimationNode", &construct<NiFltAnimationNode, RC_NiFltAnimationNode> },
|
|
{ "NiLODNode", &construct<NiLODNode, RC_NiLODNode> },
|
|
|
|
// NiSequence nodes, 4.0.0.2
|
|
{ "NiSequenceStreamHelper", &construct<NiSequenceStreamHelper, RC_NiSequenceStreamHelper> },
|
|
|
|
// NiSequence nodes, Gamebryo
|
|
{ "NiSequence", &construct<NiSequence, RC_NiSequence> },
|
|
{ "NiControllerSequence", &construct<NiControllerSequence, RC_NiControllerSequence> },
|
|
|
|
// Other nodes, 4.0.0.2
|
|
{ "NiCamera", &construct<NiCamera, RC_NiCamera> },
|
|
|
|
// ACCUMULATORS
|
|
|
|
// 4.0.0.2
|
|
{ "NiAlphaAccumulator", &construct<NiAlphaAccumulator, RC_NiAlphaAccumulator> },
|
|
{ "NiClusterAccumulator", &construct<NiClusterAccumulator, RC_NiClusterAccumulator> },
|
|
|
|
// CONTROLLERS
|
|
|
|
// 4.0.0.2
|
|
{ "NiAlphaController", &construct<NiAlphaController, RC_NiAlphaController> },
|
|
{ "NiBSPArrayController", &construct<NiBSPArrayController, RC_NiBSPArrayController> },
|
|
{ "NiFlipController", &construct<NiFlipController, RC_NiFlipController> },
|
|
{ "NiGeomMorpherController", &construct<NiGeomMorpherController, RC_NiGeomMorpherController> },
|
|
{ "NiKeyframeController", &construct<NiKeyframeController, RC_NiKeyframeController> },
|
|
{ "NiLookAtController", &construct<NiLookAtController, RC_NiLookAtController> },
|
|
// FIXME: NiLightColorController should have its own struct
|
|
{ "NiLightColorController", &construct<NiMaterialColorController, RC_NiLightColorController> },
|
|
{ "NiMaterialColorController", &construct<NiMaterialColorController, RC_NiMaterialColorController> },
|
|
{ "NiPathController", &construct<NiPathController, RC_NiPathController> },
|
|
{ "NiRollController", &construct<NiRollController, RC_NiRollController> },
|
|
{ "NiUVController", &construct<NiUVController, RC_NiUVController> },
|
|
{ "NiVisController", &construct<NiVisController, RC_NiVisController> },
|
|
|
|
// Gamebryo
|
|
{ "NiBoneLODController", &construct<NiBoneLODController, RC_NiBoneLODController> },
|
|
{ "NiControllerManager", &construct<NiControllerManager, RC_NiControllerManager> },
|
|
{ "NiLightDimmerController", &construct<NiFloatInterpController, RC_NiLightDimmerController> },
|
|
{ "NiTransformController", &construct<NiKeyframeController, RC_NiKeyframeController> },
|
|
{ "NiTextureTransformController",
|
|
&construct<NiTextureTransformController, RC_NiTextureTransformController> },
|
|
{ "NiMultiTargetTransformController",
|
|
&construct<NiMultiTargetTransformController, RC_NiMultiTargetTransformController> },
|
|
|
|
// Extra data controllers, Gamebryo
|
|
{ "NiColorExtraDataController", &construct<NiExtraDataController, RC_NiColorExtraDataController> },
|
|
{ "NiFloatExtraDataController", &construct<NiFloatExtraDataController, RC_NiFloatExtraDataController> },
|
|
{ "NiFloatsExtraDataController", &construct<NiFloatsExtraDataController, RC_NiFloatsExtraDataController> },
|
|
{ "NiFloatsExtraDataPoint3Controller",
|
|
&construct<NiFloatsExtraDataPoint3Controller, RC_NiFloatsExtraDataPoint3Controller> },
|
|
|
|
// Bethesda
|
|
{ "BSFrustumFOVController", &construct<NiFloatInterpController, RC_BSFrustumFOVController> },
|
|
{ "BSKeyframeController", &construct<BSKeyframeController, RC_BSKeyframeController> },
|
|
{ "BSLagBoneController", &construct<BSLagBoneController, RC_BSLagBoneController> },
|
|
{ "BSProceduralLightningController",
|
|
&construct<BSProceduralLightningController, RC_BSProceduralLightningController> },
|
|
{ "BSMaterialEmittanceMultController",
|
|
&construct<NiFloatInterpController, RC_BSMaterialEmittanceMultController> },
|
|
{ "BSNiAlphaPropertyTestRefController",
|
|
&construct<NiFloatInterpController, RC_BSNiAlphaPropertyTestRefController> },
|
|
{ "BSRefractionFirePeriodController",
|
|
&construct<NiSingleInterpController, RC_BSRefractionFirePeriodController> },
|
|
{ "BSRefractionStrengthController",
|
|
&construct<NiFloatInterpController, RC_BSRefractionStrengthController> },
|
|
{ "BSEffectShaderPropertyColorController",
|
|
&construct<BSEffectShaderPropertyColorController, RC_BSEffectShaderPropertyColorController> },
|
|
{ "BSEffectShaderPropertyFloatController",
|
|
&construct<BSEffectShaderPropertyFloatController, RC_BSEffectShaderPropertyFloatController> },
|
|
{ "BSLightingShaderPropertyColorController",
|
|
&construct<BSEffectShaderPropertyColorController, RC_BSLightingShaderPropertyColorController> },
|
|
{ "BSLightingShaderPropertyFloatController",
|
|
&construct<BSEffectShaderPropertyFloatController, RC_BSLightingShaderPropertyFloatController> },
|
|
{ "BSLightingShaderPropertyUShortController",
|
|
&construct<BSEffectShaderPropertyFloatController, RC_BSLightingShaderPropertyUShortController> },
|
|
{ "bhkBlendController", &construct<bhkBlendController, RC_bhkBlendController> },
|
|
{ "NiBSBoneLODController", &construct<NiBoneLODController, RC_NiBoneLODController> },
|
|
{ "NiLightRadiusController", &construct<NiFloatInterpController, RC_NiLightRadiusController> },
|
|
|
|
// Interpolators, Gamebryo
|
|
{ "NiBSplineCompFloatInterpolator",
|
|
&construct<NiBSplineCompFloatInterpolator, RC_NiBSplineCompFloatInterpolator> },
|
|
{ "NiBSplineCompPoint3Interpolator",
|
|
&construct<NiBSplineCompPoint3Interpolator, RC_NiBSplineCompPoint3Interpolator> },
|
|
{ "NiBSplineCompTransformInterpolator",
|
|
&construct<NiBSplineCompTransformInterpolator, RC_NiBSplineCompTransformInterpolator> },
|
|
{ "NiBSplineTransformInterpolator",
|
|
&construct<NiBSplineTransformInterpolator, RC_NiBSplineTransformInterpolator> },
|
|
{ "NiBlendBoolInterpolator", &construct<NiBlendBoolInterpolator, RC_NiBlendBoolInterpolator> },
|
|
{ "NiBlendFloatInterpolator", &construct<NiBlendFloatInterpolator, RC_NiBlendFloatInterpolator> },
|
|
{ "NiBlendPoint3Interpolator", &construct<NiBlendPoint3Interpolator, RC_NiBlendPoint3Interpolator> },
|
|
{ "NiBlendTransformInterpolator",
|
|
&construct<NiBlendTransformInterpolator, RC_NiBlendTransformInterpolator> },
|
|
{ "NiBoolInterpolator", &construct<NiBoolInterpolator, RC_NiBoolInterpolator> },
|
|
{ "NiBoolTimelineInterpolator", &construct<NiBoolInterpolator, RC_NiBoolTimelineInterpolator> },
|
|
{ "NiColorInterpolator", &construct<NiColorInterpolator, RC_NiColorInterpolator> },
|
|
{ "NiFloatInterpolator", &construct<NiFloatInterpolator, RC_NiFloatInterpolator> },
|
|
{ "NiLookAtInterpolator", &construct<NiLookAtInterpolator, RC_NiLookAtInterpolator> },
|
|
{ "NiPathInterpolator", &construct<NiPathInterpolator, RC_NiPathInterpolator> },
|
|
{ "NiPoint3Interpolator", &construct<NiPoint3Interpolator, RC_NiPoint3Interpolator> },
|
|
{ "NiTransformInterpolator", &construct<NiTransformInterpolator, RC_NiTransformInterpolator> },
|
|
|
|
// Interpolators, Bethesda
|
|
{ "BSRotAccumTransfInterpolator", &construct<NiTransformInterpolator, RC_BSRotAccumTransfInterpolator> },
|
|
{ "BSTreadTransfInterpolator", &construct<BSTreadTransfInterpolator, RC_BSTreadTransfInterpolator> },
|
|
|
|
// DATA
|
|
|
|
// 4.0.0.2
|
|
{ "NiColorData", &construct<NiColorData, RC_NiColorData> },
|
|
{ "NiFloatData", &construct<NiFloatData, RC_NiFloatData> },
|
|
{ "NiKeyframeData", &construct<NiKeyframeData, RC_NiKeyframeData> },
|
|
{ "NiMorphData", &construct<NiMorphData, RC_NiMorphData> },
|
|
{ "NiPalette", &construct<NiPalette, RC_NiPalette> },
|
|
{ "NiPixelData", &construct<NiPixelData, RC_NiPixelData> },
|
|
{ "NiPosData", &construct<NiPosData, RC_NiPosData> },
|
|
{ "NiSourceTexture", &construct<NiSourceTexture, RC_NiSourceTexture> },
|
|
{ "NiUVData", &construct<NiUVData, RC_NiUVData> },
|
|
{ "NiVisData", &construct<NiVisData, RC_NiVisData> },
|
|
|
|
// Gamebryo
|
|
{ "NiAdditionalGeometryData", &construct<NiAdditionalGeometryData, RC_NiAdditionalGeometryData> },
|
|
{ "NiBoolData", &construct<NiBoolData, RC_NiBoolData> },
|
|
{ "NiBSplineData", &construct<NiBSplineData, RC_NiBSplineData> },
|
|
{ "NiBSplineBasisData", &construct<NiBSplineBasisData, RC_NiBSplineBasisData> },
|
|
{ "NiDefaultAVObjectPalette", &construct<NiDefaultAVObjectPalette, RC_NiDefaultAVObjectPalette> },
|
|
{ "NiTransformData", &construct<NiKeyframeData, RC_NiKeyframeData> },
|
|
|
|
// Bethesda
|
|
{ "BSAnimNote", &construct<BSAnimNote, RC_BSAnimNote> },
|
|
{ "BSAnimNotes", &construct<BSAnimNotes, RC_BSAnimNotes> },
|
|
{ "BSPackedAdditionalGeometryData",
|
|
&construct<NiAdditionalGeometryData, RC_BSPackedAdditionalGeometryData> },
|
|
{ "BSShaderTextureSet", &construct<BSShaderTextureSet, RC_BSShaderTextureSet> },
|
|
|
|
// DYNAMIC EFFECTS
|
|
|
|
// 4.0.0.2
|
|
{ "NiAmbientLight", &construct<NiLight, RC_NiLight> },
|
|
{ "NiDirectionalLight", &construct<NiLight, RC_NiLight> },
|
|
{ "NiPointLight", &construct<NiPointLight, RC_NiLight> },
|
|
{ "NiSpotLight", &construct<NiSpotLight, RC_NiLight> },
|
|
{ "NiTextureEffect", &construct<NiTextureEffect, RC_NiTextureEffect> },
|
|
|
|
// EXTRA DATA
|
|
|
|
// 4.0.0.2
|
|
{ "NiExtraData", &construct<NiExtraData, RC_NiExtraData> },
|
|
{ "NiStringExtraData", &construct<NiStringExtraData, RC_NiStringExtraData> },
|
|
{ "NiTextKeyExtraData", &construct<NiTextKeyExtraData, RC_NiTextKeyExtraData> },
|
|
{ "NiVertWeightsExtraData", &construct<NiVertWeightsExtraData, RC_NiVertWeightsExtraData> },
|
|
|
|
// Gamebryo
|
|
{ "NiBinaryExtraData", &construct<NiBinaryExtraData, RC_NiBinaryExtraData> },
|
|
{ "NiBooleanExtraData", &construct<NiBooleanExtraData, RC_NiBooleanExtraData> },
|
|
{ "NiColorExtraData", &construct<NiVectorExtraData, RC_NiColorExtraData> },
|
|
{ "NiFloatExtraData", &construct<NiFloatExtraData, RC_NiFloatExtraData> },
|
|
{ "NiFloatsExtraData", &construct<NiFloatsExtraData, RC_NiFloatsExtraData> },
|
|
{ "NiIntegerExtraData", &construct<NiIntegerExtraData, RC_NiIntegerExtraData> },
|
|
{ "NiIntegersExtraData", &construct<NiIntegersExtraData, RC_NiIntegersExtraData> },
|
|
{ "NiVectorExtraData", &construct<NiVectorExtraData, RC_NiVectorExtraData> },
|
|
{ "NiStringsExtraData", &construct<NiStringsExtraData, RC_NiStringsExtraData> },
|
|
{ "NiStringPalette", &construct<NiStringPalette, RC_NiStringPalette> },
|
|
|
|
// Bethesda bounds
|
|
{ "BSBound", &construct<BSBound, RC_BSBound> },
|
|
{ "BSMultiBound", &construct<BSMultiBound, RC_BSMultiBound> },
|
|
{ "BSMultiBoundAABB", &construct<BSMultiBoundAABB, RC_BSMultiBoundAABB> },
|
|
{ "BSMultiBoundOBB", &construct<BSMultiBoundOBB, RC_BSMultiBoundOBB> },
|
|
{ "BSMultiBoundSphere", &construct<BSMultiBoundSphere, RC_BSMultiBoundSphere> },
|
|
|
|
// Bethesda markers
|
|
{ "BSFurnitureMarker", &construct<BSFurnitureMarker, RC_BSFurnitureMarker> },
|
|
{ "BSFurnitureMarkerNode", &construct<BSFurnitureMarker, RC_BSFurnitureMarker> },
|
|
{ "BSInvMarker", &construct<BSInvMarker, RC_BSInvMarker> },
|
|
|
|
// Other Bethesda records
|
|
{ "BSExtraData", &construct<BSExtraData, RC_BSExtraData> },
|
|
{ "BSBehaviorGraphExtraData", &construct<BSBehaviorGraphExtraData, RC_BSBehaviorGraphExtraData> },
|
|
{ "BSBoneLODExtraData", &construct<BSBoneLODExtraData, RC_BSBoneLODExtraData> },
|
|
{ "BSClothExtraData", &construct<BSClothExtraData, RC_BSClothExtraData> },
|
|
{ "BSCollisionQueryProxyExtraData",
|
|
&construct<BSCollisionQueryProxyExtraData, RC_BSCollisionQueryProxyExtraData> },
|
|
{ "BSConnectPoint::Children", &construct<BSConnectPoint::Children, RC_BSConnectPointChildren> },
|
|
{ "BSConnectPoint::Parents", &construct<BSConnectPoint::Parents, RC_BSConnectPointParents> },
|
|
{ "BSDecalPlacementVectorExtraData",
|
|
&construct<BSDecalPlacementVectorExtraData, RC_BSDecalPlacementVectorExtraData> },
|
|
{ "BSDistantObjectExtraData", &construct<BSDistantObjectExtraData, RC_BSDistantObjectExtraData> },
|
|
{ "BSDistantObjectLargeRefExtraData",
|
|
&construct<BSDistantObjectLargeRefExtraData, RC_BSDistantObjectLargeRefExtraData> },
|
|
{ "BSEyeCenterExtraData", &construct<BSEyeCenterExtraData, RC_BSEyeCenterExtraData> },
|
|
{ "BSPackedCombinedSharedGeomDataExtra",
|
|
&construct<BSPackedCombinedSharedGeomDataExtra, RC_BSPackedCombinedSharedGeomDataExtra> },
|
|
{ "BSPositionData", &construct<BSPositionData, RC_BSPositionData> },
|
|
{ "BSWArray", &construct<BSWArray, RC_BSWArray> },
|
|
{ "BSXFlags", &construct<NiIntegerExtraData, RC_BSXFlags> },
|
|
|
|
// GEOMETRY
|
|
|
|
// 4.0.0.2
|
|
{ "NiLines", &construct<NiLines, RC_NiLines> },
|
|
{ "NiLinesData", &construct<NiLinesData, RC_NiLinesData> },
|
|
{ "NiSkinData", &construct<NiSkinData, RC_NiSkinData> },
|
|
{ "NiSkinInstance", &construct<NiSkinInstance, RC_NiSkinInstance> },
|
|
{ "NiSkinPartition", &construct<NiSkinPartition, RC_NiSkinPartition> },
|
|
{ "NiTriShape", &construct<NiTriShape, RC_NiTriShape> },
|
|
{ "NiTriShapeData", &construct<NiTriShapeData, RC_NiTriShapeData> },
|
|
{ "NiTriStrips", &construct<NiTriStrips, RC_NiTriStrips> },
|
|
{ "NiTriStripsData", &construct<NiTriStripsData, RC_NiTriStripsData> },
|
|
|
|
// Bethesda
|
|
{ "BSDismemberSkinInstance", &construct<BSDismemberSkinInstance, RC_BSDismemberSkinInstance> },
|
|
{ "BSSkin::Instance", &construct<BSSkinInstance, RC_BSSkinInstance> },
|
|
{ "BSSkin::BoneData", &construct<BSSkinBoneData, RC_BSSkinBoneData> },
|
|
{ "BSTriShape", &construct<BSTriShape, RC_BSTriShape> },
|
|
{ "BSDynamicTriShape", &construct<BSDynamicTriShape, RC_BSDynamicTriShape> },
|
|
{ "BSLODTriShape", &construct<BSLODTriShape, RC_BSLODTriShape> },
|
|
{ "BSMeshLODTriShape", &construct<BSMeshLODTriShape, RC_BSMeshLODTriShape> },
|
|
{ "BSSegmentedTriShape", &construct<BSSegmentedTriShape, RC_BSSegmentedTriShape> },
|
|
{ "BSSubIndexTriShape", &construct<BSSubIndexTriShape, RC_BSSubIndexTriShape> },
|
|
|
|
// PARTICLES
|
|
|
|
// Geometry, 4.0.0.2
|
|
{ "NiAutoNormalParticles", &construct<NiParticles, RC_NiParticles> },
|
|
{ "NiAutoNormalParticlesData", &construct<NiParticlesData, RC_NiParticlesData> },
|
|
{ "NiParticles", &construct<NiParticles, RC_NiParticles> },
|
|
{ "NiParticlesData", &construct<NiParticlesData, RC_NiParticlesData> },
|
|
{ "NiRotatingParticles", &construct<NiParticles, RC_NiParticles> },
|
|
{ "NiRotatingParticlesData", &construct<NiRotatingParticlesData, RC_NiParticlesData> },
|
|
|
|
// Geometry, Gamebryo
|
|
{ "NiParticleSystem", &construct<NiParticleSystem, RC_NiParticleSystem> },
|
|
{ "NiMeshParticleSystem", &construct<NiParticleSystem, RC_NiParticleSystem> },
|
|
{ "NiPSysData", &construct<NiPSysData, RC_NiPSysData> },
|
|
{ "NiMeshPSysData", &construct<NiMeshPSysData, RC_NiMeshPSysData> },
|
|
|
|
// Geometry, Bethesda
|
|
{ "BSStripParticleSystem", &construct<NiParticleSystem, RC_BSStripParticleSystem> },
|
|
{ "BSStripPSysData", &construct<BSStripPSysData, RC_BSStripPSysData> },
|
|
|
|
// Modifiers, 4.0.0.2
|
|
{ "NiGravity", &construct<NiGravity, RC_NiGravity> },
|
|
{ "NiParticleBomb", &construct<NiParticleBomb, RC_NiParticleBomb> },
|
|
{ "NiParticleColorModifier", &construct<NiParticleColorModifier, RC_NiParticleColorModifier> },
|
|
{ "NiParticleGrowFade", &construct<NiParticleGrowFade, RC_NiParticleGrowFade> },
|
|
{ "NiParticleRotation", &construct<NiParticleRotation, RC_NiParticleRotation> },
|
|
|
|
// Modifiers, Gamebryo
|
|
{ "NiPSysAgeDeathModifier", &construct<NiPSysAgeDeathModifier, RC_NiPSysAgeDeathModifier> },
|
|
{ "NiPSysBombModifier", &construct<NiPSysBombModifier, RC_NiPSysBombModifier> },
|
|
{ "NiPSysBoundUpdateModifier", &construct<NiPSysBoundUpdateModifier, RC_NiPSysBoundUpdateModifier> },
|
|
{ "NiPSysColorModifier", &construct<NiPSysColorModifier, RC_NiPSysColorModifier> },
|
|
{ "NiPSysDragModifier", &construct<NiPSysDragModifier, RC_NiPSysDragModifier> },
|
|
{ "NiPSysGravityModifier", &construct<NiPSysGravityModifier, RC_NiPSysGravityModifier> },
|
|
{ "NiPSysGrowFadeModifier", &construct<NiPSysGrowFadeModifier, RC_NiPSysGrowFadeModifier> },
|
|
{ "NiPSysPositionModifier", &construct<NiPSysModifier, RC_NiPSysPositionModifier> },
|
|
{ "NiPSysRotationModifier", &construct<NiPSysRotationModifier, RC_NiPSysRotationModifier> },
|
|
{ "NiPSysSpawnModifier", &construct<NiPSysSpawnModifier, RC_NiPSysSpawnModifier> },
|
|
{ "NiPSysMeshUpdateModifier", &construct<NiPSysMeshUpdateModifier, RC_NiPSysMeshUpdateModifier> },
|
|
|
|
// Modifiers, Bethesda
|
|
{ "BSParentVelocityModifier", &construct<BSParentVelocityModifier, RC_BSParentVelocityModifier> },
|
|
{ "BSPSysHavokUpdateModifier", &construct<BSPSysHavokUpdateModifier, RC_BSPSysHavokUpdateModifier> },
|
|
{ "BSPSysInheritVelocityModifier",
|
|
&construct<BSPSysInheritVelocityModifier, RC_BSPSysInheritVelocityModifier> },
|
|
{ "BSPSysLODModifier", &construct<BSPSysLODModifier, RC_BSPSysLODModifier> },
|
|
{ "BSPSysRecycleBoundModifier", &construct<BSPSysRecycleBoundModifier, RC_BSPSysRecycleBoundModifier> },
|
|
{ "BSPSysScaleModifier", &construct<BSPSysScaleModifier, RC_BSPSysScaleModifier> },
|
|
{ "BSPSysSimpleColorModifier", &construct<BSPSysSimpleColorModifier, RC_BSPSysSimpleColorModifier> },
|
|
{ "BSPSysStripUpdateModifier", &construct<BSPSysStripUpdateModifier, RC_BSPSysStripUpdateModifier> },
|
|
{ "BSPSysSubTexModifier", &construct<BSPSysSubTexModifier, RC_BSPSysSubTexModifier> },
|
|
{ "BSWindModifier", &construct<BSWindModifier, RC_BSWindModifier> },
|
|
|
|
// Emitters, Gamebryo
|
|
{ "NiPSysBoxEmitter", &construct<NiPSysBoxEmitter, RC_NiPSysBoxEmitter> },
|
|
{ "NiPSysCylinderEmitter", &construct<NiPSysCylinderEmitter, RC_NiPSysCylinderEmitter> },
|
|
{ "NiPSysMeshEmitter", &construct<NiPSysMeshEmitter, RC_NiPSysMeshEmitter> },
|
|
{ "NiPSysSphereEmitter", &construct<NiPSysSphereEmitter, RC_NiPSysSphereEmitter> },
|
|
|
|
// Emitters, Bethesda
|
|
{ "BSPSysArrayEmitter", &construct<NiPSysVolumeEmitter, RC_BSPSysArrayEmitter> },
|
|
|
|
// Modifier controllers, Gamebryo
|
|
{ "NiPSysAirFieldAirFrictionCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysAirFieldAirFrictionCtlr> },
|
|
{ "NiPSysAirFieldInheritVelocityCtlr",
|
|
&construct<NiPSysModifierFloatCtlr, RC_NiPSysAirFieldInheritVelocityCtlr> },
|
|
{ "NiPSysAirFieldSpreadCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysAirFieldSpreadCtlr> },
|
|
{ "NiPSysEmitterCtlr", &construct<NiPSysEmitterCtlr, RC_NiPSysEmitterCtlr> },
|
|
{ "NiPSysEmitterDeclinationCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterDeclinationCtlr> },
|
|
{ "NiPSysEmitterDeclinationVarCtlr",
|
|
&construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterDeclinationVarCtlr> },
|
|
{ "NiPSysEmitterInitialRadiusCtlr",
|
|
&construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterInitialRadiusCtlr> },
|
|
{ "NiPSysEmitterLifeSpanCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterLifeSpanCtlr> },
|
|
{ "NiPSysEmitterPlanarAngleCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterPlanarAngleCtlr> },
|
|
{ "NiPSysEmitterPlanarAngleVarCtlr",
|
|
&construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterPlanarAngleVarCtlr> },
|
|
{ "NiPSysEmitterSpeedCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysEmitterSpeedCtlr> },
|
|
{ "NiPSysFieldAttenuationCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysFieldAttenuationCtlr> },
|
|
{ "NiPSysFieldMagnitudeCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysFieldMagnitudeCtlr> },
|
|
{ "NiPSysFieldMaxDistanceCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysFieldMaxDistanceCtlr> },
|
|
{ "NiPSysGravityStrengthCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysGravityStrengthCtlr> },
|
|
{ "NiPSysInitialRotSpeedCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysInitialRotSpeedCtlr> },
|
|
{ "NiPSysInitialRotSpeedVarCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysInitialRotSpeedVarCtlr> },
|
|
{ "NiPSysInitialRotAngleCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysInitialRotAngleCtlr> },
|
|
{ "NiPSysInitialRotAngleVarCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysInitialRotAngleVarCtlr> },
|
|
{ "NiPSysModifierActiveCtlr", &construct<NiPSysModifierBoolCtlr, RC_NiPSysModifierActiveCtlr> },
|
|
{ "NiPSysRotDampeningCtlr", &construct<NiPSysModifierFloatCtlr, RC_NiPSysRotDampeningCtlr> },
|
|
|
|
// Modifier controllers, Bethesda
|
|
{ "BSPSysMultiTargetEmitterCtlr",
|
|
&construct<BSPSysMultiTargetEmitterCtlr, RC_BSPSysMultiTargetEmitterCtlr> },
|
|
|
|
// Modifier controller data, Gamebryo
|
|
{ "NiPSysEmitterCtlrData", &construct<NiPSysEmitterCtlrData, RC_NiPSysEmitterCtlrData> },
|
|
|
|
// Colliders, 4.0.0.2
|
|
{ "NiPlanarCollider", &construct<NiPlanarCollider, RC_NiPlanarCollider> },
|
|
{ "NiSphericalCollider", &construct<NiSphericalCollider, RC_NiSphericalCollider> },
|
|
|
|
// Colliders, Gamebryo
|
|
{ "NiPSysColliderManager", &construct<NiPSysColliderManager, RC_NiPSysColliderManager> },
|
|
{ "NiPSysPlanarCollider", &construct<NiPSysPlanarCollider, RC_NiPSysPlanarCollider> },
|
|
{ "NiPSysSphericalCollider", &construct<NiPSysSphericalCollider, RC_NiPSysSphericalCollider> },
|
|
|
|
// Particle system controllers, 4.0.0.2
|
|
{ "NiParticleSystemController", &construct<NiParticleSystemController, RC_NiParticleSystemController> },
|
|
|
|
// Particle system controllers, Gamebryo
|
|
{ "NiPSysResetOnLoopCtlr", &construct<NiTimeController, RC_NiPSysResetOnLoopCtlr> },
|
|
{ "NiPSysUpdateCtlr", &construct<NiTimeController, RC_NiPSysUpdateCtlr> },
|
|
|
|
// PHYSICS
|
|
|
|
// Collision objects, Gamebryo
|
|
{ "NiCollisionObject", &construct<NiCollisionObject, RC_NiCollisionObject> },
|
|
|
|
// Collision objects, Bethesda
|
|
{ "bhkCollisionObject", &construct<bhkCollisionObject, RC_bhkCollisionObject> },
|
|
{ "bhkPCollisionObject", &construct<bhkCollisionObject, RC_bhkCollisionObject> },
|
|
{ "bhkSPCollisionObject", &construct<bhkCollisionObject, RC_bhkCollisionObject> },
|
|
{ "bhkNPCollisionObject", &construct<bhkNPCollisionObject, RC_bhkCollisionObject> },
|
|
{ "bhkBlendCollisionObject", &construct<bhkBlendCollisionObject, RC_bhkBlendCollisionObject> },
|
|
|
|
// Constraint records, Bethesda
|
|
{ "bhkBallAndSocketConstraint", &construct<bhkBallAndSocketConstraint, RC_bhkBallAndSocketConstraint> },
|
|
{ "bhkBallSocketConstraintChain",
|
|
&construct<bhkBallSocketConstraintChain, RC_bhkBallSocketConstraintChain> },
|
|
{ "bhkHingeConstraint", &construct<bhkHingeConstraint, RC_bhkHingeConstraint> },
|
|
{ "bhkLimitedHingeConstraint", &construct<bhkLimitedHingeConstraint, RC_bhkLimitedHingeConstraint> },
|
|
{ "bhkRagdollConstraint", &construct<bhkRagdollConstraint, RC_bhkRagdollConstraint> },
|
|
{ "bhkStiffSpringConstraint", &construct<bhkStiffSpringConstraint, RC_bhkStiffSpringConstraint> },
|
|
{ "bhkPrismaticConstraint", &construct<bhkPrismaticConstraint, RC_bhkPrismaticConstraint> },
|
|
{ "bhkMalleableConstraint", &construct<bhkMalleableConstraint, RC_bhkMalleableConstraint> },
|
|
{ "bhkBreakableConstraint", &construct<bhkBreakableConstraint, RC_bhkBreakableConstraint> },
|
|
|
|
// Physics body records, Bethesda
|
|
{ "bhkRigidBody", &construct<bhkRigidBody, RC_bhkRigidBody> },
|
|
{ "bhkRigidBodyT", &construct<bhkRigidBody, RC_bhkRigidBodyT> },
|
|
|
|
// Physics geometry records, Bethesda
|
|
{ "bhkBoxShape", &construct<bhkBoxShape, RC_bhkBoxShape> },
|
|
{ "bhkCapsuleShape", &construct<bhkCapsuleShape, RC_bhkCapsuleShape> },
|
|
{ "bhkCylinderShape", &construct<bhkCylinderShape, RC_bhkCylinderShape> },
|
|
{ "bhkCompressedMeshShape", &construct<bhkCompressedMeshShape, RC_bhkCompressedMeshShape> },
|
|
{ "bhkCompressedMeshShapeData", &construct<bhkCompressedMeshShapeData, RC_bhkCompressedMeshShapeData> },
|
|
{ "bhkConvexListShape", &construct<bhkConvexListShape, RC_bhkConvexListShape> },
|
|
{ "bhkConvexSweepShape", &construct<bhkConvexSweepShape, RC_bhkConvexSweepShape> },
|
|
{ "bhkConvexTransformShape", &construct<bhkConvexTransformShape, RC_bhkConvexTransformShape> },
|
|
{ "bhkConvexVerticesShape", &construct<bhkConvexVerticesShape, RC_bhkConvexVerticesShape> },
|
|
{ "bhkListShape", &construct<bhkListShape, RC_bhkListShape> },
|
|
{ "bhkMoppBvTreeShape", &construct<bhkMoppBvTreeShape, RC_bhkMoppBvTreeShape> },
|
|
{ "bhkMeshShape", &construct<bhkMeshShape, RC_bhkMeshShape> },
|
|
{ "bhkMultiSphereShape", &construct<bhkMultiSphereShape, RC_bhkMultiSphereShape> },
|
|
{ "bhkNiTriStripsShape", &construct<bhkNiTriStripsShape, RC_bhkNiTriStripsShape> },
|
|
{ "bhkPackedNiTriStripsShape", &construct<bhkPackedNiTriStripsShape, RC_bhkPackedNiTriStripsShape> },
|
|
{ "hkPackedNiTriStripsData", &construct<hkPackedNiTriStripsData, RC_hkPackedNiTriStripsData> },
|
|
{ "bhkPlaneShape", &construct<bhkPlaneShape, RC_bhkPlaneShape> },
|
|
{ "bhkSphereShape", &construct<bhkSphereShape, RC_bhkSphereShape> },
|
|
{ "bhkTransformShape", &construct<bhkConvexTransformShape, RC_bhkConvexTransformShape> },
|
|
|
|
// Phantom records, Bethesda
|
|
{ "bhkAabbPhantom", &construct<bhkAabbPhantom, RC_bhkAabbPhantom> },
|
|
{ "bhkSimpleShapePhantom", &construct<bhkSimpleShapePhantom, RC_bhkSimpleShapePhantom> },
|
|
|
|
// Physics system records, Bethesda
|
|
{ "bhkPhysicsSystem", &construct<bhkPhysicsSystem, RC_bhkPhysicsSystem> },
|
|
{ "bhkRagdollSystem", &construct<bhkRagdollSystem, RC_bhkRagdollSystem> },
|
|
|
|
// Action records
|
|
{ "bhkLiquidAction", &construct<bhkLiquidAction, RC_bhkLiquidAction> },
|
|
{ "bhkOrientHingedBodyAction", &construct<bhkOrientHingedBodyAction, RC_bhkOrientHingedBodyAction> },
|
|
|
|
// Ragdoll template records
|
|
{ "bhkRagdollTemplate", &construct<bhkRagdollTemplate, RC_bhkRagdollTemplate> },
|
|
{ "bhkRagdollTemplateData", &construct<bhkRagdollTemplateData, RC_bhkRagdollTemplateData> },
|
|
|
|
// Other records
|
|
{ "bhkPoseArray", &construct<bhkPoseArray, RC_bhkPoseArray> },
|
|
|
|
// PROPERTIES
|
|
|
|
// 4.0.0.2
|
|
{ "NiAlphaProperty", &construct<NiAlphaProperty, RC_NiAlphaProperty> },
|
|
{ "NiDitherProperty", &construct<NiDitherProperty, RC_NiDitherProperty> },
|
|
{ "NiFogProperty", &construct<NiFogProperty, RC_NiFogProperty> },
|
|
{ "NiMaterialProperty", &construct<NiMaterialProperty, RC_NiMaterialProperty> },
|
|
{ "NiShadeProperty", &construct<NiShadeProperty, RC_NiShadeProperty> },
|
|
{ "NiSpecularProperty", &construct<NiSpecularProperty, RC_NiSpecularProperty> },
|
|
{ "NiStencilProperty", &construct<NiStencilProperty, RC_NiStencilProperty> },
|
|
{ "NiTexturingProperty", &construct<NiTexturingProperty, RC_NiTexturingProperty> },
|
|
{ "NiVertexColorProperty", &construct<NiVertexColorProperty, RC_NiVertexColorProperty> },
|
|
{ "NiWireframeProperty", &construct<NiWireframeProperty, RC_NiWireframeProperty> },
|
|
{ "NiZBufferProperty", &construct<NiZBufferProperty, RC_NiZBufferProperty> },
|
|
|
|
// Shader properties, Bethesda
|
|
{ "BSShaderProperty", &construct<BSShaderProperty, RC_BSShaderProperty> },
|
|
{ "BSShaderPPLightingProperty", &construct<BSShaderPPLightingProperty, RC_BSShaderPPLightingProperty> },
|
|
{ "BSShaderNoLightingProperty", &construct<BSShaderNoLightingProperty, RC_BSShaderNoLightingProperty> },
|
|
{ "BSDistantTreeShaderProperty", &construct<BSShaderProperty, RC_BSDistantTreeShaderProperty> },
|
|
{ "BSLightingShaderProperty", &construct<BSLightingShaderProperty, RC_BSLightingShaderProperty> },
|
|
{ "BSEffectShaderProperty", &construct<BSEffectShaderProperty, RC_BSEffectShaderProperty> },
|
|
{ "BSSkyShaderProperty", &construct<BSSkyShaderProperty, RC_BSSkyShaderProperty> },
|
|
{ "BSWaterShaderProperty", &construct<BSWaterShaderProperty, RC_BSWaterShaderProperty> },
|
|
{ "DistantLODShaderProperty", &construct<BSShaderProperty, RC_DistantLODShaderProperty> },
|
|
{ "HairShaderProperty", &construct<BSShaderProperty, RC_HairShaderProperty> },
|
|
{ "Lighting30ShaderProperty", &construct<BSShaderPPLightingProperty, RC_BSShaderPPLightingProperty> },
|
|
{ "SkyShaderProperty", &construct<SkyShaderProperty, RC_SkyShaderProperty> },
|
|
{ "TallGrassShaderProperty", &construct<TallGrassShaderProperty, RC_TallGrassShaderProperty> },
|
|
{ "TileShaderProperty", &construct<TileShaderProperty, RC_TileShaderProperty> },
|
|
{ "VolumetricFogShaderProperty", &construct<BSShaderProperty, RC_VolumetricFogShaderProperty> },
|
|
{ "WaterShaderProperty", &construct<BSShaderProperty, RC_WaterShaderProperty> },
|
|
};
|
|
}
|
|
|
|
/// Make the factory map used for parsing the file
|
|
static const std::map<std::string, CreateRecord> factories = makeFactory();
|
|
|
|
std::string Reader::versionToString(std::uint32_t version)
|
|
{
|
|
int major = (version >> 24) & 0xFF;
|
|
int minor = (version >> 16) & 0xFF;
|
|
int patch = (version >> 8) & 0xFF;
|
|
int rev = version & 0xFF;
|
|
|
|
std::stringstream stream;
|
|
stream << major << "." << minor << "." << patch << "." << rev;
|
|
return stream.str();
|
|
}
|
|
|
|
void Reader::parse(Files::IStreamPtr&& stream)
|
|
{
|
|
const bool writeDebug = sWriteNifDebugLog;
|
|
if (writeDebug)
|
|
Log(Debug::Verbose) << "NIF Debug: Reading file: '" << mFilename << "'";
|
|
|
|
const std::array<std::uint64_t, 2> fileHash = Files::getHash(mFilename, *stream);
|
|
mHash.append(reinterpret_cast<const char*>(fileHash.data()), fileHash.size() * sizeof(std::uint64_t));
|
|
|
|
NIFStream nif(*this, std::move(stream), mEncoder);
|
|
|
|
// Check the header string
|
|
std::string head = nif.getVersionString();
|
|
static const std::array<std::string, 2> verStrings = {
|
|
"NetImmerse File Format",
|
|
"Gamebryo File Format",
|
|
};
|
|
const bool supportedHeader = std::any_of(verStrings.begin(), verStrings.end(),
|
|
[&](const std::string& verString) { return head.starts_with(verString); });
|
|
if (!supportedHeader)
|
|
throw Nif::Exception("Invalid NIF header: " + head, mFilename);
|
|
|
|
// Get BCD version
|
|
nif.read(mVersion);
|
|
// 4.0.0.0 is an older, practically identical version of the format.
|
|
// It's not used by Morrowind assets but Morrowind supports it.
|
|
static const std::array<uint32_t, 2> supportedVers = {
|
|
NIFStream::generateVersion(4, 0, 0, 0),
|
|
NIFFile::VER_MW,
|
|
};
|
|
const bool supportedVersion
|
|
= std::find(supportedVers.begin(), supportedVers.end(), mVersion) != supportedVers.end();
|
|
|
|
if (!supportedVersion && !sLoadUnsupportedFiles)
|
|
throw Nif::Exception("Unsupported NIF version: " + versionToString(mVersion), mFilename);
|
|
|
|
const bool hasEndianness = mVersion >= NIFStream::generateVersion(20, 0, 0, 4);
|
|
const bool hasUserVersion = mVersion >= NIFStream::generateVersion(10, 0, 1, 8);
|
|
const bool hasRecTypeListings = mVersion >= NIFStream::generateVersion(5, 0, 0, 1);
|
|
const bool hasRecTypeHashes = mVersion == NIFStream::generateVersion(20, 3, 1, 2);
|
|
const bool hasRecordSizes = mVersion >= NIFStream::generateVersion(20, 2, 0, 5);
|
|
const bool hasGroups = mVersion >= NIFStream::generateVersion(5, 0, 0, 6);
|
|
const bool hasStringTable = mVersion >= NIFStream::generateVersion(20, 1, 0, 1);
|
|
const bool hasRecordSeparators
|
|
= mVersion >= NIFStream::generateVersion(10, 0, 0, 0) && mVersion < NIFStream::generateVersion(10, 2, 0, 0);
|
|
|
|
// Record type list
|
|
std::vector<std::string> recTypes;
|
|
// Record type mapping for each record
|
|
std::vector<std::uint16_t> recTypeIndices;
|
|
|
|
{
|
|
std::uint8_t endianness = 1;
|
|
if (hasEndianness)
|
|
nif.read(endianness);
|
|
|
|
// TODO: find some big-endian files and investigate the difference
|
|
if (endianness == 0)
|
|
throw Nif::Exception("Big endian NIF files are unsupported", mFilename);
|
|
}
|
|
|
|
if (hasUserVersion)
|
|
nif.read(mUserVersion);
|
|
|
|
mRecords.resize(nif.get<std::uint32_t>());
|
|
|
|
// Bethesda stream header
|
|
{
|
|
bool hasBSStreamHeader = false;
|
|
if (mVersion == NIFFile::VER_OB_OLD)
|
|
hasBSStreamHeader = true;
|
|
else if (mUserVersion >= 3 && mVersion >= NIFStream::generateVersion(10, 1, 0, 0))
|
|
{
|
|
if (mVersion <= NIFFile::VER_OB || mVersion == NIFFile::VER_BGS)
|
|
hasBSStreamHeader = mUserVersion <= 11 || mVersion >= NIFFile::VER_OB;
|
|
}
|
|
|
|
if (hasBSStreamHeader)
|
|
{
|
|
nif.read(mBethVersion);
|
|
nif.getExportString(); // Author
|
|
if (mBethVersion >= 131)
|
|
nif.get<std::uint32_t>(); // Unknown
|
|
else
|
|
nif.getExportString(); // Process script
|
|
nif.getExportString(); // Export script
|
|
if (mBethVersion >= 103)
|
|
nif.getExportString(); // Max file path
|
|
}
|
|
}
|
|
|
|
if (writeDebug)
|
|
{
|
|
std::stringstream versionInfo;
|
|
versionInfo << "NIF Debug: Version: " << versionToString(mVersion);
|
|
if (mUserVersion)
|
|
versionInfo << "\nUser version: " << mUserVersion;
|
|
if (mBethVersion)
|
|
versionInfo << "\nBSStream version: " << mBethVersion;
|
|
Log(Debug::Verbose) << versionInfo.str();
|
|
}
|
|
|
|
if (hasRecTypeListings)
|
|
{
|
|
// TODO: 20.3.1.2 uses DJB hashes instead of strings
|
|
if (hasRecTypeHashes)
|
|
throw Nif::Exception("Hashed record types are unsupported", mFilename);
|
|
else
|
|
{
|
|
nif.getSizedStrings(recTypes, nif.get<std::uint16_t>());
|
|
nif.readVector(recTypeIndices, mRecords.size());
|
|
}
|
|
}
|
|
|
|
if (hasRecordSizes) // Record sizes
|
|
{
|
|
std::vector<std::uint32_t> recSizes; // Currently unused
|
|
nif.readVector(recSizes, mRecords.size());
|
|
}
|
|
|
|
if (hasStringTable)
|
|
{
|
|
std::uint32_t stringNum, maxStringLength;
|
|
nif.read(stringNum);
|
|
nif.read(maxStringLength);
|
|
nif.getSizedStrings(mStrings, stringNum);
|
|
}
|
|
|
|
if (hasGroups)
|
|
{
|
|
std::vector<std::uint32_t> groups; // Currently unused
|
|
nif.readVector(groups, nif.get<std::uint32_t>());
|
|
}
|
|
|
|
for (std::size_t i = 0; i < mRecords.size(); i++)
|
|
{
|
|
std::unique_ptr<Record> r;
|
|
|
|
std::string rec = hasRecTypeListings ? recTypes[recTypeIndices[i]] : nif.get<std::string>();
|
|
if (rec.empty())
|
|
{
|
|
std::stringstream error;
|
|
error << "Record type is blank (index " << i << ")";
|
|
throw Nif::Exception(error.str(), mFilename);
|
|
}
|
|
|
|
// Record separator. Some Havok records in Oblivion do not have it.
|
|
if (hasRecordSeparators && !rec.starts_with("bhk") && nif.get<int32_t>())
|
|
throw Nif::Exception("Non-zero separator precedes " + rec + ", index " + std::to_string(i), mFilename);
|
|
|
|
const auto entry = factories.find(rec);
|
|
|
|
if (entry == factories.end())
|
|
throw Nif::Exception("Unknown record type " + rec, mFilename);
|
|
|
|
r = entry->second();
|
|
|
|
if (writeDebug)
|
|
Log(Debug::Verbose) << "NIF Debug: Reading record of type " << rec << ", index " << i;
|
|
|
|
assert(r != nullptr);
|
|
assert(r->recType != RC_MISSING);
|
|
r->recName = std::move(rec);
|
|
r->recIndex = i;
|
|
r->read(&nif);
|
|
mRecords[i] = std::move(r);
|
|
}
|
|
|
|
// Determine which records are roots
|
|
mRoots.resize(nif.get<uint32_t>());
|
|
for (std::size_t i = 0; i < mRoots.size(); i++)
|
|
{
|
|
std::int32_t idx;
|
|
nif.read(idx);
|
|
if (idx >= 0 && static_cast<std::size_t>(idx) < mRecords.size())
|
|
{
|
|
mRoots[i] = mRecords[idx].get();
|
|
}
|
|
else
|
|
{
|
|
mRoots[i] = nullptr;
|
|
Log(Debug::Warning) << "NIFFile Warning: Root " << i + 1 << " does not point to a record: index " << idx
|
|
<< ". File: " << mFilename;
|
|
}
|
|
}
|
|
|
|
// Once parsing is done, do post-processing.
|
|
for (const auto& record : mRecords)
|
|
record->post(*this);
|
|
}
|
|
|
|
void Reader::setUseSkinning(bool skinning)
|
|
{
|
|
mUseSkinning = skinning;
|
|
}
|
|
|
|
std::atomic_bool Reader::sLoadUnsupportedFiles = false;
|
|
std::atomic_bool Reader::sWriteNifDebugLog = false;
|
|
|
|
void Reader::setLoadUnsupportedFiles(bool load)
|
|
{
|
|
sLoadUnsupportedFiles = load;
|
|
}
|
|
|
|
void Reader::setWriteNifDebugLog(bool value)
|
|
{
|
|
sWriteNifDebugLog = value;
|
|
}
|
|
|
|
std::string Reader::getString(std::uint32_t index) const
|
|
{
|
|
if (index == std::numeric_limits<std::uint32_t>::max())
|
|
return std::string();
|
|
return mStrings.at(index);
|
|
}
|
|
|
|
}
|