stdGameProcess.cpp
Engine/source/T3D/gameBase/std/stdGameProcess.cpp
Public Variables
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 41MODULE_BEGIN( ProcessList ) 42 43 MODULE_INIT 44 { 45 StdServerProcessList::init(); 46 StdClientProcessList::init(); 47 } 48 49 MODULE_SHUTDOWN 50 { 51 StdServerProcessList::shutdown(); 52 StdClientProcessList::shutdown(); 53 } 54 55MODULE_END; 56 57void StdServerProcessList::init() 58{ 59 smServerProcessList = new StdServerProcessList(); 60} 61 62void StdServerProcessList::shutdown() 63{ 64 delete smServerProcessList; 65} 66 67void StdClientProcessList::init() 68{ 69 smClientProcessList = new StdClientProcessList(); 70} 71 72void StdClientProcessList::shutdown() 73{ 74 delete smClientProcessList; 75} 76 77//---------------------------------------------------------------------------- 78 79 80namespace 81{ 82 // local work class 83 struct GameBaseListNode 84 { 85 GameBaseListNode() 86 { 87 mPrev=this; 88 mNext=this; 89 mObject=<a href="/coding/file/types_8lint_8h/#types_8lint_8h_1a070d2ce7b6bb7e5c05602aa8c308d0c4">NULL</a>; 90 } 91 92 GameBaseListNode * mPrev; 93 GameBaseListNode * mNext; 94 GameBase * mObject; 95 96 void linkBefore(GameBaseListNode * obj) 97 { 98 // Link this before obj 99 mNext = obj; 100 mPrev = obj->mPrev; 101 obj->mPrev = this; 102 mPrev->mNext = this; 103 } 104 }; 105} // namespace 106 107//-------------------------------------------------------------------------- 108// ClientProcessList 109//-------------------------------------------------------------------------- 110 111StdClientProcessList::StdClientProcessList() 112{ 113} 114 115bool StdClientProcessList::advanceTime( SimTime timeDelta ) 116{ 117 PROFILE_SCOPE( StdClientProcessList_AdvanceTime ); 118 119 if ( doBacklogged( timeDelta ) ) 120 return false; 121 122 bool ret = Parent::advanceTime( timeDelta ); 123 ProcessObject *obj = NULL; 124 125 AssertFatal( mLastDelta >= 0.0f && mLastDelta <= 1.0f, "mLastDelta is not zero to one."); 126 127 obj = mHead.mProcessLink.next; 128 while ( obj != &mHead ) 129 { 130 if ( obj->isTicking() ) 131 obj->interpolateTick( mLastDelta ); 132 133 obj = obj->mProcessLink.next; 134 } 135 136 // Inform objects of total elapsed delta so they can advance 137 // client side animations. 138 F32 dt = F32(timeDelta) / 1000; 139 140 // Update camera FX. 141 gCamFXMgr.update( dt ); 142 143 obj = mHead.mProcessLink.next; 144 while ( obj != &mHead ) 145 { 146 obj->advanceTime( dt ); 147 obj = obj->mProcessLink.next; 148 } 149 150 return ret; 151} 152 153//---------------------------------------------------------------------------- 154void StdClientProcessList::onAdvanceObjects() 155{ 156 PROFILE_SCOPE( StdClientProcessList_OnAdvanceObjects ); 157 158 GameConnection* connection = GameConnection::getConnectionToServer(); 159 if ( connection ) 160 { 161 // process any demo blocks that are NOT moves, and exactly one move 162 // we advance time in the demo stream by a move inserted on 163 // each tick. So before doing the tick processing we advance 164 // the demo stream until a move is ready 165 if ( connection->isPlayingBack() ) 166 { 167 U32 blockType; 168 do 169 { 170 blockType = connection->getNextBlockType(); 171 bool res = connection->processNextBlock(); 172 // if there are no more blocks, exit out of this function, 173 // as no more client time needs to process right now - we'll 174 // get it all on the next advanceClientTime() 175 if(!res) 176 return; 177 } 178 while ( blockType != GameConnection::BlockTypeMove ); 179 } 180 181 connection->mMoveList->collectMove(); 182 advanceObjects(); 183 } 184 else 185 advanceObjects(); 186} 187 188void StdClientProcessList::onTickObject( ProcessObject *obj ) 189{ 190 PROFILE_SCOPE( StdClientProcessList_OnTickObject ); 191 192 // In case the object deletes itself during its processTick. 193 SimObjectPtr<SceneObject> safePtr = static_cast<SceneObject*>( obj ); 194 195 // Each object is either advanced a single tick, or if it's 196 // being controlled by a client, ticked once for each pending move. 197 Move* movePtr; 198 U32 numMoves; 199 GameConnection* con = obj->getControllingClient(); 200 if ( con && con->getControlObject() == obj ) 201 { 202 con->mMoveList->getMoves( &movePtr, &numMoves ); 203 if ( numMoves ) 204 { 205 // Note: should only have a single move at this point 206 AssertFatal(numMoves==1,"ClientProccessList::onTickObject: more than one move in queue"); 207 208 #ifdef TORQUE_DEBUG_NET_MOVES 209 U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient()); 210 #endif 211 212 if ( obj->isTicking() ) 213 obj->processTick( movePtr ); 214 215 if ( bool(safePtr) && obj->getControllingClient() ) 216 { 217 U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() ); 218 219 // set checksum if not set or check against stored value if set 220 movePtr->checksum = newsum; 221 222 #ifdef TORQUE_DEBUG_NET_MOVES 223 Con::printf("move checksum: %i, (start %i), (move %f %f %f)", 224 movePtr->checksum,sum,movePtr->yaw,movePtr->y,movePtr->z); 225 #endif 226 } 227 con->mMoveList->clearMoves( 1 ); 228 } 229 } 230 else if ( obj->isTicking() ) 231 obj->processTick( 0 ); 232} 233 234void StdClientProcessList::advanceObjects() 235{ 236 PROFILE_SCOPE( StdClientProcessList_AdvanceObjects ); 237 238 #ifdef TORQUE_DEBUG_NET_MOVES 239 Con::printf("Advance client time..."); 240 #endif 241 242 Parent::advanceObjects(); 243 244 #ifdef TORQUE_DEBUG_NET_MOVES 245 Con::printf("---------"); 246 #endif 247} 248 249void StdClientProcessList::clientCatchup( GameConnection * connection ) 250{ 251 SimObjectPtr<GameBase> control = connection->getControlObject(); 252 if ( control ) 253 { 254 Move * movePtr; 255 U32 numMoves; 256 U32 m = 0; 257 connection->mMoveList->getMoves( &movePtr, &numMoves ); 258 259 #ifdef TORQUE_DEBUG_NET_MOVES 260 Con::printf("client catching up... (%i)", numMoves); 261 #endif 262 263 preTickSignal().trigger(); 264 265 if ( control->isTicking() ) 266 for ( m = 0; m < numMoves; m++ ) 267 control->processTick( movePtr++ ); 268 269 connection->mMoveList->clearMoves( m ); 270 } 271 272 #ifdef TORQUE_DEBUG_NET_MOVES 273 Con::printf("---------"); 274 #endif 275} 276 277//-------------------------------------------------------------------------- 278// ServerProcessList 279//-------------------------------------------------------------------------- 280 281StdServerProcessList::StdServerProcessList() 282{ 283} 284 285void StdServerProcessList::onPreTickObject( ProcessObject *pobj ) 286{ 287 if ( pobj->mIsGameBase ) 288 { 289 SimObjectPtr<GameBase> obj = getGameBase( pobj ); 290 291 // Each object is either advanced a single tick, or if it's 292 // being controlled by a client, ticked once for each pending move. 293 GameConnection *con = obj->getControllingClient(); 294 295 if ( con && con->getControlObject() == obj ) 296 { 297 Move* movePtr; 298 U32 numMoves; 299 con->mMoveList->getMoves( &movePtr, &numMoves ); 300 301 if ( numMoves == 0 ) 302 { 303 #ifdef TORQUE_DEBUG_NET_MOVES 304 Con::printf("no moves on object %i, skip tick",obj->getId()); 305 #endif 306 return; 307 } 308 } 309 } 310 311 Parent::onPreTickObject (pobj ); 312} 313 314void StdServerProcessList::onTickObject( ProcessObject *pobj ) 315{ 316 PROFILE_SCOPE( StdServerProcessList_OnTickObject ); 317 318 // Each object is either advanced a single tick, or if it's 319 // being controlled by a client, ticked once for each pending move. 320 321 GameConnection *con = pobj->getControllingClient(); 322 323 if ( pobj->mIsGameBase && con && con->getControlObject() == pobj ) 324 { 325 // In case the object is deleted during its own tick. 326 SimObjectPtr<GameBase> obj = getGameBase( pobj ); 327 328 Move* movePtr; 329 U32 m, numMoves; 330 con->mMoveList->getMoves( &movePtr, &numMoves ); 331 332 // For debugging it can be useful to know when this happens. 333 //if ( numMoves > 1 ) 334 // Con::printf( "numMoves: %i", numMoves ); 335 336 // Do we really need to test the control object each iteration? Does it change? 337 for ( m = 0; m < numMoves && con && con->getControlObject() == obj; m++, movePtr++ ) 338 { 339 #ifdef TORQUE_DEBUG_NET_MOVES 340 U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient()); 341 #endif 342 343 if ( obj->isTicking() ) 344 obj->processTick( movePtr ); 345 346 if ( con && con->getControlObject() == obj ) 347 { 348 U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() ); 349 350 // check move checksum 351 if ( movePtr->checksum != newsum ) 352 { 353 #ifdef TORQUE_DEBUG_NET_MOVES 354 if( !obj->isAIControlled() ) 355 Con::printf("move %i checksum disagree: %i != %i, (start %i), (move %f %f %f)", 356 movePtr->id, movePtr->checksum,newsum,sum,movePtr->yaw,movePtr->y,movePtr->z); 357 #endif 358 359 movePtr->checksum = Move::ChecksumMismatch; 360 } 361 else 362 { 363 #ifdef TORQUE_DEBUG_NET_MOVES 364 Con::printf("move %i checksum agree: %i == %i, (start %i), (move %f %f %f)", 365 movePtr->id, movePtr->checksum,newsum,sum,movePtr->yaw,movePtr->y,movePtr->z); 366 #endif 367 } 368 } 369 } 370 371 con->mMoveList->clearMoves( m ); 372 } 373 else if ( pobj->isTicking() ) 374 pobj->processTick( 0 ); 375} 376 377void StdServerProcessList::advanceObjects() 378{ 379 #ifdef TORQUE_DEBUG_NET_MOVES 380 Con::printf("Advance server time..."); 381 #endif 382 383 Parent::advanceObjects(); 384 385 // Credit all connections with the elapsed tick 386 SimGroup *clientGroup = Sim::getClientGroup(); 387 for(SimGroup::iterator i = clientGroup->begin(); i != clientGroup->end(); i++) 388 { 389 if (GameConnection *con = dynamic_cast<GameConnection *>(*i)) 390 { 391 con->mMoveList->advanceMove(); 392 } 393 } 394 395 #ifdef TORQUE_DEBUG_NET_MOVES 396 Con::printf("---------"); 397 #endif 398} 399 400 401 402