Browse Source

obj-select -- object selection functionality
is-camera -- Adds a test for determining if object is a camera.
cam-speed -- added method for getting the camera movement speed.
zoned-in -- connection is flagged as "zoned-in" when client is fully connected and user can interact with it.

Marc Chapman 8 years ago
parent
commit
fcce9be33c

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

@@ -20,6 +20,11 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
+//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
+// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
+// Copyright (C) 2015 Faust Logic, Inc.
+//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
+
 #ifndef _CAMERA_H_
 #define _CAMERA_H_
 
@@ -246,6 +251,8 @@ class Camera: public ShapeBase
       DECLARE_CONOBJECT( Camera );
       DECLARE_CATEGORY( "Game" );
       DECLARE_DESCRIPTION( "Represents a position, direction and field of view to render a scene from." );
+      static F32 getMovementSpeed() { return smMovementSpeed; }
+      bool isCamera() const { return true; }
 };
 
 typedef Camera::CameraMotionMode CameraMotionMode;

+ 176 - 0
Engine/source/T3D/gameBase/gameConnection.cpp

@@ -61,6 +61,7 @@
 #include "core/stream/fileStream.h"
 #endif 
 
+#include "afx/arcaneFX.h"
 //----------------------------------------------------------------------------
 #define MAX_MOVE_PACKET_SENDS 4
 
@@ -191,6 +192,12 @@ bool GameConnection::client_cache_on = false;
 //----------------------------------------------------------------------------
 GameConnection::GameConnection()
 {
+   mRolloverObj = NULL;
+   mPreSelectedObj = NULL;
+   mSelectedObj = NULL;
+   mChangedSelectedObj = false;
+   mPreSelectTimestamp = 0;
+   zoned_in = false;
    
 #ifdef AFX_CAP_DATABLOCK_CACHE 
    client_db_stream = new InfiniteBitStream;
@@ -1168,6 +1175,17 @@ void GameConnection::readPacket(BitStream *bstream)
    {
       mMoveList->clientReadMovePacket(bstream);
 
+      // selected object - do we have a change in status?
+      if (bstream->readFlag()) 
+      { 
+         if (bstream->readFlag()) 
+         { 
+            S32 gIndex = bstream->readInt(NetConnection::GhostIdBitSize);
+            setSelectedObj(static_cast<SceneObject*>(resolveGhost(gIndex)));
+         }
+         else
+            setSelectedObj(NULL);
+      }
       bool hadFlash = mDamageFlash > 0 || mWhiteOut > 0;
       mDamageFlash = 0;
       mWhiteOut = 0;
@@ -1411,6 +1429,35 @@ void GameConnection::writePacket(BitStream *bstream, PacketNotify *note)
       // all the damage flash & white out
 
       S32 gIndex = -1;
+      if (mChangedSelectedObj)
+      {
+         S32 gidx;
+         // send NULL player
+         if ((mSelectedObj == NULL) || mSelectedObj.isNull())
+         {
+            bstream->writeFlag(true);
+            bstream->writeFlag(false);
+            mChangedSelectedObj = false;
+         }
+         // send ghost-idx
+         else if ((gidx = getGhostIndex(mSelectedObj)) != -1)
+         {
+            Con::printf("SEND OBJECT SELECTION");
+            bstream->writeFlag(true);
+            bstream->writeFlag(true);
+            bstream->writeInt(gidx, NetConnection::GhostIdBitSize);
+            mChangedSelectedObj = false;
+         }
+         // not fully changed yet
+         else
+         {
+            bstream->writeFlag(false);
+            mChangedSelectedObj = true;
+         }
+      }
+      else
+         bstream->writeFlag(false);
+		 
       if (!mControlObject.isNull())
       {
          gIndex = getGhostIndex(mControlObject);
@@ -2405,6 +2452,135 @@ DefineEngineMethod( GameConnection, getVisibleGhostDistance, F32, (),,
    return object->getVisibleGhostDistance();
 }
 
+// The object selection code here is, in part, based, on functionality described
+// in the following resource:
+// Object Selection in Torque by Dave Myers 
+//   http://www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=7335
+
+ConsoleMethod(GameConnection, setSelectedObj, bool, 3, 4, "(object, [propagate_to_client])")
+{
+   SceneObject* pending_selection;
+   if (!Sim::findObject(argv[2], pending_selection))
+      return false;
+
+   bool propagate_to_client = (argc > 3) ? dAtob(argv[3]) : false;
+   object->setSelectedObj(pending_selection, propagate_to_client);
+
+   return true;
+}
+
+ConsoleMethod(GameConnection, getSelectedObj, S32, 2, 2, "()")
+{
+   SimObject* selected = object->getSelectedObj();
+   return (selected) ? selected->getId(): -1;
+}
+
+ConsoleMethod(GameConnection, clearSelectedObj, void, 2, 3, "([propagate_to_client])")
+{
+   bool propagate_to_client = (argc > 2) ? dAtob(argv[2]) : false;
+   object->setSelectedObj(NULL, propagate_to_client);
+}
+
+ConsoleMethod(GameConnection, setPreSelectedObjFromRollover, void, 2, 2, "()")
+{
+   object->setPreSelectedObjFromRollover();
+}
+
+ConsoleMethod(GameConnection, clearPreSelectedObj, void, 2, 2, "()")
+{
+   object->clearPreSelectedObj();
+}
+
+ConsoleMethod(GameConnection, setSelectedObjFromPreSelected, void, 2, 2, "()")
+{
+   object->setSelectedObjFromPreSelected();
+}
+
+void GameConnection::setSelectedObj(SceneObject* so, bool propagate_to_client) 
+{ 
+   if (!isConnectionToServer())
+   {
+      // clear previously selected object
+      if (mSelectedObj)
+         clearNotify(mSelectedObj);
+
+      // save new selection
+      mSelectedObj = so; 
+
+      // mark selected object
+      if (mSelectedObj)
+         deleteNotify(mSelectedObj);
+
+      // mark selection dirty
+      if (propagate_to_client)
+         mChangedSelectedObj = true; 
+
+      return;
+   }
+
+   // clear previously selected object
+   if (mSelectedObj)
+   {
+      mSelectedObj->setSelectionFlags(mSelectedObj->getSelectionFlags() & ~SceneObject::SELECTED);
+      clearNotify(mSelectedObj);
+      Con::executef(this, "onObjectDeselected", mSelectedObj->getIdString());
+   }
+
+   // save new selection
+   mSelectedObj = so; 
+
+   // mark selected object
+   if (mSelectedObj)
+   {
+      mSelectedObj->setSelectionFlags(mSelectedObj->getSelectionFlags() | SceneObject::SELECTED);
+      deleteNotify(mSelectedObj);
+   }
+
+   // mark selection dirty
+   //mChangedSelectedObj = true; 
+
+   // notify appropriate script of the change
+   if (mSelectedObj)
+      Con::executef(this, "onObjectSelected", mSelectedObj->getIdString());
+}
+
+void GameConnection::setRolloverObj(SceneObject* so) 
+{ 
+   // save new selection
+   mRolloverObj = so;  
+
+   // notify appropriate script of the change
+   Con::executef(this, "onObjectRollover", (mRolloverObj) ? mRolloverObj->getIdString() : "");
+}
+
+void GameConnection::setPreSelectedObjFromRollover()
+{
+   mPreSelectedObj = mRolloverObj;
+   mPreSelectTimestamp = Platform::getRealMilliseconds();
+}
+
+void GameConnection::clearPreSelectedObj()
+{
+   mPreSelectedObj = 0;
+   mPreSelectTimestamp = 0;
+}
+
+void GameConnection::setSelectedObjFromPreSelected()
+{
+   U32 now = Platform::getRealMilliseconds();
+   if (now - mPreSelectTimestamp < arcaneFX::sTargetSelectionTimeoutMS)
+      setSelectedObj(mPreSelectedObj);
+   mPreSelectedObj = 0;
+}
+
+void GameConnection::onDeleteNotify(SimObject* obj)
+{
+   if (obj == mSelectedObj)
+      setSelectedObj(NULL);
+
+   Parent::onDeleteNotify(obj);
+}
+
 #ifdef AFX_CAP_DATABLOCK_CACHE 
 
 void GameConnection::tempDisableStringBuffering(BitStream* bs) const 

+ 30 - 0
Engine/source/T3D/gameBase/gameConnection.h

@@ -386,6 +386,36 @@ protected:
    DECLARE_CALLBACK( void, onDataBlocksDone, (U32 sequence) );
    DECLARE_CALLBACK( void, onFlash, (bool state) );
    
+   // GameConnection is modified to keep track of object selections which are used in
+   // spell targeting. This code stores the current object selection as well as the
+   // current rollover object beneath the cursor. The rollover object is treated as a
+   // pending object selection and actual object selection is usually made by promoting
+   // the rollover object to the current object selection.
+private:   
+   SimObjectPtr<SceneObject> mRolloverObj;  
+   SimObjectPtr<SceneObject> mPreSelectedObj;  
+   SimObjectPtr<SceneObject> mSelectedObj;  
+   bool          mChangedSelectedObj;
+   U32           mPreSelectTimestamp;
+protected:
+   virtual void  onDeleteNotify(SimObject*);
+public:   
+   void          setRolloverObj(SceneObject*);   
+   SceneObject*  getRolloverObj() { return  mRolloverObj; }   
+   void          setSelectedObj(SceneObject*, bool propagate_to_client=false);   
+   SceneObject*  getSelectedObj() { return  mSelectedObj; }  
+   void          setPreSelectedObjFromRollover();
+   void          clearPreSelectedObj();
+   void          setSelectedObjFromPreSelected();
+   // Flag is added to indicate when a client is fully connected or "zoned-in". 
+   // This information determines when AFX will startup active effects on a newly
+   // added client. 
+private:
+   bool          zoned_in;
+public:
+   bool          isZonedIn() const { return zoned_in; }
+   void          setZonedIn() { zoned_in = true; }
+   
 #ifdef AFX_CAP_DATABLOCK_CACHE
 private:
    static StringTableEntry  server_cache_filename;

+ 6 - 1
Engine/source/T3D/player.cpp

@@ -5885,7 +5885,12 @@ void Player::applyImpulse(const Point3F&,const VectorF& vec)
 
 bool Player::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
 {
-   if (getDamageState() != Enabled)
+   // In standard Torque there's a rather brute force culling of all
+   // non-enabled players (corpses) from the ray cast. But, to
+   // demonstrate a resurrection spell, we need corpses to be
+   // selectable, so this code change allows consideration of corpses
+   // in the ray cast if corpsesHiddenFromRayCast is set to false.
+   if (sCorpsesHiddenFromRayCast && getDamageState() != Enabled)
       return false;
 
    // Collide against bounding box. Need at least this for the editor.

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

@@ -790,6 +790,9 @@ private:
    void         afx_init();
    U32          afx_packUpdate(NetConnection*, U32 mask, BitStream*, U32 retMask);
    void         afx_unpackUpdate(NetConnection*, BitStream*);
+private:
+   static bool  sCorpsesHiddenFromRayCast;
+   
 };
 
 typedef Player::Pose PlayerPose;

+ 6 - 0
Engine/source/scene/sceneObject.cpp

@@ -20,6 +20,11 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
+//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
+// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
+// Copyright (C) 2015 Faust Logic, Inc.
+//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
+
 #include "platform/platform.h"
 #include "scene/sceneObject.h"
 
@@ -144,6 +149,7 @@ SceneObject::SceneObject()
    mIsScopeAlways = false;
 
    mAccuTex = NULL;
+   mSelectionFlags = 0;
    mPathfindingIgnore = false;
 }
 

+ 22 - 0
Engine/source/scene/sceneObject.h

@@ -20,6 +20,11 @@
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 
+//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
+// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
+// Copyright (C) 2015 Faust Logic, Inc.
+//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
+
 #ifndef _SCENEOBJECT_H_
 #define _SCENEOBJECT_H_
 
@@ -778,6 +783,23 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce
    // Note: This was placed in SceneObject to both ShapeBase and TSStatic could support it.
    public:
       GFXTextureObject* mAccuTex;
+      //   mSelectionFlags field keeps track of flags related to object selection.
+      //     PRE_SELECTED marks an object as pre-selected (object under cursor)
+      //     SELECTED marks an object as selected (a target)
+   protected:
+      U8 mSelectionFlags;
+   public:
+      enum { 
+         SELECTED      = BIT(0), 
+         PRE_SELECTED  = BIT(1), 
+      };
+      virtual void setSelectionFlags(U8 flags) { mSelectionFlags = flags; }
+      U8 getSelectionFlags() const { return mSelectionFlags; }
+      bool needsSelectionHighlighting() const { return (mSelectionFlags != 0); }
+      //   This should only return true if the object represents an independent camera
+      //   as opposed to something like a Player that has a built-in camera that requires
+      //   special calculations to determine the view transform.
+      virtual bool isCamera() const { return false; }
 };
 
 #endif  // _SCENEOBJECT_H_