Преглед изворни кода

fill in the validated variables

AzaezelX пре 7 месеци
родитељ
комит
f633ef3a3d
100 измењених фајлова са 859 додато и 816 уклоњено
  1. 4 4
      Engine/source/T3D/aiPlayer.cpp
  2. 4 3
      Engine/source/T3D/assets/ShapeAnimationAsset.cpp
  3. 21 21
      Engine/source/T3D/assets/SoundAsset.cpp
  4. 4 4
      Engine/source/T3D/assets/assetImporter.cpp
  5. 1 1
      Engine/source/T3D/camera.cpp
  6. 19 14
      Engine/source/T3D/debris.cpp
  7. 10 10
      Engine/source/T3D/decal/decalData.cpp
  8. 2 2
      Engine/source/T3D/fps/guiHealthBarHud.cpp
  9. 3 3
      Engine/source/T3D/fps/guiHealthTextHud.cpp
  10. 2 2
      Engine/source/T3D/fps/guiShapeNameHud.cpp
  11. 42 38
      Engine/source/T3D/fx/explosion.cpp
  12. 28 28
      Engine/source/T3D/fx/fxFoliageReplicator.cpp
  13. 25 25
      Engine/source/T3D/fx/fxShapeReplicator.cpp
  14. 30 30
      Engine/source/T3D/fx/groundCover.cpp
  15. 5 5
      Engine/source/T3D/fx/lightning.cpp
  16. 39 26
      Engine/source/T3D/fx/particle.cpp
  17. 16 18
      Engine/source/T3D/fx/particleEmitter.cpp
  18. 1 1
      Engine/source/T3D/fx/particleEmitter.h
  19. 3 2
      Engine/source/T3D/fx/particleEmitterNode.cpp
  20. 17 17
      Engine/source/T3D/fx/precipitation.cpp
  21. 7 7
      Engine/source/T3D/fx/ribbon.cpp
  22. 16 16
      Engine/source/T3D/fx/splash.cpp
  23. 1 1
      Engine/source/T3D/gameBase/gameBase.cpp
  24. 4 4
      Engine/source/T3D/groundPlane.cpp
  25. 4 4
      Engine/source/T3D/guiObjectView.cpp
  26. 17 14
      Engine/source/T3D/item.cpp
  27. 9 11
      Engine/source/T3D/levelInfo.cpp
  28. 24 21
      Engine/source/T3D/lightAnimData.cpp
  29. 8 3
      Engine/source/T3D/lightAnimData.h
  30. 5 5
      Engine/source/T3D/lightBase.cpp
  31. 8 6
      Engine/source/T3D/lightDescription.cpp
  32. 4 4
      Engine/source/T3D/lightFlareData.cpp
  33. 0 1
      Engine/source/T3D/lighting/boxEnvironmentProbe.cpp
  34. 2 2
      Engine/source/T3D/lighting/reflectionProbe.cpp
  35. 3 2
      Engine/source/T3D/missionArea.cpp
  36. 1 1
      Engine/source/T3D/missionMarker.cpp
  37. 4 2
      Engine/source/T3D/physicalZone.cpp
  38. 12 12
      Engine/source/T3D/physics/physicsDebris.cpp
  39. 10 10
      Engine/source/T3D/physics/physicsShape.cpp
  40. 82 81
      Engine/source/T3D/player.cpp
  41. 1 1
      Engine/source/T3D/pointLight.cpp
  42. 9 9
      Engine/source/T3D/projectile.cpp
  43. 6 6
      Engine/source/T3D/proximityMine.cpp
  44. 24 24
      Engine/source/T3D/rigidShape.cpp
  45. 9 9
      Engine/source/T3D/sfx/sfxEmitter.cpp
  46. 15 14
      Engine/source/T3D/shapeBase.cpp
  47. 26 26
      Engine/source/T3D/shapeImage.cpp
  48. 3 3
      Engine/source/T3D/spotLight.cpp
  49. 6 6
      Engine/source/T3D/tsStatic.cpp
  50. 9 9
      Engine/source/T3D/turret/aiTurretShape.cpp
  51. 6 6
      Engine/source/T3D/turret/turretShape.cpp
  52. 15 15
      Engine/source/T3D/vehicles/flyingVehicle.cpp
  53. 6 6
      Engine/source/T3D/vehicles/guiSpeedometer.cpp
  54. 19 19
      Engine/source/T3D/vehicles/hoverVehicle.cpp
  55. 10 10
      Engine/source/T3D/vehicles/vehicle.cpp
  56. 19 19
      Engine/source/T3D/vehicles/wheeledVehicle.cpp
  57. 5 5
      Engine/source/afx/afxEffectGroup.cpp
  58. 15 14
      Engine/source/afx/afxEffectWrapper.cpp
  59. 2 2
      Engine/source/afx/afxEffectron.cpp
  60. 21 20
      Engine/source/afx/afxMagicMissile.cpp
  61. 10 10
      Engine/source/afx/afxMagicSpell.cpp
  62. 9 9
      Engine/source/afx/afxSelectron.cpp
  63. 2 2
      Engine/source/afx/ce/afxAnimClip.cpp
  64. 3 3
      Engine/source/afx/ce/afxAreaDamage.cpp
  65. 2 1
      Engine/source/afx/ce/afxAudioBank.cpp
  66. 2 2
      Engine/source/afx/ce/afxCameraShake.cpp
  67. 4 4
      Engine/source/afx/ce/afxDamage.cpp
  68. 5 5
      Engine/source/afx/ce/afxLightBase_T3D.cpp
  69. 2 1
      Engine/source/afx/ce/afxMachineGun.cpp
  70. 4 4
      Engine/source/afx/ce/afxModel.cpp
  71. 5 5
      Engine/source/afx/ce/afxParticleEmitter.cpp
  72. 2 2
      Engine/source/afx/ce/afxPhraseEffect.cpp
  73. 4 2
      Engine/source/afx/ce/afxPhysicalZone.cpp
  74. 1 1
      Engine/source/afx/ce/afxPlayerMovement.cpp
  75. 1 1
      Engine/source/afx/ce/afxPointLight_T3D.cpp
  76. 3 3
      Engine/source/afx/ce/afxSpotLight_T3D.cpp
  77. 10 10
      Engine/source/afx/ce/afxZodiac.cpp
  78. 6 6
      Engine/source/afx/ce/afxZodiacPlane.cpp
  79. 1 1
      Engine/source/afx/ea/afxEA_Zodiac.cpp
  80. 2 2
      Engine/source/afx/forces/afxF_Drag.cpp
  81. 1 1
      Engine/source/afx/forces/afxF_Gravity.cpp
  82. 3 3
      Engine/source/afx/rpg/afxRPGMagicSpell.cpp
  83. 2 2
      Engine/source/afx/ui/afxGuiTextHud.cpp
  84. 1 1
      Engine/source/afx/util/afxParticlePool.cpp
  85. 4 4
      Engine/source/afx/util/afxPath.cpp
  86. 1 1
      Engine/source/afx/xm/afxXM_AltitudeConform.cpp
  87. 1 1
      Engine/source/afx/xm/afxXM_BoxAdapt.cpp
  88. 1 1
      Engine/source/afx/xm/afxXM_Freeze.cpp
  89. 1 1
      Engine/source/afx/xm/afxXM_GroundConform.cpp
  90. 1 1
      Engine/source/afx/xm/afxXM_Oscillate.cpp
  91. 1 1
      Engine/source/afx/xm/afxXM_OscillateZodiacColor.cpp
  92. 4 4
      Engine/source/afx/xm/afxXM_RandomRot.cpp
  93. 1 1
      Engine/source/afx/xm/afxXM_Shockwave.cpp
  94. 4 4
      Engine/source/afx/xm/afxXM_Spin.cpp
  95. 1 1
      Engine/source/afx/xm/afxXM_VelocityOffset.cpp
  96. 9 9
      Engine/source/afx/xm/afxXM_WaveBase.cpp
  97. 5 5
      Engine/source/afx/xm/afxXfmMod.cpp
  98. 8 8
      Engine/source/environment/VolumetricFog.cpp
  99. 3 3
      Engine/source/environment/basicClouds.cpp
  100. 6 6
      Engine/source/environment/cloudLayer.cpp

+ 4 - 4
Engine/source/T3D/aiPlayer.cpp

@@ -136,27 +136,27 @@ void AIPlayer::initPersistFields()
    docsURL;
    addGroup( "AI" );
 
-      addField( "mMoveTolerance", TypeF32, Offset( mMoveTolerance, AIPlayer ), 
+      addFieldV( "mMoveTolerance", TypeRangedF32, Offset( mMoveTolerance, AIPlayer ), &CommonValidators::PositiveFloat,
          "@brief Distance from destination before stopping.\n\n"
          "When the AIPlayer is moving to a given destination it will move to within "
          "this distance of the destination and then stop.  By providing this tolerance "
          "it helps the AIPlayer from never reaching its destination due to minor obstacles, "
          "rounding errors on its position calculation, etc.  By default it is set to 0.25.\n");
 
-      addField( "moveStuckTolerance", TypeF32, Offset( mMoveStuckTolerance, AIPlayer ), 
+      addFieldV( "moveStuckTolerance", TypeRangedF32, Offset( mMoveStuckTolerance, AIPlayer ), &CommonValidators::PositiveFloat,
          "@brief Distance tolerance on stuck check.\n\n"
          "When the AIPlayer is moving to a given destination, if it ever moves less than "
          "this tolerance during a single tick, the AIPlayer is considered stuck.  At this point "
          "the onMoveStuck() callback is called on the datablock.\n");
 
-      addField( "moveStuckTestDelay", TypeS32, Offset( mMoveStuckTestDelay, AIPlayer ), 
+      addFieldV( "moveStuckTestDelay", TypeRangedS32, Offset( mMoveStuckTestDelay, AIPlayer ), &CommonValidators::PositiveInt,
          "@brief The number of ticks to wait before testing if the AIPlayer is stuck.\n\n"
          "When the AIPlayer is asked to move, this property is the number of ticks to wait "
          "before the AIPlayer starts to check if it is stuck.  This delay allows the AIPlayer "
          "to accelerate to full speed without its initial slow start being considered as stuck.\n"
          "@note Set to zero to have the stuck test start immediately.\n");
 
-      addField( "AttackRadius", TypeF32, Offset( mAttackRadius, AIPlayer ), 
+      addFieldV( "AttackRadius", TypeRangedF32, Offset( mAttackRadius, AIPlayer ), &CommonValidators::PositiveFloat,
          "@brief Distance considered in firing range for callback purposes.");
            
    endGroup( "AI" );

+ 4 - 3
Engine/source/T3D/assets/ShapeAnimationAsset.cpp

@@ -45,6 +45,7 @@
 // Debug Profiling.
 #include "platform/profiler.h"
 
+#include "console/typeValidators.h"
 //-----------------------------------------------------------------------------
 
 IMPLEMENT_CONOBJECT(ShapeAnimationAsset);
@@ -133,10 +134,10 @@ void ShapeAnimationAsset::initPersistFields()
 
    addField("isBlend", TypeBool, Offset(mIsBlend, ShapeAnimationAsset), "Is this animation blended with another?");
    addField("blendRefAnimation", TypeString, Offset(mBlendAnimAssetName, ShapeAnimationAsset), "AssetID of the animation to reference for our blending");
-   addField("blendFrame", TypeS32, Offset(mBlendFrame, ShapeAnimationAsset), "Which frame of the reference animation do we use for our blending");
+   addFieldV("blendFrame", TypeRangedS32, Offset(mBlendFrame, ShapeAnimationAsset), &CommonValidators::PositiveInt, "Which frame of the reference animation do we use for our blending");
 
-   addField("startFrame", TypeS32, Offset(mStartFrame, ShapeAnimationAsset), "What frame does this animation clip start on");
-   addField("endFrame", TypeS32, Offset(mEndFrame, ShapeAnimationAsset), "What fram does this animation clip end on");
+   addFieldV("startFrame", TypeRangedS32, Offset(mStartFrame, ShapeAnimationAsset), &CommonValidators::PositiveInt, "What frame does this animation clip start on");
+   addFieldV("endFrame", TypeRangedS32, Offset(mEndFrame, ShapeAnimationAsset), &CommonValidators::PositiveInt, "What fram does this animation clip end on");
    addField("padRotation", TypeBool, Offset(mPadRotation, ShapeAnimationAsset), "Are the rotation values padded");
    addField("padTransforms", TypeBool, Offset(mPadTransforms, ShapeAnimationAsset), "Are the transform values padded");
 }

+ 21 - 21
Engine/source/T3D/assets/SoundAsset.cpp

@@ -53,6 +53,7 @@
 #include "sfx/sfxTypes.h"
 
 #include "SoundAssetInspectors.h"
+#include "console/typeValidators.h"
 
 //-----------------------------------------------------------------------------
 
@@ -184,7 +185,6 @@ SoundAsset::~SoundAsset()
 }
 
 //-----------------------------------------------------------------------------
-
 void SoundAsset::initPersistFields()
 {
    docsURL;
@@ -207,55 +207,55 @@ void SoundAsset::initPersistFields()
          "Behavior when moving out of this slot.\n"
          "After the #detailTimeOut has expired (if any), this slot determines what the controller "
          "will do before moving on to the next slot.");
-      addField("delayTimeIn", TypeF32, Offset(mPlaylist.mSlots.mDelayTimeIn.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
+      addFieldV("delayTimeIn", TypeRangedF32, Offset(mPlaylist.mSlots.mDelayTimeIn.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Seconds to wait after moving into slot before #transitionIn.");
       addField("delayTimeInVariance", TypePoint2F, Offset(mPlaylist.mSlots.mDelayTimeIn.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Bounds on randomization of #delayTimeIn.\n\n"
          "@ref SFXPlayList_randomization\n");
-      addField("delayTimeOut", TypeF32, Offset(mPlaylist.mSlots.mDelayTimeOut.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
+      addFieldV("delayTimeOut", TypeRangedF32, Offset(mPlaylist.mSlots.mDelayTimeOut.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Seconds to wait before moving out of slot after #transitionOut.");
       addField("delayTimeOutVariance", TypePoint2F, Offset(mPlaylist.mSlots.mDelayTimeOut.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Bounds on randomization of #delayTimeOut.\n\n"
          "@ref SFXPlayList_randomization\n");
-      addField("fadeTimeIn", TypeF32, Offset(mPlaylist.mSlots.mFadeTimeIn.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
+      addFieldV("fadeTimeIn", TypeRangedF32, Offset(mPlaylist.mSlots.mFadeTimeIn.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Seconds to fade sound in (-1 to use the track's own fadeInTime.)\n"
          "@see SFXDescription::fadeTimeIn");
       addField("fadeTimeInVariance", TypePoint2F, Offset(mPlaylist.mSlots.mFadeTimeIn.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Bounds on randomization of #fadeInTime.\n\n"
          "@ref SFXPlayList_randomization\n");
-      addField("fadeTimeOut", TypeF32, Offset(mPlaylist.mSlots.mFadeTimeOut.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
+      addFieldV("fadeTimeOut", TypeRangedF32, Offset(mPlaylist.mSlots.mFadeTimeOut.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Seconds to fade sound out (-1 to use the track's own fadeOutTime.)\n"
          "@see SFXDescription::fadeTimeOut");
       addField("fadeTimeOutVariance", TypePoint2F, Offset(mPlaylist.mSlots.mFadeTimeOut.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Bounds on randomization of #fadeOutTime\n\n"
          "@ref SFXPlayList_randomization\n");
-      addField("referenceDistance", TypeF32, Offset(mPlaylist.mSlots.mMinDistance.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
+      addFieldV("referenceDistance", TypeRangedF32, Offset(mPlaylist.mSlots.mMinDistance.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "@c referenceDistance to set for 3D sounds in this slot (<1 to use @c referenceDistance of track's own description).\n"
          "@see SFXDescription::referenceDistance");
       addField("referenceDistanceVariance", TypePoint2F, Offset(mPlaylist.mSlots.mMinDistance.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Bounds on randomization of #referenceDistance.\n\n"
          "@ref SFXPlayList_randomization\n");
-      addField("maxDistance", TypeF32, Offset(mPlaylist.mSlots.mMaxDistance.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
+      addFieldV("maxDistance", TypeRangedF32, Offset(mPlaylist.mSlots.mMaxDistance.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "@c maxDistance to apply to 3D sounds in this slot (<1 to use @c maxDistance of track's own description).\n"
          "@see SFXDescription::maxDistance");
       addField("maxDistanceVariance", TypePoint2F, Offset(mPlaylist.mSlots.mMaxDistance.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Bounds on randomization of #maxDistance.\n\n"
          "@ref SFXPlayList_randomization\n");
-      addField("volumeScale", TypeF32, Offset(mPlaylist.mSlots.mVolumeScale.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
+      addFieldV("volumeScale", TypeRangedF32, Offset(mPlaylist.mSlots.mVolumeScale.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Scale factor to apply to volume of sounds played on this list slot.\n"
          "This value will scale the actual volume level set on the track assigned to the slot, i.e. a value of 0.5 will "
          "cause the track to play at half-volume.");
       addField("volumeScaleVariance", TypePoint2F, Offset(mPlaylist.mSlots.mVolumeScale.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Bounds on randomization of #volumeScale.\n\n"
          "@ref SFXPlayList_randomization\n");
-      addField("pitchScale", TypeF32, Offset(mPlaylist.mSlots.mPitchScale.mValue, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
+      addFieldV("pitchScale", TypeRangedF32, Offset(mPlaylist.mSlots.mPitchScale.mValue, SoundAsset), &CommonValidators::PositiveFloat, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Scale factor to apply to pitch of sounds played on this list slot.\n"
          "This value will scale the actual pitch set on the track assigned to the slot, i.e. a value of 0.5 will "
          "cause the track to play at half its assigned speed.");
       addField("pitchScaleVariance", TypePoint2F, Offset(mPlaylist.mSlots.mPitchScale.mVariance, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Bounds on randomization of #pitchScale.\n\n"
          "@ref SFXPlayList_randomization\n");
-      addField("repeatCount", TypeS32, Offset(mPlaylist.mSlots.mRepeatCount, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
+      addFieldV("repeatCount", TypeRangedS32, Offset(mPlaylist.mSlots.mRepeatCount, SoundAsset), &CommonValidators::PositiveInt, SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "Number of times to loop this slot.");
       addField("state", TypeSFXStateName, Offset(mPlaylist.mSlots.mState, SoundAsset), SFXPlayList::SFXPlaylistSettings::NUM_SLOTS,
          "State that must be active for this slot to play.\n\n"
@@ -267,8 +267,8 @@ void SoundAsset::initPersistFields()
    endGroup("SoundSlots");
 
    addGroup("General Profile");
-   addField("pitchAdjust", TypeF32, Offset(mProfileDesc.mPitch, SoundAsset), "Adjustment of the pitch value 1 is default.");
-   addField("volumeAdjust", TypeF32, Offset(mProfileDesc.mVolume, SoundAsset), "Adjustment to the volume.");
+   addFieldV("pitchAdjust", TypeRangedF32, Offset(mProfileDesc.mPitch, SoundAsset), &CommonValidators::PositiveFloat, "Adjustment of the pitch value 1 is default.");
+   addFieldV("volumeAdjust", TypeRangedF32, Offset(mProfileDesc.mVolume, SoundAsset), &CommonValidators::PositiveFloat, "Adjustment to the volume.");
    addField("is3D", TypeBool, Offset(mProfileDesc.mIs3D, SoundAsset), "Set this sound to 3D.");
    addField("isLooping", TypeBool, Offset(mProfileDesc.mIsLooping, SoundAsset), "Does this sound loop.");
    // if streaming, a default packet size should be chosen for all sounds.
@@ -280,27 +280,27 @@ void SoundAsset::initPersistFields()
    endGroup("General Profile");
 
    addGroup("Fading");
-      addField("fadeInTime", TypeF32, Offset(mProfileDesc.mFadeInTime, SoundAsset), "Number of seconds to gradually fade in volume from zero when playback starts.");
-      addField("fadeOutTime", TypeF32, Offset(mProfileDesc.mFadeOutTime, SoundAsset), "Number of seconds to gradually fade out volume down to zero when playback is stopped or paused.");
+      addFieldV("fadeInTime", TypeRangedF32, Offset(mProfileDesc.mFadeInTime, SoundAsset), &CommonValidators::PositiveFloat, "Number of seconds to gradually fade in volume from zero when playback starts.");
+      addFieldV("fadeOutTime", TypeRangedF32, Offset(mProfileDesc.mFadeOutTime, SoundAsset), &CommonValidators::PositiveFloat, "Number of seconds to gradually fade out volume down to zero when playback is stopped or paused.");
       addField("fadeInEase", TypeEaseF, Offset(mProfileDesc.mFadeInEase, SoundAsset), "Easing curve for fade-in transition.");
       addField("fadeOutEase", TypeEaseF, Offset(mProfileDesc.mFadeOutEase, SoundAsset), "Easing curve for fade-out transition.");
       addField("fadeLoops", TypeBool, Offset(mProfileDesc.mFadeLoops, SoundAsset), "Fade each cycle of a loop in and/or out; otherwise only fade-in first cycle.");
    endGroup("Fading");
 
    addGroup("3D");
-      addField("minDistance", TypeF32, Offset(mProfileDesc.mMinDistance, SoundAsset), "Minimum distance for sound.");
-      addField("maxDistance", TypeF32, Offset(mProfileDesc.mMaxDistance, SoundAsset), "Max distance for sound.");
-      addField("coneInsideAngle", TypeS32, Offset(mProfileDesc.mConeInsideAngle, SoundAsset), "Cone inside angle.");
-      addField("coneOutsideAngle", TypeS32, Offset(mProfileDesc.mConeOutsideAngle, SoundAsset), "Cone outside angle.");
-      addField("coneOutsideVolume", TypeF32, Offset(mProfileDesc.mConeOutsideVolume, SoundAsset), "Cone outside volume.");
-      addField("rolloffFactor", TypeF32, Offset(mProfileDesc.mRolloffFactor, SoundAsset), "Rolloff factor.");
+      addFieldV("minDistance", TypeRangedF32, Offset(mProfileDesc.mMinDistance, SoundAsset), &CommonValidators::PositiveFloat, "Minimum distance for sound.");
+      addFieldV("maxDistance", TypeRangedF32, Offset(mProfileDesc.mMaxDistance, SoundAsset), &CommonValidators::PositiveFloat, "Max distance for sound.");
+      addFieldV("coneInsideAngle", TypeRangedS32, Offset(mProfileDesc.mConeInsideAngle, SoundAsset), &CommonValidators::S32_PosDegreeRange, "Cone inside angle.");
+      addFieldV("coneOutsideAngle", TypeRangedS32, Offset(mProfileDesc.mConeOutsideAngle, SoundAsset), &CommonValidators::S32_PosDegreeRange, "Cone outside angle.");
+      addFieldV("coneOutsideVolume", TypeRangedF32, Offset(mProfileDesc.mConeOutsideVolume, SoundAsset), &CommonValidators::NormalizedFloat, "Cone outside volume.");
+      addFieldV("rolloffFactor", TypeRangedF32, Offset(mProfileDesc.mRolloffFactor, SoundAsset), &CommonValidators::PositiveFloat, "Rolloff factor.");
       addField("scatterDistance", TypePoint3F, Offset(mProfileDesc.mScatterDistance, SoundAsset), "Randomization to the spacial position of the sound.");
    endGroup("3D");
 
    addGroup("Playlist settings");
       addField("random", TYPEID< SFXPlayList::ERandomMode >(), Offset(mPlaylist.mRandomMode, SoundAsset), "Slot playback order randomization pattern.");
       addField("loopMode", TYPEID< SFXPlayList::ELoopMode >(), Offset(mPlaylist.mLoopMode, SoundAsset), "Behavior when description has looping enabled.");
-      addField("numSlotsToPlay", TypeS32, Offset(mPlaylist.mNumSlotsToPlay, SoundAsset), "Number of slots to play.");
+      addFieldV("numSlotsToPlay", TypeRangedS32, Offset(mPlaylist.mNumSlotsToPlay, SoundAsset), &playlistSlotRange, "Number of slots to play.");
       addField("trace", TypeBool, Offset(mPlaylist.mTrace, SoundAsset), "Enable/disable execution tracing for this playlist (local only).");
    endGroup("Playlist settings");
 }

+ 4 - 4
Engine/source/T3D/assets/assetImporter.cpp

@@ -153,7 +153,7 @@ void AssetImportConfig::initPersistFields()
       addField("DoUpAxisOverride", TypeBool, Offset(DoUpAxisOverride, AssetImportConfig), "Indicates if the up axis in the model file should be overridden");
       addField("UpAxisOverride", TypeRealString, Offset(UpAxisOverride, AssetImportConfig), "If overriding, what axis should be used as up. Options are X_AXIS, Y_AXIS, Z_AXIS");
       addField("DoScaleOverride", TypeBool, Offset(DoScaleOverride, AssetImportConfig), "Indicates if the scale in the model file should be overridden");
-      addField("ScaleOverride", TypeF32, Offset(ScaleOverride, AssetImportConfig), "If overriding, what scale should be used");
+      addFieldV("ScaleOverride", TypeRangedF32, Offset(ScaleOverride, AssetImportConfig), &CommonValidators::PositiveFloat, "If overriding, what scale should be used");
       addField("IgnoreNodeScale", TypeBool, Offset(IgnoreNodeScale, AssetImportConfig), "Indicates if scale of nodes should be ignored");
       addField("AdjustCenter", TypeBool, Offset(AdjustCenter, AssetImportConfig), "Indicates if the center of the model file should be automatically recentered");
       addField("AdjustFloor", TypeBool, Offset(AdjustFloor, AssetImportConfig), "Indicates if the floor height of the model file should be automatically zero'd");
@@ -223,15 +223,15 @@ void AssetImportConfig::initPersistFields()
       addField("UseMips", TypeBool, Offset(UseMips, AssetImportConfig), "Indicates if images imported with this configuration utilize mipmaps");
 
       addField("IsHDR", TypeBool, Offset(IsHDR, AssetImportConfig), "Indicates if images imported with this configuration are in an HDR format");
-      addField("Scaling", TypeF32, Offset(Scaling, AssetImportConfig), "Indicates what amount of scaling images imported with this configuration use");
+      addFieldV("Scaling", TypeRangedF32, Offset(Scaling, AssetImportConfig), &CommonValidators::PositiveFloat, "Indicates what amount of scaling images imported with this configuration use");
       addField("ImagesCompressed", TypeBool, Offset(ImagesCompressed, AssetImportConfig), "Indicates if images imported with this configuration are compressed");
       addField("GenerateMaterialOnImport", TypeBool, Offset(GenerateMaterialOnImport, AssetImportConfig), "Indicates if images imported with this configuration generate a parent material for it as well");
    endGroup("Images");
 
    addGroup("Sounds");
       addField("importSounds", TypeBool, Offset(importSounds, AssetImportConfig), "Indicates if sounds are imported with this configuration");
-      addField("VolumeAdjust", TypeF32, Offset(VolumeAdjust, AssetImportConfig), "Indicates what amount the volume is adjusted on sounds imported with this configuration");
-      addField("PitchAdjust", TypeF32, Offset(PitchAdjust, AssetImportConfig), "Indicates what amount the pitch is adjusted on sounds imported with this configuration");
+      addFieldV("VolumeAdjust", TypeRangedF32, Offset(VolumeAdjust, AssetImportConfig), &CommonValidators::PositiveFloat, "Indicates what amount the volume is adjusted on sounds imported with this configuration");
+      addFieldV("PitchAdjust", TypeRangedF32, Offset(PitchAdjust, AssetImportConfig), &CommonValidators::PositiveFloat, "Indicates what amount the pitch is adjusted on sounds imported with this configuration");
       addField("SoundsCompressed", TypeBool, Offset(SoundsCompressed, AssetImportConfig), "Indicates if sounds imported with this configuration are compressed");
    endGroup("Sounds");
 }

+ 1 - 1
Engine/source/T3D/camera.cpp

@@ -1322,7 +1322,7 @@ void Camera::initPersistFields()
          "Apply smoothing (acceleration and damping) to camera rotations." );
       addProtectedField( "mass",            TypeF32,    Offset(mMass, Camera),            &_setNewtonField, &defaultProtectedGetFn,
          "The camera's mass (Newton mode only).  Default value is 10." );
-      addProtectedField( "drag",            TypeF32,    Offset(mDrag, Camera),            &_setNewtonField, &defaultProtectedGetFn,
+      addProtectedFieldV( "drag",            TypeRangedF32,    Offset(mDrag, Camera),            &_setNewtonField, &defaultProtectedGetFn, &CommonValidators::PositiveNonZeroFloat,
          "Drag on camera when moving (Newton mode only).  Default value is 2." );
       addProtectedField( "force",           TypeF32,    Offset(mFlyForce, Camera),        &_setNewtonField, &defaultProtectedGetFn,
          "Force applied on camera when asked to move (Newton mode only).  Default value is 500." );

+ 19 - 14
Engine/source/T3D/debris.cpp

@@ -293,6 +293,11 @@ bool DebrisData::preload(bool server, String &errorStr)
    return true;
 }
 
+FRangeValidator debElasticityRange(-10.0f, 10.0f);
+FRangeValidator debFrictionRange(-10.0f, 10.0f);
+IRangeValidator debBounceRange(0, 10000);
+FRangeValidator debSpinSpeedRange(-10000.0f, 10000.0f);
+FRangeValidator debLifetimeRange(0.0f, 1000.0f);
 void DebrisData::initPersistFields()
 {
    docsURL;
@@ -312,33 +317,33 @@ void DebrisData::initPersistFields()
    endGroup("Datablocks");
 
    addGroup("Physics");
-   addField("elasticity",           TypeF32,                     Offset(elasticity,          DebrisData), 
+   addFieldV("elasticity",           TypeRangedF32,                     Offset(elasticity,          DebrisData), &debElasticityRange,
       "@brief A floating-point value specifying how 'bouncy' this object is.\n\nMust be in the range of -10 to 10.\n");
-   addField("friction",             TypeF32,                     Offset(friction,            DebrisData), 
+   addFieldV("friction", TypeRangedF32,                     Offset(friction,            DebrisData), &debFrictionRange,
       "@brief A floating-point value specifying how much velocity is lost to impact and sliding friction.\n\nMust be in the range of -10 to 10.\n");
-   addField("numBounces",           TypeS32,                     Offset(numBounces,          DebrisData), 
+   addFieldV("numBounces",           TypeRangedS32,                     Offset(numBounces,          DebrisData), &debBounceRange,
       "@brief How many times to allow this debris object to bounce until it either explodes, becomes static or snaps (defined in explodeOnMaxBounce, staticOnMaxBounce, snapOnMaxBounce).\n\n"
       "Must be within the range of 0 to 10000.\n"
       "@see bounceVariance\n");
-   addField("bounceVariance",       TypeS32,                     Offset(bounceVariance,      DebrisData), 
+   addFieldV("bounceVariance", TypeRangedS32,                     Offset(bounceVariance,      DebrisData), &debBounceRange,
       "@brief Allowed variance in the value of numBounces.\n\nMust be less than numBounces.\n@see numBounces\n");
-   addField("minSpinSpeed",         TypeF32,                     Offset(minSpinSpeed,        DebrisData), 
+   addFieldV("minSpinSpeed", TypeRangedF32,                     Offset(minSpinSpeed,        DebrisData),&debSpinSpeedRange,
       "@brief Minimum speed that this debris object will rotate.\n\nMust be in the range of -10000 to 1000, and must be less than maxSpinSpeed.\n@see maxSpinSpeed\n");
-   addField("maxSpinSpeed",         TypeF32,                     Offset(maxSpinSpeed,        DebrisData), 
+   addFieldV("maxSpinSpeed", TypeRangedF32,                     Offset(maxSpinSpeed,        DebrisData), &debSpinSpeedRange,
       "@brief Maximum speed that this debris object will rotate.\n\nMust be in the range of -10000 to 10000.\n@see minSpinSpeed\n");
-   addField("gravModifier",         TypeF32,                     Offset(gravModifier,        DebrisData), "How much gravity affects debris.");
-   addField("terminalVelocity",     TypeF32,                     Offset(terminalVelocity,    DebrisData), "Max velocity magnitude.");
-   addField("velocity",             TypeF32,                     Offset(velocity,            DebrisData), 
+   addFieldV("gravModifier", TypeRangedF32,                     Offset(gravModifier,        DebrisData), &CommonValidators::F32Range, "How much gravity affects debris.");
+   addFieldV("terminalVelocity", TypeRangedF32,                     Offset(terminalVelocity,    DebrisData), &CommonValidators::PositiveFloat, "Max velocity magnitude.");
+   addFieldV("velocity", TypeRangedF32,                     Offset(velocity,            DebrisData), &CommonValidators::PositiveFloat,
       "@brief Speed at which this debris object will move.\n\n@see velocityVariance\n");
-   addField("velocityVariance",     TypeF32,                     Offset(velocityVariance,    DebrisData), 
+   addFieldV("velocityVariance", TypeRangedF32,                     Offset(velocityVariance,    DebrisData), &CommonValidators::PositiveFloat,
       "@brief Allowed variance in the value of velocity\n\nMust be less than velocity.\n@see velocity\n");
-   addField("lifetime",             TypeF32,                     Offset(lifetime,            DebrisData), 
+   addFieldV("lifetime",             TypeRangedF32,                     Offset(lifetime,            DebrisData), &debLifetimeRange,
       "@brief Amount of time until this debris object is destroyed.\n\nMust be in the range of 0 to 1000.\n@see lifetimeVariance");
-   addField("lifetimeVariance",     TypeF32,                     Offset(lifetimeVariance,    DebrisData), 
+   addFieldV("lifetimeVariance", TypeRangedF32,                     Offset(lifetimeVariance,    DebrisData), &debLifetimeRange,
       "@brief Allowed variance in the value of lifetime.\n\nMust be less than lifetime.\n@see lifetime\n");
    addField("useRadiusMass",        TypeBool,                    Offset(useRadiusMass,       DebrisData), 
       "@brief Use mass calculations based on radius.\n\nAllows for the adjustment of elasticity and friction based on the Debris size.\n@see baseRadius\n");
-   addField("baseRadius",           TypeF32,                     Offset(baseRadius,          DebrisData), 
+   addFieldV("baseRadius", TypeRangedF32,                     Offset(baseRadius,          DebrisData), &CommonValidators::PositiveFloat,
       "@brief Radius at which the standard elasticity and friction apply.\n\nOnly used when useRaduisMass is true.\n@see useRadiusMass.\n");
    endGroup("Physics");
 
@@ -571,7 +576,7 @@ void Debris::initPersistFields()
    docsURL;
    addGroup( "Debris" );	
    
-      addField( "lifetime", TypeF32, Offset(mLifetime, Debris), 
+      addFieldV( "lifetime", TypeRangedF32, Offset(mLifetime, Debris), &CommonValidators::PositiveFloat,
          "@brief Length of time for this debris object to exist. When expired, the object will be deleted.\n\n"
          "The initial lifetime value comes from the DebrisData datablock.\n"
          "@see DebrisData::lifetime\n"

+ 10 - 10
Engine/source/T3D/decal/decalData.cpp

@@ -141,15 +141,15 @@ void DecalData::initPersistFields()
    docsURL;
    addGroup( "Decal" );
 
-      addField( "size", TypeF32, Offset( size, DecalData ), 
+      addFieldV( "size", TypeRangedF32, Offset( size, DecalData ), &CommonValidators::PositiveFloat,
          "Width and height of the decal in meters before scale is applied." );
 
       INITPERSISTFIELD_MATERIALASSET(Material, DecalData, "Material to use for this decal.");
 
-      addField( "lifeSpan", TypeS32, Offset( lifeSpan, DecalData ),
+      addFieldV( "lifeSpan", TypeRangedS32, Offset( lifeSpan, DecalData ), &CommonValidators::PositiveInt,
          "Time (in milliseconds) before this decal will be automatically deleted." );
 
-      addField( "fadeTime", TypeS32, Offset( fadeTime, DecalData ),
+      addFieldV( "fadeTime", TypeRangedS32, Offset( fadeTime, DecalData ), &CommonValidators::PositiveInt,
          "@brief Time (in milliseconds) over which to fade out the decal before "
          "deleting it at the end of its lifetime.\n\n"
          "@see lifeSpan" );
@@ -158,13 +158,13 @@ void DecalData::initPersistFields()
 
    addGroup( "Rendering" );
 
-      addField( "fadeStartPixelSize", TypeF32, Offset( fadeStartPixelSize, DecalData ), 
+      addFieldV( "fadeStartPixelSize", TypeRangedF32, Offset( fadeStartPixelSize, DecalData ), &CommonValidators::NegDefaultF32,
          "@brief LOD value - size in pixels at which decals of this type begin "
          "to fade out.\n\n"
          "This should be a larger value than #fadeEndPixelSize. However, you may "
          "also set this to a negative value to disable lod-based fading." );
 
-      addField( "fadeEndPixelSize", TypeF32, Offset( fadeEndPixelSize, DecalData ), 
+      addFieldV( "fadeEndPixelSize", TypeRangedF32, Offset( fadeEndPixelSize, DecalData ), &CommonValidators::PositiveFloat,
          "@brief LOD value - size in pixels at which decals of this type are "
          "fully faded out.\n\n"
          "This should be a smaller value than #fadeStartPixelSize." );
@@ -173,7 +173,7 @@ void DecalData::initPersistFields()
          "Default renderPriority for decals of this type (determines draw "
          "order when decals overlap)." );
 
-      addField( "clippingAngle", TypeF32, Offset( clippingAngle, DecalData ),
+      addFieldV( "clippingAngle", TypeRangedF32, Offset( clippingAngle, DecalData ), &CommonValidators::PosDegreeRangeQuarter,
          "The angle in degrees used to clip geometry that faces away from the "
          "decal projection direction." );
 
@@ -181,23 +181,23 @@ void DecalData::initPersistFields()
 
    addGroup( "Texturing" );
 
-      addField( "frame", TypeS32, Offset( frame, DecalData ),
+      addFieldV( "frame", TypeRangedS32, Offset( frame, DecalData ), &CommonValidators::PositiveInt,
          "Index of the texture rectangle within the imagemap to use for this decal." );
 
       addField( "randomize", TypeBool, Offset( randomize, DecalData ),
          "If true, a random frame from the imagemap is selected for each "
          "instance of the decal." );
 
-      addField( "textureCoordCount", TypeS32, Offset( texCoordCount, DecalData ),
+      addFieldV( "textureCoordCount", TypeRangedS32, Offset( texCoordCount, DecalData ), &CommonValidators::PositiveInt,
          "Number of individual frames in the imagemap (maximum 16)." );
 
-      addField( "texRows", TypeS32, Offset( texRows, DecalData ),
+      addFieldV( "texRows", TypeRangedS32, Offset( texRows, DecalData ), &CommonValidators::PositiveInt,
          "@brief Number of rows in the supplied imagemap.\n\n"
          "Use #texRows and #texCols if the imagemap frames are arranged in a "
          "grid; use #textureCoords to manually specify UV coordinates for "
          "irregular sized frames." );
 
-      addField( "texCols", TypeS32, Offset( texCols, DecalData ),
+      addFieldV( "texCols", TypeRangedS32, Offset( texCols, DecalData ), &CommonValidators::PositiveInt,
          "@brief Number of columns in the supplied imagemap.\n\n"
          "Use #texRows and #texCols if the imagemap frames are arranged in a "
          "grid; use #textureCoords to manually specify UV coordinates for "

+ 2 - 2
Engine/source/T3D/fps/guiHealthBarHud.cpp

@@ -120,8 +120,8 @@ void GuiHealthBarHud::initPersistFields()
    endGroup("Colors");		
 
    addGroup("Pulse");		
-   addField( "pulseRate", TypeS32, Offset( mPulseRate, GuiHealthBarHud ), "Speed at which the control will pulse." );
-   addField( "pulseThreshold", TypeF32, Offset( mPulseThreshold, GuiHealthBarHud ), "Health level the control must be under before the control will pulse." );
+   addFieldV( "pulseRate", TypeRangedS32, Offset( mPulseRate, GuiHealthBarHud ), &CommonValidators::PositiveInt, "Speed at which the control will pulse." );
+   addFieldV( "pulseThreshold", TypeRangedF32, Offset( mPulseThreshold, GuiHealthBarHud ), &CommonValidators::PositiveFloat, "Health level the control must be under before the control will pulse." );
    endGroup("Pulse");		
 
    addGroup("Misc");		

+ 3 - 3
Engine/source/T3D/fps/guiHealthTextHud.cpp

@@ -132,9 +132,9 @@ void GuiHealthTextHud::initPersistFields()
    endGroup("View");    
   
    addGroup("Alert");  
-   addField("warnThreshold", TypeF32, Offset(mWarnLevel, GuiHealthTextHud), "The health level at which to use the warningColor.");    
-   addField("pulseThreshold", TypeF32, Offset(mPulseThreshold, GuiHealthTextHud), "Health level at which to begin pulsing.");  
-   addField("pulseRate", TypeS32, Offset(mPulseRate, GuiHealthTextHud), "Speed at which the control will pulse.");  
+   addFieldV("warnThreshold", TypeRangedF32, Offset(mWarnLevel, GuiHealthTextHud), &CommonValidators::PositiveFloat, "The health level at which to use the warningColor.");
+   addFieldV("pulseThreshold", TypeRangedF32, Offset(mPulseThreshold, GuiHealthTextHud), &CommonValidators::PositiveFloat, "Health level at which to begin pulsing.");
+   addFieldV("pulseRate", TypeRangedS32, Offset(mPulseRate, GuiHealthTextHud), &CommonValidators::PositiveInt, "Speed at which the control will pulse.");
    endGroup("Alert");  
   
    Parent::initPersistFields();  

+ 2 - 2
Engine/source/T3D/fps/guiShapeNameHud.cpp

@@ -141,8 +141,8 @@ void GuiShapeNameHud::initPersistFields()
    addField( "showLabelFill",  TypeBool, Offset( mShowLabelFill, GuiShapeNameHud ), "If true, we draw a background for each shape name label." );
    addField( "showLabelFrame", TypeBool, Offset( mShowLabelFrame, GuiShapeNameHud ), "If true, we draw a frame around each shape name label."  );
    addField( "labelPadding", TypePoint2I, Offset( mLabelPadding, GuiShapeNameHud ), "The padding (in pixels) between the label text and the frame." );
-   addField( "verticalOffset", TypeF32, Offset( mVerticalOffset, GuiShapeNameHud ), "Amount to vertically offset the control in relation to the ShapeBase object in focus." );
-   addField( "distanceFade", TypeF32, Offset( mDistanceFade, GuiShapeNameHud ), "Visibility distance (how far the player must be from the ShapeBase object in focus) for this control to render." );
+   addFieldV( "verticalOffset", TypeRangedF32, Offset( mVerticalOffset, GuiShapeNameHud ), &CommonValidators::F32Range, "Amount to vertically offset the control in relation to the ShapeBase object in focus." );
+   addFieldV( "distanceFade", TypeRangedF32, Offset( mDistanceFade, GuiShapeNameHud ), &CommonValidators::PositiveFloat, "Visibility distance (how far the player must be from the ShapeBase object in focus) for this control to render." );
    endGroup("Misc");
    Parent::initPersistFields();
 }

+ 42 - 38
Engine/source/T3D/fx/explosion.cpp

@@ -384,7 +384,11 @@ ExplosionData* ExplosionData::cloneAndPerformSubstitutions(const SimObject* owne
 
    return sub_explosion_db;
 }
-
+IRangeValidator expPartDensityRange(0, 1<<14);
+IRangeValidator expDebrisNumRange(0, 1000);
+FRangeValidator expPlaySpeedRange(0.05f, FLT_MAX);
+FRangeValidator expLightRadiusRange(0.0f, MaxLightRadius,1<<8);
+FRangeValidator expTimeRange(0.0f, 1.0f, 1 << 8);
 void ExplosionData::initPersistFields()
 {
    docsURL;
@@ -409,10 +413,10 @@ void ExplosionData::initPersistFields()
          "The second effect spawns the list of ParticleEmitters given by the emitter[] "
          "field. These emitters generate particles in the normal way throughout the "
          "lifetime of the explosion." );
-      addField( "particleDensity", TypeS32, Offset(particleDensity, ExplosionData),
+      addFieldV( "particleDensity", TypeRangedS32, Offset(particleDensity, ExplosionData), &expPartDensityRange,
          "@brief Density of the particle cloud created at the start of the explosion.\n\n"
          "@see particleEmitter" );
-      addField( "particleRadius", TypeF32, Offset(particleRadius, ExplosionData),
+      addFieldV( "particleRadius", TypeRangedF32, Offset(particleRadius, ExplosionData),&CommonValidators::PositiveFloat,
          "@brief Radial distance from the explosion center at which cloud particles "
          "are emitted.\n\n"
          "@see particleEmitter" );
@@ -425,21 +429,21 @@ void ExplosionData::initPersistFields()
    addGroup("Debris");
       addField( "debris", TYPEID< DebrisData >(), Offset(debrisList, ExplosionData), EC_NUM_DEBRIS_TYPES,
          "List of DebrisData objects to spawn with this explosion." );
-      addField( "debrisThetaMin", TypeF32, Offset(debrisThetaMin, ExplosionData),
+      addFieldV( "debrisThetaMin", TypeRangedF32, Offset(debrisThetaMin, ExplosionData), &CommonValidators::PosDegreeRangeHalf,
          "Minimum angle, from the horizontal plane, to eject debris from." );
-      addField( "debrisThetaMax", TypeF32, Offset(debrisThetaMax, ExplosionData),
+      addFieldV( "debrisThetaMax", TypeRangedF32, Offset(debrisThetaMax, ExplosionData), &CommonValidators::PosDegreeRangeHalf,
          "Maximum angle, from the horizontal plane, to eject debris from." );
-      addField( "debrisPhiMin", TypeF32, Offset(debrisPhiMin, ExplosionData),
+      addFieldV( "debrisPhiMin", TypeRangedF32, Offset(debrisPhiMin, ExplosionData), &CommonValidators::PosDegreeRange,
          "Minimum reference angle, from the vertical plane, to eject debris from." );
-      addField( "debrisPhiMax", TypeF32, Offset(debrisPhiMax, ExplosionData),
+      addFieldV( "debrisPhiMax", TypeRangedF32, Offset(debrisPhiMax, ExplosionData), &CommonValidators::PosDegreeRange,
          "Maximum reference angle, from the vertical plane, to eject debris from." );
-      addField( "debrisNum", TypeS32, Offset(debrisNum, ExplosionData),
+      addFieldV( "debrisNum", TypeRangedS32, Offset(debrisNum, ExplosionData), &expDebrisNumRange,
          "Number of debris objects to create." );
-      addField( "debrisNumVariance", TypeS32, Offset(debrisNumVariance, ExplosionData),
+      addFieldV( "debrisNumVariance", TypeRangedS32, Offset(debrisNumVariance, ExplosionData), &expDebrisNumRange,
          "Variance in the number of debris objects to create (must be from 0 - debrisNum)." );
-      addField( "debrisVelocity", TypeF32, Offset(debrisVelocity, ExplosionData),
+      addFieldV( "debrisVelocity", TypeRangedF32, Offset(debrisVelocity, ExplosionData), &CommonValidators::PositiveFloat,
          "Velocity to toss debris at." );
-      addField( "debrisVelocityVariance", TypeF32, Offset(debrisVelocityVariance, ExplosionData),
+      addFieldV( "debrisVelocityVariance", TypeRangedF32, Offset(debrisVelocityVariance, ExplosionData), &CommonValidators::PositiveFloat,
          "Variance in the debris initial velocity (must be >= 0)." );
       addField( "subExplosion", TYPEID< ExplosionData >(), Offset(explosionList, ExplosionData), EC_MAX_SUB_EXPLOSIONS,
          "List of additional ExplosionData objects to create at the start of the explosion." );
@@ -450,27 +454,27 @@ void ExplosionData::initPersistFields()
       addField("explosionScale", TypePoint3F, Offset(explosionScale, ExplosionData),
       "\"X Y Z\" scale factor applied to the explosionShape model at the start "
       "of the explosion.");
-       addField("playSpeed", TypeF32, Offset(playSpeed, ExplosionData),
+       addFieldV("playSpeed", TypeRangedF32, Offset(playSpeed, ExplosionData),&expPlaySpeedRange,
           "Time scale at which to play the explosionShape <i>ambient</i> sequence.");
 
-      addField( "delayMS", TypeS32, Offset(delayMS, ExplosionData),
+      addFieldV( "delayMS", TypeRangedS32, Offset(delayMS, ExplosionData), &CommonValidators::PositiveInt,
          "Amount of time, in milliseconds, to delay the start of the explosion effect "
          "from the creation of the Explosion object." );
-      addField( "delayVariance", TypeS32, Offset(delayVariance, ExplosionData),
+      addFieldV( "delayVariance", TypeRangedS32, Offset(delayVariance, ExplosionData), &CommonValidators::PositiveInt,
          "Variance, in milliseconds, of delayMS." );
-      addField( "lifetimeMS", TypeS32, Offset(lifetimeMS, ExplosionData),
+      addFieldV( "lifetimeMS", TypeRangedS32, Offset(lifetimeMS, ExplosionData), &CommonValidators::PositiveInt,
          "@brief Lifetime, in milliseconds, of the Explosion object.\n\n"
          "@note If explosionShape is defined and contains an <i>ambient</i> animation, "
          "this field is ignored, and the playSpeed scaled duration of the animation "
          "is used instead." );
-      addField( "lifetimeVariance", TypeS32, Offset(lifetimeVariance, ExplosionData),
+      addFieldV( "lifetimeVariance", TypeRangedS32, Offset(lifetimeVariance, ExplosionData), &CommonValidators::PositiveInt,
          "Variance, in milliseconds, of the lifetimeMS of the Explosion object.\n" );
-      addField( "offset", TypeF32, Offset(offset, ExplosionData),
+      addFieldV( "offset", TypeRangedF32, Offset(offset, ExplosionData), &CommonValidators::PositiveFloat,
          "@brief Offset distance (in a random direction) of the center of the explosion "
          "from the Explosion object position.\n\n"
          "Most often used to create some variance in position for subExplosion effects." );
 
-      addField( "times", TypeF32, Offset(times, ExplosionData), EC_NUM_TIME_KEYS,
+      addFieldV( "times", TypeRangedF32, Offset(times, ExplosionData), &expTimeRange, EC_NUM_TIME_KEYS,
          "@brief Time keyframes used to scale the explosionShape model.\n\n"
          "Values should be in increasing order from 0.0 - 1.0, and correspond to "
          "the life of the Explosion where 0 is the beginning and 1 is the end of "
@@ -491,22 +495,22 @@ void ExplosionData::initPersistFields()
       addField( "camShakeAmp", TypePoint3F, Offset(camShakeAmp, ExplosionData),
          "@brief Amplitude of camera shaking, defined in the \"X Y Z\" axes.\n\n"
          "Set any value to 0 to disable shaking in that axis." );
-      addField( "camShakeDuration", TypeF32, Offset(camShakeDuration, ExplosionData),
+      addFieldV( "camShakeDuration", TypeRangedF32, Offset(camShakeDuration, ExplosionData), &CommonValidators::PositiveFloat,
          "Duration (in seconds) to shake the camera." );
-      addField( "camShakeRadius", TypeF32, Offset(camShakeRadius, ExplosionData),
+      addFieldV( "camShakeRadius", TypeRangedF32, Offset(camShakeRadius, ExplosionData), &CommonValidators::PositiveFloat,
          "Radial distance that a camera's position must be within relative to the "
          "center of the explosion to be shaken." );
-      addField( "camShakeFalloff", TypeF32, Offset(camShakeFalloff, ExplosionData),
+      addFieldV( "camShakeFalloff", TypeRangedF32, Offset(camShakeFalloff, ExplosionData), &CommonValidators::PositiveFloat,
          "Falloff value for the camera shake." );
    endGroup("Camera Shake");
 
    addGroup("Light Emitter");
-      addField( "lightStartRadius", TypeF32, Offset(lightStartRadius, ExplosionData),
+      addFieldV( "lightStartRadius", TypeRangedF32, Offset(lightStartRadius, ExplosionData), &expLightRadiusRange,
          "@brief Initial radius of the PointLight created by this explosion.\n\n"
          "Radius is linearly interpolated from lightStartRadius to lightEndRadius "
          "over the lifetime of the explosion.\n"
          "@see lifetimeMS" );
-      addField( "lightEndRadius", TypeF32, Offset(lightEndRadius, ExplosionData),
+      addFieldV( "lightEndRadius", TypeRangedF32, Offset(lightEndRadius, ExplosionData), &expLightRadiusRange,
          "@brief Final radius of the PointLight created by this explosion.\n\n"
          "@see lightStartRadius" );
       addField( "lightStartColor", TypeColorF, Offset(lightStartColor, ExplosionData),
@@ -517,15 +521,15 @@ void ExplosionData::initPersistFields()
       addField( "lightEndColor", TypeColorF, Offset(lightEndColor, ExplosionData),
          "@brief Final color of the PointLight created by this explosion.\n\n"
          "@see lightStartColor" );
-      addField( "lightStartBrightness", TypeF32, Offset(lightStartBrightness, ExplosionData),
+      addFieldV( "lightStartBrightness", TypeRangedF32, Offset(lightStartBrightness, ExplosionData), &expLightRadiusRange,
          "@brief Initial brightness of the PointLight created by this explosion.\n\n"
          "Brightness is linearly interpolated from lightStartBrightness to "
          "lightEndBrightness over the lifetime of the explosion.\n"
          "@see lifetimeMS" );
-      addField("lightEndBrightness", TypeF32, Offset(lightEndBrightness, ExplosionData),
+      addFieldV("lightEndBrightness", TypeRangedF32, Offset(lightEndBrightness, ExplosionData), &expLightRadiusRange,
          "@brief Final brightness of the PointLight created by this explosion.\n\n"
          "@see lightStartBrightness" );
-      addField( "lightNormalOffset", TypeF32, Offset(lightNormalOffset, ExplosionData),
+      addFieldV( "lightNormalOffset", TypeRangedF32, Offset(lightNormalOffset, ExplosionData), &CommonValidators::PositiveFloat,
          "Distance (in the explosion normal direction) of the PointLight position "
          "from the explosion center." );
    endGroup("Light Emitter");
@@ -754,12 +758,12 @@ void ExplosionData::packData(BitStream* stream)
    // Dynamic light info
    stream->writeFloat(lightStartRadius/MaxLightRadius, 8);
    stream->writeFloat(lightEndRadius/MaxLightRadius, 8);
-   stream->writeFloat(lightStartColor.red,7);
-   stream->writeFloat(lightStartColor.green,7);
-   stream->writeFloat(lightStartColor.blue,7);
-   stream->writeFloat(lightEndColor.red,7);
-   stream->writeFloat(lightEndColor.green,7);
-   stream->writeFloat(lightEndColor.blue,7);
+   stream->writeFloat(lightStartColor.red,8);
+   stream->writeFloat(lightStartColor.green,8);
+   stream->writeFloat(lightStartColor.blue,8);
+   stream->writeFloat(lightEndColor.red,8);
+   stream->writeFloat(lightEndColor.green,8);
+   stream->writeFloat(lightEndColor.blue,8);
    stream->writeFloat(lightStartBrightness/MaxLightRadius, 8);
    stream->writeFloat(lightEndBrightness/MaxLightRadius, 8);
    stream->write(lightNormalOffset);
@@ -858,12 +862,12 @@ void ExplosionData::unpackData(BitStream* stream)
    //
    lightStartRadius = stream->readFloat(8) * MaxLightRadius;
    lightEndRadius = stream->readFloat(8) * MaxLightRadius;
-   lightStartColor.red = stream->readFloat(7);
-   lightStartColor.green = stream->readFloat(7);
-   lightStartColor.blue = stream->readFloat(7);
-   lightEndColor.red = stream->readFloat(7);
-   lightEndColor.green = stream->readFloat(7);
-   lightEndColor.blue = stream->readFloat(7);
+   lightStartColor.red = stream->readFloat(8);
+   lightStartColor.green = stream->readFloat(8);
+   lightStartColor.blue = stream->readFloat(8);
+   lightEndColor.red = stream->readFloat(8);
+   lightEndColor.green = stream->readFloat(8);
+   lightEndColor.blue = stream->readFloat(8);
    lightStartBrightness = stream->readFloat(8) * MaxLightRadius;
    lightEndBrightness = stream->readFloat(8) * MaxLightRadius;
    stream->read( &lightNormalOffset );

+ 28 - 28
Engine/source/T3D/fx/fxFoliageReplicator.cpp

@@ -349,35 +349,35 @@ void fxFoliageReplicator::initPersistFields()
    // Add out own persistent fields.
    addGroup( "Debugging" );	// MM: Added Group Header.
       addField( "UseDebugInfo",        TypeBool,      Offset( mFieldData.mUseDebugInfo,         fxFoliageReplicator ), "Culling bins are drawn when set to true." );
-      addField( "DebugBoxHeight",      TypeF32,       Offset( mFieldData.mDebugBoxHeight,       fxFoliageReplicator ), "Height multiplier for drawn culling bins.");
+      addFieldV( "DebugBoxHeight",      TypeRangedF32,       Offset( mFieldData.mDebugBoxHeight,       fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Height multiplier for drawn culling bins.");
       addField( "HideFoliage",         TypeBool,      Offset( mFieldData.mHideFoliage,          fxFoliageReplicator ), "Foliage is hidden when set to true." );
       addField( "ShowPlacementArea",   TypeBool,      Offset( mFieldData.mShowPlacementArea,    fxFoliageReplicator ), "Draw placement rings when set to true." );
-      addField( "PlacementAreaHeight", TypeS32,       Offset( mFieldData.mPlacementBandHeight,  fxFoliageReplicator ), "Height of the placement ring in world units." );
+      addFieldV( "PlacementAreaHeight", TypeRangedS32,       Offset( mFieldData.mPlacementBandHeight,  fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Height of the placement ring in world units." );
       addField( "PlacementColour",     TypeColorF,    Offset( mFieldData.mPlaceAreaColour,      fxFoliageReplicator ), "Color of the placement ring." );
    endGroup( "Debugging" );	// MM: Added Group Footer.
 
    addGroup( "Media" );	// MM: Added Group Header.
       addField( "Seed",                TypeS32,       Offset( mFieldData.mSeed,                 fxFoliageReplicator ), "Random seed for foliage placement." );
       addField( "FoliageFile",         TypeFilename,  Offset( mFieldData.mFoliageFile,          fxFoliageReplicator ), "Image file for the foliage texture." );
-      addField( "FoliageCount",        TypeS32,       Offset( mFieldData.mFoliageCount,         fxFoliageReplicator ), "Maximum foliage instance count." );
-      addField( "FoliageRetries",      TypeS32,       Offset( mFieldData.mFoliageRetries,       fxFoliageReplicator ), "Number of times to try placing a foliage instance before giving up." );
+      addFieldV( "FoliageCount", TypeRangedS32,       Offset( mFieldData.mFoliageCount,         fxFoliageReplicator ), &CommonValidators::NaturalNumber, "Maximum foliage instance count." );
+      addFieldV( "FoliageRetries", TypeRangedS32,       Offset( mFieldData.mFoliageRetries,       fxFoliageReplicator ), &CommonValidators::PositiveInt, "Number of times to try placing a foliage instance before giving up." );
    endGroup( "Media" );	// MM: Added Group Footer.
 
    addGroup( "Area" );	// MM: Added Group Header.
-      addField( "InnerRadiusX",        TypeS32,       Offset( mFieldData.mInnerRadiusX,         fxFoliageReplicator ), "Placement area inner radius on the X axis" );
-      addField( "InnerRadiusY",        TypeS32,       Offset( mFieldData.mInnerRadiusY,         fxFoliageReplicator ), "Placement area inner radius on the Y axis" );
-      addField( "OuterRadiusX",        TypeS32,       Offset( mFieldData.mOuterRadiusX,         fxFoliageReplicator ), "Placement area outer radius on the X axis" );
-      addField( "OuterRadiusY",        TypeS32,       Offset( mFieldData.mOuterRadiusY,         fxFoliageReplicator ), "Placement area outer radius on the Y axis" );
+      addFieldV( "InnerRadiusX",        TypeRangedS32,       Offset( mFieldData.mInnerRadiusX,         fxFoliageReplicator ), &CommonValidators::PositiveInt, "Placement area inner radius on the X axis" );
+      addFieldV( "InnerRadiusY", TypeRangedS32,       Offset( mFieldData.mInnerRadiusY,         fxFoliageReplicator ), &CommonValidators::PositiveInt, "Placement area inner radius on the Y axis" );
+      addFieldV( "OuterRadiusX", TypeRangedS32,       Offset( mFieldData.mOuterRadiusX,         fxFoliageReplicator ), &CommonValidators::PositiveInt, "Placement area outer radius on the X axis" );
+      addFieldV( "OuterRadiusY", TypeRangedS32,       Offset( mFieldData.mOuterRadiusY,         fxFoliageReplicator ), &CommonValidators::PositiveInt, "Placement area outer radius on the Y axis" );
    endGroup( "Area" );	// MM: Added Group Footer.
 
    addGroup( "Dimensions" );	// MM: Added Group Header.
-      addField( "MinWidth",            TypeF32,       Offset( mFieldData.mMinWidth,             fxFoliageReplicator ), "Minimum width of foliage billboards" );
-      addField( "MaxWidth",            TypeF32,       Offset( mFieldData.mMaxWidth,             fxFoliageReplicator ), "Maximum width of foliage billboards" );
-      addField( "MinHeight",           TypeF32,       Offset( mFieldData.mMinHeight,            fxFoliageReplicator ), "Minimum height of foliage billboards" );
-      addField( "MaxHeight",           TypeF32,       Offset( mFieldData.mMaxHeight,            fxFoliageReplicator ), "Maximum height of foliage billboards" );
+      addFieldV( "MinWidth", TypeRangedF32,       Offset( mFieldData.mMinWidth,             fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Minimum width of foliage billboards" );
+      addFieldV( "MaxWidth", TypeRangedF32,       Offset( mFieldData.mMaxWidth,             fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Maximum width of foliage billboards" );
+      addFieldV( "MinHeight", TypeRangedF32,       Offset( mFieldData.mMinHeight,            fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Minimum height of foliage billboards" );
+      addFieldV( "MaxHeight", TypeRangedF32,       Offset( mFieldData.mMaxHeight,            fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Maximum height of foliage billboards" );
       addField( "FixAspectRatio",      TypeBool,      Offset( mFieldData.mFixAspectRatio,       fxFoliageReplicator ), "Maintain aspect ratio of image if true. This option ignores MaxWidth." );
       addField( "FixSizeToMax",        TypeBool,      Offset( mFieldData.mFixSizeToMax,         fxFoliageReplicator ), "Use only MaxWidth and MaxHeight for billboard size. Ignores MinWidth and MinHeight." );
-      addField( "OffsetZ",             TypeF32,       Offset( mFieldData.mOffsetZ,              fxFoliageReplicator ), "Offset billboards by this amount vertically." );
+      addFieldV( "OffsetZ", TypeRangedF32,       Offset( mFieldData.mOffsetZ,              fxFoliageReplicator ), &CommonValidators::F32Range, "Offset billboards by this amount vertically." );
       addField( "RandomFlip",          TypeBool,      Offset( mFieldData.mRandomFlip,           fxFoliageReplicator ), "Randomly flip billboards left-to-right." );
       addField( "UseTrueBillboards",   TypeBool,      Offset( mFieldData.mUseTrueBillboards,    fxFoliageReplicator ), "Use camera facing billboards ( including the z axis )." );
    endGroup( "Dimensions" );	// MM: Added Group Footer.
@@ -385,29 +385,29 @@ void fxFoliageReplicator::initPersistFields()
    addGroup( "Culling" );	// MM: Added Group Header.
       addField( "UseCulling",          TypeBool,      Offset( mFieldData.mUseCulling,           fxFoliageReplicator ), "Use culling bins when enabled." );
       addField( "CullResolution",      TypeS32,       Offset( mFieldData.mCullResolution,       fxFoliageReplicator ), "Minimum size of culling bins.  Must be >= 8 and <= OuterRadius." );
-      addField( "ViewDistance",        TypeF32,       Offset( mFieldData.mViewDistance,         fxFoliageReplicator ), "Maximum distance from camera where foliage appears." );
-      addField( "ViewClosest",         TypeF32,       Offset( mFieldData.mViewClosest,          fxFoliageReplicator ), "Minimum distance from camera where foliage appears." );
-      addField( "FadeInRegion",        TypeF32,       Offset( mFieldData.mFadeInRegion,         fxFoliageReplicator ), "Region beyond ViewDistance where foliage fades in/out." );
-      addField( "FadeOutRegion",       TypeF32,       Offset( mFieldData.mFadeOutRegion,        fxFoliageReplicator ), "Region before ViewClosest where foliage fades in/out." );
-      addField( "AlphaCutoff",         TypeF32,       Offset( mFieldData.mAlphaCutoff,          fxFoliageReplicator ), "Minimum alpha value allowed on foliage instances." );
-      addField( "GroundAlpha",         TypeF32,       Offset( mFieldData.mGroundAlpha,          fxFoliageReplicator ), "Alpha of the foliage at ground level. 0 = transparent, 1 = opaque." );
+      addFieldV( "ViewDistance", TypeRangedF32,       Offset( mFieldData.mViewDistance,         fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Maximum distance from camera where foliage appears." );
+      addFieldV( "ViewClosest", TypeRangedF32,       Offset( mFieldData.mViewClosest,          fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Minimum distance from camera where foliage appears." );
+      addFieldV( "FadeInRegion", TypeRangedF32,       Offset( mFieldData.mFadeInRegion,         fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Region beyond ViewDistance where foliage fades in/out." );
+      addFieldV( "FadeOutRegion", TypeRangedF32,       Offset( mFieldData.mFadeOutRegion,        fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Region before ViewClosest where foliage fades in/out." );
+      addFieldV( "AlphaCutoff", TypeRangedF32,       Offset( mFieldData.mAlphaCutoff,          fxFoliageReplicator ),&CommonValidators::NormalizedFloat, "Minimum alpha value allowed on foliage instances.");
+      addFieldV( "GroundAlpha", TypeRangedF32,       Offset( mFieldData.mGroundAlpha,          fxFoliageReplicator ), &CommonValidators::NormalizedFloat, "Alpha of the foliage at ground level. 0 = transparent, 1 = opaque." );
    endGroup( "Culling" );	// MM: Added Group Footer.
 
    addGroup( "Animation" );	// MM: Added Group Header.
       addField( "SwayOn",              TypeBool,      Offset( mFieldData.mSwayOn,               fxFoliageReplicator ), "Foliage should sway randomly when true." );
       addField( "SwaySync",            TypeBool,      Offset( mFieldData.mSwaySync,             fxFoliageReplicator ), "Foliage instances should sway together when true and SwayOn is enabled." );
-      addField( "SwayMagSide",         TypeF32,       Offset( mFieldData.mSwayMagnitudeSide,    fxFoliageReplicator ), "Left-to-right sway magnitude." );
-      addField( "SwayMagFront",        TypeF32,       Offset( mFieldData.mSwayMagnitudeFront,   fxFoliageReplicator ), "Front-to-back sway magnitude." );
-      addField( "MinSwayTime",         TypeF32,       Offset( mFieldData.mMinSwayTime,          fxFoliageReplicator ), "Minumum sway cycle time in seconds." );
-      addField( "MaxSwayTime",         TypeF32,       Offset( mFieldData.mMaxSwayTime,          fxFoliageReplicator ), "Maximum sway cycle time in seconds." );
+      addFieldV( "SwayMagSide", TypeRangedF32,       Offset( mFieldData.mSwayMagnitudeSide,    fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Left-to-right sway magnitude." );
+      addFieldV( "SwayMagFront", TypeRangedF32,       Offset( mFieldData.mSwayMagnitudeFront,   fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Front-to-back sway magnitude." );
+      addFieldV( "MinSwayTime", TypeRangedF32,       Offset( mFieldData.mMinSwayTime,          fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Minumum sway cycle time in seconds." );
+      addFieldV( "MaxSwayTime", TypeRangedF32,       Offset( mFieldData.mMaxSwayTime,          fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Maximum sway cycle time in seconds." );
    endGroup( "Animation" );	// MM: Added Group Footer.
 
    addGroup( "Lighting" );	// MM: Added Group Header.
       addField( "LightOn",             TypeBool,      Offset( mFieldData.mLightOn,              fxFoliageReplicator ), "Foliage should be illuminated with changing lights when true." );
       addField( "LightSync",           TypeBool,      Offset( mFieldData.mLightSync,            fxFoliageReplicator ), "Foliage instances have the same lighting when set and LightOn is set." );
-      addField( "MinLuminance",        TypeF32,       Offset( mFieldData.mMinLuminance,         fxFoliageReplicator ), "Minimum luminance for foliage instances." );
-      addField( "MaxLuminance",        TypeF32,       Offset( mFieldData.mMaxLuminance,         fxFoliageReplicator ), "Maximum luminance for foliage instances." );
-      addField( "LightTime",           TypeF32,       Offset( mFieldData.mLightTime,            fxFoliageReplicator ), "Time before foliage illumination cycle repeats." );
+      addFieldV( "MinLuminance", TypeRangedF32,       Offset( mFieldData.mMinLuminance,         fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Minimum luminance for foliage instances." );
+      addFieldV( "MaxLuminance", TypeRangedF32,       Offset( mFieldData.mMaxLuminance,         fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Maximum luminance for foliage instances." );
+      addFieldV( "LightTime", TypeRangedF32,       Offset( mFieldData.mLightTime,            fxFoliageReplicator ), &CommonValidators::PositiveFloat, "Time before foliage illumination cycle repeats." );
    endGroup( "Lighting" );	// MM: Added Group Footer.
 
    addGroup( "Restrictions" );	// MM: Added Group Header.
@@ -415,11 +415,11 @@ void fxFoliageReplicator::initPersistFields()
       addField( "AllowOnStatics",      TypeBool,      Offset( mFieldData.mAllowStatics,         fxFoliageReplicator ), "Foliage will be placed on Static shapes when set." );
       addField( "AllowOnWater",        TypeBool,      Offset( mFieldData.mAllowOnWater,         fxFoliageReplicator ), "Foliage will be placed on/under water when set." );
       addField( "AllowWaterSurface",   TypeBool,      Offset( mFieldData.mAllowWaterSurface,    fxFoliageReplicator ), "Foliage will be placed on water when set. Requires AllowOnWater." );
-      addField( "AllowedTerrainSlope", TypeS32,       Offset( mFieldData.mAllowedTerrainSlope,  fxFoliageReplicator ), "Maximum surface angle allowed for foliage instances." );
+      addFieldV( "AllowedTerrainSlope", TypeRangedS32,       Offset( mFieldData.mAllowedTerrainSlope,  fxFoliageReplicator ), &CommonValidators::S32_PosDegreeRangeQuarter, "Maximum surface angle allowed for foliage instances." );
    endGroup( "Restrictions" );	// MM: Added Group Footer.
 
    addGroup( "AFX" );
-      addField( "AmbientModulationBias", TypeF32,     Offset( mFieldData.mAmbientModulationBias,fxFoliageReplicator ), "Multiplier controling amount foliage is modulated by sun's ambient." );
+      addFieldV( "AmbientModulationBias", TypeRangedF32,     Offset( mFieldData.mAmbientModulationBias,fxFoliageReplicator ), &CommonValidators::NormalizedFloat, "Multiplier controling amount foliage is modulated by sun's ambient." );
    endGroup( "AFX" );
    // Initialise parents' persistent fields.
    Parent::initPersistFields();

+ 25 - 25
Engine/source/T3D/fx/fxShapeReplicator.cpp

@@ -680,30 +680,30 @@ U32 fxShapeReplicator::packUpdate(NetConnection * con, U32 mask, BitStream * str
    {
       stream->writeAffineTransform(mObjToWorld);						// Replicator Position.
 
-      stream->writeInt(mFieldData.mSeed, 32);							// Replicator Seed.
-      stream->writeInt(mFieldData.mShapeCount, 32);					// Shapes Count.
-      stream->writeInt(mFieldData.mShapeRetries, 32);					// Shapes Retries.
+      stream->write(mFieldData.mSeed);							// Replicator Seed.
+      stream->write(mFieldData.mShapeCount);					// Shapes Count.
+      stream->write(mFieldData.mShapeRetries);					// Shapes Retries.
       stream->writeString(mFieldData.mShapeFile);
-      stream->writeInt(mFieldData.mInnerRadiusX, 32);					// Shapes Inner Radius X.
-      stream->writeInt(mFieldData.mInnerRadiusY, 32);					// Shapes Inner Radius Y.
-      stream->writeInt(mFieldData.mOuterRadiusX, 32);					// Shapes Outer Radius X.
-      stream->writeInt(mFieldData.mOuterRadiusY, 32);					// Shapes Outer Radius Y.
+      stream->write(mFieldData.mInnerRadiusX);					// Shapes Inner Radius X.
+      stream->write(mFieldData.mInnerRadiusY);					// Shapes Inner Radius Y.
+      stream->write(mFieldData.mOuterRadiusX);					// Shapes Outer Radius X.
+      stream->write(mFieldData.mOuterRadiusY);					// Shapes Outer Radius Y.
       mathWrite(*stream, mFieldData.mShapeScaleMin);					// Shapes Scale Min.
       mathWrite(*stream, mFieldData.mShapeScaleMax);					// Shapes Scale Max.
       mathWrite(*stream, mFieldData.mShapeRotateMin);					// Shapes Rotate Min.
       mathWrite(*stream, mFieldData.mShapeRotateMax);					// Shapes Rotate Max.
-      stream->writeSignedInt(mFieldData.mOffsetZ, 32);				// Shapes Offset Z.
+      stream->write(mFieldData.mOffsetZ);				// Shapes Offset Z.
       stream->writeFlag(mFieldData.mAllowOnTerrain);					// Allow on Terrain.
       stream->writeFlag(mFieldData.mAllowStatics);					// Allow on Statics.
       stream->writeFlag(mFieldData.mAllowOnWater);					// Allow on Water.
       stream->writeFlag(mFieldData.mAllowWaterSurface);				// Allow on Water Surface.
-      stream->writeSignedInt(mFieldData.mAllowedTerrainSlope, 32);	// Shapes Offset Z.
+      stream->write(mFieldData.mAllowedTerrainSlope);	// Shapes Offset Z.
       stream->writeFlag(mFieldData.mAlignToTerrain);					// Shapes AlignToTerrain.
       mathWrite(*stream, mFieldData.mTerrainAlignment);				// Write Terrain Alignment.
       stream->writeFlag(mFieldData.mHideReplications);				// Hide Replications.
       stream->writeFlag(mFieldData.mInteractions);					// Shape Interactions.
       stream->writeFlag(mFieldData.mShowPlacementArea);				// Show Placement Area Flag.
-      stream->writeInt(mFieldData.mPlacementBandHeight, 32);			// Placement Area Height.
+      stream->write(mFieldData.mPlacementBandHeight);			// Placement Area Height.
       stream->write(mFieldData.mPlaceAreaColour);
    }
 
@@ -725,30 +725,30 @@ void fxShapeReplicator::unpackUpdate(NetConnection * con, BitStream * stream)
 
       stream->readAffineTransform(&ReplicatorObjectMatrix);				// Replication Position.
 
-      mFieldData.mSeed					= stream->readInt(32);			// Replicator Seed.
-      mFieldData.mShapeCount				= stream->readInt(32);			// Shapes Count.
-      mFieldData.mShapeRetries			= stream->readInt(32);			// Shapes Retries.
+      stream->read(&mFieldData.mSeed);			               // Replicator Seed.
+      stream->read(&mFieldData.mShapeCount);			         // Shapes Count.
+      stream->read(&mFieldData.mShapeRetries);			         // Shapes Retries.
       mFieldData.mShapeFile				= stream->readSTString();		// Shape File.
-      mFieldData.mInnerRadiusX			= stream->readInt(32);			// Shapes Inner Radius X.
-      mFieldData.mInnerRadiusY			= stream->readInt(32);			// Shapes Inner Radius Y.
-      mFieldData.mOuterRadiusX			= stream->readInt(32);			// Shapes Outer Radius X.
-      mFieldData.mOuterRadiusY			= stream->readInt(32);			// Shapes Outer Radius Y.
-      mathRead(*stream, &mFieldData.mShapeScaleMin);						// Shapes Scale Min.
-      mathRead(*stream, &mFieldData.mShapeScaleMax);						// Shapes Scale Max.
-      mathRead(*stream, &mFieldData.mShapeRotateMin);						// Shapes Rotate Min.
-      mathRead(*stream, &mFieldData.mShapeRotateMax);						// Shapes Rotate Max.
-      mFieldData.mOffsetZ					= stream->readSignedInt(32);	// Shapes Offset Z.
+      stream->read(&mFieldData.mInnerRadiusX);			         // Shapes Inner Radius X.
+      stream->read(&mFieldData.mInnerRadiusY);			         // Shapes Inner Radius Y.
+      stream->read(&mFieldData.mOuterRadiusX);			         // Shapes Outer Radius X.
+      stream->read(&mFieldData.mOuterRadiusY);			         // Shapes Outer Radius Y.
+      mathRead(*stream, &mFieldData.mShapeScaleMin);				   // Shapes Scale Min.
+      mathRead(*stream, &mFieldData.mShapeScaleMax);				   // Shapes Scale Max.
+      mathRead(*stream, &mFieldData.mShapeRotateMin);					// Shapes Rotate Min.
+      mathRead(*stream, &mFieldData.mShapeRotateMax);					// Shapes Rotate Max.
+      stream->read(&mFieldData.mOffsetZ);	// Shapes Offset Z.
       mFieldData.mAllowOnTerrain			= stream->readFlag();			// Allow on Terrain.
       mFieldData.mAllowStatics			= stream->readFlag();			// Allow on Statics.
       mFieldData.mAllowOnWater			= stream->readFlag();			// Allow on Water.
       mFieldData.mAllowWaterSurface		= stream->readFlag();			// Allow on Water Surface.
-      mFieldData.mAllowedTerrainSlope		= stream->readSignedInt(32);	// Allowed Terrain Slope.
+      stream->read(&mFieldData.mAllowedTerrainSlope);	      // Allowed Terrain Slope.
       mFieldData.mAlignToTerrain			= stream->readFlag();			// Read AlignToTerrain.
-      mathRead(*stream, &mFieldData.mTerrainAlignment);					// Read Terrain Alignment.
+      mathRead(*stream, &mFieldData.mTerrainAlignment);			// Read Terrain Alignment.
       mFieldData.mHideReplications		= stream->readFlag();			// Hide Replications.
       mFieldData.mInteractions			= stream->readFlag();			// Read Interactions.
       mFieldData.mShowPlacementArea	= stream->readFlag();				// Show Placement Area Flag.
-      mFieldData.mPlacementBandHeight	= stream->readInt(32);				// Placement Area Height.
+      stream->read(&mFieldData.mPlacementBandHeight);	// Placement Area Height.
       stream->read(&mFieldData.mPlaceAreaColour);
 
       // Set Transform.

+ 30 - 30
Engine/source/T3D/fx/groundCover.cpp

@@ -545,18 +545,18 @@ void GroundCover::initPersistFields()
 
       INITPERSISTFIELD_MATERIALASSET(Material, GroundCover, "Material used by all GroundCover segments.");
 
-      addField( "radius",        TypeF32,          Offset( mRadius, GroundCover ),              "Outer generation radius from the current camera position." );
-      addField( "dissolveRadius",TypeF32,          Offset( mFadeRadius, GroundCover ),          "This is less than or equal to radius and defines when fading of cover elements begins." );
-      addField( "reflectScale",  TypeF32,          Offset( mReflectRadiusScale, GroundCover ),  "Scales the various culling radii when rendering a reflection. Typically for water." );
+      addFieldV( "radius", TypeRangedF32,          Offset( mRadius, GroundCover ), &CommonValidators::PositiveFloat,              "Outer generation radius from the current camera position." );
+      addFieldV( "dissolveRadius", TypeRangedF32,          Offset( mFadeRadius, GroundCover ), &CommonValidators::PositiveFloat,          "This is less than or equal to radius and defines when fading of cover elements begins." );
+      addFieldV( "reflectScale", TypeRangedF32,          Offset( mReflectRadiusScale, GroundCover ), &CommonValidators::PositiveFloat,  "Scales the various culling radii when rendering a reflection. Typically for water." );
 
-      addField( "gridSize",      TypeS32,          Offset( mGridSize, GroundCover ),            "The number of cells per axis in the grid." );
-      addField( "zOffset",       TypeF32,          Offset( mZOffset, GroundCover ),             "Offset along the Z axis to render the ground cover." );
+      addFieldV( "gridSize",      TypeRangedS32,          Offset( mGridSize, GroundCover ), &CommonValidators::PositiveInt,            "The number of cells per axis in the grid." );
+      addFieldV( "zOffset", TypeRangedF32,          Offset( mZOffset, GroundCover ), &CommonValidators::F32Range,             "Offset along the Z axis to render the ground cover." );
 
       addField( "seed",          TypeS32,          Offset( mRandomSeed, GroundCover ),          "This RNG seed is saved and sent to clients for generating the same cover." );
-      addField( "maxElements",   TypeS32,          Offset( mMaxPlacement, GroundCover ),        "The maximum amount of cover elements to include in the grid at any one time." );
+      addFieldV( "maxElements",   TypeRangedS32,          Offset( mMaxPlacement, GroundCover ), &CommonValidators::PositiveInt,        "The maximum amount of cover elements to include in the grid at any one time." );
 
-      addField( "maxBillboardTiltAngle", TypeF32,  Offset( mMaxBillboardTiltAngle, GroundCover ),"The maximum amout of degrees the billboard will tilt down to match the camera." );
-      addField( "shapeCullRadius", TypeF32,        Offset( mShapeCullRadius, GroundCover ),     "This is the distance at which DTS elements are  completely culled out." );      
+      addFieldV( "maxBillboardTiltAngle", TypeRangedF32,  Offset( mMaxBillboardTiltAngle, GroundCover ), &CommonValidators::PosDegreeRangeHalf,"The maximum amout of degrees the billboard will tilt down to match the camera." );
+      addFieldV( "shapeCullRadius", TypeRangedF32,        Offset( mShapeCullRadius, GroundCover ), &CommonValidators::PositiveFloat,     "This is the distance at which DTS elements are  completely culled out." );
       addField( "shapesCastShadows", TypeBool,     Offset( mShapesCastShadows, GroundCover ),   "Whether DTS elements should cast shadows or not." );
 
       addArray( "Types", MAX_COVERTYPES );
@@ -570,37 +570,37 @@ void GroundCover::initPersistFields()
 
          addField( "invertLayer",   TypeBool,      Offset( mInvertLayer, GroundCover ), MAX_COVERTYPES,     "Indicates that the terrain material index given in 'layer' is an exclusion mask." );
 
-         addField( "probability",   TypeF32,       Offset( mProbability, GroundCover ), MAX_COVERTYPES,     "The probability of one cover type verses another (relative to all cover types)." );
+         addFieldV( "probability",   TypeRangedF32,       Offset( mProbability, GroundCover ), &CommonValidators::PositiveFloat, MAX_COVERTYPES,     "The probability of one cover type verses another (relative to all cover types)." );
 
-         addField( "sizeMin",       TypeF32,       Offset( mSizeMin, GroundCover ), MAX_COVERTYPES,         "The minimum random size for each cover type." );
+         addFieldV( "sizeMin", TypeRangedF32,       Offset( mSizeMin, GroundCover ), &CommonValidators::PositiveFloat, MAX_COVERTYPES,         "The minimum random size for each cover type." );
 
-         addField( "sizeMax",       TypeF32,       Offset( mSizeMax, GroundCover ), MAX_COVERTYPES,         "The maximum random size of this cover type." );
+         addFieldV( "sizeMax", TypeRangedF32,       Offset( mSizeMax, GroundCover ), &CommonValidators::PositiveFloat, MAX_COVERTYPES,         "The maximum random size of this cover type." );
 
-         addField( "sizeExponent",  TypeF32,       Offset( mSizeExponent, GroundCover ), MAX_COVERTYPES,    "An exponent used to bias between the minimum and maximum random sizes." );
+         addFieldV( "sizeExponent", TypeRangedF32,       Offset( mSizeExponent, GroundCover ), &CommonValidators::PositiveFloat, MAX_COVERTYPES,    "An exponent used to bias between the minimum and maximum random sizes." );
 
-         addField( "windScale",     TypeF32,       Offset( mWindScale, GroundCover ), MAX_COVERTYPES,       "The wind effect scale." );
+         addFieldV( "windScale", TypeRangedF32,       Offset( mWindScale, GroundCover ), &CommonValidators::PositiveFloat, MAX_COVERTYPES,       "The wind effect scale." );
 
-		 addField( "minSlope",      TypeF32,       Offset(mMinSlope, GroundCover), MAX_COVERTYPES,          "The minimum slope angle in degrees for placement.");
+         addFieldV( "minSlope", TypeRangedF32,       Offset(mMinSlope, GroundCover), &CommonValidators::PosDegreeRangeQuarter, MAX_COVERTYPES,          "The minimum slope angle in degrees for placement.");
 
-         addField( "maxSlope",      TypeF32,       Offset( mMaxSlope, GroundCover ), MAX_COVERTYPES,        "The maximum slope angle in degrees for placement." );
+         addFieldV( "maxSlope", TypeRangedF32,       Offset( mMaxSlope, GroundCover ), &CommonValidators::PosDegreeRangeQuarter, MAX_COVERTYPES,        "The maximum slope angle in degrees for placement." );
 
 		 addField("conformToNormal",TypeBool,      Offset(mConformToNormal, GroundCover), MAX_COVERTYPES,   "Use the terrain's slope for angle");
-		 addField("minRotX",        TypeF32,       Offset(mMinRotX, GroundCover), MAX_COVERTYPES,           "minumum amount of rotation along the X axis to add");
-		 addField("maxRotX",        TypeF32,       Offset(mMaxRotX, GroundCover), MAX_COVERTYPES,           "maximum amount of rotation along the X axis to add");
-		 addField("minRotY",        TypeF32,       Offset(mMinRotY, GroundCover), MAX_COVERTYPES,           "minumum amount of rotation along the Y axis to add");
-		 addField("maxRotY",        TypeF32,       Offset(mMaxRotY, GroundCover), MAX_COVERTYPES,           "maximum amount of rotation along the Y axis to add");
+		 addFieldV("minRotX", TypeRangedF32,       Offset(mMinRotX, GroundCover), &CommonValidators::DegreeRange, MAX_COVERTYPES,           "minumum amount of rotation along the X axis to add");
+		 addFieldV("maxRotX", TypeRangedF32,       Offset(mMaxRotX, GroundCover), &CommonValidators::DegreeRange, MAX_COVERTYPES,           "maximum amount of rotation along the X axis to add");
+		 addFieldV("minRotY", TypeRangedF32,       Offset(mMinRotY, GroundCover), &CommonValidators::DegreeRange, MAX_COVERTYPES,           "minumum amount of rotation along the Y axis to add");
+		 addFieldV("maxRotY", TypeRangedF32,       Offset(mMaxRotY, GroundCover), &CommonValidators::DegreeRange, MAX_COVERTYPES,           "maximum amount of rotation along the Y axis to add");
 
-         addField( "minElevation",  TypeF32,       Offset( mMinElevation, GroundCover ), MAX_COVERTYPES,    "The minimum world space elevation for placement." );
+         addFieldV( "minElevation", TypeRangedF32,       Offset( mMinElevation, GroundCover ), &CommonValidators::F32Range, MAX_COVERTYPES,    "The minimum world space elevation for placement." );
 
-         addField( "maxElevation",  TypeF32,       Offset( mMaxElevation, GroundCover ), MAX_COVERTYPES,    "The maximum world space elevation for placement." );
+         addFieldV( "maxElevation", TypeRangedF32,       Offset( mMaxElevation, GroundCover ), &CommonValidators::F32Range, MAX_COVERTYPES,    "The maximum world space elevation for placement." );
 
-         addField( "minClumpCount", TypeS32,       Offset( mMinClumpCount, GroundCover ), MAX_COVERTYPES,   "The minimum amount of elements in a clump." );
+         addFieldV( "minClumpCount", TypeRangedS32,       Offset( mMinClumpCount, GroundCover ), &CommonValidators::PositiveInt, MAX_COVERTYPES,   "The minimum amount of elements in a clump." );
       
-         addField( "maxClumpCount", TypeS32,       Offset( mMaxClumpCount, GroundCover ), MAX_COVERTYPES,   "The maximum amount of elements in a clump." );
+         addFieldV( "maxClumpCount", TypeRangedS32,       Offset( mMaxClumpCount, GroundCover ), &CommonValidators::PositiveInt, MAX_COVERTYPES,   "The maximum amount of elements in a clump." );
 
-         addField( "clumpExponent", TypeF32,       Offset( mClumpCountExponent, GroundCover ), MAX_COVERTYPES, "An exponent used to bias between the minimum and maximum clump counts for a particular clump." );
+         addFieldV( "clumpExponent", TypeRangedF32,       Offset( mClumpCountExponent, GroundCover ), &CommonValidators::PositiveFloat, MAX_COVERTYPES, "An exponent used to bias between the minimum and maximum clump counts for a particular clump." );
 
-         addField( "clumpRadius",   TypeF32,       Offset( mClumpRadius, GroundCover ), MAX_COVERTYPES,     "The maximum clump radius." );
+         addFieldV( "clumpRadius", TypeRangedF32,       Offset( mClumpRadius, GroundCover ), &CommonValidators::PositiveFloat, MAX_COVERTYPES,     "The maximum clump radius." );
 
       endArray( "Types" );
 
@@ -610,12 +610,12 @@ void GroundCover::initPersistFields()
 
       addField( "windDirection",    TypePoint2F,   Offset( mWindDirection, GroundCover ),             "The direction of the wind." );
 
-      addField( "windGustLength",   TypeF32,       Offset( mWindGustLength, GroundCover ),            "The length in meters between peaks in the wind gust." );
-      addField( "windGustFrequency",TypeF32,       Offset( mWindGustFrequency, GroundCover ),         "Controls how often the wind gust peaks per second." );
-      addField( "windGustStrength", TypeF32,       Offset( mWindGustStrength, GroundCover ),          "The maximum distance in meters that the peak wind  gust will displace an element." );
+      addFieldV( "windGustLength", TypeRangedF32,       Offset( mWindGustLength, GroundCover ), &CommonValidators::PositiveFloat,            "The length in meters between peaks in the wind gust." );
+      addFieldV( "windGustFrequency", TypeRangedF32,       Offset( mWindGustFrequency, GroundCover ), &CommonValidators::PositiveFloat,         "Controls how often the wind gust peaks per second." );
+      addFieldV( "windGustStrength", TypeRangedF32,       Offset( mWindGustStrength, GroundCover ), &CommonValidators::PositiveFloat,          "The maximum distance in meters that the peak wind  gust will displace an element." );
 
-      addField( "windTurbulenceFrequency",   TypeF32, Offset( mWindTurbulenceFrequency, GroundCover ),"Controls the overall rapidity of the wind turbulence." );
-      addField( "windTurbulenceStrength",    TypeF32, Offset( mWindTurbulenceStrength, GroundCover ), "The maximum distance in meters that the turbulence can displace a ground cover element." );
+      addFieldV( "windTurbulenceFrequency", TypeRangedF32, Offset( mWindTurbulenceFrequency, GroundCover ), &CommonValidators::PositiveFloat,"Controls the overall rapidity of the wind turbulence." );
+      addFieldV( "windTurbulenceStrength", TypeRangedF32, Offset( mWindTurbulenceStrength, GroundCover ), &CommonValidators::PositiveFloat, "The maximum distance in meters that the turbulence can displace a ground cover element." );
 
    endGroup( "GroundCover Wind" );
 

+ 5 - 5
Engine/source/T3D/fx/lightning.cpp

@@ -410,12 +410,12 @@ void Lightning::initPersistFields()
 {
    docsURL;
    addGroup( "Strikes" );
-   addField( "strikesPerMinute", TypeS32, Offset(strikesPerMinute, Lightning),
+   addFieldV( "strikesPerMinute", TypeRangedS32, Offset(strikesPerMinute, Lightning), &CommonValidators::PositiveInt,
       "@brief Number of lightning strikes to perform per minute.\n\n"
       "Automatically invokes strikeRandomPoint() at regular intervals." );
-   addField( "strikeWidth", TypeF32, Offset(strikeWidth, Lightning),
+   addFieldV( "strikeWidth", TypeRangedF32, Offset(strikeWidth, Lightning), &CommonValidators::PositiveFloat,
       "Width of a lightning bolt." );
-   addField( "strikeRadius", TypeF32, Offset(strikeRadius, Lightning),
+   addFieldV( "strikeRadius", TypeRangedF32, Offset(strikeRadius, Lightning), &CommonValidators::PositiveFloat,
       "@brief Horizontal size (XY plane) of the search box used to find and "
       "damage Player or Vehicle objects within range of the strike.\n\n"
       "Only the object at highest altitude with a clear line of sight to the "
@@ -431,9 +431,9 @@ void Lightning::initPersistFields()
    endGroup( "Colors" );
 
    addGroup( "Bolts" );
-   addField( "chanceToHitTarget", TypeF32, Offset(chanceToHitTarget, Lightning),
+   addFieldV( "chanceToHitTarget", TypeRangedF32, Offset(chanceToHitTarget, Lightning), &CommonValidators::NormalizedFloat,
       "Percentage chance (0-1) that a given lightning bolt will hit something." );
-   addField( "boltStartRadius", TypeF32, Offset(boltStartRadius, Lightning),
+   addFieldV( "boltStartRadius", TypeRangedF32, Offset(boltStartRadius, Lightning), &CommonValidators::PositiveFloat,
       "@brief Radial distance from the center of the Lightning object for the "
       "start point of the bolt.\n\n"
       "The actual start point will be a random point within this radius." );

+ 39 - 26
Engine/source/T3D/fx/particle.cpp

@@ -141,6 +141,8 @@ ParticleData::ParticleData()
 FRangeValidator dragCoefFValidator(0.f, 5.f);
 FRangeValidator gravCoefFValidator(-10.f, 10.f);
 FRangeValidator spinRandFValidator(-1000.f, 1000.f);
+FRangeValidator particleTimeFValidator(0.0f, 1.0f, 1<<8);
+FRangeValidator particleSizeFValidator(0.0f, MaxParticleSize, 1<<16);
 
 //-----------------------------------------------------------------------------
 // initPersistFields
@@ -160,31 +162,31 @@ void ParticleData::initPersistFields()
          "If true, particles blend like ParticleBlendStyle NORMAL, if false, "
          "blend like ParticleBlendStyle ADDITIVE.\n"
          "@note If ParticleEmitterData::blendStyle is set, it will override this value.");
-      addField("lifetimeMS", TYPEID< S32 >(), Offset(lifetimeMS, ParticleData),
+      addFieldV("lifetimeMS", TypeRangedS32, Offset(lifetimeMS, ParticleData), &CommonValidators::PositiveInt,
          "Time in milliseconds before this particle is destroyed.");
-      addField("lifetimeVarianceMS", TYPEID< S32 >(), Offset(lifetimeVarianceMS, ParticleData),
+      addFieldV("lifetimeVarianceMS", TypeRangedS32, Offset(lifetimeVarianceMS, ParticleData), &CommonValidators::PositiveInt,
          "Variance in lifetime of particle, from 0 - lifetimeMS.");
    endGroup("Basic");
 
    addGroup("Motion");
-      addFieldV("dragCoefficient", TYPEID< F32 >(), Offset(dragCoefficient, ParticleData), &dragCoefFValidator,
+      addFieldV("dragCoefficient", TypeRangedF32, Offset(dragCoefficient, ParticleData), &dragCoefFValidator,
          "Particle physics drag amount.");
-      addField("windCoefficient", TYPEID< F32 >(), Offset(windCoefficient, ParticleData),
+      addFieldV("windCoefficient", TypeRangedF32, Offset(windCoefficient, ParticleData),&CommonValidators::F32Range,
          "Strength of wind on the particles.");
-      addFieldV("gravityCoefficient", TYPEID< F32 >(), Offset(gravityCoefficient, ParticleData), &gravCoefFValidator,
+      addFieldV("gravityCoefficient", TypeRangedF32, Offset(gravityCoefficient, ParticleData), &gravCoefFValidator,
          "Strength of gravity on the particles.");
-      addFieldV("inheritedVelFactor", TYPEID< F32 >(), Offset(inheritedVelFactor, ParticleData), &CommonValidators::NormalizedFloat,
+      addFieldV("inheritedVelFactor", TypeRangedF32, Offset(inheritedVelFactor, ParticleData), &CommonValidators::NormalizedFloat,
          "Amount of emitter velocity to add to particle initial velocity.");
-      addField("constantAcceleration", TYPEID< F32 >(), Offset(constantAcceleration, ParticleData),
+      addFieldV("constantAcceleration", TypeRangedF32, Offset(constantAcceleration, ParticleData), &CommonValidators::F32Range,
          "Constant acceleration to apply to this particle.");
    endGroup("Motion");
    
    addGroup("Spin");
-      addField("spinSpeed", TYPEID< F32 >(), Offset(spinSpeed, ParticleData),
+      addFieldV("spinSpeed", TypeRangedF32, Offset(spinSpeed, ParticleData), &spinRandFValidator,
          "Speed at which to spin the particle.");
-      addFieldV("spinRandomMin", TYPEID< F32 >(), Offset(spinRandomMin, ParticleData), &spinRandFValidator,
+      addFieldV("spinRandomMin", TypeRangedF32, Offset(spinRandomMin, ParticleData), &spinRandFValidator,
          "Minimum allowed spin speed of this particle, between -1000 and spinRandomMax.");
-      addFieldV("spinRandomMax", TYPEID< F32 >(), Offset(spinRandomMax, ParticleData), &spinRandFValidator,
+      addFieldV("spinRandomMax", TypeRangedF32, Offset(spinRandomMax, ParticleData), &spinRandFValidator,
          "Maximum allowed spin speed of this particle, between spinRandomMin and 1000.");
    endGroup("Spin");
   
@@ -223,16 +225,16 @@ void ParticleData::initPersistFields()
 
    // Interpolation variables
    addGroup("Over Time");
-      addProtectedField("times", TYPEID< F32 >(), Offset(times, ParticleData), &protectedSetTimes,
-         &defaultProtectedGetFn, PDC_NUM_KEYS,
+      addProtectedFieldV("times", TypeRangedF32, Offset(times, ParticleData), &protectedSetTimes,
+         &defaultProtectedGetFn, &particleTimeFValidator, PDC_NUM_KEYS,
          "@brief Time keys used with the colors and sizes keyframes.\n\n"
          "Values are from 0.0 (particle creation) to 1.0 (end of lifespace).");
       addField( "colors", TYPEID< LinearColorF >(), Offset(colors, ParticleData), PDC_NUM_KEYS,
          "@brief Particle RGBA color keyframe values.\n\n"
          "The particle color will linearly interpolate between the color/time keys "
          "over the lifetime of the particle." );
-      addProtectedField( "sizes", TYPEID< F32 >(), Offset(sizes, ParticleData), &protectedSetSizes, 
-         &defaultProtectedGetFn, PDC_NUM_KEYS,
+      addProtectedFieldV( "sizes", TypeRangedF32, Offset(sizes, ParticleData), &protectedSetSizes,
+         &defaultProtectedGetFn, &particleSizeFValidator, PDC_NUM_KEYS,
          "@brief Particle size keyframe values.\n\n"
          "The particle size will linearly interpolate between the size/time keys "
          "over the lifetime of the particle." );
@@ -242,10 +244,10 @@ void ParticleData::initPersistFields()
       addProtectedField("textureExtName", TypeFilename, Offset(mTextureExtName,     ParticleData), _setTextureExtData, &defaultProtectedGetFn, "", AbstractClassRep::FIELD_HideInInspectors);
       INITPERSISTFIELD_IMAGEASSET(TextureExt, ParticleData, "");
       addField("constrainPos",         TypeBool,     Offset(constrain_pos,      ParticleData));
-      addField("angle",                TypeF32,      Offset(start_angle,        ParticleData));
-      addField("angleVariance",        TypeF32,      Offset(angle_variance,     ParticleData));
-      addField("sizeBias",             TypeF32,      Offset(sizeBias,           ParticleData));
-      addField("spinBias",             TypeF32,      Offset(spinBias,           ParticleData));
+      addFieldV("angle", TypeRangedF32,      Offset(start_angle,        ParticleData), &CommonValidators::DegreeRange);
+      addFieldV("angleVariance", TypeRangedF32,      Offset(angle_variance,     ParticleData), &CommonValidators::DegreeRange);
+      addFieldV("sizeBias", TypeRangedF32,      Offset(sizeBias,           ParticleData), &CommonValidators::F32Range);
+      addFieldV("spinBias", TypeRangedF32,      Offset(spinBias,           ParticleData), &CommonValidators::F32Range);
       addField("randomizeSpinDir",     TypeBool,     Offset(randomizeSpinDir,   ParticleData));
    endGroup("AFX"); 
    Parent::initPersistFields();
@@ -296,10 +298,10 @@ void ParticleData::packData(BitStream* stream)
 
    for( i=0; i<count; i++ )
    {
-      stream->writeFloat( colors[i].red, 7);
-      stream->writeFloat( colors[i].green, 7);
-      stream->writeFloat( colors[i].blue, 7);
-      stream->writeFloat( colors[i].alpha, 7);
+      stream->writeFloat( colors[i].red, 8);
+      stream->writeFloat( colors[i].green, 8);
+      stream->writeFloat( colors[i].blue, 8);
+      stream->writeFloat( colors[i].alpha, 8);
       // AFX bits raised from 14 to 16 to allow larger sizes
       stream->writeFloat( sizes[i]/MaxParticleSize, 16);
       stream->writeFloat( times[i], 8);
@@ -381,10 +383,10 @@ void ParticleData::unpackData(BitStream* stream)
    S32 count = stream->readInt(3) + 1;
    for(i = 0;i < count; i++)
    {
-      colors[i].red = stream->readFloat(7);
-      colors[i].green = stream->readFloat(7);
-      colors[i].blue = stream->readFloat(7);
-      colors[i].alpha = stream->readFloat(7);
+      colors[i].red = stream->readFloat(8);
+      colors[i].green = stream->readFloat(8);
+      colors[i].blue = stream->readFloat(8);
+      colors[i].alpha = stream->readFloat(8);
       // AFX bits raised from 14 to 16 to allow larger sizes
       sizes[i] = stream->readFloat(16) * MaxParticleSize;
       times[i] = stream->readFloat(8);
@@ -443,6 +445,17 @@ bool ParticleData::protectedSetTimes( void *object, const char *index, const cha
 
    pData->times[i] = mClampF( val, 0.f, 1.f );
 
+   pData->times[0] = 0.0f;
+
+   S32 last = i - 1;
+   S32 next = i + 1;
+   if (last >= 0 && next < PDC_NUM_KEYS-1)
+   {
+      if ((pData->times[last] != -1.0f) && (pData->times[i] < pData->times[last]))
+         pData->times[i] = pData->times[last];
+      else if ((pData->times[next] != -1.0f) && (pData->times[i] > pData->times[next]))
+         pData->times[i] = pData->times[next];
+   }
    return false;
 }
 

+ 16 - 18
Engine/source/T3D/fx/particleEmitter.cpp

@@ -199,8 +199,6 @@ IRangeValidator ejectPeriodIValidator(1, 2047);
 IRangeValidator periodVarianceIValidator(0, 2047);
 FRangeValidator ejectionFValidator(0.f, 655.35f);
 FRangeValidator velVarianceFValidator(0.f, 163.83f);
-FRangeValidator thetaFValidator(0.f, 180.f);
-FRangeValidator phiFValidator(0.f, 360.f);
 
 //-----------------------------------------------------------------------------
 // initPersistFields
@@ -210,45 +208,45 @@ void ParticleEmitterData::initPersistFields()
    docsURL;
    addGroup( "ParticleEmitterData" );
 
-      addFieldV("ejectionPeriodMS", TYPEID< S32 >(), Offset(ejectionPeriodMS,   ParticleEmitterData), &ejectPeriodIValidator,
+      addFieldV("ejectionPeriodMS", TypeRangedS32, Offset(ejectionPeriodMS,   ParticleEmitterData), &ejectPeriodIValidator,
          "Time (in milliseconds) between each particle ejection." );
 
-      addFieldV("periodVarianceMS", TYPEID< S32 >(), Offset(periodVarianceMS,   ParticleEmitterData), &periodVarianceIValidator,
+      addFieldV("periodVarianceMS", TypeRangedS32, Offset(periodVarianceMS,   ParticleEmitterData), &periodVarianceIValidator,
          "Variance in ejection period, from 1 - ejectionPeriodMS." );
 
-      addFieldV( "ejectionVelocity", TYPEID< F32 >(), Offset(ejectionVelocity, ParticleEmitterData), &ejectionFValidator,
+      addFieldV( "ejectionVelocity", TypeRangedF32, Offset(ejectionVelocity, ParticleEmitterData), &ejectionFValidator,
          "Particle ejection velocity." );
 
-      addFieldV( "velocityVariance", TYPEID< F32 >(), Offset(velocityVariance, ParticleEmitterData), &velVarianceFValidator,
+      addFieldV( "velocityVariance", TypeRangedF32, Offset(velocityVariance, ParticleEmitterData), &velVarianceFValidator,
          "Variance for ejection velocity, from 0 - ejectionVelocity." );
 
-      addFieldV( "ejectionOffset", TYPEID< F32 >(), Offset(ejectionOffset, ParticleEmitterData), &ejectionFValidator,
+      addFieldV( "ejectionOffset", TypeRangedF32, Offset(ejectionOffset, ParticleEmitterData), &ejectionFValidator,
          "Distance along ejection Z axis from which to eject particles." );
 		 
-      addFieldV( "ejectionOffsetVariance", TYPEID< F32 >(), Offset(ejectionOffsetVariance, ParticleEmitterData), &ejectionFValidator,
+      addFieldV( "ejectionOffsetVariance", TypeRangedF32, Offset(ejectionOffsetVariance, ParticleEmitterData), &ejectionFValidator,
          "Distance Padding along ejection Z axis from which to eject particles." );
 
-      addFieldV( "thetaMin", TYPEID< F32 >(), Offset(thetaMin, ParticleEmitterData), &thetaFValidator,
+      addFieldV( "thetaMin", TypeRangedF32, Offset(thetaMin, ParticleEmitterData), &CommonValidators::PosDegreeRangeHalf,
          "Minimum angle, from the horizontal plane, to eject from." );
 
-      addFieldV( "thetaMax", TYPEID< F32 >(), Offset(thetaMax, ParticleEmitterData), &thetaFValidator,
+      addFieldV( "thetaMax", TypeRangedF32, Offset(thetaMax, ParticleEmitterData), &CommonValidators::PosDegreeRangeHalf,
          "Maximum angle, from the horizontal plane, to eject particles from." );
 
-	  addFieldV( "thetaVariance", TYPEID< F32 >(), Offset(thetaVariance, ParticleEmitterData), &thetaFValidator,
+	  addFieldV( "thetaVariance", TypeRangedF32, Offset(thetaVariance, ParticleEmitterData), &CommonValidators::PosDegreeRangeHalf,
          "Angle variance from the previous particle, from 0 - 180." );
 
-      addFieldV( "phiReferenceVel", TYPEID< F32 >(), Offset(phiReferenceVel, ParticleEmitterData), &phiFValidator,
+      addFieldV( "phiReferenceVel", TypeRangedF32, Offset(phiReferenceVel, ParticleEmitterData), &CommonValidators::PosDegreeRange,
          "Reference angle, from the vertical plane, to eject particles from." );
 
-      addFieldV( "phiVariance", TYPEID< F32 >(), Offset(phiVariance, ParticleEmitterData), &phiFValidator,
+      addFieldV( "phiVariance", TypeRangedF32, Offset(phiVariance, ParticleEmitterData), &CommonValidators::PosDegreeRange,
          "Variance from the reference angle, from 0 - 360." );
 
-      addField( "softnessDistance", TYPEID< F32 >(), Offset(softnessDistance, ParticleEmitterData),
+      addFieldV( "softnessDistance", TypeRangedF32, Offset(softnessDistance, ParticleEmitterData), &CommonValidators::PositiveFloat,
          "For soft particles, the distance (in meters) where particles will be "
          "faded based on the difference in depth between the particle and the "
          "scene geometry." );
 
-      addField( "ambientFactor", TYPEID< F32 >(), Offset(ambientFactor, ParticleEmitterData),
+      addFieldV( "ambientFactor", TypeRangedF32, Offset(ambientFactor, ParticleEmitterData), &CommonValidators::NormalizedFloat,
          "Used to generate the final particle color by controlling interpolation "
          "between the particle color and the particle color multiplied by the "
          "ambient light color." );
@@ -272,10 +270,10 @@ void ParticleEmitterData::initPersistFields()
          "A random one of these datablocks is selected each time a particle is "
          "emitted." );
 
-      addField( "lifetimeMS", TYPEID< S32 >(), Offset(lifetimeMS, ParticleEmitterData),
+      addFieldV( "lifetimeMS", TypeRangedS32, Offset(lifetimeMS, ParticleEmitterData), &CommonValidators::PositiveInt,
          "Lifetime of emitted particles (in milliseconds)." );
 
-      addField("lifetimeVarianceMS", TYPEID< S32 >(), Offset(lifetimeVarianceMS, ParticleEmitterData),
+      addFieldV("lifetimeVarianceMS", TypeRangedS32, Offset(lifetimeVarianceMS, ParticleEmitterData), &CommonValidators::PositiveInt,
          "Variance in particle lifetime from 0 - lifetimeMS." );
 
       addField( "useEmitterSizes", TYPEID< bool >(), Offset(useEmitterSizes, ParticleEmitterData),
@@ -338,7 +336,7 @@ void ParticleEmitterData::initPersistFields()
 #if defined(AFX_CAP_PARTICLE_POOLS)
    addGroup("AFX Pooled Particles");
    addField("poolData", TYPEID<afxParticlePoolData>(), Offset(pool_datablock, ParticleEmitterData));
-   addField("poolIndex",            TypeS32,                      Offset(pool_index,        ParticleEmitterData));
+   addFieldV("poolIndex",            TypeRangedS32,                      Offset(pool_index,        ParticleEmitterData), &CommonValidators::PositiveInt);
    addField("poolDepthFade",        TypeBool,                     Offset(pool_depth_fade,   ParticleEmitterData));
    addField("poolRadialFade",       TypeBool,                     Offset(pool_radial_fade,  ParticleEmitterData));
    endGroup("AFX Pooled Particles");

+ 1 - 1
Engine/source/T3D/fx/particleEmitter.h

@@ -98,7 +98,7 @@ class ParticleEmitterData : public GameBaseData
    F32 ambientFactor;
 
    S32   lifetimeMS;                         ///< Lifetime of particles
-   U32   lifetimeVarianceMS;                 ///< Varience in lifetime from 0 to n
+   S32   lifetimeVarianceMS;                 ///< Varience in lifetime from 0 to n
 
    bool  overrideAdvance;                    ///<
    bool  orientParticles;                    ///< Particles always face the screen

+ 3 - 2
Engine/source/T3D/fx/particleEmitterNode.cpp

@@ -87,10 +87,11 @@ ParticleEmitterNodeData::~ParticleEmitterNodeData()
 //-----------------------------------------------------------------------------
 // initPersistFields
 //-----------------------------------------------------------------------------
+FRangeValidator emTimeMultipleRange(0.01f,100.0f);
 void ParticleEmitterNodeData::initPersistFields()
 {
    docsURL;
-   addField( "timeMultiple", TYPEID< F32 >(), Offset(timeMultiple, ParticleEmitterNodeData),
+   addFieldV( "timeMultiple", TypeRangedF32, Offset(timeMultiple, ParticleEmitterNodeData), &emTimeMultipleRange,
       "@brief Time multiplier for particle emitter nodes.\n\n"
       "Increasing timeMultiple is like running the emitter at a faster rate - single-shot "
       "emitters will complete in a shorter time, and continuous emitters will generate "
@@ -187,7 +188,7 @@ void ParticleEmitterNode::initPersistFields()
       "Controls whether particles are emitted from this node." );
    addField( "emitter",  TYPEID< ParticleEmitterData >(), Offset(mEmitterDatablock, ParticleEmitterNode),
       "Datablock to use when emitting particles." );
-   addField( "velocity", TYPEID< F32 >(), Offset(mVelocity, ParticleEmitterNode),
+   addFieldV( "velocity", TypeRangedF32, Offset(mVelocity, ParticleEmitterNode), &CommonValidators::F32Range,
       "Velocity to use when emitting particles (in the direction of the "
       "ParticleEmitterNode object's up (Z) axis)." );
 

+ 17 - 17
Engine/source/T3D/fx/precipitation.cpp

@@ -173,11 +173,11 @@ void PrecipitationData::initPersistFields()
 
    addField( "splashShader", TypeString, Offset(mSplashShaderName, PrecipitationData),
       "The name of the shader used for splashes." );
-   addField( "dropsPerSide", TypeS32, Offset(mDropsPerSide, PrecipitationData),
+   addFieldV( "dropsPerSide", TypeRangedS32, Offset(mDropsPerSide, PrecipitationData), &CommonValidators::PositiveInt,
       "@brief How many rows and columns are in the raindrop texture.\n\n"
       "For example, if the texture has 16 raindrops arranged in a grid, this "
       "field should be set to 4." );
-   addField( "splashesPerSide", TypeS32, Offset(mSplashesPerSide, PrecipitationData),
+   addFieldV( "splashesPerSide", TypeRangedS32, Offset(mSplashesPerSide, PrecipitationData), &CommonValidators::PositiveInt,
       "@brief How many rows and columns are in the splash texture.\n\n"
       "For example, if the texture has 9 splashes arranged in a grid, this "
       "field should be set to 3." );
@@ -368,45 +368,45 @@ void Precipitation::initPersistFields()
    docsURL;
    addGroup("Precipitation");
 
-      addFieldV( "numDrops", TypeS32, Offset(mNumDrops, Precipitation), &ValidNumDropsRange,
+      addFieldV( "numDrops", TypeRangedS32, Offset(mNumDrops, Precipitation), &ValidNumDropsRange,
          "@brief Maximum number of drops allowed to exist in the precipitation "
          "box at any one time.\n\n"
          "The actual number of drops in the effect depends on the current "
          "percentage, which can change over time using modifyStorm()." );
 
-      addField( "boxWidth", TypeF32, Offset(mBoxWidth, Precipitation),
+      addFieldV( "boxWidth", TypeRangedF32, Offset(mBoxWidth, Precipitation), &CommonValidators::PositiveFloat,
          "Width and depth (horizontal dimensions) of the precipitation box." );
 
-      addField( "boxHeight", TypeF32, Offset(mBoxHeight, Precipitation),
+      addFieldV( "boxHeight", TypeRangedF32, Offset(mBoxHeight, Precipitation), &CommonValidators::PositiveFloat,
          "Height (vertical dimension) of the precipitation box." );
 
    endGroup("Precipitation");
 
    addGroup("Rendering");
 
-      addField( "dropSize", TypeF32, Offset(mDropSize, Precipitation),
+      addFieldV( "dropSize", TypeRangedF32, Offset(mDropSize, Precipitation), &CommonValidators::PositiveFloat,
          "Size of each drop of precipitation. This will scale the texture." );
 
-      addField( "splashSize", TypeF32, Offset(mSplashSize, Precipitation),
+      addFieldV( "splashSize", TypeRangedF32, Offset(mSplashSize, Precipitation), &CommonValidators::PositiveFloat,
          "Size of each splash animation when a drop collides with another surface." );
 
-      addField( "splashMS", TypeS32, Offset(mSplashMS, Precipitation),
+      addFieldV( "splashMS", TypeRangedS32, Offset(mSplashMS, Precipitation), &CommonValidators::PositiveInt,
          "Lifetime of splashes in milliseconds." );
 
       addField( "animateSplashes", TypeBool, Offset(mAnimateSplashes, Precipitation),
          "Set to true to enable splash animations when drops collide with other surfaces." );
 
-      addField( "dropAnimateMS", TypeS32, Offset(mDropAnimateMS, Precipitation),
+      addFieldV( "dropAnimateMS", TypeRangedS32, Offset(mDropAnimateMS, Precipitation), &CommonValidators::PositiveInt,
          "@brief Length (in milliseconds) to display each drop frame.\n\n"
          "If #dropAnimateMS <= 0, drops select a single random frame at creation "
          "that does not change throughout the drop's lifetime. If #dropAnimateMS "
          "> 0, each drop cycles through the the available frames in the drop "
          "texture at the given rate." );
 
-      addField( "fadeDist", TypeF32, Offset(mFadeDistance, Precipitation),
+      addFieldV( "fadeDist", TypeRangedF32, Offset(mFadeDistance, Precipitation), &CommonValidators::PositiveFloat,
          "The distance at which drops begin to fade out." );
 
-      addField( "fadeDistEnd", TypeF32, Offset(mFadeDistanceEnd, Precipitation),
+      addFieldV( "fadeDistEnd", TypeRangedF32, Offset(mFadeDistanceEnd, Precipitation), &CommonValidators::PositiveFloat,
          "The distance at which drops are completely faded out." );
 
       addField( "useTrueBillboards", TypeBool, Offset(mUseTrueBillboards, Precipitation),
@@ -459,23 +459,23 @@ void Precipitation::initPersistFields()
          "Controls whether drops are affected by wind.\n"
          "@see ForestWindEmitter" );
 
-      addField( "minSpeed", TypeF32, Offset(mMinSpeed, Precipitation),
+      addFieldV( "minSpeed", TypeRangedF32, Offset(mMinSpeed, Precipitation), &CommonValidators::PositiveFloat,
          "@brief Minimum speed at which a drop will fall.\n\n"
          "On creation, the drop will be assigned a random speed between #minSpeed "
          "and #maxSpeed." );
 
-      addField( "maxSpeed", TypeF32, Offset(mMaxSpeed, Precipitation),
+      addFieldV( "maxSpeed", TypeRangedF32, Offset(mMaxSpeed, Precipitation), &CommonValidators::PositiveFloat,
          "@brief Maximum speed at which a drop will fall.\n\n"
          "On creation, the drop will be assigned a random speed between #minSpeed "
          "and #maxSpeed." );
 
-      addField( "minMass", TypeF32, Offset(mMinMass, Precipitation),
+      addFieldV( "minMass", TypeRangedF32, Offset(mMinMass, Precipitation), &CommonValidators::PositiveFloat,
          "@brief Minimum mass of a drop.\n\n"
          "Drop mass determines how strongly the drop is affected by wind and "
          "turbulence. On creation, the drop will be assigned a random speed "
          "between #minMass and #minMass." );
 
-      addField( "maxMass", TypeF32, Offset(mMaxMass, Precipitation),
+      addFieldV( "maxMass", TypeRangedF32, Offset(mMaxMass, Precipitation), &CommonValidators::PositiveFloat,
          "@brief Maximum mass of a drop.\n\n"
          "Drop mass determines how strongly the drop is affected by wind and "
          "turbulence. On creation, the drop will be assigned a random speed "
@@ -489,10 +489,10 @@ void Precipitation::initPersistFields()
          "Check to enable turbulence. This causes precipitation drops to spiral "
          "while falling." );
 
-      addField( "maxTurbulence", TypeF32, Offset(mMaxTurbulence, Precipitation),
+      addFieldV( "maxTurbulence", TypeRangedF32, Offset(mMaxTurbulence, Precipitation), &CommonValidators::PositiveFloat,
          "Radius at which precipitation drops spiral when turbulence is enabled." );
 
-      addField( "turbulenceSpeed", TypeF32, Offset(mTurbulenceSpeed, Precipitation),
+      addFieldV( "turbulenceSpeed", TypeRangedF32, Offset(mTurbulenceSpeed, Precipitation), &CommonValidators::PositiveFloat,
          "Speed at which precipitation drops spiral when turbulence is enabled." );
 
    endGroup("Turbulence");

+ 7 - 7
Engine/source/T3D/fx/ribbon.cpp

@@ -73,27 +73,27 @@ void RibbonData::initPersistFields()
 
    addGroup("Ribbon");
 
-   addField("size", TypeF32, Offset(mSizes, RibbonData), NumFields,
+   addFieldV("size", TypeRangedF32, Offset(mSizes, RibbonData), &CommonValidators::PositiveFloat, NumFields,
       "The size of the ribbon at the specified keyframe.");
    addField("color", TypeColorF, Offset(mColours, RibbonData), NumFields,
       "The colour of the ribbon at the specified keyframe.");
-   addField("position", TypeF32, Offset(mTimes, RibbonData), NumFields,
+   addFieldV("position", TypeRangedF32, Offset(mTimes, RibbonData), &CommonValidators::PositiveFloat, NumFields,
       "The position of the keyframe along the lifetime of the ribbon.");
 
-   addField("ribbonLength", TypeS32, Offset(mRibbonLength, RibbonData),
+   addFieldV("ribbonLength", TypeRangedS32, Offset(mRibbonLength, RibbonData), &CommonValidators::NaturalNumber,
       "The amount of segments the Ribbon can maximally have in length.");
-   addField("segmentsPerUpdate", TypeS32, Offset(segmentsPerUpdate, RibbonData),
+   addFieldV("segmentsPerUpdate", TypeRangedS32, Offset(segmentsPerUpdate, RibbonData), &CommonValidators::NaturalNumber,
       "How many segments to add each update.");
-   addField("skipAmount", TypeS32, Offset(mSegmentSkipAmount, RibbonData),
+   addFieldV("skipAmount", TypeRangedS32, Offset(mSegmentSkipAmount, RibbonData), &CommonValidators::PositiveInt,
       "The amount of segments to skip each update.");
 
    addField("useFadeOut", TypeBool, Offset(mUseFadeOut, RibbonData),
       "If true, the ribbon will fade away after deletion.");
-   addField("fadeAwayStep", TypeF32, Offset(mFadeAwayStep, RibbonData),
+   addFieldV("fadeAwayStep", TypeRangedF32, Offset(mFadeAwayStep, RibbonData), &CommonValidators::PositiveFloat,
       "How much to fade the ribbon with each update, after deletion.");
    addField("ribbonMaterial", TypeString, Offset(mMatName, RibbonData),
       "The material the ribbon uses for rendering.");
-   addField("tileScale", TypeF32, Offset(mTileScale, RibbonData),
+   addFieldV("tileScale", TypeRangedF32, Offset(mTileScale, RibbonData), &CommonValidators::NormalizedFloat,
       "How much to scale each 'tile' with, where 1 means the material is stretched"
       "across the whole ribbon. (If TexcoordsRelativeToDistance is true, this is in meters.)");
    addField("fixedTexcoords", TypeBool, Offset(mFixedTexcoords, RibbonData),

+ 16 - 16
Engine/source/T3D/fx/splash.cpp

@@ -121,26 +121,26 @@ void SplashData::initPersistFields()
 
    addField("scale",             TypePoint3F,                  Offset(scale,              SplashData), "The scale of this splashing effect, defined as the F32 points X, Y, Z.\n");
    addField("emitter",           TYPEID< ParticleEmitterData >(),   Offset(emitterList,        SplashData), NUM_EMITTERS, "List of particle emitters to create at the point of this Splash effect.\n");
-   addField("delayMS",           TypeS32,                      Offset(delayMS,            SplashData), "Time to delay, in milliseconds, before actually starting this effect.\n");
-   addField("delayVariance",     TypeS32,                      Offset(delayVariance,      SplashData), "Time variance for delayMS.\n");
-   addField("lifetimeMS",        TypeS32,                      Offset(lifetimeMS,         SplashData), "Lifetime for this effect, in milliseconds.\n");
-   addField("lifetimeVariance",  TypeS32,                      Offset(lifetimeVariance,   SplashData), "Time variance for lifetimeMS.\n");
-   addField("width",             TypeF32,                      Offset(width,              SplashData), "Width for the X and Y coordinates to create this effect within.");
-   addField("numSegments",       TypeS32,                      Offset(numSegments,        SplashData), "Number of ejection points in the splash ring.\n");
-   addField("velocity",          TypeF32,                      Offset(velocity,           SplashData), "Velocity for the splash effect to travel.\n");
-   addField("height",            TypeF32,                      Offset(height,             SplashData), "Height for the splash to reach.\n");
-   addField("acceleration",      TypeF32,                      Offset(acceleration,       SplashData), "Constant acceleration value to place upon the splash effect.\n");
-   addField("times",             TypeF32,                      Offset(times,              SplashData), NUM_TIME_KEYS, "Times to transition through the splash effect. Up to 4 allowed. Values are 0.0 - 1.0, and corrispond to the life of the particle where 0 is first created and 1 is end of lifespace.\n" );
+   addFieldV("delayMS", TypeRangedS32,                      Offset(delayMS,            SplashData), &CommonValidators::PositiveInt, "Time to delay, in milliseconds, before actually starting this effect.\n");
+   addFieldV("delayVariance", TypeRangedS32,                      Offset(delayVariance,      SplashData), &CommonValidators::PositiveInt, "Time variance for delayMS.\n");
+   addFieldV("lifetimeMS", TypeRangedS32,                      Offset(lifetimeMS,         SplashData), &CommonValidators::PositiveInt, "Lifetime for this effect, in milliseconds.\n");
+   addFieldV("lifetimeVariance", TypeRangedS32,                      Offset(lifetimeVariance,   SplashData), &CommonValidators::PositiveInt, "Time variance for lifetimeMS.\n");
+   addFieldV("width", TypeRangedF32,                      Offset(width,              SplashData), &CommonValidators::PositiveFloat, "Width for the X and Y coordinates to create this effect within.");
+   addFieldV("numSegments", TypeRangedS32,                      Offset(numSegments,        SplashData), &CommonValidators::NaturalNumber, "Number of ejection points in the splash ring.\n");
+   addFieldV("velocity", TypeRangedF32,                      Offset(velocity,           SplashData), &CommonValidators::PositiveFloat, "Velocity for the splash effect to travel.\n");
+   addFieldV("height", TypeRangedF32,                      Offset(height,             SplashData), &CommonValidators::PositiveFloat, "Height for the splash to reach.\n");
+   addFieldV("acceleration", TypeRangedF32,                      Offset(acceleration,       SplashData), &CommonValidators::PositiveFloat, "Constant acceleration value to place upon the splash effect.\n");
+   addFieldV("times", TypeRangedF32,                      Offset(times,              SplashData), &CommonValidators::NormalizedFloat, NUM_TIME_KEYS, "Times to transition through the splash effect. Up to 4 allowed. Values are 0.0 - 1.0, and corrispond to the life of the particle where 0 is first created and 1 is end of lifespace.\n" );
    addField("colors",            TypeColorF,                   Offset(colors,             SplashData), NUM_TIME_KEYS, "Color values to set the splash effect, rgba. Up to 4 allowed. Will transition through colors based on values set in the times value. Example: colors[0] = \"0.6 1.0 1.0 0.5\".\n" );
 
    INITPERSISTFIELD_IMAGEASSET_ARRAY(Texture, NUM_TEX, SplashData, "Image to use as the texture for the splash effect.\n");
 
-   addField("texWrap",           TypeF32,                      Offset(texWrap,            SplashData), "Amount to wrap the texture around the splash ring, 0.0f - 1.0f.\n");
-   addField("texFactor",         TypeF32,                      Offset(texFactor,          SplashData), "Factor in which to apply the texture to the splash ring, 0.0f - 1.0f.\n");
-   addField("ejectionFreq",      TypeF32,                      Offset(ejectionFreq,       SplashData), "Frequency in which to emit splash rings.\n");
-   addField("ejectionAngle",     TypeF32,                      Offset(ejectionAngle,      SplashData), "Rotational angle to create a splash ring.\n");
-   addField("ringLifetime",      TypeF32,                      Offset(ringLifetime,       SplashData), "Lifetime, in milliseconds, for a splash ring.\n");
-   addField("startRadius",       TypeF32,                      Offset(startRadius,        SplashData), "Starting radius size of a splash ring.\n");
+   addFieldV("texWrap", TypeRangedF32,                      Offset(texWrap,            SplashData), &CommonValidators::NormalizedFloat, "Amount to wrap the texture around the splash ring, 0.0f - 1.0f.\n");
+   addFieldV("texFactor", TypeRangedF32,                      Offset(texFactor,          SplashData), &CommonValidators::NormalizedFloat, "Factor in which to apply the texture to the splash ring, 0.0f - 1.0f.\n");
+   addFieldV("ejectionFreq", TypeRangedF32,                      Offset(ejectionFreq,       SplashData), &CommonValidators::PositiveFloat, "Frequency in which to emit splash rings.\n");
+   addFieldV("ejectionAngle", TypeRangedF32,                      Offset(ejectionAngle,      SplashData), &CommonValidators::DegreeRange, "Rotational angle to create a splash ring.\n");
+   addFieldV("ringLifetime",      TypeRangedF32,                      Offset(ringLifetime,       SplashData), &CommonValidators::PositiveFloat, "Lifetime, in milliseconds, for a splash ring.\n");
+   addFieldV("startRadius", TypeRangedF32,                      Offset(startRadius,        SplashData), &CommonValidators::PositiveFloat, "Starting radius size of a splash ring.\n");
    addField("explosion",         TYPEID< ExplosionData >(),    Offset(explosion,          SplashData), "ExplosionData object to create at the creation position of this splash effect.\n");
 
    Parent::initPersistFields();

+ 1 - 1
Engine/source/T3D/gameBase/gameBase.cpp

@@ -127,7 +127,7 @@ IMPLEMENT_CALLBACK( GameBase, setControl, void, ( bool controlled ), ( controlle
 
 GameBaseData::GameBaseData()
 {
-   mCategory = "";
+   mCategory = StringTable->EmptyString();
    mPacked = false;
 }
 GameBaseData::GameBaseData(const GameBaseData& other, bool temp_clone) : SimDataBlock(other, temp_clone)

+ 4 - 4
Engine/source/T3D/groundPlane.cpp

@@ -100,15 +100,15 @@ GroundPlane::~GroundPlane()
    mConvexList->nukeList();
    SAFE_DELETE( mConvexList );
 }
-
+FRangeValidator squareSizeRange(sMIN_SQUARE_SIZE, FLT_MAX);
 void GroundPlane::initPersistFields()
 {
    docsURL;
    addGroup( "Plane" );
 
-      addField( "squareSize",    TypeF32,          Offset( mSquareSize, GroundPlane ), "Square size in meters to which %GroundPlane subdivides its geometry." );
-      addField( "scaleU",        TypeF32,          Offset( mScaleU, GroundPlane ), "Scale of texture repeat in the U direction." );
-      addField( "scaleV",        TypeF32,          Offset( mScaleV, GroundPlane ), "Scale of texture repeat in the V direction." );
+      addFieldV( "squareSize",    TypeRangedF32,          Offset( mSquareSize, GroundPlane ),&squareSizeRange, "Square size in meters to which %GroundPlane subdivides its geometry." );
+      addFieldV( "scaleU", TypeRangedF32,          Offset( mScaleU, GroundPlane ), &CommonValidators::PositiveFloat, "Scale of texture repeat in the U direction." );
+      addFieldV( "scaleV", TypeRangedF32,          Offset( mScaleV, GroundPlane ), &CommonValidators::PositiveFloat, "Scale of texture repeat in the V direction." );
 
       INITPERSISTFIELD_MATERIALASSET(Material, GroundPlane, "The material used to render the ground plane.");
 

+ 4 - 4
Engine/source/T3D/guiObjectView.cpp

@@ -171,13 +171,13 @@ void GuiObjectView::initPersistFields()
    
    addGroup( "Camera" );
    
-      addField( "orbitDiststance", TypeF32, Offset( mOrbitDist, GuiObjectView ),
+      addFieldV( "orbitDiststance", TypeRangedF32, Offset( mOrbitDist, GuiObjectView ), &CommonValidators::PositiveFloat,
          "Distance from which to render the model." );
-      addField( "minOrbitDiststance", TypeF32, Offset( mMinOrbitDist, GuiObjectView ),
+      addFieldV( "minOrbitDiststance", TypeRangedF32, Offset( mMinOrbitDist, GuiObjectView ), &CommonValidators::PositiveFloat,
          "Maxiumum distance to which the camera can be zoomed out." );
-      addField( "maxOrbitDiststance", TypeF32, Offset( mMaxOrbitDist, GuiObjectView ),
+      addFieldV( "maxOrbitDiststance", TypeRangedF32, Offset( mMaxOrbitDist, GuiObjectView ), &CommonValidators::PositiveFloat,
          "Minimum distance below which the camera will not zoom in further." );
-      addField( "cameraSpeed", TypeF32, Offset( mCameraSpeed, GuiObjectView ),
+      addFieldV( "cameraSpeed", TypeRangedF32, Offset( mCameraSpeed, GuiObjectView ), &CommonValidators::PositiveFloat,
          "Multiplier for mouse camera operations." );
       addField( "cameraRotation", TypePoint3F, Offset( mCameraRotation, GuiObjectView ),
          "Set the camera rotation." );

+ 17 - 14
Engine/source/T3D/item.cpp

@@ -135,20 +135,23 @@ ImplementEnumType( ItemLightType,
    { Item::PulsingLight,      "PulsingLight",   "The item has a pulsing light attached.\n" }
 EndImplementEnumType;
 
+FRangeValidator itemFrictionRange(0.0f, FLT_MAX, 1<<10);
+FRangeValidator itemElasticityRange(0.0f, FLT_MAX, 1<<10);
+FRangeValidator itemGravityModRange(FLT_MIN, FLT_MAX, 1<<10);
 void ItemData::initPersistFields()
 {
    docsURL;
    Parent::initPersistFields();
    addGroup("Physics");
-      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.");
+      addFieldV("friction",          TypeRangedF32,       Offset(friction,           ItemData), &itemFrictionRange, "A floating-point value specifying how much velocity is lost to impact and sliding friction.");
+      addFieldV("elasticity", TypeRangedF32,       Offset(elasticity,         ItemData) ,&itemElasticityRange, "A floating-point value specifying how 'bouncy' this ItemData is.");
       addField("sticky",            TypeBool,      Offset(sticky,             ItemData),
          "@brief If true, ItemData will 'stick' to any surface it collides with.\n\n"
          "When an item does stick to a surface, the Item::onStickyCollision() callback is called.  The Item has methods to retrieve "
          "the world position and normal the Item is stuck to.\n"
          "@note Valid objects to stick to must be of StaticShapeObjectType.\n");
-      addField("gravityMod",        TypeF32,       Offset(gravityMod,         ItemData), "Floating point value to multiply the existing gravity with, just for this ItemData.");
-      addField("maxVelocity",       TypeF32,       Offset(maxVelocity,        ItemData), "Maximum velocity that this ItemData is able to move.");
+      addFieldV("gravityMod", TypeRangedF32,       Offset(gravityMod,         ItemData),&itemGravityModRange, "Floating point value to multiply the existing gravity with, just for this ItemData.");
+      addFieldV("maxVelocity", TypeRangedF32,       Offset(maxVelocity,        ItemData), &CommonValidators::PositiveFloat, "Maximum velocity that this ItemData is able to move.");
       addField("simpleServerCollision",   TypeBool,  Offset(simpleServerCollision,    ItemData),
          "@brief Determines if only simple server-side collision will be used (for pick ups).\n\n"
          "If set to true then only simple, server-side collision detection will be used.  This is often the case "
@@ -164,10 +167,10 @@ void ItemData::initPersistFields()
       addField("lightColor",        TypeColorF,    Offset(lightColor,         ItemData),
          "@brief Color value to make this light. Example: \"1.0,1.0,1.0\"\n\n"
          "@see lightType\n");
-      addField("lightTime",         TypeS32,       Offset(lightTime,          ItemData), 
+      addFieldV("lightTime",         TypeRangedS32,       Offset(lightTime,          ItemData), &CommonValidators::NaturalNumber,
          "@brief Time value for the light of this ItemData, used to control the pulse speed of the PulsingLight LightType.\n\n"
          "@see lightType\n");
-      addField("lightRadius",       TypeF32,       Offset(lightRadius,        ItemData), 
+      addFieldV("lightRadius",       TypeRangedF32,       Offset(lightRadius,        ItemData), &CommonValidators::PositiveFloat,
          "@brief Distance from the center point of this ItemData for the light to affect\n\n"
          "@see lightType\n");
       addField("lightOnlyStatic",   TypeBool,      Offset(lightOnlyStatic,    ItemData), 
@@ -191,10 +194,10 @@ void ItemData::packData(BitStream* stream)
    {
       AssertFatal(Item::NumLightTypes < (1 << 2), "ItemData: light type needs more bits");
       stream->writeInt(lightType, 2);
-      stream->writeFloat(lightColor.red, 7);
-      stream->writeFloat(lightColor.green, 7);
-      stream->writeFloat(lightColor.blue, 7);
-      stream->writeFloat(lightColor.alpha, 7);
+      stream->writeFloat(lightColor.red, 8);
+      stream->writeFloat(lightColor.green, 8);
+      stream->writeFloat(lightColor.blue, 8);
+      stream->writeFloat(lightColor.alpha, 8);
       stream->write(lightTime);
       stream->write(lightRadius);
       stream->writeFlag(lightOnlyStatic);
@@ -222,10 +225,10 @@ void ItemData::unpackData(BitStream* stream)
    if(stream->readFlag())
    {
       lightType = stream->readInt(2);
-      lightColor.red = stream->readFloat(7);
-      lightColor.green = stream->readFloat(7);
-      lightColor.blue = stream->readFloat(7);
-      lightColor.alpha = stream->readFloat(7);
+      lightColor.red = stream->readFloat(8);
+      lightColor.green = stream->readFloat(8);
+      lightColor.blue = stream->readFloat(8);
+      lightColor.alpha = stream->readFloat(8);
       stream->read(&lightTime);
       stream->read(&lightRadius);
       lightOnlyStatic = stream->readFlag();

+ 9 - 11
Engine/source/T3D/levelInfo.cpp

@@ -123,20 +123,18 @@ LevelInfo::~LevelInfo()
 
 //-----------------------------------------------------------------------------
 
-FRangeValidator ValiDampnessRange(0.0f, 1.0f);
-
 void LevelInfo::initPersistFields()
 {
    docsURL;
    addGroup( "Visibility" );
 
-      addField( "nearClip", TypeF32, Offset( mNearClip, LevelInfo ), "Closest distance from the camera's position to render the world." );
-      addField( "visibleDistance", TypeF32, Offset( mVisibleDistance, LevelInfo ), "Furthest distance from the camera's position to render the world." );
-      addField( "visibleGhostDistance", TypeF32, Offset( mVisibleGhostDistance, LevelInfo ), "Furthest distance from the camera's position to render players. Defaults to visibleDistance." );
-      addField( "decalBias", TypeF32, Offset( mDecalBias, LevelInfo ),
+      addFieldV( "nearClip", TypeRangedF32, Offset( mNearClip, LevelInfo ), &CommonValidators::PositiveFloat, "Closest distance from the camera's position to render the world." );
+      addFieldV( "visibleDistance", TypeRangedF32, Offset( mVisibleDistance, LevelInfo ), &CommonValidators::PositiveFloat, "Furthest distance from the camera's position to render the world." );
+      addFieldV( "visibleGhostDistance", TypeRangedF32, Offset( mVisibleGhostDistance, LevelInfo ), &CommonValidators::PositiveFloat, "Furthest distance from the camera's position to render players. Defaults to visibleDistance." );
+      addFieldV( "decalBias", TypeRangedF32, Offset( mDecalBias, LevelInfo ), &CommonValidators::PositiveFloat,
          "NearPlane bias used when rendering Decal and DecalRoad. This should be tuned to the visibleDistance in your level." );
 
-      addFieldV("dampness", TypeF32, Offset(mDampness, LevelInfo), &ValiDampnessRange,
+      addFieldV("dampness", TypeRangedF32, Offset(mDampness, LevelInfo), &CommonValidators::NormalizedFloat,
          "@brief dampness influence");
    endGroup( "Visibility" );
 
@@ -145,13 +143,13 @@ void LevelInfo::initPersistFields()
       addField( "fogColor", TypeColorF, Offset( mFogData.color, LevelInfo ),
          "The default color for the scene fog." );
 
-      addField( "fogDensity", TypeF32, Offset( mFogData.density, LevelInfo ),
+      addFieldV( "fogDensity", TypeRangedF32, Offset( mFogData.density, LevelInfo ), &CommonValidators::NormalizedFloat,
          "The 0 to 1 density value for the exponential fog falloff." );
 
-      addField( "fogDensityOffset", TypeF32, Offset( mFogData.densityOffset, LevelInfo ),
+      addFieldV( "fogDensityOffset", TypeRangedF32, Offset( mFogData.densityOffset, LevelInfo ), &CommonValidators::PositiveFloat,
          "An offset from the camera in meters for moving the start of the fog effect." );
 
-      addField( "fogAtmosphereHeight", TypeF32, Offset( mFogData.atmosphereHeight, LevelInfo ),
+      addFieldV( "fogAtmosphereHeight", TypeRangedF32, Offset( mFogData.atmosphereHeight, LevelInfo ), &CommonValidators::PositiveFloat,
          "A height in meters for altitude fog falloff." );
 
    endGroup( "Fog" );
@@ -165,7 +163,7 @@ void LevelInfo::initPersistFields()
 
    addGroup( "Lighting" );
 
-      addField( "ambientLightBlendPhase", TypeF32, Offset( mAmbientLightBlendPhase, LevelInfo ),
+      addFieldV( "ambientLightBlendPhase", TypeRangedF32, Offset( mAmbientLightBlendPhase, LevelInfo ), &CommonValidators::PositiveFloat,
          "Number of seconds it takes to blend from one ambient light color to a different one." );
 
       addField( "ambientLightBlendCurve", TypeEaseF, Offset( mAmbientLightBlendCurve, LevelInfo ),

+ 24 - 21
Engine/source/T3D/lightAnimData.cpp

@@ -65,77 +65,80 @@ void LightAnimData::initPersistFields()
    docsURL;
    addGroup( "Offset",
       "The XYZ translation animation state relative to the light position." );
-
-      addField( "offsetA", TypeF32, Offset( mOffset.value1, LightAnimData ), 3,
+      addArray("XYZ Pan", Axis);
+         addFieldV( "offsetA", TypeRangedF32, Offset( mOffset.value1, LightAnimData ), &CommonValidators::PositiveFloat, Axis,
          "The value of the A key in the keyframe sequence." );
 
-      addField( "offsetZ", TypeF32, Offset( mOffset.value2, LightAnimData ), 3,
+         addFieldV( "offsetZ", TypeRangedF32, Offset( mOffset.value2, LightAnimData ), &CommonValidators::PositiveFloat, Axis,
          "The value of the Z key in the keyframe sequence." );
 
-      addField( "offsetPeriod", TypeF32, Offset( mOffset.period, LightAnimData ), 3,
+         addFieldV( "offsetPeriod", TypeRangedF32, Offset( mOffset.period, LightAnimData ), &CommonValidators::PositiveFloat, Axis,
          "The animation time for keyframe sequence." );
 
-      addField( "offsetKeys", TypeString, Offset( mOffset.keys, LightAnimData ), 3,
+        addField( "offsetKeys", TypeString, Offset( mOffset.keys, LightAnimData ), Axis,
          "The keyframe sequence encoded into a string where characters from A to Z define "
          "a position between the two animation values." );
 
-      addField( "offsetSmooth", TypeBool, Offset( mOffset.smooth, LightAnimData ), 3,
+         addField( "offsetSmooth", TypeBool, Offset( mOffset.smooth, LightAnimData ), Axis,
          "If true the transition between keyframes will be smooth." );
-
+      endArray("XYZ Pan");
    endGroup( "Offset" );
 
    addGroup( "Rotation",
       "The XYZ rotation animation state relative to the light orientation." );
+      addArray("XYZ Rot", Axis);
 
-      addField( "rotA", TypeF32, Offset( mRot.value1, LightAnimData ), 3,
+         addFieldV( "rotA", TypeRangedF32, Offset( mRot.value1, LightAnimData ), &CommonValidators::DegreeRange, Axis,
          "The value of the A key in the keyframe sequence." );
 
-      addField( "rotZ", TypeF32, Offset( mRot.value2, LightAnimData ), 3,
+         addFieldV( "rotZ", TypeRangedF32, Offset( mRot.value2, LightAnimData ), &CommonValidators::DegreeRange, Axis,
          "The value of the Z key in the keyframe sequence." );
 
-      addField( "rotPeriod", TypeF32, Offset( mRot.period, LightAnimData ), 3,
+         addFieldV( "rotPeriod", TypeRangedF32, Offset( mRot.period, LightAnimData ), &CommonValidators::PositiveFloat, Axis,
          "The animation time for keyframe sequence." );
 
-      addField( "rotKeys", TypeString, Offset( mRot.keys, LightAnimData ), 3,
+         addField( "rotKeys", TypeString, Offset( mRot.keys, LightAnimData ), Axis,
          "The keyframe sequence encoded into a string where characters from A to Z define "
          "a position between the two animation values." );
 
-      addField( "rotSmooth", TypeBool, Offset( mRot.smooth, LightAnimData ), 3,
+         addField( "rotSmooth", TypeBool, Offset( mRot.smooth, LightAnimData ), Axis,
          "If true the transition between keyframes will be smooth." );
-
+      endArray("XYZ Rot");
    endGroup( "Rotation" );
 
    addGroup( "Color",
       "The RGB color animation state." );
+      addArray("RGB", Channel);
 
-      addField( "colorA", TypeF32, Offset( mColor.value1, LightAnimData ), 3,
+         addFieldV( "colorA", TypeRangedF32, Offset( mColor.value1, LightAnimData ), &CommonValidators::F32_8BitPercent, Channel,
          "The value of the A key in the keyframe sequence." );
 
-      addField( "colorZ", TypeF32, Offset( mColor.value2, LightAnimData ), 3,
+         addFieldV( "colorZ", TypeRangedF32, Offset( mColor.value2, LightAnimData ), &CommonValidators::F32_8BitPercent, Channel,
          "The value of the Z key in the keyframe sequence." );
 
-      addField( "colorPeriod", TypeF32, Offset( mColor.period, LightAnimData ), 3,
+         addFieldV( "colorPeriod", TypeRangedF32, Offset( mColor.period, LightAnimData ), &CommonValidators::PositiveFloat, Channel,
          "The animation time for keyframe sequence." );
 
-      addField( "colorKeys", TypeString, Offset( mColor.keys, LightAnimData ), 3,
+         addField( "colorKeys", TypeString, Offset( mColor.keys, LightAnimData ), Channel,
          "The keyframe sequence encoded into a string where characters from A to Z define "
          "a position between the two animation values." );
 
-      addField( "colorSmooth", TypeBool, Offset( mColor.smooth, LightAnimData ), 3,
+         addField( "colorSmooth", TypeBool, Offset( mColor.smooth, LightAnimData ), Channel,
          "If true the transition between keyframes will be smooth." );
+      endArray("RGB");
 
    endGroup( "Color" );
 
    addGroup( "Brightness",
       "The brightness animation state." );
 
-      addField( "brightnessA", TypeF32, Offset( mBrightness.value1, LightAnimData ),
+      addFieldV( "brightnessA", TypeRangedF32, Offset( mBrightness.value1, LightAnimData ), &CommonValidators::PositiveFloat,
          "The value of the A key in the keyframe sequence." );
 
-      addField( "brightnessZ", TypeF32, Offset( mBrightness.value2, LightAnimData ),
+      addFieldV( "brightnessZ", TypeRangedF32, Offset( mBrightness.value2, LightAnimData ), &CommonValidators::PositiveFloat,
          "The value of the Z key in the keyframe sequence." );
 
-      addField( "brightnessPeriod", TypeF32, Offset( mBrightness.period, LightAnimData ),
+      addFieldV( "brightnessPeriod", TypeRangedF32, Offset( mBrightness.period, LightAnimData ), &CommonValidators::PositiveFloat,
          "The animation time for keyframe sequence." );
 
       addField( "brightnessKeys", TypeString, Offset( mBrightness.keys, LightAnimData ),

+ 8 - 3
Engine/source/T3D/lightAnimData.h

@@ -164,14 +164,19 @@ public:
       void read( BitStream *stream );
    };
 
+   enum animEnums
+   {
+      Axis = 3,
+      Channel = 3
+   };
    /// The positional animation parameters for x, y, and z.
-   AnimValue<3> mOffset;
+   AnimValue<Axis> mOffset;
 
    /// The rotational animation parameters for x, y, and z.
-   AnimValue<3> mRot;
+   AnimValue<Axis> mRot;
 
    /// The color animation parameters for r, g, and b.
-   AnimValue<3> mColor;
+   AnimValue<Channel> mColor;
 
    /// The brightness animation parameter.
    AnimValue<1> mBrightness;

+ 5 - 5
Engine/source/T3D/lightBase.cpp

@@ -97,11 +97,11 @@ void LightBase::initPersistFields()
       
       addField( "isEnabled", TypeBool, Offset( mIsEnabled, LightBase ), "Enables/Disables the object rendering and functionality in the scene." );
       addField( "color", TypeColorF, Offset( mColor, LightBase ), "Changes the base color hue of the light." );
-      addField( "brightness", TypeF32, Offset( mBrightness, LightBase ), "Adjusts the lights power, 0 being off completely." );      
+      addFieldV( "brightness", TypeRangedF32, Offset( mBrightness, LightBase ), &CommonValidators::PositiveFloat, "Adjusts the lights power, 0 being off completely." );
       addField( "castShadows", TypeBool, Offset( mCastShadows, LightBase ), "Enables/disabled shadow casts by this light." );
       //addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightBase ), "static shadow refresh rate (milliseconds)" );
       //addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightBase ), "dynamic shadow refresh rate (milliseconds)");
-      addField( "priority", TypeF32, Offset( mPriority, LightBase ), "Used for sorting of lights by the light manager. "
+      addFieldV( "priority", TypeRangedF32, Offset( mPriority, LightBase ), &CommonValidators::PositiveFloat, "Used for sorting of lights by the light manager. "
 		  "Priority determines if a light has a stronger effect than, those with a lower value" );
 
    endGroup( "Light" );
@@ -110,15 +110,15 @@ void LightBase::initPersistFields()
 
       addField( "animate", TypeBool, Offset( mAnimState.active, LightBase ), "Toggles animation for the light on and off" );
       addField( "animationType", TYPEID< LightAnimData >(), Offset( mAnimationData, LightBase ), "Datablock containing light animation information (LightAnimData)" );
-      addFieldV( "animationPeriod", TypeF32, Offset( mAnimState.animationPeriod, LightBase ), &CommonValidators::PositiveNonZeroFloat, "The length of time in seconds for a single playback of the light animation (must be > 0)" );
-      addField( "animationPhase", TypeF32, Offset( mAnimState.animationPhase, LightBase ), "The phase used to offset the animation start time to vary the animation of nearby lights." );      
+      addFieldV( "animationPeriod", TypeRangedF32, Offset( mAnimState.animationPeriod, LightBase ), &CommonValidators::PositiveNonZeroFloat, "The length of time in seconds for a single playback of the light animation (must be > 0)" );
+      addFieldV( "animationPhase", TypeRangedF32, Offset( mAnimState.animationPhase, LightBase ), &CommonValidators::PositiveFloat, "The phase used to offset the animation start time to vary the animation of nearby lights." );
 
    endGroup( "Light Animation" );
 
    addGroup( "Misc" );
 
       addField( "flareType", TYPEID< LightFlareData >(), Offset( mFlareData, LightBase ), "Datablock containing light flare information (LightFlareData)" );
-      addField( "flareScale", TypeF32, Offset( mFlareScale, LightBase ), "Globally scales all features of the light flare" );
+      addFieldV( "flareScale", TypeRangedF32, Offset( mFlareScale, LightBase ), &CommonValidators::PositiveFloat, "Globally scales all features of the light flare" );
 
    endGroup( "Misc" );
 

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

@@ -29,6 +29,7 @@
 #include "core/stream/bitStream.h"
 #include "lighting/lightInfo.h"
 #include "console/engineAPI.h"
+#include "console/typeValidators.h"
 
 
 LightDescription::LightDescription()
@@ -94,26 +95,27 @@ void LightDescription::initPersistFields()
    addGroup( "Light" );
 
       addField( "color", TypeColorF, Offset( color, LightDescription ), "Changes the base color hue of the light." );
-      addField( "brightness", TypeF32, Offset( brightness, LightDescription ), "Adjusts the lights power, 0 being off completely." );      
-      addField( "range", TypeF32, Offset( range, LightDescription ), "Controls the size (radius) of the light" );
+      addFieldV( "brightness", TypeRangedF32, Offset( brightness, LightDescription ), &CommonValidators::PositiveFloat, "Adjusts the lights power, 0 being off completely." );
+      addFieldV( "range", TypeRangedF32, Offset( range, LightDescription ), &CommonValidators::PositiveFloat, "Controls the size (radius) of the light" );
       addField( "castShadows", TypeBool, Offset( castShadows, LightDescription ), "Enables/disabled shadow casts by this light." );
+      /*
       addField( "staticRefreshFreq", TypeS32, Offset( mStaticRefreshFreq, LightDescription ), "static shadow refresh rate (milliseconds)" );
       addField( "dynamicRefreshFreq", TypeS32, Offset( mDynamicRefreshFreq, LightDescription ), "dynamic shadow refresh rate (milliseconds)");
-
+      */
    endGroup( "Light" );
 
    addGroup( "Light Animation" );
 
       addField( "animationType", TYPEID< LightAnimData >(), Offset( animationData, LightDescription ), "Datablock containing light animation information (LightAnimData)" );
-      addField( "animationPeriod", TypeF32, Offset( animationPeriod, LightDescription ), "The length of time in seconds for a single playback of the light animation" );
-      addField( "animationPhase", TypeF32, Offset( animationPhase, LightDescription ), "The phase used to offset the animation start time to vary the animation of nearby lights." );
+      addFieldV( "animationPeriod", TypeRangedF32, Offset( animationPeriod, LightDescription ), &CommonValidators::PositiveFloat, "The length of time in seconds for a single playback of the light animation" );
+      addFieldV( "animationPhase", TypeRangedF32, Offset( animationPhase, LightDescription ), &CommonValidators::PositiveFloat, "The phase used to offset the animation start time to vary the animation of nearby lights." );
 
    endGroup( "Light Animation" );
 
    addGroup( "Misc" );
 
       addField( "flareType", TYPEID< LightFlareData >(), Offset( flareData, LightDescription ), "Datablock containing light flare information (LightFlareData)" );
-      addField( "flareScale", TypeF32, Offset( flareScale, LightDescription ), "Globally scales all features of the light flare" );
+      addFieldV( "flareScale", TypeRangedF32, Offset( flareScale, LightDescription ), &CommonValidators::PositiveFloat, "Globally scales all features of the light flare" );
 
    endGroup( "Misc" );
 

+ 4 - 4
Engine/source/T3D/lightFlareData.cpp

@@ -145,10 +145,10 @@ void LightFlareData::initPersistFields()
    docsURL;
    addGroup( "LightFlareData" );
 
-      addField( "overallScale", TypeF32, Offset( mScale, LightFlareData ),
+      addFieldV( "overallScale", TypeRangedF32, Offset( mScale, LightFlareData ), &CommonValidators::PositiveFloat,
          "Size scale applied to all elements of the flare." );
 
-      addField( "occlusionRadius", TypeF32, Offset( mOcclusionRadius, LightFlareData ), 
+      addFieldV( "occlusionRadius", TypeRangedF32, Offset( mOcclusionRadius, LightFlareData ), &CommonValidators::PositiveFloat,
          "If positive an occlusion query is used to test flare visibility, else it uses simple raycasts." );
 
       addField( "renderReflectPass", TypeBool, Offset( mRenderReflectPass, LightFlareData ), 
@@ -168,10 +168,10 @@ void LightFlareData::initPersistFields()
          addField( "elementRect", TypeRectF, Offset( mElementRect, LightFlareData ), MAX_ELEMENTS,
             "A rectangle specified in pixels of the flareTexture image." );
 
-         addField( "elementDist", TypeF32, Offset( mElementDist, LightFlareData ), MAX_ELEMENTS,
+         addFieldV( "elementDist", TypeRangedF32, Offset( mElementDist, LightFlareData ), &CommonValidators::PositiveFloat, MAX_ELEMENTS,
             "Where this element appears along the flare beam." );
 
-         addField( "elementScale", TypeF32, Offset( mElementScale, LightFlareData ), MAX_ELEMENTS,
+         addFieldV( "elementScale", TypeRangedF32, Offset( mElementScale, LightFlareData ), &CommonValidators::PositiveFloat, MAX_ELEMENTS,
             "Size scale applied to this element." );
 
          addField( "elementTint", TypeColorF, Offset( mElementTint, LightFlareData ), MAX_ELEMENTS,

+ 0 - 1
Engine/source/T3D/lighting/boxEnvironmentProbe.cpp

@@ -92,7 +92,6 @@ void BoxEnvironmentProbe::initPersistFields()
    docsURL;
    // SceneObject already handles exposing the transform
    Parent::initPersistFields();
-
    removeField("radius");
 }
 

+ 2 - 2
Engine/source/T3D/lighting/reflectionProbe.cpp

@@ -157,11 +157,11 @@ void ReflectionProbe::initPersistFields()
       addProtectedField("enabled", TypeBool, Offset(mEnabled, ReflectionProbe),
          &_setEnabled, &defaultProtectedGetFn, "Is the probe enabled or not");
       addField("canDamp", TypeBool, Offset(mCanDamp, ReflectionProbe),"wetness allowed");
-      addField("attenuation", TypeF32, Offset(mAtten, ReflectionProbe), "falloff percent");
+      addFieldV("attenuation", TypeRangedF32, Offset(mAtten, ReflectionProbe), &CommonValidators::NormalizedFloat, "falloff percent");
    endGroup("Rendering");
 
    addGroup("Reflection");
-      addProtectedField("radius", TypeF32, Offset(mRadius, ReflectionProbe), &_setRadius, &defaultProtectedGetFn, 
+      addProtectedFieldV("radius", TypeRangedF32, Offset(mRadius, ReflectionProbe), &_setRadius, &defaultProtectedGetFn, &CommonValidators::PositiveFloat,
          "The name of the material used to render the mesh.");
 
       addProtectedField("EditPosOffset", TypeBool, Offset(mEditPosOffset, ReflectionProbe),

+ 3 - 2
Engine/source/T3D/missionArea.cpp

@@ -22,6 +22,7 @@
 
 #include "T3D/missionArea.h"
 #include "console/consoleTypes.h"
+#include "console/typeValidators.h"
 #include "core/stream/bitStream.h"
 #include "math/mathIO.h"
 #include "console/engineAPI.h"
@@ -133,8 +134,8 @@ void MissionArea::initPersistFields()
    docsURL;
    addGroup("Dimensions");	
    addField("area", TypeRectI, Offset(mArea, MissionArea), "Four corners (X1, X2, Y1, Y2) that makes up the level's boundaries");
-   addField("flightCeiling", TypeF32, Offset(mFlightCeiling, MissionArea), "Represents the top of the mission area, used by FlyingVehicle. ");
-   addField("flightCeilingRange", TypeF32, Offset(mFlightCeilingRange, MissionArea), "Distance from ceiling before FlyingVehicle thrust is cut off. ");
+   addFieldV("flightCeiling", TypeRangedF32, Offset(mFlightCeiling, MissionArea),&CommonValidators::F32Range, "Represents the top of the mission area, used by FlyingVehicle. ");
+   addFieldV("flightCeilingRange", TypeRangedF32, Offset(mFlightCeilingRange, MissionArea), &CommonValidators::F32Range, "Distance from ceiling before FlyingVehicle thrust is cut off. ");
    endGroup("Dimensions");
 
    Parent::initPersistFields();

+ 1 - 1
Engine/source/T3D/missionMarker.cpp

@@ -489,7 +489,7 @@ void SpawnSphere::initPersistFields()
    endGroup( "Spawn" );
 
    addGroup( "Dimensions" );
-   addField( "radius", TypeF32, Offset(mRadius, SpawnSphere), "Deprecated" );
+   addFieldV( "radius", TypeRangedF32, Offset(mRadius, SpawnSphere), &CommonValidators::PositiveFloat, "Deprecated" );
    endGroup( "Dimensions" );
 
    addGroup( "Weight" );

+ 4 - 2
Engine/source/T3D/physicalZone.cpp

@@ -146,12 +146,14 @@ void PhysicalZone::consoleInit()
 	   "@ingroup EnviroMisc\n");
 }
 
+FRangeValidator velocityModRange(-40.0f, 40.0f);
+FRangeValidator gravityModRange(-40.0f, 40.0f);
 void PhysicalZone::initPersistFields()
 {
    docsURL;
    addGroup("Misc");
-   addField("velocityMod",  TypeF32,               Offset(mVelocityMod,  PhysicalZone), "Multiply velocity of objects entering zone by this value every tick.");
-   addField("gravityMod",   TypeF32,               Offset(mGravityMod,   PhysicalZone), "Gravity in PhysicalZone. Multiplies against standard gravity.");
+   addFieldV("velocityMod",  TypeRangedF32,               Offset(mVelocityMod,  PhysicalZone), &velocityModRange, "Multiply velocity of objects entering zone by this value every tick.");
+   addFieldV("gravityMod", TypeRangedF32,               Offset(mGravityMod,   PhysicalZone), &gravityModRange, "Gravity in PhysicalZone. Multiplies against standard gravity.");
    addField("appliedForce", TypePoint3F,           Offset(mAppliedForce, PhysicalZone), "Three-element floating point value representing forces in three axes to apply to objects entering PhysicalZone.");
    addField("polyhedron",   TypeTriggerPolyhedron, Offset(mPolyhedron,   PhysicalZone),
       "The polyhedron type is really a quadrilateral and consists of a corner"

+ 12 - 12
Engine/source/T3D/physics/physicsDebris.cpp

@@ -128,29 +128,29 @@ void PhysicsDebrisData::initPersistFields()
 
    addGroup( "Physics" );
 
-      addField("lifetime", TypeF32, Offset( lifetime, PhysicsDebrisData ),
+      addFieldV("lifetime", TypeRangedF32, Offset( lifetime, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Base time, in seconds, that debris persists after time of creation.\n\n"
          "@note A %PhysicsDebris' lifetime multiplied by it's $pref::PhysicsDebris::lifetimeScale "
          "must be equal to or greater than 1.0.\n\n");
 
-      addField("lifetimeVariance", TypeF32, Offset( lifetimeVariance, PhysicsDebrisData ),
+      addFieldV("lifetimeVariance", TypeRangedF32, Offset( lifetimeVariance, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Range of variation randomly applied to lifetime when debris is created.\n\n"
          "Represents the maximum amount of seconds that will be added or subtracted to a shape's base lifetime. "
          "A value of 0 will apply the same lifetime to each shape created.\n\n");
 
-      addField( "mass", TypeF32, Offset( mass, PhysicsDebrisData ),
+      addFieldV( "mass", TypeRangedF32, Offset( mass, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Value representing the mass of the shape.\n\n"
          "A shape's mass influences the magnitude of any force applied to it. "
          "@note All PhysicsDebris objects are dynamic.");
 
-      addField( "friction", TypeF32, Offset( dynamicFriction, PhysicsDebrisData ),
+      addFieldV( "friction", TypeRangedF32, Offset( dynamicFriction, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Coefficient of kinetic %friction to be applied to the shape.\n\n" 
          "Kinetic %friction reduces the velocity of a moving object while it is in contact with a surface. "
          "A larger coefficient will result in a larger reduction in velocity. "
          "A shape's friction should be smaller than it's staticFriction, but greater than 0.\n\n"
          "@note This value is only applied while an object is in motion. For an object starting at rest, see PhysicsDebrisData::staticFriction");
 
-      addField( "staticFriction", TypeF32, Offset( staticFriction, PhysicsDebrisData ),
+      addFieldV( "staticFriction", TypeRangedF32, Offset( staticFriction, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Coefficient of static %friction to be applied to the shape.\n\n" 
          "Static %friction determines the force needed to start moving an at-rest object in contact with a surface. "
          "If the force applied onto shape cannot overcome the force of static %friction, the shape will remain at rest. "
@@ -158,7 +158,7 @@ void PhysicsDebrisData::initPersistFields()
          "This value should be both greater than 0 and the PhysicsDebrisData::friction.\n\n"
          "@note This value is only applied while an object is at rest. For an object in motion, see PhysicsDebrisData::friction");
 
-      addField( "restitution", TypeF32, Offset( restitution, PhysicsDebrisData ),
+      addFieldV( "restitution", TypeRangedF32, Offset( restitution, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Bounce coeffecient applied to the shape in response to a collision.\n\n"
          "Restitution is a ratio of a shape's velocity before and after a collision. "
          "A value of 0 will zero out a shape's post-collision velocity, making it stop on contact. "
@@ -167,29 +167,29 @@ void PhysicsDebrisData::initPersistFields()
          "@note Values near or equaling 1.0 are likely to cause undesirable results in the physics simulation."
          " Because of this, it is reccomended to avoid values close to 1.0");
 
-      addField( "linearDamping", TypeF32, Offset( linearDamping, PhysicsDebrisData ),
+      addFieldV( "linearDamping", TypeRangedF32, Offset( linearDamping, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Value that reduces an object's linear velocity over time.\n\n"
          "Larger values will cause velocity to decay quicker.\n\n" );
 
-      addField( "angularDamping", TypeF32, Offset( angularDamping, PhysicsDebrisData ),
+      addFieldV( "angularDamping", TypeRangedF32, Offset( angularDamping, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Value that reduces an object's rotational velocity over time.\n\n"
          "Larger values will cause velocity to decay quicker.\n\n" );
 
-      addField( "linearSleepThreshold", TypeF32, Offset( linearSleepThreshold, PhysicsDebrisData ),
+      addFieldV( "linearSleepThreshold", TypeRangedF32, Offset( linearSleepThreshold, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Minimum linear velocity before the shape can be put to sleep.\n\n"
          "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
          "@note The shape must be dynamic.");
 
-      addField( "angularSleepThreshold", TypeF32, Offset( angularSleepThreshold, PhysicsDebrisData ),
+      addFieldV( "angularSleepThreshold", TypeRangedF32, Offset( angularSleepThreshold, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Minimum rotational velocity before the shape can be put to sleep.\n\n"
          "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
          "@note The shape must be dynamic.");
 
-      addField( "waterDampingScale", TypeF32, Offset( waterDampingScale, PhysicsDebrisData ),
+      addFieldV( "waterDampingScale", TypeRangedF32, Offset( waterDampingScale, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief Scale to apply to linear and angular dampening while underwater.\n\n "
          "@see angularDamping linearDamping" );
 
-      addField( "buoyancyDensity", TypeF32, Offset( buoyancyDensity, PhysicsDebrisData ),
+      addFieldV( "buoyancyDensity", TypeRangedF32, Offset( buoyancyDensity, PhysicsDebrisData ), &CommonValidators::PositiveFloat,
          "@brief The density of this shape for purposes of calculating buoyant forces.\n\n"
          "The result of the calculated buoyancy is relative to the density of the WaterObject the PhysicsDebris is within."
          "@see WaterObject::density");

+ 10 - 10
Engine/source/T3D/physics/physicsShape.cpp

@@ -106,21 +106,21 @@ void PhysicsShapeData::initPersistFields()
 
    addGroup( "Physics" );
       
-      addField( "mass", TypeF32, Offset( mass, PhysicsShapeData ),
+      addFieldV( "mass", TypeRangedF32, Offset( mass, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief Value representing the mass of the shape.\n\n"
          "A shape's mass influences the magnitude of any force exerted on it. "
          "For example, a PhysicsShape with a large mass requires a much larger force to move than "
          "the same shape with a smaller mass.\n"
          "@note A mass of zero will create a kinematic shape while anything greater will create a dynamic shape.");
 
-      addField( "friction", TypeF32, Offset( dynamicFriction, PhysicsShapeData ),
+      addFieldV( "friction", TypeRangedF32, Offset( dynamicFriction, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief Coefficient of kinetic %friction to be applied to the shape.\n\n" 
          "Kinetic %friction reduces the velocity of a moving object while it is in contact with a surface. "
          "A higher coefficient will result in a larger velocity reduction. "
          "A shape's friction should be lower than it's staticFriction, but larger than 0.\n\n"
          "@note This value is only applied while an object is in motion. For an object starting at rest, see PhysicsShape::staticFriction");
 
-      addField( "staticFriction", TypeF32, Offset( staticFriction, PhysicsShapeData ),
+      addFieldV( "staticFriction", TypeRangedF32, Offset( staticFriction, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief Coefficient of static %friction to be applied to the shape.\n\n" 
          "Static %friction determines the force needed to start moving an at-rest object in contact with a surface. "
          "If the force applied onto shape cannot overcome the force of static %friction, the shape will remain at rest. "
@@ -128,7 +128,7 @@ void PhysicsShapeData::initPersistFields()
          "This value should be larger than zero and the physicsShape's friction.\n\n"
          "@note This value is only applied while an object is at rest. For an object in motion, see PhysicsShape::friction");
 
-      addField( "restitution", TypeF32, Offset( restitution, PhysicsShapeData ),
+      addFieldV( "restitution", TypeRangedF32, Offset( restitution, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief Coeffecient of a bounce applied to the shape in response to a collision.\n\n"
          "Restitution is a ratio of a shape's velocity before and after a collision. "
          "A value of 0 will zero out a shape's post-collision velocity, making it stop on contact. "
@@ -137,30 +137,30 @@ void PhysicsShapeData::initPersistFields()
          "@note Values near or equaling 1.0 are likely to cause undesirable results in the physics simulation."
          " Because of this it is reccomended to avoid values close to 1.0");
 
-      addField( "linearDamping", TypeF32, Offset( linearDamping, PhysicsShapeData ),
+      addFieldV( "linearDamping", TypeRangedF32, Offset( linearDamping, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief Value that reduces an object's linear velocity over time.\n\n"
          "Larger values will cause velocity to decay quicker.\n\n" );
 
-      addField( "angularDamping", TypeF32, Offset( angularDamping, PhysicsShapeData ),
+      addFieldV( "angularDamping", TypeRangedF32, Offset( angularDamping, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief Value that reduces an object's rotational velocity over time.\n\n"
          "Larger values will cause velocity to decay quicker.\n\n" );
 
-      addField( "linearSleepThreshold", TypeF32, Offset( linearSleepThreshold, PhysicsShapeData ),
+      addFieldV( "linearSleepThreshold", TypeRangedF32, Offset( linearSleepThreshold, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief Minimum linear velocity before the shape can be put to sleep.\n\n"
          "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
          "@note The shape must be dynamic.");
 
-      addField( "angularSleepThreshold", TypeF32, Offset( angularSleepThreshold, PhysicsShapeData ),
+      addFieldV( "angularSleepThreshold", TypeRangedF32, Offset( angularSleepThreshold, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief Minimum rotational velocity before the shape can be put to sleep.\n\n"
          "This should be a positive value. Shapes put to sleep will not be simulated in order to save system resources.\n\n"
          "@note The shape must be dynamic.");
 
-      addField( "waterDampingScale", TypeF32, Offset( waterDampingScale, PhysicsShapeData ),
+      addFieldV( "waterDampingScale", TypeRangedF32, Offset( waterDampingScale, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief Scale to apply to linear and angular dampening while underwater.\n\n "
          "Used with the waterViscosity of the  "
          "@see angularDamping linearDamping" );
 
-      addField( "buoyancyDensity", TypeF32, Offset( buoyancyDensity, PhysicsShapeData ),
+      addFieldV( "buoyancyDensity", TypeRangedF32, Offset( buoyancyDensity, PhysicsShapeData ), &CommonValidators::PositiveFloat,
          "@brief The density of the shape for calculating buoyant forces.\n\n"
          "The result of the calculated buoyancy is relative to the density of the WaterObject the PhysicsShape is within.\n\n"
          "@see WaterObject::density");

+ 82 - 81
Engine/source/T3D/player.cpp

@@ -699,19 +699,20 @@ bool PlayerData::isJumpAction(U32 action)
 {
    return (action == JumpAnim || action == StandJumpAnim);
 }
+IRangeValidator jumpDelayRange(0, 1 << PlayerData::JumpDelayBits);
 
 void PlayerData::initPersistFields()
 {
    docsURL;
    Parent::initPersistFields();
 
-   addField( "pickupRadius", TypeF32, Offset(pickupRadius, PlayerData),
+   addFieldV( "pickupRadius", TypeRangedF32, Offset(pickupRadius, PlayerData), &CommonValidators::PositiveFloat,
       "@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 "
       "to determine the actual distance, to a maximum of 2 times the bounding box size.  The "
       "initial bounding box is that used for the root pose, and therefore doesn't take into "
       "account the change in pose.\n");
-   addField( "maxTimeScale", TypeF32, Offset(maxTimeScale, PlayerData),
+   addFieldV( "maxTimeScale", TypeRangedF32, Offset(maxTimeScale, PlayerData), &CommonValidators::PositiveFloat,
       "@brief Maximum time scale for action animations.\n\n"
       "If an action animation has a defined ground frame, it is automatically scaled to match the "
       "player's ground velocity.  This field limits the maximum time scale used even if "
@@ -725,13 +726,13 @@ void PlayerData::initPersistFields()
       addField( "firstPersonShadows", TypeBool, Offset(firstPersonShadows, PlayerData),
          "@brief Forces shadows to be rendered in first person when renderFirstPerson is disabled.  Defaults to false.\n\n" );
 
-      addField( "minLookAngle", TypeF32, Offset(minLookAngle, PlayerData),
+      addFieldV( "minLookAngle", TypeRangedF32, Offset(minLookAngle, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Lowest angle (in radians) the player can look.\n\n"
          "@note An angle of zero is straight ahead, with positive up and negative down." );
-      addField( "maxLookAngle", TypeF32, Offset(maxLookAngle, PlayerData),
+      addFieldV( "maxLookAngle", TypeRangedF32, Offset(maxLookAngle, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Highest angle (in radians) the player can look.\n\n"
          "@note An angle of zero is straight ahead, with positive up and negative down." );
-      addField( "maxFreelookAngle", TypeF32, Offset(maxFreelookAngle, PlayerData),
+      addFieldV( "maxFreelookAngle", TypeRangedF32, Offset(maxFreelookAngle, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Defines the maximum left and right angles (in radians) the player can "
          "look in freelook mode.\n\n" );
 
@@ -739,72 +740,72 @@ void PlayerData::initPersistFields()
 
    addGroup( "Movement" );
 
-      addField( "maxStepHeight", TypeF32, Offset(maxStepHeight, PlayerData),
+      addFieldV( "maxStepHeight", TypeRangedF32, Offset(maxStepHeight, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum height the player can step up.\n\n"
          "The player will automatically step onto changes in ground height less "
          "than maxStepHeight.  The player will collide with ground height changes "
          "greater than this." );
 
-      addField( "runForce", TypeF32, Offset(runForce, PlayerData),
+      addFieldV( "runForce", TypeRangedF32, Offset(runForce, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Force used to accelerate the player when running.\n\n" );
 
-      addField( "runEnergyDrain", TypeF32, Offset(runEnergyDrain, PlayerData),
+      addFieldV( "runEnergyDrain", TypeRangedF32, Offset(runEnergyDrain, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Energy value drained each tick that the player is moving.\n\n"
          "The player will not be able to move when his energy falls below "
          "minRunEnergy.\n"
          "@note Setting this to zero will disable any energy drain.\n"
          "@see minRunEnergy\n");
-      addField( "minRunEnergy", TypeF32, Offset(minRunEnergy, PlayerData),
+      addFieldV( "minRunEnergy", TypeRangedF32, Offset(minRunEnergy, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum energy level required to run or swim.\n\n"
          "@see runEnergyDrain\n");
 
-      addField( "maxForwardSpeed", TypeF32, Offset(maxForwardSpeed, PlayerData),
+      addFieldV( "maxForwardSpeed", TypeRangedF32, Offset(maxForwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum forward speed when running." );
-      addField( "maxBackwardSpeed", TypeF32, Offset(maxBackwardSpeed, PlayerData),
+      addFieldV( "maxBackwardSpeed", TypeRangedF32, Offset(maxBackwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum backward speed when running." );
-      addField( "maxSideSpeed", TypeF32, Offset(maxSideSpeed, PlayerData),
+      addFieldV( "maxSideSpeed", TypeRangedF32, Offset(maxSideSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum sideways speed when running." );
 
-      addField( "runSurfaceAngle", TypeF32, Offset(runSurfaceAngle, PlayerData),
+      addFieldV( "runSurfaceAngle", TypeRangedF32, Offset(runSurfaceAngle, PlayerData), &CommonValidators::PosDegreeRangeQuarter,
          "@brief Maximum angle from vertical (in degrees) the player can run up.\n\n" );
 
-      addField( "minImpactSpeed", TypeF32, Offset(minImpactSpeed, PlayerData),
+      addFieldV( "minImpactSpeed", TypeRangedF32, Offset(minImpactSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum impact speed to apply falling damage.\n\n"
          "This field also sets the minimum speed for the onImpact callback "
          "to be invoked.\n"
          "@see ShapeBaseData::onImpact()\n");
-      addField( "minLateralImpactSpeed", TypeF32, Offset(minLateralImpactSpeed, PlayerData),
+      addFieldV( "minLateralImpactSpeed", TypeRangedF32, Offset(minLateralImpactSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum impact speed to apply non-falling damage.\n\n"
          "This field also sets the minimum speed for the onLateralImpact callback "
          "to be invoked.\n"
          "@see ShapeBaseData::onLateralImpact()\n");
 
-      addField( "horizMaxSpeed", TypeF32, Offset(horizMaxSpeed, PlayerData),
+      addFieldV( "horizMaxSpeed", TypeRangedF32, Offset(horizMaxSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum horizontal speed.\n\n"
          "@note This limit is only enforced if the player's horizontal speed "
          "exceeds horizResistSpeed.\n"
          "@see horizResistSpeed\n"
          "@see horizResistFactor\n" );
-      addField( "horizResistSpeed", TypeF32, Offset(horizResistSpeed, PlayerData),
+      addFieldV( "horizResistSpeed", TypeRangedF32, Offset(horizResistSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Horizontal speed at which resistence will take place.\n\n"
          "@see horizMaxSpeed\n"
          "@see horizResistFactor\n" );
-      addField( "horizResistFactor", TypeF32, Offset(horizResistFactor, PlayerData),
+      addFieldV( "horizResistFactor", TypeRangedF32, Offset(horizResistFactor, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Factor of resistence once horizResistSpeed has been reached.\n\n"
          "@see horizMaxSpeed\n"
          "@see horizResistSpeed\n" );
 
-      addField( "upMaxSpeed", TypeF32, Offset(upMaxSpeed, PlayerData),
+      addFieldV( "upMaxSpeed", TypeRangedF32, Offset(upMaxSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum upwards speed.\n\n"
          "@note This limit is only enforced if the player's upward speed exceeds "
          "upResistSpeed.\n"
          "@see upResistSpeed\n"
          "@see upResistFactor\n" );
-      addField( "upResistSpeed", TypeF32, Offset(upResistSpeed, PlayerData),
+      addFieldV( "upResistSpeed", TypeRangedF32, Offset(upResistSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Upwards speed at which resistence will take place.\n\n"
          "@see upMaxSpeed\n"
          "@see upResistFactor\n" );
-      addField( "upResistFactor", TypeF32, Offset(upResistFactor, PlayerData),
+      addFieldV( "upResistFactor", TypeRangedF32, Offset(upResistFactor, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Factor of resistence once upResistSpeed has been reached.\n\n"
          "@see upMaxSpeed\n"
          "@see upResistSpeed\n" );
@@ -813,29 +814,29 @@ void PlayerData::initPersistFields()
    
    addGroup( "Movement: Jumping" );
 
-      addField( "jumpForce", TypeF32, Offset(jumpForce, PlayerData),
+      addFieldV( "jumpForce", TypeRangedF32, Offset(jumpForce, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Force used to accelerate the player when a jump is initiated.\n\n" );
 
-      addField( "jumpEnergyDrain", TypeF32, Offset(jumpEnergyDrain, PlayerData),
+      addFieldV( "jumpEnergyDrain", TypeRangedF32, Offset(jumpEnergyDrain, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Energy level drained each time the player jumps.\n\n"
          "@note Setting this to zero will disable any energy drain\n"
          "@see minJumpEnergy\n");
-      addField( "minJumpEnergy", TypeF32, Offset(minJumpEnergy, PlayerData),
+      addFieldV( "minJumpEnergy", TypeRangedF32, Offset(minJumpEnergy, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum energy level required to jump.\n\n"
          "@see jumpEnergyDrain\n");
 
-      addField( "minJumpSpeed", TypeF32, Offset(minJumpSpeed, PlayerData),
+      addFieldV( "minJumpSpeed", TypeRangedF32, Offset(minJumpSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum speed needed to jump.\n\n"
          "If the player's own z velocity is greater than this, then it is used to scale "
          "the jump speed, up to maxJumpSpeed.\n"
          "@see maxJumpSpeed\n");
-      addField( "maxJumpSpeed", TypeF32, Offset(maxJumpSpeed, PlayerData),
+      addFieldV( "maxJumpSpeed", TypeRangedF32, Offset(maxJumpSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum vertical speed before the player can no longer jump.\n\n" );
-      addField( "jumpSurfaceAngle", TypeF32, Offset(jumpSurfaceAngle, PlayerData),
+      addFieldV( "jumpSurfaceAngle", TypeRangedF32, Offset(jumpSurfaceAngle, PlayerData), &CommonValidators::PosDegreeRangeQuarter,
          "@brief Angle from vertical (in degrees) where the player can jump.\n\n" );
-      addField( "jumpDelay", TypeS32, Offset(jumpDelay, PlayerData),
+      addFieldV( "jumpDelay", TypeRangedS32, Offset(jumpDelay, PlayerData), &jumpDelayRange,
          "@brief Delay time in number of ticks ticks between jumps.\n\n" );
-      addField( "airControl", TypeF32, Offset(airControl, PlayerData),
+      addFieldV( "airControl", TypeRangedF32, Offset(airControl, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Amount of movement control the player has when in the air.\n\n"
          "This is applied as a multiplier to the player's x and y motion.\n");
       addField( "jumpTowardsNormal", TypeBool, Offset(jumpTowardsNormal, PlayerData),
@@ -849,31 +850,31 @@ void PlayerData::initPersistFields()
    
    addGroup( "Movement: Sprinting" );
 
-      addField( "sprintForce", TypeF32, Offset(sprintForce, PlayerData),
+      addFieldV( "sprintForce", TypeRangedF32, Offset(sprintForce, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Force used to accelerate the player when sprinting.\n\n" );
 
-      addField( "sprintEnergyDrain", TypeF32, Offset(sprintEnergyDrain, PlayerData),
+      addFieldV( "sprintEnergyDrain", TypeRangedF32, Offset(sprintEnergyDrain, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Energy value drained each tick that the player is sprinting.\n\n"
          "The player will not be able to move when his energy falls below "
          "sprintEnergyDrain.\n"
          "@note Setting this to zero will disable any energy drain.\n"
          "@see minSprintEnergy\n");
-      addField( "minSprintEnergy", TypeF32, Offset(minSprintEnergy, PlayerData),
+      addFieldV( "minSprintEnergy", TypeRangedF32, Offset(minSprintEnergy, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum energy level required to sprint.\n\n"
          "@see sprintEnergyDrain\n");
 
-      addField( "maxSprintForwardSpeed", TypeF32, Offset(maxSprintForwardSpeed, PlayerData),
+      addFieldV( "maxSprintForwardSpeed", TypeRangedF32, Offset(maxSprintForwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum forward speed when sprinting." );
-      addField( "maxSprintBackwardSpeed", TypeF32, Offset(maxSprintBackwardSpeed, PlayerData),
+      addFieldV( "maxSprintBackwardSpeed", TypeRangedF32, Offset(maxSprintBackwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum backward speed when sprinting." );
-      addField( "maxSprintSideSpeed", TypeF32, Offset(maxSprintSideSpeed, PlayerData),
+      addFieldV( "maxSprintSideSpeed", TypeRangedF32, Offset(maxSprintSideSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum sideways speed when sprinting." );
 
-      addField( "sprintStrafeScale", TypeF32, Offset(sprintStrafeScale, PlayerData),
+      addFieldV( "sprintStrafeScale", TypeRangedF32, Offset(sprintStrafeScale, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Amount to scale strafing motion vector while sprinting." );
-      addField( "sprintYawScale", TypeF32, Offset(sprintYawScale, PlayerData),
+      addFieldV( "sprintYawScale", TypeRangedF32, Offset(sprintYawScale, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Amount to scale yaw motion while sprinting." );
-      addField( "sprintPitchScale", TypeF32, Offset(sprintPitchScale, PlayerData),
+      addFieldV( "sprintPitchScale", TypeRangedF32, Offset(sprintPitchScale, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Amount to scale pitch motion while sprinting." );
 
       addField( "sprintCanJump", TypeBool, Offset(sprintCanJump, PlayerData),
@@ -883,82 +884,82 @@ void PlayerData::initPersistFields()
 
    addGroup( "Movement: Swimming" );
 
-      addField( "swimForce", TypeF32, Offset(swimForce, PlayerData),
+      addFieldV( "swimForce", TypeRangedF32, Offset(swimForce, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Force used to accelerate the player when swimming.\n\n" );
-      addField( "maxUnderwaterForwardSpeed", TypeF32, Offset(maxUnderwaterForwardSpeed, PlayerData),
+      addFieldV( "maxUnderwaterForwardSpeed", TypeRangedF32, Offset(maxUnderwaterForwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum forward speed when underwater.\n\n" );
-      addField( "maxUnderwaterBackwardSpeed", TypeF32, Offset(maxUnderwaterBackwardSpeed, PlayerData),
+      addFieldV( "maxUnderwaterBackwardSpeed", TypeRangedF32, Offset(maxUnderwaterBackwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum backward speed when underwater.\n\n" );
-      addField( "maxUnderwaterSideSpeed", TypeF32, Offset(maxUnderwaterSideSpeed, PlayerData),
+      addFieldV( "maxUnderwaterSideSpeed", TypeRangedF32, Offset(maxUnderwaterSideSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum sideways speed when underwater.\n\n" );
 
    endGroup( "Movement: Swimming" );
 
    addGroup( "Movement: Crouching" );
 
-      addField( "crouchForce", TypeF32, Offset(crouchForce, PlayerData),
+      addFieldV( "crouchForce", TypeRangedF32, Offset(crouchForce, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Force used to accelerate the player when crouching.\n\n" );
-      addField( "maxCrouchForwardSpeed", TypeF32, Offset(maxCrouchForwardSpeed, PlayerData),
+      addFieldV( "maxCrouchForwardSpeed", TypeRangedF32, Offset(maxCrouchForwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum forward speed when crouching.\n\n" );
-      addField( "maxCrouchBackwardSpeed", TypeF32, Offset(maxCrouchBackwardSpeed, PlayerData),
+      addFieldV( "maxCrouchBackwardSpeed", TypeRangedF32, Offset(maxCrouchBackwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum backward speed when crouching.\n\n" );
-      addField( "maxCrouchSideSpeed", TypeF32, Offset(maxCrouchSideSpeed, PlayerData),
+      addFieldV( "maxCrouchSideSpeed", TypeRangedF32, Offset(maxCrouchSideSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum sideways speed when crouching.\n\n" );
 
    endGroup( "Movement: Crouching" );
 
    addGroup( "Movement: Prone" );
 
-      addField( "proneForce", TypeF32, Offset(proneForce, PlayerData),
+      addFieldV( "proneForce", TypeRangedF32, Offset(proneForce, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Force used to accelerate the player when prone (laying down).\n\n" );
-      addField( "maxProneForwardSpeed", TypeF32, Offset(maxProneForwardSpeed, PlayerData),
+      addFieldV( "maxProneForwardSpeed", TypeRangedF32, Offset(maxProneForwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum forward speed when prone (laying down).\n\n" );
-      addField( "maxProneBackwardSpeed", TypeF32, Offset(maxProneBackwardSpeed, PlayerData),
+      addFieldV( "maxProneBackwardSpeed", TypeRangedF32, Offset(maxProneBackwardSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum backward speed when prone (laying down).\n\n" );
-      addField( "maxProneSideSpeed", TypeF32, Offset(maxProneSideSpeed, PlayerData),
+      addFieldV( "maxProneSideSpeed", TypeRangedF32, Offset(maxProneSideSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum sideways speed when prone (laying down).\n\n" );
 
    endGroup( "Movement: Prone" );
 
    addGroup( "Movement: Jetting" );
 
-      addField( "jetJumpForce", TypeF32, Offset(jetJumpForce, PlayerData),
+      addFieldV( "jetJumpForce", TypeRangedF32, Offset(jetJumpForce, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Force used to accelerate the player when a jet jump is initiated.\n\n" );
 
-      addField( "jetJumpEnergyDrain", TypeF32, Offset(jetJumpEnergyDrain, PlayerData),
+      addFieldV( "jetJumpEnergyDrain", TypeRangedF32, Offset(jetJumpEnergyDrain, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Energy level drained each time the player jet jumps.\n\n"
          "@note Setting this to zero will disable any energy drain\n"
          "@see jetMinJumpEnergy\n");
-      addField( "jetMinJumpEnergy", TypeF32, Offset(jetMinJumpEnergy, PlayerData),
+      addFieldV( "jetMinJumpEnergy", TypeRangedF32, Offset(jetMinJumpEnergy, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum energy level required to jet jump.\n\n"
          "@see jetJumpEnergyDrain\n");
 
-      addField( "jetMinJumpSpeed", TypeF32, Offset(jetMinJumpSpeed, PlayerData),
+      addFieldV( "jetMinJumpSpeed", TypeRangedF32, Offset(jetMinJumpSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum speed needed to jet jump.\n\n"
          "If the player's own z velocity is greater than this, then it is used to scale "
          "the jet jump speed, up to jetMaxJumpSpeed.\n"
          "@see jetMaxJumpSpeed\n");
-      addField( "jetMaxJumpSpeed", TypeF32, Offset(jetMaxJumpSpeed, PlayerData),
+      addFieldV( "jetMaxJumpSpeed", TypeRangedF32, Offset(jetMaxJumpSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum vertical speed before the player can no longer jet jump.\n\n" );
-      addField( "jetJumpSurfaceAngle", TypeF32, Offset(jetJumpSurfaceAngle, PlayerData),
+      addFieldV( "jetJumpSurfaceAngle", TypeRangedF32, Offset(jetJumpSurfaceAngle, PlayerData), &CommonValidators::PosDegreeRangeQuarter,
          "@brief Angle from vertical (in degrees) where the player can jet jump.\n\n" );
 
    endGroup( "Movement: Jetting" );
 
    addGroup( "Falling" );
 
-      addField( "fallingSpeedThreshold", TypeF32, Offset(fallingSpeedThreshold, PlayerData),
+      addFieldV( "fallingSpeedThreshold", TypeRangedF32, Offset(fallingSpeedThreshold, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Downward speed at which we consider the player falling.\n\n" );
 
-      addField( "recoverDelay", TypeS32, Offset(recoverDelay, PlayerData),
+      addFieldV( "recoverDelay", TypeRangedS32, Offset(recoverDelay, PlayerData), &CommonValidators::PositiveInt,
          "@brief Number of ticks for the player to recover from falling.\n\n" );
 
-      addField( "recoverRunForceScale", TypeF32, Offset(recoverRunForceScale, PlayerData),
+      addFieldV( "recoverRunForceScale", TypeRangedF32, Offset(recoverRunForceScale, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Scale factor applied to runForce while in the recover state.\n\n"
          "This can be used to temporarily slow the player's movement after a fall, or "
          "prevent the player from moving at all if set to zero.\n" );
 
-      addField( "landSequenceTime", TypeF32, Offset(landSequenceTime, PlayerData),
+      addFieldV( "landSequenceTime", TypeRangedF32, Offset(landSequenceTime, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Time of land sequence play back when using new recover system.\n\n"
          "If greater than 0 then the legacy fall recovery system will be bypassed "
          "in favour of just playing the player's land sequence.  The time to "
@@ -988,27 +989,27 @@ void PlayerData::initPersistFields()
          "@brief Collision bounding box used when the player is swimming.\n\n"
          "@see boundingBox" );
 
-      addField( "boxHeadPercentage", TypeF32, Offset(boxHeadPercentage, PlayerData),
+      addFieldV( "boxHeadPercentage", TypeRangedF32, Offset(boxHeadPercentage, PlayerData), &CommonValidators::NormalizedFloat,
          "@brief Percentage of the player's bounding box height that represents the head.\n\n"
          "Used when computing the damage location.\n"
          "@see Player::getDamageLocation" );
-      addField( "boxTorsoPercentage", TypeF32, Offset(boxTorsoPercentage, PlayerData),
+      addFieldV( "boxTorsoPercentage", TypeRangedF32, Offset(boxTorsoPercentage, PlayerData), &CommonValidators::NormalizedFloat,
          "@brief Percentage of the player's bounding box height that represents the torso.\n\n"
          "Used when computing the damage location.\n"
          "@see Player::getDamageLocation" );
-      addField( "boxHeadLeftPercentage", TypeF32, Offset(boxHeadLeftPercentage, PlayerData),
+      addFieldV( "boxHeadLeftPercentage", TypeRangedF32, Offset(boxHeadLeftPercentage, PlayerData), &CommonValidators::NormalizedFloat,
          "@brief Percentage of the player's bounding box width that represents the left side of the head.\n\n"
          "Used when computing the damage location.\n"
          "@see Player::getDamageLocation" );
-      addField( "boxHeadRightPercentage", TypeF32, Offset(boxHeadRightPercentage, PlayerData),
+      addFieldV( "boxHeadRightPercentage", TypeRangedF32, Offset(boxHeadRightPercentage, PlayerData), &CommonValidators::NormalizedFloat,
          "@brief Percentage of the player's bounding box width that represents the right side of the head.\n\n"
          "Used when computing the damage location.\n"
          "@see Player::getDamageLocation" );
-      addField( "boxHeadBackPercentage", TypeF32, Offset(boxHeadBackPercentage, PlayerData),
+      addFieldV( "boxHeadBackPercentage", TypeRangedF32, Offset(boxHeadBackPercentage, PlayerData), &CommonValidators::NormalizedFloat,
          "@brief Percentage of the player's bounding box depth that represents the back side of the head.\n\n"
          "Used when computing the damage location.\n"
          "@see Player::getDamageLocation" );
-      addField( "boxHeadFrontPercentage", TypeF32, Offset(boxHeadFrontPercentage, PlayerData),
+      addFieldV( "boxHeadFrontPercentage", TypeRangedF32, Offset(boxHeadFrontPercentage, PlayerData), &CommonValidators::NormalizedFloat,
          "@brief Percentage of the player's bounding box depth that represents the front side of the head.\n\n"
          "Used when computing the damage location.\n"
          "@see Player::getDamageLocation" );
@@ -1022,12 +1023,12 @@ void PlayerData::initPersistFields()
          "walks along the ground).\n\n"
          "@note The generation of foot puffs requires the appropriate triggeres to be defined in the "
          "player's animation sequences.  Without these, no foot puffs will be generated.\n");
-      addField( "footPuffNumParts", TypeS32, Offset(footPuffNumParts, PlayerData),
+      addFieldV( "footPuffNumParts", TypeRangedS32, Offset(footPuffNumParts, PlayerData), &CommonValidators::PositiveInt,
          "@brief Number of footpuff particles to generate each step.\n\n"
          "Each foot puff is randomly placed within the defined foot puff radius.  This "
          "includes having footPuffNumParts set to one.\n"
          "@see footPuffRadius\n");
-      addField( "footPuffRadius", TypeF32, Offset(footPuffRadius, PlayerData),
+      addFieldV( "footPuffRadius", TypeRangedF32, Offset(footPuffRadius, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Particle creation radius for footpuff particles.\n\n"
          "This is applied to each foot puff particle, even if footPuffNumParts is set to one.  So "
          "set this value to zero if you want a single foot puff placed at exactly the same location "
@@ -1038,7 +1039,7 @@ void PlayerData::initPersistFields()
 
       addField( "decalData", TYPEID< DecalData >(), Offset(decalData, PlayerData),
          "@brief Decal to place on the ground for player footsteps.\n\n" );
-      addField( "decalOffset",TypeF32, Offset(decalOffset, PlayerData),
+      addFieldV( "decalOffset", TypeRangedF32, Offset(decalOffset, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Distance from the center of the model to the right foot.\n\n"
          "While this defines the distance to the right foot, it is also used to place "
          "the left foot decal as well.  Just on the opposite side of the player." );
@@ -1054,37 +1055,37 @@ void PlayerData::initPersistFields()
       addField( "splash", TYPEID< SplashData >(), Offset(splash, PlayerData),
          "@brief SplashData datablock used to create splashes when the player moves "
          "through water.\n\n" );
-      addField( "splashVelocity", TypeF32, Offset(splashVelocity, PlayerData),
+      addFieldV( "splashVelocity", TypeRangedF32, Offset(splashVelocity, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum velocity when moving through water to generate splashes.\n\n" );
-      addField( "splashAngle", TypeF32, Offset(splashAngle, PlayerData),
+      addFieldV( "splashAngle", TypeRangedF32, Offset(splashAngle, PlayerData), &CommonValidators::PosDegreeRange,
          "@brief Maximum angle (in degrees) from pure vertical movement in water to "
          "generate splashes.\n\n" );
 
-      addField( "splashFreqMod", TypeF32, Offset(splashFreqMod, PlayerData),
+      addFieldV( "splashFreqMod", TypeRangedF32, Offset(splashFreqMod, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Multipled by speed to determine the number of splash particles to generate.\n\n" );
-      addField( "splashVelEpsilon", TypeF32, Offset(splashVelEpsilon, PlayerData),
+      addFieldV( "splashVelEpsilon", TypeRangedF32, Offset(splashVelEpsilon, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum speed to generate splash particles.\n\n" );
-      addField( "bubbleEmitTime", TypeF32, Offset(bubbleEmitTime, PlayerData),
+      addFieldV( "bubbleEmitTime", TypeRangedF32, Offset(bubbleEmitTime, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Time in seconds to generate bubble particles after entering the water.\n\n" );
       addField( "splashEmitter", TYPEID< ParticleEmitterData >(), Offset(splashEmitterList, PlayerData), NUM_SPLASH_EMITTERS,
          "@brief Particle emitters used to generate splash particles.\n\n" );
 
-      addField( "footstepSplashHeight", TypeF32, Offset(footSplashHeight, PlayerData),
+      addFieldV( "footstepSplashHeight", TypeRangedF32, Offset(footSplashHeight, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Water coverage level to choose between FootShallowSound and FootWadingSound.\n\n"
          "@see FootShallowSound\n"
          "@see FootWadingSound\n");
 
-      addField( "mediumSplashSoundVelocity", TypeF32, Offset(medSplashSoundVel, PlayerData),
+      addFieldV( "mediumSplashSoundVelocity", TypeRangedF32, Offset(medSplashSoundVel, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum velocity when entering the water for choosing between the impactWaterEasy and "
          "impactWaterMedium sounds to play.\n\n"
          "@see impactWaterEasy\n"
          "@see impactWaterMedium\n" );
-      addField( "hardSplashSoundVelocity", TypeF32, Offset(hardSplashSoundVel, PlayerData),
+      addFieldV( "hardSplashSoundVelocity", TypeRangedF32, Offset(hardSplashSoundVel, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum velocity when entering the water for choosing between the impactWaterMedium and "
          "impactWaterHard sound to play.\n\n"
          "@see impactWaterMedium\n"
          "@see impactWaterHard\n" );
-      addField( "exitSplashSoundVelocity", TypeF32, Offset(exitSplashSoundVel, PlayerData),
+      addFieldV( "exitSplashSoundVelocity", TypeRangedF32, Offset(exitSplashSoundVel, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum velocity when leaving the water for the exitingWater sound to "
          "play.\n\n"
          "@see exitingWater");
@@ -1093,7 +1094,7 @@ void PlayerData::initPersistFields()
 
    addGroup( "Interaction: Ground Impact" );
 
-      addField( "groundImpactMinSpeed", TypeF32, Offset(groundImpactMinSpeed, PlayerData),
+      addFieldV( "groundImpactMinSpeed", TypeRangedF32, Offset(groundImpactMinSpeed, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Minimum falling impact speed to apply damage and initiate the camera "
          "shaking effect.\n\n" );
       addField( "groundImpactShakeFreq", TypePoint3F, Offset(groundImpactShakeFreq, PlayerData),
@@ -1102,10 +1103,10 @@ void PlayerData::initPersistFields()
       addField( "groundImpactShakeAmp", TypePoint3F, Offset(groundImpactShakeAmp, PlayerData),
          "@brief Amplitude of the camera shake effect after falling.\n\n"
          "This is how much to shake the camera.\n");
-      addField( "groundImpactShakeDuration", TypeF32, Offset(groundImpactShakeDuration, PlayerData),
+      addFieldV( "groundImpactShakeDuration", TypeRangedF32, Offset(groundImpactShakeDuration, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Duration (in seconds) of the camera shake effect after falling.\n\n"
          "This is how long to shake the camera.\n");
-      addField( "groundImpactShakeFalloff", TypeF32, Offset(groundImpactShakeFalloff, PlayerData),
+      addFieldV( "groundImpactShakeFalloff", TypeRangedF32, Offset(groundImpactShakeFalloff, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Falloff factor of the camera shake effect after falling.\n\n"
          "This is how to fade the camera shake over the duration.\n");
 

+ 1 - 1
Engine/source/T3D/pointLight.cpp

@@ -102,7 +102,7 @@ void PointLight::initPersistFields()
    docsURL;
    addGroup( "Light" );
 
-      addField( "radius", TypeF32, Offset( mRadius, PointLight ), "Controls the falloff of the light emission" );
+      addFieldV( "radius", TypeRangedF32, Offset( mRadius, PointLight ), &CommonValidators::PositiveFloat, "Controls the falloff of the light emission" );
 
    endGroup( "Light" );
 

+ 9 - 9
Engine/source/T3D/projectile.cpp

@@ -273,42 +273,42 @@ void ProjectileData::initPersistFields()
    endGroup("Light Emitter");   
 
    addGroup("Physics");
-      addProtectedField("lifetime", TypeS32, Offset(lifetime, ProjectileData), &setLifetime, &getScaledValue,
+      addProtectedFieldV("lifetime", TypeRangedS32, Offset(lifetime, ProjectileData), &setLifetime, &getScaledValue, &CommonValidators::NaturalNumber,
          "@brief Amount of time, in milliseconds, before the projectile is removed from the simulation.\n\n"
          "Used with fadeDelay to determine the transparency of the projectile at a given time. "
          "A projectile may exist up to a maximum of 131040ms (or 4095 ticks) as defined by Projectile::MaxLivingTicks in the source code."
          "@see fadeDelay");
-      addProtectedField("armingDelay", TypeS32, Offset(armingDelay, ProjectileData), &setArmingDelay, &getScaledValue,
+      addProtectedFieldV("armingDelay", TypeRangedS32, Offset(armingDelay, ProjectileData), &setArmingDelay, &getScaledValue, &CommonValidators::PositiveInt,
          "@brief Amount of time, in milliseconds, before the projectile will cause damage or explode on impact.\n\n"
          "This value must be equal to or less than the projectile's lifetime.\n\n"
          "@see lifetime");
-      addProtectedField("fadeDelay", TypeS32, Offset(fadeDelay, ProjectileData), &setFadeDelay, &getScaledValue,
+      addProtectedFieldV("fadeDelay", TypeRangedS32, Offset(fadeDelay, ProjectileData), &setFadeDelay, &getScaledValue, &CommonValidators::NaturalNumber,
          "@brief Amount of time, in milliseconds, before the projectile begins to fade out.\n\n"
          "This value must be smaller than the projectile's lifetime to have an affect.");
       addField("isBallistic", TypeBool, Offset(isBallistic, ProjectileData),
          "@brief Detetmines if the projectile should be affected by gravity and whether or not "
          "it bounces before exploding.\n\n");
-      addField("velInheritFactor", TypeF32, Offset(velInheritFactor, ProjectileData),
+      addFieldV("velInheritFactor", TypeRangedF32, Offset(velInheritFactor, ProjectileData), &CommonValidators::F32Range,
          "@brief Amount of velocity the projectile recieves from the source that created it.\n\n"
          "Use an amount between 0 and 1 for the best effect. "
          "This value is never modified by the engine.\n"
          "@note This value by default is not transmitted between the server and the client.");
-      addField("muzzleVelocity", TypeF32, Offset(muzzleVelocity, ProjectileData),
+      addFieldV("muzzleVelocity", TypeRangedF32, Offset(muzzleVelocity, ProjectileData), &CommonValidators::PositiveFloat,
          "@brief Amount of velocity the projectile recieves from the \"muzzle\" of the gun.\n\n"
          "Used with velInheritFactor to determine the initial velocity of the projectile. "
          "This value is never modified by the engine.\n\n"
          "@note This value by default is not transmitted between the server and the client.\n\n"
          "@see velInheritFactor");
-      addField("impactForce", TypeF32, Offset(impactForce, ProjectileData));
-      addField("bounceElasticity", TypeF32, Offset(bounceElasticity, ProjectileData),
+      addFieldV("impactForce", TypeRangedF32, Offset(impactForce, ProjectileData), &CommonValidators::PositiveFloat);
+      addFieldV("bounceElasticity", TypeRangedF32, Offset(bounceElasticity, ProjectileData), &CommonValidators::PositiveFloat,
          "@brief Influences post-bounce velocity of a projectile that does not explode on contact.\n\n"
          "Scales the velocity from a bounce after friction is taken into account. "
          "A value of 1.0 will leave it's velocity unchanged while values greater than 1.0 will increase it.\n");
-      addField("bounceFriction", TypeF32, Offset(bounceFriction, ProjectileData),
+      addFieldV("bounceFriction", TypeRangedF32, Offset(bounceFriction, ProjectileData), &CommonValidators::PositiveFloat,
          "@brief Factor to reduce post-bounce velocity of a projectile that does not explode on contact.\n\n"
          "Reduces bounce velocity by this factor and a multiple of the tangent to impact. "
          "Used to simulate surface friction.\n");
-      addField("gravityMod", TypeF32, Offset(gravityMod, ProjectileData),
+      addFieldV("gravityMod", TypeRangedF32, Offset(gravityMod, ProjectileData), &CommonValidators::F32Range,
          "@brief Scales the influence of gravity on the projectile.\n\n"
          "The larger this value is, the more that gravity will affect the projectile. "
          "A value of 1.0 will assume \"normal\" influence upon it.\n"

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

@@ -96,12 +96,12 @@ void ProximityMineData::initPersistFields()
    endGroup("Sounds");
 
    addGroup( "Arming" );
-   addField( "armingDelay", TypeF32, Offset(armingDelay, ProximityMineData), 
+   addFieldV( "armingDelay", TypeRangedF32, Offset(armingDelay, ProximityMineData), &CommonValidators::PositiveFloat,
       "Delay (in seconds) from when the mine is placed to when it becomes active." );
    endGroup( "Arming" );
 
    addGroup( "Triggering" );
-   addField( "autoTriggerDelay", TypeF32, Offset(autoTriggerDelay, ProximityMineData),
+   addFieldV( "autoTriggerDelay", TypeRangedF32, Offset(autoTriggerDelay, ProximityMineData), &CommonValidators::PositiveFloat,
       "@brief Delay (in seconds) from arming until the mine automatically "
       "triggers and explodes, even if no object has entered the trigger area.\n\n"
       "Set to 0 to disable." );
@@ -109,16 +109,16 @@ void ProximityMineData::initPersistFields()
       "@brief Controls whether the mine can be triggered by the object that owns it.\n\n"
       "For example, a player could deploy mines that are only dangerous to other "
       "players and not himself." );
-   addField( "triggerRadius", TypeF32, Offset(triggerRadius, ProximityMineData),
+   addFieldV( "triggerRadius", TypeRangedF32, Offset(triggerRadius, ProximityMineData), &CommonValidators::PositiveFloat,
       "Distance at which an activated mine will detect other objects and explode." );
-   addField( "triggerSpeed", TypeF32, Offset(triggerSpeed, ProximityMineData),
+   addFieldV( "triggerSpeed", TypeRangedF32, Offset(triggerSpeed, ProximityMineData), &CommonValidators::PositiveFloat,
       "Speed above which moving objects within the trigger radius will trigger the mine" );
-   addField( "triggerDelay", TypeF32, Offset(triggerDelay, ProximityMineData),
+   addFieldV( "triggerDelay", TypeRangedF32, Offset(triggerDelay, ProximityMineData), &CommonValidators::PositiveFloat,
       "Delay (in seconds) from when the mine is triggered until it explodes." );
    endGroup( "Triggering" );
 
    addGroup( "Explosion" );
-   addField( "explosionOffset", TypeF32, Offset(explosionOffset, ProximityMineData),
+   addFieldV( "explosionOffset", TypeRangedF32, Offset(explosionOffset, ProximityMineData), &CommonValidators::F32Range,
       "@brief Offset from the mine's origin where the explosion emanates from."
       "Sometimes a thrown mine may be slightly sunk into the ground.  This can be just "
       "enough to cause the explosion to occur under the ground, especially on flat "

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

@@ -517,12 +517,12 @@ void RigidShapeData::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");
+      addFieldV("triggerDustHeight", TypeRangedF32,                      Offset(triggerDustHeight,  RigidShapeData), &CommonValidators::PositiveFloat, "Maximum height from the ground at which the object will generate dust.\n");
+      addFieldV("dustHeight", TypeRangedF32,                      Offset(dustHeight,         RigidShapeData), &CommonValidators::PositiveFloat, "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");  
+      addFieldV("splashFreqMod", TypeRangedF32,                Offset(splashFreqMod,   RigidShapeData), &CommonValidators::PositiveFloat, "The simulated frequency modulation of a splash generated by this object. Multiplied along with speed and time elapsed when determining splash emition rate.\n");
+      addFieldV("splashVelEpsilon", TypeRangedF32,              Offset(splashVelEpsilon, RigidShapeData), &CommonValidators::PositiveFloat, "The threshold speed at which we consider the object's movement to have stopped when updating splash effects.\n");
    endGroup( "Particle Effects" );
    
    addGroup( "Sounds" );
@@ -534,34 +534,34 @@ void RigidShapeData::initPersistFields()
          "@brief Creates a representation of the object in the physics plugin.\n");
       addField("massCenter", TypePoint3F, Offset(massCenter, RigidShapeData), "Center of mass for rigid body.");
       addField("massBox", TypePoint3F, Offset(massBox, RigidShapeData), "Size of inertial box.");
-      addField("bodyRestitution", TypeF32, Offset(body.restitution, RigidShapeData), "The percentage of kinetic energy kept by this object in a collision.");
-      addField("bodyFriction", TypeF32, Offset(body.friction, RigidShapeData), "How much friction this object has. Lower values will cause the object to appear to be more slippery.");
-      addField("maxDrag", TypeF32, Offset(maxDrag, RigidShapeData), "Maximum drag available to this object.");
-      addField("minDrag", TypeF32, Offset(minDrag, RigidShapeData), "Minimum drag available to this object.");
-      addField("integration", TypeS32, Offset(integration, RigidShapeData), "Number of physics steps to process per tick.");
-      addField("collisionTol", TypeF32, Offset(collisionTol, RigidShapeData), "Collision distance tolerance.");
-      addField("contactTol", TypeF32, Offset(contactTol, RigidShapeData), "Contact velocity tolerance.");
-      addField("dragForce",            TypeF32, Offset(dragForce,            RigidShapeData), "Used to simulate the constant drag acting on the object");
-      addField("vertFactor",           TypeF32, Offset(vertFactor,           RigidShapeData), "The scalar applied to the vertical portion of the velocity drag acting on a object.");
+      addFieldV("bodyRestitution", TypeRangedF32, Offset(body.restitution, RigidShapeData), &CommonValidators::PositiveFloat, "The percentage of kinetic energy kept by this object in a collision.");
+      addFieldV("bodyFriction", TypeRangedF32, Offset(body.friction, RigidShapeData), &CommonValidators::PositiveFloat, "How much friction this object has. Lower values will cause the object to appear to be more slippery.");
+      addFieldV("maxDrag", TypeRangedF32, Offset(maxDrag, RigidShapeData), &CommonValidators::PositiveFloat, "Maximum drag available to this object.");
+      addFieldV("minDrag", TypeRangedF32, Offset(minDrag, RigidShapeData), &CommonValidators::PositiveFloat, "Minimum drag available to this object.");
+      addFieldV("integration", TypeRangedS32, Offset(integration, RigidShapeData), &CommonValidators::NaturalNumber, "Number of physics steps to process per tick.");
+      addFieldV("collisionTol", TypeRangedF32, Offset(collisionTol, RigidShapeData), &CommonValidators::PositiveFloat, "Collision distance tolerance.");
+      addFieldV("contactTol", TypeRangedF32, Offset(contactTol, RigidShapeData), &CommonValidators::PositiveFloat, "Contact velocity tolerance.");
+      addFieldV("dragForce", TypeRangedF32, Offset(dragForce,            RigidShapeData), &CommonValidators::PositiveFloat, "Used to simulate the constant drag acting on the object");
+      addFieldV("vertFactor", TypeRangedF32, Offset(vertFactor,           RigidShapeData), &CommonValidators::PositiveFloat, "The scalar applied to the vertical portion of the velocity drag acting on a object.");
    endGroup("Physics");
 
    addGroup("Collision");
-      addField("minImpactSpeed", TypeF32, Offset(minImpactSpeed, RigidShapeData),
+      addFieldV("minImpactSpeed", TypeRangedF32, Offset(minImpactSpeed, RigidShapeData), &CommonValidators::PositiveFloat,
       "Minimum collision speed to classify collision as impact (triggers onImpact on server object)." );
-      addField("softImpactSpeed", TypeF32, Offset(softImpactSpeed, RigidShapeData), "Minimum speed at which this object must be travelling for the soft impact sound to be played.");
-      addField("hardImpactSpeed", TypeF32, Offset(hardImpactSpeed, RigidShapeData), "Minimum speed at which the object must be travelling for the hard impact sound to be played.");
-      addField("minRollSpeed", TypeF32, Offset(minRollSpeed, RigidShapeData));
-      addField("exitSplashSoundVelocity", TypeF32,       Offset(exitSplashSoundVel, RigidShapeData), "The minimum velocity at which the exit splash sound will be played when emerging from 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("hardSplashSoundVelocity", TypeF32,       Offset(hardSplashSoundVel, RigidShapeData), "The minimum velocity at which the hard splash sound will be played when impacting water.\n");
+      addFieldV("softImpactSpeed", TypeRangedF32, Offset(softImpactSpeed, RigidShapeData), &CommonValidators::PositiveFloat, "Minimum speed at which this object must be travelling for the soft impact sound to be played.");
+      addFieldV("hardImpactSpeed", TypeRangedF32, Offset(hardImpactSpeed, RigidShapeData), &CommonValidators::PositiveFloat, "Minimum speed at which the object must be travelling for the hard impact sound to be played.");
+      addFieldV("minRollSpeed", TypeRangedF32, Offset(minRollSpeed, RigidShapeData), &CommonValidators::PositiveFloat);
+      addFieldV("exitSplashSoundVelocity", TypeRangedF32,       Offset(exitSplashSoundVel, RigidShapeData), &CommonValidators::PositiveFloat, "The minimum velocity at which the exit splash sound will be played when emerging from water.\n");
+      addFieldV("softSplashSoundVelocity", TypeRangedF32,       Offset(softSplashSoundVel, RigidShapeData), &CommonValidators::PositiveFloat,"The minimum velocity at which the soft splash sound will be played when impacting water.\n");
+      addFieldV("mediumSplashSoundVelocity", TypeRangedF32,     Offset(medSplashSoundVel, RigidShapeData), &CommonValidators::PositiveFloat, "The minimum velocity at which the medium splash sound will be played when impacting water.\n");
+      addFieldV("hardSplashSoundVelocity", TypeRangedF32,       Offset(hardSplashSoundVel, RigidShapeData), &CommonValidators::PositiveFloat, "The minimum velocity at which the hard splash sound will be played when impacting water.\n");
    endGroup("Collision");   
    
    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("cameraLag",      TypeF32,        Offset(cameraLag,      RigidShapeData), "Scalar amount by which the third person camera lags the object, relative to the object's linear velocity.\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");
+      addFieldV("cameraLag", TypeRangedF32,        Offset(cameraLag,      RigidShapeData), &CommonValidators::PositiveFloat, "Scalar amount by which the third person camera lags the object, relative to the object's linear velocity.\n");
+      addFieldV("cameraDecay", TypeRangedF32,        Offset(cameraDecay,  RigidShapeData), &CommonValidators::PositiveFloat, "Scalar rate at which the third person camera offset decays, per tick.\n");
+      addFieldV("cameraOffset", TypeRangedF32,        Offset(cameraOffset,   RigidShapeData), &CommonValidators::PositiveFloat, "The vertical offset of the object's camera.\n");
    endGroup( "Camera" );
 }   
 

+ 9 - 9
Engine/source/T3D/sfx/sfxEmitter.cpp

@@ -327,19 +327,19 @@ void SFXEmitter::initPersistFields()
          "The SFXSource to which to assign the sound of this emitter as a child.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::sourceGroup" );
-      addField( "volume",              TypeF32,       Offset( mDescription.mVolume, SFXEmitter ),
+      addFieldV( "volume", TypeRangedF32,       Offset( mDescription.mVolume, SFXEmitter ), &CommonValidators::PositiveFloat,
          "Volume level to apply to the sound.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::volume" );
-      addField( "pitch",               TypeF32,       Offset( mDescription.mPitch, SFXEmitter ),
+      addFieldV( "pitch", TypeRangedF32,       Offset( mDescription.mPitch, SFXEmitter ), &CommonValidators::PositiveFloat,
          "Pitch shift to apply to the sound.  Default is 1 = play at normal speed.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::pitch" );
-      addField( "fadeInTime",          TypeF32,       Offset( mDescription.mFadeInTime, SFXEmitter ),
+      addFieldV( "fadeInTime", TypeRangedF32,       Offset( mDescription.mFadeInTime, SFXEmitter ), &CommonValidators::PositiveFloat,
          "Number of seconds to gradually fade in volume from zero when playback starts.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::fadeInTime" );
-      addField( "fadeOutTime",         TypeF32,       Offset( mDescription.mFadeOutTime, SFXEmitter ),
+      addFieldV( "fadeOutTime", TypeRangedF32,       Offset( mDescription.mFadeOutTime, SFXEmitter ), &CommonValidators::PositiveFloat,
          "Number of seconds to gradually fade out volume down to zero when playback is stopped or paused.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::fadeOutTime" );
@@ -352,11 +352,11 @@ void SFXEmitter::initPersistFields()
          "Whether to play #fileName as a positional (3D) sound or not.\n"
          "If a #track is assigned, the value of this field is ignored.\n\n"
          "@see SFXDescription::is3D" );
-      addField( "referenceDistance",   TypeF32,       Offset( mDescription.mMinDistance, SFXEmitter ),
+      addFieldV( "referenceDistance", TypeRangedF32,       Offset( mDescription.mMinDistance, SFXEmitter ), &CommonValidators::PositiveFloat,
          "Distance at which to start volume attenuation of the 3D sound.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::referenceDistance" );
-      addField( "maxDistance",         TypeF32,       Offset( mDescription.mMaxDistance, SFXEmitter ),
+      addFieldV( "maxDistance", TypeRangedF32,       Offset( mDescription.mMaxDistance, SFXEmitter ), &CommonValidators::PositiveFloat,
          "Distance at which to stop volume attenuation of the 3D sound.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::maxDistance" );
@@ -364,15 +364,15 @@ void SFXEmitter::initPersistFields()
          "Bounds on random offset to apply to initial 3D sound position.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::scatterDistance" );
-      addField( "coneInsideAngle",     TypeS32,       Offset( mDescription.mConeInsideAngle, SFXEmitter ),
+      addFieldV( "coneInsideAngle",     TypeRangedS32,       Offset( mDescription.mConeInsideAngle, SFXEmitter ), &CommonValidators::S32_PosDegreeRange,
          "Angle of inner volume cone of 3D sound in degrees.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::coneInsideAngle" );
-      addField( "coneOutsideAngle",    TypeS32,       Offset( mDescription.mConeOutsideAngle, SFXEmitter ),
+      addFieldV( "coneOutsideAngle", TypeRangedS32,       Offset( mDescription.mConeOutsideAngle, SFXEmitter ), &CommonValidators::S32_PosDegreeRange,
          "Angle of outer volume cone of 3D sound in degrees\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::coneOutsideAngle" );
-      addField( "coneOutsideVolume",   TypeF32,       Offset( mDescription.mConeOutsideVolume, SFXEmitter ),
+      addFieldV( "coneOutsideVolume", TypeRangedF32,       Offset( mDescription.mConeOutsideVolume, SFXEmitter ), &CommonValidators::NormalizedFloat,
          "Volume scale factor of outside of outer volume 3D sound cone.\n"
          "@note This field is ignored if #useTrackDescriptionOnly is true.\n\n"
          "@see SFXDescription::coneOutsideVolume" );

+ 15 - 14
Engine/source/T3D/shapeBase.cpp

@@ -557,26 +557,26 @@ void ShapeBaseData::initPersistFields()
    endGroup("Particle Effects");
 
    addGroup( "Physics" );   
-      addProtectedField("mass", TypeF32, Offset(mass, ShapeBaseData), &_setMass, &defaultProtectedGetFn, "Shape mass.\nUsed in simulation of moving objects.\n"  );
-      addField( "drag", TypeF32, Offset(drag, ShapeBaseData),
+      addProtectedFieldV("mass", TypeRangedF32, Offset(mass, ShapeBaseData), &_setMass, &defaultProtectedGetFn, &CommonValidators::PositiveFloat, "Shape mass.\nUsed in simulation of moving objects.\n"  );
+      addFieldV( "drag", TypeRangedF32, Offset(drag, ShapeBaseData), &CommonValidators::PositiveNonZeroFloat,
          "Drag factor.\nReduces velocity of moving objects." );
-      addField( "density", TypeF32, Offset(density, ShapeBaseData),
+      addFieldV( "density", TypeRangedF32, Offset(density, ShapeBaseData), &CommonValidators::PositiveNonZeroFloat,
          "Shape density.\nUsed when computing buoyancy when in water.\n" );
    endGroup( "Physics" );
 
    addGroup( "Damage/Energy" );
-      addField( "maxEnergy", TypeF32, Offset(maxEnergy, ShapeBaseData),
+      addFieldV( "maxEnergy", TypeRangedF32, Offset(maxEnergy, ShapeBaseData), &CommonValidators::PositiveFloat,
          "Maximum energy level for this object." );
-      addField( "maxDamage", TypeF32, Offset(maxDamage, ShapeBaseData),
+      addFieldV( "maxDamage", TypeRangedF32, Offset(maxDamage, ShapeBaseData), &CommonValidators::PositiveFloat,
          "Maximum damage level for this object." );
-      addField( "disabledLevel", TypeF32, Offset(disabledLevel, ShapeBaseData),
+      addFieldV( "disabledLevel", TypeRangedF32, Offset(disabledLevel, ShapeBaseData), &CommonValidators::PositiveFloat,
          "Damage level above which the object is disabled.\n"
          "Currently unused." );
-      addField( "destroyedLevel", TypeF32, Offset(destroyedLevel, ShapeBaseData),
+      addFieldV( "destroyedLevel", TypeRangedF32, Offset(destroyedLevel, ShapeBaseData), &CommonValidators::PositiveFloat,
          "Damage level above which the object is destroyed.\n"
          "When the damage level increases above this value, the object damage "
          "state is set to \"Destroyed\"." );
-      addField( "repairRate", TypeF32, Offset(repairRate, ShapeBaseData),
+      addFieldV( "repairRate", TypeRangedF32, Offset(repairRate, ShapeBaseData), &CommonValidators::PositiveFloat,
          "Rate at which damage is repaired in damage units/tick.\n"
          "This value is subtracted from the damage level until it reaches 0." );
       addField( "inheritEnergyFromMount", TypeBool, Offset(inheritEnergyFromMount, ShapeBaseData),
@@ -588,19 +588,19 @@ void ShapeBaseData::initPersistFields()
    endGroup( "Damage/Energy" );
 
    addGroup( "Camera", "The settings used by the shape when it is the camera." );
-      addField( "cameraMaxDist", TypeF32, Offset(cameraMaxDist, ShapeBaseData),
+      addFieldV( "cameraMaxDist", TypeRangedF32, Offset(cameraMaxDist, ShapeBaseData), &CommonValidators::PositiveFloat,
          "The maximum distance from the camera to the object.\n"
          "Used when computing a custom camera transform for this object.\n\n"
          "@see observeThroughObject" );
-      addField( "cameraMinDist", TypeF32, Offset(cameraMinDist, ShapeBaseData),
+      addFieldV( "cameraMinDist", TypeRangedF32, Offset(cameraMinDist, ShapeBaseData), &CommonValidators::PositiveFloat,
          "The minimum distance from the camera to the object.\n"
          "Used when computing a custom camera transform for this object.\n\n"
          "@see observeThroughObject" );
-      addField( "cameraDefaultFov", TypeF32, Offset(cameraDefaultFov, ShapeBaseData),
+      addFieldV( "cameraDefaultFov", TypeRangedF32, Offset(cameraDefaultFov, ShapeBaseData), &CommonValidators::PosDegreeRange,
          "The default camera vertical FOV in degrees." );
-      addField( "cameraMinFov", TypeF32, Offset(cameraMinFov, ShapeBaseData),
+      addFieldV( "cameraMinFov", TypeRangedF32, Offset(cameraMinFov, ShapeBaseData), &CommonValidators::PosDegreeRange,
          "The minimum camera vertical FOV allowed in degrees." );
-      addField( "cameraMaxFov", TypeF32, Offset(cameraMaxFov, ShapeBaseData),
+      addFieldV( "cameraMaxFov", TypeRangedF32, Offset(cameraMaxFov, ShapeBaseData), &CommonValidators::PosDegreeRange,
          "The maximum camera vertical FOV allowed in degrees." );
       addField( "cameraCanBank", TypeBool, Offset(cameraCanBank, ShapeBaseData),
          "If the derrived class supports it, allow the camera to bank." );
@@ -634,7 +634,7 @@ void ShapeBaseData::initPersistFields()
    onlyKeepClearSubstitutions("explosion");
    onlyKeepClearSubstitutions("underwaterExplosion");
    Parent::initPersistFields();
-
+   /*
    addGroup("BL Projected Shadows");
       addField("shadowSize", TypeS32, Offset(shadowSize, ShapeBaseData),
          "Size of the projected shadow texture (must be power of 2).");
@@ -647,6 +647,7 @@ void ShapeBaseData::initPersistFields()
          "Scalar applied to the radius of spot shadows (initial radius is based "
          "on the shape bounds but can be adjusted with this field).");
    endGroup("BL Projected Shadows");
+   */
 
 }
 

+ 26 - 26
Engine/source/T3D/shapeImage.cpp

@@ -623,7 +623,7 @@ S32 ShapeBaseImageData::lookupState(const char* name)
    Con::errorf(ConsoleLogEntry::General,"ShapeBaseImageData:: Could not resolve state \"%s\" for image \"%s\"",name,getName());
    return 0;
 }
-
+IRangeValidator mountRange(-1, SceneObject::NumMountPoints);
 void ShapeBaseImageData::initPersistFields()
 {
    docsURL;
@@ -636,10 +636,10 @@ void ShapeBaseImageData::initPersistFields()
       addField("shellExitDir", TypePoint3F, Offset(shellExitDir, ShapeBaseImageData),
          "@brief Vector direction to eject shell casings.\n\n"
          "@see casing");
-      addField("shellExitVariance", TypeF32, Offset(shellExitVariance, ShapeBaseImageData),
+      addFieldV("shellExitVariance", TypeRangedF32, Offset(shellExitVariance, ShapeBaseImageData), &CommonValidators::DegreeRange,
          "@brief Variance (in degrees) from the shellExitDir vector to eject casings.\n\n"
          "@see shellExitDir");
-      addField("shellVelocity", TypeF32, Offset(shellVelocity, ShapeBaseImageData),
+      addFieldV("shellVelocity", TypeRangedF32, Offset(shellVelocity, ShapeBaseImageData), &CommonValidators::PositiveFloat,
          "@brief Speed at which to eject casings.\n\n"
          "@see casing");
       addField("computeCRC", TypeBool, Offset(computeCRC, ShapeBaseImageData),
@@ -680,7 +680,7 @@ void ShapeBaseImageData::initPersistFields()
          "@note Setting this to true causes up to four animation threads to be advanced on the server "
          "for each instance in use, although for most images only one or two are actually defined.\n\n"
          "@see useEyeNode\n");
-      addField( "scriptAnimTransitionTime", TypeF32, Offset(scriptAnimTransitionTime, ShapeBaseImageData),
+      addFieldV( "scriptAnimTransitionTime", TypeRangedF32, Offset(scriptAnimTransitionTime, ShapeBaseImageData), &CommonValidators::PositiveFloat,
          "@brief The amount of time to transition between the previous sequence and new sequence when the script prefix has changed.\n\n"
          "When setImageScriptAnimPrefix() is used on a ShapeBase that has this image mounted, the image "
          "will attempt to switch to the new animation sequence based on the given script prefix.  This is "
@@ -697,12 +697,12 @@ void ShapeBaseImageData::initPersistFields()
    addField("usesEnergy", TypeBool, Offset(usesEnergy, ShapeBaseImageData),
       "@brief Flag indicating whether this Image uses energy instead of ammo.  The energy level comes from the ShapeBase object we're mounted to.\n\n"
       "@see ShapeBase::setEnergyLevel()");
-   addField("minEnergy", TypeF32, Offset(minEnergy, ShapeBaseImageData),
+   addFieldV("minEnergy", TypeRangedF32, Offset(minEnergy, ShapeBaseImageData), &CommonValidators::PositiveFloat,
       "@brief Minimum Image energy for it to be operable.\n\n"
       "@see usesEnergy");
 
    addGroup("Mounting");
-   addField( "mountPoint", TypeS32, Offset(mountPoint, ShapeBaseImageData),
+   addFieldV( "mountPoint", TypeRangedS32, Offset(mountPoint, ShapeBaseImageData), &mountRange,
       "@brief Mount node # to mount this Image to.\n\n"
       "This should correspond to a mount# node on the ShapeBase derived object we are mounting to." );
    addField( "offset", TypeMatrixPosition, Offset(mountOffset, ShapeBaseImageData),
@@ -753,12 +753,12 @@ void ShapeBaseImageData::initPersistFields()
       addField( "camShakeAmp", TypePoint3F, Offset(camShakeAmp, ShapeBaseImageData),
          "@brief Amplitude of the camera shaking effect.\n\n"
          "@see shakeCamera" );
-      addField( "camShakeDuration", TypeF32, Offset(camShakeDuration, ShapeBaseImageData),
+      addFieldV( "camShakeDuration", TypeRangedF32, Offset(camShakeDuration, ShapeBaseImageData), &CommonValidators::PositiveFloat,
          "Duration (in seconds) to shake the camera." );
-      addField( "camShakeRadius", TypeF32, Offset(camShakeRadius, ShapeBaseImageData),
+      addFieldV( "camShakeRadius", TypeRangedF32, Offset(camShakeRadius, ShapeBaseImageData), &CommonValidators::PositiveFloat,
          "Radial distance that a camera's position must be within relative to the "
          "center of the explosion to be shaken." );
-      addField( "camShakeFalloff", TypeF32, Offset(camShakeFalloff, ShapeBaseImageData),
+      addFieldV( "camShakeFalloff", TypeRangedF32, Offset(camShakeFalloff, ShapeBaseImageData), &CommonValidators::PositiveFloat,
          "Falloff value for the camera shake." );
    endGroup("Camera Shake");
 
@@ -769,7 +769,7 @@ void ShapeBaseImageData::initPersistFields()
    addField( "correctMuzzleVectorTP", TypeBool,  Offset(correctMuzzleVectorTP, ShapeBaseImageData),
       "@brief Flag to adjust the aiming vector to the camera's LOS point when in 3rd person view.\n\n"
       "@see ShapeBase::getMuzzleVector()" );
-   addField( "mass", TypeF32, Offset(mass, ShapeBaseImageData),
+   addFieldV( "mass", TypeRangedF32, Offset(mass, ShapeBaseImageData), &CommonValidators::PositiveFloat,
       "@brief Mass of this Image.\n\n"
       "This is added to the total mass of the ShapeBase object." );
    addField( "accuFire", TypeBool, Offset(accuFire, ShapeBaseImageData),
@@ -785,13 +785,13 @@ void ShapeBaseImageData::initPersistFields()
       addField( "lightColor", TypeColorF, Offset(lightColor, ShapeBaseImageData),
          "@brief The color of light this Image emits.\n\n"
          "@see lightType");
-      addField( "lightDuration", TypeS32, Offset(lightDuration, ShapeBaseImageData),
+      addFieldV( "lightDuration", TypeRangedS32, Offset(lightDuration, ShapeBaseImageData), &CommonValidators::PositiveInt,
          "@brief Duration in SimTime of Pulsing and WeaponFire type lights.\n\n"
          "@see lightType");
-      addField( "lightRadius", TypeF32, Offset(lightRadius, ShapeBaseImageData),
+      addFieldV( "lightRadius", TypeRangedF32, Offset(lightRadius, ShapeBaseImageData), &CommonValidators::PositiveFloat,
          "@brief Radius of the light this Image emits.\n\n"
          "@see lightType");
-      addField( "lightBrightness", TypeF32, Offset(lightBrightness, ShapeBaseImageData),
+      addFieldV( "lightBrightness", TypeRangedF32, Offset(lightBrightness, ShapeBaseImageData), &CommonValidators::PositiveFloat,
          "@brief Brightness of the light this Image emits.\n\n"
          "Only valid for WeaponFireLight."
          "@see lightType");
@@ -868,7 +868,7 @@ void ShapeBaseImageData::initPersistFields()
          "Name of the state to transition to when the generic trigger 3 state "
          "changes to false." );
 
-      addField( "stateTimeoutValue", TypeF32, Offset(stateTimeoutValue, ShapeBaseImageData), MaxStates,
+      addFieldV( "stateTimeoutValue", TypeRangedF32, Offset(stateTimeoutValue, ShapeBaseImageData), &CommonValidators::PositiveFloat, MaxStates,
          "Time in seconds to wait before transitioning to stateTransitionOnTimeout." );
       addField( "stateWaitForTimeout", TypeBool, Offset(stateWaitForTimeout, ShapeBaseImageData), MaxStates,
          "If false, this state ignores stateTimeoutValue and transitions "
@@ -884,7 +884,7 @@ void ShapeBaseImageData::initPersistFields()
          "client when it receives the 'reload' event." );
       addField( "stateEjectShell", TypeBool, Offset(stateEjectShell, ShapeBaseImageData), MaxStates,
          "If true, a shell casing will be ejected in this state." );
-      addField( "stateEnergyDrain", TypeF32, Offset(stateEnergyDrain, ShapeBaseImageData), MaxStates,
+      addFieldV( "stateEnergyDrain", TypeRangedF32, Offset(stateEnergyDrain, ShapeBaseImageData), &CommonValidators::PositiveFloat, MaxStates,
          "@brief Amount of energy to subtract from the Image in this state.\n\n"
          "Energy is drained at stateEnergyDrain units/tick as long as we are in "
          "this state.\n"
@@ -943,7 +943,7 @@ void ShapeBaseImageData::initPersistFields()
          "Do we transition to the new state's sequence when we leave the state?" );
       addField( "stateSequenceNeverTransition", TypeBool, Offset(stateSequenceNeverTransition, ShapeBaseImageData), MaxStates,
          "Never allow a transition to this sequence.  Often used for a fire sequence." );
-      addField( "stateSequenceTransitionTime", TypeF32, Offset(stateSequenceTransitionTime, ShapeBaseImageData), MaxStates,
+      addFieldV( "stateSequenceTransitionTime", TypeRangedF32, Offset(stateSequenceTransitionTime, ShapeBaseImageData), &CommonValidators::PositiveFloat, MaxStates,
          "The time to transition in or out of a sequence." );
 
       addField( "stateShapeSequence", TypeString, Offset(stateShapeSequence, ShapeBaseImageData), MaxStates,
@@ -963,7 +963,7 @@ void ShapeBaseImageData::initPersistFields()
          "@brief Emitter to generate particles in this state (from muzzle point or "
          "specified node).\n\n"
          "@see stateEmitterNode" );
-      addField( "stateEmitterTime", TypeF32, Offset(stateEmitterTime, ShapeBaseImageData), MaxStates,
+      addFieldV( "stateEmitterTime", TypeRangedF32, Offset(stateEmitterTime, ShapeBaseImageData), &CommonValidators::PositiveFloat, MaxStates,
          "How long (in seconds) to emit particles on entry to this state." );
       addField( "stateEmitterNode", TypeString, Offset(stateEmitterNode, ShapeBaseImageData), MaxStates,
          "@brief Name of the node to emit particles from.\n\n"
@@ -977,7 +977,7 @@ void ShapeBaseImageData::initPersistFields()
    endArray( "States" );
 
    addGroup("Sounds");
-      addField( "maxConcurrentSounds", TypeS32, Offset(maxConcurrentSounds, ShapeBaseImageData),
+      addFieldV( "maxConcurrentSounds", TypeRangedS32, Offset(maxConcurrentSounds, ShapeBaseImageData), &CommonValidators::PositiveInt,
          "@brief Maximum number of sounds this Image can play at a time.\n\n"
          "Any value <= 0 indicates that it can play an infinite number of sounds." );
    endGroup("Sounds");
@@ -1047,10 +1047,10 @@ void ShapeBaseImageData::packData(BitStream* stream)
    {
       stream->write(lightRadius);
       stream->write(lightDuration);
-      stream->writeFloat(lightColor.red, 7);
-      stream->writeFloat(lightColor.green, 7);
-      stream->writeFloat(lightColor.blue, 7);
-      stream->writeFloat(lightColor.alpha, 7);
+      stream->writeFloat(lightColor.red, 8);
+      stream->writeFloat(lightColor.green, 8);
+      stream->writeFloat(lightColor.blue, 8);
+      stream->writeFloat(lightColor.alpha, 8);
       stream->write(lightBrightness);
    }
 
@@ -1232,10 +1232,10 @@ void ShapeBaseImageData::unpackData(BitStream* stream)
    {
       stream->read(&lightRadius);
       stream->read(&lightDuration);
-      lightColor.red = stream->readFloat(7);
-      lightColor.green = stream->readFloat(7);
-      lightColor.blue = stream->readFloat(7);
-      lightColor.alpha = stream->readFloat(7);
+      lightColor.red = stream->readFloat(8);
+      lightColor.green = stream->readFloat(8);
+      lightColor.blue = stream->readFloat(8);
+      lightColor.alpha = stream->readFloat(8);
       stream->read( &lightBrightness );
    }
 

+ 3 - 3
Engine/source/T3D/spotLight.cpp

@@ -98,9 +98,9 @@ void SpotLight::initPersistFields()
    docsURL;
    addGroup( "Light" );
       
-      addField( "range", TypeF32, Offset( mRange, SpotLight ) );
-      addField( "innerAngle", TypeF32, Offset( mInnerConeAngle, SpotLight ) );
-      addField( "outerAngle", TypeF32, Offset( mOuterConeAngle, SpotLight ) );
+      addFieldV( "range", TypeRangedF32, Offset( mRange, SpotLight ), &CommonValidators::PositiveFloat);
+      addFieldV( "innerAngle", TypeRangedF32, Offset( mInnerConeAngle, SpotLight ), &CommonValidators::DegreeRangeQuarter);
+      addFieldV( "outerAngle", TypeRangedF32, Offset( mOuterConeAngle, SpotLight ), &CommonValidators::DegreeRangeQuarter);
 
    endGroup( "Light" );
 

+ 6 - 6
Engine/source/T3D/tsStatic.cpp

@@ -219,9 +219,9 @@ void TSStatic::initPersistFields()
    addGroup("Animation");
    addField("playAmbient", TypeBool, Offset(mPlayAmbient, TSStatic),
       "Enables automatic playing of the animation sequence named \"ambient\" (if it exists) when the TSStatic is loaded.");
-   addFieldV("AnimOffset", TypeF32, Offset(mAnimOffset, TSStatic), &percentValidator,
+   addFieldV("AnimOffset", TypeRangedF32, Offset(mAnimOffset, TSStatic), &percentValidator,
       "Percent Animation Offset.");
-   addFieldV("AnimSpeed", TypeF32, Offset(mAnimSpeed, TSStatic), &speedValidator,
+   addFieldV("AnimSpeed", TypeRangedF32, Offset(mAnimSpeed, TSStatic), &speedValidator,
       "Percent Animation Speed.");
    endGroup("Animation");
 
@@ -253,16 +253,16 @@ void TSStatic::initPersistFields()
 
    addGroup("AlphaFade");
    addField("alphaFadeEnable", TypeBool, Offset(mUseAlphaFade, TSStatic), "Turn on/off Alpha Fade");
-   addField("alphaFadeStart", TypeF32, Offset(mAlphaFadeStart, TSStatic), "Distance of start Alpha Fade");
-   addField("alphaFadeEnd", TypeF32, Offset(mAlphaFadeEnd, TSStatic), "Distance of end Alpha Fade");
+   addFieldV("alphaFadeStart", TypeRangedF32, Offset(mAlphaFadeStart, TSStatic), &CommonValidators::PositiveFloat, "Distance of start Alpha Fade");
+   addFieldV("alphaFadeEnd", TypeRangedF32, Offset(mAlphaFadeEnd, TSStatic), &CommonValidators::PositiveFloat, "Distance of end Alpha Fade");
    addField("alphaFadeInverse", TypeBool, Offset(mInvertAlphaFade, TSStatic), "Invert Alpha Fade's Start & End Distance");
    endGroup("AlphaFade");
 
    addGroup("Debug");
 
-   addField("renderNormals", TypeF32, Offset(mRenderNormalScalar, TSStatic),
+   addFieldV("renderNormals", TypeRangedF32, Offset(mRenderNormalScalar, TSStatic), &CommonValidators::PositiveFloat,
       "Debug rendering mode shows the normals for each point in the TSStatic's mesh.");
-   addField("forceDetail", TypeS32, Offset(mForceDetail, TSStatic),
+   addFieldV("forceDetail", TypeRangedS32, Offset(mForceDetail, TSStatic), &CommonValidators::PositiveInt,
       "Forces rendering to a particular detail level.");
 
    endGroup("Debug");

+ 9 - 9
Engine/source/T3D/turret/aiTurretShape.cpp

@@ -127,28 +127,28 @@ void AITurretShapeData::initPersistFields()
    docsURL;
    Parent::initPersistFields();
    addGroup("AI Steering");
-      addField("maxScanHeading",       TypeF32,       Offset(maxScanHeading,        AITurretShapeData),
+      addFieldV("maxScanHeading",       TypeRangedF32,       Offset(maxScanHeading,        AITurretShapeData), &CommonValidators::PosDegreeRangeQuarter,
          "@brief Maximum number of degrees to scan left and right.\n\n"
          "@note Maximum scan heading is 90 degrees.\n");
-      addField("maxScanPitch",         TypeF32,       Offset(maxScanPitch,          AITurretShapeData),
+      addFieldV("maxScanPitch", TypeRangedF32,       Offset(maxScanPitch,          AITurretShapeData), &CommonValidators::PosDegreeRangeQuarter,
          "@brief Maximum number of degrees to scan up and down.\n\n"
          "@note Maximum scan pitch is 90 degrees.\n");
-      addField("maxScanDistance",      TypeF32,       Offset(maxScanDistance,       AITurretShapeData),
+      addFieldV("maxScanDistance", TypeRangedF32,       Offset(maxScanDistance,       AITurretShapeData), &CommonValidators::PositiveFloat,
          "@brief Maximum distance to scan.\n\n"
          "When combined with maxScanHeading and maxScanPitch this forms a 3D scanning wedge used to initially "
          "locate a target.\n");
-      addField("scanTickFrequency",          TypeS32,       Offset(scanTickFrequency,       AITurretShapeData),
+      addFieldV("scanTickFrequency",          TypeRangedS32,       Offset(scanTickFrequency,       AITurretShapeData), &CommonValidators::NaturalNumber,
          "@brief How often should we perform a full scan when looking for a target.\n\n"
          "Expressed as the number of ticks between full scans, but no less than 1.\n");
-      addField("scanTickFrequencyVariance",  TypeS32,       Offset(scanTickFrequencyVariance,       AITurretShapeData),
+      addFieldV("scanTickFrequencyVariance", TypeRangedS32,       Offset(scanTickFrequencyVariance,       AITurretShapeData), &CommonValidators::PositiveInt,
          "@brief Random amount that should be added to the scan tick frequency each scan period.\n\n"
          "Expressed as the number of ticks to randomly add, but no less than zero.\n");
-      addField("trackLostTargetTime",  TypeF32,       Offset(trackLostTargetTime,       AITurretShapeData),
+      addFieldV("trackLostTargetTime", TypeRangedF32,       Offset(trackLostTargetTime,       AITurretShapeData), &CommonValidators::PositiveFloat,
          "@brief How long after the turret has lost the target should it still track it.\n\n"
          "Expressed in seconds.\n");
-   addField("maxWeaponRange",       TypeF32,       Offset(maxWeaponRange,       AITurretShapeData),
+   addFieldV("maxWeaponRange", TypeRangedF32,       Offset(maxWeaponRange,       AITurretShapeData), &CommonValidators::PositiveFloat,
       "@brief Maximum distance that the weapon will fire upon a target.\n\n");
-   addField("weaponLeadVelocity",   TypeF32,       Offset(weaponLeadVelocity,   AITurretShapeData),
+   addFieldV("weaponLeadVelocity", TypeRangedF32,       Offset(weaponLeadVelocity,   AITurretShapeData), &CommonValidators::PositiveFloat,
       "@brief Velocity used to lead target.\n\n"
       "If value <= 0, don't lead target.\n");
    endGroup("AI Steering");
@@ -173,7 +173,7 @@ void AITurretShapeData::initPersistFields()
       addField( "stateTransitionOnTimeout", TypeString, Offset(stateTransitionTimeout, AITurretShapeData), MaxStates,
          "Name of the state to transition to when we have been in this state "
          "for stateTimeoutValue seconds." );
-      addField( "stateTimeoutValue", TypeF32, Offset(stateTimeoutValue, AITurretShapeData), MaxStates,
+      addFieldV( "stateTimeoutValue", TypeRangedF32, Offset(stateTimeoutValue, AITurretShapeData), &CommonValidators::PositiveFloat, MaxStates,
          "Time in seconds to wait before transitioning to stateTransitionOnTimeout." );
       addField( "stateWaitForTimeout", TypeBool, Offset(stateWaitForTimeout, AITurretShapeData), MaxStates,
          "If false, this state ignores stateTimeoutValue and transitions "

+ 6 - 6
Engine/source/T3D/turret/turretShape.cpp

@@ -138,17 +138,17 @@ void TurretShapeData::initPersistFields()
          "@brief Should the turret allow only z rotations.\n\n"
          "True indicates that the turret may only be rotated on its z axis, just like the Item class.  "
          "This keeps the turret always upright regardless of the surface it lands on.\n");
-      addField("maxHeading",        TypeF32,       Offset(maxHeading,         TurretShapeData),
+      addFieldV("maxHeading", TypeRangedF32,       Offset(maxHeading,         TurretShapeData), &CommonValidators::PosDegreeRangeQuarter,
          "@brief Maximum number of degrees to rotate from center.\n\n"
          "A value of 180 or more degrees indicates the turret may rotate completely around.\n");
-      addField("minPitch",          TypeF32,       Offset(minPitch,           TurretShapeData),
+      addFieldV("minPitch", TypeRangedF32,       Offset(minPitch,           TurretShapeData), &CommonValidators::PosDegreeRangeQuarter,
          "@brief Minimum number of degrees to rotate down from straight ahead.\n\n");
-      addField("maxPitch",          TypeF32,       Offset(maxPitch,           TurretShapeData),
+      addFieldV("maxPitch", TypeRangedF32,       Offset(maxPitch,           TurretShapeData), &CommonValidators::PosDegreeRangeQuarter,
          "@brief Maximum number of degrees to rotate up from straight ahead.\n\n");
-      addField("headingRate",       TypeF32,       Offset(headingRate,        TurretShapeData),
+      addFieldV("headingRate", TypeRangedF32,       Offset(headingRate,        TurretShapeData), &CommonValidators::DegreeRange,
          "@brief Degrees per second rotation.\n\n"
          "A value of 0 means no rotation is allowed.  A value less than 0 means the rotation is instantaneous.\n");
-      addField("pitchRate",         TypeF32,       Offset(pitchRate,          TurretShapeData),
+      addFieldV("pitchRate", TypeRangedF32,       Offset(pitchRate,          TurretShapeData), &CommonValidators::DegreeRange,
          "@brief Degrees per second rotation.\n\n"
          "A value of 0 means no rotation is allowed.  A value less than 0 means the rotation is instantaneous.\n");
    endGroup("Steering");
@@ -167,7 +167,7 @@ void TurretShapeData::initPersistFields()
    endGroup("Weapon State");
 
    addGroup("Camera", "The settings used by the shape when it is the camera.");
-   addField("cameraOffset",      TypeF32,       Offset(cameraOffset,       TurretShapeData),
+   addFieldV("cameraOffset",      TypeRangedF32,       Offset(cameraOffset,       TurretShapeData), &CommonValidators::F32Range,
       "Vertical (Z axis) height of the camera above the turret." );
    endGroup("Camera");
 }

+ 15 - 15
Engine/source/T3D/vehicles/flyingVehicle.cpp

@@ -179,52 +179,52 @@ void FlyingVehicleData::initPersistFields()
    Parent::initPersistFields();
 
    addGroup("Physics");
-   addField( "rollForce", TypeF32, Offset(rollForce, FlyingVehicleData),
+   addFieldV( "rollForce", TypeRangedF32, Offset(rollForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "@brief Damping torque against rolling maneuvers (rotation about the y-axis), "
       "proportional to linear velocity.\n\n"
       "Acts to adjust roll to a stable position over time as the vehicle moves." );
-   addField( "rotationalDrag", TypeF32, Offset(rotationalDrag, FlyingVehicleData),
+   addFieldV( "rotationalDrag", TypeRangedF32, Offset(rotationalDrag, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "Rotational drag factor (slows vehicle rotation speed in all axes)." );
-   addField( "horizontalSurfaceForce", TypeF32, Offset(horizontalSurfaceForce, FlyingVehicleData),
+   addFieldV( "horizontalSurfaceForce", TypeRangedF32, Offset(horizontalSurfaceForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "@brief Damping force in the opposite direction to sideways velocity.\n\n"
       "Provides \"bite\" into the wind for climbing/diving and turning)." );
-   addField( "hoverHeight", TypeF32, Offset(hoverHeight, FlyingVehicleData),
+   addFieldV( "hoverHeight", TypeRangedF32, Offset(hoverHeight, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "The vehicle's height off the ground when at rest." );
-   addField( "createHoverHeight", TypeF32, Offset(createHoverHeight, FlyingVehicleData),
+   addFieldV( "createHoverHeight", TypeRangedF32, Offset(createHoverHeight, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "@brief The vehicle's height off the ground when useCreateHeight is active.\n\n"
       "This can help avoid problems with spawning the vehicle." );
    endGroup("Physics");
 
    addGroup("Steering");
-   addField( "maneuveringForce", TypeF32, Offset(maneuveringForce, FlyingVehicleData),
+   addFieldV( "maneuveringForce", TypeRangedF32, Offset(maneuveringForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "@brief Maximum X and Y (horizontal plane) maneuvering force.\n\n"
       "The actual force applied depends on the current thrust." );
-   addField( "verticalSurfaceForce", TypeF32, Offset(verticalSurfaceForce, FlyingVehicleData),
+   addFieldV( "verticalSurfaceForce", TypeRangedF32, Offset(verticalSurfaceForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "@brief Damping force in the opposite direction to vertical velocity.\n\n"
       "Controls side slip; lower numbers give more slide." );
-   addField( "vertThrustMultiple", TypeF32, Offset(vertThrustMultiple, FlyingVehicleData),
+   addFieldV( "vertThrustMultiple", TypeRangedF32, Offset(vertThrustMultiple, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "Multiplier applied to the jetForce (defined in VehicleData) when thrusting vertically." );
-   addField( "steeringForce", TypeF32, Offset(steeringForce, FlyingVehicleData),
+   addFieldV( "steeringForce", TypeRangedF32, Offset(steeringForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "@brief Maximum X and Z (sideways and vertical) steering force.\n\n"
       "The actual force applied depends on the current steering input." );
-   addField( "steeringRollForce", TypeF32, Offset(steeringRollForce, FlyingVehicleData),
+   addFieldV( "steeringRollForce", TypeRangedF32, Offset(steeringRollForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "Roll force induced by sideways steering input value (controls how much "
       "the vehicle rolls when turning)." );
    endGroup("Steering");
 
    addGroup("AutoCorrection");
-   addField( "maxAutoSpeed", TypeF32, Offset(maxAutoSpeed, FlyingVehicleData),
+   addFieldV( "maxAutoSpeed", TypeRangedF32, Offset(maxAutoSpeed, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "Maximum speed for automatic vehicle control assistance - vehicles "
       "travelling at speeds above this value do not get control assitance." );
-   addField( "autoInputDamping", TypeF32, Offset(autoInputDamping, FlyingVehicleData),
+   addFieldV( "autoInputDamping", TypeRangedF32, Offset(autoInputDamping, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "@brief Scale factor applied to steering input if speed is less than "
       "maxAutoSpeed to.improve handling at very low speeds.\n\n"
       "Smaller values make steering less sensitive." );
-   addField( "autoLinearForce", TypeF32, Offset(autoLinearForce, FlyingVehicleData),
+   addFieldV( "autoLinearForce", TypeRangedF32, Offset(autoLinearForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "@brief Corrective force applied to slow the vehicle when moving at less than "
       "maxAutoSpeed.\n\n"
       "The force is inversely proportional to vehicle speed." );
-   addField( "autoAngularForce", TypeF32, Offset(autoAngularForce, FlyingVehicleData),
+   addFieldV( "autoAngularForce", TypeRangedF32, Offset(autoAngularForce, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "@brief Corrective torque applied to level out the vehicle when moving at less "
       "than maxAutoSpeed.\n\n"
       "The torque is inversely proportional to vehicle speed." );
@@ -245,7 +245,7 @@ void FlyingVehicleData::initPersistFields()
       "and JetNozzle3." );
    addField( "trailEmitter",TYPEID< ParticleEmitterData >(), Offset(jetEmitter[TrailEmitter], FlyingVehicleData),
       "Emitter to generate contrail particles from model nodes contrail0 - contrail3." );
-   addField( "minTrailSpeed", TypeF32, Offset(minTrailSpeed, FlyingVehicleData),
+   addFieldV( "minTrailSpeed", TypeRangedF32, Offset(minTrailSpeed, FlyingVehicleData), &CommonValidators::PositiveFloat,
       "Minimum speed at which to start generating contrail particles." );
    endGroup("Particle Effects");
 

+ 6 - 6
Engine/source/T3D/vehicles/guiSpeedometer.cpp

@@ -111,15 +111,15 @@ void GuiSpeedometerHud::initPersistFields()
    docsURL;
    addGroup("Needle");
 
-   addField("maxSpeed", TypeF32, Offset( mMaxSpeed, GuiSpeedometerHud ),
+   addFieldV("maxSpeed", TypeRangedF32, Offset( mMaxSpeed, GuiSpeedometerHud ), &CommonValidators::PositiveFloat,
       "Maximum Vehicle speed (in Torque units per second) to represent on the "
       "speedo (Vehicle speeds greater than this are clamped to maxSpeed)." );
 
-   addField("minAngle", TypeF32, Offset( mMinAngle, GuiSpeedometerHud ),
+   addFieldV("minAngle", TypeRangedF32, Offset( mMinAngle, GuiSpeedometerHud ), &CommonValidators::DegreeRange,
       "Angle (in radians) of the needle when the Vehicle speed is 0. An angle "
       "of 0 points right, 90 points up etc)." );
 
-   addField("maxAngle", TypeF32, Offset( mMaxAngle, GuiSpeedometerHud ),
+   addFieldV("maxAngle", TypeRangedF32, Offset( mMaxAngle, GuiSpeedometerHud ), &CommonValidators::DegreeRange,
       "Angle (in radians) of the needle when the Vehicle speed is >= maxSpeed. "
       "An angle of 0 points right, 90 points up etc)." );
 
@@ -130,13 +130,13 @@ void GuiSpeedometerHud::initPersistFields()
       "Center of the needle, offset from the GuiSpeedometerHud control top "
       "left corner" );
 
-   addField("length", TypeF32, Offset( mNeedleLength, GuiSpeedometerHud ),
+   addFieldV("length", TypeRangedF32, Offset( mNeedleLength, GuiSpeedometerHud ), &CommonValidators::PositiveFloat,
       "Length of the needle from center to end" );
 
-   addField("width", TypeF32, Offset( mNeedleWidth, GuiSpeedometerHud ),
+   addFieldV("width", TypeRangedF32, Offset( mNeedleWidth, GuiSpeedometerHud ), &CommonValidators::PositiveFloat,
       "Width of the needle" );
 
-   addField("tail", TypeF32, Offset( mTailLength, GuiSpeedometerHud ),
+   addFieldV("tail", TypeRangedF32, Offset( mTailLength, GuiSpeedometerHud ), &CommonValidators::PositiveFloat,
       "Length of the needle from center to tail" );
 
    endGroup("Needle");

+ 19 - 19
Engine/source/T3D/vehicles/hoverVehicle.cpp

@@ -175,11 +175,11 @@ void HoverVehicleData::initPersistFields()
    docsURL;
    Parent::initPersistFields();
    addGroup("Physics");
-      addField( "normalForce", TypeF32, Offset(normalForce, HoverVehicleData),
+      addFieldV( "normalForce", TypeRangedF32, Offset(normalForce, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Force generated in the ground normal direction when the vehicle is not "
          "floating (within stabalizer length from the ground).\n\n"
          "@see stabLenMin" );
-      addField( "stabLenMin", TypeF32, Offset(stabLenMin, HoverVehicleData),
+      addFieldV( "stabLenMin", TypeRangedF32, Offset(stabLenMin, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Length of the base stabalizer when travelling at minimum speed (0).\n"
          "Each tick, the vehicle performs 2 raycasts (from the center back and "
          "center front of the vehicle) to check for contact with the ground. The "
@@ -188,10 +188,10 @@ void HoverVehicleData::initPersistFields()
          "spring and ground normal forces are not applied.\n\n"
          "<img src=\"images/hoverVehicle_forces.png\">\n"
          "@see stabSpringConstant" );
-      addField( "stabLenMax", TypeF32, Offset(stabLenMax, HoverVehicleData),
+      addFieldV( "stabLenMax", TypeRangedF32, Offset(stabLenMax, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Length of the base stabalizer when travelling at maximum speed "
          "(maxThrustSpeed).\n\n@see stabLenMin\n\n@see mainThrustForce" );
-      addField("vertFactor", TypeF32, Offset(vertFactor, HoverVehicleData),
+      addFieldV("vertFactor", TypeRangedF32, Offset(vertFactor, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Scalar applied to the vertical portion of the velocity drag acting on "
          "the vehicle.\nFor the horizontal (X and Y) components of velocity drag, "
          "a factor of 0.25 is applied when the vehicle is floating, and a factor "
@@ -199,49 +199,49 @@ void HoverVehicleData::initPersistFields()
          "is multiplied by the vehicle's dragForce, as defined above, and the "
          "result is subtracted from it's movement force.\n"
          "@note The vertFactor must be between 0.0 and 1.0 (inclusive).");
-      addField("stabSpringConstant", TypeF32, Offset(stabSpringConstant, HoverVehicleData),
+      addFieldV("stabSpringConstant", TypeRangedF32, Offset(stabSpringConstant, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Value used to generate stabalizer spring force. The force generated "
          "depends on stabilizer compression, that is how close the vehicle is "
          "to the ground proportional to current stabalizer length.\n\n"
          "@see stabLenMin");
-      addField("stabDampingConstant", TypeF32, Offset(stabDampingConstant, HoverVehicleData),
+      addFieldV("stabDampingConstant", TypeRangedF32, Offset(stabDampingConstant, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Damping spring force acting against changes in the stabalizer length.\n\n"
          "@see stabLenMin");
    endGroup("Physics");
 
    addGroup("Steering");
-      addField( "steeringForce", TypeF32, Offset(steeringForce, HoverVehicleData),
+      addFieldV( "steeringForce", TypeRangedF32, Offset(steeringForce, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Yaw (rotation about the Z-axis) force applied when steering in the x-axis direction."
          "about the vehicle's Z-axis)" );
-      addField( "rollForce", TypeF32, Offset(rollForce, HoverVehicleData),
+      addFieldV( "rollForce", TypeRangedF32, Offset(rollForce, HoverVehicleData), &CommonValidators::PositiveFloat,
       "Roll (rotation about the Y-axis) force applied when steering in the x-axis direction." );
-      addField( "pitchForce", TypeF32, Offset(pitchForce, HoverVehicleData),
+      addFieldV( "pitchForce", TypeRangedF32, Offset(pitchForce, HoverVehicleData), &CommonValidators::PositiveFloat,
       "Pitch (rotation about the X-axis) force applied when steering in the y-axis direction." );
-      addField( "dragForce", TypeF32, Offset(dragForce, HoverVehicleData),
+      addFieldV( "dragForce", TypeRangedF32, Offset(dragForce, HoverVehicleData), &CommonValidators::PositiveFloat,
       "Drag force factor that acts opposite to the vehicle velocity.\nAlso "
       "used to determnine the vehicle's maxThrustSpeed.\n@see mainThrustForce" );
-      addField( "mainThrustForce", TypeF32, Offset(mainThrustForce, HoverVehicleData),
+      addFieldV( "mainThrustForce", TypeRangedF32, Offset(mainThrustForce, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Force generated by thrusting the vehicle forward.\nAlso used to determine "
          "the maxThrustSpeed:\n\n"
          "@tsexample\n"
          "maxThrustSpeed = (mainThrustForce + strafeThrustForce) / dragForce;\n"
          "@endtsexample\n" );
-      addField( "reverseThrustForce", TypeF32, Offset(reverseThrustForce, HoverVehicleData),
+      addFieldV( "reverseThrustForce", TypeRangedF32, Offset(reverseThrustForce, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Force generated by thrusting the vehicle backward." );
-      addField( "strafeThrustForce", TypeF32, Offset(strafeThrustForce, HoverVehicleData),
+      addFieldV( "strafeThrustForce", TypeRangedF32, Offset(strafeThrustForce, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Force generated by thrusting the vehicle to one side.\nAlso used to "
          "determine the vehicle's maxThrustSpeed.\n@see mainThrustForce" );
-      addField( "turboFactor", TypeF32, Offset(turboFactor, HoverVehicleData),
+      addFieldV( "turboFactor", TypeRangedF32, Offset(turboFactor, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Scale factor applied to the vehicle's thrust force when jetting." );
-      addField( "floatingThrustFactor", TypeF32, Offset(floatingThrustFactor, HoverVehicleData),
+      addFieldV( "floatingThrustFactor", TypeRangedF32, Offset(floatingThrustFactor, HoverVehicleData), &CommonValidators::PositiveFloat,
          "Scalar applied to the vehicle's thrust force when the vehicle is floating.\n"
          "@note The floatingThrustFactor must be between 0.0 and 1.0 (inclusive)." );
    endGroup("Steering");
 
    addGroup("AutoCorrection");
-   addField( "gyroDrag", TypeF32, Offset(gyroDrag, HoverVehicleData),
+   addFieldV( "gyroDrag", TypeRangedF32, Offset(gyroDrag, HoverVehicleData), &CommonValidators::PositiveFloat,
       "Damping torque that acts against the vehicle's current angular momentum." );
-   addField( "restorativeForce", TypeF32, Offset(restorativeForce, HoverVehicleData),
+   addFieldV( "restorativeForce", TypeRangedF32, Offset(restorativeForce, HoverVehicleData), &CommonValidators::PositiveFloat,
       "Force generated to stabalize the vehicle (return it to neutral pitch/roll) "
       "when the vehicle is floating (more than stabalizer length from the "
       "ground.\n\n@see stabLenMin" );
@@ -258,12 +258,12 @@ void HoverVehicleData::initPersistFields()
       "\"X Y Z\" offset from the vehicle's origin from which to generate dust "
       "trail particles.\nBy default particles are emitted directly beneath the "
       "origin of the vehicle model." );
-   addField( "triggerTrailHeight", TypeF32, Offset(triggerTrailHeight, HoverVehicleData),
+   addFieldV( "triggerTrailHeight", TypeRangedF32, Offset(triggerTrailHeight, HoverVehicleData), &CommonValidators::PositiveFloat,
       "Maximum height above surface to emit dust trail particles.\nIf the vehicle "
       "is less than triggerTrailHeight above a static surface with a material that "
       "has 'showDust' set to true, the vehicle will emit particles from the "
       "dustTrailEmitter." );
-   addField( "dustTrailFreqMod", TypeF32, Offset(dustTrailFreqMod, HoverVehicleData),
+   addFieldV( "dustTrailFreqMod", TypeRangedF32, Offset(dustTrailFreqMod, HoverVehicleData), &CommonValidators::PositiveFloat,
       "Number of dust trail particles to generate based on vehicle speed.\nThe "
       "vehicle's speed is divided by this value to determine how many particles "
       "to generate each frame. Lower values give a more dense trail, higher "

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

@@ -297,12 +297,12 @@ void VehicleData::initPersistFields()
       "damageEmitterOffset[1] = \"-0.5 3 1\";\n"
       "numDmgEmitterAreas = 2;\n"
       "@endtsexample\n" );
-   addField( "damageLevelTolerance", TypeF32, Offset(damageLevelTolerance, VehicleData), VC_NUM_DAMAGE_LEVELS,
+   addFieldV( "damageLevelTolerance", TypeRangedF32, Offset(damageLevelTolerance, VehicleData), &CommonValidators::PositiveFloat, 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),
+   addFieldV( "numDmgEmitterAreas", TypeRangedF32, Offset(numDmgEmitterAreas, VehicleData), &CommonValidators::PositiveFloat,
       "Number of damageEmitterOffset values to use for each damageEmitter.\n\n"
       "@see damageEmitterOffset" );
    endGroup("Particle Effects");
@@ -313,33 +313,33 @@ void VehicleData::initPersistFields()
    endGroup("Physics");
 
    addGroup("Collision");
-   addField( "collDamageThresholdVel", TypeF32, Offset(collDamageThresholdVel, VehicleData),
+   addFieldV( "collDamageThresholdVel", TypeRangedF32, Offset(collDamageThresholdVel, VehicleData), &CommonValidators::PositiveFloat,
       "Minimum collision velocity to cause damage to this vehicle.\nCurrently unused." );
-   addField( "collDamageMultiplier", TypeF32, Offset(collDamageMultiplier, VehicleData),
+   addFieldV( "collDamageMultiplier", TypeRangedF32, Offset(collDamageMultiplier, VehicleData), &CommonValidators::PositiveFloat,
       "@brief Damage to this vehicle after a collision (multiplied by collision "
       "velocity).\n\nCurrently unused." );
    endGroup("Collision");
 
    addGroup("Steering");
-      addField( "jetForce", TypeF32, Offset(jetForce, VehicleData),
+      addFieldV( "jetForce", TypeRangedF32, Offset(jetForce, VehicleData), &CommonValidators::PositiveFloat,
          "@brief Additional force applied to the vehicle when it is jetting.\n\n"
          "For WheeledVehicles, the force is applied in the forward direction. For "
          "FlyingVehicles, the force is applied in the thrust direction." );
-      addField( "jetEnergyDrain", TypeF32, Offset(jetEnergyDrain, VehicleData),
+      addFieldV( "jetEnergyDrain", TypeRangedF32, Offset(jetEnergyDrain, VehicleData), &CommonValidators::PositiveFloat,
       "@brief Energy amount to drain for each tick the vehicle is jetting.\n\n"
          "Once the vehicle's energy level reaches 0, it will no longer be able to jet." );
-      addField( "minJetEnergy", TypeF32, Offset(minJetEnergy, VehicleData),
+      addFieldV( "minJetEnergy", TypeRangedF32, Offset(minJetEnergy, VehicleData), &CommonValidators::PositiveFloat,
       "Minimum vehicle energy level to begin jetting." );
-      addField( "maxSteeringAngle", TypeF32, Offset(maxSteeringAngle, VehicleData),
+      addFieldV( "maxSteeringAngle", TypeRangedF32, Offset(maxSteeringAngle, VehicleData), &CommonValidators::PositiveFloat,
          "Maximum yaw (horizontal) and pitch (vertical) steering angle in radians." );
    endGroup("Steering");
 
    addGroup("AutoCorrection");
    addField( "powerSteering", TypeBool, Offset(powerSteering, VehicleData),
       "If true, steering does not auto-centre while the vehicle is being steered by its driver." );
-   addField( "steeringReturn", TypeF32, Offset(steeringReturn, VehicleData),
+   addFieldV( "steeringReturn", TypeRangedF32, Offset(steeringReturn, VehicleData), &CommonValidators::PositiveFloat,
       "Rate at which the vehicle's steering returns to forwards when it is moving." );
-   addField( "steeringReturnSpeedScale", TypeF32, Offset(steeringReturnSpeedScale, VehicleData),
+   addFieldV( "steeringReturnSpeedScale", TypeRangedF32, Offset(steeringReturnSpeedScale, VehicleData), &CommonValidators::PositiveFloat,
       "Amount of effect the vehicle's speed has on its rate of steering return." );
    endGroup("AutoCorrection");
 }

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

@@ -115,20 +115,20 @@ void WheeledVehicleTire::initPersistFields()
    docsURL;
    INITPERSISTFIELD_SHAPEASSET(Shape, WheeledVehicleTire, "The shape to use for the wheel.");
 
-   addField( "mass", TypeF32, Offset(mass, WheeledVehicleTire),
+   addFieldV( "mass", TypeRangedF32, Offset(mass, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "The mass of the wheel.\nCurrently unused." );
-   addField( "radius", TypeF32, Offset(radius, WheeledVehicleTire),
+   addFieldV( "radius", TypeRangedF32, Offset(radius, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "@brief The radius of the wheel.\n\n"
       "The radius is determined from the bounding box of the shape provided "
       "in the shapefile field, and does not need to be specified in script. "
       "The tire should be built with its hub axis along the object's Y-axis." );
-   addField( "staticFriction", TypeF32, Offset(staticFriction, WheeledVehicleTire),
+   addFieldV( "staticFriction", TypeRangedF32, Offset(staticFriction, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "Tire friction when the wheel is not slipping (has traction)." );
-   addField( "kineticFriction", TypeF32, Offset(kineticFriction, WheeledVehicleTire),
+   addFieldV( "kineticFriction", TypeRangedF32, Offset(kineticFriction, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "Tire friction when the wheel is slipping (no traction)." );
-   addField( "restitution", TypeF32, Offset(restitution, WheeledVehicleTire),
+   addFieldV( "restitution", TypeRangedF32, Offset(restitution, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "Tire restitution.\nCurrently unused." );
-   addField( "lateralForce", TypeF32, Offset(lateralForce, WheeledVehicleTire),
+   addFieldV( "lateralForce", TypeRangedF32, Offset(lateralForce, WheeledVehicleTire, &CommonValidators::PositiveFloat), &CommonValidators::PositiveFloat,
       "@brief Tire force perpendicular to the direction of movement.\n\n"
       "Lateral force can in simple terms be considered left/right steering "
       "force. WheeledVehicles are acted upon by forces generated by their tires "
@@ -146,14 +146,14 @@ void WheeledVehicleTire::initPersistFields()
       "For this field, the larger the value supplied for the lateralForce, the "
       "larger the effect steering maneuvers can have. In Torque tire forces are "
       "applied at a vehicle's wheel hubs." );
-   addField( "lateralDamping", TypeF32, Offset(lateralDamping, WheeledVehicleTire),
+   addFieldV( "lateralDamping", TypeRangedF32, Offset(lateralDamping, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "Damping force applied against lateral forces generated by the tire.\n\n"
       "@see lateralForce" );
-   addField( "lateralRelaxation", TypeF32, Offset(lateralRelaxation, WheeledVehicleTire),
+   addFieldV( "lateralRelaxation", TypeRangedF32, Offset(lateralRelaxation, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "@brief Relaxing force applied against lateral forces generated by the tire.\n\n"
       "The lateralRelaxation force measures how strongly the tire effectively "
       "un-deforms.\n\n@see lateralForce" );
-   addField( "longitudinalForce", TypeF32, Offset(longitudinalForce, WheeledVehicleTire),
+   addFieldV( "longitudinalForce", TypeRangedF32, Offset(longitudinalForce, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "@brief Tire force in the direction of movement.\n\n"
       "Longitudinal force can in simple terms be considered forward/backward "
       "movement force. WheeledVehicles are acted upon by forces generated by "
@@ -162,10 +162,10 @@ void WheeledVehicleTire::initPersistFields()
       "For this field, the larger the value, the larger the effect "
       "acceleration/deceleration inputs have.\n\n"
       "@see lateralForce" );
-   addField( "longitudinalDamping", TypeF32, Offset(longitudinalDamping, WheeledVehicleTire),
+   addFieldV( "longitudinalDamping", TypeRangedF32, Offset(longitudinalDamping, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "Damping force applied against longitudinal forces generated by the tire.\n\n"
       "@see longitudinalForce" );
-   addField( "longitudinalRelaxation", TypeF32, Offset(longitudinalRelaxation, WheeledVehicleTire),
+   addFieldV( "longitudinalRelaxation", TypeRangedF32, Offset(longitudinalRelaxation, WheeledVehicleTire), &CommonValidators::PositiveFloat,
       "@brief Relaxing force applied against longitudinal forces generated by the tire.\n\n"
       "The longitudinalRelaxation force measures how strongly the tire effectively "
       "un-deforms.\n\n"
@@ -235,20 +235,20 @@ WheeledVehicleSpring::WheeledVehicleSpring()
 void WheeledVehicleSpring::initPersistFields()
 {
    docsURL;
-   addField( "length", TypeF32, Offset(length, WheeledVehicleSpring),
+   addFieldV( "length", TypeRangedF32, Offset(length, WheeledVehicleSpring), &CommonValidators::PositiveFloat,
       "@brief Maximum spring length. ie. how far the wheel can extend from the "
       "root hub position.\n\n"
       "This should be set to the vertical (Z) distance the hub travels in the "
       "associated spring animation." );
-   addField( "force", TypeF32, Offset(force, WheeledVehicleSpring),
+   addFieldV( "force", TypeRangedF32, Offset(force, WheeledVehicleSpring), &CommonValidators::PositiveFloat,
       "@brief Maximum spring force (when compressed to minimum length, 0).\n\n"
       "Increasing this will make the vehicle suspension ride higher (for a given "
       "vehicle mass), and also make the vehicle more bouncy when landing jumps." );
-   addField( "damping", TypeF32, Offset(damping, WheeledVehicleSpring),
+   addFieldV( "damping", TypeRangedF32, Offset(damping, WheeledVehicleSpring), &CommonValidators::PositiveFloat,
       "@brief Force applied to slow changes to the extension of this spring.\n\n"
       "Increasing this makes the suspension stiffer which can help stabilise "
       "bouncy vehicles." );
-   addField( "antiSwayForce", TypeF32, Offset(antiSway, WheeledVehicleSpring),
+   addFieldV( "antiSwayForce", TypeRangedF32, Offset(antiSway, WheeledVehicleSpring), &CommonValidators::PositiveFloat,
       "@brief Force applied to equalize extension of the spring on the opposite "
       "wheel.\n\n"
       "This force helps to keep the suspension balanced when opposite wheels "
@@ -465,17 +465,17 @@ void WheeledVehicleData::initPersistFields()
    endGroup("Sounds");
 
    addGroup("Steering");
-   addField("maxWheelSpeed", TypeF32, Offset(maxWheelSpeed, WheeledVehicleData),
+   addFieldV("maxWheelSpeed", TypeRangedF32, Offset(maxWheelSpeed, WheeledVehicleData), &CommonValidators::PositiveFloat,
       "@brief Maximum linear velocity of each wheel.\n\n"
       "This caps the maximum speed of the vehicle." );
-   addField("engineTorque", TypeF32, Offset(engineTorque, WheeledVehicleData),
+   addFieldV("engineTorque", TypeRangedF32, Offset(engineTorque, WheeledVehicleData), &CommonValidators::PositiveFloat,
       "@brief Torque available from the engine at 100% throttle.\n\n"
       "This controls vehicle acceleration. ie. how fast it will reach maximum speed." );
-   addField("engineBrake", TypeF32, Offset(engineBrake, WheeledVehicleData),
+   addFieldV("engineBrake", TypeRangedF32, Offset(engineBrake, WheeledVehicleData), &CommonValidators::PositiveFloat,
       "@brief Braking torque applied by the engine when the throttle and brake "
       "are both 0.\n\n"
       "This controls how quickly the vehicle will coast to a stop." );
-   addField("brakeTorque", TypeF32, Offset(brakeTorque, WheeledVehicleData),
+   addFieldV("brakeTorque", TypeRangedF32, Offset(brakeTorque, WheeledVehicleData), &CommonValidators::PositiveFloat,
       "@brief Torque applied when braking.\n\n"
       "This controls how fast the vehicle will stop when the brakes are applied." );
    addField("downforce", TypeF32, Offset(mDownForce, WheeledVehicleData),

+ 5 - 5
Engine/source/afx/afxEffectGroup.cpp

@@ -143,20 +143,20 @@ void afxEffectGroupData::initPersistFields()
    docsURL;
   addField("groupEnabled",   TypeBool,    myOffset(group_enabled),
     "...");
-  addField("count",          TypeS32,     myOffset(group_count),
+  addFieldV("count", TypeRangedS32,     myOffset(group_count), &CommonValidators::NaturalNumber,
     "...");
   addField("indexOffset",    TypeS8,      myOffset(idx_offset),
     "...");
   addField("assignIndices",  TypeBool,    myOffset(assign_idx),
     "...");
 
-  addField("delay",          TypeF32,     myOffset(timing.delay),
+  addFieldV("delay",          TypeRangedF32,     myOffset(timing.delay), &CommonValidators::PositiveFloat,
     "...");
-  addField("lifetime",       TypeF32,     myOffset(timing.lifetime),
+  addFieldV("lifetime", TypeRangedF32,     myOffset(timing.lifetime), &CommonValidators::PositiveFloat,
     "...");
-  addField("fadeInTime",     TypeF32,     myOffset(timing.fade_in_time),
+  addFieldV("fadeInTime", TypeRangedF32,     myOffset(timing.fade_in_time), &CommonValidators::PositiveFloat,
     "...");
-  addField("fadeOutTime",    TypeF32,     myOffset(timing.fade_out_time),
+  addFieldV("fadeOutTime", TypeRangedF32,     myOffset(timing.fade_out_time), &CommonValidators::PositiveFloat,
     "...");
 
   // effect lists

+ 15 - 14
Engine/source/afx/afxEffectWrapper.cpp

@@ -35,6 +35,7 @@
 #include "afx/afxEffectWrapper.h"
 #include "afx/util/afxAnimCurve.h"
 #include "afx/util/afxEase.h"
+#include "console/typeValidators.h"
 
 //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 // afxEffectWrapperData
@@ -237,33 +238,33 @@ void afxEffectWrapperData::initPersistFields()
   addField("ghostIsConstraintSrc",    TypeBool,     myOffset(use_ghost_as_cons_obj),
     "...");
 
-  addField("delay",             TypeF32,          myOffset(ewd_timing.delay),
+  addFieldV("delay", TypeRangedF32,          myOffset(ewd_timing.delay), &CommonValidators::PositiveFloat,
     "...");
-  addField("lifetime",          TypeF32,          myOffset(ewd_timing.lifetime),
+  addFieldV("lifetime", TypeRangedF32,          myOffset(ewd_timing.lifetime), &CommonValidators::PositiveFloat,
     "...");
-  addField("fadeInTime",        TypeF32,          myOffset(ewd_timing.fade_in_time),
+  addFieldV("fadeInTime", TypeRangedF32,          myOffset(ewd_timing.fade_in_time), &CommonValidators::PositiveFloat,
     "...");
-  addField("residueLifetime",   TypeF32,          myOffset(ewd_timing.residue_lifetime),
+  addFieldV("residueLifetime", TypeRangedF32,          myOffset(ewd_timing.residue_lifetime), &CommonValidators::PositiveFloat,
     "...");
   addField("fadeInEase",        TypePoint2F,      myOffset(ewd_timing.fadein_ease),
     "...");
   addField("fadeOutEase",       TypePoint2F,      myOffset(ewd_timing.fadeout_ease),
     "...");
-  addField("lifetimeBias",      TypeF32,          myOffset(ewd_timing.life_bias),
+  addFieldV("lifetimeBias", TypeRangedF32,          myOffset(ewd_timing.life_bias), &CommonValidators::PositiveFloat,
     "...");
-  addField("fadeOutTime",       TypeF32,          myOffset(user_fade_out_time),
+  addFieldV("fadeOutTime", TypeRangedF32,          myOffset(user_fade_out_time), &CommonValidators::PositiveFloat,
     "...");
 
-  addField("rateFactor",        TypeF32,          myOffset(rate_factor),
+  addFieldV("rateFactor", TypeRangedF32,          myOffset(rate_factor), &CommonValidators::PositiveFloat,
     "...");
-  addField("scaleFactor",       TypeF32,          myOffset(scale_factor),
+  addFieldV("scaleFactor", TypeRangedF32,          myOffset(scale_factor), &CommonValidators::PositiveFloat,
     "...");
 
   addField("isLooping",         TypeBool,         myOffset(is_looping),
     "...");
-  addField("loopCount",         TypeS32,          myOffset(n_loops),
+  addFieldV("loopCount",         TypeRangedS32,          myOffset(n_loops), &CommonValidators::PositiveInt,
     "...");
-  addField("loopGapTime",       TypeF32,          myOffset(loop_gap_time),
+  addFieldV("loopGapTime", TypeRangedF32,          myOffset(loop_gap_time), &CommonValidators::PositiveFloat,
     "...");
 
   addField("ignoreTimeFactor",    TypeBool,       myOffset(ignore_time_factor),
@@ -296,9 +297,9 @@ void afxEffectWrapperData::initPersistFields()
     "...");
   addField("direction",         TypePoint3F,      myOffset(direction),
     "...");
-  addField("speed",             TypeF32,          myOffset(speed),
+  addFieldV("speed", TypeRangedF32,          myOffset(speed), &CommonValidators::PositiveFloat,
     "...");
-  addField("mass",              TypeF32,          myOffset(mass),
+  addFieldV("mass", TypeRangedF32,          myOffset(mass), &CommonValidators::PositiveFloat,
     "...");
 
   addField("borrowAltitudes",   TypeBool,         myOffset(borrow_altitudes),
@@ -739,9 +740,9 @@ afxEffectWrapper::~afxEffectWrapper()
 void afxEffectWrapper::initPersistFields()
 {
    docsURL;
-  addField("liveScaleFactor",     TypeF32,    myOffset(mLive_scale_factor),
+  addFieldV("liveScaleFactor", TypeRangedF32,    myOffset(mLive_scale_factor), &CommonValidators::PositiveFloat,
     "...");
-  addField("liveFadeFactor",      TypeF32,    myOffset(mLive_fade_factor),
+  addFieldV("liveFadeFactor", TypeRangedF32,    myOffset(mLive_fade_factor), &CommonValidators::PositiveFloat,
     "...");
 
   Parent::initPersistFields();

+ 2 - 2
Engine/source/afx/afxEffectron.cpp

@@ -111,9 +111,9 @@ void afxEffectronData::reloadReset()
 void afxEffectronData::initPersistFields()
 {
    docsURL;
-  addField("duration",    TypeF32,      myOffset(duration),
+  addFieldV("duration", TypeRangedF32,      myOffset(duration), &CommonValidators::PositiveFloat,
     "...");
-  addField("numLoops",    TypeS32,      myOffset(n_loops),
+  addFieldV("numLoops", TypeRangedS32,      myOffset(n_loops), &CommonValidators::NegDefaultInt,
     "...");
   // effect lists
   // for each of these, dummy_fx_entry is set and then a validator adds it to the appropriate effects list 

+ 21 - 20
Engine/source/afx/afxMagicMissile.cpp

@@ -324,8 +324,9 @@ afxMagicMissileData* afxMagicMissileData::cloneAndPerformSubstitutions(const Sim
 
 FRangeValidator muzzleVelocityValidator(0, 10000);
 FRangeValidator missilePrecisionValidator(0.f, 100.f);
-FRangeValidator missileTrackDelayValidator(0, 100000);
+IRangeValidator missileTrackDelayValidator(0, 100000);
 FRangeValidator missileBallisticCoefficientValidator(0, 1);
+FRangeValidator missileFollowTerrainAdjustRateValidator(0.05f, FLT_MAX);
 
 void afxMagicMissileData::initPersistFields()
 {
@@ -353,36 +354,36 @@ void afxMagicMissileData::initPersistFields()
    endGroup("Light Emitter");
 
    addGroup("Physics");
-      addNamedFieldV(lifetime,    TypeS32,              afxMagicMissileData,  &ticksFromMS);
-      addFieldV("casterSafetyTime", TypeS32, myOffset(caster_safety_time), &ticksFromMS);
+      addNamedFieldV(lifetime,    TypeRangedS32,              afxMagicMissileData,  &ticksFromMS);
+      addFieldV("casterSafetyTime", TypeRangedS32, myOffset(caster_safety_time), &ticksFromMS);
       addField("isBallistic", TypeBool,   Offset(isBallistic, afxMagicMissileData));
-      addNamedFieldV(muzzleVelocity,    TypeF32,      afxMagicMissileData,  &muzzleVelocityValidator);
-      addNamedFieldV(ballisticCoefficient,  TypeF32,    afxMagicMissileData,  &missileBallisticCoefficientValidator);
-      addField("gravityMod", TypeF32, Offset(gravityMod, afxMagicMissileData));
+      addNamedFieldV(muzzleVelocity,    TypeRangedF32,      afxMagicMissileData,  &muzzleVelocityValidator);
+      addNamedFieldV(ballisticCoefficient,  TypeRangedF32,    afxMagicMissileData,  &missileBallisticCoefficientValidator);
+      addFieldV("gravityMod", TypeRangedF32, Offset(gravityMod, afxMagicMissileData), &CommonValidators::F32Range);
       addField("collisionMask",         TypeS32,      myOffset(collision_mask));
       addField("startingVelocityVector",TypePoint3F,  myOffset(starting_vel_vec));
       addNamedField(acceleration,     TypeF32,  afxMagicMissileData);
-      addNamedFieldV(accelDelay,      TypeS32,  afxMagicMissileData,  &ticksFromMS);
-      addNamedFieldV(accelLifetime,   TypeS32,  afxMagicMissileData,  &ticksFromMS);
+      addNamedFieldV(accelDelay, TypeRangedS32,  afxMagicMissileData,  &ticksFromMS);
+      addNamedFieldV(accelLifetime, TypeRangedS32,  afxMagicMissileData,  &ticksFromMS);
       addField("reverseTargeting", TypeBool, myOffset(reverse_targeting));
    endGroup("Physics");
 
    addGroup("Physics-Tracking");
       addNamedField(isGuided,               TypeBool,   afxMagicMissileData);
-      addNamedFieldV(precision,             TypeF32,    afxMagicMissileData,  &missilePrecisionValidator); 
-      addNamedFieldV(trackDelay,            TypeS32,    afxMagicMissileData,  &missileTrackDelayValidator);
+      addNamedFieldV(precision,             TypeRangedF32,    afxMagicMissileData,  &missilePrecisionValidator);
+      addNamedFieldV(trackDelay,            TypeRangedS32,    afxMagicMissileData,  &missileTrackDelayValidator);
    endGroup("Physics-Tracking");
 
    addGroup("Physics-Avoidance");
       addField("followTerrain",             TypeBool, myOffset(followTerrain));
-      addField("followTerrainHeight",       TypeF32,  myOffset(followTerrainHeight));
-      addField("followTerrainAdjustRate",   TypeF32,  myOffset(followTerrainAdjustRate));
-      addFieldV("followTerrainAdjustDelay", TypeS32,  myOffset(followTerrainAdjustDelay), &ticksFromMS);
-
-      addField("hoverAltitude",       TypeF32,    myOffset(hover_altitude));
-      addField("hoverAttackDistance", TypeF32,    myOffset(hover_attack_distance));
-      addField("hoverAttackGradient", TypeF32,    myOffset(hover_attack_gradient));
-      addFieldV("hoverTime",          TypeS32,    myOffset(hover_time), &ticksFromMS); 
+      addFieldV("followTerrainHeight", TypeRangedS32,  myOffset(followTerrainHeight), &CommonValidators::PositiveFloat);
+      addFieldV("followTerrainAdjustRate", TypeRangedS32,  myOffset(followTerrainAdjustRate), &missileFollowTerrainAdjustRateValidator);
+      addFieldV("followTerrainAdjustDelay", TypeRangedS32,  myOffset(followTerrainAdjustDelay), &ticksFromMS);
+
+      addFieldV("hoverAltitude", TypeRangedF32,    myOffset(hover_altitude), &CommonValidators::PositiveFloat);
+      addFieldV("hoverAttackDistance", TypeRangedF32,    myOffset(hover_attack_distance), &CommonValidators::PositiveFloat);
+      addFieldV("hoverAttackGradient", TypeRangedF32,    myOffset(hover_attack_gradient), &CommonValidators::PositiveNonZeroFloat);
+      addFieldV("hoverTime", TypeRangedS32,    myOffset(hover_time), &ticksFromMS);
    endGroup("Physics-Avoidance");
 
    addGroup("Physics-Launch");
@@ -391,8 +392,8 @@ void afxMagicMissileData::initPersistFields()
       addField("launchOffsetServer",TypePoint3F,  myOffset(launch_offset_server));
       addField("launchOffsetClient",TypePoint3F,  myOffset(launch_offset_client));
       addField("launchNodeOffset",  TypePoint3F,  myOffset(launch_node_offset));
-      addField("launchAimPitch",    TypeF32,      myOffset(launch_pitch));
-      addField("launchAimPan",      TypeF32,      myOffset(launch_pan));
+      addFieldV("launchAimPitch",    TypeRangedF32,      myOffset(launch_pitch), &CommonValidators::DegreeRange);
+      addFieldV("launchAimPan", TypeRangedF32,      myOffset(launch_pan), &CommonValidators::DegreeRange);
       addField("launchConstraintServer",  TypeString,   myOffset(launch_cons_s_spec));
       addField("launchConstraintClient",  TypeString,   myOffset(launch_cons_c_spec));
       addField("echoLaunchOffset",  TypeBool,     myOffset(echo_launch_offset));

+ 10 - 10
Engine/source/afx/afxMagicSpell.cpp

@@ -220,22 +220,22 @@ void afxMagicSpellData::initPersistFields()
   // for each effect list, dummy_fx_entry is set and then a validator adds it to the appropriate effects list
 
   addGroup("Casting Stage");
-  addField("castingDur",            TypeF32,        myOffset(mCasting_dur),
+  addFieldV("castingDur",            TypeRangedF32,        myOffset(mCasting_dur), &CommonValidators::PositiveFloat,
     "...");
-  addField("numCastingLoops",       TypeS32,        myOffset(mNum_casting_loops),
+  addFieldV("numCastingLoops",       TypeRangedS32,        myOffset(mNum_casting_loops), &CommonValidators::NaturalNumber,
     "...");
-  addField("extraCastingTime",      TypeF32,        myOffset(mExtra_casting_time),
+  addFieldV("extraCastingTime", TypeRangedF32,        myOffset(mExtra_casting_time), &CommonValidators::PositiveFloat,
     "...");
   addFieldV("addCastingEffect", TYPEID<afxEffectBaseData>(), Offset(mDummy_fx_entry, afxMagicSpellData), &_castingPhrase,
     "...");
   endGroup("Casting Stage");
 
   addGroup("Delivery Stage");
-  addField("deliveryDur",           TypeF32,        myOffset(mDelivery_dur),
+  addFieldV("deliveryDur", TypeRangedF32,        myOffset(mDelivery_dur), &CommonValidators::PositiveFloat,
     "...");
-  addField("numDeliveryLoops",      TypeS32,        myOffset(mNum_delivery_loops),
+  addFieldV("numDeliveryLoops", TypeRangedS32,        myOffset(mNum_delivery_loops), &CommonValidators::NaturalNumber,
     "...");
-  addField("extraDeliveryTime",     TypeF32,        myOffset(mExtra_delivery_time),
+  addFieldV("extraDeliveryTime", TypeRangedF32,        myOffset(mExtra_delivery_time), &CommonValidators::PositiveFloat,
     "...");
   addFieldV("addLaunchEffect", TYPEID<afxEffectBaseData>(), Offset(mDummy_fx_entry, afxMagicSpellData), &_launchPhrase,
     "...");
@@ -244,11 +244,11 @@ void afxMagicSpellData::initPersistFields()
   endGroup("Delivery Stage");
 
   addGroup("Linger Stage");
-  addField("lingerDur",             TypeF32,        myOffset(mLinger_dur),
+  addFieldV("lingerDur", TypeRangedF32,        myOffset(mLinger_dur), &CommonValidators::PositiveFloat,
     "...");
-  addField("numLingerLoops",        TypeS32,        myOffset(mNum_linger_loops),
+  addFieldV("numLingerLoops", TypeRangedS32,        myOffset(mNum_linger_loops), &CommonValidators::NaturalNumber,
     "...");
-  addField("extraLingerTime",       TypeF32,        myOffset(mExtra_linger_time),
+  addFieldV("extraLingerTime", TypeRangedF32,        myOffset(mExtra_linger_time), &CommonValidators::PositiveFloat,
     "...");
   addFieldV("addImpactEffect", TYPEID<afxEffectBaseData>(), Offset(mDummy_fx_entry, afxMagicSpellData), &_impactPhrase,
     "...");
@@ -259,7 +259,7 @@ void afxMagicSpellData::initPersistFields()
   // interrupt flags
   addField("allowMovementInterrupts", TypeBool,     myOffset(mDo_move_interrupts),
     "...");
-  addField("movementInterruptSpeed",  TypeF32,      myOffset(mMove_interrupt_speed),
+  addFieldV("movementInterruptSpeed", TypeRangedF32,      myOffset(mMove_interrupt_speed), &CommonValidators::PositiveFloat,
     "...");
 
   // delivers projectile spells

+ 9 - 9
Engine/source/afx/afxSelectron.cpp

@@ -153,17 +153,17 @@ void afxSelectronData::initPersistFields()
    static ewValidator _selectPhrase(SELECT_PHRASE);
    static ewValidator _deselectPhrase(DESELECT_PHRASE);
 
-  addField("mainDur",                   TypeF32,    myOffset(main_dur),
+  addFieldV("mainDur",                   TypeRangedF32,    myOffset(main_dur), &CommonValidators::PositiveFloat,
     "...");
-  addField("selectDur",                 TypeF32,    myOffset(select_dur),
+  addFieldV("selectDur",                 TypeRangedF32,    myOffset(select_dur), &CommonValidators::PositiveFloat,
     "...");
-  addField("deselectDur",               TypeF32,    myOffset(deselect_dur),
+  addFieldV("deselectDur",               TypeRangedF32,    myOffset(deselect_dur), &CommonValidators::PositiveFloat,
     "...");
-  addField("mainRepeats",               TypeS32,    myOffset(n_main_loops),
+  addFieldV("mainRepeats", TypeRangedS32,    myOffset(n_main_loops), &CommonValidators::NaturalNumber,
     "...");
-  addField("selectRepeats",             TypeS32,    myOffset(n_select_loops),
+  addFieldV("selectRepeats", TypeRangedS32,    myOffset(n_select_loops), &CommonValidators::NaturalNumber,
     "...");
-  addField("deselectRepeats",           TypeS32,    myOffset(n_deselect_loops),
+  addFieldV("deselectRepeats", TypeRangedS32,    myOffset(n_deselect_loops), &CommonValidators::NaturalNumber,
     "...");
   addField("selectionTypeMask",         TypeS32,    myOffset(obj_type_mask),
     "...");
@@ -180,11 +180,11 @@ void afxSelectronData::initPersistFields()
     "...");
 
   // deprecated
-  addField("numMainLoops",      TypeS32,      myOffset(n_main_loops),
+  addFieldV("numMainLoops", TypeRangedS32,      myOffset(n_main_loops), &CommonValidators::NaturalNumber,
     "...");
-  addField("numSelectLoops",    TypeS32,      myOffset(n_select_loops),
+  addFieldV("numSelectLoops", TypeRangedS32,      myOffset(n_select_loops), &CommonValidators::NaturalNumber,
     "...");
-  addField("numDeselectLoops",  TypeS32,      myOffset(n_deselect_loops),
+  addFieldV("numDeselectLoops", TypeRangedS32,      myOffset(n_deselect_loops), &CommonValidators::NaturalNumber,
     "...");
 
   Parent::initPersistFields();

+ 2 - 2
Engine/source/afx/ce/afxAnimClip.cpp

@@ -106,11 +106,11 @@ void afxAnimClipData::initPersistFields()
     "The name of an animation sequence to be played by a ShapeBase-derived object to which this effect is "
     "constrained. Also works on afxModel effects.\n"
     "default: \"\"\n");
-  addField("rate",              TYPEID< F32 >(),               myOffset(rate),                  
+  addFieldV("rate", TypeRangedF32,               myOffset(rate), &CommonValidators::F32Range,
     "The desired playback speed for the sequence. A value of 1.0 indicates forward playback at a normal rate. Negative "
     "values cause the sequence to play backwards.\n"
     "default: 1.0\n");
-  addField("posOffset",         TYPEID< F32 >(),               myOffset(pos_offset),
+  addFieldV("posOffset", TypeRangedF32,               myOffset(pos_offset), &CommonValidators::NormalizedFloat,
     "Sets a starting offset for the selected animation clip. It directly specifies an animation thread position in the 0.0 to "
     "1.0 range as a fraction of the clip's duration.\n"
     "default: 1.0\n");

+ 3 - 3
Engine/source/afx/ce/afxAreaDamage.cpp

@@ -79,13 +79,13 @@ void afxAreaDamageData::initPersistFields()
     "An arbitrary string which is passed as an argument to a spell's onDamage() script "
     "method. It is used to classify a type of damage such as 'melee', 'magical', or "
     "'fire'.");
-  addField("damage",                    TypeF32,        myOffset(amount),
+  addFieldV("damage", TypeRangedF32,        myOffset(amount), &CommonValidators::F32Range,
     "An amount of area damage to inflict on a target. Objects within half the radius "
     "receive full damage which then diminishes out to the full distance of the specified "
     "radius.");
-  addField("radius",                    TypeF32,        myOffset(radius),
+  addFieldV("radius", TypeRangedF32,        myOffset(radius), &CommonValidators::PositiveFloat,
     "Radius centered at the effect position in which damage will be applied.");
-  addField("impulse",                   TypeF32,        myOffset(impulse),
+  addFieldV("impulse", TypeRangedF32,        myOffset(impulse), &CommonValidators::F32Range,
     "Specifies an amount of force to apply to damaged objects. Objects within half the "
     "radius receive full impulse which then diminishes out to the full distance of the "
     "specified radius.");

+ 2 - 1
Engine/source/afx/ce/afxAudioBank.cpp

@@ -30,6 +30,7 @@
 #include "sfx/sfxDescription.h"
 
 #include "afx/ce/afxAudioBank.h"
+#include "console/typeValidators.h"
 
 //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 
@@ -133,7 +134,7 @@ void afxAudioBank::initPersistFields()
     "SFXDescription datablock to use with this set of sounds.");
   addField("preload",     TypeBool,                 Offset(mPreload, afxAudioBank),
     "If set to true, file is pre-loaded, otherwise it is loaded on-demand.");
-  addField("playIndex",   TypeS32,                  Offset(play_index, afxAudioBank),
+  addFieldV("playIndex", TypeRangedS32,                  Offset(play_index, afxAudioBank), &CommonValidators::NegDefaultInt,
     "An array index that selects a sound to play from the filenames[] field. Values "
     "outside of the range of assigned filename[] entries will not play any sound.");
 

+ 2 - 2
Engine/source/afx/ce/afxCameraShake.cpp

@@ -71,9 +71,9 @@ void afxCameraShakeData::initPersistFields()
     "The camera shake frequencies for all three axes: X, Y, Z.");
   addField("amplitude", TypePoint3F,   Offset(camShakeAmp,        afxCameraShakeData),
     "The camera shake amplitudes for all three axes: X, Y, Z.");
-  addField("radius",    TypeF32,       Offset(camShakeRadius,     afxCameraShakeData),
+  addFieldV("radius", TypeRangedF32,       Offset(camShakeRadius,     afxCameraShakeData), &CommonValidators::PositiveFloat,
     "Radius about the effect position in which shaking will be applied.");
-  addField("falloff",   TypeF32,       Offset(camShakeFalloff,    afxCameraShakeData),
+  addFieldV("falloff", TypeRangedF32,       Offset(camShakeFalloff,    afxCameraShakeData), &CommonValidators::PositiveFloat,
     "Magnitude by which shaking decreases over distance to radius.");
 
   Parent::initPersistFields();

+ 4 - 4
Engine/source/afx/ce/afxDamage.cpp

@@ -83,19 +83,19 @@ void afxDamageData::initPersistFields()
     "An arbitrary string which is passed as an argument to a spell's onDamage() script "
     "method. It is used to classify a type of damage such as 'melee', 'magical', or "
     "'fire'.");
-  addField("directDamage",        TypeF32,        myOffset(amount),
+  addFieldV("directDamage",        TypeRangedF32,        myOffset(amount), &CommonValidators::F32Range,
     "An amount of direct damage to inflict on a target.");
   addField("directDamageRepeats", TypeS8,         myOffset(repeats),
     "The number of times to inflict the damage specified by directDamage. Values "
     "greater than 1 inflict damage over time, with the amount of directDamage "
     "repeatedly dealt at evenly spaced intervals over the lifetime of the effect.");
-  addField("areaDamage",          TypeF32,        myOffset(ad_amount),
+  addFieldV("areaDamage", TypeRangedF32,        myOffset(ad_amount), &CommonValidators::F32Range,
     "An amount of area damage to inflict on a target. Objects within half the radius "
     "receive full damage which then diminishes out to the full distance of "
     "areaDamageRadius.");
-  addField("areaDamageRadius",    TypeF32,        myOffset(radius),
+  addFieldV("areaDamageRadius", TypeRangedF32,        myOffset(radius), &CommonValidators::PositiveFloat,
     "Radius centered at the effect position in which damage will be applied.");
-  addField("areaDamageImpulse",   TypeF32,        myOffset(impulse),
+  addFieldV("areaDamageImpulse", TypeRangedF32,        myOffset(impulse), &CommonValidators::F32Range,
     "Specifies an amount of force to apply to damaged objects. Objects within half the "
     "radius receive full impulse which then diminishes out to the full distance of "
     "areaDamageRadius.");

+ 5 - 5
Engine/source/afx/ce/afxLightBase_T3D.cpp

@@ -104,11 +104,11 @@ void afxT3DLightBaseData::initPersistFields()
         "Enables/Disables the object rendering and functionality in the scene.");
       addField( "color", TypeColorF, Offset( mColor, afxT3DLightBaseData ),
         "Changes the base color hue of the light.");
-      addField( "brightness", TypeF32, Offset( mBrightness, afxT3DLightBaseData ),
+      addFieldV( "brightness", TypeRangedF32, Offset( mBrightness, afxT3DLightBaseData ), &CommonValidators::PositiveFloat,
         "Adjusts the lights power, 0 being off completely.");
       addField( "castShadows", TypeBool, Offset( mCastShadows, afxT3DLightBaseData ),
         "Enables/disables shadow casts by this light.");
-      addField( "priority", TypeF32, Offset( mPriority, afxT3DLightBaseData ),
+      addFieldV( "priority", TypeRangedF32, Offset( mPriority, afxT3DLightBaseData ), &CommonValidators::PositiveFloat,
         "Used for sorting of lights by the light manager. Priority determines if a light "
         "has a stronger effect than, those with a lower value");
       addField( "localRenderViz", TypeBool, Offset( mLocalRenderViz, afxT3DLightBaseData ),
@@ -123,9 +123,9 @@ void afxT3DLightBaseData::initPersistFields()
         "Toggles animation for the light on and off");
       addField( "animationType", TYPEID<LightAnimData>(), Offset( mAnimationData, afxT3DLightBaseData ),
         "Datablock containing light animation information (LightAnimData)");
-      addField( "animationPeriod", TypeF32, Offset( mAnimState.animationPeriod, afxT3DLightBaseData ),
+      addFieldV( "animationPeriod", TypeRangedF32, Offset( mAnimState.animationPeriod, afxT3DLightBaseData ), &CommonValidators::PositiveFloat,
         "The length of time in seconds for a single playback of the light animation");
-      addField( "animationPhase", TypeF32, Offset( mAnimState.animationPhase, afxT3DLightBaseData ),
+      addFieldV( "animationPhase", TypeRangedF32, Offset( mAnimState.animationPhase, afxT3DLightBaseData ), &CommonValidators::PositiveFloat,
         "The phase used to offset the animation start time to vary the animation of "
         "nearby lights.");
 
@@ -135,7 +135,7 @@ void afxT3DLightBaseData::initPersistFields()
 
       addField( "flareType", TYPEID<LightFlareData>(), Offset( mFlareData, afxT3DLightBaseData ),
         "Datablock containing light flare information (LightFlareData)");
-      addField( "flareScale", TypeF32, Offset( mFlareScale, afxT3DLightBaseData ),
+      addFieldV( "flareScale", TypeRangedF32, Offset( mFlareScale, afxT3DLightBaseData ), &CommonValidators::PositiveFloat,
         "Globally scales all features of the light flare");
 
    endGroup( "Misc" );

+ 2 - 1
Engine/source/afx/ce/afxMachineGun.cpp

@@ -31,6 +31,7 @@
 #include "T3D/projectile.h"
 
 #include "afx/ce/afxMachineGun.h"
+#include "console/typeValidators.h"
 
 //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 // afxMachineGunData
@@ -68,7 +69,7 @@ void afxMachineGunData::initPersistFields()
    docsURL;
   addField("projectile", TYPEID<ProjectileData>(), myOffset(projectile_data),
     "A ProjectileData datablock describing the projectile to be launched.");
-  addField("roundsPerMinute", TypeS32, myOffset(rounds_per_minute),
+  addFieldV("roundsPerMinute", TypeRangedS32, myOffset(rounds_per_minute), &CommonValidators::PositiveInt,
     "Specifies the number of projectiles fired over a minute of time. A value of 1200 "
     "will create 20 projectiles per second.\n"
     "Sample values for real machine guns:\n"

+ 4 - 4
Engine/source/afx/ce/afxModel.cpp

@@ -180,18 +180,18 @@ void afxModelData::initPersistFields()
    addGroup("Animation");
       addField("sequence",              TypeString, myOffset(sequence),
          "The name of an animation sequence to play in the model.");
-      addField("sequenceRate",          TypeF32,      myOffset(seq_rate),
+      addFieldV("sequenceRate", TypeRangedF32,      myOffset(seq_rate), &CommonValidators::F32Range,
          "The rate of playback for the sequence.");
-      addField("sequenceOffset",        TypeF32,      myOffset(seq_offset),
+      addFieldV("sequenceOffset", TypeRangedF32,      myOffset(seq_offset), &CommonValidators::F32Range,
          "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 "
          "to convert from seconds to the thread offset.");
    endGroup("Animation");
 
    addGroup("Rendering");
-      addField("alphaMult",             TypeF32,      myOffset(alpha_mult),
+      addFieldV("alphaMult", TypeRangedF32,      myOffset(alpha_mult), &CommonValidators::PositiveFloat,
          "An alpha multiplier used to set maximum opacity of the model.");
-      addField("fogMult",               TypeF32,      myOffset(fog_mult), "");
+      addFieldV("fogMult", TypeRangedF32,      myOffset(fog_mult), &CommonValidators::PositiveFloat, "");
       addField("remapTextureTags",      TypeString,   myOffset(remap_txr_tags),
          "Rename one or more texture tags in the model. Texture tags are what link a "
          "model's textures to materials.\n"

+ 5 - 5
Engine/source/afx/ce/afxParticleEmitter.cpp

@@ -292,9 +292,9 @@ afxParticleEmitterConeData::afxParticleEmitterConeData(const afxParticleEmitterC
 void afxParticleEmitterConeData::initPersistFields()
 {
    docsURL;
-  addField("spreadMin",   TypeF32,    Offset(spread_min, afxParticleEmitterConeData),
+  addFieldV("spreadMin",   TypeRangedF32,    Offset(spread_min, afxParticleEmitterConeData), &CommonValidators::PosDegreeRangeHalf,
     "...");
-  addField("spreadMax",   TypeF32,    Offset(spread_max, afxParticleEmitterConeData),
+  addFieldV("spreadMax", TypeRangedF32,    Offset(spread_max, afxParticleEmitterConeData), &CommonValidators::PosDegreeRangeHalf,
     "...");
 
   Parent::initPersistFields();
@@ -416,7 +416,7 @@ void afxParticleEmitterPathData::initPersistFields()
     "...");
   addField("groundConformInteriors",  TypeBool, Offset(ground_conform_interiors,  afxParticleEmitterPathData),
     "...");
-  addField("groundConformHeight",     TypeF32,  Offset(ground_conform_height,     afxParticleEmitterPathData),
+  addFieldV("groundConformHeight",     TypeRangedF32,  Offset(ground_conform_height,     afxParticleEmitterPathData), &CommonValidators::PositiveFloat,
     "...");
 
   Parent::initPersistFields();
@@ -647,9 +647,9 @@ afxParticleEmitterDiscData::afxParticleEmitterDiscData(const afxParticleEmitterD
 void afxParticleEmitterDiscData::initPersistFields()
 {
    docsURL;
-  addField("radiusMin",   TypeF32,    Offset(pe_radius_min, afxParticleEmitterDiscData),
+  addFieldV("radiusMin",   TypeRangedF32,    Offset(pe_radius_min, afxParticleEmitterDiscData), &CommonValidators::PositiveFloat,
     "...");
-  addField("radiusMax",   TypeF32,    Offset(pe_radius_max, afxParticleEmitterDiscData),
+  addFieldV("radiusMax", TypeRangedF32,    Offset(pe_radius_max, afxParticleEmitterDiscData), &CommonValidators::PositiveFloat,
     "...");
 
   Parent::initPersistFields();

+ 2 - 2
Engine/source/afx/ce/afxPhraseEffect.cpp

@@ -140,11 +140,11 @@ EndImplementEnumType;
 void afxPhraseEffectData::initPersistFields()
 {
    docsURL;
-  addField("duration",    TypeF32,      myOffset(duration),
+  addFieldV("duration",    TypeRangedF32,      myOffset(duration), &CommonValidators::NegDefaultF32,
     "Specifies a duration for the phrase-effect. If set to infinity, the phrase-effect "
     "needs to have a phraseType of continuous. Set infinite duration using "
     "$AFX::INFINITE_TIME.");
-  addField("numLoops",    TypeS32,      myOffset(n_loops),
+  addFieldV("numLoops", TypeRangedS32,      myOffset(n_loops), &CommonValidators::NegDefaultInt,
     "Specifies the number of times the phrase-effect should loop. If set to infinity, "
     "the phrase-effect needs to have a phraseType of continuous. Set infinite looping "
     "using $AFX::INFINITE_REPEATS.");

+ 4 - 2
Engine/source/afx/ce/afxPhysicalZone.cpp

@@ -73,13 +73,15 @@ afxPhysicalZoneData::afxPhysicalZoneData(const afxPhysicalZoneData& other, bool
 
 #define myOffset(field) Offset(field, afxPhysicalZoneData)
 
+FRangeValidator afxVelocityModRange(-40.0f, 40.0f);
+FRangeValidator afxGravityModRange(-40.0f, 40.0f);
 void afxPhysicalZoneData::initPersistFields()
 {
    docsURL;
-  addField("velocityMod",               TypeF32,         myOffset(mVelocityMod),
+  addFieldV("velocityMod", TypeRangedF32,         myOffset(mVelocityMod), &afxVelocityModRange,
     "A multiplier that biases the velocity of an object every tick it is within the "
     "zone.");
-  addField("gravityMod",                TypeF32,         myOffset(mGravityMod),
+  addFieldV("gravityMod", TypeRangedF32,         myOffset(mGravityMod), &afxGravityModRange,
     "A multiplier that biases the influence of gravity on objects within the zone.");
   addField("appliedForce",              TypePoint3F,     myOffset(mAppliedForce),
     "A three-valued vector representing a directional force applied to objects withing "

+ 1 - 1
Engine/source/afx/ce/afxPlayerMovement.cpp

@@ -81,7 +81,7 @@ EndImplementEnumType;
 void afxPlayerMovementData::initPersistFields()
 {
    docsURL;
-  addField("speedBias",     TypeF32,        myOffset(speed_bias),
+  addFieldV("speedBias",     TypeRangedF32,        myOffset(speed_bias), &CommonValidators::F32Range,
     "A floating-point multiplier that scales the constraint Player's movement speed.");
   addField("movement",      TypePoint3F,    myOffset(movement),
     "");

+ 1 - 1
Engine/source/afx/ce/afxPointLight_T3D.cpp

@@ -65,7 +65,7 @@ void afxT3DPointLightData::initPersistFields()
    docsURL;
    addGroup( "Light" );
       
-      addField( "radius", TypeF32, Offset( mRadius, afxT3DPointLightData ),
+      addFieldV( "radius", TypeRangedF32, Offset( mRadius, afxT3DPointLightData ), &CommonValidators::PositiveFloat,
         "Controls the falloff of the light emission");
 
    endGroup( "Light" );

+ 3 - 3
Engine/source/afx/ce/afxSpotLight_T3D.cpp

@@ -69,11 +69,11 @@ void afxT3DSpotLightData::initPersistFields()
    docsURL;
    addGroup( "Light" );
       
-      addField( "range", TypeF32, Offset( mRange, afxT3DSpotLightData ),
+      addFieldV( "range", TypeRangedF32, Offset( mRange, afxT3DSpotLightData ), &CommonValidators::PositiveFloat,
         "...");
-      addField( "innerAngle", TypeF32, Offset( mInnerConeAngle, afxT3DSpotLightData ),
+      addFieldV( "innerAngle", TypeRangedF32, Offset( mInnerConeAngle, afxT3DSpotLightData ), &CommonValidators::DegreeRangeQuarter,
         "...");
-      addField( "outerAngle", TypeF32, Offset( mOuterConeAngle, afxT3DSpotLightData ),
+      addFieldV( "outerAngle", TypeRangedF32, Offset( mOuterConeAngle, afxT3DSpotLightData ), &CommonValidators::DegreeRangeQuarter,
         "...");
 
    endGroup( "Light" );

+ 10 - 10
Engine/source/afx/ce/afxZodiac.cpp

@@ -158,7 +158,7 @@ void afxZodiacData::initPersistFields()
 {
    docsURL;
    INITPERSISTFIELD_IMAGEASSET(Texture, afxZodiacData, "An image to use as the zodiac's texture.");
-  addField("radius",                TypeF32,        Offset(radius_xy,         afxZodiacData),
+  addFieldV("radius",                TypeRangedF32,        Offset(radius_xy,         afxZodiacData), &CommonValidators::PositiveFloat,
     "The zodiac's radius in scene units.");
   addField("verticalRange",         TypePoint2F,    Offset(vert_range,        afxZodiacData),
     "For interior zodiacs only, verticalRange specifies distances above and below the "
@@ -167,18 +167,18 @@ void afxZodiacData::initPersistFields()
     "Specifies if the zodiac's verticalRange should scale according to changes in the "
     "radius. When a zodiacs is used as an expanding shockwave, this value should be set "
     "to false, otherwise the zodiac can expand to cover an entire interior.");
-  addField("startAngle",            TypeF32,        Offset(start_ang,         afxZodiacData),
+  addFieldV("startAngle", TypeRangedF32,        Offset(start_ang,         afxZodiacData), &CommonValidators::DegreeRange,
     "The starting angle in degrees of the zodiac's rotation.");
-  addField("rotationRate",          TypeF32,        Offset(ang_per_sec,       afxZodiacData),
+  addFieldV("rotationRate", TypeRangedF32,        Offset(ang_per_sec,       afxZodiacData), &CommonValidators::DegreeRange,
     "The rate of rotation in degrees-per-second. Zodiacs with a positive rotationRate "
     "rotate clockwise, while those with negative values turn counter-clockwise.");
-  addField("growInTime",            TypeF32,        Offset(grow_in_time,      afxZodiacData),
+  addFieldV("growInTime", TypeRangedF32,        Offset(grow_in_time,      afxZodiacData), &CommonValidators::PositiveFloat,
     "A duration of time in seconds over which the zodiac grows from a zero size to its "
     "full size as specified by the radius.");
-  addField("shrinkOutTime",         TypeF32,        Offset(shrink_out_time,   afxZodiacData),
+  addFieldV("shrinkOutTime", TypeRangedF32,        Offset(shrink_out_time,   afxZodiacData), &CommonValidators::PositiveFloat,
     "A duration of time in seconds over which the zodiac shrinks from full size to "
     "invisible.");
-  addField("growthRate",            TypeF32,        Offset(growth_rate,       afxZodiacData),
+  addFieldV("growthRate", TypeRangedF32,        Offset(growth_rate,       afxZodiacData), &CommonValidators::F32Range,
     "A rate in meters-per-second at which the zodiac grows in size. A negative value will "
     "shrink the zodiac.");
   addField("color",                 TypeColorF,     Offset(color,             afxZodiacData),
@@ -215,20 +215,20 @@ void afxZodiacData::initPersistFields()
   addField("interiorIgnoreTransparent", TypeBool,   Offset(interior_transp_ignore, afxZodiacData),
     "");
 
-  addField("altitudeMax",           TypeF32,      Offset(altitude_max, afxZodiacData),
+  addFieldV("altitudeMax", TypeRangedF32,      Offset(altitude_max, afxZodiacData), &CommonValidators::F32Range,
     "The altitude at which zodiac becomes invisible as the result of fading out or "
     "becoming too small.");
-  addField("altitudeFalloff",       TypeF32,      Offset(altitude_falloff, afxZodiacData),
+  addFieldV("altitudeFalloff", TypeRangedF32,      Offset(altitude_falloff, afxZodiacData), &CommonValidators::F32Range,
     "The altitude at which zodiac begins to fade and/or shrink.");
   addField("altitudeShrinks",       TypeBool,     Offset(altitude_shrinks, afxZodiacData),
     "When true, zodiac becomes smaller as altitude increases.");
   addField("altitudeFades",         TypeBool,     Offset(altitude_fades, afxZodiacData),
     "When true, zodiac fades out as altitude increases.");
 
-  addField("distanceMax",           TypeF32,      Offset(distance_max, afxZodiacData),
+  addFieldV("distanceMax", TypeRangedF32,      Offset(distance_max, afxZodiacData), &CommonValidators::PositiveFloat,
     "The distance from camera at which the zodiac becomes invisible as the result of "
     "fading out.");
-  addField("distanceFalloff",       TypeF32,      Offset(distance_falloff, afxZodiacData),
+  addFieldV("distanceFalloff", TypeRangedF32,      Offset(distance_falloff, afxZodiacData), &CommonValidators::PositiveFloat,
     "The distance from camera at which the zodiac begins to fade out.");
 
   addField("useGradientRange",      TypeBool,     Offset(use_grade_range, afxZodiacData),

+ 6 - 6
Engine/source/afx/ce/afxZodiacPlane.cpp

@@ -114,20 +114,20 @@ void afxZodiacPlaneData::initPersistFields()
    docsURL;
    INITPERSISTFIELD_IMAGEASSET(Texture, afxZodiacPlaneData, "An image to use as the zodiac's texture.");
 
-  addField("radius",          TypeF32,        myOffset(radius_xy),
+  addFieldV("radius", TypeRangedF32,        myOffset(radius_xy), &CommonValidators::PositiveFloat,
     "The zodiac's radius in scene units.");
-  addField("startAngle",      TypeF32,        myOffset(start_ang),
+  addFieldV("startAngle", TypeRangedF32,        myOffset(start_ang), &CommonValidators::DegreeRange,
     "The starting angle in degrees of the zodiac's rotation.");
-  addField("rotationRate",    TypeF32,        myOffset(ang_per_sec),
+  addFieldV("rotationRate", TypeRangedF32,        myOffset(ang_per_sec), &CommonValidators::DegreeRange,
     "The rate of rotation in degrees-per-second. Zodiacs with a positive rotationRate "
     "rotate clockwise, while those with negative values turn counter-clockwise.");
-  addField("growInTime",      TypeF32,        myOffset(grow_in_time),
+  addFieldV("growInTime", TypeRangedF32,        myOffset(grow_in_time), &CommonValidators::PositiveFloat,
     "A duration of time in seconds over which the zodiac grows from a zero size to its "
     "full size as specified by the radius.");
-  addField("shrinkOutTime",   TypeF32,        myOffset(shrink_out_time),
+  addFieldV("shrinkOutTime", TypeRangedF32,        myOffset(shrink_out_time), &CommonValidators::PositiveFloat,
     "A duration of time in seconds over which the zodiac shrinks from full size to "
     "invisible.");
-  addField("growthRate",      TypeF32,        myOffset(growth_rate),
+  addFieldV("growthRate", TypeRangedF32,        myOffset(growth_rate), &CommonValidators::F32Range,
     "A rate in meters-per-second at which the zodiac grows in size. A negative value will "
     "shrink the zodiac.");
   addField("color",           TypeColorF,     myOffset(color),

+ 1 - 1
Engine/source/afx/ea/afxEA_Zodiac.cpp

@@ -399,7 +399,7 @@ void afxEA_Zodiac::initPersistFields()
    docsURL;
   addField("liveColor",         TypeColorF,     myOffset(live_color),
     "...");
-  addField("liveColorFactor",   TypeF32,        myOffset(live_color_factor),
+  addFieldV("liveColorFactor",   TypeRangedF32,        myOffset(live_color_factor), &CommonValidators::PositiveFloat,
     "...");
 
   Parent::initPersistFields();

+ 2 - 2
Engine/source/afx/forces/afxF_Drag.cpp

@@ -103,9 +103,9 @@ afxF_DragData::afxF_DragData(const afxF_DragData& other, bool temp_clone) : afxF
 void afxF_DragData::initPersistFields()
 {
    docsURL;
-  addField("drag",                TypeF32,      myOffset(drag_coefficient),
+  addFieldV("drag",                TypeRangedF32,      myOffset(drag_coefficient), &CommonValidators::PositiveNonZeroFloat,
     "...");
-  addField("airDensity",          TypeF32,      myOffset(air_density),
+  addFieldV("airDensity", TypeRangedF32,      myOffset(air_density), &CommonValidators::PositiveNonZeroFloat,
     "...");
   addField("crossSectionalArea",  TypeF32,      myOffset(cross_sectional_area),
     "...");

+ 1 - 1
Engine/source/afx/forces/afxF_Gravity.cpp

@@ -95,7 +95,7 @@ afxF_GravityData::afxF_GravityData(const afxF_GravityData& other, bool temp_clon
 void afxF_GravityData::initPersistFields()
 {
    docsURL;
-  addField("gravity",   TypeF32,     myOffset(gravity),
+  addFieldV("gravity", TypeRangedF32,     myOffset(gravity), &CommonValidators::F32Range,
     "...");
 
   Parent::initPersistFields();

+ 3 - 3
Engine/source/afx/rpg/afxRPGMagicSpell.cpp

@@ -91,9 +91,9 @@ void afxRPGMagicSpellData::initPersistFields()
   addField("target", TYPEID< afxRPGMagicSpellData::TargetType >(), myOffset(spell_target),
     "...");
 
-  addField("range",             TypeF32,        myOffset(spell_range),
+  addFieldV("range",             TypeRangedF32,        myOffset(spell_range), &CommonValidators::PositiveFloat,
     "...");
-  addField("manaCost",          TypeS32,        myOffset(mana_cost),
+  addFieldV("manaCost",          TypeRangedS32,        myOffset(mana_cost), &CommonValidators::PositiveInt,
     "...");
   addField("reagentCost",       TypeS8,         myOffset(reagent_cost), MAX_REAGENTS_PER_SPELL,
     "...");
@@ -101,7 +101,7 @@ void afxRPGMagicSpellData::initPersistFields()
     "...");
 
   // spell phase timing
-  addField("castingDur",        TypeF32,        myOffset(casting_dur));
+  addFieldV("castingDur", TypeRangedF32,        myOffset(casting_dur), &CommonValidators::PositiveFloat);
 
   // interface elements
   addField("iconBitmap",        TypeFilename,   myOffset(icon_name));

+ 2 - 2
Engine/source/afx/ui/afxGuiTextHud.cpp

@@ -75,9 +75,9 @@ void afxGuiTextHud::initPersistFields()
     "...");
    addField( "showFrame",  TypeBool, Offset( mShowFrame, afxGuiTextHud ),
     "...");
-   addField( "verticalOffset", TypeF32, Offset( mVerticalOffset, afxGuiTextHud  ),
+   addFieldV( "verticalOffset", TypeRangedF32, Offset( mVerticalOffset, afxGuiTextHud  ), &CommonValidators::F32Range,
     "...");
-   addField( "distanceFade", TypeF32, Offset( mDistanceFade, afxGuiTextHud ),
+   addFieldV( "distanceFade", TypeRangedF32, Offset( mDistanceFade, afxGuiTextHud ), &CommonValidators::PositiveFloat,
     "...");
    addField( "labelAllShapes",  TypeBool, Offset( mLabelAllShapes, afxGuiTextHud ),
     "...");

+ 1 - 1
Engine/source/afx/util/afxParticlePool.cpp

@@ -75,7 +75,7 @@ void afxParticlePoolData::initPersistFields()
     "...");
   addField("baseColor",   TypeColorF,  Offset(base_color,   afxParticlePoolData),
     "...");
-  addField("blendWeight", TypeF32,     Offset(blend_weight, afxParticlePoolData),
+  addFieldV("blendWeight", TypeRangedF32,     Offset(blend_weight, afxParticlePoolData), &CommonValidators::PositiveFloat,
     "...");
 
   Parent::initPersistFields();

+ 4 - 4
Engine/source/afx/util/afxPath.cpp

@@ -151,13 +151,13 @@ void afxPathData::initPersistFields()
     "...");
   addField("loop",       TypeString,  Offset(loop_string,   afxPathData),
     "...");
-  addField("mult",       TypeF32,     Offset(mult,          afxPathData),
+  addFieldV("mult", TypeRangedF32,     Offset(mult,          afxPathData), &CommonValidators::F32Range,
     "...");
-  addField("delay",      TypeF32,     Offset(delay,         afxPathData),
+  addFieldV("delay", TypeRangedF32,     Offset(delay,         afxPathData), &CommonValidators::PositiveFloat,
     "...");
-  addField("lifetime",   TypeF32,     Offset(lifetime,      afxPathData),
+  addFieldV("lifetime",   TypeRangedF32,     Offset(lifetime,      afxPathData), &CommonValidators::PositiveFloat,
     "...");
-  addField("timeOffset", TypeF32,     Offset(time_offset,   afxPathData),
+  addFieldV("timeOffset", TypeRangedF32,     Offset(time_offset,   afxPathData), &CommonValidators::F32Range,
     "...");
   addField("reverse",    TypeBool,    Offset(reverse,       afxPathData),
     "...");

+ 1 - 1
Engine/source/afx/xm/afxXM_AltitudeConform.cpp

@@ -109,7 +109,7 @@ afxXM_AltitudeConformData::afxXM_AltitudeConformData(const afxXM_AltitudeConform
 void afxXM_AltitudeConformData::initPersistFields()
 {
    docsURL;
-  addField("height",              TypeF32,      Offset(height, afxXM_AltitudeConformData),
+  addFieldV("height",              TypeRangedF32,      Offset(height, afxXM_AltitudeConformData), &CommonValidators::F32Range,
     "...");
   addField("conformToTerrain",    TypeBool,     Offset(do_terrain, afxXM_AltitudeConformData),
     "...");

+ 1 - 1
Engine/source/afx/xm/afxXM_BoxAdapt.cpp

@@ -99,7 +99,7 @@ afxXM_BoxAdaptData::afxXM_BoxAdaptData(const afxXM_BoxAdaptData& other, bool tem
 void afxXM_BoxAdaptData::initPersistFields()
 {
    docsURL;
-  addField("scaleFactor",     TypeF32,        Offset(scale_factor, afxXM_BoxAdaptData),
+  addFieldV("scaleFactor",     TypeRangedF32,        Offset(scale_factor, afxXM_BoxAdaptData), &CommonValidators::PositiveFloat,
     "...");
   addField("dimensionRange",  TypePoint2F,    Offset(dim_range, afxXM_BoxAdaptData),
     "...");

+ 1 - 1
Engine/source/afx/xm/afxXM_Freeze.cpp

@@ -163,7 +163,7 @@ void afxXM_FreezeData::initPersistFields()
    docsURL;
   addField("mask",  TypeS32,    Offset(mask, afxXM_FreezeData),
     "...");
-  addField("delay", TypeF32,    Offset(delay, afxXM_FreezeData),
+  addFieldV("delay", TypeRangedF32,    Offset(delay, afxXM_FreezeData), &CommonValidators::PositiveFloat,
     "...");
 
   Parent::initPersistFields();

+ 1 - 1
Engine/source/afx/xm/afxXM_GroundConform.cpp

@@ -101,7 +101,7 @@ afxXM_GroundConformData::afxXM_GroundConformData(const afxXM_GroundConformData&
 void afxXM_GroundConformData::initPersistFields()
 {
    docsURL;
-  addField("height",              TypeF32,      Offset(height, afxXM_GroundConformData),
+  addFieldV("height", TypeRangedF32,      Offset(height, afxXM_GroundConformData), &CommonValidators::F32Range,
     "...");
   addField("conformToTerrain",    TypeBool,     Offset(do_terrain, afxXM_GroundConformData),
     "...");

+ 1 - 1
Engine/source/afx/xm/afxXM_Oscillate.cpp

@@ -166,7 +166,7 @@ void afxXM_OscillateData::initPersistFields()
     "...");
   addField("max",                 TypePoint3F,  Offset(max,   afxXM_OscillateData),
     "...");
-  addField("speed",               TypeF32,      Offset(speed, afxXM_OscillateData),
+  addFieldV("speed",               TypeRangedF32,      Offset(speed, afxXM_OscillateData), &CommonValidators::PositiveFloat,
     "...");
   addField("axis",                TypePoint3F,  Offset(axis,  afxXM_OscillateData),
     "...");

+ 1 - 1
Engine/source/afx/xm/afxXM_OscillateZodiacColor.cpp

@@ -94,7 +94,7 @@ void afxXM_OscillateZodiacColorData::initPersistFields()
     "...");
   addField("colorB",              TypeColorF,   Offset(color_b,   afxXM_OscillateZodiacColorData),
     "...");
-  addField("speed",               TypeF32,      Offset(speed, afxXM_OscillateZodiacColorData),
+  addFieldV("speed",               TypeRangedF32,      Offset(speed, afxXM_OscillateZodiacColorData), &CommonValidators::PositiveFloat,
     "...");
 
   Parent::initPersistFields();

+ 4 - 4
Engine/source/afx/xm/afxXM_RandomRot.cpp

@@ -109,13 +109,13 @@ void afxXM_RandomRotData::initPersistFields()
    docsURL;
   addField("axis",      TypePoint3F,  Offset(axis, afxXM_RandomRotData),
     "...");
-  addField("thetaMin",  TypeF32,      Offset(theta_min, afxXM_RandomRotData),
+  addFieldV("thetaMin", TypeRangedF32,      Offset(theta_min, afxXM_RandomRotData), &CommonValidators::PosDegreeRangeHalf,
     "...");
-  addField("thetaMax",  TypeF32,      Offset(theta_max, afxXM_RandomRotData),
+  addFieldV("thetaMax", TypeRangedF32,      Offset(theta_max, afxXM_RandomRotData), &CommonValidators::PosDegreeRangeHalf,
     "...");
-  addField("phiMin",    TypeF32,      Offset(phi_min, afxXM_RandomRotData),
+  addFieldV("phiMin", TypeRangedF32,      Offset(phi_min, afxXM_RandomRotData), &CommonValidators::PosDegreeRange,
     "...");
-  addField("phiMax",    TypeF32,      Offset(phi_max, afxXM_RandomRotData),
+  addFieldV("phiMax", TypeRangedF32,      Offset(phi_max, afxXM_RandomRotData), &CommonValidators::PosDegreeRange,
     "...");
 
   Parent::initPersistFields();

+ 1 - 1
Engine/source/afx/xm/afxXM_Shockwave.cpp

@@ -103,7 +103,7 @@ afxXM_ShockwaveData::afxXM_ShockwaveData(const afxXM_ShockwaveData& other, bool
 void afxXM_ShockwaveData::initPersistFields()
 {
    docsURL;
-  addField("rate",      TypeF32,      Offset(rate, afxXM_ShockwaveData),
+  addFieldV("rate",      TypeRangedF32,      Offset(rate, afxXM_ShockwaveData), &CommonValidators::PositiveFloat,
     "...");
   addField("aimZOnly",  TypeBool,     Offset(aim_z_only, afxXM_ShockwaveData),
     "...");

+ 4 - 4
Engine/source/afx/xm/afxXM_Spin.cpp

@@ -122,13 +122,13 @@ void afxXM_SpinData::initPersistFields()
    docsURL;
   addField("spinAxis",            TypePoint3F,  Offset(spin_axis, afxXM_SpinData),
     "...");
-  addField("spinAngle",           TypeF32,      Offset(spin_angle, afxXM_SpinData),
+  addFieldV("spinAngle",           TypeRangedF32,      Offset(spin_angle, afxXM_SpinData), &CommonValidators::DegreeRange,
     "...");
-  addField("spinAngleVariance",   TypeF32,      Offset(spin_angle_var, afxXM_SpinData),
+  addFieldV("spinAngleVariance", TypeRangedF32,      Offset(spin_angle_var, afxXM_SpinData), &CommonValidators::DegreeRange,
     "...");
-  addField("spinRate",            TypeF32,      Offset(spin_rate, afxXM_SpinData),
+  addFieldV("spinRate", TypeRangedF32,      Offset(spin_rate, afxXM_SpinData), &CommonValidators::DegreeRange,
     "...");
-  addField("spinRateVariance",    TypeF32,      Offset(spin_rate_var, afxXM_SpinData),
+  addFieldV("spinRateVariance", TypeRangedF32,      Offset(spin_rate_var, afxXM_SpinData), &CommonValidators::DegreeRange,
     "...");
 
   Parent::initPersistFields();

+ 1 - 1
Engine/source/afx/xm/afxXM_VelocityOffset.cpp

@@ -166,7 +166,7 @@ afxXM_VelocityOffsetData::afxXM_VelocityOffsetData(const afxXM_VelocityOffsetDat
 void afxXM_VelocityOffsetData::initPersistFields()
 {
    docsURL;
-  addField("offsetFactor",    TypeF32,      Offset(offset_factor, afxXM_VelocityOffsetData),
+  addFieldV("offsetFactor",    TypeRangedF32,      Offset(offset_factor, afxXM_VelocityOffsetData), &CommonValidators::F32Range,
     "...");
   addField("offsetPos2",      TypeBool,     Offset(offset_pos2, afxXM_VelocityOffsetData),
     "...");

+ 9 - 9
Engine/source/afx/xm/afxXM_WaveBase.cpp

@@ -151,28 +151,28 @@ void afxXM_WaveBaseData::initPersistFields()
   addField("op",            TYPEID< afxXM_WaveBaseData::WaveOpType >(),    Offset(op, afxXM_WaveBaseData),
     "...");
 
-  addField("speed",         TypeF32,      Offset(speed, afxXM_WaveBaseData), 
+  addFieldV("speed",         TypeRangedF32,      Offset(speed, afxXM_WaveBaseData), &CommonValidators::PositiveFloat,
     "waves per second");
-  addField("speedVariance", TypeF32,      Offset(speed_vari, afxXM_WaveBaseData),
+  addFieldV("speedVariance", TypeRangedF32,      Offset(speed_vari, afxXM_WaveBaseData), &CommonValidators::PositiveFloat,
     "...");
-  addField("acceleration",  TypeF32,      Offset(accel, afxXM_WaveBaseData),
+  addFieldV("acceleration", TypeRangedF32,      Offset(accel, afxXM_WaveBaseData), &CommonValidators::PositiveFloat,
     "...");
-  addField("phaseShift",    TypeF32,      Offset(phase_shift, afxXM_WaveBaseData),
+  addFieldV("phaseShift", TypeRangedF32,      Offset(phase_shift, afxXM_WaveBaseData), &CommonValidators::PositiveFloat,
     "...");
-  addField("dutyCycle",     TypeF32,      Offset(duty_cycle, afxXM_WaveBaseData),
+  addFieldV("dutyCycle", TypeRangedF32,      Offset(duty_cycle, afxXM_WaveBaseData), &CommonValidators::PositiveFloat,
     "...");
-  addField("dutyShift",     TypeF32,      Offset(duty_shift, afxXM_WaveBaseData),
+  addFieldV("dutyShift", TypeRangedF32,      Offset(duty_shift, afxXM_WaveBaseData), &CommonValidators::PositiveFloat,
     "...");
-  addField("offDutyT",      TypeF32,      Offset(off_duty_t, afxXM_WaveBaseData),
+  addFieldV("offDutyT", TypeRangedF32,      Offset(off_duty_t, afxXM_WaveBaseData), &CommonValidators::PositiveFloat,
     "...");
 
   addField("wavesPerPulse", TypeByteRange2,      Offset(waves_per_pulse, afxXM_WaveBaseData),
     "...");
   addField("wavesPerRest",  TypeByteRange2,      Offset(waves_per_rest, afxXM_WaveBaseData),
     "...");
-  addField("restDuration",          TypeF32,      Offset(rest_dur, afxXM_WaveBaseData),
+  addFieldV("restDuration", TypeRangedF32,      Offset(rest_dur, afxXM_WaveBaseData), &CommonValidators::PositiveFloat,
     "...");
-  addField("restDurationVariance",  TypeF32,      Offset(rest_dur_vari, afxXM_WaveBaseData),
+  addFieldV("restDurationVariance", TypeRangedF32,      Offset(rest_dur_vari, afxXM_WaveBaseData), &CommonValidators::PositiveFloat,
     "...");
 
   addField("axis",          TypePoint3F,  Offset(axis, afxXM_WaveBaseData),

+ 5 - 5
Engine/source/afx/xm/afxXfmMod.cpp

@@ -215,19 +215,19 @@ F32 afxXM_WeightedBaseData::getWeightFactor() const
 void afxXM_WeightedBaseData::initPersistFields()
 {
    docsURL;
-  addField("delay",         TypeF32,      Offset(delay,         afxXM_WeightedBaseData),
+  addFieldV("delay", TypeRangedF32,      Offset(delay,         afxXM_WeightedBaseData), &CommonValidators::PositiveFloat,
     "...");
-  addField("lifetime",      TypeF32,      Offset(lifetime,      afxXM_WeightedBaseData),
+  addFieldV("lifetime",      TypeRangedF32,      Offset(lifetime,      afxXM_WeightedBaseData), &CommonValidators::PositiveFloat,
     "...");
-  addField("fadeInTime",    TypeF32,      Offset(fade_in_time,  afxXM_WeightedBaseData),
+  addFieldV("fadeInTime", TypeRangedF32,      Offset(fade_in_time,  afxXM_WeightedBaseData), &CommonValidators::PositiveFloat,
     "...");
-  addField("fadeOutTime",   TypeF32,      Offset(fade_out_time, afxXM_WeightedBaseData),
+  addFieldV("fadeOutTime", TypeRangedF32,      Offset(fade_out_time, afxXM_WeightedBaseData), &CommonValidators::PositiveFloat,
     "...");
   addField("fadeInEase",    TypePoint2F,  Offset(fadein_ease,   afxXM_WeightedBaseData),
     "...");
   addField("fadeOutEase",   TypePoint2F,  Offset(fadeout_ease,  afxXM_WeightedBaseData),
     "...");
-  addField("lifetimeBias",  TypeF32,      Offset(life_bias,     afxXM_WeightedBaseData),
+  addFieldV("lifetimeBias", TypeRangedF32,      Offset(life_bias,     afxXM_WeightedBaseData), &CommonValidators::F32Range,
     "...");
 
   Parent::initPersistFields();

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

@@ -174,22 +174,22 @@ void VolumetricFog::initPersistFields()
    addGroup("VolumetricFogData");
    addField("FogColor", TypeColorI, Offset(mFogColor, VolumetricFog),
       "Fog color RGBA (Alpha is ignored)");
-   addField("FogDensity", TypeF32, Offset(mFogDensity, VolumetricFog), 
+   addFieldV("FogDensity", TypeRangedF32, Offset(mFogDensity, VolumetricFog), &CommonValidators::PositiveFloat,
       "Overal fog density value (0 disables the fog).");
    addField("IgnoreWater", TypeBool, Offset(mIgnoreWater, VolumetricFog), 
       "Set to true if volumetric fog should continue while submerged.");
-   addField("MinSize", TypeF32, Offset(mMinDisplaySize, VolumetricFog), 
+   addFieldV("MinSize", TypeRangedF32, Offset(mMinDisplaySize, VolumetricFog), &CommonValidators::PositiveFloat,
       "Min size (in pixels) for fog to be rendered.");
-   addField("FadeSize", TypeF32, Offset(mFadeSize, VolumetricFog), 
+   addFieldV("FadeSize", TypeRangedF32, Offset(mFadeSize, VolumetricFog), &CommonValidators::PositiveFloat,
       "Object size in pixels at which the FX-fading kicks in (0 disables fading).");
    endGroup("VolumetricFogData");
 
    addGroup("VolumetricFogModulation");
    INITPERSISTFIELD_IMAGEASSET(Texture, VolumetricFog, "A texture which contains Fogdensity modulator in the red channel and color with 1-green channel. No texture disables modulation.");
 
-   addField("tiles", TypeF32, Offset(mTexTiles, VolumetricFog), 
+   addFieldV("tiles", TypeRangedF32, Offset(mTexTiles, VolumetricFog), &CommonValidators::PositiveFloat,
       "How many times the texture is mapped to the object.");
-   addField("modStrength", TypeF32, Offset(mStrength, VolumetricFog),
+   addFieldV("modStrength", TypeRangedF32, Offset(mStrength, VolumetricFog), &CommonValidators::PositiveFloat,
       "Overall strength of the density modulation (0 disables modulation).");
    addField("PrimSpeed", TypePoint2F, Offset(mSpeed1, VolumetricFog),
       "Overall primary speed of the density modulation (x-speed(u) y-speed(v))");
@@ -200,18 +200,18 @@ void VolumetricFog::initPersistFields()
    addGroup("Reflections");
    addField("Reflectable", TypeBool, Offset(mReflect, VolumetricFog), 
       "Set to true if volumetric fog should be reflected.");
-   addField("ReflectStrength", TypeF32, Offset(mFogReflStrength, VolumetricFog), 
+   addFieldV("ReflectStrength", TypeRangedF32, Offset(mFogReflStrength, VolumetricFog), &CommonValidators::NormalizedFloat,
       "Strength of the reflections (0 disables the fog).");
    endGroup("Reflections");
 
    addGroup("PostFX");
    addField("useGlow", TypeBool, Offset(mUseGlow, VolumetricFog), 
       "Set to true if volumetric fog should use glow PostFX.");
-   addField("glowStrength", TypeF32, Offset(mGlowStrength, VolumetricFog),
+   addFieldV("glowStrength", TypeRangedF32, Offset(mGlowStrength, VolumetricFog), &CommonValidators::PositiveFloat,
       "Overall strength of the glow PostFX.");
    addField("modLightRay", TypeBool, Offset(mModifLightRays, VolumetricFog), 
       "Set to true if volumetric fog should modify the brightness of the Lightrays.");
-   addField("lightRayMod", TypeF32, Offset(mLightRayMod, VolumetricFog),
+   addFieldV("lightRayMod", TypeRangedF32, Offset(mLightRayMod, VolumetricFog), &CommonValidators::PositiveFloat,
       "Modifier for LightRay PostFX when inside Fog.");
    endGroup("PostFX");
 }

+ 3 - 3
Engine/source/environment/basicClouds.cpp

@@ -179,19 +179,19 @@ void BasicClouds::initPersistFields()
 
          INITPERSISTFIELD_IMAGEASSET_ARRAY(Texture, TEX_COUNT, BasicClouds, "Texture for this layer.");
 
-         addField( "texScale", TypeF32, Offset( mTexScale, BasicClouds ), TEX_COUNT,
+         addFieldV( "texScale", TypeRangedF32, Offset( mTexScale, BasicClouds ), &CommonValidators::PositiveFloat, TEX_COUNT,
             "Texture repeat for this layer." );
 
          addField( "texDirection", TypePoint2F, Offset( mTexDirection, BasicClouds ), TEX_COUNT,
             "Texture scroll direction for this layer, relative to the world axis." );
 
-         addField( "texSpeed", TypeF32, Offset( mTexSpeed, BasicClouds ), TEX_COUNT,
+         addFieldV( "texSpeed", TypeRangedF32, Offset( mTexSpeed, BasicClouds ), &CommonValidators::PositiveFloat, TEX_COUNT,
             "Texture scroll speed for this layer." );   
 
          addField( "texOffset", TypePoint2F, Offset( mTexOffset, BasicClouds ), TEX_COUNT,
             "UV offset for this layer." );
 
-         addField( "height", TypeF32, Offset( mHeight, BasicClouds ), TEX_COUNT,
+         addFieldV( "height", TypeRangedF32, Offset( mHeight, BasicClouds ), &CommonValidators::F32Range, TEX_COUNT,
             "Abstract number which controls the curvature and height of the dome mesh" );
 
       endArray( "Layers" );      

+ 6 - 6
Engine/source/environment/cloudLayer.cpp

@@ -198,13 +198,13 @@ void CloudLayer::initPersistFields()
       
       addArray( "Textures", TEX_COUNT );
 
-         addField( "texScale", TypeF32, Offset( mTexScale, CloudLayer ), TEX_COUNT,
+         addFieldV( "texScale", TypeRangedF32, Offset( mTexScale, CloudLayer ), &CommonValidators::PositiveFloat, TEX_COUNT,
             "Controls the texture repeat of this slot." );
 
          addField( "texDirection", TypePoint2F, Offset( mTexDirection, CloudLayer ), TEX_COUNT,
             "Controls the direction this slot scrolls." );
 
-         addField( "texSpeed", TypeF32, Offset( mTexSpeed, CloudLayer ), TEX_COUNT,
+         addFieldV( "texSpeed", TypeRangedF32, Offset( mTexSpeed, CloudLayer ), &CommonValidators::PositiveFloat, TEX_COUNT,
             "Controls the speed this slot scrolls." );
 
       endArray( "Textures" );
@@ -212,16 +212,16 @@ void CloudLayer::initPersistFields()
       addField( "baseColor", TypeColorF, Offset( mBaseColor, CloudLayer ),
          "Base cloud color before lighting." );
 
-      addField( "exposure", TypeF32, Offset( mExposure, CloudLayer ),
+      addFieldV( "exposure", TypeRangedF32, Offset( mExposure, CloudLayer ), &CommonValidators::PositiveFloat,
          "Brightness scale so CloudLayer can be overblown if desired." );
       
-      addField( "coverage", TypeF32, Offset( mCoverage, CloudLayer ),
+      addFieldV( "coverage", TypeRangedF32, Offset( mCoverage, CloudLayer ), &CommonValidators::NormalizedFloat,
          "Fraction of sky covered by clouds 0-1." );
 
-      addField( "windSpeed", TypeF32, Offset( mWindSpeed, CloudLayer ),
+      addFieldV( "windSpeed", TypeRangedF32, Offset( mWindSpeed, CloudLayer ), &CommonValidators::NormalizedFloat,
          "Overall scalar to texture scroll speed." );
 
-      addField( "height", TypeF32, Offset( mHeight, CloudLayer ),
+      addFieldV( "height", TypeRangedF32, Offset( mHeight, CloudLayer ), &CommonValidators::F32Range,
          "Abstract number which controls the curvature and height of the dome mesh." );
 
    endGroup( "CloudLayer" );

Неке датотеке нису приказане због велике количине промена