Initial commit
This commit is contained in:
245
Torque/SDK/engine/game/gameProcess.cc
Normal file
245
Torque/SDK/engine/game/gameProcess.cc
Normal file
@@ -0,0 +1,245 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "core/dnet.h"
|
||||
#include "game/gameConnection.h"
|
||||
#include "game/gameBase.h"
|
||||
#include "game/shapeBase.h"
|
||||
#include "platform/profiler.h"
|
||||
#include "console/consoleTypes.h"
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
ProcessList gClientProcessList(false);
|
||||
ProcessList gServerProcessList(true);
|
||||
|
||||
bool ProcessList::mDebugControlSync = false;
|
||||
|
||||
ProcessList::ProcessList(bool isServer)
|
||||
{
|
||||
mDirty = false;
|
||||
mCurrentTag = 0;
|
||||
mLastTick = 0;
|
||||
mLastTime = 0;
|
||||
mLastDelta = 0;
|
||||
mIsServer = isServer;
|
||||
// Con::addVariable("debugControlSync",TypeBool, &mDebugControlSync);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void ProcessList::orderList()
|
||||
{
|
||||
// GameBase tags are intialized to 0, so current tag
|
||||
// should never be 0.
|
||||
if (!++mCurrentTag)
|
||||
mCurrentTag++;
|
||||
|
||||
// Install a temporary head node
|
||||
GameBase list;
|
||||
list.plLinkBefore(head.mProcessLink.next);
|
||||
head.plUnlink();
|
||||
|
||||
// Reverse topological sort into the orignal head node
|
||||
while (list.mProcessLink.next != &list) {
|
||||
GameBase* ptr = list.mProcessLink.next;
|
||||
ptr->mProcessTag = mCurrentTag;
|
||||
ptr->plUnlink();
|
||||
if (ptr->mAfterObject) {
|
||||
// Build chain "stack" of dependant objects and patch
|
||||
// it to the end of the current list.
|
||||
while (bool(ptr->mAfterObject) &&
|
||||
ptr->mAfterObject->mProcessTag != mCurrentTag) {
|
||||
ptr->mAfterObject->mProcessTag = mCurrentTag;
|
||||
ptr->mAfterObject->plUnlink();
|
||||
ptr->mAfterObject->plLinkBefore(ptr);
|
||||
ptr = ptr->mAfterObject;
|
||||
}
|
||||
ptr->plJoin(&head);
|
||||
}
|
||||
else
|
||||
ptr->plLinkBefore(&head);
|
||||
}
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool ProcessList::advanceServerTime(SimTime timeDelta)
|
||||
{
|
||||
PROFILE_START(AdvanceServerTime);
|
||||
|
||||
if (mDirty) orderList();
|
||||
|
||||
SimTime targetTime = mLastTime + timeDelta;
|
||||
SimTime targetTick = targetTime & ~TickMask;
|
||||
SimTime tickCount = (targetTick - mLastTick) >> TickShift;
|
||||
|
||||
bool ret = mLastTick != targetTick;
|
||||
// Advance all the objects
|
||||
for (; mLastTick != targetTick; mLastTick += TickMs)
|
||||
advanceObjects();
|
||||
|
||||
// Credit all the connections with the elapsed ticks.
|
||||
SimGroup *g = Sim::getClientGroup();
|
||||
for (SimGroup::iterator i = g->begin(); i != g->end(); i++)
|
||||
if (GameConnection *t = dynamic_cast<GameConnection *>(*i))
|
||||
t->incMoveCredit(tickCount);
|
||||
|
||||
mLastTime = targetTime;
|
||||
PROFILE_END();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool ProcessList::advanceClientTime(SimTime timeDelta)
|
||||
{
|
||||
PROFILE_START(AdvanceClientTime);
|
||||
|
||||
if (mDirty) orderList();
|
||||
|
||||
SimTime targetTime = mLastTime + timeDelta;
|
||||
SimTime targetTick = (targetTime + TickMask) & ~TickMask;
|
||||
SimTime tickCount = (targetTick - mLastTick) >> TickShift;
|
||||
|
||||
// See if the control object has pending moves.
|
||||
GameBase* control = 0;
|
||||
GameConnection* connection = GameConnection::getConnectionToServer();
|
||||
if (connection)
|
||||
{
|
||||
// If the connection to the server is backlogged
|
||||
// the simulation is frozen.
|
||||
if (connection->isBacklogged()) {
|
||||
mLastTime = targetTime;
|
||||
mLastTick = targetTick;
|
||||
PROFILE_END();
|
||||
return false;
|
||||
}
|
||||
if (connection->areMovesPending())
|
||||
control = connection->getControlObject();
|
||||
}
|
||||
|
||||
// If we are going to tick, or have moves pending for the
|
||||
// control object, we need to reset everyone back to their
|
||||
// last full tick pos.
|
||||
if (mLastDelta && (tickCount || control))
|
||||
for (GameBase* obj = head.mProcessLink.next; obj != &head;
|
||||
obj = obj->mProcessLink.next)
|
||||
if (obj->mProcessTick)
|
||||
obj->interpolateTick(0);
|
||||
|
||||
// Produce new moves and advance all the objects
|
||||
if (tickCount)
|
||||
{
|
||||
for (; mLastTick != targetTick; mLastTick += TickMs)
|
||||
{
|
||||
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)
|
||||
{
|
||||
PROFILE_END();
|
||||
return true;
|
||||
}
|
||||
} while(blockType != GameConnection::BlockTypeMove);
|
||||
}
|
||||
connection->collectMove(mLastTick);
|
||||
}
|
||||
advanceObjects();
|
||||
}
|
||||
}
|
||||
else
|
||||
if (control)
|
||||
{
|
||||
// Sync up the control object with the latest client moves.
|
||||
Move* movePtr;
|
||||
U32 m = 0, numMoves;
|
||||
connection->getMoveList(&movePtr, &numMoves);
|
||||
while (m < numMoves)
|
||||
{
|
||||
control->processTick(&movePtr[m++]);
|
||||
}
|
||||
connection->clearMoves(m);
|
||||
}
|
||||
|
||||
mLastDelta = (TickMs - (targetTime & TickMask)) & TickMask;
|
||||
F32 dt = mLastDelta / F32(TickMs);
|
||||
for (GameBase* obj = head.mProcessLink.next; obj != &head;
|
||||
obj = obj->mProcessLink.next)
|
||||
if (obj->mProcessTick)
|
||||
obj->interpolateTick(dt);
|
||||
|
||||
// Inform objects of total elapsed delta so they can advance
|
||||
// client side animations.
|
||||
dt = F32(timeDelta) / 1000;
|
||||
for (GameBase* obj = head.mProcessLink.next; obj != &head;
|
||||
obj = obj->mProcessLink.next)
|
||||
obj->advanceTime(dt);
|
||||
|
||||
mLastTime = targetTime;
|
||||
PROFILE_END();
|
||||
return tickCount != 0;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void ProcessList::advanceObjects()
|
||||
{
|
||||
PROFILE_START(AdvanceObjects);
|
||||
|
||||
// A little link list shuffling is done here to avoid problems
|
||||
// with objects being deleted from within the process method.
|
||||
GameBase list;
|
||||
GameBase* obj;
|
||||
list.plLinkBefore(head.mProcessLink.next);
|
||||
head.plUnlink();
|
||||
while ((obj = list.mProcessLink.next) != &list) {
|
||||
obj->plUnlink();
|
||||
obj->plLinkBefore(&head);
|
||||
|
||||
// Each object is either advanced a single tick, or if it's
|
||||
// being controlled by a client, ticked once for each pending move.
|
||||
if (obj->mTypeMask & GameBaseObjectType) {
|
||||
|
||||
GameBase *pGB = static_cast<GameBase *>(obj);
|
||||
GameConnection* con = pGB->getControllingClient();
|
||||
|
||||
if (con && con->getControlObject() == pGB) {
|
||||
Move* movePtr;
|
||||
U32 m, numMoves;
|
||||
|
||||
con->getMoveList(&movePtr, &numMoves);
|
||||
|
||||
for (m = 0; m < numMoves && pGB->getControllingClient() == con; )
|
||||
obj->processTick(&movePtr[m++]);
|
||||
|
||||
con->clearMoves(m);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (obj->mProcessTick)
|
||||
obj->processTick(0);
|
||||
}
|
||||
PROFILE_END();
|
||||
}
|
||||
Reference in New Issue
Block a user