Merge branch 'master' into console-func-refactor

Conflicts:
	Engine/source/app/net/net.cpp
	Engine/source/console/astNodes.cpp
	Engine/source/console/compiledEval.cpp
	Engine/source/console/console.h
	Engine/source/console/consoleInternal.h
	Engine/source/console/engineAPI.h
This commit is contained in:
Daniel Buckmaster 2014-10-14 14:40:17 +11:00
commit b507dc9555
6487 changed files with 315149 additions and 609761 deletions

View file

@ -0,0 +1,379 @@
#include "platform/platform.h"
#include "T3D/gameBase/extended/extendedGameProcess.h"
#include "T3D/gameBase/extended/extendedMoveList.h"
#include "platform/profiler.h"
#include "console/consoleTypes.h"
#include "core/dnet.h"
#include "core/stream/bitStream.h"
#include "core/frameAllocator.h"
#include "core/util/refBase.h"
#include "math/mPoint3.h"
#include "math/mMatrix.h"
#include "math/mathUtils.h"
#include "T3D/gameBase/gameBase.h"
#include "T3D/gameBase/gameConnection.h"
#include "T3D/fx/cameraFXMgr.h"
MODULE_BEGIN( ProcessList )
MODULE_INIT
{
ExtendedServerProcessList::init();
ExtendedClientProcessList::init();
}
MODULE_SHUTDOWN
{
ExtendedServerProcessList::shutdown();
ExtendedClientProcessList::shutdown();
}
MODULE_END;
void ExtendedServerProcessList::init()
{
smServerProcessList = new ExtendedServerProcessList();
}
void ExtendedServerProcessList::shutdown()
{
delete smServerProcessList;
}
void ExtendedClientProcessList::init()
{
smClientProcessList = new ExtendedClientProcessList();
}
void ExtendedClientProcessList::shutdown()
{
delete smClientProcessList;
}
//----------------------------------------------------------------------------
namespace
{
// local work class
struct GameBaseListNode
{
GameBaseListNode()
{
mPrev=this;
mNext=this;
mObject=NULL;
}
GameBaseListNode * mPrev;
GameBaseListNode * mNext;
GameBase * mObject;
void linkBefore(GameBaseListNode * obj)
{
// Link this before obj
mNext = obj;
mPrev = obj->mPrev;
obj->mPrev = this;
mPrev->mNext = this;
}
};
} // namespace
//--------------------------------------------------------------------------
// ExtendedClientProcessList
//--------------------------------------------------------------------------
ExtendedClientProcessList::ExtendedClientProcessList()
{
}
bool ExtendedClientProcessList::advanceTime( SimTime timeDelta )
{
PROFILE_SCOPE( ExtendedClientProcessList_AdvanceTime );
if ( doBacklogged( timeDelta ) )
return false;
bool ret = Parent::advanceTime( timeDelta );
ProcessObject *obj = NULL;
AssertFatal( mLastDelta >= 0.0f && mLastDelta <= 1.0f, "mLastDelta is not zero to one.");
obj = mHead.mProcessLink.next;
while ( obj != &mHead )
{
if ( obj->isTicking() )
obj->interpolateTick( mLastDelta );
obj = obj->mProcessLink.next;
}
// Inform objects of total elapsed delta so they can advance
// client side animations.
F32 dt = F32(timeDelta) / 1000;
// Update camera FX.
gCamFXMgr.update( dt );
obj = mHead.mProcessLink.next;
while ( obj != &mHead )
{
obj->advanceTime( dt );
obj = obj->mProcessLink.next;
}
return ret;
}
//----------------------------------------------------------------------------
void ExtendedClientProcessList::onAdvanceObjects()
{
PROFILE_SCOPE( ExtendedClientProcessList_OnAdvanceObjects );
GameConnection* connection = GameConnection::getConnectionToServer();
if ( connection )
{
// process any demo blocks that are NOT moves, and exactly one move
// we advance time in the demo stream by a move inserted on
// each tick. So before doing the tick processing we advance
// the demo stream until a move is ready
if ( connection->isPlayingBack() )
{
U32 blockType;
do
{
blockType = connection->getNextBlockType();
bool res = connection->processNextBlock();
// if there are no more blocks, exit out of this function,
// as no more client time needs to process right now - we'll
// get it all on the next advanceClientTime()
if(!res)
return;
}
while ( blockType != GameConnection::BlockTypeMove );
}
connection->mMoveList->collectMove();
advanceObjects();
}
else
advanceObjects();
}
void ExtendedClientProcessList::onTickObject( ProcessObject *obj )
{
PROFILE_SCOPE( ExtendedClientProcessList_OnTickObject );
// In case the object deletes itself during its processTick.
SimObjectPtr<SceneObject> safePtr = static_cast<SceneObject*>( obj );
// Each object is either advanced a single tick, or if it's
// being controlled by a client, ticked once for each pending move.
ExtendedMove* extMovePtr;
U32 numMoves;
GameConnection* con = obj->getControllingClient();
if ( con && con->getControlObject() == obj )
{
ExtendedMoveList* extMoveList = static_cast<ExtendedMoveList*>(con->mMoveList);
extMoveList->getExtMoves( &extMovePtr, &numMoves );
if ( numMoves )
{
// Note: should only have a single move at this point
AssertFatal(numMoves==1,"ClientProccessList::onTickObject: more than one move in queue");
#ifdef TORQUE_DEBUG_NET_MOVES
U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
#endif
if ( obj->isTicking() )
obj->processTick( extMovePtr );
if ( bool(safePtr) && obj->getControllingClient() )
{
U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );
// set checksum if not set or check against stored value if set
extMovePtr->checksum = newsum;
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("move checksum: %i, (start %i), (move %f %f %f)",
movePtr->checksum,sum,movePtr->yaw,movePtr->y,movePtr->z);
#endif
}
con->mMoveList->clearMoves( 1 );
}
}
else if ( obj->isTicking() )
obj->processTick( 0 );
}
void ExtendedClientProcessList::advanceObjects()
{
PROFILE_SCOPE( ExtendedClientProcessList_AdvanceObjects );
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("Advance client time...");
#endif
Parent::advanceObjects();
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("---------");
#endif
}
void ExtendedClientProcessList::clientCatchup( GameConnection * connection )
{
SimObjectPtr<GameBase> control = connection->getControlObject();
if ( control )
{
ExtendedMove * extMovePtr;
U32 numMoves;
U32 m = 0;
ExtendedMoveList* extMoveList = static_cast<ExtendedMoveList*>(connection->mMoveList);
extMoveList->getExtMoves( &extMovePtr, &numMoves );
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("client catching up... (%i)", numMoves);
#endif
preTickSignal().trigger();
if ( control->isTicking() )
for ( m = 0; m < numMoves; m++ )
control->processTick( extMovePtr++ );
extMoveList->clearMoves( m );
}
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("---------");
#endif
}
//--------------------------------------------------------------------------
// ServerProcessList
//--------------------------------------------------------------------------
ExtendedServerProcessList::ExtendedServerProcessList()
{
}
void ExtendedServerProcessList::onPreTickObject( ProcessObject *pobj )
{
if ( pobj->mIsGameBase )
{
SimObjectPtr<GameBase> obj = getGameBase( pobj );
// Each object is either advanced a single tick, or if it's
// being controlled by a client, ticked once for each pending move.
GameConnection *con = obj->getControllingClient();
if ( con && con->getControlObject() == obj )
{
ExtendedMove* extMovePtr;
U32 numMoves;
ExtendedMoveList* extMoveList = static_cast<ExtendedMoveList*>(con->mMoveList);
extMoveList->getExtMoves( &extMovePtr, &numMoves );
if ( numMoves == 0 )
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("no moves on object %i, skip tick",obj->getId());
#endif
return;
}
}
}
Parent::onPreTickObject (pobj );
}
void ExtendedServerProcessList::onTickObject( ProcessObject *pobj )
{
PROFILE_SCOPE( ExtendedServerProcessList_OnTickObject );
// Each object is either advanced a single tick, or if it's
// being controlled by a client, ticked once for each pending move.
GameConnection *con = pobj->getControllingClient();
if ( pobj->mIsGameBase && con && con->getControlObject() == pobj )
{
// In case the object is deleted during its own tick.
SimObjectPtr<GameBase> obj = getGameBase( pobj );
ExtendedMove* extMovePtr;
U32 m, numMoves;
ExtendedMoveList* extMoveList = static_cast<ExtendedMoveList*>(con->mMoveList);
extMoveList->getExtMoves( &extMovePtr, &numMoves );
// For debugging it can be useful to know when this happens.
//if ( numMoves > 1 )
// Con::printf( "numMoves: %i", numMoves );
// Do we really need to test the control object each iteration? Does it change?
for ( m = 0; m < numMoves && con && con->getControlObject() == obj; m++, extMovePtr++ )
{
#ifdef TORQUE_DEBUG_NET_MOVES
U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
#endif
if ( obj->isTicking() )
obj->processTick( extMovePtr );
if ( con && con->getControlObject() == obj )
{
U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );
// check move checksum
if ( extMovePtr->checksum != newsum )
{
#ifdef TORQUE_DEBUG_NET_MOVES
if( !obj->isAIControlled() )
Con::printf("move %i checksum disagree: %i != %i, (start %i), (move %f %f %f)",
extMovePtr->id, extMovePtr->checksum,newsum,sum,extMovePtr->yaw,extMovePtr->y,extMovePtr->z);
#endif
extMovePtr->checksum = Move::ChecksumMismatch;
}
else
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("move %i checksum agree: %i == %i, (start %i), (move %f %f %f)",
extMovePtr->id, extMovePtr->checksum,newsum,sum,extMovePtr->yaw,extMovePtr->y,extMovePtr->z);
#endif
}
}
}
extMoveList->clearMoves( m );
}
else if ( pobj->isTicking() )
pobj->processTick( 0 );
}
void ExtendedServerProcessList::advanceObjects()
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("Advance server time...");
#endif
Parent::advanceObjects();
// Credit all connections with the elapsed tick
SimGroup *clientGroup = Sim::getClientGroup();
for(SimGroup::iterator i = clientGroup->begin(); i != clientGroup->end(); i++)
{
if (GameConnection *con = dynamic_cast<GameConnection *>(*i))
{
con->mMoveList->advanceMove();
}
}
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("---------");
#endif
}

View file

@ -0,0 +1,60 @@
#ifndef _GAMEPROCESS_EXTENDED_H_
#define _GAMEPROCESS_EXTENDED_H_
//#include "T3D/gameBase/processList.h"
#ifndef _GAMEPROCESS_H_
#include "T3D/gameBase/gameProcess.h"
#endif
class GameBase;
class GameConnection;
struct Move;
//----------------------------------------------------------------------------
/// List to keep track of GameBases to process.
class ExtendedClientProcessList : public ClientProcessList
{
typedef ClientProcessList Parent;
protected:
// ProcessList
void onTickObject(ProcessObject *);
void advanceObjects();
void onAdvanceObjects();
public:
ExtendedClientProcessList();
// ProcessList
bool advanceTime( SimTime timeDelta );
// ClientProcessList
void clientCatchup( GameConnection *conn );
static void init();
static void shutdown();
};
class ExtendedServerProcessList : public ServerProcessList
{
typedef ServerProcessList Parent;
protected:
// ProcessList
void onPreTickObject( ProcessObject *pobj );
void onTickObject( ProcessObject *pobj );
void advanceObjects();
public:
ExtendedServerProcessList();
static void init();
static void shutdown();
};
#endif // _GAMEPROCESS_EXTENDED_H_

View file

@ -0,0 +1,302 @@
#include "T3D/gameBase/extended/extendedMove.h"
#include "core/stream/bitStream.h"
#include "math/mathIO.h"
#include "core/module.h"
#include "console/consoleTypes.h"
#include "core/strings/stringFunctions.h"
MODULE_BEGIN( ExtendedMoveManager )
MODULE_INIT_AFTER( MoveManager )
MODULE_INIT
{
ExtendedMoveManager::init();
}
MODULE_END;
S32 ExtendedMoveManager::mPosX[ExtendedMove::MaxPositionsRotations] = { 0, };
S32 ExtendedMoveManager::mPosY[ExtendedMove::MaxPositionsRotations] = { 0, };
S32 ExtendedMoveManager::mPosZ[ExtendedMove::MaxPositionsRotations] = { 0, };
bool ExtendedMoveManager::mRotIsEuler[ExtendedMove::MaxPositionsRotations] = { 0, };
F32 ExtendedMoveManager::mRotAX[ExtendedMove::MaxPositionsRotations] = { 0, };
F32 ExtendedMoveManager::mRotAY[ExtendedMove::MaxPositionsRotations] = { 0, };
F32 ExtendedMoveManager::mRotAZ[ExtendedMove::MaxPositionsRotations] = { 0, };
F32 ExtendedMoveManager::mRotAA[ExtendedMove::MaxPositionsRotations] = { 1, };
void ExtendedMoveManager::init()
{
for(U32 i = 0; i < ExtendedMove::MaxPositionsRotations; ++i)
{
char varName[256];
dSprintf(varName, sizeof(varName), "mvPosX%d", i);
Con::addVariable(varName, TypeS32, &mPosX[i],
"X position of controller in millimeters. Only 13 bits are networked.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvPosY%d", i);
Con::addVariable(varName, TypeS32, &mPosY[i],
"Y position of controller in millimeters. Only 13 bits are networked.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvPosZ%d", i);
Con::addVariable(varName, TypeS32, &mPosZ[i],
"Z position of controller in millimeters. Only 13 bits are networked.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotIsEuler%d", i);
Con::addVariable(varName, TypeBool, &mRotIsEuler[i],
"@brief Indicates that the given rotation is Euler angles.\n\n"
"When false (the default) the given rotation is a four component angled axis "
"(a vector and angle). When true, the given rotation is a three component "
"Euler angle. When using Euler angles, the $mvRotA component of the ExtendedMove "
"is ignored for this set of rotations.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotX%d", i);
Con::addVariable(varName, TypeF32, &mRotAX[i],
"X rotation vector component of controller.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotY%d", i);
Con::addVariable(varName, TypeF32, &mRotAY[i],
"Y rotation vector component of controller.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotZ%d", i);
Con::addVariable(varName, TypeF32, &mRotAZ[i],
"Z rotation vector component of controller.\n"
"@ingroup Game");
dSprintf(varName, sizeof(varName), "mvRotA%d", i);
Con::addVariable(varName, TypeF32, &mRotAA[i],
"Angle rotation (in degrees) component of controller.\n"
"@ingroup Game");
}
}
const ExtendedMove NullExtendedMove;
#define CLAMPPOS(x) (x<0 ? -((-x) & (1<<(MaxPositionBits-1))-1) : (x & (1<<(MaxPositionBits-1))-1))
#define CLAMPROT(f) ((S32)(((f + 1) * .5) * ((1 << MaxRotationBits) - 1)) & ((1<<MaxRotationBits)-1))
#define UNCLAMPROT(x) ((F32)(x * 2 / F32((1 << MaxRotationBits) - 1) - 1.0f))
ExtendedMove::ExtendedMove() : Move()
{
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
posX[i] = 0;
posY[i] = 0;
posZ[i] = 0;
rotX[i] = 0;
rotY[i] = 0;
rotZ[i] = 0;
rotW[i] = 1;
EulerBasedRotation[i] = false;
}
}
void ExtendedMove::pack(BitStream *stream, const Move * basemove)
{
bool alwaysWriteAll = basemove!=NULL;
if (!basemove)
basemove = &NullExtendedMove;
// Write the standard Move stuff
packMove(stream, basemove, alwaysWriteAll);
// Extended Move
const ExtendedMove* extBaseMove = static_cast<const ExtendedMove*>(basemove);
bool extendedDifferent = false;
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
bool check = (posX[i] != extBaseMove->posX[i]) ||
(posY[i] != extBaseMove->posY[i]) ||
(posZ[i] != extBaseMove->posZ[i]) ||
(rotX[i] != extBaseMove->rotX[i]) ||
(rotY[i] != extBaseMove->rotY[i]) ||
(rotZ[i] != extBaseMove->rotZ[i]);
if(!EulerBasedRotation[i])
{
check = check || (rotW[i] != extBaseMove->rotW[i]);
}
extendedDifferent = extendedDifferent || check;
}
if (alwaysWriteAll || stream->writeFlag(extendedDifferent))
{
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
// Position
if(stream->writeFlag(posX[i] != extBaseMove->posX[i]))
stream->writeSignedInt(posX[i], MaxPositionBits);
if(stream->writeFlag(posY[i] != extBaseMove->posY[i]))
stream->writeSignedInt(posY[i], MaxPositionBits);
if(stream->writeFlag(posZ[i] != extBaseMove->posZ[i]))
stream->writeSignedInt(posZ[i], MaxPositionBits);
// Rotation
stream->writeFlag(EulerBasedRotation[i]);
if(stream->writeFlag(rotX[i] != extBaseMove->rotX[i]))
stream->writeInt(crotX[i], MaxRotationBits);
if(stream->writeFlag(rotY[i] != extBaseMove->rotY[i]))
stream->writeInt(crotY[i], MaxRotationBits);
if(stream->writeFlag(rotZ[i] != extBaseMove->rotZ[i]))
stream->writeInt(crotZ[i], MaxRotationBits);
if(!EulerBasedRotation[i])
{
if(stream->writeFlag(rotW[i] != extBaseMove->rotW[i]))
stream->writeInt(crotW[i], MaxRotationBits);
}
}
}
}
void ExtendedMove::unpack(BitStream *stream, const Move * basemove)
{
bool alwaysReadAll = basemove!=NULL;
if (!basemove)
basemove=&NullExtendedMove;
// Standard Move stuff
bool isBaseMove = !unpackMove(stream, basemove, alwaysReadAll);
// ExtendedMove
const ExtendedMove* extBaseMove = static_cast<const ExtendedMove*>(basemove);
if (alwaysReadAll || stream->readFlag())
{
isBaseMove = false;
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
// Position
if(stream->readFlag())
posX[i] = stream->readSignedInt(MaxPositionBits);
else
posX[i] = extBaseMove->posX[i];
if(stream->readFlag())
posY[i] = stream->readSignedInt(MaxPositionBits);
else
posY[i] = extBaseMove->posY[i];
if(stream->readFlag())
posZ[i] = stream->readSignedInt(MaxPositionBits);
else
posZ[i] = extBaseMove->posZ[i];
// Rotation
EulerBasedRotation[i] = stream->readFlag();
F32 scale = 1.0f;
if(EulerBasedRotation[i])
scale = M_2PI_F;
if(stream->readFlag())
{
crotX[i] = stream->readInt(MaxRotationBits);
rotX[i] = UNCLAMPROT(crotX[i]) * scale;
}
else
{
rotX[i] = extBaseMove->rotX[i];
}
if(stream->readFlag())
{
crotY[i] = stream->readInt(MaxRotationBits);
rotY[i] = UNCLAMPROT(crotY[i]) * scale;
}
else
{
rotY[i] = extBaseMove->rotY[i];
}
if(stream->readFlag())
{
crotZ[i] = stream->readInt(MaxRotationBits);
rotZ[i] = UNCLAMPROT(crotZ[i]) * scale;
}
else
{
rotZ[i] = extBaseMove->rotZ[i];
}
if(!EulerBasedRotation[i])
{
if(stream->readFlag())
{
crotW[i] = stream->readInt(MaxRotationBits);
rotW[i] = UNCLAMPROT(crotW[i]);
}
else
{
rotW[i] = extBaseMove->rotW[i];
}
}
}
}
if(isBaseMove)
{
*this = *extBaseMove;
}
}
void ExtendedMove::clamp()
{
// Clamp the values the same as for net traffic so the client matches the server
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
// Positions
posX[i] = CLAMPPOS(posX[i]);
posY[i] = CLAMPPOS(posY[i]);
posZ[i] = CLAMPPOS(posZ[i]);
// Rotations
if(EulerBasedRotation[i])
{
crotX[i] = CLAMPROT(rotX[i] / M_2PI_F);
crotY[i] = CLAMPROT(rotY[i] / M_2PI_F);
crotZ[i] = CLAMPROT(rotZ[i] / M_2PI_F);
}
else
{
crotX[i] = CLAMPROT(rotX[i]);
crotY[i] = CLAMPROT(rotY[i]);
crotZ[i] = CLAMPROT(rotZ[i]);
crotW[i] = CLAMPROT(rotW[i]);
}
}
// Perform the standard Move clamp
Parent::clamp();
}
void ExtendedMove::unclamp()
{
// Unclamp the values the same as for net traffic so the client matches the server
for(U32 i=0; i<MaxPositionsRotations; ++i)
{
// Rotations
if(EulerBasedRotation[i])
{
rotX[i] = UNCLAMPROT(crotX[i]) * M_2PI_F;
rotY[i] = UNCLAMPROT(crotY[i]) * M_2PI_F;
rotZ[i] = UNCLAMPROT(crotZ[i]) * M_2PI_F;
}
else
{
rotX[i] = UNCLAMPROT(crotX[i]);
rotY[i] = UNCLAMPROT(crotY[i]);
rotZ[i] = UNCLAMPROT(crotZ[i]);
rotW[i] = UNCLAMPROT(crotW[i]);
}
}
// Perform the standard Move unclamp
Parent::unclamp();
}

View file

@ -0,0 +1,54 @@
#ifndef _EXTENDEDMOVE_H_
#define _EXTENDEDMOVE_H_
#include "T3D/gameBase/moveManager.h"
#include "math/mQuat.h"
struct ExtendedMove : public Move
{
typedef Move Parent;
enum Constants {
MaxPositionsRotations = 3,
MaxPositionBits = 13,
MaxRotationBits = 16,
};
// Position is in millimeters
S32 posX[MaxPositionsRotations], posY[MaxPositionsRotations], posZ[MaxPositionsRotations];
bool EulerBasedRotation[MaxPositionsRotations];
F32 rotX[MaxPositionsRotations], rotY[MaxPositionsRotations], rotZ[MaxPositionsRotations], rotW[MaxPositionsRotations];
// Network clamped rotation
S32 crotX[MaxPositionsRotations], crotY[MaxPositionsRotations], crotZ[MaxPositionsRotations], crotW[MaxPositionsRotations];
ExtendedMove();
virtual void pack(BitStream *stream, const Move * move = NULL);
virtual void unpack(BitStream *stream, const Move * move = NULL);
virtual void clamp();
virtual void unclamp();
};
extern const ExtendedMove NullExtendedMove;
class ExtendedMoveManager
{
public:
static S32 mPosX[ExtendedMove::MaxPositionsRotations];
static S32 mPosY[ExtendedMove::MaxPositionsRotations];
static S32 mPosZ[ExtendedMove::MaxPositionsRotations];
static bool mRotIsEuler[ExtendedMove::MaxPositionsRotations];
static F32 mRotAX[ExtendedMove::MaxPositionsRotations];
static F32 mRotAY[ExtendedMove::MaxPositionsRotations];
static F32 mRotAZ[ExtendedMove::MaxPositionsRotations];
static F32 mRotAA[ExtendedMove::MaxPositionsRotations];
static void init();
};
#endif // _EXTENDEDMOVE_H_

View file

@ -0,0 +1,380 @@
#include "platform/platform.h"
#include "T3D/gameBase/extended/extendedMoveList.h"
#include "T3D/gameBase/gameConnection.h"
#include "core/stream/bitStream.h"
#define MAX_MOVE_PACKET_SENDS 4
ExtendedMoveList::ExtendedMoveList()
{
mMoveCredit = MaxMoveCount;
mControlMismatch = false;
reset();
}
void ExtendedMoveList::reset()
{
mLastMoveAck = 0;
mLastClientMove = 0;
mFirstMoveIndex = 0;
mExtMoveVec.clear();
}
bool ExtendedMoveList::getNextExtMove( ExtendedMove &curMove )
{
if ( mExtMoveVec.size() > MaxMoveQueueSize )
return false;
// From MoveList
F32 pitchAdd = MoveManager::mPitchUpSpeed - MoveManager::mPitchDownSpeed;
F32 yawAdd = MoveManager::mYawLeftSpeed - MoveManager::mYawRightSpeed;
F32 rollAdd = MoveManager::mRollRightSpeed - MoveManager::mRollLeftSpeed;
curMove.pitch = MoveManager::mPitch + pitchAdd;
curMove.yaw = MoveManager::mYaw + yawAdd;
curMove.roll = MoveManager::mRoll + rollAdd;
MoveManager::mPitch = 0;
MoveManager::mYaw = 0;
MoveManager::mRoll = 0;
curMove.x = MoveManager::mRightAction - MoveManager::mLeftAction + MoveManager::mXAxis_L;
curMove.y = MoveManager::mForwardAction - MoveManager::mBackwardAction + MoveManager::mYAxis_L;
curMove.z = MoveManager::mUpAction - MoveManager::mDownAction;
curMove.freeLook = MoveManager::mFreeLook;
curMove.deviceIsKeyboardMouse = MoveManager::mDeviceIsKeyboardMouse;
for(U32 i = 0; i < MaxTriggerKeys; i++)
{
curMove.trigger[i] = false;
if(MoveManager::mTriggerCount[i] & 1)
curMove.trigger[i] = true;
else if(!(MoveManager::mPrevTriggerCount[i] & 1) && MoveManager::mPrevTriggerCount[i] != MoveManager::mTriggerCount[i])
curMove.trigger[i] = true;
MoveManager::mPrevTriggerCount[i] = MoveManager::mTriggerCount[i];
}
for(U32 i=0; i<ExtendedMove::MaxPositionsRotations; ++i)
{
// Process position
curMove.posX[i] = ExtendedMoveManager::mPosX[i];
curMove.posY[i] = ExtendedMoveManager::mPosY[i];
curMove.posZ[i] = ExtendedMoveManager::mPosZ[i];
// Process rotation. There are two possible forms of rotation: Angle Axis and Euler angles.
curMove.EulerBasedRotation[i] = ExtendedMoveManager::mRotIsEuler[i];
if(curMove.EulerBasedRotation[i])
{
// Euler angle based rotation passed in as degrees. We only need to work with three components.
curMove.rotX[i] = mDegToRad(ExtendedMoveManager::mRotAX[i]);
curMove.rotY[i] = mDegToRad(ExtendedMoveManager::mRotAY[i]);
curMove.rotZ[i] = mDegToRad(ExtendedMoveManager::mRotAZ[i]);
}
else
{
//Rotation is passed in as an Angle Axis in degrees. We need to convert this into a Quat.
QuatF q(Point3F(ExtendedMoveManager::mRotAX[i], ExtendedMoveManager::mRotAY[i], ExtendedMoveManager::mRotAZ[i]), mDegToRad(ExtendedMoveManager::mRotAA[i]));
curMove.rotX[i] = q.x;
curMove.rotY[i] = q.y;
curMove.rotZ[i] = q.z;
curMove.rotW[i] = q.w;
}
}
if (mConnection->getControlObject())
mConnection->getControlObject()->preprocessMove(&curMove);
curMove.clamp(); // clamp for net traffic
return true;
}
U32 ExtendedMoveList::getMoves(Move** movePtr,U32* numMoves)
{
// We don't want to be here
AssertFatal(0, "getMoves() called");
numMoves = 0;
return 0;
}
U32 ExtendedMoveList::getExtMoves( ExtendedMove** movePtr, U32 *numMoves )
{
if (!mConnection->isConnectionToServer())
{
if (mExtMoveVec.size() > mMoveCredit)
mExtMoveVec.setSize(mMoveCredit);
}
// From MoveList but converted to use mExtMoveVec
if (mConnection->isConnectionToServer())
{
// give back moves starting at the last client move...
AssertFatal(mLastClientMove >= mFirstMoveIndex, "Bad move request");
AssertFatal(mLastClientMove - mFirstMoveIndex <= mExtMoveVec.size(), "Desynched first and last move.");
*numMoves = mExtMoveVec.size() - mLastClientMove + mFirstMoveIndex;
*movePtr = mExtMoveVec.address() + mLastClientMove - mFirstMoveIndex;
}
else
{
// return the full list
*numMoves = mExtMoveVec.size();
*movePtr = mExtMoveVec.begin();
}
return *numMoves;
}
void ExtendedMoveList::collectMove()
{
ExtendedMove mv;
if (mConnection)
{
if(!mConnection->isPlayingBack() && getNextExtMove(mv))
{
mv.checksum=Move::ChecksumMismatch;
pushMove(mv);
mConnection->recordBlock(GameConnection::BlockTypeMove, sizeof(ExtendedMove), &mv);
}
}
else
{
if(getNextExtMove(mv))
{
mv.checksum=Move::ChecksumMismatch;
pushMove(mv);
}
}
}
void ExtendedMoveList::pushMove(const Move &mv)
{
const ExtendedMove* extMove = dynamic_cast<const ExtendedMove*>(&mv);
AssertFatal(extMove, "Regular Move struct passed to pushMove()");
pushExtMove(*extMove);
}
void ExtendedMoveList::pushExtMove( const ExtendedMove &mv )
{
U32 id = mFirstMoveIndex + mExtMoveVec.size();
U32 sz = mExtMoveVec.size();
mExtMoveVec.push_back(mv);
mExtMoveVec[sz].id = id;
mExtMoveVec[sz].sendCount = 0;
}
void ExtendedMoveList::clearMoves(U32 count)
{
if (!mConnection->isConnectionToServer())
{
count = mClamp(count,0,mMoveCredit);
mMoveCredit -= count;
}
// From MoveList but converted to use mExtMoveVec
if (mConnection->isConnectionToServer())
{
mLastClientMove += count;
AssertFatal(mLastClientMove >= mFirstMoveIndex, "Bad move request");
AssertFatal(mLastClientMove - mFirstMoveIndex <= mExtMoveVec.size(), "Desynched first and last move.");
if (!mConnection)
// drop right away if no connection
ackMoves(count);
}
else
{
AssertFatal(count <= mExtMoveVec.size(),"GameConnection: Clearing too many moves");
for (S32 i=0; i<count; i++)
if (mExtMoveVec[i].checksum == Move::ChecksumMismatch)
mControlMismatch = true;
else
mControlMismatch = false;
if (count == mExtMoveVec.size())
mExtMoveVec.clear();
else
while (count--)
mExtMoveVec.pop_front();
}
}
void ExtendedMoveList::advanceMove()
{
AssertFatal(!mConnection->isConnectionToServer(), "Cannot inc move credit on the client.");
// Game tick increment
mMoveCredit++;
if (mMoveCredit > MaxMoveCount)
mMoveCredit = MaxMoveCount;
// Clear pending moves for the elapsed time if there
// is no control object.
if ( mConnection->getControlObject() == NULL )
mExtMoveVec.clear();
}
void ExtendedMoveList::clientWriteMovePacket(BitStream *bstream)
{
AssertFatal(mLastMoveAck == mFirstMoveIndex, "Invalid move index.");
U32 count = mExtMoveVec.size();
ExtendedMove* extMove = mExtMoveVec.address();
U32 start = mLastMoveAck;
U32 offset;
for(offset = 0; offset < count; offset++)
if(extMove[offset].sendCount < MAX_MOVE_PACKET_SENDS)
break;
if(offset == count && count != 0)
offset--;
start += offset;
count -= offset;
if (count > MaxMoveCount)
count = MaxMoveCount;
bstream->writeInt(start,32);
bstream->writeInt(count,MoveCountBits);
ExtendedMove* prevExtMove = NULL;
for (int i = 0; i < count; i++)
{
extMove[offset + i].sendCount++;
extMove[offset + i].pack(bstream,prevExtMove);
bstream->writeInt(extMove[offset + i].checksum & (~(0xFFFFFFFF << Move::ChecksumBits)),Move::ChecksumBits);
prevExtMove = &extMove[offset+i];
}
}
void ExtendedMoveList::serverReadMovePacket(BitStream *bstream)
{
// Server side packet read.
U32 start = bstream->readInt(32);
U32 count = bstream->readInt(MoveCountBits);
ExtendedMove* prevExtMove = NULL;
ExtendedMove prevExtMoveHolder;
// Skip forward (must be starting up), or over the moves
// we already have.
int skip = mLastMoveAck - start;
if (skip < 0)
{
mLastMoveAck = start;
}
else
{
if (skip > count)
skip = count;
for (int i = 0; i < skip; i++)
{
prevExtMoveHolder.unpack(bstream,prevExtMove);
prevExtMoveHolder.checksum = bstream->readInt(Move::ChecksumBits);
prevExtMove = &prevExtMoveHolder;
S32 idx = mExtMoveVec.size()-skip+i;
if (idx>=0)
{
#ifdef TORQUE_DEBUG_NET_MOVES
if (mExtMoveVec[idx].checksum != prevExtMoveHolder.checksum)
Con::printf("updated checksum on move %i from %i to %i",mExtMoveVec[idx].id,mExtMoveVec[idx].checksum,prevExtMoveHolder.checksum);
#endif
mExtMoveVec[idx].checksum = prevExtMoveHolder.checksum;
}
}
start += skip;
count = count - skip;
}
// Put the rest on the move list.
int index = mExtMoveVec.size();
mExtMoveVec.increment(count);
while (index < mExtMoveVec.size())
{
mExtMoveVec[index].unpack(bstream,prevExtMove);
mExtMoveVec[index].checksum = bstream->readInt(Move::ChecksumBits);
prevExtMove = &mExtMoveVec[index];
mExtMoveVec[index].id = start++;
index ++;
}
mLastMoveAck += count;
}
void ExtendedMoveList::serverWriteMovePacket(BitStream * bstream)
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("ack %i minus %i",mLastMoveAck,mExtMoveVec.size());
#endif
// acknowledge only those moves that have been ticked
bstream->writeInt(mLastMoveAck - mExtMoveVec.size(),32);
}
void ExtendedMoveList::clientReadMovePacket(BitStream * bstream)
{
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("pre move ack: %i", mLastMoveAck);
#endif
mLastMoveAck = bstream->readInt(32);
#ifdef TORQUE_DEBUG_NET_MOVES
Con::printf("post move ack %i, first move %i, last move %i", mLastMoveAck, mFirstMoveIndex, mLastClientMove);
#endif
if (mLastMoveAck < mFirstMoveIndex)
mLastMoveAck = mFirstMoveIndex;
if(mLastMoveAck > mLastClientMove)
mLastClientMove = mLastMoveAck;
while(mFirstMoveIndex < mLastMoveAck)
{
if (mExtMoveVec.size())
{
mExtMoveVec.pop_front();
mFirstMoveIndex++;
}
else
{
AssertWarn(1, "Popping off too many moves!");
mFirstMoveIndex = mLastMoveAck;
}
}
}
bool ExtendedMoveList::isBacklogged()
{
if ( !mConnection->isConnectionToServer() )
return false;
return mLastClientMove - mFirstMoveIndex == mExtMoveVec.size() &&
mExtMoveVec.size() >= MaxMoveCount;
}
bool ExtendedMoveList::areMovesPending()
{
return mConnection->isConnectionToServer() ?
mExtMoveVec.size() - mLastClientMove + mFirstMoveIndex :
mExtMoveVec.size();
}
void ExtendedMoveList::ackMoves(U32 count)
{
mLastMoveAck += count;
if(mLastMoveAck > mLastClientMove)
mLastClientMove = mLastMoveAck;
while(mFirstMoveIndex < mLastMoveAck)
{
if (mExtMoveVec.size())
{
mExtMoveVec.pop_front();
mFirstMoveIndex++;
}
else
{
AssertWarn(1, "Popping off too many moves!");
mFirstMoveIndex = mLastMoveAck;
}
}
}

View file

@ -0,0 +1,55 @@
#ifndef _EXTENDEDMOVELIST_H_
#define _EXTENDEDMOVELIST_H_
#ifndef _TVECTOR_H_
#include "core/util/tVector.h"
#endif
#ifndef _MOVELIST_H_
#include "T3D/gameBase/moveList.h"
#endif
#include "T3D/gameBase/extended/extendedMove.h"
class ExtendedMoveList : public MoveList
{
typedef MoveList Parent;
public:
ExtendedMoveList();
void clientWriteMovePacket(BitStream *);
void clientReadMovePacket(BitStream *);
void serverWriteMovePacket(BitStream *);
void serverReadMovePacket(BitStream *);
void advanceMove();
void onAdvanceObjects() {}
U32 getMoves(Move** movePtr,U32* numMoves);
U32 getExtMoves( ExtendedMove** movePtr, U32 *numMoves );
void collectMove();
void pushMove( const Move &mv );
void pushExtMove( const ExtendedMove &mv );
void clearMoves( U32 count );
virtual void reset();
bool isBacklogged();
bool areMovesPending();
void ackMoves( U32 count );
protected:
U32 mMoveCredit;
Vector<ExtendedMove> mExtMoveVec;
protected:
bool getNextExtMove( ExtendedMove &curMove );
};
#endif // _EXTENDEDMOVELIST_H_

View file

@ -614,7 +614,7 @@ void GameBase::onUnmount( SceneObject *obj, S32 node )
bool GameBase::setDataBlockProperty( void *obj, const char *index, const char *db)
{
if( db == NULL || !db || !db[ 0 ] )
if( db == NULL || !db[ 0 ] )
{
Con::errorf( "GameBase::setDataBlockProperty - Can't unset datablock on GameBase objects" );
return false;

View file

@ -409,8 +409,8 @@ public:
virtual bool isValidCameraFov( F32 fov ) { return true; }
virtual bool useObjsEyePoint() const { return false; }
virtual bool onlyFirstPerson() const { return false; }
virtual F32 getDamageFlash() const { return 1.0f; }
virtual F32 getWhiteOut() const { return 1.0f; }
virtual F32 getDamageFlash() const { return 0.0f; }
virtual F32 getWhiteOut() const { return 0.0f; }
// Not implemented here, but should return the Camera to world transformation matrix
virtual void getCameraTransform (F32 *pos, MatrixF *mat ) { *mat = MatrixF::Identity; }

View file

@ -41,6 +41,8 @@
#ifdef TORQUE_HIFI_NET
#include "T3D/gameBase/hifi/hifiMoveList.h"
#elif defined TORQUE_EXTENDED_MOVE
#include "T3D/gameBase/extended/extendedMoveList.h"
#else
#include "T3D/gameBase/std/stdMoveList.h"
#endif
@ -175,6 +177,8 @@ GameConnection::GameConnection()
#ifdef TORQUE_HIFI_NET
mMoveList = new HifiMoveList();
#elif defined TORQUE_EXTENDED_MOVE
mMoveList = new ExtendedMoveList();
#else
mMoveList = new StdMoveList();
#endif
@ -215,6 +219,14 @@ GameConnection::GameConnection()
// first person
mFirstPerson = true;
mUpdateFirstPerson = false;
// Control scheme
mUpdateControlScheme = false;
mAbsoluteRotation = false;
mAddYawToAbsRot = false;
mAddPitchToAbsRot = false;
clearDisplayDevice();
}
GameConnection::~GameConnection()
@ -740,7 +752,15 @@ void GameConnection::setFirstPerson(bool firstPerson)
mUpdateFirstPerson = true;
}
//----------------------------------------------------------------------------
void GameConnection::setControlSchemeParameters(bool absoluteRotation, bool addYawToAbsRot, bool addPitchToAbsRot)
{
mAbsoluteRotation = absoluteRotation;
mAddYawToAbsRot = addYawToAbsRot;
mAddPitchToAbsRot = addPitchToAbsRot;
mUpdateControlScheme = true;
}
//----------------------------------------------------------------------------
@ -823,6 +843,11 @@ void GameConnection::writeDemoStartBlock(ResizeBitStream *stream)
stream->write(mCameraPos);
stream->write(mCameraSpeed);
// Control scheme
stream->write(mAbsoluteRotation);
stream->write(mAddYawToAbsRot);
stream->write(mAddPitchToAbsRot);
stream->writeString(Con::getVariable("$Client::MissionFile"));
mMoveList->writeDemoStartBlock(stream);
@ -899,6 +924,11 @@ bool GameConnection::readDemoStartBlock(BitStream *stream)
stream->read(&mCameraPos);
stream->read(&mCameraSpeed);
// Control scheme
stream->read(&mAbsoluteRotation);
stream->read(&mAddYawToAbsRot);
stream->read(&mAddPitchToAbsRot);
char buf[256];
stream->readString(buf);
Con::setVariable("$Client::MissionFile",buf);
@ -1075,6 +1105,16 @@ void GameConnection::readPacket(BitStream *bstream)
else
setCameraObject(0);
// server changed control scheme
if(bstream->readFlag())
{
bool absoluteRotation = bstream->readFlag();
bool addYawToAbsRot = bstream->readFlag();
bool addPitchToAbsRot = bstream->readFlag();
setControlSchemeParameters(absoluteRotation, addYawToAbsRot, addPitchToAbsRot);
mUpdateControlScheme = false;
}
// server changed first person
if(bstream->readFlag())
{
@ -1105,6 +1145,16 @@ void GameConnection::readPacket(BitStream *bstream)
if (bstream->readFlag())
mControlForceMismatch = true;
// client changed control scheme
if(bstream->readFlag())
{
bool absoluteRotation = bstream->readFlag();
bool addYawToAbsRot = bstream->readFlag();
bool addPitchToAbsRot = bstream->readFlag();
setControlSchemeParameters(absoluteRotation, addYawToAbsRot, addPitchToAbsRot);
mUpdateControlScheme = false;
}
// client changed first person
if(bstream->readFlag())
{
@ -1167,6 +1217,15 @@ void GameConnection::writePacket(BitStream *bstream, PacketNotify *note)
}
bstream->writeFlag(forceUpdate);
// Control scheme changed?
if(bstream->writeFlag(mUpdateControlScheme))
{
bstream->writeFlag(mAbsoluteRotation);
bstream->writeFlag(mAddYawToAbsRot);
bstream->writeFlag(mAddPitchToAbsRot);
mUpdateControlScheme = false;
}
// first person changed?
if(bstream->writeFlag(mUpdateFirstPerson))
{
@ -1255,6 +1314,15 @@ void GameConnection::writePacket(BitStream *bstream, PacketNotify *note)
else
bstream->writeFlag( false );
// Control scheme changed?
if(bstream->writeFlag(mUpdateControlScheme))
{
bstream->writeFlag(mAbsoluteRotation);
bstream->writeFlag(mAddYawToAbsRot);
bstream->writeFlag(mAddPitchToAbsRot);
mUpdateControlScheme = false;
}
// first person changed?
if(bstream->writeFlag(mUpdateFirstPerson))
{
@ -1727,6 +1795,13 @@ DefineEngineMethod( GameConnection, setControlObject, bool, (GameBase* ctrlObj),
return true;
}
DefineEngineMethod( GameConnection, clearDisplayDevice, void, (),,
"@brief Clear any display device.\n\n"
"A display device may define a number of properties that are used during rendering.\n\n")
{
object->clearDisplayDevice();
}
DefineEngineMethod( GameConnection, getControlObject, GameBase*, (),,
"@brief On the server, returns the object that the client is controlling."
"By default the control object is an instance of the Player class, but can also be an instance "
@ -2105,3 +2180,21 @@ DefineEngineMethod( GameConnection, setFirstPerson, void, (bool firstPerson),,
{
object->setFirstPerson(firstPerson);
}
DefineEngineMethod( GameConnection, setControlSchemeParameters, void, (bool absoluteRotation, bool addYawToAbsRot, bool addPitchToAbsRot),,
"@brief Set the control scheme that may be used by a connection's control object.\n\n"
"@param absoluteRotation Use absolute rotation values from client, likely through ExtendedMove.\n"
"@param addYawToAbsRot Add relative yaw control to the absolute rotation calculation. Only useful when absoluteRotation is true.\n\n" )
{
object->setControlSchemeParameters(absoluteRotation, addYawToAbsRot, addPitchToAbsRot);
}
DefineEngineMethod( GameConnection, getControlSchemeAbsoluteRotation, bool, (),,
"@brief Get the connection's control scheme absolute rotation property.\n\n"
"@return True if the connection's control object should use an absolute rotation control scheme.\n\n"
"@see GameConnection::setControlSchemeParameters()\n\n")
{
return object->getControlSchemeAbsoluteRotation();
}

View file

@ -45,6 +45,7 @@ enum GameConnectionConstants
DataBlockQueueCount = 16
};
class IDisplayDevice;
class SFXProfile;
class MatrixF;
class MatrixF;
@ -86,6 +87,16 @@ private:
F32 mCameraFov; ///< Current camera fov (in degrees).
F32 mCameraPos; ///< Current camera pos (0-1).
F32 mCameraSpeed; ///< Camera in/out speed.
IDisplayDevice* mDisplayDevice; ///< Optional client display device that imposes rendering properties.
/// @}
/// @name Client side control scheme that may be referenced by control objects
/// @{
bool mUpdateControlScheme; ///< Set to notify client or server of control scheme change
bool mAbsoluteRotation; ///< Use absolute rotation values from client, likely through ExtendedMove
bool mAddYawToAbsRot; ///< Add relative yaw control to the absolute rotation calculation. Only useful with mAbsoluteRotation.
bool mAddPitchToAbsRot; ///< Add relative pitch control to the absolute rotation calculation. Only useful with mAbsoluteRotation.
/// @}
public:
@ -263,6 +274,16 @@ public:
void setFirstPerson(bool firstPerson);
bool hasDisplayDevice() const { return mDisplayDevice != NULL; }
const IDisplayDevice* getDisplayDevice() const { return mDisplayDevice; }
void setDisplayDevice(IDisplayDevice* display) { mDisplayDevice = display; }
void clearDisplayDevice() { mDisplayDevice = NULL; }
void setControlSchemeParameters(bool absoluteRotation, bool addYawToAbsRot, bool addPitchToAbsRot);
bool getControlSchemeAbsoluteRotation() {return mAbsoluteRotation;}
bool getControlSchemeAddYawToAbsRot() {return mAddYawToAbsRot;}
bool getControlSchemeAddPitchToAbsRot() {return mAddPitchToAbsRot;}
/// @}
void detectLag();

View file

@ -76,8 +76,8 @@ public:
/// Reset move list back to last acknowledged move.
void resetCatchup() { mLastClientMove = mLastMoveAck; }
void collectMove();
void pushMove( const Move &mv );
virtual void collectMove();
virtual void pushMove( const Move &mv );
virtual void clearMoves( U32 count );
virtual void markControlDirty() { mLastClientMove = mLastMoveAck; }
@ -85,15 +85,15 @@ public:
void clearMismatch() { mControlMismatch = false; }
/// Clear out all moves in the list and reset to initial state.
void reset();
virtual void reset();
/// If there are no pending moves and the input queue is full,
/// then the connection to the server must be clogged.
bool isBacklogged();
virtual bool isBacklogged();
bool areMovesPending();
virtual bool areMovesPending();
void ackMoves( U32 count );
virtual void ackMoves( U32 count );
protected:

View file

@ -66,20 +66,7 @@ F32 MoveManager::mYAxis_R = 0;
U32 MoveManager::mTriggerCount[MaxTriggerKeys] = { 0, };
U32 MoveManager::mPrevTriggerCount[MaxTriggerKeys] = { 0, };
const Move NullMove =
{
/*px=*/16, /*py=*/16, /*pz=*/16,
/*pyaw=*/0, /*ppitch=*/0, /*proll=*/0,
/*x=*/0, /*y=*/0,/*z=*/0,
/*yaw=*/0, /*pitch=*/0, /*roll=*/0,
/*id=*/0,
/*sendCount=*/0,
/*checksum=*/false,
/*deviceIsKeyboardMouse=*/false,
/*freeLook=*/false,
/*triggers=*/{false,false,false,false,false,false}
};
const Move NullMove;
void MoveManager::init()
{
@ -161,6 +148,26 @@ void MoveManager::init()
}
}
Move::Move()
{
px=16; py=16; pz=16;
pyaw=0; ppitch=0; proll=0;
x=0; y=0; z=0;
yaw=0; pitch=0; roll=0;
id=0;
sendCount=0;
checksum = false;
deviceIsKeyboardMouse = false;
freeLook = false;
trigger[0] = false;
trigger[1] = false;
trigger[2] = false;
trigger[3] = false;
trigger[4] = false;
trigger[5] = false;
}
static inline F32 clampFloatWrap(F32 val)
{
return val - F32(S32(val));
@ -235,6 +242,11 @@ void Move::pack(BitStream *stream, const Move * basemove)
if (!basemove)
basemove = &NullMove;
packMove(stream, basemove, alwaysWriteAll);
}
bool Move::packMove(BitStream *stream, const Move* basemove, bool alwaysWriteAll)
{
S32 i;
bool triggerDifferent = false;
for (i=0; i < MaxTriggerKeys; i++)
@ -272,6 +284,8 @@ void Move::pack(BitStream *stream, const Move * basemove)
for(i = 0; i < MaxTriggerKeys; i++)
stream->writeFlag(trigger[i]);
}
return (triggerDifferent || somethingDifferent);
}
void Move::unpack(BitStream *stream, const Move * basemove)
@ -280,7 +294,20 @@ void Move::unpack(BitStream *stream, const Move * basemove)
if (!basemove)
basemove=&NullMove;
if (alwaysReadAll || stream->readFlag())
bool readMove = unpackMove(stream, basemove, alwaysReadAll);
if(!readMove)
*this = *basemove;
}
bool Move::unpackMove(BitStream *stream, const Move* basemove, bool alwaysReadAll)
{
bool readMove = alwaysReadAll;
if(!readMove)
{
readMove = stream->readFlag();
}
if (readMove)
{
pyaw = stream->readFlag() ? stream->readInt(16) : basemove->pyaw;
ppitch = stream->readFlag() ? stream->readInt(16) : basemove->ppitch;
@ -297,6 +324,6 @@ void Move::unpack(BitStream *stream, const Move * basemove)
trigger[i] = triggersDiffer ? stream->readFlag() : basemove->trigger[i];
unclamp();
}
else
*this = *basemove;
return readMove;
}

View file

@ -51,10 +51,16 @@ struct Move
bool freeLook;
bool trigger[MaxTriggerKeys];
void pack(BitStream *stream, const Move * move = NULL);
void unpack(BitStream *stream, const Move * move = NULL);
void clamp();
void unclamp();
Move();
virtual void pack(BitStream *stream, const Move * move = NULL);
virtual void unpack(BitStream *stream, const Move * move = NULL);
virtual void clamp();
virtual void unclamp();
protected:
bool packMove(BitStream *stream, const Move* basemove, bool alwaysWriteAll);
bool unpackMove(BitStream *stream, const Move* basemove, bool alwaysReadAll);
};
extern const Move NullMove;

View file

@ -92,7 +92,7 @@ void StdMoveList::clientWriteMovePacket(BitStream *bstream)
bstream->writeInt(start,32);
bstream->writeInt(count,MoveCountBits);
Move * prevMove = NULL;
for (int i = 0; i < count; i++)
for (S32 i = 0; i < count; i++)
{
move[offset + i].sendCount++;
move[offset + i].pack(bstream,prevMove);
@ -112,7 +112,7 @@ void StdMoveList::serverReadMovePacket(BitStream *bstream)
// Skip forward (must be starting up), or over the moves
// we already have.
int skip = mLastMoveAck - start;
S32 skip = mLastMoveAck - start;
if (skip < 0)
{
mLastMoveAck = start;
@ -121,7 +121,7 @@ void StdMoveList::serverReadMovePacket(BitStream *bstream)
{
if (skip > count)
skip = count;
for (int i = 0; i < skip; i++)
for (S32 i = 0; i < skip; i++)
{
prevMoveHolder.unpack(bstream,prevMove);
prevMoveHolder.checksum = bstream->readInt(Move::ChecksumBits);
@ -141,7 +141,7 @@ void StdMoveList::serverReadMovePacket(BitStream *bstream)
}
// Put the rest on the move list.
int index = mMoveVec.size();
S32 index = mMoveVec.size();
mMoveVec.increment(count);
while (index < mMoveVec.size())
{