Ver Fonte

elevated mAicontroller to shapebase
aiwheeleedveiclecontrollerdata resolvespeed now only touches throttle
objects assigned aicontrollers now reflect that by thier objecttype
basic flocking

AzaezelX há 8 meses atrás
pai
commit
3210325f3f

+ 137 - 54
Engine/source/T3D/AI/AIController.cpp

@@ -122,6 +122,27 @@ bool AIController::getAIMove(Move* movePtr)
    Point3F location = eye.getPosition();
    Point3F rotation = sbo->getTransform().toEuler();
 
+   // Test for target location in sight if it's an object. The LOS is
+   // run from the eye position to the center of the object's bounding,
+   // which is not very accurate.
+   if (getAim() && getAim()->mObj)
+   {
+      GameBase* gbo = dynamic_cast<GameBase*>(getAIInfo()->mObj.getPointer());
+      if (getAim()->checkInLos(gbo))
+      {
+         if (!getAim()->mTargetInLOS)
+         {
+            throwCallback("onTargetEnterLOS");
+            getAim()->mTargetInLOS = true;
+         }
+      }
+      else if (getAim()->mTargetInLOS)
+      {
+         throwCallback("onTargetExitLOS");
+         getAim()->mTargetInLOS = false;
+      }
+   }
+
 #ifdef TORQUE_NAVIGATION_ENABLED
    if (sbo->getDamageState() == ShapeBase::Enabled && getGoal())
    {
@@ -181,6 +202,7 @@ bool AIController::getAIMove(Move* movePtr)
    }
 #endif // TORQUE_NAVIGATION_ENABLED
 
+   getNav()->flock();
    // Orient towards the aim point, aim object, or towards
    // our destination.
    if (getAim() || mMovement.mMoveState != ModeStop)
@@ -189,7 +211,7 @@ bool AIController::getAIMove(Move* movePtr)
       if (getAim())
          mMovement.mAimLocation = getAim()->getPosition();
       else
-         mMovement.mAimLocation = getNav()->mMoveDestination;
+         mMovement.mAimLocation = getNav()->getMoveDestination();
 
       mControllerData->resolveYawPtr(this, location, movePtr);
       mControllerData->resolvePitchPtr(this, location, movePtr);
@@ -197,11 +219,10 @@ bool AIController::getAIMove(Move* movePtr)
 
       if (mMovement.mMoveState != AIController::ModeStop)
       {
-         F32 xDiff = getNav()->mMoveDestination.x - location.x;
-         F32 yDiff = getNav()->mMoveDestination.y - location.y;
+         F32 xDiff = getNav()->getMoveDestination().x - location.x;
+         F32 yDiff = getNav()->getMoveDestination().y - location.y;
          if (mFabs(xDiff) < mControllerData->mMoveTolerance && mFabs(yDiff) < mControllerData->mMoveTolerance)
          {
-            mMovement.mMoveState = AIController::ModeStop;
             getNav()->onReachDestination();
          }
          else
@@ -214,27 +235,7 @@ bool AIController::getAIMove(Move* movePtr)
 
    mControllerData->resolveTriggerStatePtr(this, movePtr);
 
-   // Test for target location in sight if it's an object. The LOS is
-   // run from the eye position to the center of the object's bounding,
-   // which is not very accurate.
-   if (getAim() && getAim()->mObj)
-   {
-      GameBase* gbo = dynamic_cast<GameBase*>(getAIInfo()->mObj.getPointer());
-      if (getAim()->checkInLos(gbo))
-      {
-         if (!getAim()->mTargetInLOS)
-         {
-            throwCallback("onTargetEnterLOS");
-            getAim()->mTargetInLOS = true;
-         }
-      }
-      else if (getAim()->mTargetInLOS)
-      {
-         throwCallback("onTargetExitLOS");
-         getAim()->mTargetInLOS = false;
-      }
-   }
-
+   getAIInfo()->mLastPos = getAIInfo()->getPosition();
    return true;
 }
 
@@ -250,17 +251,18 @@ void AIController::Movement::stopMove()
 {
    mMoveState = ModeStop;
 #ifdef TORQUE_NAVIGATION_ENABLED
-   mControllerRef->getNav()->clearPath();
-   mControllerRef->clearCover();
-   mControllerRef->getNav()->clearFollow();
+   getCtrl()->getNav()->clearPath();
+   getCtrl()->clearCover();
+   getCtrl()->getNav()->clearFollow();
 #endif
 }
 void AIController::Movement::onStuck()
 {
-   mControllerRef->throwCallback("onMoveStuck");
+   mMoveState = AIController::ModeStuck;
+   getCtrl()->throwCallback("onMoveStuck");
 #ifdef TORQUE_NAVIGATION_ENABLED
-   if (!mControllerRef->getNav()->getPath().isNull())
-      mControllerRef->getNav()->repath();
+   if (!getCtrl()->getNav()->getPath().isNull())
+      getCtrl()->getNav()->repath();
 #endif
 }
 
@@ -386,28 +388,28 @@ void AIControllerData::resolveRoll(AIController* obj, Point3F location, Move* mo
 
 void AIControllerData::resolveSpeed(AIController* obj, Point3F location, Move* movePtr)
 {
-   F32 xDiff = obj->getNav()->mMoveDestination.x - location.x;
-   F32 yDiff = obj->getNav()->mMoveDestination.y - location.y;
+   F32 xDiff = obj->getNav()->getMoveDestination().x - location.x;
+   F32 yDiff = obj->getNav()->getMoveDestination().y - location.y;
    Point3F rotation = obj->getAIInfo()->mObj->getTransform().toEuler();
 
    // Build move direction in world space
    if (mIsZero(xDiff))
-      movePtr->y = (location.y > obj->getNav()->mMoveDestination.y) ? -1.0f : 1.0f;
+      movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
    else
       if (mIsZero(yDiff))
-         movePtr->x = (location.x > obj->getNav()->mMoveDestination.x) ? -1.0f : 1.0f;
+         movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
       else
          if (mFabs(xDiff) > mFabs(yDiff))
          {
             F32 value = mFabs(yDiff / xDiff);
-            movePtr->y = (location.y > obj->getNav()->mMoveDestination.y) ? -value : value;
-            movePtr->x = (location.x > obj->getNav()->mMoveDestination.x) ? -1.0f : 1.0f;
+            movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -value : value;
+            movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
          }
          else
          {
             F32 value = mFabs(xDiff / yDiff);
-            movePtr->x = (location.x > obj->getNav()->mMoveDestination.x) ? -value : value;
-            movePtr->y = (location.y > obj->getNav()->mMoveDestination.y) ? -1.0f : 1.0f;
+            movePtr->x = (location.x > obj->getNav()->getMoveDestination().x) ? -value : value;
+            movePtr->y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
          }
 
    // Rotate the move into object space (this really only needs
@@ -430,15 +432,11 @@ void AIControllerData::resolveSpeed(AIController* obj, Point3F location, Move* m
          speed *= dist / maxDist;
       movePtr->x *= speed;
       movePtr->y *= speed;
-
-      obj->mMovement.mMoveState = AIController::ModeSlowing;
    }
    else
    {
       movePtr->x *= obj->mMovement.mMoveSpeed;
       movePtr->y *= obj->mMovement.mMoveSpeed;
-
-      obj->mMovement.mMoveState = AIController::ModeMove;
    }
 }
 
@@ -453,36 +451,57 @@ void AIControllerData::resolveTriggerState(AIController* obj, Move* movePtr)
 
 void AIControllerData::resolveStuck(AIController* obj)
 {
-   if (obj->mMovement.mMoveState == AIController::ModeStop) return;
+   if (obj->mMovement.mMoveState == AIController::ModeStuck) return;
    if (!obj->getGoal()) return;
    ShapeBase* sbo = dynamic_cast<ShapeBase*>(obj->getAIInfo()->mObj.getPointer());
    // Don't check for ai stuckness if animation during
    // an anim-clip effect override.
    if (sbo->getDamageState() == ShapeBase::Enabled && !(sbo->anim_clip_flags & ShapeBase::ANIM_OVERRIDDEN) && !sbo->isAnimationLocked())
    {
-      if (obj->mMovement.mMoveStuckTestCountdown > 0)
-         --obj->mMovement.mMoveStuckTestCountdown;
-      else
+      // We should check to see if we are stuck...
+      F32 locationDelta = (obj->getAIInfo()->getPosition() - obj->getAIInfo()->mLastPos).len();
+      if (locationDelta < mMoveStuckTolerance)
       {
-         // We should check to see if we are stuck...
-         F32 locationDelta = (obj->getAIInfo()->getPosition() - obj->getAIInfo()->mLastPos).len();
-         if (locationDelta < mMoveStuckTolerance)
+         if (obj->mMovement.mMoveStuckTestCountdown > 0)
+            --obj->mMovement.mMoveStuckTestCountdown;
+         else
          {
             // If we are slowing down, then it's likely that our location delta will be less than
             // our move stuck tolerance. Because we can be both slowing and stuck
             // we should TRY to check if we've moved. This could use better detection.
             if (obj->mMovement.mMoveState != AIController::ModeSlowing || locationDelta == 0)
             {
-               obj->mMovement.mMoveState = AIController::ModeStuck;
                obj->mMovement.onStuck();
-               obj->throwCallback("onStuck");
             }
+            obj->mMovement.mMoveStuckTestCountdown = obj->mControllerData->mMoveStuckTestDelay;
          }
       }
-      obj->getAIInfo()->mLastPos = obj->getAIInfo()->getPosition();
    }
 }
 
+AIControllerData::AIControllerData()
+{
+   mMoveTolerance = 0.25;
+   mFollowTolerance = 1.0;
+   mAttackRadius = 2.0;
+   mMoveStuckTolerance = 0.01f;
+   mMoveStuckTestDelay = 30;
+   mLinkTypes = LinkData(AllFlags);
+   mNavSize = AINavigation::Regular;
+
+   mFlocking.mChance = 100;
+   mFlocking.mMin = 1.0f;
+   mFlocking.mMax = 3.0f;
+   mFlocking.mSideStep = 0.125f;
+
+   resolveYawPtr.bind(this, &AIControllerData::resolveYaw);
+   resolvePitchPtr.bind(this, &AIControllerData::resolvePitch);
+   resolveRollPtr.bind(this, &AIControllerData::resolveRoll);
+   resolveSpeedPtr.bind(this, &AIControllerData::resolveSpeed);
+   resolveTriggerStatePtr.bind(this, &AIControllerData::resolveTriggerState);
+   resolveStuckPtr.bind(this, &AIControllerData::resolveStuck);
+}
+
 void AIControllerData::initPersistFields()
 {
    docsURL;
@@ -518,6 +537,14 @@ void AIControllerData::initPersistFields()
    addFieldV("AttackRadius", TypeRangedF32, Offset(mAttackRadius, AIControllerData), &CommonValidators::PositiveFloat,
       "@brief Distance considered in firing range for callback purposes.");
 
+   addFieldV("FlockChance", TypeRangedS32, Offset(mFlocking.mChance, AIControllerData), &CommonValidators::S32Percent,
+      "@brief chance of flocking.");
+   addFieldV("FlockMin", TypeRangedF32, Offset(mFlocking.mMin, AIControllerData), &CommonValidators::PositiveFloat,
+      "@brief min flocking separation distance.");
+   addFieldV("FlockMax", TypeRangedF32, Offset(mFlocking.mMax, AIControllerData), &CommonValidators::PositiveFloat,
+      "@brief max flocking clustering distance.");
+   addFieldV("FlockSideStep", TypeRangedF32, Offset(mFlocking.mSideStep, AIControllerData), &CommonValidators::PositiveFloat,
+      "@brief Distance from destination before we stop moving out of the way.");
    endGroup("AI");
 
 #ifdef TORQUE_NAVIGATION_ENABLED
@@ -626,7 +653,7 @@ F32 AIWheeledVehicleControllerData::getSteeringAngle(AIController* obj, Point3F
 
    // What is our target
    Point3F desired;
-   desired = obj->getNav()->mMoveDestination;
+   desired = obj->getNav()->getMoveDestination();
 
    MatrixF mat = wvo->getTransform();
    Point3F center, front;
@@ -739,4 +766,60 @@ void AIWheeledVehicleControllerData::resolveYaw(AIController* obj, Point3F locat
       movePtr->yaw = getSteeringAngle(obj, location);
    }
 };
+
+void AIWheeledVehicleControllerData::resolveSpeed(AIController* obj, Point3F location, Move* movePtr)
+{
+   F32 xDiff = obj->getNav()->getMoveDestination().x - location.x;
+   F32 yDiff = obj->getNav()->getMoveDestination().y - location.y;
+   Point3F rotation = obj->getAIInfo()->mObj->getTransform().toEuler();
+
+   Point2F movTarg;
+
+   // Build move direction in world space
+   if (mIsZero(xDiff))
+      movTarg.y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
+   else
+   {
+      if (mIsZero(yDiff))
+         movTarg.x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
+      else
+      {
+         if (mFabs(xDiff) > mFabs(yDiff))
+         {
+            F32 value = mFabs(yDiff / xDiff);
+            movTarg.y = (location.y > obj->getNav()->getMoveDestination().y) ? -value : value;
+            movTarg.x = (location.x > obj->getNav()->getMoveDestination().x) ? -1.0f : 1.0f;
+         }
+         else
+         {
+            F32 value = mFabs(xDiff / yDiff);
+            movTarg.x = (location.x > obj->getNav()->getMoveDestination().x) ? -value : value;
+            movTarg.y = (location.y > obj->getNav()->getMoveDestination().y) ? -1.0f : 1.0f;
+         }
+      }
+   }
+   // Rotate the move into object space (this really only needs
+   // a 2D matrix)
+   Point3F newMove;
+   MatrixF moveMatrix;
+   moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw)));
+   moveMatrix.mulV(Point3F(movTarg.x, movTarg.y, 0.0f), &newMove);
+   movTarg.y = newMove.y;
+
+   // Set Throttle.  We'll slow down once we get close
+   // to try and stop on the spot...
+   if (obj->mMovement.mMoveSlowdown)
+   {
+      F32 throttle = obj->mMovement.mMoveSpeed;
+      F32 dist = mSqrt(xDiff * xDiff + yDiff * yDiff);
+      F32 maxDist = mMoveTolerance * 2;
+      if (dist < maxDist)
+         throttle *= dist / maxDist;
+      movePtr->y *= throttle;
+   }
+   else
+   {
+      movePtr->y *= obj->mMovement.mMoveSpeed;
+   }
+}
 #endif //_AICONTROLLER_H_

+ 13 - 17
Engine/source/T3D/AI/AIController.h

@@ -84,6 +84,7 @@ public:
    struct Movement
    {
       AIController* mControllerRef;
+      AIController* getCtrl() { return mControllerRef; };
       MoveState mMoveState;
       F32 mMoveSpeed = 1.0;
       void setMoveSpeed(F32 speed) { mMoveSpeed = speed; };
@@ -101,6 +102,7 @@ public:
    struct TriggerState
    {
       AIController* mControllerRef;
+      AIController* getCtrl() { return mControllerRef; };
       bool mMoveTriggers[MaxTriggerKeys];
       // Trigger sets/gets
       void setMoveTrigger(U32 slot, const bool isSet = true);
@@ -143,23 +145,7 @@ class AIControllerData : public SimDataBlock {
 
 public:
 
-   AIControllerData()
-   {
-      mMoveTolerance = 0.25;
-      mFollowTolerance = 1.0;
-      mAttackRadius = 2.0;
-      mMoveStuckTolerance = 0.01f;
-      mMoveStuckTestDelay = 30;
-      mLinkTypes = LinkData(AllFlags);
-      mNavSize = AINavigation::Regular;
-
-      resolveYawPtr.bind(this, &AIControllerData::resolveYaw);
-      resolvePitchPtr.bind(this, &AIControllerData::resolvePitch);
-      resolveRollPtr.bind(this, &AIControllerData::resolveRoll);
-      resolveSpeedPtr.bind(this, &AIControllerData::resolveSpeed);
-      resolveTriggerStatePtr.bind(this, &AIControllerData::resolveTriggerState);
-      resolveStuckPtr.bind(this, &AIControllerData::resolveStuck);
-   };
+   AIControllerData();
    ~AIControllerData() {};
    void packData(BitStream* stream) override {};
    void unpackData(BitStream* stream) override {};
@@ -171,6 +157,14 @@ public:
    F32 mAttackRadius;                  // Distance to trigger weaponry calcs
    F32 mMoveStuckTolerance;            // Distance tolerance on stuck check
    S32 mMoveStuckTestDelay;            // The number of ticks to wait before checking if the AI is stuck
+
+   struct Flocking {
+      U32 mChance;                     // chance of flocking
+      F32 mMin;                        // min flocking separation distance
+      F32 mMax;                        // max flocking clustering distance
+      F32 mSideStep;                   // Distance from destination before we stop moving out of the way
+   } mFlocking;
+
    /// Types of link we can use.
    LinkData mLinkTypes;
    AINavigation::NavSize mNavSize;
@@ -223,9 +217,11 @@ public:
    AIWheeledVehicleControllerData()
    {
       resolveYawPtr.bind(this, &AIWheeledVehicleControllerData::resolveYaw);
+      resolveSpeedPtr.bind(this, &AIControllerData::resolveSpeed);
    }
    F32 getSteeringAngle(AIController* obj, Point3F location);
    void resolveYaw(AIController* obj, Point3F location, Move* movePtr);
+   void resolveSpeed(AIController* obj, Point3F location, Move* movePtr);
    DECLARE_CONOBJECT(AIWheeledVehicleControllerData);
 };
 #endif // TORQUE_NAVIGATION_ENABLED

+ 2 - 2
Engine/source/T3D/AI/AIInfo.h

@@ -22,8 +22,8 @@
 #ifndef _AIINFO_H_
 #define _AIINFO_H_
 
-#ifndef _SHAPEBASE_H_
-#include "T3D/shapeBase.h"
+#ifndef _SCENEOBJECT_H_
+#include "scene/sceneObject.h"
 #endif
 
 class AIController;

+ 124 - 0
Engine/source/T3D/AI/AINavigation.cpp

@@ -21,6 +21,9 @@
 //-----------------------------------------------------------------------------
 #include "AINavigation.h"
 #include "AIController.h"
+#include "T3D/shapeBase.h"
+
+static U32 sAILoSMask = TerrainObjectType | StaticShapeObjectType | StaticObjectType | AIObjectType;
 
 AINavigation::AINavigation(AIController* controller)
 {
@@ -283,6 +286,127 @@ void AINavigation::clearPath()
    mPathData = PathData();
 }
 
+void AINavigation::flock()
+{
+   AIControllerData::Flocking flockingData = getCtrl()->mControllerData->mFlocking;
+   SimObjectPtr<SceneObject> obj = getCtrl()->getAIInfo()->mObj;
+
+   if (mRandI(0,100) > flockingData.mChance)
+      return;
+
+   obj->disableCollision();
+   Point3F pos = obj->getBoxCenter();
+   Point3F searchArea = Point3F(flockingData.mMin / 2, flockingData.mMax / 2, getCtrl()->getAIInfo()->mObj->getObjBox().maxExtents.z / 2);
+
+   F32 maxFlocksq = flockingData.mMax * flockingData.mMax;
+
+   if (getCtrl()->getGoal())
+   {
+      Point3F dest = mMoveDestination;
+
+      if (getCtrl()->mMovement.mMoveState == AIController::ModeStuck)
+      {
+         Point3F shuffle = Point3F(mRandF() - 0.5, mRandF() - 0.5, 0);
+         shuffle.normalize();
+         dest += shuffle * flockingData.mMin;
+      }
+
+      dest.z = pos.z;
+      if ((pos - dest).len() > flockingData.mSideStep)
+      {
+         //find closest object
+         SimpleQueryList sql;
+         Box3F queryBox = Box3F(pos - searchArea, pos + searchArea);
+         obj->getContainer()->findObjects(queryBox, AIObjectType, SimpleQueryList::insertionCallback, &sql);
+         sql.mList.remove(obj);
+
+         Point3F avoidanceOffset = Point3F::Zero;
+         U32 found = 0;
+
+         //avoid objects in the way
+         RayInfo info;
+         if (obj->getContainer()->castRay(pos, dest + Point3F(0, 0, obj->getObjBox().len_z() / 2), sAILoSMask, &info))
+         {
+            Point3F blockerOffset = (info.point - dest);
+            blockerOffset.z = 0;
+            avoidanceOffset += blockerOffset;
+         }
+
+         //avoid bots that are too close
+         for (U32 i = 0; i < sql.mList.size(); i++)
+         {
+            ShapeBase* other = dynamic_cast<ShapeBase*>(sql.mList[i]);
+            Point3F objectCenter = other->getBoxCenter();
+
+            F32 sumRad = flockingData.mMin + other->getAIController()->mControllerData->mFlocking.mMin;
+            sumRad += getCtrl()->getAIInfo()->mRadius + other->getAIController()->getAIInfo()->mRadius;
+
+            Point3F offset = (pos - objectCenter);
+            F32 offsetLensq = offset.lenSquared(); //square roots are expensive, so use squared val compares
+            if ((flockingData.mMin > 0) && (offsetLensq < (sumRad * sumRad)))
+            {
+               other->disableCollision();
+               if (!obj->getContainer()->castRay(pos, other->getBoxCenter(), sAILoSMask, &info))
+               {
+                  found++;
+                  offset.normalizeSafe();
+                  offset *= sumRad;
+                  avoidanceOffset += offset; //accumulate total group, move away from that
+               }
+               other->enableCollision();
+            }
+         }
+         //if we don't have to worry about bumping into one another (nothing found lower than minFLock), see about grouping up
+         if (found == 0)
+         {
+            for (U32 i = 0; i < sql.mList.size(); i++)
+            {
+               ShapeBase* other = static_cast<ShapeBase*>(sql.mList[i]);
+               Point3F objectCenter = other->getBoxCenter();
+
+               F32 sumRad = flockingData.mMin + other->getAIController()->mControllerData->mFlocking.mMin;
+               sumRad += getCtrl()->getAIInfo()->mRadius + other->getAIController()->getAIInfo()->mRadius;
+
+               Point3F offset = (pos - objectCenter);
+               if ((flockingData.mMin > 0) && ((sumRad * sumRad) < (maxFlocksq)))
+               {
+                  other->disableCollision();
+                  if (!obj->getContainer()->castRay(pos, other->getBoxCenter(), sAILoSMask, &info))
+                  {
+                     found++;
+                     offset.normalizeSafe();
+                     offset *= sumRad;
+                     avoidanceOffset -= offset; // subtract total group, move toward it
+                  }
+                  other->enableCollision();
+               }
+            }
+         }
+
+         avoidanceOffset.z = 0;
+         avoidanceOffset.x = (mRandF() * avoidanceOffset.x) * 0.5 + avoidanceOffset.x * 0.75;
+         avoidanceOffset.y = (mRandF() * avoidanceOffset.y) * 0.5 + avoidanceOffset.y * 0.75;
+         if (avoidanceOffset.lenSquared() < (maxFlocksq))
+         {
+            avoidanceOffset.normalizeSafe();
+            dest += avoidanceOffset;
+         }
+
+         //if we're not jumping...
+         if ((mPathData.path) && !(mPathData.path->getFlags(mPathData.index) & JumpFlag))
+         {
+            //make sure we don't run off a cliff
+            Point3F zlen(0, 0, getCtrl()->getAIInfo()->mRadius);
+            if (obj->getContainer()->castRay(dest + zlen, dest - zlen, TerrainObjectType | StaticShapeObjectType | StaticObjectType, &info))
+            {
+               mMoveDestination = dest;
+            }
+         }
+      }
+   }
+   obj->enableCollision();
+}
+
 DefineEngineMethod(AIController, setMoveDestination, void, (Point3F goal, bool slowDown), (true),
    "@brief Tells the AI to move to the location provided\n\n"
 

+ 1 - 0
Engine/source/T3D/AI/AINavigation.h

@@ -96,6 +96,7 @@ struct AINavigation
    /// Move to the specified node in the current path.
    void moveToNode(S32 node);
 
+   void flock();
 };
 
 #endif

+ 1 - 0
Engine/source/T3D/gameFunctions.cpp

@@ -669,6 +669,7 @@ static void RegisterGameFunctions()
    Con::setIntVariable("$TypeMasks::PathShapeObjectType",     PathShapeObjectType);
 // PATHSHAPE END
    Con::setIntVariable("$TypeMasks::TurretObjectType", TurretObjectType);
+   Con::setIntVariable("$TypeMasks::AIObjectType", AIObjectType);
 
    Con::addVariable("Ease::InOut", TypeS32, &gEaseInOut, 
       "InOut ease for curve movement.\n"

+ 1 - 1
Engine/source/T3D/objectTypes.h

@@ -174,7 +174,7 @@ enum SceneObjectTypes
    /// @see TurretShape
    TurretObjectType = BIT(29),
    N_A_31 = BIT(30),
-   N_A_32 = BIT(31),
+   AIObjectType = BIT(31),
 
    /// @}
 };

+ 0 - 41
Engine/source/T3D/player.cpp

@@ -461,7 +461,6 @@ PlayerData::PlayerData()
 
    physicsPlayerType = StringTable->EmptyString();
    mControlMap = StringTable->EmptyString();
-   mAIControllData = NULL;
    dMemset( actionList, 0, sizeof(actionList) );
 }
 
@@ -742,8 +741,6 @@ void PlayerData::initPersistFields()
    addGroup( "Movement" );
       addField("controlMap", TypeString, Offset(mControlMap, PlayerData),
       "@brief movemap used by these types of objects.\n\n");
-      addField("aiControllerData", TYPEID< AIControllerData >(), Offset(mAIControllData, PlayerData),
-         "@brief ai controller used by these types of objects.\n\n");
    
       addFieldV( "maxStepHeight", TypeRangedF32, Offset(maxStepHeight, PlayerData), &CommonValidators::PositiveFloat,
          "@brief Maximum height the player can step up.\n\n"
@@ -1645,7 +1642,6 @@ Player::Player()
    mLastAbsoluteYaw = 0.0f;
    mLastAbsolutePitch = 0.0f;
    mLastAbsoluteRoll = 0.0f;
-   mAIController = NULL;
    afx_init();
 }
 
@@ -1656,7 +1652,6 @@ Player::~Player()
       delete mShapeFPInstance[i];
       mShapeFPInstance[i] = 0;
    }
-   if (mAIController) mAIController->deleteObject();
 }
 
 
@@ -2260,42 +2255,6 @@ void Player::advanceTime(F32 dt)
       }
    }
 }
-
-bool Player::setAIController(SimObjectId controller)
-{
-   if (Sim::findObject(controller, mAIController) && mAIController->mControllerData)
-   {
-      mAIController->setAIInfo(this);
-      return true;
-   }
-   Con::errorf("unable to find AIController : %i", controller);
-   mAIController = NULL;
-   return false;
-}
-
-DefineEngineMethod(Player, setAIController, bool, (S32 controller), , "")
-{
-   return object->setAIController(controller);
-}
-
-DefineEngineMethod(Player, getAIController, AIController*, (), , "")
-{
-   return object->getAIController();
-}
-
-
-bool Player::getAIMove(Move* move)
-{
-   if (!isServerObject()) return false;
-   if (mAIController)
-   {
-      mAIController->getAIMove(move); //actual result
-      return true;
-   }
-
-   return false;
-}
-
 void Player::setState(ActionState state, U32 recoverTicks)
 {
    if (state != mState) {

+ 0 - 7
Engine/source/T3D/player.h

@@ -55,7 +55,6 @@ class OpenVRTrackedObject;
 #include "navigation/navMesh.h"
 #include "navigation/coverPoint.h"
 #endif // TORQUE_NAVIGATION_ENABLED
-#include "AI/AIController.h"
 
 //----------------------------------------------------------------------------
 
@@ -354,7 +353,6 @@ struct PlayerData: public ShapeBaseData {
    // Jump off surfaces at their normal rather than straight up
    bool jumpTowardsNormal;
    StringTableEntry mControlMap;
-   AIControllerData* mAIControllData;
    // For use if/when mPhysicsPlayer is created
    StringTableEntry physicsPlayerType;
 
@@ -496,7 +494,6 @@ protected:
 
    SimObjectPtr<ShapeBase> mControlObject; ///< Controlling object
 
-   AIController* mAIController;
    /// @name Animation threads & data
    /// @{
 
@@ -762,10 +759,6 @@ public:
    Point3F getMomentum() const override;
    void    setMomentum(const Point3F &momentum) override;
    bool    displaceObject(const Point3F& displaceVector) override;
-   virtual bool    getAIMove(Move*);
-   bool setAIController(SimObjectId controller);
-   AIController* getAIController() { return mAIController; };
-
    bool checkDismountPosition(const MatrixF& oldPos, const MatrixF& newPos);  ///< Is it safe to dismount here?
 
    //

+ 50 - 2
Engine/source/T3D/shapeBase.cpp

@@ -69,6 +69,7 @@
 #include "core/stream/fileStream.h"
 #include "T3D/accumulationVolume.h"
 #include "console/persistenceManager.h"
+#include "AI/AIController.h"
 
 IMPLEMENT_CO_DATABLOCK_V1(ShapeBaseData);
 
@@ -195,7 +196,8 @@ ShapeBaseData::ShapeBaseData()
    useEyePoint( false ),
    isInvincible( false ),
    renderWhenDestroyed( true ),
-   inheritEnergyFromMount( false )
+   inheritEnergyFromMount( false ),
+   mAIControllData(NULL)
 {
    INIT_ASSET(Shape);
    INIT_ASSET(DebrisShape);
@@ -544,6 +546,10 @@ void ShapeBaseData::initPersistFields()
       addField("silentBBoxValidation", TypeBool, Offset(silent_bbox_check, ShapeBaseData));
       INITPERSISTFIELD_SHAPEASSET(DebrisShape, ShapeBaseData, "The shape asset to use for auto-generated breakups via blowup(). @note may not be functional.");
    endGroup( "Shapes" );
+   addGroup("Movement");
+      addField("aiControllerData", TYPEID< AIControllerData >(), Offset(mAIControllData, ShapeBaseData),
+      "@brief ai controller used by these types of objects.\n\n");
+   endGroup("Movement");
 
    addGroup("Particle Effects");
       addField( "explosion", TYPEID< ExplosionData >(), Offset(explosion, ShapeBaseData),
@@ -981,7 +987,8 @@ ShapeBase::ShapeBase()
    mCameraFov( 90.0f ),
    mIsControlled( false ),
    mLastRenderFrame( 0 ),
-   mLastRenderDistance( 0.0f )
+   mLastRenderDistance( 0.0f ),
+   mAIController(NULL)
 {
    mTypeMask |= ShapeBaseObjectType | LightObjectType;   
 
@@ -1032,6 +1039,7 @@ ShapeBase::~ShapeBase()
       cur->next = sFreeTimeoutList;
       sFreeTimeoutList = cur;
    }
+   if (mAIController) mAIController->deleteObject();
 }
 
 void ShapeBase::initPersistFields()
@@ -5449,3 +5457,43 @@ DefineEngineMethod(ShapeBase, getNodePoint, Point3F, (const char* nodeName), ,
 
    return pos;
 }
+
+bool ShapeBase::setAIController(SimObjectId controller)
+{
+   if (Sim::findObject(controller, mAIController) && mAIController->mControllerData)
+   {
+      mAIController->setAIInfo(this);
+      mTypeMask |= AIObjectType;
+      return true;
+   }
+   Con::errorf("unable to find AIController : %i", controller);
+   mAIController = NULL;
+   mTypeMask |= ~AIObjectType;
+   return false;
+}
+
+bool ShapeBase::getAIMove(Move* move)
+{
+   if (!isServerObject()) return false;
+   if (!(mTypeMask & VehicleObjectType || mTypeMask & PlayerObjectType)) return false; //only support players and vehicles for now
+   if (mAIController)
+   {
+      mAIController->getAIMove(move); //actual result
+      mTypeMask |= AIObjectType;
+      return true;
+   }
+   mAIController = NULL;
+   mTypeMask &= ~AIObjectType;
+   return false;
+}
+
+
+DefineEngineMethod(ShapeBase, setAIController, bool, (S32 controller), , "")
+{
+   return object->setAIController(controller);
+}
+
+DefineEngineMethod(ShapeBase, getAIController, AIController*, (), , "")
+{
+   return object->getAIController();
+}

+ 8 - 0
Engine/source/T3D/shapeBase.h

@@ -88,6 +88,8 @@ class ShapeBase;
 class SFXSource;
 class SFXTrack;
 class SFXProfile;
+struct AIController;
+struct AIControllerData;
 
 typedef void* Light;
 
@@ -555,6 +557,7 @@ public:
    U32 cubeDescId;
    ReflectorDesc *reflectorDesc;
 
+   AIControllerData* mAIControllData;
    /// @name Destruction
    ///
    /// Everyone likes to blow things up!
@@ -1754,6 +1757,11 @@ public:
    /// Returns true if this object is controlling by something
    bool isControlled() { return(mIsControlled); }
 
+   AIController* mAIController;
+   bool setAIController(SimObjectId controller);
+   AIController* getAIController() { return mAIController; };
+   virtual bool getAIMove(Move* move);
+
    /// Returns true if this object is being used as a camera in first person
    bool isFirstPerson() const;
 

+ 1 - 40
Engine/source/T3D/vehicles/vehicle.cpp

@@ -148,7 +148,6 @@ VehicleData::VehicleData()
    collDamageMultiplier = 0.05f;
    enablePhysicsRep = true;
    mControlMap = StringTable->EmptyString();
-   mAIControllData = NULL;
 }
 
 
@@ -325,9 +324,7 @@ void VehicleData::initPersistFields()
    addGroup("Movement");
    addField("controlMap", TypeString, Offset(mControlMap, VehicleData),
       "@brief movemap used by these types of objects.\n\n");
-   addField("aiControllerData", TYPEID< AIControllerData >(), Offset(mAIControllData, VehicleData),
-      "@brief ai controller used by these types of objects.\n\n");
-   endGroup("Collision");
+   endGroup("Movement");
 
    addGroup("Steering");
       addFieldV( "jetForce", TypeRangedF32, Offset(jetForce, VehicleData), &CommonValidators::PositiveFloat,
@@ -414,7 +411,6 @@ Vehicle::Vehicle()
    mWorkingQueryBoxCountDown = sWorkingQueryBoxStaleThreshold;
 
    mPhysicsRep = NULL;
-   mAIController = NULL;
 }
 
 U32 Vehicle::getCollisionMask()
@@ -481,7 +477,6 @@ bool Vehicle::onAdd()
 void Vehicle::onRemove()
 {
    SAFE_DELETE(mPhysicsRep);
-   if (mAIController) mAIController->deleteObject();
    U32 i=0;
 
    for( i=0; i<VehicleData::VC_NUM_DAMAGE_EMITTERS; i++ )
@@ -1236,37 +1231,3 @@ void Vehicle::_renderMuzzleVector( ObjectRenderInst *ri, SceneRenderState *state
 
    PrimBuild::end();
 }
-
-bool Vehicle::setAIController(SimObjectId controller)
-{
-   if (Sim::findObject(controller, mAIController) && mAIController->mControllerData)
-   {
-      mAIController->setAIInfo(this);
-      return true;
-   }
-   Con::errorf("unable to find AIController : %i", controller);
-   mAIController = NULL;
-   return false;
-}
-
-bool Vehicle::getAIMove(Move* move)
-{
-   if (!isServerObject()) return false;
-   if (mAIController)
-   {
-      mAIController->getAIMove(move); //actual result
-      return true;
-   }
-
-   return false;
-}
-
-DefineEngineMethod(Vehicle, setAIController, bool, (S32 controller), , "")
-{
-   return object->setAIController(controller);
-}
-
-DefineEngineMethod(Vehicle, getAIController, AIController*, (), , "")
-{
-   return object->getAIController();
-}

+ 0 - 5
Engine/source/T3D/vehicles/vehicle.h

@@ -73,7 +73,6 @@ struct VehicleData : public RigidShapeData
 
    bool enablePhysicsRep;
    StringTableEntry mControlMap;
-   AIControllerData* mAIControllData;
 
    //
    VehicleData();
@@ -102,7 +101,6 @@ class Vehicle : public RigidShape
    Point2F mSteering;
    F32 mThrottle;
    bool mJetting;
-   AIController* mAIController;
    GFXStateBlockRef  mSolidSB;
 
    SimObjectPtr<ParticleEmitter> mDamageEmitterList[VehicleData::VC_NUM_DAMAGE_EMITTERS];
@@ -152,9 +150,6 @@ public:
 
    Point2F getSteering() { return mSteering; };
    F32 getThrottle() { return mThrottle;};
-   bool setAIController(SimObjectId controller);
-   AIController* getAIController() { return mAIController; };
-   virtual bool    getAIMove(Move*);
 
    /// Interpolates between move ticks @see processTick
    /// @param   dt   Change in time between the last call and this call to the function

+ 1 - 1
Engine/source/console/simObject.cpp

@@ -82,7 +82,7 @@ ImplementBitfieldType(GameTypeMasksType,
 { SceneObjectTypes::PathShapeObjectType, "$TypeMasks::PathShapeObjectType", "Path-following Objects.\n" },
 { SceneObjectTypes::TurretObjectType, "$TypeMasks::TurretObjectType", "Turret Objects.\n" },
 { SceneObjectTypes::N_A_31, "$TypeMasks::N_A_31", "unused 31st bit.\n" },
-{ SceneObjectTypes::N_A_32, "$TypeMasks::N_A_32", "unused 32nd bit.\n" },
+{ SceneObjectTypes::AIObjectType, "$TypeMasks::AIObjectType", "AIObjectType.\n" },
 
 EndImplementBitfieldType;
 

+ 13 - 15
Engine/source/navigation/guiNavEditorCtrl.cpp

@@ -37,6 +37,7 @@
 #include "gui/buttons/guiButtonCtrl.h"
 #include "gui/worldEditor/undoActions.h"
 #include "T3D/gameBase/gameConnection.h"
+#include "T3D/AI/AIController.h"
 
 IMPLEMENT_CONOBJECT(GuiNavEditorCtrl);
 
@@ -226,12 +227,11 @@ void GuiNavEditorCtrl::spawnPlayer(const Point3F &pos)
          missionCleanup->addObject(obj);
       }
       mPlayer = obj;
-      Player* po = dynamic_cast<Player*>(obj);
-      if (!po) return; //todo, more types
-      if (po->getAIController())
+      ShapeBase* sbo = dynamic_cast<ShapeBase*>(obj);
+      if (sbo->getAIController())
       {
-         if (po->getAIController()->mControllerData)
-            Con::executef(this, "onPlayerSelected", Con::getIntArg(po->getAIController()->mControllerData->mLinkTypes.getFlags()));
+         if (sbo->getAIController()->mControllerData)
+            Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
       }
       else
       {
@@ -398,12 +398,11 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
             if(ri.object)
             {
                mPlayer = ri.object;
-               Player* po = dynamic_cast<Player*>(ri.object);
-               if (!po) return; //todo, more types
-               if (po->getAIController())
+               ShapeBase* sbo = dynamic_cast<ShapeBase*>(ri.object);
+               if (sbo->getAIController())
                {
-                  if (po->getAIController()->mControllerData)
-                     Con::executef(this, "onPlayerSelected", Con::getIntArg(po->getAIController()->mControllerData->mLinkTypes.getFlags()));
+                  if (sbo->getAIController()->mControllerData)
+                     Con::executef(this, "onPlayerSelected", Con::getIntArg(sbo->getAIController()->mControllerData->mLinkTypes.getFlags()));
                }
                else
                {
@@ -413,12 +412,11 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
          }
          else if (!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
          {
-            Player* po = dynamic_cast<Player*>(mPlayer.getPointer());
-            if (!po) return; //todo, more types
-            if (po->getAIController())
+            ShapeBase* sbo = dynamic_cast<ShapeBase*>(mPlayer.getPointer());
+            if (sbo->getAIController())
             {
-               if (po->getAIController()->mControllerData)
-                  po->getAIController()->getNav()->setPathDestination(ri.point,true);
+               if (sbo->getAIController()->mControllerData)
+                  sbo->getAIController()->getNav()->setPathDestination(ri.point,true);
             }
          }
       }