Browse Source

layout consistency pass pt 2 -place shapebase inheriting initpersistfields up top so the child layout appends to the parent

AzaezelX 2 years ago
parent
commit
ace18d0246

+ 1 - 1
Engine/source/T3D/examples/renderShapeExample.cpp

@@ -72,12 +72,12 @@ RenderShapeExample::~RenderShapeExample()
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 void RenderShapeExample::initPersistFields()
 void RenderShapeExample::initPersistFields()
 {
 {
+   Parent::initPersistFields();
    addGroup( "Shapes" );
    addGroup( "Shapes" );
    INITPERSISTFIELD_SHAPEASSET(Shape, RenderShapeExample, "The path to the shape file.")
    INITPERSISTFIELD_SHAPEASSET(Shape, RenderShapeExample, "The path to the shape file.")
    endGroup( "Shapes" );
    endGroup( "Shapes" );
 
 
    // SceneObject already handles exposing the transform
    // SceneObject already handles exposing the transform
-   Parent::initPersistFields();
 }
 }
 
 
 void RenderShapeExample::inspectPostApply()
 void RenderShapeExample::inspectPostApply()

+ 1 - 2
Engine/source/T3D/item.cpp

@@ -137,6 +137,7 @@ EndImplementEnumType;
 
 
 void ItemData::initPersistFields()
 void ItemData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
    addGroup("Physics");
    addGroup("Physics");
       addField("friction",          TypeF32,       Offset(friction,           ItemData), "A floating-point value specifying how much velocity is lost to impact and sliding friction.");
       addField("friction",          TypeF32,       Offset(friction,           ItemData), "A floating-point value specifying how much velocity is lost to impact and sliding friction.");
       addField("elasticity",        TypeF32,       Offset(elasticity,         ItemData), "A floating-point value specifying how 'bouncy' this ItemData is.");
       addField("elasticity",        TypeF32,       Offset(elasticity,         ItemData), "A floating-point value specifying how 'bouncy' this ItemData is.");
@@ -172,8 +173,6 @@ void ItemData::initPersistFields()
          "@brief If true, this ItemData will only cast a light if the Item for this ItemData has a static value of true.\n\n"
          "@brief If true, this ItemData will only cast a light if the Item for this ItemData has a static value of true.\n\n"
          "@see lightType\n");
          "@see lightType\n");
    endGroup("Light Emitter");
    endGroup("Light Emitter");
-
-   Parent::initPersistFields();
 }
 }
 
 
 void ItemData::packData(BitStream* stream)
 void ItemData::packData(BitStream* stream)

+ 2 - 3
Engine/source/T3D/physics/physicsDebris.cpp

@@ -125,7 +125,7 @@ void PhysicsDebrisData::initPersistFields()
         "@brief Determines if the shape's shadow should be cast onto the environment.\n\n" );
         "@brief Determines if the shape's shadow should be cast onto the environment.\n\n" );
    endGroup("Rendering");
    endGroup("Rendering");
 
 
-   addGroup( "Physical Properties" );
+   addGroup( "Physics" );
 
 
       addField("lifetime", TypeF32, Offset( lifetime, PhysicsDebrisData ),
       addField("lifetime", TypeF32, Offset( lifetime, PhysicsDebrisData ),
          "@brief Base time, in seconds, that debris persists after time of creation.\n\n"
          "@brief Base time, in seconds, that debris persists after time of creation.\n\n"
@@ -193,8 +193,7 @@ void PhysicsDebrisData::initPersistFields()
          "The result of the calculated buoyancy is relative to the density of the WaterObject the PhysicsDebris is within."
          "The result of the calculated buoyancy is relative to the density of the WaterObject the PhysicsDebris is within."
          "@see WaterObject::density");
          "@see WaterObject::density");
 
 
-   endGroup( "Physical Properties" );
-
+   endGroup( "Physics" );
    Parent::initPersistFields();
    Parent::initPersistFields();
 }
 }
 
 

+ 2 - 3
Engine/source/T3D/physics/physicsShape.cpp

@@ -87,8 +87,6 @@ PhysicsShapeData::~PhysicsShapeData()
 
 
 void PhysicsShapeData::initPersistFields()
 void PhysicsShapeData::initPersistFields()
 {
 {
-   Parent::initPersistFields();
-
    addGroup("Shapes");
    addGroup("Shapes");
 
 
       INITPERSISTFIELD_SHAPEASSET(Shape, PhysicsShapeData, "@brief Shape asset to be used with this physics object.\n\n"
       INITPERSISTFIELD_SHAPEASSET(Shape, PhysicsShapeData, "@brief Shape asset to be used with this physics object.\n\n"
@@ -173,7 +171,8 @@ void PhysicsShapeData::initPersistFields()
       addField( "simType", TYPEID< PhysicsShapeData::SimType >(), Offset( simType, PhysicsShapeData ),
       addField( "simType", TYPEID< PhysicsShapeData::SimType >(), Offset( simType, PhysicsShapeData ),
          "@brief Controls whether this shape is simulated on the server, client, or both physics simulations.\n\n" );
          "@brief Controls whether this shape is simulated on the server, client, or both physics simulations.\n\n" );
 
 
-   endGroup( "Networking" );   
+   endGroup( "Networking" );
+   Parent::initPersistFields();
 }
 }
 
 
 void PhysicsShapeData::packData( BitStream *stream )
 void PhysicsShapeData::packData( BitStream *stream )

+ 2 - 2
Engine/source/T3D/player.cpp

@@ -704,6 +704,8 @@ bool PlayerData::isJumpAction(U32 action)
 
 
 void PlayerData::initPersistFields()
 void PlayerData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
+
    addField( "pickupRadius", TypeF32, Offset(pickupRadius, PlayerData),
    addField( "pickupRadius", TypeF32, Offset(pickupRadius, PlayerData),
       "@brief Radius around the player to collide with Items in the scene (on server).\n\n"
       "@brief Radius around the player to collide with Items in the scene (on server).\n\n"
       "Internally the pickupRadius is added to the larger side of the initial bounding box "
       "Internally the pickupRadius is added to the larger side of the initial bounding box "
@@ -1162,8 +1164,6 @@ void PlayerData::initPersistFields()
          "need to.\n");
          "need to.\n");
 
 
    endGroup( "Third Person" );
    endGroup( "Third Person" );
-
-   Parent::initPersistFields();
 }
 }
 
 
 void PlayerData::packData(BitStream* stream)
 void PlayerData::packData(BitStream* stream)

+ 40 - 42
Engine/source/T3D/projectile.cpp

@@ -232,6 +232,45 @@ ProjectileData::ProjectileData(const ProjectileData& other, bool temp_clone) : G
 
 
 void ProjectileData::initPersistFields()
 void ProjectileData::initPersistFields()
 {
 {
+   addGroup("Shapes");
+      addProtectedField("projectileShapeName", TypeShapeFilename, Offset(mProjectileShapeName, ProjectileData), &_setProjectileShapeData, &defaultProtectedGetFn,
+         "@brief File path to the model of the projectile.\n\n", AbstractClassRep::FIELD_HideInInspectors);
+      INITPERSISTFIELD_SHAPEASSET(ProjectileShape, ProjectileData, "@brief The model of the projectile.\n\n");
+      addField("scale", TypePoint3F, Offset(scale, ProjectileData),
+         "@brief Scale to apply to the projectile's size.\n\n"
+         "@note This is applied after SceneObject::scale\n");
+   endGroup("Shapes");
+
+   addGroup("Particle Effects");
+      addField("particleEmitter", TYPEID< ParticleEmitterData >(), Offset(particleEmitter, ProjectileData),
+         "@brief Particle emitter datablock used to generate particles while the projectile is outside of water.\n\n"
+         "@note If datablocks are defined for both particleEmitter and particleWaterEmitter, both effects will play "
+         "as the projectile enters or leaves water.\n\n"
+         "@see particleWaterEmitter\n");
+      addField("particleWaterEmitter", TYPEID< ParticleEmitterData >(), Offset(particleWaterEmitter, ProjectileData),
+         "@brief Particle emitter datablock used to generate particles while the projectile is submerged in water.\n\n"
+         "@note If datablocks are defined for both particleWaterEmitter and particleEmitter , both effects will play "
+         "as the projectile enters or leaves water.\n\n"
+         "@see particleEmitter\n");
+      addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, ProjectileData),
+         "@brief Explosion datablock used when the projectile explodes outside of water.\n\n");
+      addField("waterExplosion", TYPEID< ExplosionData >(), Offset(waterExplosion, ProjectileData),
+         "@brief Explosion datablock used when the projectile explodes underwater.\n\n");
+      addField("splash", TYPEID< SplashData >(), Offset(splash, ProjectileData),
+         "@brief Splash datablock used to create splash effects as the projectile enters or leaves water\n\n");
+      addField("decal", TYPEID< DecalData >(), Offset(decal, ProjectileData),
+         "@brief Decal datablock used for decals placed at projectile explosion points.\n\n");
+   endGroup("Particle Effects");
+
+   addGroup("Sounds");
+      INITPERSISTFIELD_SOUNDASSET(ProjectileSound, ProjectileData, "The sound for the projectile.");
+   endGroup("Sounds");
+
+   addGroup("Light Emitter");
+      addField("lightDesc", TYPEID< LightDescription >(), Offset(lightDesc, ProjectileData),
+         "@brief LightDescription datablock used for lights attached to the projectile.\n\n");
+   endGroup("Light Emitter");   
+
    addGroup("Physics");
    addGroup("Physics");
       addProtectedField("lifetime", TypeS32, Offset(lifetime, ProjectileData), &setLifetime, &getScaledValue,
       addProtectedField("lifetime", TypeS32, Offset(lifetime, ProjectileData), &setLifetime, &getScaledValue,
          "@brief Amount of time, in milliseconds, before the projectile is removed from the simulation.\n\n"
          "@brief Amount of time, in milliseconds, before the projectile is removed from the simulation.\n\n"
@@ -276,46 +315,7 @@ void ProjectileData::initPersistFields()
          "@note ProjectileData::isBallistic must be true for this to have any affect.");
          "@note ProjectileData::isBallistic must be true for this to have any affect.");
    endGroup("Physics");
    endGroup("Physics");
 
 
-   addGroup("Shapes");
-      addProtectedField("projectileShapeName", TypeShapeFilename, Offset(mProjectileShapeName, ProjectileData), &_setProjectileShapeData, &defaultProtectedGetFn,
-         "@brief File path to the model of the projectile.\n\n", AbstractClassRep::FIELD_HideInInspectors);
-      INITPERSISTFIELD_SHAPEASSET(ProjectileShape, ProjectileData, "@brief The model of the projectile.\n\n");
-      addField("scale", TypePoint3F, Offset(scale, ProjectileData),
-         "@brief Scale to apply to the projectile's size.\n\n"
-         "@note This is applied after SceneObject::scale\n");
-   endGroup("Shapes");
-
-   addGroup("Particle Effects");
-      addField("particleEmitter", TYPEID< ParticleEmitterData >(), Offset(particleEmitter, ProjectileData),
-         "@brief Particle emitter datablock used to generate particles while the projectile is outside of water.\n\n"
-         "@note If datablocks are defined for both particleEmitter and particleWaterEmitter, both effects will play "
-         "as the projectile enters or leaves water.\n\n"
-         "@see particleWaterEmitter\n");
-      addField("particleWaterEmitter", TYPEID< ParticleEmitterData >(), Offset(particleWaterEmitter, ProjectileData),
-         "@brief Particle emitter datablock used to generate particles while the projectile is submerged in water.\n\n"
-         "@note If datablocks are defined for both particleWaterEmitter and particleEmitter , both effects will play "
-         "as the projectile enters or leaves water.\n\n"
-         "@see particleEmitter\n");
-      addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, ProjectileData),
-         "@brief Explosion datablock used when the projectile explodes outside of water.\n\n");
-      addField("waterExplosion", TYPEID< ExplosionData >(), Offset(waterExplosion, ProjectileData),
-         "@brief Explosion datablock used when the projectile explodes underwater.\n\n");
-      addField("splash", TYPEID< SplashData >(), Offset(splash, ProjectileData),
-         "@brief Splash datablock used to create splash effects as the projectile enters or leaves water\n\n");
-      addField("decal", TYPEID< DecalData >(), Offset(decal, ProjectileData),
-         "@brief Decal datablock used for decals placed at projectile explosion points.\n\n");
-   endGroup("Particle Effects");
-
-   addGroup("Sounds");
-      INITPERSISTFIELD_SOUNDASSET(ProjectileSound, ProjectileData, "The sound for the projectile.");
-   endGroup("Sounds");
-
-   addGroup("Light Emitter");
-      addField("lightDesc", TYPEID< LightDescription >(), Offset(lightDesc, ProjectileData),
-         "@brief LightDescription datablock used for lights attached to the projectile.\n\n");
-   endGroup("Light Emitter");   
-
-
+   Parent::initPersistFields();
    // disallow some field substitutions
    // disallow some field substitutions
    onlyKeepClearSubstitutions("explosion");
    onlyKeepClearSubstitutions("explosion");
    onlyKeepClearSubstitutions("particleEmitter");
    onlyKeepClearSubstitutions("particleEmitter");
@@ -323,8 +323,6 @@ void ProjectileData::initPersistFields()
    onlyKeepClearSubstitutions("sound");
    onlyKeepClearSubstitutions("sound");
    onlyKeepClearSubstitutions("splash");
    onlyKeepClearSubstitutions("splash");
    onlyKeepClearSubstitutions("waterExplosion");
    onlyKeepClearSubstitutions("waterExplosion");
-
-   Parent::initPersistFields();
 }
 }
 
 
 
 

+ 6 - 8
Engine/source/T3D/proximityMine.cpp

@@ -88,12 +88,15 @@ ProximityMineData::ProximityMineData()
 
 
 void ProximityMineData::initPersistFields()
 void ProximityMineData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
+   addGroup("Sounds");
+      INITPERSISTFIELD_SOUNDASSET(ArmSound, ProximityMineData, "Arming sound for this proximity mine.");
+      INITPERSISTFIELD_SOUNDASSET(TriggerSound, ProximityMineData, "Arming sound for this proximity mine.");
+   endGroup("Sounds");
+
    addGroup( "Arming" );
    addGroup( "Arming" );
    addField( "armingDelay", TypeF32, Offset(armingDelay, ProximityMineData), 
    addField( "armingDelay", TypeF32, Offset(armingDelay, ProximityMineData), 
       "Delay (in seconds) from when the mine is placed to when it becomes active." );
       "Delay (in seconds) from when the mine is placed to when it becomes active." );
-
-   INITPERSISTFIELD_SOUNDASSET(ArmSound, ProximityMineData, "Arming sound for this proximity mine.");
-
    endGroup( "Arming" );
    endGroup( "Arming" );
 
 
    addGroup( "Triggering" );
    addGroup( "Triggering" );
@@ -111,9 +114,6 @@ void ProximityMineData::initPersistFields()
       "Speed above which moving objects within the trigger radius will trigger the mine" );
       "Speed above which moving objects within the trigger radius will trigger the mine" );
    addField( "triggerDelay", TypeF32, Offset(triggerDelay, ProximityMineData),
    addField( "triggerDelay", TypeF32, Offset(triggerDelay, ProximityMineData),
       "Delay (in seconds) from when the mine is triggered until it explodes." );
       "Delay (in seconds) from when the mine is triggered until it explodes." );
-
-   INITPERSISTFIELD_SOUNDASSET(TriggerSound, ProximityMineData, "Arming sound for this proximity mine.");
-
    endGroup( "Triggering" );
    endGroup( "Triggering" );
 
 
    addGroup( "Explosion" );
    addGroup( "Explosion" );
@@ -124,8 +124,6 @@ void ProximityMineData::initPersistFields()
       "ground, which can end up blocking the explosion.  This offset along the mine's "
       "ground, which can end up blocking the explosion.  This offset along the mine's "
       "'up' normal allows you to raise the explosion origin to a better height.");
       "'up' normal allows you to raise the explosion origin to a better height.");
    endGroup( "Explosion" );
    endGroup( "Explosion" );
-
-   Parent::initPersistFields();
 }
 }
 
 
 bool ProximityMineData::preload( bool server, String& errorStr )
 bool ProximityMineData::preload( bool server, String& errorStr )

+ 17 - 17
Engine/source/T3D/rigidShape.cpp

@@ -512,6 +512,22 @@ void RigidShapeData::unpackData(BitStream* stream)
 
 
 void RigidShapeData::initPersistFields()
 void RigidShapeData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
+
+   addGroup( "Particle Effects" );
+      addField("dustEmitter",       TYPEID< ParticleEmitterData >(),   Offset(dustEmitter,        RigidShapeData), "Array of pointers to ParticleEmitterData datablocks which will be used to emit particles at object/terrain contact point.\n");
+      addField("triggerDustHeight", TypeF32,                      Offset(triggerDustHeight,  RigidShapeData), "Maximum height from the ground at which the object will generate dust.\n");
+      addField("dustHeight",        TypeF32,                      Offset(dustHeight,         RigidShapeData), "Height of dust effects.\n");
+      addField("dustTrailEmitter",     TYPEID< ParticleEmitterData >(),   Offset(dustTrailEmitter,   RigidShapeData), "Particle emitter used to create a dust trail for the moving object.\n");
+      addField("splashEmitter",        TYPEID< ParticleEmitterData >(),   Offset(splashEmitterList,     RigidShapeData), VC_NUM_SPLASH_EMITTERS, "Array of pointers to ParticleEmitterData datablocks which will generate splash effects.\n");
+      addField("splashFreqMod",  TypeF32,                Offset(splashFreqMod,   RigidShapeData), "The simulated frequency modulation of a splash generated by this object. Multiplied along with speed and time elapsed when determining splash emition rate.\n");
+      addField("splashVelEpsilon", TypeF32,              Offset(splashVelEpsilon, RigidShapeData), "The threshold speed at which we consider the object's movement to have stopped when updating splash effects.\n");  
+   endGroup( "Particle Effects" );
+   
+   addGroup( "Sounds" );
+      INITPERSISTFIELD_SOUNDASSET_ENUMED(BodySounds, bodySounds, Body::Sounds::MaxSounds, RigidShapeData, "Sounds for body.");      INITPERSISTFIELD_SOUNDASSET_ENUMED(WaterSounds, waterSounds, Sounds::MaxSounds, RigidShapeData, "Sounds for interacting with water.");
+   endGroup( "Sounds" );
+
    addGroup("Physics");
    addGroup("Physics");
       addField("enablePhysicsRep", TypeBool, Offset(enablePhysicsRep, RigidShapeData),
       addField("enablePhysicsRep", TypeBool, Offset(enablePhysicsRep, RigidShapeData),
          "@brief Creates a representation of the object in the physics plugin.\n");
          "@brief Creates a representation of the object in the physics plugin.\n");
@@ -538,21 +554,7 @@ void RigidShapeData::initPersistFields()
       addField("softSplashSoundVelocity", TypeF32,       Offset(softSplashSoundVel, RigidShapeData),"The minimum velocity at which the soft splash sound will be played when impacting water.\n");
       addField("softSplashSoundVelocity", TypeF32,       Offset(softSplashSoundVel, RigidShapeData),"The minimum velocity at which the soft splash sound will be played when impacting water.\n");
       addField("mediumSplashSoundVelocity", TypeF32,     Offset(medSplashSoundVel, RigidShapeData), "The minimum velocity at which the medium splash sound will be played when impacting water.\n");
       addField("mediumSplashSoundVelocity", TypeF32,     Offset(medSplashSoundVel, RigidShapeData), "The minimum velocity at which the medium splash sound will be played when impacting water.\n");
       addField("hardSplashSoundVelocity", TypeF32,       Offset(hardSplashSoundVel, RigidShapeData), "The minimum velocity at which the hard splash sound will be played when impacting water.\n");
       addField("hardSplashSoundVelocity", TypeF32,       Offset(hardSplashSoundVel, RigidShapeData), "The minimum velocity at which the hard splash sound will be played when impacting water.\n");
-   endGroup("Collision");
-   
-   addGroup( "Particle Effects" );
-      addField("dustEmitter",       TYPEID< ParticleEmitterData >(),   Offset(dustEmitter,        RigidShapeData), "Array of pointers to ParticleEmitterData datablocks which will be used to emit particles at object/terrain contact point.\n");
-      addField("triggerDustHeight", TypeF32,                      Offset(triggerDustHeight,  RigidShapeData), "Maximum height from the ground at which the object will generate dust.\n");
-      addField("dustHeight",        TypeF32,                      Offset(dustHeight,         RigidShapeData), "Height of dust effects.\n");
-      addField("dustTrailEmitter",     TYPEID< ParticleEmitterData >(),   Offset(dustTrailEmitter,   RigidShapeData), "Particle emitter used to create a dust trail for the moving object.\n");
-      addField("splashEmitter",        TYPEID< ParticleEmitterData >(),   Offset(splashEmitterList,     RigidShapeData), VC_NUM_SPLASH_EMITTERS, "Array of pointers to ParticleEmitterData datablocks which will generate splash effects.\n");
-      addField("splashFreqMod",  TypeF32,                Offset(splashFreqMod,   RigidShapeData), "The simulated frequency modulation of a splash generated by this object. Multiplied along with speed and time elapsed when determining splash emition rate.\n");
-      addField("splashVelEpsilon", TypeF32,              Offset(splashVelEpsilon, RigidShapeData), "The threshold speed at which we consider the object's movement to have stopped when updating splash effects.\n");  
-   endGroup( "Particle Effects" );
-   
-   addGroup( "Sounds" );
-      INITPERSISTFIELD_SOUNDASSET_ENUMED(BodySounds, bodySounds, Body::Sounds::MaxSounds, RigidShapeData, "Sounds for body.");      INITPERSISTFIELD_SOUNDASSET_ENUMED(WaterSounds, waterSounds, Sounds::MaxSounds, RigidShapeData, "Sounds for interacting with water.");
-   endGroup( "Sounds" );
+   endGroup("Collision");   
    
    
    addGroup( "Camera" );
    addGroup( "Camera" );
       addField("cameraRoll",     TypeBool,       Offset(cameraRoll,     RigidShapeData), "Specifies whether the camera's rotation matrix, and the render eye transform are multiplied during camera updates.\n");
       addField("cameraRoll",     TypeBool,       Offset(cameraRoll,     RigidShapeData), "Specifies whether the camera's rotation matrix, and the render eye transform are multiplied during camera updates.\n");
@@ -560,8 +562,6 @@ void RigidShapeData::initPersistFields()
       addField("cameraDecay",  TypeF32,        Offset(cameraDecay,  RigidShapeData), "Scalar rate at which the third person camera offset decays, per tick.\n");
       addField("cameraDecay",  TypeF32,        Offset(cameraDecay,  RigidShapeData), "Scalar rate at which the third person camera offset decays, per tick.\n");
       addField("cameraOffset",   TypeF32,        Offset(cameraOffset,   RigidShapeData), "The vertical offset of the object's camera.\n");
       addField("cameraOffset",   TypeF32,        Offset(cameraOffset,   RigidShapeData), "The vertical offset of the object's camera.\n");
    endGroup( "Camera" );
    endGroup( "Camera" );
-
-   Parent::initPersistFields();
 }   
 }   
 
 
 
 

+ 9 - 12
Engine/source/T3D/shapeBase.cpp

@@ -534,9 +534,11 @@ bool ShapeBaseData::_setMass( void* object, const char* index, const char* data
 
 
 void ShapeBaseData::initPersistFields()
 void ShapeBaseData::initPersistFields()
 {
 {
-
    addGroup( "Shapes" );
    addGroup( "Shapes" );
       INITPERSISTFIELD_SHAPEASSET(Shape, ShapeBaseData, "The source shape asset.");
       INITPERSISTFIELD_SHAPEASSET(Shape, ShapeBaseData, "The source shape asset.");
+      addField("computeCRC", TypeBool, Offset(computeCRC, ShapeBaseData),
+         "If true, verify that the CRC of the client's shape model matches the "
+         "server's CRC for the shape model when loaded by the client.");
       addField("silentBBoxValidation", TypeBool, Offset(silent_bbox_check, ShapeBaseData));
       addField("silentBBoxValidation", TypeBool, Offset(silent_bbox_check, ShapeBaseData));
       INITPERSISTFIELD_SHAPEASSET(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional.");
       INITPERSISTFIELD_SHAPEASSET(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional.");
    endGroup( "Shapes" );
    endGroup( "Shapes" );
@@ -614,12 +616,6 @@ void ShapeBaseData::initPersistFields()
          "transform and FOV (instead of the default eye transform)." );
          "transform and FOV (instead of the default eye transform)." );
    endGroup("Camera");
    endGroup("Camera");
 
 
-   addGroup( "Misc" );
-      addField( "computeCRC", TypeBool, Offset(computeCRC, ShapeBaseData),
-         "If true, verify that the CRC of the client's shape model matches the "
-         "server's CRC for the shape model when loaded by the client." );
-   endGroup( "Misc" );
-
    addGroup( "Reflection" );
    addGroup( "Reflection" );
       addField( "cubeReflectorDesc", TypeRealString, Offset( cubeDescName, ShapeBaseData ), 
       addField( "cubeReflectorDesc", TypeRealString, Offset( cubeDescName, ShapeBaseData ), 
          "References a ReflectorDesc datablock that defines performance and quality properties for dynamic reflections.\n");
          "References a ReflectorDesc datablock that defines performance and quality properties for dynamic reflections.\n");
@@ -631,6 +627,12 @@ void ShapeBaseData::initPersistFields()
 
 
    addField("remapTextureTags",      TypeString,   Offset(remap_txr_tags, ShapeBaseData));
    addField("remapTextureTags",      TypeString,   Offset(remap_txr_tags, ShapeBaseData));
 
 
+   // disallow some field substitutions
+   onlyKeepClearSubstitutions("debris"); // subs resolving to "~~", or "~0" are OK
+   onlyKeepClearSubstitutions("explosion");
+   onlyKeepClearSubstitutions("underwaterExplosion");
+   Parent::initPersistFields();
+
    addGroup("BL Projected Shadows");
    addGroup("BL Projected Shadows");
       addField("shadowSize", TypeS32, Offset(shadowSize, ShapeBaseData),
       addField("shadowSize", TypeS32, Offset(shadowSize, ShapeBaseData),
          "Size of the projected shadow texture (must be power of 2).");
          "Size of the projected shadow texture (must be power of 2).");
@@ -644,11 +646,6 @@ void ShapeBaseData::initPersistFields()
          "on the shape bounds but can be adjusted with this field).");
          "on the shape bounds but can be adjusted with this field).");
    endGroup("BL Projected Shadows");
    endGroup("BL Projected Shadows");
 
 
-   // disallow some field substitutions
-   onlyKeepClearSubstitutions("debris"); // subs resolving to "~~", or "~0" are OK
-   onlyKeepClearSubstitutions("explosion");
-   onlyKeepClearSubstitutions("underwaterExplosion");
-   Parent::initPersistFields();
 }
 }
 
 
 DefineEngineMethod( ShapeBaseData, checkDeployPos, bool, ( TransformF txfm ),,
 DefineEngineMethod( ShapeBaseData, checkDeployPos, bool, ( TransformF txfm ),,

+ 1 - 2
Engine/source/T3D/staticShape.cpp

@@ -108,13 +108,12 @@ StaticShapeData::StaticShapeData(const StaticShapeData& other, bool temp_clone)
 
 
 void StaticShapeData::initPersistFields()
 void StaticShapeData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
    addField("noIndividualDamage",   TypeBool, Offset(noIndividualDamage,   StaticShapeData), "Deprecated\n\n @internal");
    addField("noIndividualDamage",   TypeBool, Offset(noIndividualDamage,   StaticShapeData), "Deprecated\n\n @internal");
    addField("dynamicType",          TypeS32,  Offset(dynamicTypeField,     StaticShapeData), 
    addField("dynamicType",          TypeS32,  Offset(dynamicTypeField,     StaticShapeData), 
       "@brief An integer value which, if speficied, is added to the value retured by getType().\n\n"
       "@brief An integer value which, if speficied, is added to the value retured by getType().\n\n"
       "This allows you to extend the type mask for a StaticShape that uses this datablock.  Type masks "
       "This allows you to extend the type mask for a StaticShape that uses this datablock.  Type masks "
       "are used for container queries, etc.");
       "are used for container queries, etc.");
-
-   Parent::initPersistFields();
 }
 }
 
 
 void StaticShapeData::packData(BitStream* stream)
 void StaticShapeData::packData(BitStream* stream)

+ 1 - 2
Engine/source/T3D/turret/aiTurretShape.cpp

@@ -124,6 +124,7 @@ AITurretShapeData::AITurretShapeData()
 
 
 void AITurretShapeData::initPersistFields()
 void AITurretShapeData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
    addGroup("AI Steering");
    addGroup("AI Steering");
       addField("maxScanHeading",       TypeF32,       Offset(maxScanHeading,        AITurretShapeData),
       addField("maxScanHeading",       TypeF32,       Offset(maxScanHeading,        AITurretShapeData),
          "@brief Maximum number of degrees to scan left and right.\n\n"
          "@brief Maximum number of degrees to scan left and right.\n\n"
@@ -194,8 +195,6 @@ void AITurretShapeData::initPersistFields()
          "Scoped to AITurretShapeData.");
          "Scoped to AITurretShapeData.");
 
 
    endArray( "States" );
    endArray( "States" );
-
-   Parent::initPersistFields();
 }
 }
 
 
 bool AITurretShapeData::onAdd()
 bool AITurretShapeData::onAdd()

+ 1 - 3
Engine/source/T3D/turret/turretShape.cpp

@@ -131,6 +131,7 @@ TurretShapeData::TurretShapeData()
 
 
 void TurretShapeData::initPersistFields()
 void TurretShapeData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
    addGroup("Steering");
    addGroup("Steering");
       addField("zRotOnly",       TypeBool,         Offset(zRotOnly,       TurretShapeData),
       addField("zRotOnly",       TypeBool,         Offset(zRotOnly,       TurretShapeData),
          "@brief Should the turret allow only z rotations.\n\n"
          "@brief Should the turret allow only z rotations.\n\n"
@@ -168,9 +169,6 @@ void TurretShapeData::initPersistFields()
    addField("cameraOffset",      TypeF32,       Offset(cameraOffset,       TurretShapeData),
    addField("cameraOffset",      TypeF32,       Offset(cameraOffset,       TurretShapeData),
       "Vertical (Z axis) height of the camera above the turret." );
       "Vertical (Z axis) height of the camera above the turret." );
    endGroup("Camera");
    endGroup("Camera");
-
-
-   Parent::initPersistFields();
 }
 }
 
 
 void TurretShapeData::packData(BitStream* stream)
 void TurretShapeData::packData(BitStream* stream)

+ 2 - 1
Engine/source/T3D/vehicles/flyingVehicle.cpp

@@ -175,6 +175,8 @@ bool FlyingVehicleData::preload(bool server, String &errorStr)
 
 
 void FlyingVehicleData::initPersistFields()
 void FlyingVehicleData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
+
    addGroup("Physics");
    addGroup("Physics");
    addField( "rollForce", TypeF32, Offset(rollForce, FlyingVehicleData),
    addField( "rollForce", TypeF32, Offset(rollForce, FlyingVehicleData),
       "@brief Damping torque against rolling maneuvers (rotation about the y-axis), "
       "@brief Damping torque against rolling maneuvers (rotation about the y-axis), "
@@ -249,7 +251,6 @@ void FlyingVehicleData::initPersistFields()
    addGroup("Sounds");
    addGroup("Sounds");
       INITPERSISTFIELD_SOUNDASSET_ENUMED(FlyingSounds, engineSounds, Sounds::MaxSounds, FlyingVehicleData, "EngineSounds.");
       INITPERSISTFIELD_SOUNDASSET_ENUMED(FlyingSounds, engineSounds, Sounds::MaxSounds, FlyingVehicleData, "EngineSounds.");
    endGroup("Sounds");
    endGroup("Sounds");
-   Parent::initPersistFields();
 }
 }
 
 
 void FlyingVehicleData::packData(BitStream* stream)
 void FlyingVehicleData::packData(BitStream* stream)

+ 1 - 4
Engine/source/T3D/vehicles/hoverVehicle.cpp

@@ -174,6 +174,7 @@ HoverVehicleData::~HoverVehicleData()
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------
 void HoverVehicleData::initPersistFields()
 void HoverVehicleData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
    addGroup("Physics");
    addGroup("Physics");
       addField( "normalForce", TypeF32, Offset(normalForce, HoverVehicleData),
       addField( "normalForce", TypeF32, Offset(normalForce, HoverVehicleData),
          "Force generated in the ground normal direction when the vehicle is not "
          "Force generated in the ground normal direction when the vehicle is not "
@@ -273,10 +274,6 @@ void HoverVehicleData::initPersistFields()
    addGroup("Particle Effects");
    addGroup("Particle Effects");
       INITPERSISTFIELD_SOUNDASSET_ENUMED(HoverSounds, hoverSoundsEnum, Sounds::MaxSounds, HoverVehicleData, "Sounds for hover vehicle.");
       INITPERSISTFIELD_SOUNDASSET_ENUMED(HoverSounds, hoverSoundsEnum, Sounds::MaxSounds, HoverVehicleData, "Sounds for hover vehicle.");
    endGroup("Sounds");
    endGroup("Sounds");
-
-
-
-   Parent::initPersistFields();
 }
 }
 
 
 
 

+ 32 - 32
Engine/source/T3D/vehicles/vehicle.cpp

@@ -274,6 +274,38 @@ void VehicleData::unpackData(BitStream* stream)
 
 
 void VehicleData::initPersistFields()
 void VehicleData::initPersistFields()
 {
 {
+   Parent::initPersistFields();   
+
+   addGroup("Particle Effects");
+   addField( "damageEmitter", TYPEID< ParticleEmitterData >(), Offset(damageEmitterList, VehicleData), VC_NUM_DAMAGE_EMITTERS,
+      "@brief Array of particle emitters used to generate damage (dust, smoke etc) "
+      "effects.\n\n"
+      "Currently, the first two emitters (indices 0 and 1) are used when the damage "
+      "level exceeds the associated damageLevelTolerance. The 3rd emitter is used "
+      "when the emitter point is underwater.\n\n"
+      "@see damageEmitterOffset" );
+   addField( "damageEmitterOffset", TypePoint3F, Offset(damageEmitterOffset, VehicleData), VC_NUM_DAMAGE_EMITTER_AREAS,
+      "@brief Object space \"x y z\" offsets used to emit particles for the "
+      "active damageEmitter.\n\n"
+      "@tsexample\n"
+      "// damage levels\n"
+      "damageLevelTolerance[0] = 0.5;\n"
+      "damageEmitter[0] = SmokeEmitter;\n"
+      "// emit offsets (used for all active damage level emitters)\n"
+      "damageEmitterOffset[0] = \"0.5 3 1\";\n"
+      "damageEmitterOffset[1] = \"-0.5 3 1\";\n"
+      "numDmgEmitterAreas = 2;\n"
+      "@endtsexample\n" );
+   addField( "damageLevelTolerance", TypeF32, Offset(damageLevelTolerance, VehicleData), VC_NUM_DAMAGE_LEVELS,
+      "@brief Damage levels (as a percentage of maxDamage) above which to begin "
+      "emitting particles from the associated damageEmitter.\n\n"
+      "Levels should be in order of increasing damage.\n\n"
+      "@see damageEmitterOffset" );
+   addField( "numDmgEmitterAreas", TypeF32, Offset(numDmgEmitterAreas, VehicleData),
+      "Number of damageEmitterOffset values to use for each damageEmitter.\n\n"
+      "@see damageEmitterOffset" );
+   endGroup("Particle Effects");
+
    addGroup("Physics");
    addGroup("Physics");
    addField("enablePhysicsRep", TypeBool, Offset(enablePhysicsRep, VehicleData),
    addField("enablePhysicsRep", TypeBool, Offset(enablePhysicsRep, VehicleData),
       "@brief Creates a representation of the object in the physics plugin.\n");
       "@brief Creates a representation of the object in the physics plugin.\n");
@@ -309,38 +341,6 @@ void VehicleData::initPersistFields()
    addField( "steeringReturnSpeedScale", TypeF32, Offset(steeringReturnSpeedScale, VehicleData),
    addField( "steeringReturnSpeedScale", TypeF32, Offset(steeringReturnSpeedScale, VehicleData),
       "Amount of effect the vehicle's speed has on its rate of steering return." );
       "Amount of effect the vehicle's speed has on its rate of steering return." );
    endGroup("AutoCorrection");
    endGroup("AutoCorrection");
-
-   addGroup("Particle Effects");
-   addField( "damageEmitter", TYPEID< ParticleEmitterData >(), Offset(damageEmitterList, VehicleData), VC_NUM_DAMAGE_EMITTERS,
-      "@brief Array of particle emitters used to generate damage (dust, smoke etc) "
-      "effects.\n\n"
-      "Currently, the first two emitters (indices 0 and 1) are used when the damage "
-      "level exceeds the associated damageLevelTolerance. The 3rd emitter is used "
-      "when the emitter point is underwater.\n\n"
-      "@see damageEmitterOffset" );
-   addField( "damageEmitterOffset", TypePoint3F, Offset(damageEmitterOffset, VehicleData), VC_NUM_DAMAGE_EMITTER_AREAS,
-      "@brief Object space \"x y z\" offsets used to emit particles for the "
-      "active damageEmitter.\n\n"
-      "@tsexample\n"
-      "// damage levels\n"
-      "damageLevelTolerance[0] = 0.5;\n"
-      "damageEmitter[0] = SmokeEmitter;\n"
-      "// emit offsets (used for all active damage level emitters)\n"
-      "damageEmitterOffset[0] = \"0.5 3 1\";\n"
-      "damageEmitterOffset[1] = \"-0.5 3 1\";\n"
-      "numDmgEmitterAreas = 2;\n"
-      "@endtsexample\n" );
-   addField( "damageLevelTolerance", TypeF32, Offset(damageLevelTolerance, VehicleData), VC_NUM_DAMAGE_LEVELS,
-      "@brief Damage levels (as a percentage of maxDamage) above which to begin "
-      "emitting particles from the associated damageEmitter.\n\n"
-      "Levels should be in order of increasing damage.\n\n"
-      "@see damageEmitterOffset" );
-   addField( "numDmgEmitterAreas", TypeF32, Offset(numDmgEmitterAreas, VehicleData),
-      "Number of damageEmitterOffset values to use for each damageEmitter.\n\n"
-      "@see damageEmitterOffset" );
-   endGroup("Particle Effects");
-
-   Parent::initPersistFields();
 }
 }
 
 
 
 

+ 12 - 12
Engine/source/T3D/vehicles/wheeledVehicle.cpp

@@ -448,6 +448,18 @@ bool WheeledVehicleData::mirrorWheel(Wheel* we)
 
 
 void WheeledVehicleData::initPersistFields()
 void WheeledVehicleData::initPersistFields()
 {
 {
+   Parent::initPersistFields();
+
+   addGroup("Particle Effects");
+   addField("tireEmitter", TYPEID< ParticleEmitterData >(), Offset(tireEmitter, WheeledVehicleData),
+      "ParticleEmitterData datablock used to generate particles from each wheel "
+      "when the vehicle is moving and the wheel is in contact with the ground.");
+   endGroup("Particle Effects");
+
+   addGroup("Sounds");
+   INITPERSISTFIELD_SOUNDASSET_ENUMED(WheeledVehicleSounds, WheeledVehicleSoundsEnum, MaxSounds, WheeledVehicleData, "Sounds related to wheeled vehicle.");
+   endGroup("Sounds");
+
    addGroup("Steering");
    addGroup("Steering");
    addField("maxWheelSpeed", TypeF32, Offset(maxWheelSpeed, WheeledVehicleData),
    addField("maxWheelSpeed", TypeF32, Offset(maxWheelSpeed, WheeledVehicleData),
       "@brief Maximum linear velocity of each wheel.\n\n"
       "@brief Maximum linear velocity of each wheel.\n\n"
@@ -463,18 +475,6 @@ void WheeledVehicleData::initPersistFields()
       "@brief Torque applied when braking.\n\n"
       "@brief Torque applied when braking.\n\n"
       "This controls how fast the vehicle will stop when the brakes are applied." );
       "This controls how fast the vehicle will stop when the brakes are applied." );
    endGroup("Steering");
    endGroup("Steering");
-
-   addGroup("Particle Effects");
-   addField("tireEmitter",TYPEID< ParticleEmitterData >(), Offset(tireEmitter, WheeledVehicleData),
-      "ParticleEmitterData datablock used to generate particles from each wheel "
-      "when the vehicle is moving and the wheel is in contact with the ground.");
-   endGroup("Particle Effects");
-
-   addGroup("Sounds");
-      INITPERSISTFIELD_SOUNDASSET_ENUMED(WheeledVehicleSounds, WheeledVehicleSoundsEnum, MaxSounds, WheeledVehicleData, "Sounds related to wheeled vehicle.");
-   endGroup("Sounds");
-   
-   Parent::initPersistFields();
 }
 }
 
 
 
 

+ 7 - 6
Engine/source/afx/afxMagicMissile.cpp

@@ -331,18 +331,19 @@ void afxMagicMissileData::initPersistFields()
 {
 {
    static IRangeValidatorScaled ticksFromMS(TickMs, 0, MaxLifetimeTicks);
    static IRangeValidatorScaled ticksFromMS(TickMs, 0, MaxLifetimeTicks);
 
 
-   addGroup("Particle Effects");
-      addField("particleEmitter", TYPEID<ParticleEmitterData>(), Offset(particleEmitter, afxMagicMissileData));
-      addField("particleWaterEmitter", TYPEID<ParticleEmitterData>(), Offset(particleWaterEmitter, afxMagicMissileData));
-   endGroup("Particle Effects");
-
    addGroup("Shapes");
    addGroup("Shapes");
       INITPERSISTFIELD_SHAPEASSET(ProjectileShape, afxMagicMissileData, "Shape for the projectile");
       INITPERSISTFIELD_SHAPEASSET(ProjectileShape, afxMagicMissileData, "Shape for the projectile");
       addField("scale", TypePoint3F, Offset(scale, afxMagicMissileData));
       addField("scale", TypePoint3F, Offset(scale, afxMagicMissileData));
    endGroup("Shapes");
    endGroup("Shapes");
 
 
-   INITPERSISTFIELD_SOUNDASSET(ProjectileSound, afxMagicMissileData, "sound for the projectile");
+   addGroup("Particle Effects");
+      addField("particleEmitter", TYPEID<ParticleEmitterData>(), Offset(particleEmitter, afxMagicMissileData));
+      addField("particleWaterEmitter", TYPEID<ParticleEmitterData>(), Offset(particleWaterEmitter, afxMagicMissileData));
+   endGroup("Particle Effects");
 
 
+   addGroup("Sounds");
+      INITPERSISTFIELD_SOUNDASSET(ProjectileSound, afxMagicMissileData, "sound for the projectile");
+   endGroup("Sounds");
    /* From stock Projectile code...
    /* From stock Projectile code...
    addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, ProjectileData));
    addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, ProjectileData));
    addField("waterExplosion", TYPEID< ExplosionData >(), Offset(waterExplosion, ProjectileData));
    addField("waterExplosion", TYPEID< ExplosionData >(), Offset(waterExplosion, ProjectileData));

+ 5 - 2
Engine/source/afx/ce/afxModel.cpp

@@ -176,7 +176,7 @@ void afxModelData::initPersistFields()
       INITPERSISTFIELD_SHAPEASSET(Shape, afxModelData, "The name of a .dts format file to use for the model.");
       INITPERSISTFIELD_SHAPEASSET(Shape, afxModelData, "The name of a .dts format file to use for the model.");
    addGroup("Shapes");
    addGroup("Shapes");
 
 
-   addGroup("Rendering");
+   addGroup("Animation");
       addField("sequence",              TypeString, myOffset(sequence),
       addField("sequence",              TypeString, myOffset(sequence),
          "The name of an animation sequence to play in the model.");
          "The name of an animation sequence to play in the model.");
       addField("sequenceRate",          TypeF32,      myOffset(seq_rate),
       addField("sequenceRate",          TypeF32,      myOffset(seq_rate),
@@ -185,6 +185,9 @@ void afxModelData::initPersistFields()
          "An offset in seconds indicating a starting point for the animation sequence "
          "An offset in seconds indicating a starting point for the animation sequence "
          "specified by the sequence field. A rate of 1.0 (rather than sequenceRate) is used "
          "specified by the sequence field. A rate of 1.0 (rather than sequenceRate) is used "
          "to convert from seconds to the thread offset.");
          "to convert from seconds to the thread offset.");
+   endGroup("Animation");
+
+   addGroup("Rendering");
       addField("alphaMult",             TypeF32,      myOffset(alpha_mult),
       addField("alphaMult",             TypeF32,      myOffset(alpha_mult),
          "An alpha multiplier used to set maximum opacity of the model.");
          "An alpha multiplier used to set maximum opacity of the model.");
       addField("fogMult",               TypeF32,      myOffset(fog_mult), "");
       addField("fogMult",               TypeF32,      myOffset(fog_mult), "");
@@ -196,7 +199,7 @@ void afxModelData::initPersistFields()
          "that exists in the model, while the second is a new name to replace it. The string "
          "that exists in the model, while the second is a new name to replace it. The string "
          "can have any number of remapping tokens as long as the total string length does not "
          "can have any number of remapping tokens as long as the total string length does not "
          "exceed 255.");
          "exceed 255.");
-  addGroup("Rendering");
+  endGroup("Rendering");
 
 
   addGroup("Deprecated");
   addGroup("Deprecated");
   addField("useVertexAlpha",        TypeBool,     myOffset(use_vertex_alpha),
   addField("useVertexAlpha",        TypeBool,     myOffset(use_vertex_alpha),

+ 1 - 1
Engine/source/environment/VolumetricFog.cpp

@@ -165,6 +165,7 @@ VolumetricFog::~VolumetricFog()
 
 
 void VolumetricFog::initPersistFields()
 void VolumetricFog::initPersistFields()
 {
 {
+   Parent::initPersistFields();
    addGroup("Shapes");
    addGroup("Shapes");
       INITPERSISTFIELD_SHAPEASSET(Shape, VolumetricFog, "The source shape asset.");
       INITPERSISTFIELD_SHAPEASSET(Shape, VolumetricFog, "The source shape asset.");
    endGroup("Shapes");
    endGroup("Shapes");
@@ -212,7 +213,6 @@ void VolumetricFog::initPersistFields()
    addField("lightRayMod", TypeF32, Offset(mLightRayMod, VolumetricFog),
    addField("lightRayMod", TypeF32, Offset(mLightRayMod, VolumetricFog),
       "Modifier for LightRay PostFX when inside Fog.");
       "Modifier for LightRay PostFX when inside Fog.");
    endGroup("PostFX");
    endGroup("PostFX");
-   Parent::initPersistFields();
 }
 }
 
 
 bool VolumetricFog::_setShapeAsset(void* obj, const char* index, const char* data)
 bool VolumetricFog::_setShapeAsset(void* obj, const char* index, const char* data)

+ 13 - 0
Engine/source/environment/sun.cpp

@@ -138,9 +138,22 @@ void Sun::onRemove()
    removeFromScene();
    removeFromScene();
    Parent::onRemove();
    Parent::onRemove();
 }
 }
+const char * getDocsLink(const char* filename, U32 lineNumber)
+{
+   Vector<String> fileStringSplit;
+   String::String(filename).split("source", fileStringSplit);
+   String fileString = fileStringSplit.last();
+   String fileLineString = fileString + String::String("#L") + String::ToString(lineNumber);
+   String URL = String::String("<a:https://github.com/TorqueGameEngines/Torque3D/blob/development/Engine/source/") + fileLineString + String::String(">docs</a>");
+
+   return (new String(URL))->c_str();
+}
+
+#define doDocsLink getDocsLink(__FILE__,__LINE__)
 
 
 void Sun::initPersistFields()
 void Sun::initPersistFields()
 {
 {
+   addProtectedField("docs", TypeBool, NULL, &defaultProtectedNotSetFn, &defaultProtectedGetFn, doDocsLink);
    addGroup( "Orbit" );
    addGroup( "Orbit" );
 
 
       addField( "azimuth", TypeF32, Offset( mSunAzimuth, Sun ), 
       addField( "azimuth", TypeF32, Offset( mSunAzimuth, Sun ), 

+ 1 - 2
Engine/source/forest/forestItem.cpp

@@ -58,8 +58,6 @@ ForestItemData::ForestItemData()
 
 
 void ForestItemData::initPersistFields()
 void ForestItemData::initPersistFields()
 {
 {
-   Parent::initPersistFields();
-
    addGroup( "Shapes" );
    addGroup( "Shapes" );
 
 
       INITPERSISTFIELD_SHAPEASSET(Shape, ForestItemData, "Shape asset for this item type");
       INITPERSISTFIELD_SHAPEASSET(Shape, ForestItemData, "Shape asset for this item type");
@@ -108,6 +106,7 @@ void ForestItemData::initPersistFields()
          "Frequency (speed) of the effect on leafs/fronds." );
          "Frequency (speed) of the effect on leafs/fronds." );
 
 
    endGroup( "Wind" );
    endGroup( "Wind" );
+   Parent::initPersistFields();
 }
 }
 
 
 void ForestItemData::consoleInit()
 void ForestItemData::consoleInit()

+ 5 - 0
Engine/source/math/mathTypes.cpp

@@ -1011,6 +1011,11 @@ DefineEngineFunction( VectorOrthoBasis, MatrixF, ( AngAxisF aa ),,
    return mat;
    return mat;
 }
 }
 
 
+DefineEngineFunction(toEuler, VectorF, (MatrixF _in), ,
+   "#Brief get the rotation of a matrix\n")
+{
+   return _in.getForwardVector();
+}
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
 
 //ConsoleFunction(VectorRot, const char*, 3, 3, "(Vector3F, float) rotate a vector in 2d")
 //ConsoleFunction(VectorRot, const char*, 3, 3, "(Vector3F, float) rotate a vector in 2d")