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.
This commit is contained in:
Marc Chapman 2017-07-26 23:59:44 +01:00
parent d4c2eeea98
commit fcce9be33c
7 changed files with 250 additions and 1 deletions

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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.

View file

@ -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;

View file

@ -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;
}

View file

@ -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_