VPath.cpp

Engine/source/Verve/VPath/VPath.cpp

More...

Public Functions

DefineEngineFunction(getServerPathSet , S32 , () , "( void )" )
DefineEngineMethod(VPath , addNode , void , (TransformF transform, F32 weight, S32 location) , (MatrixF::Identity, 1.0, -1) , "( transform pTransform, float pWeight, [int pLocation] ) - Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> node with the given properties. Nodes represent physical points that attached objects move towards or between, but the PathType determines \"how\" they move between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">them.\n</a>" "@param pTransform The position and rotation of the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pWeight The weight of the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pLocation The index of the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , deleteNode , void , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Delete the node with the given index. If you delete <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> node that an attached object is moving to, or from then the object 's movement will adjust so that it has <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> valid <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" " @param pNodeIndex The index of the node <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">deleted.\n</a>" " @return No return value." )
DefineEngineMethod(VPath , detachObject , void , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Detach the object from this path in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">place.\n</a>" "@param pObject The SimObjectID of the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">detached.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , getNodeCount , S32 , () , "() - Get the number of nodes in this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" "@return Returns the number of nodes." )
DefineEngineMethod(VPath , getNodeLength , F32 , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the length of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the length of the given node." )
DefineEngineMethod(VPath , getNodeLocalPosition , Point3F , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the position of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" " @return Returns the Local Position of the given node." )
DefineEngineMethod(VPath , getNodeLocalRotation , AngAxisF , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the Local Rotation of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the Local Rotation of the given node." )
DefineEngineMethod(VPath , getNodeLocalTransform , const char * , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the local transform (local position and rotation) of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the transform of the given node." )
DefineEngineMethod(VPath , getNodeOrientationMode , const char * , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Gets the current orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> string indicating the orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> and its properties." )
DefineEngineMethod(VPath , getNodeWeight , F32 , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the weight of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the weight of the given node." )
DefineEngineMethod(VPath , getNodeWorldPosition , Point3F , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the position of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> Position of the given node." )
DefineEngineMethod(VPath , getNodeWorldRotation , AngAxisF , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> Rotation of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> Rotation of the given node." )
DefineEngineMethod(VPath , getNodeWorldTransform , TransformF , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> Transform (position and rotation) of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the transform of the given node." )
DefineEngineMethod(VPath , getPathObjectEndNode , S32 , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get the index of the node this object is meant <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> stop upon <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reaching.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the node index." )
DefineEngineMethod(VPath , getPathObjectInterp , F32 , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get the current interp position of the path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the current interp position." )
DefineEngineMethod(VPath , getPathObjectNode , S32 , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Gets the last node of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the node index." )
DefineEngineMethod(VPath , getPathObjectOffset , const char * , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get the position offset assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the position offset." )
DefineEngineMethod(VPath , getPathObjectOrientationMode , const char * , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Gets the current orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> string indicating the orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> and its properties." )
DefineEngineMethod(VPath , getPathObjectSpeed , F32 , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get the speed this object is traveling along the path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">at.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the speed of the object." )
DefineEngineMethod(VPath , getPathPosition , const char * , (S32 srcNodeIndex, S32 dstNodeIndex, F32 timeInterp) , (0, 0, 1.0) , "( int pSrcNodeIndex, int pDstNodeIndex, int pTimeInterp ) - Get the world position of the path at the interp point between two <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">nodes.\n</a>" "@param pSrcNodeIndex The first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pDstNodeIndex The second <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pTimeInterp The time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> interp between the two nodes. <a href="/coding/file/document_8h/#document_8h_1a071cf97155ba72ac9a1fc4ad7e63d481">Value</a> is between 0.0 and 1.0.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns the world position of the interp time between the two given nodes." )
DefineEngineMethod(VPath , getPathTransform , const char * , (S32 srcNodeIndex, S32 dstNodeIndex, F32 timeInterp) , (0, 0, 1.0) , "( int pSrcNodeIndex, int pDstNodeIndex, float pTimeInterp ) - Get the transform of the path at the interp point between two <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">nodes.\n</a>" "@param pSrcNodeIndex The first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pDstNodeIndex The second <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pTimeInterp The time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> interp between the two nodes. <a href="/coding/file/document_8h/#document_8h_1a071cf97155ba72ac9a1fc4ad7e63d481">Value</a> is between 0.0 and 1.0.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns the transform of the interp time between the two given nodes." )
DefineEngineMethod(VPath , isObjectAttached , bool , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Is the object attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this path?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param pObject The SimObjectID of the object you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the object is attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this path." )
DefineEngineMethod(VPath , isPathObjectActive , bool , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Is the object actively traveling around this path?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns true of the object is active." )
DefineEngineMethod(VPath , isPathObjectForward , bool , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> this object is traveling forwards along the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the object is traveling forwards." )
DefineEngineMethod(VPath , setNodePosition , void , (S32 nodeIndex, Point3F position) , (0, Point3F::Zero) , "( int pNodeIndex, vector pPosition ) - Set the position of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pPosition The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be applied <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , setNodeRotation , void , (S32 nodeIndex, AngAxisF aa) , (0, AngAxisF()) , "( int pNodeIndex, angAxis pRotation ) - Set the rotation of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pRotation The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> rotation <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be applied <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , setNodeTransform , void , (S32 nodeIndex, TransformF transform) , (0, MatrixF::Identity) , "( int pNodeIndex, matrix pTransform ) - Set the transform of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pTransform The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> transform <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be applied <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , setNodeWeight , void , (S32 nodeIndex, F32 nodeWeight) , (0, 1.0) , "( int pNodeIndex, float pWeight ) - Set the weight of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pWeight The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> weight <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be applied <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , setPathObjectActive , void , (SceneObject *sceneObject, bool isActive) , (nullAsType< SceneObject * >(), true) , "( SimObject pObject, bool pActive ) - Enable or disable the object from traveling around this path. Inactive objects are still attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the path, but are not <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">updated.\n</a>" " @param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" " @param pActive The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> status of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" " @return No return value." )
DefineEngineMethod(VPath , setPathObjectEndNode , void , (SceneObject *sceneObject, S32 nodeIndex) , (nullAsType< SceneObject * >(), 0) , "( SimObject pObject, bool pNodeIndex ) - Set end node of the path object. If <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> of \"-1\" is applied, the object will path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">indefinitely.\n</a>" " @param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" " @param pNodeIndex The index of the node that the object will cease pathing upon <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reaching.\n</a>" " @return No return value." )
DefineEngineMethod(VPath , setPathObjectForward , void , (SceneObject *sceneObject, bool forward) , (nullAsType< SceneObject * >(), true) , "( SimObject pObject, bool pForward ) - Set the travel direction of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pForward The direction of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , setPathObjectInterp , void , (SceneObject *sceneObject, F32 timeInterp) , (nullAsType< SceneObject * >(), 1.0) , "( SimObject pObject, float pTimeInterp ) - Set the interp position of the object between its current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">nodes.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pTimeInterp The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> interp position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , setPathObjectNode , void , (SceneObject *sceneObject, S32 nodeIndex) , (nullAsType< SceneObject * >(), 0) , "( SimObject pObject, bool pNodeIndex ) - <a href="/coding/class/structmove/">Move</a> the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the node's position. You may also want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> observe the \"setPathObjectInterp\" method.\n" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pNodeIndex The index of the node that the object will reposition <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , setPathObjectOffset , void , (SceneObject *sceneObject, Point3F offset) , (nullAsType< SceneObject * >(), Point3F::Zero) , "( SimObject pObject, vector pOffset ) - Set the position offset of the object. As the object is moving along the path, its position is offset by this value. Setting the \"Relative\" parameter <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a0e48c1f64b558d03d870367324920354">while</a> attaching an object will automatically apply an offset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pOffset The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> position offset of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , setPathObjectSpeed , void , (SceneObject *sceneObject, F32 speed) , (nullAsType< SceneObject * >(), 1.0) , "( SimObject pObject, float pSpeed ) - Set the speed of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pSpeed The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return No return value." )
DefineEngineMethod(VPath , setPathType , void , (String pathType) , ("LINEAR") , "( string pPathType ) - The path type dictates how attached objects move between nodes. There are currently two supported path types, \"BEZIER\" and \"LINEAR\".\n" "@return No return value." )
DefineEngineStringlyVariadicMethod(VPath , attachObject , void , 7 , 8 , "( SimObject pObject, bool pForward, float pSpeed, bool pRelative, int pStartNode, [int pEndNode] ) - Attach an object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this path with the given properties. If the object is already attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> path, then <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> warning will be displayed and the object will *not *be attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" " @param pObject The SimObjectID of the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">attached.\n</a>" " @param pForward Should the object be moving forward?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @param pSpeed The speed that the object will travel around the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" " @param pRelative <a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a660d8e8336a58d3d6950e2a638583056">Offset</a> the object based on the difference between the start node and its current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position.\n</a>" " @param pStartNode The index of the node this object starts pathing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from.\n</a>" " @param pEndNode The index of the node this object will stop pathing at." " @return No return value." )
DefineEngineStringlyVariadicMethod(VPath , setNodeOrientationMode , void , 4 , 5 , "( int pNodeIndex, string pOrientationType, [vector pPoint] ) - Set the orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pOrientationType The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> orientation type of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pPoint If the orientation type is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> POINT, this parameter must be <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">vector.\n</a>" " @return No return value." )
DefineEngineStringlyVariadicMethod(VPath , setPathObjectOrientationMode , void , 4 , 5 , "( SimObject pObject, string pOrientationType, [<a href="/coding/class/classsimobject/">SimObject</a> pObject / vector pPoint] ) - Set the orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> of the object. This property affects the rotation of the object. If you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> ignore the object's rotation altogether, set the <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> \"FREE\".\n" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pOrientationType The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> orientation type of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject If the orientation type is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> OBJECT, this parameter must be the SimObjectID of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" " @param pPoint If the orientation type is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> POINT, this parameter must be <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">vector.\n</a>" " @return No return value." )

Detailed Description

Public Variables

 EndImplementEnumType 
F32 gBezierInterpStep 
U32 gPathTypeBits 

Public Functions

DefineEngineFunction(getServerPathSet , S32 , () , "( void )" )

DefineEngineMethod(VPath , addNode , void , (TransformF transform, F32 weight, S32 location) , (MatrixF::Identity, 1.0, -1) , "( transform pTransform, float pWeight, [int pLocation] ) - Add <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> node with the given properties. Nodes represent physical points that attached objects move towards or between, but the PathType determines \"how\" they move between <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">them.\n</a>" "@param pTransform The position and rotation of the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pWeight The weight of the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pLocation The index of the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , deleteNode , void , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Delete the node with the given index. If you delete <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> node that an attached object is moving to, or from then the object 's movement will adjust so that it has <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> valid <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" " @param pNodeIndex The index of the node <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">deleted.\n</a>" " @return No return value." )

DefineEngineMethod(VPath , detachObject , void , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Detach the object from this path in <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">place.\n</a>" "@param pObject The SimObjectID of the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">detached.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , getNodeCount , S32 , () , "() - Get the number of nodes in this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" "@return Returns the number of nodes." )

DefineEngineMethod(VPath , getNodeLength , F32 , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the length of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the length of the given node." )

DefineEngineMethod(VPath , getNodeLocalPosition , Point3F , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the position of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" " @return Returns the Local Position of the given node." )

DefineEngineMethod(VPath , getNodeLocalRotation , AngAxisF , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the Local Rotation of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the Local Rotation of the given node." )

DefineEngineMethod(VPath , getNodeLocalTransform , const char * , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the local transform (local position and rotation) of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the transform of the given node." )

DefineEngineMethod(VPath , getNodeOrientationMode , const char * , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Gets the current orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> string indicating the orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> and its properties." )

DefineEngineMethod(VPath , getNodeWeight , F32 , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the weight of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the weight of the given node." )

DefineEngineMethod(VPath , getNodeWorldPosition , Point3F , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the position of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> Position of the given node." )

DefineEngineMethod(VPath , getNodeWorldRotation , AngAxisF , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> Rotation of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> Rotation of the given node." )

DefineEngineMethod(VPath , getNodeWorldTransform , TransformF , (S32 nodeIndex) , (0) , "( int pNodeIndex ) - Get the <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a81f4537631c9ab219ec74de554483adc">World</a> Transform (position and rotation) of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return Returns the transform of the given node." )

DefineEngineMethod(VPath , getPathObjectEndNode , S32 , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get the index of the node this object is meant <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> stop upon <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reaching.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the node index." )

DefineEngineMethod(VPath , getPathObjectInterp , F32 , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get the current interp position of the path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the current interp position." )

DefineEngineMethod(VPath , getPathObjectNode , S32 , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Gets the last node of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the node index." )

DefineEngineMethod(VPath , getPathObjectOffset , const char * , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get the position offset assigned <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the position offset." )

DefineEngineMethod(VPath , getPathObjectOrientationMode , const char * , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Gets the current orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> string indicating the orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> and its properties." )

DefineEngineMethod(VPath , getPathObjectSpeed , F32 , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get the speed this object is traveling along the path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">at.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns the speed of the object." )

DefineEngineMethod(VPath , getPathPosition , const char * , (S32 srcNodeIndex, S32 dstNodeIndex, F32 timeInterp) , (0, 0, 1.0) , "( int pSrcNodeIndex, int pDstNodeIndex, int pTimeInterp ) - Get the world position of the path at the interp point between two <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">nodes.\n</a>" "@param pSrcNodeIndex The first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pDstNodeIndex The second <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pTimeInterp The time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> interp between the two nodes. <a href="/coding/file/document_8h/#document_8h_1a071cf97155ba72ac9a1fc4ad7e63d481">Value</a> is between 0.0 and 1.0.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns the world position of the interp time between the two given nodes." )

DefineEngineMethod(VPath , getPathTransform , const char * , (S32 srcNodeIndex, S32 dstNodeIndex, F32 timeInterp) , (0, 0, 1.0) , "( int pSrcNodeIndex, int pDstNodeIndex, float pTimeInterp ) - Get the transform of the path at the interp point between two <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">nodes.\n</a>" "@param pSrcNodeIndex The first <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pDstNodeIndex The second <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pTimeInterp The time <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> interp between the two nodes. <a href="/coding/file/document_8h/#document_8h_1a071cf97155ba72ac9a1fc4ad7e63d481">Value</a> is between 0.0 and 1.0.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@return Returns the transform of the interp time between the two given nodes." )

DefineEngineMethod(VPath , isObjectAttached , bool , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Is the object attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this path?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param pObject The SimObjectID of the object you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">check.\n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the object is attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this path." )

DefineEngineMethod(VPath , isPathObjectActive , bool , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Is the object actively traveling around this path?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns true of the object is active." )

DefineEngineMethod(VPath , isPathObjectForward , bool , (SceneObject *sceneObject) , (nullAsType< SceneObject * >()) , "( SimObject pObject ) - Get <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> this object is traveling forwards along the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">observed.\n</a>" "@return Returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> the object is traveling forwards." )

DefineEngineMethod(VPath , setNodePosition , void , (S32 nodeIndex, Point3F position) , (0, Point3F::Zero) , "( int pNodeIndex, vector pPosition ) - Set the position of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pPosition The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> position <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be applied <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , setNodeRotation , void , (S32 nodeIndex, AngAxisF aa) , (0, AngAxisF()) , "( int pNodeIndex, angAxis pRotation ) - Set the rotation of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pRotation The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> rotation <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be applied <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , setNodeTransform , void , (S32 nodeIndex, TransformF transform) , (0, MatrixF::Identity) , "( int pNodeIndex, matrix pTransform ) - Set the transform of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pTransform The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> transform <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be applied <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , setNodeWeight , void , (S32 nodeIndex, F32 nodeWeight) , (0, 1.0) , "( int pNodeIndex, float pWeight ) - Set the weight of the given <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pWeight The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> weight <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be applied <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , setPathObjectActive , void , (SceneObject *sceneObject, bool isActive) , (nullAsType< SceneObject * >(), true) , "( SimObject pObject, bool pActive ) - Enable or disable the object from traveling around this path. Inactive objects are still attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the path, but are not <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">updated.\n</a>" " @param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" " @param pActive The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> status of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" " @return No return value." )

DefineEngineMethod(VPath , setPathObjectEndNode , void , (SceneObject *sceneObject, S32 nodeIndex) , (nullAsType< SceneObject * >(), 0) , "( SimObject pObject, bool pNodeIndex ) - Set end node of the path object. If <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/pointer_8h/#pointer_8h_1a32aff7c6c4cd253fdf6563677afab5ce">value</a> of \"-1\" is applied, the object will path <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">indefinitely.\n</a>" " @param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" " @param pNodeIndex The index of the node that the object will cease pathing upon <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">reaching.\n</a>" " @return No return value." )

DefineEngineMethod(VPath , setPathObjectForward , void , (SceneObject *sceneObject, bool forward) , (nullAsType< SceneObject * >(), true) , "( SimObject pObject, bool pForward ) - Set the travel direction of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pForward The direction of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , setPathObjectInterp , void , (SceneObject *sceneObject, F32 timeInterp) , (nullAsType< SceneObject * >(), 1.0) , "( SimObject pObject, float pTimeInterp ) - Set the interp position of the object between its current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">nodes.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pTimeInterp The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> interp position of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , setPathObjectNode , void , (SceneObject *sceneObject, S32 nodeIndex) , (nullAsType< SceneObject * >(), 0) , "( SimObject pObject, bool pNodeIndex ) - <a href="/coding/class/structmove/">Move</a> the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the node's position. You may also want <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> observe the \"setPathObjectInterp\" method.\n" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pNodeIndex The index of the node that the object will reposition <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">to.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , setPathObjectOffset , void , (SceneObject *sceneObject, Point3F offset) , (nullAsType< SceneObject * >(), Point3F::Zero) , "( SimObject pObject, vector pOffset ) - Set the position offset of the object. As the object is moving along the path, its position is offset by this value. Setting the \"Relative\" parameter <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a0e48c1f64b558d03d870367324920354">while</a> attaching an object will automatically apply an offset <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">value.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pOffset The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> position offset of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , setPathObjectSpeed , void , (SceneObject *sceneObject, F32 speed) , (nullAsType< SceneObject * >(), 1.0) , "( SimObject pObject, float pSpeed ) - Set the speed of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pSpeed The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@return No return value." )

DefineEngineMethod(VPath , setPathType , void , (String pathType) , ("LINEAR") , "( string pPathType ) - The path type dictates how attached objects move between nodes. There are currently two supported path types, \"BEZIER\" and \"LINEAR\".\n" "@return No return value." )

DefineEngineStringlyVariadicMethod(VPath , attachObject , void , 7 , 8 , "( SimObject pObject, bool pForward, float pSpeed, bool pRelative, int pStartNode, [int pEndNode] ) - Attach an object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this path with the given properties. If the object is already attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> path, then <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> warning will be displayed and the object will *not *be attached <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> this <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" " @param pObject The SimObjectID of the object <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">attached.\n</a>" " @param pForward Should the object be moving forward?\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @param pSpeed The speed that the object will travel around the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">path.\n</a>" " @param pRelative <a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a660d8e8336a58d3d6950e2a638583056">Offset</a> the object based on the difference between the start node and its current <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">position.\n</a>" " @param pStartNode The index of the node this object starts pathing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from.\n</a>" " @param pEndNode The index of the node this object will stop pathing at." " @return No return value." )

DefineEngineStringlyVariadicMethod(VPath , setNodeOrientationMode , void , 4 , 5 , "( int pNodeIndex, string pOrientationType, [vector pPoint] ) - Set the orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pNodeIndex The index of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">node.\n</a>" "@param pOrientationType The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> orientation type of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pPoint If the orientation type is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> POINT, this parameter must be <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">vector.\n</a>" " @return No return value." )

DefineEngineStringlyVariadicMethod(VPath , setPathObjectOrientationMode , void , 4 , 5 , "( SimObject pObject, string pOrientationType, [<a href="/coding/class/classsimobject/">SimObject</a> pObject / vector pPoint] ) - Set the orientation <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> of the object. This property affects the rotation of the object. If you wish <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> ignore the object's rotation altogether, set the <a href="/coding/file/zipobject_8cpp/#zipobject_8cpp_1ac6c3dfb4c3a68f849f32cbfb21da4e77">mode</a> <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> \"FREE\".\n" "@param pObject The SimObjectID of the object being <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">altered.\n</a>" "@param pOrientationType The <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> orientation type of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" "@param pObject If the orientation type is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> OBJECT, this parameter must be the SimObjectID of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object.\n</a>" " @param pPoint If the orientation type is set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> POINT, this parameter must be <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">vector.\n</a>" " @return No return value." )

getPathTypeEnum(const char * pLabel)

IMPLEMENT_CO_NETOBJECT_V1(VPath )

ImplementEnumType(VPathType , "" )

   1
   2//-----------------------------------------------------------------------------
   3// Verve
   4// Copyright (C) 2014 - Violent Tulip
   5//
   6// Permission is hereby granted, free of charge, to any person obtaining a copy
   7// of this software and associated documentation files (the "Software"), to
   8// deal in the Software without restriction, including without limitation the
   9// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  10// sell copies of the Software, and to permit persons to whom the Software is
  11// furnished to do so, subject to the following conditions:
  12//
  13// The above copyright notice and this permission notice shall be included in
  14// all copies or substantial portions of the Software.
  15//
  16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  22// IN THE SOFTWARE.
  23//-----------------------------------------------------------------------------
  24#include "VPath.h"
  25
  26#include "console/consoleTypes.h"
  27#include "core/iTickable.h"
  28#include "core/stream/bitStream.h"
  29#include "math/mMathFn.h"
  30#include "math/mathIO.h"
  31#include "math/mTransform.h"
  32
  33//-----------------------------------------------------------------------------
  34
  35// Uncomment this definition to debug the network information.
  36//#define VPATH_DEBUG_NET
  37
  38// Uncomment this definition to debug the time step information
  39//#define VPATH_DEBUG_STEP
  40
  41//-----------------------------------------------------------------------------
  42
  43SimObjectPtr<SimSet> VPath::gServerSet         = NULL;
  44
  45U32                  VPath::gMaxNodeTransmit   = 16;
  46U32                  VPath::gMaxNodeBits       = 8;
  47U32                  VPath::gMaxNodeCount      = 1 << gMaxNodeBits;      // 256
  48
  49U32                  VPath::gMaxObjectTransmit = 4;
  50U32                  VPath::gMaxObjectBits     = 4;
  51U32                  VPath::gMaxObjectCount    = 1 << gMaxObjectBits;     // 16
  52
  53Point3F              VPath::gBezierAxis( 0.f, 1.f, 0.f );
  54Point3F              VPath::gBezierUp( 0.f, 0.f, 1.f );
  55
  56//-----------------------------------------------------------------------------
  57
  58static U32           gPathTypeBits     = getBinLog2( getNextPow2( VPath::k_PathTypeSize ) );
  59static F32           gBezierInterpStep = 0.0001f;
  60
  61//-----------------------------------------------------------------------------
  62// Path Type Table.
  63//-----------------------------------------------------------------------------
  64
  65// Implement the Path Type enum list.
  66ImplementEnumType( VPathType, "" )
  67    { VPath::k_PathBezier,   "BEZIER" },
  68    { VPath::k_PathLinear,   "LINEAR" },
  69EndImplementEnumType;
  70
  71static VPath::ePathType getPathTypeEnum( const char *pLabel )
  72{
  73    VPath::ePathType out;
  74    if ( !castConsoleTypeFromString( out, pLabel ) )
  75    {
  76        // Bah!
  77        return VPath::k_PathInvalid;
  78    }
  79
  80    // Return.
  81    return out;
  82}
  83
  84//-----------------------------------------------------------------------------
  85IMPLEMENT_CO_NETOBJECT_V1( VPath );
  86//-----------------------------------------------------------------------------
  87
  88VPath::VPath( void ) :
  89        mPathType( k_PathBezier )
  90{
  91    // Marker Type.
  92    mTypeMask = MarkerObjectType;
  93
  94    // Ghost & Scope.
  95    mNetFlags.set( Ghostable | ScopeAlways );
  96
  97    // Process Ticks.
  98    setProcessTick( true );
  99
 100    VECTOR_SET_ASSOCIATION( mNodeList );
 101    VECTOR_SET_ASSOCIATION( mObjectList );
 102}
 103
 104VPath::~VPath( void )
 105{
 106    // Void.
 107}
 108
 109bool VPath::onAdd( void )
 110{
 111    if ( !Parent::onAdd() )
 112    {
 113        return false;
 114    }
 115
 116    // Add to Scene.
 117    addToScene();
 118
 119    if ( isServerObject() )
 120    {
 121        // Read Fields.
 122        readFields();
 123
 124        // Add to Set.
 125        getServerSet()->addObject( this );   
 126    }
 127
 128    return true;
 129}
 130
 131void VPath::onDeleteNotify( SimObject *pObject )
 132{
 133    // Parent Notify.
 134    Parent::onDeleteNotify( pObject );
 135
 136    if ( SceneObject *sceneObject = dynamic_cast<SceneObject*>( pObject ) )
 137    {
 138        // Detach Object.
 139        detachObject( sceneObject );
 140
 141        // Exit.
 142        return;
 143    }
 144
 145    if ( NetConnection *connection = dynamic_cast<NetConnection*>( pObject ) )
 146    {
 147        // Clear Connection References.
 148        for ( VPathObjectIterator itr = mObjectList.begin(); itr != mObjectList.end(); itr++ )
 149        {
 150            // Erase Connection.
 151            ( *itr )->clearConnection( connection );
 152        }
 153
 154        // Exit.
 155        return;
 156    }
 157}
 158
 159void VPath::onRemove( void )
 160{
 161    // Remove From Scene.
 162    removeFromScene();
 163
 164    // Clear Everything.
 165    clear();
 166
 167    Parent::onRemove();
 168}
 169
 170void VPath::initPersistFields( void )
 171{
 172    Parent::initPersistFields();
 173
 174    addProtectedField( "PathType", TYPEID<ePathType>(), Offset( mPathType, VPath ), &setPathType, &defaultProtectedGetFn, "The type of path this is." );
 175}
 176
 177SimSet *VPath::getServerSet( void )
 178{
 179    if ( !gServerSet )
 180    {
 181        gServerSet = new SimSet();
 182        gServerSet->registerObject( "ServerPathSet" );
 183        Sim::getRootGroup()->addObject( gServerSet );
 184    }
 185
 186    return gServerSet;
 187}
 188
 189DefineEngineFunction( getServerPathSet, S32, (),, "( void )" )
 190{
 191    return VPath::getServerSet()->getId();
 192}
 193
 194//-----------------------------------------------------------------------------
 195//
 196// Editor Methods.
 197//
 198//-----------------------------------------------------------------------------
 199
 200bool VPath::collideBox( const Point3F &pStart, const Point3F &pEnd, RayInfo* pInfo )
 201{
 202    if ( mObjBox.isContained( pStart ) )
 203    {
 204        pInfo->t        = 0.f;
 205        pInfo->object   = this;
 206        pInfo->normal   = VectorF( 0.f, 0.f, 1.f );
 207        pInfo->material = NULL;
 208
 209        return true;
 210    }
 211
 212    return Parent::collideBox( pStart, pEnd, pInfo );
 213}
 214
 215//-----------------------------------------------------------------------------
 216//
 217// Update Methods.
 218//
 219//-----------------------------------------------------------------------------
 220
 221F32 VPath::getUpdatePriority( CameraScopeQuery *pFocusObject, U32 pUpdateMask, S32 pUpdateSkips )
 222{
 223    if ( mObjectList.size() > 0 )
 224    {
 225        for ( VPathObjectIterator itr = mObjectList.begin(); itr != mObjectList.end(); itr++ )
 226        {
 227            // Fetch Object.
 228            VPathObject *pathObject = ( *itr );
 229            if ( pathObject->isActive() )
 230            {
 231                // High Priority.
 232                return 100.f;
 233            }
 234        }
 235    }
 236
 237    // Normal Priority.
 238    return 0.f;
 239}
 240
 241void VPath::updateContainer( void )
 242{
 243    if ( mNodeList.size() == 0 )
 244    {
 245        // Sanity!.
 246        return;
 247    }
 248
 249    // Init Min / Max.
 250    mObjBox.minExtents = ( mNodeList[0]->getLocalPosition() );
 251    mObjBox.maxExtents = mObjBox.minExtents;
 252
 253    for ( VPathNodeIterator itr = mNodeList.begin(); itr != mNodeList.end(); itr++ )
 254    {
 255        // Fetch Node.
 256        VPathNode *node = ( *itr );
 257
 258        // Node Position.
 259        const Point3F &nodeLocalPosition = node->getLocalPosition();
 260
 261        // Update Object Box.
 262        mObjBox.minExtents.setMin( nodeLocalPosition );
 263        mObjBox.maxExtents.setMax( nodeLocalPosition );
 264    }
 265
 266    // Adjust.
 267    mObjBox.minExtents -= Point3F( 1.f, 1.f, 1.f );
 268    mObjBox.maxExtents += Point3F( 1.f, 1.f, 1.f );
 269
 270    // Reset Box.
 271    resetWorldBox();
 272    resetRenderWorldBox();
 273}
 274
 275void VPath::updateNodeTransforms( void )
 276{
 277    // Fetch Transform Details.
 278    const MatrixF &pathTransform = getTransform();
 279    const QuatF   &pathRotation( pathTransform );
 280    const VectorF &pathScale     = getScale();
 281
 282    for ( VPathNodeIterator itr = mNodeList.begin(); itr != mNodeList.end(); itr++ )
 283    {
 284        // Fetch Node.
 285        VPathNode *node = ( *itr );
 286
 287        // Fetch Node Spatials.
 288        const Point3F &nodePosition = node->getLocalPosition();
 289        const QuatF   &nodeRotation = node->getLocalRotation();
 290
 291        // Calculate the new Position.
 292        Point3F newPosition = nodePosition;
 293        newPosition.convolve( pathScale );
 294        pathTransform.mulP( newPosition );
 295
 296        // Calculate the new Rotation.
 297        QuatF newRotation;
 298        newRotation.mul( nodeRotation, pathRotation );
 299
 300        // Apply.
 301        node->setWorldPosition( newPosition );
 302        node->setWorldRotation( newRotation );
 303    }
 304}
 305
 306void VPath::setTransform( const MatrixF &pMatrix )
 307{
 308    // Parent Call.
 309    Parent::setTransform( pMatrix );
 310
 311    // Update Nodes.
 312    updateNodeTransforms();
 313
 314    if ( isServerObject() )
 315    {
 316        // Update Path.
 317        setMaskBits( PathUpdateMask );
 318    }
 319}
 320
 321void VPath::setScale( const VectorF &pScale )
 322{
 323    // Parent Call.
 324    Parent::setScale( pScale );
 325
 326    // Update Nodes.
 327    updateNodeTransforms();
 328
 329    if ( isServerObject() )
 330    {
 331        // Update Path.
 332        setMaskBits( PathUpdateMask );
 333    }
 334}
 335
 336DefineEngineMethod( VPath, setPathType, void, (String pathType), ("LINEAR"), "( string pPathType ) - The path type dictates how attached objects move between nodes. There are currently two supported path types, \"BEZIER\" and \"LINEAR\".\n"
 337                                               "@return No return value." )
 338{
 339    // Fetch Enum.
 340    const VPath::ePathType &type = getPathTypeEnum(pathType);
 341
 342    // Update.
 343    object->setPathType( type );
 344}
 345
 346void VPath::setPathType( const ePathType &pType )
 347{
 348    // Apply Value.
 349    mPathType = pType;
 350
 351    // Calculate Path.
 352    calculatePath();
 353
 354    if ( isServerObject() )
 355    {
 356        // Update Path.
 357        setMaskBits( PathUpdateMask );
 358    }
 359}
 360
 361bool VPath::setPathType( void *pObject, const char *pArray, const char *pData )
 362{
 363    // Apply Type.
 364    static_cast<VPath*>( pObject )->setPathType( getPathTypeEnum( pData ) );
 365    return false;
 366}
 367
 368//-----------------------------------------------------------------------------
 369//
 370// Mounting Methods.
 371//
 372//-----------------------------------------------------------------------------
 373
 374bool VPath::isMountIndex( const U32 &pIndex )
 375{
 376    for ( SceneObject *itr = getMountList(); itr != NULL; itr = itr->getMountLink() )
 377    {
 378        if ( itr->getMountNode() == pIndex )
 379        {
 380            // Yes.
 381            return true;
 382        }
 383    }
 384
 385    // No.
 386    return false;
 387}
 388
 389U32 VPath::getAvailableMountIndex( void )
 390{
 391    U32 i = 0;
 392    while( isMountIndex( i ) )
 393    {
 394        // Increment.
 395        i++;
 396    }
 397
 398    // Return Index.
 399    return i;
 400}
 401
 402void VPath::mountObject( SceneObject *pObject, S32 pIndex, const MatrixF &pTransform )
 403{
 404#ifdef VPATH_DEBUG_NET
 405    Con::printf( "VPath::mountObject() %d | %d, IsAttached %d", isServerObject(), pObject->getId(), isObjectAttached( pObject ) );
 406#endif
 407
 408    // Attached?
 409    if ( !isObjectAttached( pObject ) )
 410    {
 411        if ( isServerObject() )
 412        {
 413            // Shouldn't Use this Method.
 414            Con::warnf( "VPath::mountObject() - Use 'attachObject' instead." );
 415        }
 416
 417        // Not Attached.
 418        return;
 419    }
 420
 421    // Parent Call.
 422    Parent::mountObject( pObject, pIndex, pTransform );
 423
 424    // Clear the mounted mask.
 425    // Note: This is so that we send the mounting information via the VPath
 426    //       packets instead of letting T3D handle it.
 427    pObject->clearMaskBits( SceneObject::MountedMask );
 428}
 429
 430void VPath::unmountObject( SceneObject *pObject )
 431{
 432    // Fetch Path Object.
 433    VPathObject *pathObject = getPathObject( pObject );
 434
 435#ifdef VPATH_DEBUG_NET
 436    Con::printf( "VPath::unmountObject() %d | %d, IsAttached %d", isServerObject(), pObject->getId(), pathObject != NULL );
 437#endif
 438
 439    // Valid?
 440    if ( !pathObject || pObject->getObjectMount() != this ) 
 441    {
 442        // Warn.
 443        Con::warnf( "VPath::unmountObject() - Object is not attached to this Path. %d", pObject->getId() );
 444        // Not Mounted Here!
 445        return;
 446    }
 447
 448    // Parent Call.
 449    Parent::unmountObject( pObject );
 450
 451    // Clear the mounted mask.
 452    // Note: This is so that we send the mounting information via the VPath
 453    //       packets instead of letting T3D handle it.
 454    pObject->clearMaskBits( SceneObject::MountedMask );
 455}
 456
 457void VPath::getMountTransform( S32 pIndex, const MatrixF &pInTransform, MatrixF *pTransform )
 458{
 459    // Fetch the Scene Object.
 460    VPathObject *pathObject = NULL;
 461    for ( SceneObject *itr = getMountList(); itr != NULL; itr = itr->getMountLink() )
 462    {
 463        if ( itr->getMountNode() == pIndex )
 464        {
 465            pathObject = getPathObject( itr );
 466            break;
 467        }
 468    }
 469
 470    if ( !pathObject )
 471    {
 472        // Reset Transform.
 473        *pTransform = pInTransform;
 474        // Sanity!
 475        return;
 476    }
 477
 478    // Advance the Object.
 479    advanceObject( pathObject, TickSec );
 480
 481    // Apply Transform.
 482    *pTransform = pathObject->getTransform();
 483}
 484
 485void VPath::getRenderMountTransform( F32 pDelta, S32 pIndex, const MatrixF &pInTransform, MatrixF *pTransform )
 486{
 487    // Fetch the Scene Object.
 488    VPathObject *pathObject = NULL;
 489    for ( SceneObject *itr = getMountList(); itr != NULL; itr = itr->getMountLink() )
 490    {
 491        if ( itr->getMountNode() == pIndex )
 492        {
 493            pathObject = getPathObject( itr );
 494            break;
 495        }
 496    }
 497
 498    if ( !pathObject )
 499    {
 500        // Reset Transform.
 501        *pTransform = pInTransform;
 502        // Sanity!
 503        return;
 504    }
 505
 506    // Apply Transform.
 507    *pTransform = pathObject->getRenderTransform( pDelta );
 508}
 509
 510VectorF VPath::getMountVelocity( const U32 &pIndex )
 511{
 512    // Fetch the Scene Object.
 513    VPathObject *pathObject = NULL;
 514    for ( SceneObject *itr = getMountList(); itr != NULL; itr = itr->getMountLink() )
 515    {
 516        if ( itr->getMountNode() == pIndex )
 517        {
 518            pathObject = getPathObject( itr );
 519            break;
 520        }
 521    }
 522
 523    if ( !pathObject )
 524    {
 525        // Sanity!
 526        return VectorF::Zero;
 527    }
 528
 529    // Determine Velocity.
 530    return ( pathObject->getOrientation() * pathObject->getSpeed() );
 531}
 532
 533//-----------------------------------------------------------------------------
 534//
 535// Persistence Methods.
 536//
 537//-----------------------------------------------------------------------------
 538
 539void VPath::readFields( void )
 540{
 541    const char *nodeData = "";
 542    for ( S32 nodeIndex = 0; String::compare( nodeData = getDataField( StringTable->insert( avar( "Node%d", nodeIndex ) ), NULL ), "" ) != 0; nodeIndex++ )
 543    {
 544        // Create Node.
 545        VPathNode *node = createNode();
 546        // Deserialize the Node.
 547        node->fromString( nodeData );
 548        // Add the Node.
 549        addNode( node );
 550
 551        // Clear Field.
 552        setDataField( StringTable->insert( avar( "Node%d", nodeIndex ) ), NULL, "" );
 553    }
 554
 555    // Update Transforms.
 556    updateNodeTransforms();
 557
 558    // Update Size.
 559    updateContainer();
 560
 561    // Calculate Path.
 562    calculatePath();
 563}
 564
 565void VPath::writeFields( Stream &pStream, U32 pTabStop )
 566{
 567    // Field Name.
 568    StringTableEntry fieldName = StringTable->insert( "node" );
 569
 570    for ( VPathNodeIterator itr = mNodeList.begin(); itr != mNodeList.end(); itr++ )
 571    {
 572        // Set Field.
 573        setDataField( fieldName, avar( "%d" , ( itr - mNodeList.begin() ) ), ( *itr )->toString().c_str() );
 574    }
 575
 576    // Write Fields.
 577    Parent::writeFields( pStream, pTabStop );
 578
 579    for ( VPathNodeIterator itr = mNodeList.begin(); itr != mNodeList.end(); itr++ )
 580    {
 581        // Clear Field.
 582        setDataField( fieldName, avar( "%d" , ( itr - mNodeList.begin() ) ), "" );
 583    }
 584}
 585
 586U32 VPath::packUpdate( NetConnection *pConnection, U32 pMask, BitStream *pStream )
 587{
 588    U32 retMask = Parent::packUpdate( pConnection, pMask, pStream );
 589
 590    if ( pMask & InitialUpdateMask )
 591    {
 592        // Delete Notify.
 593        deleteNotify( pConnection );
 594    }
 595
 596    if ( pStream->writeFlag( pMask & PathUpdateMask ) )
 597    {
 598        // Write Path Type.
 599        pStream->writeInt( mPathType, gPathTypeBits );
 600
 601        // Write Transform.
 602        mathWrite( *pStream, mObjToWorld );
 603        // Write Scale.
 604        mathWrite( *pStream, mObjScale );
 605    }
 606
 607    if ( pStream->writeFlag( pMask & NodeUpdateMask ) )
 608    {
 609        // Path needs recalculating?
 610        bool needsCalculating = false;
 611
 612        // Delete Vector.
 613        Vector<U32> deleteVector;
 614        // Update Vector.
 615        Vector<U32> updateVector;
 616
 617        for ( U32 i = 0; i < mNodeList.size(); i++ )
 618        {
 619            // Fetch Node.
 620            VPathNode *node = mNodeList[i];
 621
 622            // Already In Map?
 623            if ( !node->isConnection( pConnection ) )
 624            {
 625                // Insert.
 626                node->addConnection( pConnection );
 627            }
 628
 629            // Fetch State.
 630            VNetStateInfo *state = node->getState( pConnection );
 631
 632            // Delete new node?
 633            if ( state->Mask & VPathNode::k_StateDelete
 634                 && state->Mask & VPathNode::k_StateCreate )
 635            {
 636                // Remove Node.
 637                removeNode( i-- );
 638                // Flag true.
 639                needsCalculating = true;
 640            }
 641
 642            // Delete?
 643            else if ( state->Mask & VPathNode::k_StateDelete )
 644            {
 645                // Add To List.
 646                deleteVector.push_front( i );
 647            }
 648
 649            // Update?
 650            else if ( state->Mask & VPathNode::k_StateUpdate )
 651            {
 652                if ( updateVector.size() < gMaxNodeTransmit )
 653                {
 654                    // Add To List.
 655                    updateVector.push_back( i );
 656                }
 657            }
 658        }
 659
 660        // More Updates?
 661        if ( updateVector.size() == gMaxNodeTransmit )
 662        {
 663            // More Updates.
 664            retMask |= NodeUpdateMask;
 665        }
 666
 667        // Write Count.
 668        pStream->writeInt( updateVector.size(), gMaxNodeBits + 1 );
 669
 670        for ( Vector<U32>::iterator itr = updateVector.begin(); itr != updateVector.end(); itr++ )
 671        {
 672            // Fetch Index.
 673            const U32 index = ( *itr );
 674
 675            // Write Index.
 676            pStream->writeInt( index, gMaxNodeBits );
 677            // Pack Update.
 678            retMask |= mNodeList[index]->packNode( pConnection, pStream );
 679        }
 680
 681        // Write Count.
 682        pStream->writeInt( deleteVector.size(), gMaxNodeBits + 1 );
 683
 684        if ( deleteVector.size() > 0 )
 685        {
 686            for ( Vector<U32>::iterator itr = deleteVector.begin(); itr != deleteVector.end(); itr++ )
 687            {
 688                // Fetch Index.
 689                const U32 index = ( *itr );
 690
 691                // Write Index.
 692                pStream->writeInt( index, gMaxNodeBits );
 693                // Remove Node.
 694                removeNode( index );
 695            }
 696
 697            // Flag true.
 698            needsCalculating = true;
 699            // Clear Vector.
 700            deleteVector.clear();
 701        }
 702
 703        // Recalculate path?
 704        if ( needsCalculating )
 705        {
 706            // Update Size.
 707            updateContainer();
 708            // Calculate Path.
 709            calculatePath();
 710        }
 711    }
 712
 713    if ( pStream->writeFlag( pMask & ObjectUpdateMask ) )
 714    {
 715        // Detach Vector.
 716        Vector<U32> detachVector;
 717        // Update Vector.
 718        Vector<U32> updateVector;
 719
 720        for ( U32 i = 0; i < mObjectList.size(); i++ )
 721        {
 722            // Fetch Node.
 723            VPathObject *pathObject = mObjectList[i];
 724
 725            // Already In Map?
 726            if ( !pathObject->isConnection( pConnection ) )
 727            {
 728                // Insert.
 729                pathObject->addConnection( pConnection );
 730            }
 731
 732            // Fetch State.
 733            VNetStateInfo *state = pathObject->getState( pConnection );
 734
 735            // Detach newly attached object?
 736            if ( state->Mask & VPathObject::k_StateAttach
 737                 && state->Mask & VPathObject::k_StateDetach )
 738            {
 739                // Process Detach.
 740                onDetachObject( pathObject );
 741                // Decrease index.
 742                i -= 1;
 743
 744                // Skip.
 745                continue;
 746            }
 747
 748            // Update?
 749            if ( state->Mask & VPathObject::k_StateUpdate )
 750            {
 751                if ( updateVector.size() < gMaxObjectTransmit )
 752                {
 753                    // Add To List.
 754                    updateVector.push_back( i );
 755                }
 756            }
 757
 758            // Detach?
 759            if ( state->Mask & VPathObject::k_StateDetach )
 760            {
 761                // Add To List.
 762                detachVector.push_front( i );
 763            }
 764        }
 765
 766        // More Updates?
 767        if ( updateVector.size() == gMaxObjectTransmit )
 768        {
 769            // More Updates.
 770            retMask |= ObjectUpdateMask;
 771        }
 772
 773        // Write Count.
 774        pStream->writeInt( updateVector.size(), gMaxObjectBits + 1 );
 775
 776        for ( Vector<U32>::iterator itr = updateVector.begin(); itr != updateVector.end(); itr++ )
 777        {
 778            // Fetch Index.
 779            const U32 index = ( *itr );
 780
 781            // Write Index.
 782            pStream->writeInt( index, gMaxObjectBits );
 783
 784            // Fetch the object.
 785            VPathObject *pathObject = mObjectList[index];
 786            // Fetch State.
 787            VNetStateInfo *state = pathObject->getState( pConnection );
 788
 789            // Was the Object Attached?
 790            if ( pStream->writeFlag( state->Mask & VPathObject::k_StateAttach ) )
 791            {
 792#ifdef VPATH_DEBUG_NET
 793                Con::printf( "VPath::packUpdate() - Attached - %d | %d", isServerObject(), index );
 794#endif
 795
 796                // Clear Update.
 797                state->Mask &= ~<a href="/coding/class/structvpathobject/">VPathObject</a>::k_StateAttach;
 798            }
 799
 800            // Pack Object.
 801            retMask |= mObjectList[index]->packUpdate( pConnection, pStream );
 802        }
 803
 804        // Write Count.
 805        pStream->writeInt( detachVector.size(), gMaxObjectBits + 1 );
 806
 807        if ( detachVector.size() > 0 )
 808        {
 809            for ( Vector<U32>::iterator itr = detachVector.begin(); itr != detachVector.end(); itr++ )
 810            {
 811                // Fetch Index.
 812                const U32 index = ( *itr );
 813                // Write Index.
 814                pStream->writeInt( index, gMaxObjectBits );
 815                // Process Detach.
 816                onDetachObject( mObjectList[index] );
 817            }
 818
 819            // Clear Vector.
 820            detachVector.clear();
 821        }
 822    }
 823
 824    // Return.
 825    return retMask;
 826}
 827
 828void VPath::unpackUpdate( NetConnection *pConnection, BitStream *pStream )
 829{
 830    Parent::unpackUpdate( pConnection, pStream );
 831
 832    // Update Path?
 833    if ( pStream->readFlag() )
 834    {
 835        // Read Path Type.
 836        mPathType = pStream->readInt( gPathTypeBits );
 837
 838        // Read Transform.
 839        mathRead( *pStream, &mObjToWorld );
 840        // Read Scale.
 841        mathRead( *pStream, &mObjScale );
 842
 843        // Update Nodes.
 844        updateNodeTransforms();
 845        // Calculate Path.
 846        calculatePath();
 847    }
 848
 849    // Update Nodes?
 850    if ( pStream->readFlag() )
 851    {
 852        // Number To Update.
 853        const U32 updateCount = pStream->readInt( gMaxNodeBits + 1 );
 854
 855        for ( U32 i = 0; i < updateCount; i++ )
 856        {
 857            // Read Index.
 858            const U32 nodeIndex = pStream->readInt( gMaxNodeBits );
 859
 860            // Was the Node Created?
 861            if ( pStream->readFlag() )
 862            {
 863                // Create Node.
 864                VPathNode *node = createNode();
 865                // Add the Node.
 866                addNode( node, nodeIndex );
 867            }
 868
 869            // Reference Node.
 870            VPathNode *node = mNodeList[nodeIndex];
 871            // Apply Update.
 872            node->unpackNode( pConnection, pStream );
 873        }
 874
 875        // Number To Delete.
 876        const U32 deleteCount = pStream->readInt( gMaxNodeBits + 1 );
 877
 878        for ( U32 i = 0; i < deleteCount; i++ )
 879        {
 880            // Remove Node.
 881            removeNode( pStream->readInt( gMaxNodeBits ) );
 882        }
 883
 884        // Update Size.
 885        updateContainer();
 886        // Calculate Path.
 887        calculatePath();
 888    }
 889
 890    // Update Objects?
 891    if ( pStream->readFlag() )
 892    {
 893        // Number To Update.
 894        const U32 updateCount = pStream->readInt( gMaxObjectBits + 1 );
 895
 896        for ( U32 i = 0; i < updateCount; i++ )
 897        {
 898            // Read Index.
 899            const U32 objectIndex = pStream->readInt( gMaxObjectBits );
 900
 901            // Read Attached.
 902            // Note: The editor handles the both the server and client side attachment calls.
 903            //       This is dangerous because there could be a mix up in indices, but it is
 904            //       needed to ensure the editor runs smoothly :(
 905            const bool wasAttached = pStream->readFlag();
 906            if ( wasAttached && objectIndex >= mObjectList.size() )
 907            {
 908#ifdef VPATH_DEBUG_NET
 909                Con::printf( "VPath::unpackUpdate() - WasAttached - %d | %d", isServerObject(), objectIndex );
 910#endif
 911
 912                // Create & Add to the List.
 913                attachObject( new VPathObject() );
 914            }
 915
 916            // Reference Node.
 917            VPathObject *pathObject = mObjectList[objectIndex];
 918
 919            // Unpack Update.
 920            pathObject->unpackUpdate( pConnection, pStream );
 921
 922            // Object Attached this Unpack?
 923            if ( wasAttached )
 924            {
 925                // Reset.
 926                setPathObjectInterp( pathObject, pathObject->getTimeInterp() );
 927            }
 928        }
 929
 930        // Number To Detach.
 931        const U32 detachCount = pStream->readInt( gMaxObjectBits + 1 );
 932
 933        for ( U32 i = 0; i < detachCount; i++ )
 934        {
 935            // Fetch the path object.
 936            VPathObject *pathObject = mObjectList[pStream->readInt( gMaxObjectBits )];
 937            // Detach callback.
 938            onDetachObject( pathObject );
 939        }
 940    }
 941}
 942
 943//-----------------------------------------------------------------------------
 944//
 945// Node Methods.
 946//
 947//-----------------------------------------------------------------------------
 948
 949VPathNode *VPath::createNode( void )
 950{
 951    return new VPathNode();
 952}
 953
 954void VPath::deleteNode( VPathNode *pNode )
 955{
 956    delete pNode;
 957}
 958
 959void VPath::clear( void )
 960{
 961    for ( VPathObjectIterator itr = mObjectList.begin(); itr != mObjectList.end(); itr++ )
 962    {
 963        VPathObject *pathObject = ( *itr );
 964
 965        // Fetch the attached object.
 966        SceneObject *refObject = pathObject->getObject();
 967        // Unmount Object.
 968        unmountObject( refObject );
 969
 970        // Delete the Path Object.
 971        delete pathObject;
 972    }
 973
 974    // Clear Object List.
 975    mObjectList.clear();
 976
 977    for ( VPathNodeIterator itr = mNodeList.begin(); itr != mNodeList.end(); itr++ )
 978    {
 979        deleteNode( ( *itr ) );
 980    }
 981
 982    // Clear Node List.
 983    mNodeList.clear();
 984
 985    if ( isServerObject() )
 986    {
 987        // Update.
 988        setMaskBits( NodeUpdateMask );
 989    }
 990}
 991
 992VPathNode *VPath::getNode( const S32 &pNodeIndex )
 993{
 994    // Sanity!
 995    AssertFatal( pNodeIndex >= 0 && pNodeIndex < mNodeList.size(), "VPath::getNode() - Invalid Index" );
 996
 997    // Return Node.
 998    return mNodeList[pNodeIndex];
 999}
1000
1001DefineEngineMethod( VPath, addNode, void, (TransformF transform, F32 weight, S32 location), (MatrixF::Identity, 1.0, -1),
1002                                          "( transform pTransform, float pWeight, [int pLocation] ) - Add a node with the given properties. Nodes represent physical points that attached objects move towards or between, but the PathType determines \"how\" they move between them.\n"
1003                                           "@param pTransform The position and rotation of the new node.\n"
1004                                           "@param pWeight The weight of the new node.\n"
1005                                           "@param pLocation The index of the new node.\n"
1006                                           "@return No return value.")
1007{
1008    // Fetch Invers Path Transform.
1009    MatrixF pathTransformInv = object->getTransform();
1010    pathTransformInv.setPosition( Point3F::Zero );
1011    pathTransformInv.inverse();
1012
1013    Point3F  pos;
1014    QuatF    rot;
1015    AngAxisF aa;
1016
1017    pos = transform.mPosition;
1018    aa = transform.mOrientation;
1019
1020    // Set Rotation.
1021    rot.set( aa );
1022
1023    // World to Local Position.
1024    Point3F nodePosition = ( pos - object->getPosition() );
1025    pathTransformInv.mulP( nodePosition );
1026
1027    // World to Local Rotation.
1028    MatrixF nodeRotationMat;
1029    rot.setMatrix( &nodeRotationMat );
1030    pathTransformInv.mul( nodeRotationMat );
1031    
1032    // Set Quat.
1033    QuatF nodeRotation;
1034    nodeRotation.set( nodeRotationMat );
1035
1036    // Add Node.
1037    VPathNode *node = object->addNode( nodePosition, nodeRotation, weight, location );
1038
1039    // Valid Node?
1040    if ( node )
1041    {
1042        // Update Size.
1043        object->updateContainer();
1044
1045        // Calculate Path.
1046        object->calculatePath();
1047    }
1048}
1049
1050VPathNode *VPath::addNode( const Point3F &pPosition, const QuatF &pRotation, const F32 &pWeight, const S32 &pLocation )
1051{
1052    // Reference Object.
1053    VPathNode *pathNode = createNode();
1054
1055    // Store Properties.
1056    pathNode->setLocalPosition( pPosition );
1057    pathNode->setLocalRotation( pRotation );
1058    pathNode->setWeight( pWeight );
1059
1060    // Add Node.
1061    return addNode( pathNode, pLocation );
1062}
1063
1064VPathNode *VPath::addNode( VPathNode *pNode, const S32 &pLocation )
1065{
1066    if ( pNode->getPath() )
1067    {
1068        // Error.
1069        Con::errorf( "VPath::addNode() - Node already belongs to a Path, '%d'", pNode->getPath()->getId() );
1070
1071        return NULL;
1072    }
1073    else if ( mNodeList.size() == gMaxNodeCount )
1074    {
1075        // Error.
1076        Con::errorf( "VPath::addNode() - Reached Max Nodes (%d)", gMaxNodeCount );
1077
1078        // Delete Node.
1079        deleteNode( pNode );
1080
1081        return NULL;
1082    }
1083
1084    // Set Path.
1085    pNode->setPath( this );
1086
1087    // Update World Data.
1088    pNode->updateWorldData();
1089
1090    if ( pLocation < 0 )
1091    {
1092        // Push Back.
1093        mNodeList.push_back( pNode );
1094    }
1095    else
1096    {
1097        // Fetch Size.
1098        const S32 nodeCount = mNodeList.size();
1099
1100        if ( pLocation >= nodeCount )
1101        {
1102            // Push Back.
1103            mNodeList.push_back( pNode );
1104        }
1105        else
1106        {
1107            // Insert.
1108            mNodeList.insert( ( mNodeList.address() + pLocation ), pNode );
1109        }
1110    }
1111
1112    if ( isServerObject() )
1113    {
1114        // Update.
1115        setMaskBits( NodeUpdateMask );
1116    }
1117
1118    // Return Node.
1119    return pNode;
1120}
1121
1122DefineEngineMethod( VPath, deleteNode, void, (S32 nodeIndex), (0), "( int pNodeIndex ) - Delete the node with the given index. If you delete a node that an attached object is moving to, or from then the object's movement will adjust so that it has a valid path.\n"
1123                                              "@param pNodeIndex The index of the node to be deleted.\n"
1124                                              "@return No return value." )
1125{
1126    // Apply Update.
1127    object->deleteNode( nodeIndex );
1128}
1129
1130void VPath::deleteNode( const S32 &pNodeIndex )
1131{
1132    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
1133    {
1134        // Woops!
1135        Con::warnf( "VPath::deleteNode() - Invalid Index Specified (%d).", pNodeIndex );
1136        return;
1137    }
1138
1139    // Fetch Node.
1140    VPathNode *node = mNodeList[pNodeIndex];
1141
1142    // Remove Node References.
1143    for ( VPathObjectIterator itr = mObjectList.begin(); itr != mObjectList.end(); itr++ )
1144    {
1145        // Fetch Object.
1146        VPathObject *pathObject = ( *itr );
1147
1148        if ( ( pathObject->getSourceNode() >= pNodeIndex ) || ( pathObject->getDestinationNode() >= pNodeIndex ) )
1149        {
1150            S32 srcNode = pathObject->getSourceNode();
1151            S32 dstNode = pathObject->getDestinationNode();
1152
1153            if ( pathObject->isForward() )
1154            {
1155                if ( srcNode >= pNodeIndex )
1156                {
1157                    srcNode -= 1;
1158                }
1159
1160                if ( dstNode > pNodeIndex )
1161                {
1162                    dstNode -= 1;
1163                }
1164            }
1165            else
1166            {
1167                if ( srcNode > pNodeIndex )
1168                {
1169                    srcNode -= 1;
1170                }
1171
1172                if ( dstNode >= pNodeIndex )
1173                {
1174                    dstNode -= 1;
1175                }
1176            }
1177
1178            // Normalize indices.
1179            normalizeNodeIndex( srcNode, ( mNodeList.size() - 1 ) );
1180            normalizeNodeIndex( dstNode, ( mNodeList.size() - 1 ) );
1181
1182            // Apply Update.
1183            pathObject->setNode( srcNode, dstNode );
1184
1185            if ( isServerObject() )
1186            {
1187                // Update Objects.
1188                setMaskBits( ObjectUpdateMask );
1189            }
1190        }
1191    }
1192
1193    if ( isServerObject() )
1194    {
1195        // Network Flags.
1196        setMaskBits( NodeUpdateMask );
1197
1198        // Flag for Deletion.
1199        node->setMaskBits( VPathNode::k_StateDelete );
1200    }
1201}
1202
1203void VPath::removeNode( const S32 &pNodeIndex )
1204{
1205    // Fetch the node.
1206    VPathNode *node = getNode( pNodeIndex );
1207    if ( !node )
1208    {
1209        // Quit.
1210        return;
1211    }
1212
1213    // Delete Node.
1214    deleteNode( node );
1215    // Erase Node.
1216    mNodeList.erase( pNodeIndex );
1217}
1218
1219S32 VPath::normalizeNodeIndex( S32 &pNodeIndex )
1220{
1221    const S32 nodeCount = mNodeList.size();
1222    if ( nodeCount == 0 )
1223    {
1224        // No Nodex.
1225        pNodeIndex = 0;
1226    }
1227    else
1228    {
1229        while ( pNodeIndex < 0 )
1230        {
1231            // Wrap Backwards.
1232            pNodeIndex += nodeCount;
1233        }
1234
1235        // Wrap Forwards.
1236        pNodeIndex %= nodeCount;
1237    }
1238
1239    // Return Index.
1240    return pNodeIndex;
1241}
1242
1243S32 VPath::normalizeNodeIndex( const S32 &pNodeIndex )
1244{
1245    // Temp.
1246    S32 nodeIndex = pNodeIndex;
1247
1248    // Return Index.
1249    return normalizeNodeIndex( nodeIndex );
1250}
1251
1252S32 VPath::normalizeNodeIndex( S32 &pNodeIndex, const S32 &pNodeCount )
1253{
1254    if ( pNodeCount == 0 )
1255    {
1256        // No Nodex.
1257        pNodeIndex = 0;
1258    }
1259    else
1260    {
1261        while ( pNodeIndex < 0 )
1262        {
1263            // Wrap Backwards.
1264            pNodeIndex += pNodeCount;
1265        }
1266
1267        // Wrap Forwards.
1268        pNodeIndex %= pNodeCount;
1269    }
1270
1271    // Return Index.
1272    return pNodeIndex;
1273}
1274
1275//-----------------------------------------------------------------------------
1276//
1277// Object Methods.
1278//
1279//-----------------------------------------------------------------------------
1280
1281DefineEngineMethod( VPath, isObjectAttached, bool, (SceneObject* sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Is the object attached to this path?\n"
1282                                                    "@param pObject The SimObjectID of the object you wish to check.\n"
1283                                                    "@return Returns true if the object is attached to this path." )
1284{
1285    if (sceneObject== nullptr)
1286    {
1287        Con::errorf( "VPath::isObjectAttached() - Invalid Target Object." );
1288        return false;
1289    }
1290
1291    // Attached?
1292    return object->isObjectAttached( sceneObject );
1293}
1294
1295bool VPath::isObjectAttached( SceneObject *pObject )
1296{
1297    // Valid Object?
1298    return ( getPathObject( pObject ) != NULL );
1299}
1300
1301VPathObject *VPath::getPathObject( SceneObject *pObject )
1302{
1303    for ( VPathObjectIterator itr = mObjectList.begin(); itr != mObjectList.end(); itr++ )
1304    {
1305        // Correct Object?
1306        if ( ( *itr )->getObject() == pObject )
1307        {
1308            // Yes.
1309            return ( *itr );
1310        }
1311    }
1312
1313    return NULL;
1314}
1315
1316DefineEngineStringlyVariadicMethod( VPath, attachObject, void, 7, 8, "( SimObject pObject, bool pForward, float pSpeed, bool pRelative, int pStartNode, [int pEndNode] ) - Attach an object to this path with the given properties. If the object is already attached to a path, then a warning will be displayed and the object will *not* be attached to this path.\n"
1317                                                "@param pObject The SimObjectID of the object to be attached.\n"
1318                                                "@param pForward Should the object be moving forward?\n"
1319                                                "@param pSpeed The speed that the object will travel around the path.\n"
1320                                                "@param pRelative Offset the object based on the difference between the start node and its current position.\n"
1321                                                "@param pStartNode The index of the node this object starts pathing from.\n"
1322                                                "@param pEndNode The index of the node this object will stop pathing at."
1323                                                "@return No return value." )
1324{
1325    // Fetch Object.
1326    SceneObject *sceneObject;
1327    if ( !Sim::findObject( argv[2], sceneObject ) )
1328    {
1329        Con::errorf( "VPath::attachObject() - Invalid Target Object." );
1330        return;
1331    }
1332
1333    // Fetch Direction.
1334    const bool forward   = dAtob( argv[3] );
1335    // Fetch Speed.
1336    const F32  speed     = dAtof( argv[4] );
1337    // Fetch Relativity.
1338    const bool relative  = dAtob( argv[5] );
1339    // Fetch Start Node.
1340    const S32  startNode = dAtoi( argv[6] );
1341    // Fetch End Node.
1342    const S32  endNode   = ( argc >= 8 ) ? dAtoi( argv[7] ) : -1;
1343
1344    // Attach Object.
1345    object->attachObject( sceneObject, forward, speed, relative, startNode, endNode );
1346}
1347
1348void VPath::attachObject( SceneObject *pObject, const bool &pForward, const F32 &pSpeed, const bool &pRelative, const S32 &pStartNode, const S32 &pEndNode )
1349{
1350    attachObject( pObject, pForward, pSpeed, pRelative, pStartNode, pEndNode, VPathObject::k_OrientationToPath, NULL );
1351}
1352
1353void VPath::attachObject( SceneObject *pObject, const bool &pForward, const F32 &pSpeed, const bool &pRelative, const S32 &pStartNode, const S32 &pEndNode, const VPathObject::eOrientationType &pOrientationMode )
1354{
1355    attachObject( pObject, pForward, pSpeed, pRelative, pStartNode, pEndNode, pOrientationMode, NULL );
1356}
1357
1358void VPath::attachObject( SceneObject *pObject, const bool &pForward, const F32 &pSpeed, const bool &pRelative, const S32 &pStartNode, const S32 &pEndNode, const VPathObject::eOrientationType &pOrientationMode, void *pOrientationData )
1359{
1360    // Already Pathing?
1361    if ( isObjectAttached( pObject ) )
1362    {
1363        Con::warnf( "VPath::attachObject() - Object Already Attached to a Path." );
1364        return;
1365    }
1366
1367    // Determine Target Nodes.
1368    const S32 srcNode = normalizeNodeIndex( pStartNode );
1369    const S32 dstNode = normalizeNodeIndex( ( pForward ) ? pStartNode + 1 : pStartNode - 1 );
1370    const S32 endNode = ( pEndNode == -1 ) ? pEndNode : normalizeNodeIndex( pEndNode );
1371
1372    // Valid Source Node?
1373    if ( getNodeCount() == 0 || !getNode( srcNode ) )
1374    {
1375        Con::warnf( "VPath::attachObject() - Invalid Start Node." );
1376        return;
1377    }
1378
1379    VPathObject *pathObject = new VPathObject();
1380
1381    // Init Properties.
1382    pathObject->setActive( true );
1383    pathObject->setObject( pObject );
1384
1385    pathObject->setForward( pForward );
1386
1387    pathObject->setTimeInterp( 0.f );
1388    pathObject->setPathInterp( 0.f );
1389    pathObject->setOffset( Point3F::Zero );
1390    pathObject->setSpeed( pSpeed );
1391
1392    switch( pOrientationMode )
1393    {
1394        case VPathObject::k_OrientationFree :
1395        case VPathObject::k_OrientationInterpolate :
1396        case VPathObject::k_OrientationToPath :
1397            {
1398                pathObject->setOrientationMode( pOrientationMode );
1399
1400            } break;
1401
1402        case VPathObject::k_OrientationToObject :
1403            {
1404                pathObject->setOrientationMode( pOrientationMode, (SceneObject*)pOrientationData );
1405
1406            } break;
1407
1408        case VPathObject::k_OrientationToPoint :
1409            {
1410                pathObject->setOrientationMode( pOrientationMode, ( *(Point3F*)pOrientationData ) );
1411
1412            } break;
1413    }
1414
1415    pathObject->setNode( srcNode, dstNode );
1416    pathObject->setStartNode( srcNode );
1417    pathObject->setEndNode( endNode );
1418
1419    // Fetch Init Node.
1420    VPathNode *node = mNodeList[srcNode];
1421
1422    // Relative Position?
1423    if ( pRelative )
1424    {
1425        // Set Position Offset.
1426        pathObject->setOffset( pObject->getPosition() - node->getWorldPosition() );
1427    }
1428
1429    // Set info.
1430    setPathObjectInterp( pathObject, 0.f );
1431
1432    // Attach.
1433    attachObject( pathObject );
1434}
1435
1436void VPath::attachObject( VPathObject *pPathObject )
1437{
1438#ifdef VPATH_DEBUG_NET
1439    Con::printf( "VPath::attachObject() - %d", isServerObject() );
1440#endif
1441
1442    if ( mObjectList.size() == gMaxObjectCount )
1443    {
1444        Con::errorf( "VPath::attachObject() - Reached Max Objects (%d)", gMaxObjectCount );
1445        return;
1446    }
1447
1448    // Add to List.
1449    mObjectList.push_back( pPathObject );
1450
1451    // Callback.
1452    onAttachObject( pPathObject );
1453
1454    if ( isServerObject() )
1455    {
1456        // Update.
1457        setMaskBits( ObjectUpdateMask );
1458    }
1459}
1460
1461void VPath::onAttachObject( VPathObject *pPathObject )
1462{
1463    // Valid Object?
1464    SceneObject *refObject = pPathObject->getObject();
1465    if ( !refObject )
1466    {
1467        return;
1468    }
1469
1470#ifdef VPATH_DEBUG_NET
1471    Con::printf( "VPath::onAttachObject() - %d | %d", isServerObject(), refObject->getId() );
1472#endif
1473
1474    // Delete Notify.
1475    deleteNotify( refObject );
1476
1477    if ( isServerObject() )
1478    {
1479        // Fetch the Available Mount Index.
1480        U32 mountIndex = getAvailableMountIndex();
1481        // Mount the Object to this Path.
1482        mountObject( refObject, mountIndex );
1483
1484        // Return Buffer.
1485        char buffer[1][32];
1486        dSprintf( buffer[0], sizeof( buffer[0] ), "%d", refObject->getId() );
1487
1488        // Callback.
1489        // VPath::onAttachObject( %object );
1490        Con::executef( this, "onAttachObject", buffer[0] );
1491    }
1492}
1493
1494DefineEngineMethod( VPath, detachObject, void, (SceneObject *sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Detach the object from this path in place.\n"
1495                                                "@param pObject The SimObjectID of the object to be detached.\n"
1496                                                "@return No return value." )
1497{
1498    // Fetch Object.
1499    if (sceneObject == nullptr)
1500    {
1501        Con::errorf( "VPath::detachObject() - Invalid Target Object." );
1502        return;
1503    }
1504
1505    // Detach Object.
1506    object->detachObject( sceneObject );
1507}
1508
1509void VPath::detachObject( SceneObject *pObject )
1510{
1511    VPathObject *pathObject = getPathObject( pObject );
1512    if ( !pathObject )
1513    {
1514        Con::warnf( "VPath::detachObject() - Object (%d) Not Attached to Path.", pObject->getId() );
1515        return;
1516    }
1517
1518    // Detach.
1519    detachObject( pathObject );
1520}
1521
1522void VPath::detachObject( VPathObject *pPathObject )
1523{
1524#ifdef VPATH_DEBUG_NET
1525        Con::printf( "VPath::detachObject() - %d", isServerObject() );
1526#endif
1527
1528    if ( isServerObject() )
1529    {
1530        // Update Objects.
1531        setMaskBits( ObjectUpdateMask );
1532
1533        // Detach.
1534        pPathObject->setMaskBits( VPathObject::k_StateDetach );
1535    }
1536
1537    /*
1538    // Valid Object?
1539    SceneObject *refObject = pPathObject->getObject();
1540    if ( refObject )
1541    {
1542        // Unmount Object.
1543        unmountObject( refObject );
1544    }
1545    */
1546}
1547
1548void VPath::onDetachObject( VPathObject *pPathObject )
1549{
1550    // Valid Object?
1551    SceneObject *refObject = pPathObject->getObject();
1552    if ( !refObject )
1553    {
1554        return;
1555    }
1556
1557#ifdef VPATH_DEBUG_NET
1558        Con::printf( "VPath::onDetachObject() - %d | %d", isServerObject(), refObject->getId() );
1559#endif
1560    
1561    // Reset.
1562    setPathObjectInterp( pPathObject, pPathObject->getTimeInterp() );
1563    // Unmount Object.
1564    unmountObject( refObject );
1565
1566    // Delete the Path Object.
1567    delete pPathObject;
1568    // Remove from the Set.
1569    mObjectList.erase( mObjectList.find_next( pPathObject ) );
1570
1571    // Clear Delete Notify.
1572    clearNotify( refObject );
1573
1574    if ( isServerObject() )
1575    {
1576        // Return Buffer.
1577        char buffer[1][32];
1578        dSprintf( buffer[0], sizeof( buffer[0] ), "%d", refObject->getId() );
1579
1580        // Callback.
1581        // VPath::onDetachObject( %object );
1582        Con::executef( this, "onDetachObject", buffer[0] );
1583    }
1584}
1585
1586void VPath::processTick( const Move *pMove )
1587{
1588}
1589
1590void VPath::advanceObject( VPathObject *pPathObject, const F32 &pDelta )
1591{
1592    SceneObject *refObject = pPathObject->getObject();
1593    if ( !refObject || mIsZero( pDelta ) )
1594    {
1595        // Ignore.
1596        return;
1597    }
1598
1599    // Spatial Delta.
1600    pPathObject->popDelta();
1601
1602    // Active and Moving?
1603    if ( !pPathObject->isActive() || mIsZero( pPathObject->getSpeed() ) )
1604    {
1605        // Update Delta.
1606        pPathObject->pushDelta( refObject->getPosition(), refObject->getTransform().getForwardVector() );
1607        // Skip.
1608        return;
1609    }
1610
1611    // Fetch Nodes.
1612    VPathNode *srcNode = mNodeList[pPathObject->getSourceNode()];
1613    VPathNode *dstNode = mNodeList[pPathObject->getDestinationNode()];
1614    VPathNode *lenNode = ( pPathObject->isForward() ) ? srcNode : dstNode;
1615
1616    // Calculate Interp Delta.
1617    const F32 stepDistance    = ( pPathObject->getSpeed() * pDelta );
1618    const F32 speedMod        = ( pPathObject->getSpeed() / lenNode->getLength() );
1619    F32 timeInterp            = pPathObject->getTimeInterp();
1620    F32 timeInterpDelta       = ( speedMod * pDelta );
1621    F32 pathInterp            = pPathObject->getPathInterp();
1622    F32 pathInterpDelta       = 0.f;
1623
1624    // Fetch the old position.
1625    const Point3F oldPosition = pPathObject->getPosition();
1626    // Calculate the new position and path delta.
1627    Point3F newPosition = getAdvancedPathPosition( pPathObject, stepDistance, pathInterpDelta );
1628
1629    // Finished?
1630    if ( ( timeInterp + timeInterpDelta ) >= 1.f )
1631    {
1632        // Finished?
1633        if ( pPathObject->getDestinationNode() == pPathObject->getEndNode() )
1634        {
1635            // Stop Updates.
1636            pPathObject->setActive( false );
1637        }
1638        else
1639        {
1640            // Update Nodes.
1641            const S32 srcNodeIndex = pPathObject->getDestinationNode();
1642            const S32 dstNodeIndex = normalizeNodeIndex( ( pPathObject->isForward() ) ? srcNodeIndex + 1 : srcNodeIndex - 1 );
1643            
1644#ifdef VPATH_DEBUG_STEP
1645            if ( isServerObject() )
1646                Con::errorf( "Change Node:\n  Source, %d\n  Destination, %d", srcNodeIndex, dstNodeIndex );
1647#endif
1648
1649            // Apply Changes.
1650            pPathObject->setNode( srcNodeIndex, dstNodeIndex );
1651            pPathObject->setTimeInterp( 0.f );
1652            pPathObject->setPathInterp( 0.f );
1653            pPathObject->setPosition( newPosition );
1654
1655            // Reset local interp information.
1656            timeInterp = 0.f;
1657            timeInterpDelta = 0.f;
1658            pathInterp = 0.f;
1659            pathInterpDelta = 0.f;
1660
1661            // Fetch the distance we've travelled.
1662            const F32 &advanceDistance = ( newPosition - oldPosition ).len();
1663            // Any remaining distance?
1664            if ( ( stepDistance - advanceDistance ) > 0.0001f )
1665            {
1666                // Determine how much more we need to move.
1667                Point3F newPosition0 = newPosition;
1668                newPosition = getAdvancedPathPosition( pPathObject, ( stepDistance - advanceDistance ), pathInterpDelta );
1669
1670#ifdef VPATH_DEBUG_STEP
1671                if ( isServerObject() )
1672                    Con::errorf( "Transition Step: %f\nTransition Distance: %f + %f = %f", pathInterpDelta, advanceDistance, ( newPosition - newPosition0 ).len(), advanceDistance + ( newPosition - newPosition0 ).len() );
1673#endif
1674            }
1675        }
1676
1677        if ( isServerObject() )
1678        {
1679            // Return Buffer.
1680            char buffer[3][32];
1681            dSprintf( buffer[0], sizeof( buffer[0] ), "%d", refObject->getId() );
1682            dSprintf( buffer[1], sizeof( buffer[1] ), "%d", pPathObject->isActive() ? pPathObject->getSourceNode() : pPathObject->getDestinationNode() );
1683            dSprintf( buffer[2], sizeof( buffer[2] ), "%d", !pPathObject->isActive() );
1684
1685            // Callback.
1686            // VPath::onReachNode( %object, %node, %finished );
1687            Con::executef( this, "onReachNode", buffer[0], buffer[1], buffer[2] );
1688        }
1689    }
1690
1691    // Update Object Interp.
1692    timeInterp = mClampF( timeInterp + timeInterpDelta, 0.f, 1.f );
1693    pathInterp = mClampF( pathInterp + pathInterpDelta, 0.f, 1.f );
1694
1695    // Apply Changes.
1696    pPathObject->setTimeInterp( timeInterp );
1697    pPathObject->setPathInterp( pathInterp );
1698    pPathObject->setPosition( newPosition );
1699
1700#ifdef VPATH_DEBUG_STEP
1701    if ( isServerObject() )
1702        Con::printf( "Time / Distance: %f %f / %f %f", timeInterp, pathInterp, stepDistance, ( newPosition - oldPosition ).len() );
1703#endif
1704
1705    switch ( pPathObject->getOrientationMode().Type )
1706    {
1707        case VPathObject::k_OrientationInterpolate :
1708        case VPathObject::k_OrientationToObject :
1709        case VPathObject::k_OrientationToPoint :
1710            {
1711                // Update Orientation.
1712                updateOrientation( pPathObject );
1713
1714            } break;
1715
1716        case VPathObject::k_OrientationToPath :
1717            {
1718                // Determine the path orientation.
1719                VectorF pathOrientation = ( newPosition - oldPosition );
1720                pathOrientation.normalize();
1721
1722                // Update Orientation.
1723                updateOrientation( pPathObject, pathOrientation );
1724
1725            } break;
1726    }
1727
1728    // Update Delta.
1729    pPathObject->pushDelta( pPathObject->getPosition(), pPathObject->getOrientation() );
1730
1731    if ( isServerObject() )
1732    {
1733        // Update Objects.
1734        setMaskBits( ObjectUpdateMask );
1735
1736        // Update This Object.
1737        pPathObject->setMaskBits( VPathObject::k_StateUpdatePosition );
1738    }
1739}
1740
1741void VPath::updatePosition( VPathObject *pPathObject )
1742{
1743    // Fetch Nodes.
1744    VPathNode *srcNode = getNode( pPathObject->getSourceNode() );
1745    VPathNode *dstNode = getNode( pPathObject->getDestinationNode() );
1746
1747    // Fetch Position.
1748    F32 pathInterp = 0.f;
1749    const Point3F newPosition = getPathPosition( srcNode, dstNode, pPathObject->getTimeInterp(), pPathObject->isForward(), pathInterp );
1750
1751    // Apply Position.
1752    pPathObject->setPosition( newPosition );
1753    pPathObject->setPathInterp( pathInterp );
1754}
1755
1756void VPath::updateOrientation( VPathObject *pPathObject )
1757{
1758    // Update Orientation?
1759    if ( pPathObject->getOrientationMode().Type == VPathObject::k_OrientationFree )
1760    {
1761        // Skip.
1762        return;
1763    }
1764
1765    // Fetch Nodes.
1766    VPathNode *srcNode = getNode( pPathObject->getSourceNode() );
1767    VPathNode *dstNode = getNode( pPathObject->getDestinationNode() );
1768
1769    // Determine Path Orientation.
1770    VectorF pathOrientation;
1771    switch ( pPathObject->getOrientationMode().Type )
1772    {
1773        case VPathObject::k_OrientationInterpolate :
1774            {
1775                // Interpolate Between Transforms.
1776                QuatF rot;
1777                rot.interpolate( srcNode->getWorldRotation(), dstNode->getWorldRotation(), pPathObject->getPathInterp() );
1778
1779                // Set Matrix.
1780                MatrixF mat;
1781                rot.setMatrix( &mat );
1782
1783                // Fetch Orientation.
1784                pathOrientation = mat.getColumn3F( 1 );
1785
1786            } break;
1787
1788        case VPathObject::k_OrientationToObject :
1789            {
1790                // Fetch Orientation.
1791                pathOrientation = ( pPathObject->getOrientationMode().Object->getPosition() - pPathObject->getWorldPosition() );
1792                pathOrientation.normalizeSafe();
1793
1794            } break;
1795
1796        case VPathObject::k_OrientationToPoint :
1797            {
1798                // Fetch Orientation.
1799                pathOrientation = ( pPathObject->getOrientationMode().Point - pPathObject->getWorldPosition() );
1800                pathOrientation.normalizeSafe();
1801
1802            } break;
1803
1804        case VPathObject::k_OrientationToPath :
1805            {
1806                // Fetch Orientation.
1807                pathOrientation = getPathOrientation( srcNode, dstNode, pPathObject->getPathInterp(), pPathObject->isForward() );
1808
1809            } break;
1810    }
1811
1812    // Update.
1813    updateOrientation( pPathObject, pathOrientation );
1814}
1815
1816void VPath::updateOrientation( VPathObject *pPathObject, const Point3F &pPathOrientation )
1817{
1818    // Update Orientation?
1819    if ( pPathObject->getOrientationMode().Type == VPathObject::k_OrientationFree )
1820    {
1821        // Skip.
1822        return;
1823    }
1824
1825    // Fetch Nodes.
1826    VPathNode *srcNode = getNode( pPathObject->getSourceNode() );
1827    VPathNode *dstNode = getNode( pPathObject->getDestinationNode() );
1828
1829    // Determine Source Orientation.
1830    VectorF srcOrientation;
1831    switch ( srcNode->getOrientationMode().Type )
1832    {
1833        case VPathNode::k_OrientationToPoint :
1834            {
1835                // Fetch Orientation.
1836                srcOrientation = ( srcNode->getOrientationMode().Point - pPathObject->getWorldPosition() );
1837                srcOrientation.normalize();
1838
1839            } break;
1840
1841        default :
1842            {
1843                // Use Path Orientation.
1844                srcOrientation = pPathOrientation;
1845
1846            } break;
1847    }
1848
1849    // Determine Destination Orientation.
1850    VectorF dstOrientation;
1851    switch ( dstNode->getOrientationMode().Type )
1852    {
1853        case VPathNode::k_OrientationToPoint :
1854            {
1855                // Fetch Orientation.
1856                dstOrientation = ( dstNode->getOrientationMode().Point - pPathObject->getWorldPosition() );
1857                dstOrientation.normalize();
1858
1859            } break;
1860
1861        default :
1862            {
1863                // Use Path Orientation.
1864                dstOrientation = pPathOrientation;
1865
1866            } break;
1867    }
1868
1869    // Determine Actual Orientation.
1870    VectorF orientation;
1871    orientation.interpolate( srcOrientation, dstOrientation, pPathObject->getTimeInterp() );
1872
1873    // Apply.
1874    pPathObject->setOrientation( orientation );
1875}
1876
1877//-----------------------------------------------------------------------------
1878//
1879// Path Methods.
1880//
1881//-----------------------------------------------------------------------------
1882
1883void VPath::calculatePath( void )
1884{
1885    if ( mNodeList.size() < 2 )
1886    {
1887        // No Path.
1888        return;
1889    }
1890
1891    switch ( mPathType )
1892    {
1893        case k_PathLinear : 
1894            {
1895                for ( VPathNodeIterator itr = mNodeList.begin(); itr != mNodeList.end(); itr++ )
1896                {
1897                    if ( itr == ( mNodeList.end() - 1 ) )
1898                    {
1899                        // Head, Front.
1900                        calculateLinearPath( ( *itr ), ( *( mNodeList.begin() ) ) );
1901                    }
1902                    else
1903                    {
1904                        // Head, Next.
1905                        calculateLinearPath( ( *itr ), ( *( itr + 1 ) ) );
1906                    }
1907                }
1908
1909            } break;
1910
1911        case k_PathBezier :
1912            {
1913                for ( VPathNodeIterator itr = mNodeList.begin(); itr != mNodeList.end(); itr++ )
1914                {
1915                    if ( itr == ( mNodeList.end() - 1 ) )
1916                    {
1917                        // Head, Prev, Front.
1918                        calculateBezierPath( ( *itr ), ( *( mNodeList.begin() ) ) );
1919                    }
1920                    else
1921                    {
1922                        // Head, Prev, Next.
1923                        calculateBezierPath( ( *itr ), ( *( itr + 1 ) ) );
1924                    }
1925                }
1926
1927            } break;
1928    }
1929}
1930
1931Point3F VPath::getAdvancedPathPosition( VPathObject *pPathObject, const F32 &pTargetDistance, F32 &pPathInterpDelta )
1932{
1933    switch( mPathType )
1934    {
1935        case k_PathLinear : 
1936            {
1937                return getAdvancedLinearPathPosition( pPathObject, pTargetDistance, pPathInterpDelta );
1938
1939            } break;
1940
1941        case k_PathBezier :
1942            {
1943                return getAdvancedBezierPathPosition( pPathObject, pTargetDistance, pPathInterpDelta );
1944
1945            } break;
1946    }
1947
1948    // Sanity!
1949    AssertFatal( false, "Invalid path type!" );
1950    return Point3F::Zero;
1951}
1952
1953DefineEngineMethod( VPath, getPathTransform, const char *, (S32 srcNodeIndex, S32 dstNodeIndex, F32 timeInterp), (0,0,1.0), "( int pSrcNodeIndex, int pDstNodeIndex, float pTimeInterp ) - Get the transform of the path at the interp point between two nodes.\n"
1954                                                            "@param pSrcNodeIndex The first node.\n"
1955                                                            "@param pDstNodeIndex The second node.\n"
1956                                                            "@param pTimeInterp The time to interp between the two nodes. Value is between 0.0 and 1.0.\n"
1957                                                            "@return Returns the transform of the interp time between the two given nodes." )
1958{
1959    // Fetch Nodes.
1960    VPathNode *srcNode = object->getNode(srcNodeIndex);
1961    VPathNode *dstNode = object->getNode(dstNodeIndex);
1962
1963    // Interp Time.
1964    const F32 &interp = timeInterp;
1965
1966    // Fetch Position & Orientation.
1967    const Point3F position    = object->getPathPosition( srcNode, dstNode, interp, true );
1968    const VectorF orientation = object->getPathOrientation( srcNode, dstNode, interp, true );
1969
1970    // Y-Axis.
1971    VectorF yVec = orientation;
1972    yVec.normalize();
1973
1974    // X-Axis.
1975    VectorF xVec = mCross( yVec, VPath::gBezierUp );
1976    xVec.normalize();
1977
1978    // Z-Axis.
1979    VectorF zVec = mCross( xVec, yVec );
1980    zVec.normalize();
1981
1982    // Setup Object Transform.
1983    MatrixF mat( true );
1984    mat.setColumn( 0, xVec );
1985    mat.setColumn( 1, yVec );
1986    mat.setColumn( 2, zVec );
1987
1988    // AngAxis.
1989    AngAxisF aa( mat );
1990
1991    // Return Buffer;
1992    char *buffer = Con::getReturnBuffer( 256 );
1993    dSprintf( buffer, 256, "%g %g %g %g %g %g %g", position.x, position.y, position.z,
1994                                                   aa.axis.x, aa.axis.y, aa.axis.z, aa.angle );
1995
1996    // Return.
1997    return buffer;
1998}
1999
2000DefineEngineMethod( VPath, getPathPosition, const char *, (S32 srcNodeIndex, S32 dstNodeIndex, F32 timeInterp), (0, 0, 1.0), "( int pSrcNodeIndex, int pDstNodeIndex, int pTimeInterp ) - Get the world position of the path at the interp point between two nodes.\n"
2001                                                           "@param pSrcNodeIndex The first node.\n"
2002                                                           "@param pDstNodeIndex The second node.\n"
2003                                                           "@param pTimeInterp The time to interp between the two nodes. Value is between 0.0 and 1.0.\n"
2004                                                           "@return Returns the world position of the interp time between the two given nodes." )
2005{
2006    // Fetch Nodes.
2007    VPathNode *srcNode = object->getNode(srcNodeIndex);
2008    VPathNode *dstNode = object->getNode(dstNodeIndex);
2009
2010    // Interp Time.
2011    const F32 &interp = timeInterp;
2012
2013    // Find Position.
2014    const Point3F position = object->getPathPosition( srcNode, dstNode, interp, true );
2015
2016    // Return Buffer;
2017    char *buffer = Con::getReturnBuffer( 128 );
2018    dSprintf( buffer, 128, "%g %g %g", position.x, position.y, position.z );
2019
2020    // Return.
2021    return buffer;
2022}
2023
2024Point3F VPath::getPathPosition( VPathNode *pSourceNode, VPathNode *pDestinationNode, const F32 &pTimeInterp, const bool &pForward )
2025{
2026    F32 pathInterp = 0.f;
2027    return getPathPosition( pSourceNode, pDestinationNode, pTimeInterp, pForward, pathInterp );
2028}
2029
2030Point3F VPath::getPathPosition( VPathNode *pSourceNode, VPathNode *pDestinationNode, const F32 &pTimeInterp, const bool &pForward, F32 &pPathInterp )
2031{
2032    switch( mPathType )
2033    {
2034        case k_PathBezier :
2035            {
2036                return getBezierPathPosition( pSourceNode, pDestinationNode, pTimeInterp, pForward, pPathInterp );
2037
2038            } break;
2039
2040        case k_PathLinear :
2041            {
2042                return getLinearPathPosition( pSourceNode, pDestinationNode, pTimeInterp, pForward, pPathInterp );
2043
2044            } break;
2045    }
2046
2047    // NULL.
2048    return Point3F::Zero;
2049}
2050
2051VectorF VPath::getPathOrientation( VPathNode *pSourceNode, VPathNode *pDestinationNode, const F32 &pTimeInterp, const bool &pForward )
2052{
2053    switch( mPathType )
2054    {
2055        case k_PathBezier :
2056            {
2057                return getBezierPathOrientation( pSourceNode, pDestinationNode, pTimeInterp, pForward );
2058
2059            } break;
2060
2061        case k_PathLinear :
2062            {
2063                return getLinearPathOrientation( pSourceNode, pDestinationNode, pTimeInterp, pForward );
2064
2065            } break;
2066    }
2067
2068    // NULL.
2069    return VectorF::Zero;
2070}
2071
2072//-----------------------------------------------------------------------------
2073//
2074// Linear Path Methods.
2075//
2076//-----------------------------------------------------------------------------
2077
2078void VPath::calculateLinearPath( VPathNode *pNode, VPathNode *pNextNode )
2079{
2080    // Calculate Segment Length.
2081    pNode->setLength( ( pNextNode->getWorldPosition() - pNode->getWorldPosition() ).len() );
2082}
2083
2084Point3F VPath::getAdvancedLinearPathPosition( VPathObject *pPathObject, const F32 &pTargetDistance, F32 &pPathInterpDelta )
2085{
2086    // Fetch Nodes.
2087    VPathNode *srcNode = mNodeList[pPathObject->getSourceNode()];
2088    VPathNode *dstNode = mNodeList[pPathObject->getDestinationNode()];
2089
2090    // Fetch the length of the segment.
2091    const F32 length = ( pPathObject->isForward() ) ? srcNode->getLength() : dstNode->getLength();
2092
2093    // Set the interp delta.
2094    pPathInterpDelta = ( pTargetDistance / length );
2095
2096    // Return the position.
2097    F32 pathInterp = 0.f;
2098    return getLinearPathPosition( srcNode, dstNode, pPathObject->getPathInterp(), pPathObject->isForward(), pathInterp );
2099}
2100
2101Point3F VPath::getLinearPathPosition( VPathNode *pSourceNode, VPathNode *pDestinationNode, const F32 &pTimeInterp, const bool &pForward, F32 &pPathInterp )
2102{
2103    // Set path interp to the time interp.
2104    pPathInterp = pTimeInterp;
2105
2106    if ( pTimeInterp <= 0.f )
2107    {
2108        // Source Node.
2109        return pSourceNode->getWorldPosition();
2110    }
2111    else if ( pTimeInterp >= 1.f )
2112    {
2113        // Destination Node.
2114        return pDestinationNode->getWorldPosition();
2115    }
2116
2117    // Calculate Position.
2118    Point3F position;
2119    position.interpolate( pSourceNode->getWorldPosition(), pDestinationNode->getWorldPosition(), pTimeInterp );
2120
2121    // Return.
2122    return position;
2123}
2124
2125VectorF VPath::getLinearPathOrientation( VPathNode *pSourceNode, VPathNode *pDestinationNode, const F32 &pTimeInterp, const bool &pForward )
2126{
2127    // Calculate Orientation.
2128    VectorF newOrientation = ( pDestinationNode->getWorldPosition() - pSourceNode->getWorldPosition() );
2129    newOrientation.normalizeSafe();
2130
2131    // Return.
2132    return newOrientation;
2133}
2134
2135//-----------------------------------------------------------------------------
2136//
2137// Bezier Path Methods.
2138//
2139//-----------------------------------------------------------------------------
2140
2141void VPath::calculateBezierPath( VPathNode *pNode, VPathNode *pNextNode )
2142{
2143    // Reset Length.
2144    F32 segmentLength = 0.f;
2145
2146    // Positions.
2147    const Point3F &pt0 = pNode->getWorldPosition();
2148    const Point3F &pt3 = pNextNode->getWorldPosition();
2149
2150    // Fetch Node Rotation Matrices.
2151    MatrixF mat0, mat1;
2152    pNode->getWorldRotation().setMatrix( &mat0 );
2153    pNextNode->getWorldRotation().setMatrix( &mat1 );
2154
2155    // Determine Tangent Axis.
2156    Point3F pt1(  gBezierAxis * pNode->getWeight() );
2157    Point3F pt2( -gBezierAxis * pNextNode->getWeight() );
2158
2159    // Rotate Axis.
2160    mat0.mulP( pt1 );
2161    mat1.mulP( pt2 );
2162
2163    // Offset Points.
2164    pt1 += pt0;
2165    pt2 += pt3;
2166
2167    // Initial Position.
2168    Point3F ptA = pt0;
2169    const F32 i = gBezierInterpStep;
2170    for ( F32 t = 0.f, it = ( 1.f - t ); t <= 1.f; t += i, it = ( 1.f - t ) )
2171    {
2172        // Calculate Position.
2173        Point3F ptB = ( pt0 * it * it * it ) + ( 3 * pt1 * it * it * t ) + ( 3 * pt2 * it * t * t ) + ( pt3 * t * t * t );
2174
2175        // Add Segment.
2176        segmentLength += ( ptB - ptA ).len();
2177
2178        // Store Position.
2179        ptA = ptB;
2180    }
2181
2182    // Apply Update.
2183    pNode->setLength( segmentLength );
2184}
2185
2186Point3F VPath::getAdvancedBezierPathPosition( VPathObject *pPathObject, const F32 &pTargetDistance, F32 &pPathInterpDelta )
2187{
2188    // Fetch Nodes.
2189    VPathNode *srcNode = mNodeList[pPathObject->getSourceNode()];
2190    VPathNode *dstNode = mNodeList[pPathObject->getDestinationNode()];
2191
2192    // Fetch the delta position.
2193    return getBezierPathPosition( srcNode, dstNode, pPathObject->getPathInterp(), pPathObject->getPosition(), pTargetDistance, pPathObject->isForward(), true, pPathInterpDelta );
2194}
2195
2196Point3F VPath::getBezierPathPosition( VPathNode *pSourceNode, VPathNode *pDestinationNode, const F32 &pTimeInterp, const bool &pForward, F32 &pPathInterp )
2197{
2198    // Fetch the length of the segment.
2199    const F32 length = ( pForward ) ? pSourceNode->getLength() : pDestinationNode->getLength();
2200
2201    // Determine the real interp time for the distance fraction.
2202    return getBezierPathPosition( pSourceNode, pDestinationNode, 0.f, pSourceNode->getWorldPosition(), ( length * pTimeInterp ), pForward, false, pPathInterp );
2203}
2204
2205Point3F VPath::getBezierPathPosition( VPathNode *pSourceNode, VPathNode *pDestinationNode, const F32 &pTimeInterp, const Point3F &pReferencePosition, const F32 &pTargetDistance, const bool &pForward, const bool &pRelativeToReference, F32 &pPathInterpDelta )
2206{
2207    // Positions.
2208    const Point3F &pt0 = pSourceNode->getWorldPosition();
2209    const Point3F &pt3 = pDestinationNode->getWorldPosition();
2210
2211    // Fetch Node Rotation Matrices.
2212    MatrixF mat0, mat1;
2213    pSourceNode->getWorldRotation().setMatrix( &mat0 );
2214    pDestinationNode->getWorldRotation().setMatrix( &mat1 );
2215
2216    // Determine Tangent Axis.
2217    Point3F pt1(  gBezierAxis * pSourceNode->getWeight() );
2218    Point3F pt2( -gBezierAxis * pDestinationNode->getWeight() );
2219
2220    if ( !pForward )
2221    {
2222        pt1 *= -1.f;
2223        pt2 *= -1.f;
2224    }
2225
2226    // Rotate Axis.
2227    mat0.mulP( pt1 );
2228    mat1.mulP( pt2 );
2229
2230    // Offset Points.
2231    pt1 += pt0;
2232    pt2 += pt3;
2233
2234    // Move Position.
2235    Point3F movePosition = pReferencePosition;
2236    // Movement Distance.
2237    F32 moveDistance = 0.f;
2238
2239    // Determine the Real Delta.
2240    const F32 i = gBezierInterpStep;
2241    for ( F32 t = ( pTimeInterp + i ), it = ( 1.f - t ); t <= 1.f; t += i, it = ( 1.f - t ) )
2242    {
2243        // Calculate Step.
2244        const Point3F stepPosition = ( pt0 * it * it * it ) + ( 3 * pt1 * it * it * t ) + ( 3 * pt2 * it * t * t ) + ( pt3 * t * t * t );
2245        // Step Length.
2246        const F32 &stepDistance = ( stepPosition - movePosition ).len();
2247
2248        if ( pRelativeToReference )
2249        {
2250            // Calculate Distance.
2251            moveDistance = ( pReferencePosition - stepPosition ).len();
2252
2253            // Moved Target Distance?
2254            if ( moveDistance >= pTargetDistance )
2255            {
2256                // Interpolate Step.
2257                const F32 stepInterp = ( moveDistance - pTargetDistance ) / moveDistance;
2258                // Store Interp Delta.
2259                pPathInterpDelta = ( t - pTimeInterp ) * ( 1.f - stepInterp );
2260                
2261                // Interpolate the step.
2262                Point3F outPosition;
2263                outPosition.interpolate( pReferencePosition, stepPosition, ( 1.f - stepInterp ) );
2264                // Return the position.
2265                return outPosition;
2266            }
2267        }
2268        else
2269        {
2270            // Calculate Distance.
2271            moveDistance += stepDistance;
2272
2273            // Moved Target Distance?
2274            if ( moveDistance >= pTargetDistance )
2275            {
2276                // Interpolate Step.
2277                const F32 stepInterp = ( moveDistance - pTargetDistance ) / stepDistance;
2278                // Store Interp Delta.
2279                pPathInterpDelta = ( t - pTimeInterp ) - ( stepInterp * i );
2280                
2281                // Interpolate the step.
2282                Point3F outPosition;
2283                outPosition.interpolate( movePosition, stepPosition, ( 1.f - stepInterp ) );
2284                // Return the position.
2285                return outPosition;
2286            }
2287        }
2288
2289        // Apply New Position.
2290        movePosition = stepPosition;
2291    }
2292    
2293    // Update.
2294    pPathInterpDelta = ( 1.f - pTimeInterp );
2295    // At the destination node?
2296    return pt3;
2297}
2298
2299VectorF VPath::getBezierPathOrientation( VPathNode *pSourceNode, VPathNode *pDestinationNode, const F32 &pTimeInterp, const bool &pForward )
2300{
2301    // Positions.
2302    const Point3F &pt0 = pSourceNode->getWorldPosition();
2303    const Point3F &pt3 = pDestinationNode->getWorldPosition();
2304
2305    // Fetch Node Rotation Matrices.
2306    MatrixF mat0, mat1;
2307    pSourceNode->getWorldRotation().setMatrix( &mat0 );
2308    pDestinationNode->getWorldRotation().setMatrix( &mat1 );
2309
2310    // Determine Tangent Axis.
2311    Point3F pt1(  gBezierAxis * pSourceNode->getWeight() );
2312    Point3F pt2( -gBezierAxis * pDestinationNode->getWeight() );
2313
2314    if ( !pForward )
2315    {
2316        pt1 *= -1.f;
2317        pt2 *= -1.f;
2318    }
2319
2320    // Rotate Axis.
2321    mat0.mulP( pt1 );
2322    mat1.mulP( pt2 );
2323
2324    const F32 halfStep = ( gBezierInterpStep / 2.f );
2325    if ( ( pTimeInterp - halfStep ) <= 0.f )
2326    {
2327        // Orientation From Node Tangent.
2328        pt1.normalize();
2329
2330        // Return.
2331        return pt1;
2332    }
2333    else if ( ( pTimeInterp + halfStep ) >= 1.f )
2334    {
2335        // Orientation From Node Tangent.
2336        pt2.normalize();
2337
2338        // Return.
2339        return -pt2;
2340    }
2341
2342    // Offset Points.
2343    pt1 += pt0;
2344    pt2 += pt3;
2345
2346    // Interp Times.
2347    const F32 t0  = ( pTimeInterp - halfStep );
2348    const F32 it0 = ( 1.f - t0 );
2349
2350    const F32 t1  = ( pTimeInterp + halfStep );
2351    const F32 it1 = ( 1.f - t1 );
2352
2353    // Calculate Position.
2354    Point3F d0 = ( pt0 * it0 * it0 * it0 ) + ( 3 * pt1 * it0 * it0 * t0 ) + ( 3 * pt2 * it0 * t0 * t0 ) + ( pt3 * t0 * t0 * t0 );
2355    Point3F d1 = ( pt0 * it1 * it1 * it1 ) + ( 3 * pt1 * it1 * it1 * t1 ) + ( 3 * pt2 * it1 * t1 * t1 ) + ( pt3 * t1 * t1 * t1 );
2356
2357    // Set Orientation.
2358    Point3F orientation = ( d1 - d0 );
2359    orientation.normalizeSafe();
2360
2361    // Return.
2362    return orientation;
2363}
2364
2365//-----------------------------------------------------------------------------
2366//
2367// Path Node Property Methods.
2368//
2369//-----------------------------------------------------------------------------
2370
2371DefineEngineMethod( VPath, getNodeCount, S32, (),, "() - Get the number of nodes in this path.\n"
2372                                               "@return Returns the number of nodes." )
2373{
2374    // Return Count.
2375    return object->getNodeCount();
2376}
2377
2378S32 VPath::getNodeCount( void )
2379{
2380    // Return the Size of the Node List.
2381    return mNodeList.size();
2382}
2383
2384DefineEngineMethod( VPath, getNodeLocalTransform, const char *, (S32 nodeIndex), (0), "( int pNodeIndex ) - Get the local transform (local position and rotation) of the given node.\n"
2385                                                                 "@param pNodeIndex The index of the node.\n"
2386                                                                 "@return Returns the transform of the given node." )
2387{
2388    // Fetch Position.
2389    const Point3F &position = object->getNodeLocalPosition(nodeIndex);
2390
2391    // Fetch Rotation.
2392    const QuatF   &rotation = object->getNodeLocalRotation(nodeIndex);
2393
2394    // Angle & Axis.
2395    AngAxisF aa( rotation );
2396
2397    // Return Buffer.
2398    char *buffer = Con::getReturnBuffer( 256 );
2399    dSprintf( buffer, 128, "%.3g %.3g %.3g %.3g %.3g %.3g %.3g", position.x, position.y, position.z, aa.axis.x, aa.axis.y, aa.axis.z, aa.angle );
2400
2401    return buffer;
2402}
2403
2404DefineEngineMethod( VPath, getNodeLocalPosition, Point3F, (S32 nodeIndex), (0), "( int pNodeIndex ) - Get the position of the given node.\n"
2405                                                                "@param pNodeIndex The index of the node.\n"
2406                                                           "    @return Returns the Local Position of the given node." )
2407{
2408    // Fetch Position.
2409    const Point3F &position = object->getNodeLocalPosition(nodeIndex);
2410
2411    return position;
2412}
2413
2414Point3F VPath::getNodeLocalPosition( const S32 &pNodeIndex )
2415{
2416    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2417    {
2418        // Woops!
2419        Con::warnf( "VPath::getNodeLocalPosition() - Invalid Index Specified (%d).", pNodeIndex );
2420        return Point3F::Zero;
2421    }
2422
2423    return mNodeList[pNodeIndex]->getLocalPosition();
2424}
2425
2426DefineEngineMethod( VPath, getNodeLocalRotation, AngAxisF, (S32 nodeIndex), (0), "( int pNodeIndex ) - Get the Local Rotation of the given node.\n"
2427                                                                "@param pNodeIndex The index of the node.\n"
2428                                                                "@return Returns the Local Rotation of the given node." )
2429{
2430    // Fetch Rotation.
2431    const QuatF &rotation = object->getNodeLocalRotation(nodeIndex);
2432
2433    // Angle & Axis.
2434    AngAxisF aa( rotation );
2435
2436    return aa;
2437}
2438
2439QuatF VPath::getNodeLocalRotation( const S32 &pNodeIndex )
2440{
2441    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2442    {
2443        // Woops!
2444        Con::warnf( "VPath::getNodeLocalRotation() - Invalid Index Specified (%d).", pNodeIndex );
2445        return QuatF( Point3F::Zero, 0.f );
2446    }
2447
2448    return mNodeList[pNodeIndex]->getLocalRotation();
2449}
2450
2451DefineEngineMethod( VPath, getNodeWorldTransform, TransformF, (S32 nodeIndex), (0), "( int pNodeIndex ) - Get the World Transform (position and rotation) of the given node.\n"
2452                                                                 "@param pNodeIndex The index of the node.\n"
2453                                                                 "@return Returns the transform of the given node." )
2454{
2455    // Fetch Position.
2456    const Point3F &position = object->getNodeWorldPosition(nodeIndex);
2457
2458    // Fetch Rotation.
2459    const QuatF   &rotation = object->getNodeWorldRotation(nodeIndex);
2460
2461    // Angle & Axis.
2462    AngAxisF aa( rotation );
2463
2464    TransformF trans;
2465    trans.mPosition = position;
2466    trans.mOrientation = aa;
2467
2468    return trans;
2469}
2470
2471DefineEngineMethod( VPath, getNodeWorldPosition, Point3F, (S32 nodeIndex), (0), "( int pNodeIndex ) - Get the position of the given node.\n"
2472                                                                "@param pNodeIndex The index of the node.\n"
2473                                                                "@return Returns the World Position of the given node." )
2474{
2475    // Fetch Position.
2476    const Point3F &position = object->getNodeWorldPosition(nodeIndex);
2477
2478    return position;
2479}
2480
2481Point3F VPath::getNodeWorldPosition( const S32 &pNodeIndex )
2482{
2483    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2484    {
2485        // Woops!
2486        Con::warnf( "VPath::getNodeWorldPosition() - Invalid Index Specified (%d).", pNodeIndex );
2487        return Point3F::Zero;
2488    }
2489
2490    return mNodeList[pNodeIndex]->getWorldPosition();
2491}
2492
2493DefineEngineMethod( VPath, getNodeWorldRotation, AngAxisF, (S32 nodeIndex), (0), "( int pNodeIndex ) - Get the World Rotation of the given node.\n"
2494                                                                "@param pNodeIndex The index of the node.\n"
2495                                                                "@return Returns the World Rotation of the given node." )
2496{
2497    // Fetch Rotation.
2498    const QuatF &rotation = object->getNodeWorldRotation(nodeIndex);
2499
2500    // Angle & Axis.
2501    AngAxisF aa( rotation );
2502
2503    return aa;
2504}
2505
2506QuatF VPath::getNodeWorldRotation( const S32 &pNodeIndex )
2507{
2508    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2509    {
2510        // Woops!
2511        Con::warnf( "VPath::getNodeWorldRotation() - Invalid Index Specified (%d).", pNodeIndex );
2512        return QuatF( Point3F::Zero, 0.f );
2513    }
2514
2515    return mNodeList[pNodeIndex]->getWorldRotation();
2516}
2517
2518DefineEngineMethod( VPath, getNodeWeight, F32, (S32 nodeIndex), (0), "( int pNodeIndex ) - Get the weight of the given node.\n"
2519                                                "@param pNodeIndex The index of the node.\n"
2520                                                "@return Returns the weight of the given node." )
2521{
2522    // Fetch Weight.
2523    return object->getNodeWeight(nodeIndex);
2524}
2525
2526F32 VPath::getNodeWeight( const S32 &pNodeIndex )
2527{
2528    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2529    {
2530        // Woops!
2531        Con::warnf( "VPath::getNodeWeight() - Invalid Index Specified (%d).", pNodeIndex );
2532        return 0.f;
2533    }
2534
2535    return mNodeList[pNodeIndex]->getWeight();
2536}
2537
2538DefineEngineMethod( VPath, getNodeLength, F32, (S32 nodeIndex), (0), "( int pNodeIndex ) - Get the length of the given node.\n"
2539                                                "@param pNodeIndex The index of the node.\n"
2540                                                "@return Returns the length of the given node." )
2541{
2542    // Fetch Length.
2543    return object->getNodeLength( nodeIndex );
2544}
2545
2546F32 VPath::getNodeLength( const S32 &pNodeIndex )
2547{
2548    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2549    {
2550        // Woops!
2551        Con::warnf( "VPath::getNodeLength() - Invalid Index Specified (%d).", pNodeIndex );
2552        return 0.f;
2553    }
2554
2555    return mNodeList[pNodeIndex]->getLength();
2556}
2557
2558DefineEngineMethod( VPath, setNodeTransform, void, (S32 nodeIndex, TransformF transform), (0, MatrixF::Identity), "( int pNodeIndex, matrix pTransform ) - Set the transform of the given node.\n"
2559                                                    "@param pNodeIndex The index of the node.\n"
2560                                                    "@param pTransform The new transform to be applied to the node.\n"
2561                                                    "@return No return value." )
2562{
2563    // Fetch Position & Rotation.
2564    Point3F position = transform.mPosition;
2565    AngAxisF aa = transform.mOrientation;
2566    QuatF    rotation;
2567
2568    // Set Rotation.
2569    rotation.set( aa );
2570
2571    // Apply Update.
2572    object->setNodePosition( nodeIndex, position );
2573    object->setNodeRotation( nodeIndex, rotation );
2574}
2575
2576DefineEngineMethod( VPath, setNodePosition, void, (S32 nodeIndex, Point3F position), (0, Point3F::Zero), "( int pNodeIndex, vector pPosition ) - Set the position of the given node.\n"
2577                                                   "@param pNodeIndex The index of the node.\n"
2578                                                   "@param pPosition The new position to be applied to the node.\n"
2579                                                   "@return No return value." )
2580{
2581    // Apply Update.
2582    object->setNodePosition( nodeIndex, position );
2583}
2584
2585void VPath::setNodePosition( const S32 &pNodeIndex, const Point3F &pPosition )
2586{
2587    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2588    {
2589        // Woops!
2590        Con::warnf( "VPath::setNodePosition() - Invalid Index Specified (%d).", pNodeIndex );
2591        return;
2592    }
2593
2594    // Fetch Node.
2595    VPathNode *node = mNodeList[pNodeIndex];
2596
2597    // Apply Update.
2598    node->setLocalPosition( pPosition );
2599
2600    // Update Size.
2601    updateContainer();
2602
2603    // Calculate Path.
2604    calculatePath();
2605
2606    if ( isServerObject() )
2607    {
2608        // Network Flags.
2609        setMaskBits( NodeUpdateMask );
2610    }
2611}
2612
2613DefineEngineMethod( VPath, setNodeRotation, void, (S32 nodeIndex, AngAxisF aa), (0, AngAxisF()), "( int pNodeIndex, angAxis pRotation ) - Set the rotation of the given node.\n"
2614                                                   "@param pNodeIndex The index of the node.\n"
2615                                                   "@param pRotation The new rotation to be applied to the node.\n"
2616                                                   "@return No return value."  )
2617{
2618    QuatF    rotation;
2619
2620    // Set Rotation.
2621    rotation.set( aa );
2622
2623    // Apply Update.
2624    object->setNodeRotation( nodeIndex, rotation );
2625}
2626
2627void VPath::setNodeRotation( const S32 &pNodeIndex, const QuatF &pRotation )
2628{
2629    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2630    {
2631        // Woops!
2632        Con::warnf( "VPath::setNodeRotation() - Invalid Index Specified (%d).", pNodeIndex );
2633        return;
2634    }
2635
2636    // Fetch Node.
2637    VPathNode *node = mNodeList[pNodeIndex];
2638
2639    // Apply Update.
2640    node->setLocalRotation( pRotation );
2641
2642    // Calculate Path.
2643    calculatePath();
2644
2645    if ( isServerObject() )
2646    {
2647        // Network Flags.
2648        setMaskBits( NodeUpdateMask );
2649    }
2650}
2651
2652DefineEngineMethod( VPath, setNodeWeight, void, (S32 nodeIndex, F32 nodeWeight), (0, 1.0), "( int pNodeIndex, float pWeight ) - Set the weight of the given node.\n"
2653                                                 "@param pNodeIndex The index of the node.\n"
2654                                                 "@param pWeight The new weight to be applied to the node.\n"
2655                                                 "@return No return value."  )
2656{
2657    // Apply Update.
2658    object->setNodeWeight( nodeIndex, nodeWeight );
2659}
2660
2661void VPath::setNodeWeight( const S32 &pNodeIndex, const F32 &pWeight )
2662{
2663    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2664    {
2665        // Woops!
2666        Con::warnf( "VPath::setNodeWeight() - Invalid Index Specified (%d).", pNodeIndex );
2667        return;
2668    }
2669
2670    // Fetch Node.
2671    VPathNode *node = mNodeList[pNodeIndex];
2672
2673    // Apply Update.
2674    node->setWeight( pWeight );
2675
2676    // Calculate Path.
2677    calculatePath();
2678
2679    if ( isServerObject() )
2680    {
2681        // Network Flags.
2682        setMaskBits( NodeUpdateMask );
2683    }
2684}
2685
2686DefineEngineMethod( VPath, getNodeOrientationMode, const char *, (S32 nodeIndex), (0), "( int pNodeIndex ) - Gets the current orientation mode of the node.\n"
2687                                                                  "@param pNodeIndex The index of the node.\n"
2688                                                                  "@return Returns a string indicating the orientation mode and its properties." )
2689{
2690    if ( nodeIndex < 0 || nodeIndex >= object->getNodeCount() )
2691    {
2692        // Woops!
2693        Con::warnf( "VPath::getNodeOrientationMode() - Invalid Index Specified (%d).", nodeIndex );
2694        return "";
2695    }
2696
2697    // Fetch Object
2698    VPathNode *node = object->getNode( nodeIndex );
2699
2700    // Fetch Orientation Mode.
2701    const VPathNode::sOrientation &orientation = node->getOrientationMode();
2702
2703    // Determine the Type.
2704    StringTableEntry type = VPathNode::getOrientationTypeLabel( orientation.Type );
2705
2706    // Buffer.
2707    char *buffer = Con::getReturnBuffer( 128 );
2708
2709    switch( orientation.Type )
2710    {
2711        case VPathNode::k_OrientationFree :
2712            {
2713                // Buffer String.
2714                dSprintf( buffer, 128, "%s", type );
2715
2716            } break;
2717
2718        case VPathNode::k_OrientationToPoint:
2719            {
2720                // Fetch Point.
2721                const Point3F &lookAtPoint = orientation.Point;
2722                // Buffer String.
2723                dSprintf( buffer, 128, "%s\t%.2f %.2f %.2f", type, lookAtPoint.x, lookAtPoint.y, lookAtPoint.z );
2724
2725            } break;
2726    }
2727
2728    // Return Buffer.
2729    return buffer;
2730}
2731
2732DefineEngineStringlyVariadicMethod( VPath, setNodeOrientationMode, void, 4, 5, "( int pNodeIndex, string pOrientationType, [vector pPoint] ) - Set the orientation mode of the node.\n"
2733                                                          "@param pNodeIndex The index of the node.\n"
2734                                                          "@param pOrientationType The new orientation type of the object.\n"
2735                                                          "@param pPoint If the orientation type is set to POINT, this parameter must be a vector.\n"
2736                                                          "@return No return value." )
2737{
2738    // Fetch Index.
2739    const S32 nodeIndex = dAtoi( argv[2] );
2740
2741    // Orient?
2742    const VPathNode::eOrientationType type = VPathNode::getOrientationTypeEnum( argv[3] );
2743
2744    switch ( type )
2745    {
2746        case VPathNode::k_OrientationFree :
2747            {
2748                // Apply Mode.
2749                object->setNodeOrientationMode( nodeIndex, type );
2750
2751            } break;
2752
2753        case VPathNode::k_OrientationToPoint:
2754            {
2755                // Fetch Point.
2756                Point3F lookAtPoint( 0.f, 0.f, 0.f );
2757                dSscanf( argv[4], "%g %g %g", &lookAtPoint.x, &lookAtPoint.y, &lookAtPoint.z );
2758
2759                // Apply Mode.
2760                object->setNodeOrientationMode( nodeIndex, type, lookAtPoint );
2761
2762            } break;
2763
2764        default :
2765            {
2766                AssertFatal( false, "VPath::setNodeOrientationMode() - Invalid Orientation Mode Specified." );
2767
2768            } break;
2769    }
2770}
2771
2772void VPath::setNodeOrientationMode( const S32 &pNodeIndex, const VPathNode::eOrientationType &pType )
2773{
2774    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2775    {
2776        // Woops!
2777        Con::warnf( "VPath::setNodeOrientationMode() - Invalid Index Specified (%d).", pNodeIndex );
2778        return;
2779    }
2780
2781    // Fetch Node.
2782    VPathNode *node = mNodeList[pNodeIndex];
2783
2784    // Apply.
2785    node->setOrientationMode( pType );
2786
2787    // Network Flags.
2788    setMaskBits( NodeUpdateMask );
2789}
2790
2791void VPath::setNodeOrientationMode( const S32 &pNodeIndex, const VPathNode::eOrientationType &pType, const Point3F pPoint )
2792{
2793    if ( pNodeIndex < 0 || pNodeIndex >= mNodeList.size() )
2794    {
2795        // Woops!
2796        Con::warnf( "VPath::setNodeOrientationMode() - Invalid Index Specified (%d).", pNodeIndex );
2797        return;
2798    }
2799
2800    // Fetch Node.
2801    VPathNode *node = mNodeList[pNodeIndex];
2802
2803    // Apply.
2804    node->setOrientationMode( pType, pPoint );
2805
2806    // Network Flags.
2807    setMaskBits( NodeUpdateMask );
2808}
2809
2810//-----------------------------------------------------------------------------
2811//
2812// Path Object Property Methods.
2813//
2814//-----------------------------------------------------------------------------
2815
2816DefineEngineMethod( VPath, isPathObjectActive, bool, (SceneObject *sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Is the object actively traveling around this path?\n"
2817                                                      "@param pObject The SimObjectID of the object being observed.\n"
2818                                                      "@return Returns true of the object is active." )
2819{
2820    // Fetch Object.
2821    if (sceneObject == nullptr)
2822    {
2823        Con::errorf( "VPath::isPathObjectActive() - Invalid Target Object." );
2824        return false;
2825    }
2826
2827    // Fetch Object
2828    VPathObject *pathObject = object->getPathObject( sceneObject );
2829
2830    // Return.
2831    return pathObject->isActive();
2832}
2833
2834DefineEngineMethod( VPath, setPathObjectActive, void, (SceneObject *sceneObject, bool isActive), (nullAsType<SceneObject*>(), true), "( SimObject pObject, bool pActive ) - Enable or disable the object from traveling around this path. Inactive objects are still attached to the path, but are not updated.\n"
2835                                                       "@param pObject The SimObjectID of the object being altered.\n"
2836                                                       "@param pActive The new status of the object.\n"
2837                                                       "@return No return value." )
2838{
2839    // Fetch Object.
2840    if (sceneObject == nullptr)
2841    {
2842        Con::errorf( "VPath::setPathObjectActive() - Invalid Target Object." );
2843        return;
2844    }
2845
2846    // Apply.
2847    object->setPathObjectActive( sceneObject, isActive);
2848}
2849
2850void VPath::setPathObjectActive( SceneObject *pObject, const bool &pActive )
2851{
2852    VPathObject *pathObject = getPathObject( pObject );
2853    if ( !pathObject )
2854    {
2855        Con::warnf( "VPath::setPathObjectActive() - Object (%d) Not Attached to Path.", pObject->getId() );
2856        return;
2857    }
2858
2859    // Apply.
2860    pathObject->setActive( pActive );
2861
2862    // Network Flags.
2863    setMaskBits( ObjectUpdateMask );
2864}
2865
2866DefineEngineMethod( VPath, getPathObjectInterp, F32, (SceneObject *sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Get the current interp position of the path object.\n"
2867                                                      "@param pObject The SimObjectID of the object being observed.\n"
2868                                                      "@return Returns the current interp position." )
2869{
2870    // Fetch Object.
2871    if (sceneObject == nullptr)
2872    {
2873        Con::errorf( "VPath::getPathObjectInterp() - Invalid Target Object." );
2874        return false;
2875    }
2876
2877    // Fetch Object
2878    VPathObject *pathObject = object->getPathObject( sceneObject );
2879
2880    // Return.
2881    return pathObject->getTimeInterp();
2882}
2883
2884DefineEngineMethod( VPath, setPathObjectInterp, void, (SceneObject *sceneObject, F32 timeInterp), (nullAsType<SceneObject*>(), 1.0), "( SimObject pObject, float pTimeInterp ) - Set the interp position of the object between its current nodes.\n"
2885                                                       "@param pObject The SimObjectID of the object being altered.\n"
2886                                                       "@param pTimeInterp The new interp position of the object.\n"
2887                                                       "@return No return value." )
2888{
2889    // Fetch Object.
2890    if (sceneObject == nullptr)
2891    {
2892        Con::errorf( "VPath::setPathObjectInterp() - Invalid Target Object." );
2893        return;
2894    }
2895
2896    // Apply.
2897    object->setPathObjectInterp( sceneObject, timeInterp);
2898}
2899
2900void VPath::setPathObjectInterp( SceneObject *pObject, const F32 &pTimeInterp )
2901{
2902    VPathObject *pathObject = getPathObject( pObject );
2903    if ( !pathObject )
2904    {
2905        Con::warnf( "VPath::setPathObjectInterp() - Object (%d) Not Attached to Path.", pObject->getId() );
2906        return;
2907    }
2908
2909    // Update.
2910    setPathObjectInterp( pathObject, pTimeInterp );
2911}
2912
2913void VPath::setPathObjectInterp( VPathObject *pPathObject, const F32 &pTimeInterp )
2914{
2915    // Set Interp Time.
2916    pPathObject->setTimeInterp( pTimeInterp );
2917
2918    // Update Position.
2919    updatePosition( pPathObject );
2920    // Update Orientation.
2921    updateOrientation( pPathObject );
2922    // Reset the delta.
2923    pPathObject->resetDelta();
2924
2925    // Set the object transform.
2926    pPathObject->getObject()->setTransform( pPathObject->getTransform() );
2927
2928    if ( isServerObject() )
2929    {
2930        // Update Objects.
2931        setMaskBits( ObjectUpdateMask );
2932
2933        // Update This Object.
2934        pPathObject->setMaskBits( VPathObject::k_StateUpdatePosition );
2935    }
2936}
2937
2938DefineEngineMethod( VPath, getPathObjectOffset, const char *, (SceneObject *sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Get the position offset assigned to this object.\n"
2939                                                      "@param pObject The SimObjectID of the object being observed.\n"
2940                                                      "@return Returns the position offset." )
2941{
2942    // Fetch Object.
2943    if (sceneObject == nullptr)
2944    {
2945        Con::errorf( "VPath::getPathObjectOffset() - Invalid Target Object." );
2946        return "";
2947    }
2948
2949    // Fetch Object
2950    VPathObject *pathObject = object->getPathObject( sceneObject );
2951
2952    // Fetch Offset.
2953    const Point3F &offset = pathObject->getOffset();
2954
2955    // Buffer.
2956    char *buffer = Con::getReturnBuffer( 64 );
2957    dSprintf( buffer, 64, "%f %f %f", offset.x, offset.y, offset.z );
2958    return buffer;
2959}
2960
2961DefineEngineMethod( VPath, setPathObjectOffset, void, (SceneObject *sceneObject, Point3F offset), (nullAsType<SceneObject*>(), Point3F::Zero), "( SimObject pObject, vector pOffset ) - Set the position offset of the object. As the object is moving along the path, its position is offset by this value. Setting the \"Relative\" parameter while attaching an object will automatically apply an offset value.\n"
2962                                                       "@param pObject The SimObjectID of the object being altered.\n"
2963                                                       "@param pOffset The new position offset of the object.\n"
2964                                                       "@return No return value." )
2965{
2966    // Fetch Object.
2967    if (sceneObject == nullptr)
2968    {
2969        Con::errorf( "VPath::setPathObjectOffset() - Invalid Target Object." );
2970        return;
2971    }
2972
2973    // Apply.
2974    object->setPathObjectOffset( sceneObject, offset );
2975}
2976
2977void VPath::setPathObjectOffset( SceneObject *pObject, const Point3F &pOffset )
2978{
2979    VPathObject *pathObject = getPathObject( pObject );
2980    if ( !pathObject )
2981    {
2982        Con::warnf( "VPath::setPathObjectOffset() - Object (%d) Not Attached to Path.", pObject->getId() );
2983        return;
2984    }
2985
2986    // Apply.
2987    pathObject->setOffset( pOffset );
2988
2989    // Network Flags.
2990    setMaskBits( ObjectUpdateMask );
2991}
2992
2993DefineEngineMethod( VPath, getPathObjectSpeed, F32, (SceneObject *sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Get the speed this object is traveling along the path at.\n"
2994                                                     "@param pObject The SimObjectID of the object being observed.\n"
2995                                                     "@return Returns the speed of the object." )
2996{
2997    // Fetch Object.
2998    if (sceneObject == nullptr)
2999    {
3000        Con::errorf( "VPath::getPathObjectSpeed() - Invalid Target Object." );
3001        return false;
3002    }
3003
3004    // Fetch Object
3005    VPathObject *pathObject = object->getPathObject( sceneObject );
3006
3007    // Return.
3008    return pathObject->getSpeed();
3009}
3010
3011DefineEngineMethod( VPath, setPathObjectSpeed, void, (SceneObject *sceneObject, F32 speed), (nullAsType<SceneObject*>(), 1.0), "( SimObject pObject, float pSpeed ) - Set the speed of the object.\n"
3012                                                      "@param pObject The SimObjectID of the object being altered.\n"
3013                                                      "@param pSpeed The new speed of the object.\n"
3014                                                      "@return No return value." )
3015{
3016    // Fetch Object.
3017    if (sceneObject == nullptr)
3018    {
3019        Con::errorf( "VPath::setPathObjectSpeed() - Invalid Target Object." );
3020        return;
3021    }
3022
3023    // Apply.
3024    object->setPathObjectSpeed( sceneObject, speed );
3025}
3026
3027void VPath::setPathObjectSpeed( SceneObject *pObject, const F32 &pSpeed )
3028{
3029    VPathObject *pathObject = getPathObject( pObject );
3030    if ( !pathObject )
3031    {
3032        Con::warnf( "VPath::setPathObjectSpeed() - Object (%d) Not Attached to Path.", pObject->getId() );
3033        return;
3034    }
3035
3036    // Apply.
3037    pathObject->setSpeed( mFabs( pSpeed ) );
3038
3039    // Network Flags.
3040    setMaskBits( ObjectUpdateMask );  
3041}
3042
3043DefineEngineMethod( VPath, getPathObjectOrientationMode, const char *, (SceneObject *sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Gets the current orientation mode of the object.\n"
3044                                                                        "@param pObject The SimObjectID of the object being observed.\n"
3045                                                                        "@return Returns a string indicating the orientation mode and its properties." )
3046{
3047    // Fetch Object.
3048    if (sceneObject == nullptr)
3049    {
3050        Con::errorf( "VPath::getPathObjectOrientationMode() - Invalid Target Object." );
3051        return "";
3052    }
3053
3054    // Fetch Object
3055    VPathObject *pathObject = object->getPathObject( sceneObject );
3056
3057    // Fetch Orientation Mode.
3058    const VPathObject::sOrientation &orientation = pathObject->getOrientationMode();
3059
3060    // Determine the Type.
3061    StringTableEntry type = VPathObject::getOrientationTypeLabel( orientation.Type );
3062
3063    // Buffer.
3064    char *buffer = Con::getReturnBuffer( 128 );
3065
3066    switch( orientation.Type )
3067    {
3068        case VPathObject::k_OrientationFree :
3069        case VPathObject::k_OrientationInterpolate :
3070        case VPathObject::k_OrientationToPath :
3071            {
3072                // Buffer String.
3073                dSprintf( buffer, 128, "%s", type );
3074
3075            } break;
3076
3077        case VPathObject::k_OrientationToObject : 
3078            {
3079                // Fetch the Object ID.
3080                const S32 objId = ( ( orientation.Object ) ? orientation.Object->getId() : 0 );
3081                // Buffer String.
3082                dSprintf( buffer, 128, "%s %d", type, objId );
3083
3084            } break;
3085
3086        case VPathObject::k_OrientationToPoint:
3087            {
3088                // Fetch Point.
3089                const Point3F &lookAtPoint = orientation.Point;
3090                // Buffer String.
3091                dSprintf( buffer, 128, "%s %f %f %f", type, lookAtPoint.x, lookAtPoint.y, lookAtPoint.z );
3092
3093            } break;
3094    }
3095
3096    // Return Buffer.
3097    return buffer;
3098}
3099
3100DefineEngineStringlyVariadicMethod( VPath, setPathObjectOrientationMode, void, 4, 5, "( SimObject pObject, string pOrientationType, [SimObject pObject / vector pPoint] ) - Set the orientation mode of the object. This property affects the rotation of the object. If you wish to ignore the object's rotation altogether, set the mode to \"FREE\".\n"
3101                                                                "@param pObject The SimObjectID of the object being altered.\n"
3102                                                                "@param pOrientationType The new orientation type of the object.\n"
3103                                                                "@param pObject If the orientation type is set to OBJECT, this parameter must be the SimObjectID of a scene object.\n"
3104                                                                "@param pPoint If the orientation type is set to POINT, this parameter must be a vector.\n"
3105                                                                "@return No return value." )
3106{
3107    // Fetch Object.
3108    SceneObject *sceneObject;
3109    if ( !Sim::findObject( argv[2], sceneObject ) )
3110    {
3111        Con::errorf( "VPath::setPathObjectOrientationMode() - Invalid Target Object." );
3112        return;
3113    }
3114
3115    // Orient?
3116    const VPathObject::eOrientationType type = VPathObject::getOrientationTypeEnum( argv[3] );
3117
3118    switch ( type )
3119    {
3120        case VPathObject::k_OrientationFree :
3121        case VPathObject::k_OrientationInterpolate :
3122        case VPathObject::k_OrientationToPath :
3123            {
3124                // Apply Mode.
3125                object->setPathObjectOrientationMode( sceneObject, type );
3126
3127            } break;
3128
3129        case VPathObject::k_OrientationToObject : 
3130            {
3131                // Fetch Object.
3132                SceneObject *lookAtObject = dynamic_cast<SceneObject*>( Sim::findObject( argv[4] ) );
3133                if ( !lookAtObject )
3134                {
3135                    Con::errorf( "VPath::setPathObjectOrientationMode() - Invalid LookAt Object." );
3136                    return;
3137                }
3138
3139                // Apply Mode.
3140                object->setPathObjectOrientationMode( sceneObject, type, lookAtObject );
3141
3142            } break;
3143
3144        case VPathObject::k_OrientationToPoint:
3145            {
3146                // Fetch Point.
3147                Point3F lookAtPoint( 0.f, 0.f, 0.f );
3148                dSscanf( argv[4], "%g %g %g", &lookAtPoint.x, &lookAtPoint.y, &lookAtPoint.z );
3149
3150                // Apply Mode.
3151                object->setPathObjectOrientationMode( sceneObject, type, lookAtPoint );
3152
3153            } break;
3154
3155        default :
3156            {
3157                AssertFatal( false, "VPath::setPathObjectOrientationMode() - Invalid Orientation Mode Specified." );
3158
3159            } break;
3160    }
3161}
3162
3163void VPath::setPathObjectOrientationMode( SceneObject *pObject, const VPathObject::eOrientationType &pType )
3164{
3165    VPathObject *pathObject = getPathObject( pObject );
3166    if ( !pathObject )
3167    {
3168        Con::warnf( "VPath::setPathObjectOrientationMode() - Object (%d) Not Attached to Path.", pObject->getId() );
3169        return;
3170    }
3171
3172    // Apply.
3173    pathObject->setOrientationMode( pType );
3174
3175    // Network Flags.
3176    setMaskBits( ObjectUpdateMask );
3177}
3178
3179void VPath::setPathObjectOrientationMode( SceneObject *pObject, const VPathObject::eOrientationType &pType, SceneObject *pLookAtObject )
3180{
3181    VPathObject *pathObject = getPathObject( pObject );
3182    if ( !pathObject )
3183    {
3184        Con::warnf( "VPath::setPathObjectOrientationMode() - Object (%d) Not Attached to Path.", pObject->getId() );
3185        return;
3186    }
3187
3188    // Apply.
3189    pathObject->setOrientationMode( pType, pLookAtObject );
3190
3191    // Network Flags.
3192    setMaskBits( ObjectUpdateMask );
3193}
3194
3195void VPath::setPathObjectOrientationMode( SceneObject *pObject, const VPathObject::eOrientationType &pType, const Point3F pPoint )
3196{
3197    VPathObject *pathObject = getPathObject( pObject );
3198    if ( !pathObject )
3199    {
3200        Con::warnf( "VPath::setPathObjectOrientationMode() - Object (%d) Not Attached to Path.", pObject->getId() );
3201        return;
3202    }
3203
3204    // Apply.
3205    pathObject->setOrientationMode( pType, pPoint );
3206
3207    // Network Flags.
3208    setMaskBits( ObjectUpdateMask );
3209}
3210
3211DefineEngineMethod( VPath, isPathObjectForward, bool, (SceneObject *sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Get if this object is traveling forwards along the path.\n"
3212                                                       "@param pObject The SimObjectID of the object being observed.\n"
3213                                                       "@return Returns true if the object is traveling forwards." )
3214{
3215    // Fetch Object.
3216    if (sceneObject == nullptr)
3217    {
3218        Con::errorf( "VPath::isPathObjectForward() - Invalid Target Object." );
3219        return false;
3220    }
3221
3222    // Fetch Object
3223    VPathObject *pathObject = object->getPathObject( sceneObject );
3224
3225    // Return.
3226    return pathObject->isForward();
3227}
3228
3229DefineEngineMethod( VPath, setPathObjectForward, void, (SceneObject *sceneObject, bool forward), (nullAsType<SceneObject*>(), true), "( SimObject pObject, bool pForward ) - Set the travel direction of the object.\n"
3230                                                        "@param pObject The SimObjectID of the object being altered.\n"
3231                                                        "@param pForward The direction of the object.\n"
3232                                                        "@return No return value." )
3233{
3234    // Fetch Object.
3235    if (sceneObject == nullptr)
3236    {
3237        Con::errorf( "VPath::setPathObjectForward() - Invalid Target Object." );
3238        return;
3239    }
3240
3241    // Apply.
3242    object->setPathObjectForward( sceneObject, forward);
3243}
3244
3245void VPath::setPathObjectForward( SceneObject *pObject, const bool &pForward )
3246{
3247    VPathObject *pathObject = getPathObject( pObject );
3248    if ( !pathObject )
3249    {
3250        Con::warnf( "VPath::setPathObjectForward() - Object (%d) Not Attached to Path.", pObject->getId() );
3251        return;
3252    }
3253
3254    // Apply.
3255    pathObject->setForward( pForward );
3256
3257    // Network Flags.
3258    setMaskBits( ObjectUpdateMask );
3259}
3260
3261DefineEngineMethod( VPath, getPathObjectNode, S32, (SceneObject *sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Gets the last node of the object.\n"
3262                                                    "@param pObject The SimObjectID of the object being observed.\n"
3263                                                    "@return Returns the node index." )
3264{
3265    // Fetch Object.
3266    if (sceneObject == nullptr)
3267    {
3268        Con::errorf( "VPath::getPathObjectNode() - Invalid Target Object." );
3269        return false;
3270    }
3271
3272    // Fetch Object
3273    VPathObject *pathObject = object->getPathObject( sceneObject );
3274
3275    // Return.
3276    return pathObject->getSourceNode();
3277}
3278
3279DefineEngineMethod( VPath, setPathObjectNode, void, (SceneObject *sceneObject, S32 nodeIndex), (nullAsType<SceneObject*>(), 0), "( SimObject pObject, bool pNodeIndex ) - Move the object to the node's position. You may also want to observe the \"setPathObjectInterp\" method.\n"
3280                                                     "@param pObject The SimObjectID of the object being altered.\n"
3281                                                     "@param pNodeIndex The index of the node that the object will reposition to.\n"
3282                                                     "@return No return value." )
3283{
3284    // Fetch Object.
3285    if (sceneObject == nullptr)
3286    {
3287        Con::errorf( "VPath::setPathObjectNode() - Invalid Target Object." );
3288        return;
3289    }
3290
3291    // Apply.
3292    object->setPathObjectNode( sceneObject, nodeIndex);
3293}
3294
3295void VPath::setPathObjectNode( SceneObject *pObject, const S32 &pNodeIndex )
3296{
3297    VPathObject *pathObject = getPathObject( pObject );
3298    if ( !pathObject )
3299    {
3300        Con::warnf( "VPath::setPathObjectNode() - Object (%d) Not Attached to Path.", pObject->getId() );
3301        return;
3302    }
3303
3304    // Source & Destination Nodes.
3305    const S32 srcNode = pNodeIndex;
3306    const S32 dstNode = ( pathObject->isForward() ) ? ( pNodeIndex + 1 ) : ( pNodeIndex - 1 );
3307
3308    // Set Current Node.
3309    pathObject->setNode( normalizeNodeIndex( srcNode ), normalizeNodeIndex( dstNode ) );
3310
3311    // Reset Interp.
3312    pathObject->setTimeInterp( 0.f );
3313    pathObject->setPathInterp( 0.f );
3314
3315    // Network Flags.
3316    setMaskBits( ObjectUpdateMask );
3317}
3318
3319DefineEngineMethod( VPath, getPathObjectEndNode, S32, (SceneObject *sceneObject), (nullAsType<SceneObject*>()), "( SimObject pObject ) - Get the index of the node this object is meant to stop upon reaching.\n"
3320                                                       "@param pObject The SimObjectID of the object being observed.\n"
3321                                                       "@return Returns the node index." )
3322{
3323    // Fetch Object.
3324    if (sceneObject == nullptr)
3325    {
3326        Con::errorf( "VPath::getPathObjectEndNode() - Invalid Target Object." );
3327        return false;
3328    }
3329
3330    // Fetch Object
3331    VPathObject *pathObject = object->getPathObject( sceneObject );
3332
3333    // Return.
3334    return pathObject->getEndNode();
3335}
3336
3337DefineEngineMethod( VPath, setPathObjectEndNode, void, (SceneObject *sceneObject, S32 nodeIndex), (nullAsType<SceneObject*>(), 0), "( SimObject pObject, bool pNodeIndex ) - Set end node of the path object. If a value of \"-1\" is applied, the object will path indefinitely.\n"
3338                                                        "@param pObject The SimObjectID of the object being altered.\n"
3339                                                        "@param pNodeIndex The index of the node that the object will cease pathing upon reaching.\n"
3340                                                        "@return No return value." )
3341{
3342    // Fetch Object.
3343    if (sceneObject == nullptr)
3344    {
3345        Con::errorf( "VPath::setPathObjectEndNode() - Invalid Target Object." );
3346        return;
3347    }
3348
3349    // Apply.
3350    object->setPathObjectEndNode( sceneObject, nodeIndex);
3351}
3352
3353void VPath::setPathObjectEndNode( SceneObject *pObject, const S32 &pNodeIndex )
3354{
3355    VPathObject *pathObject = getPathObject( pObject );
3356    if ( !pathObject )
3357    {
3358        Con::warnf( "VPath::setPathObjectEndNode() - Object (%d) Not Attached to Path.", pObject->getId() );
3359        return;
3360    }
3361
3362    // Set index.
3363    S32 index = pNodeIndex;
3364
3365    if ( index != -1 )
3366    {
3367        // Normalize index.
3368        normalizeNodeIndex( index );
3369    }
3370
3371    // Apply.
3372    pathObject->setEndNode( index );
3373
3374    // Network Flags.
3375    setMaskBits( ObjectUpdateMask );
3376}
3377