Torque3D Documentation / _generateds / stdGameProcess.cpp

stdGameProcess.cpp

Engine/source/T3D/gameBase/std/stdGameProcess.cpp

More...

Detailed Description

Public Variables

 MODULE_END 
 MODULE_INIT 
 MODULE_SHUTDOWN 
  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "T3D/gameBase/std/stdGameProcess.h"
 26
 27#include "platform/profiler.h"
 28#include "console/consoleTypes.h"
 29#include "core/dnet.h"
 30#include "core/stream/bitStream.h"
 31#include "core/frameAllocator.h"
 32#include "core/util/refBase.h"
 33#include "math/mPoint3.h"
 34#include "math/mMatrix.h"
 35#include "math/mathUtils.h"
 36#include "T3D/gameBase/gameBase.h"
 37#include "T3D/gameBase/gameConnection.h"
 38#include "T3D/gameBase/std/stdMoveList.h"
 39#include "T3D/fx/cameraFXMgr.h"
 40
 41#ifdef TORQUE_EXPERIMENTAL_EC
 42#include "T3D/components/coreInterfaces.h"
 43#include "T3D/components/component.h"
 44#endif
 45
 46MODULE_BEGIN( ProcessList )
 47
 48   MODULE_INIT
 49   {
 50      StdServerProcessList::init();
 51      StdClientProcessList::init();
 52   }
 53
 54   MODULE_SHUTDOWN
 55   {
 56      StdServerProcessList::shutdown();
 57      StdClientProcessList::shutdown();
 58   }
 59
 60MODULE_END;
 61
 62void StdServerProcessList::init()
 63{
 64   smServerProcessList = new StdServerProcessList();
 65}
 66
 67void StdServerProcessList::shutdown()
 68{
 69   delete smServerProcessList;
 70}
 71
 72void StdClientProcessList::init()
 73{
 74   smClientProcessList = new StdClientProcessList();
 75}
 76
 77void StdClientProcessList::shutdown()
 78{
 79   delete smClientProcessList;
 80}
 81
 82//----------------------------------------------------------------------------
 83
 84
 85namespace
 86{
 87   // local work class
 88   struct GameBaseListNode
 89   {
 90      GameBaseListNode()
 91      {
 92         mPrev=this;
 93         mNext=this;
 94         mObject=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>;
 95      }
 96
 97      GameBaseListNode * mPrev;
 98      GameBaseListNode * mNext;
 99      GameBase * mObject;
100
101      void linkBefore(GameBaseListNode * obj)
102      {
103         // Link this before obj
104         mNext = obj;
105         mPrev = obj->mPrev;
106         obj->mPrev = this;
107         mPrev->mNext = this;
108      }
109   };
110} // namespace
111
112//--------------------------------------------------------------------------
113// ClientProcessList
114//--------------------------------------------------------------------------
115
116StdClientProcessList::StdClientProcessList()
117{
118}
119
120bool StdClientProcessList::advanceTime( SimTime timeDelta )
121{
122   PROFILE_SCOPE( StdClientProcessList_AdvanceTime );
123
124   if ( doBacklogged( timeDelta ) )
125      return false;
126 
127   bool ret = Parent::advanceTime( timeDelta );
128   ProcessObject *obj = NULL;
129
130   AssertFatal( mLastDelta >= 0.0f && mLastDelta <= 1.0f, "mLastDelta is not zero to one.");
131   
132   obj = mHead.mProcessLink.next;
133   while ( obj != &mHead )
134   {      
135      if ( obj->isTicking() )
136         obj->interpolateTick( mLastDelta );
137
138      obj = obj->mProcessLink.next;
139   }
140
141#ifdef TORQUE_EXPERIMENTAL_EC
142   for (U32 i = 0; i < UpdateInterface::all.size(); i++)
143   {
144      Component *comp = dynamic_cast<Component*>(UpdateInterface::all[i]);
145
146      if (!comp->isClientObject() || !comp->isActive())
147            continue;
148
149      UpdateInterface::all[i]->interpolateTick(mLastDelta);
150   }
151#endif
152
153   // Inform objects of total elapsed delta so they can advance
154   // client side animations.
155   F32 dt = F32(timeDelta) / 1000;
156
157   // Update camera FX.
158   gCamFXMgr.update( dt );
159
160   obj = mHead.mProcessLink.next;
161   while ( obj != &mHead )
162   {      
163      obj->advanceTime( dt );
164      obj = obj->mProcessLink.next;
165   }
166   
167#ifdef TORQUE_EXPERIMENTAL_EC
168   for (U32 i = 0; i < UpdateInterface::all.size(); i++)
169   {
170      Component *comp = dynamic_cast<Component*>(UpdateInterface::all[i]);
171
172      if (comp)
173      {
174         if (!comp->isClientObject() || !comp->isActive())
175            continue;
176      }
177
178      UpdateInterface::all[i]->advanceTime(dt);
179   }
180#endif
181
182   return ret;
183}
184
185//----------------------------------------------------------------------------
186void StdClientProcessList::onAdvanceObjects()
187{
188   PROFILE_SCOPE( StdClientProcessList_OnAdvanceObjects );
189
190   GameConnection* connection = GameConnection::getConnectionToServer();
191   if ( connection )
192   {
193      // process any demo blocks that are NOT moves, and exactly one move
194      // we advance time in the demo stream by a move inserted on
195      // each tick.  So before doing the tick processing we advance
196      // the demo stream until a move is ready
197      if ( connection->isPlayingBack() )
198      {
199         U32 blockType;
200         do
201         {
202            blockType = connection->getNextBlockType();
203            bool res = connection->processNextBlock();
204            // if there are no more blocks, exit out of this function,
205            // as no more client time needs to process right now - we'll
206            // get it all on the next advanceClientTime()
207            if(!res)
208               return;
209         }
210         while ( blockType != GameConnection::BlockTypeMove );
211      }
212
213      connection->mMoveList->collectMove();
214      advanceObjects();
215   }
216   else
217      advanceObjects();
218}
219
220void StdClientProcessList::onTickObject( ProcessObject *obj )
221{
222   PROFILE_SCOPE( StdClientProcessList_OnTickObject );
223
224   // In case the object deletes itself during its processTick.
225   SimObjectPtr<SceneObject> safePtr = static_cast<SceneObject*>( obj );   
226
227   // Each object is either advanced a single tick, or if it's
228   // being controlled by a client, ticked once for each pending move.
229   Move* movePtr;
230   U32 numMoves;
231   GameConnection* con = obj->getControllingClient();
232   if  ( con && con->getControlObject() == obj )
233   {
234      con->mMoveList->getMoves( &movePtr, &numMoves );
235      if ( numMoves )
236      {
237         // Note: should only have a single move at this point
238         AssertFatal(numMoves==1,"ClientProccessList::onTickObject: more than one move in queue");
239
240         #ifdef TORQUE_DEBUG_NET_MOVES
241         U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
242         #endif
243
244         if ( obj->isTicking() )
245            obj->processTick( movePtr );
246
247         if ( bool(safePtr) && obj->getControllingClient() )
248         {
249            U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );
250
251            // set checksum if not set or check against stored value if set
252            movePtr->checksum = newsum;
253
254            #ifdef TORQUE_DEBUG_NET_MOVES
255            Con::printf("move checksum: %i, (start %i), (move %f %f %f)",
256               movePtr->checksum,sum,movePtr->yaw,movePtr->y,movePtr->z);
257            #endif
258         }
259         con->mMoveList->clearMoves( 1 );
260      }
261   }
262   else if ( obj->isTicking() )
263      obj->processTick( 0 );
264}
265
266void StdClientProcessList::advanceObjects()
267{
268   PROFILE_SCOPE( StdClientProcessList_AdvanceObjects );
269
270   #ifdef TORQUE_DEBUG_NET_MOVES
271   Con::printf("Advance client time...");
272   #endif
273
274   Parent::advanceObjects();
275
276   #ifdef TORQUE_DEBUG_NET_MOVES
277   Con::printf("---------");
278   #endif
279}
280
281void StdClientProcessList::clientCatchup( GameConnection *  connection )
282{
283   SimObjectPtr<GameBase> control = connection->getControlObject();
284   if ( control )
285   {
286      Move * movePtr;
287      U32 numMoves;
288      U32 m = 0;
289      connection->mMoveList->getMoves( &movePtr, &numMoves );
290
291      #ifdef TORQUE_DEBUG_NET_MOVES
292      Con::printf("client catching up... (%i)", numMoves);
293      #endif
294
295      preTickSignal().trigger();
296
297      if ( control->isTicking() )
298         for ( m = 0; m < numMoves; m++ )
299            control->processTick( movePtr++ );
300
301      connection->mMoveList->clearMoves( m );
302   }
303
304   #ifdef TORQUE_DEBUG_NET_MOVES
305   Con::printf("---------");
306   #endif
307}
308
309//--------------------------------------------------------------------------
310// ServerProcessList
311//--------------------------------------------------------------------------
312   
313StdServerProcessList::StdServerProcessList()
314{
315}
316
317void StdServerProcessList::onPreTickObject( ProcessObject *pobj )
318{
319   if ( pobj->mIsGameBase )
320   {
321      SimObjectPtr<GameBase> obj = getGameBase( pobj );
322
323      // Each object is either advanced a single tick, or if it's
324      // being controlled by a client, ticked once for each pending move.
325      GameConnection *con = obj->getControllingClient();
326
327      if ( con && con->getControlObject() == obj )
328      {
329         Move* movePtr;
330         U32 numMoves;
331         con->mMoveList->getMoves( &movePtr, &numMoves );
332
333         if ( numMoves == 0 )
334         {
335   #ifdef TORQUE_DEBUG_NET_MOVES
336            Con::printf("no moves on object %i, skip tick",obj->getId());
337   #endif         
338            return;
339         }
340      }
341   }
342
343   Parent::onPreTickObject (pobj );
344}
345
346void StdServerProcessList::onTickObject( ProcessObject *pobj )
347{
348   PROFILE_SCOPE( StdServerProcessList_OnTickObject );
349   
350   // Each object is either advanced a single tick, or if it's
351   // being controlled by a client, ticked once for each pending move.
352
353   GameConnection *con = pobj->getControllingClient();
354
355   if ( pobj->mIsGameBase && con && con->getControlObject() == pobj )
356   {
357      // In case the object is deleted during its own tick.
358      SimObjectPtr<GameBase> obj = getGameBase( pobj );
359
360      Move* movePtr;
361      U32 m, numMoves;
362      con->mMoveList->getMoves( &movePtr, &numMoves );
363
364      // For debugging it can be useful to know when this happens.
365      //if ( numMoves > 1 )
366      //   Con::printf( "numMoves: %i", numMoves );
367
368      // Do we really need to test the control object each iteration? Does it change?
369      for ( m = 0; m < numMoves && con && con->getControlObject() == obj; m++, movePtr++ )
370      {         
371         #ifdef TORQUE_DEBUG_NET_MOVES
372         U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
373         #endif
374      
375         if ( obj->isTicking() )
376            obj->processTick( movePtr );
377
378         if ( con && con->getControlObject() == obj )
379         {
380            U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );
381
382            // check move checksum
383            if ( movePtr->checksum != newsum )
384            {
385               #ifdef TORQUE_DEBUG_NET_MOVES
386               if( !obj->isAIControlled() )
387                  Con::printf("move %i checksum disagree: %i != %i, (start %i), (move %f %f %f)",
388                     movePtr->id, movePtr->checksum,newsum,sum,movePtr->yaw,movePtr->y,movePtr->z);
389               #endif
390
391               movePtr->checksum = Move::ChecksumMismatch;
392            }
393            else
394            {
395               #ifdef TORQUE_DEBUG_NET_MOVES
396               Con::printf("move %i checksum agree: %i == %i, (start %i), (move %f %f %f)",
397                  movePtr->id, movePtr->checksum,newsum,sum,movePtr->yaw,movePtr->y,movePtr->z);
398               #endif
399            }
400         }
401      }
402
403      con->mMoveList->clearMoves( m );
404   }
405   else if ( pobj->isTicking() )
406      pobj->processTick( 0 );
407}
408
409void StdServerProcessList::advanceObjects()
410{
411   #ifdef TORQUE_DEBUG_NET_MOVES
412   Con::printf("Advance server time...");
413   #endif
414
415   Parent::advanceObjects();
416
417   // Credit all connections with the elapsed tick
418   SimGroup *clientGroup = Sim::getClientGroup();
419   for(SimGroup::iterator i = clientGroup->begin(); i != clientGroup->end(); i++)
420   {
421      if (GameConnection *con = dynamic_cast<GameConnection *>(*i))
422      {
423         con->mMoveList->advanceMove();
424      }
425   }
426
427   #ifdef TORQUE_DEBUG_NET_MOVES
428   Con::printf("---------");
429   #endif
430}
431
432
433
434