hifiMoveList.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "T3D/gameBase/hifi/hifiMoveList.h"
  23. #include "T3D/gameBase/hifi/hifiGameProcess.h"
  24. #include "T3D/gameBase/gameConnection.h"
  25. #include "core/stream/bitStream.h"
  26. #define MAX_MOVE_PACKET_SENDS 4
  27. const U32 DefaultTargetMoveListSize = 3;
  28. const U32 DefaultMaxMoveSizeList = 5;
  29. const F32 DefaultSmoothMoveAvg = 0.15f;
  30. const F32 DefaultMoveListSizeSlack = 1.0f;
  31. HifiMoveList::HifiMoveList()
  32. {
  33. mLastSentMove = 0;
  34. mAvgMoveQueueSize = DefaultTargetMoveListSize ;
  35. mTargetMoveListSize = DefaultTargetMoveListSize;
  36. mMaxMoveListSize = DefaultMaxMoveSizeList;
  37. mSmoothMoveAvg = DefaultSmoothMoveAvg;
  38. mMoveListSizeSlack = DefaultMoveListSizeSlack;
  39. mTotalServerTicks = ServerTicksUninitialized;
  40. mSuppressMove = false;
  41. }
  42. void HifiMoveList::updateClientServerTickDiff(S32 & tickDiff)
  43. {
  44. if (mLastMoveAck==0)
  45. tickDiff=0;
  46. // Make adjustments to move list to account for tick mis-matches between client and server.
  47. if (tickDiff>0)
  48. {
  49. // Server ticked more than client. Adjust for this by reseting all hifi objects
  50. // to a later position in the tick cache (see ageTickCache below) and at the same
  51. // time pulling back some moves we thought we had made (so that time on client
  52. // doesn't change).
  53. S32 dropTicks = tickDiff;
  54. while (dropTicks)
  55. {
  56. #ifdef TORQUE_DEBUG_NET_MOVES
  57. Con::printf("dropping move%s",mLastClientMove>mFirstMoveIndex ? "" : " but none there");
  58. #endif
  59. if (mLastClientMove>mFirstMoveIndex)
  60. mLastClientMove--;
  61. else
  62. tickDiff--;
  63. dropTicks--;
  64. }
  65. AssertFatal(mLastClientMove >= mFirstMoveIndex, "Bad move request");
  66. AssertFatal(mLastClientMove - mFirstMoveIndex <= mMoveVec.size(), "Desynched first and last move.");
  67. }
  68. else
  69. {
  70. // Client ticked more than server. Adjust for this by taking extra moves
  71. // (either adding back moves that were dropped above, or taking new ones).
  72. for (S32 i=0; i<-tickDiff; i++)
  73. {
  74. if (mMoveVec.size() > mLastClientMove - mFirstMoveIndex)
  75. {
  76. #ifdef TORQUE_DEBUG_NET_MOVES
  77. Con::printf("add back move");
  78. #endif
  79. mLastClientMove++;
  80. }
  81. else
  82. {
  83. #ifdef TORQUE_DEBUG_NET_MOVES
  84. Con::printf("add back move -- create one");
  85. #endif
  86. collectMove();
  87. mLastClientMove++;
  88. }
  89. }
  90. }
  91. // drop moves that are not made yet (because we rolled them back) and not yet sent
  92. U32 len = getMax(mLastClientMove-mFirstMoveIndex,mLastSentMove-mFirstMoveIndex);
  93. mMoveVec.setSize(len);
  94. #ifdef TORQUE_DEBUG_NET_MOVES
  95. Con::printf("move list size: %i, last move: %i, last sent: %i",mMoveVec.size(),mLastClientMove-mFirstMoveIndex,mLastSentMove-mFirstMoveIndex);
  96. #endif
  97. }
  98. S32 HifiMoveList::getServerTicks(U32 serverTickNum)
  99. {
  100. S32 serverTicks=0;
  101. if (serverTicksInitialized())
  102. {
  103. // handle tick wrapping...
  104. const S32 MaxTickCount = (1<<TotalTicksBits);
  105. const S32 HalfMaxTickCount = MaxTickCount>>1;
  106. U32 prevTickNum = mTotalServerTicks & TotalTicksMask;
  107. serverTicks = serverTickNum-prevTickNum;
  108. if (serverTicks>HalfMaxTickCount)
  109. serverTicks -= MaxTickCount;
  110. else if (-serverTicks>HalfMaxTickCount)
  111. serverTicks += MaxTickCount;
  112. AssertFatal(serverTicks>=0,"Server can't tick backwards!!!");
  113. if (serverTicks<0)
  114. serverTicks=0;
  115. }
  116. mTotalServerTicks = serverTickNum;
  117. return serverTicks;
  118. }
  119. void HifiMoveList::markControlDirty()
  120. {
  121. mLastClientMove = mLastMoveAck;
  122. // save state for future update
  123. GameBase *obj = mConnection->getControlObject();
  124. AssertFatal(obj,"ClientProcessList::markControlDirty: no control object");
  125. obj->setGhostUpdated(true);
  126. obj->getTickCache().beginCacheList();
  127. TickCacheEntry * tce = obj->getTickCache().incCacheList();
  128. BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize);
  129. obj->writePacketData( mConnection, &bs );
  130. }
  131. void HifiMoveList::resetMoveList()
  132. {
  133. mMoveVec.clear();
  134. mLastMoveAck = 0;
  135. mLastClientMove = 0;
  136. mFirstMoveIndex = 0;
  137. mLastSentMove = 0;
  138. }
  139. U32 HifiMoveList::getMoves(Move** movePtr,U32* numMoves)
  140. {
  141. if (mConnection->isConnectionToServer())
  142. // give back moves starting at the last client move...
  143. return Parent::getMoves(movePtr,numMoves);
  144. if (mSuppressMove || mMoveVec.size()==0)
  145. {
  146. *numMoves=0;
  147. *movePtr=NULL;
  148. }
  149. else
  150. {
  151. *numMoves=1;
  152. *movePtr=mMoveVec.begin();
  153. }
  154. return *numMoves;
  155. }
  156. void HifiMoveList::advanceMove()
  157. {
  158. S32 numMoves = mMoveVec.size();
  159. mAvgMoveQueueSize *= (1.0f-mSmoothMoveAvg);
  160. mAvgMoveQueueSize += mSmoothMoveAvg * F32(numMoves);
  161. #ifdef TORQUE_DEBUG_NET_MOVES
  162. Con::printf("moves remaining: %i, running avg: %f",numMoves,mAvgMoveQueueSize);
  163. #endif
  164. if (mAvgMoveQueueSize<mTargetMoveListSize-mMoveListSizeSlack && numMoves<mTargetMoveListSize && numMoves)
  165. {
  166. numMoves=0;
  167. mAvgMoveQueueSize = (F32)getMax(S32(mAvgMoveQueueSize + mMoveListSizeSlack + 0.5f),numMoves);
  168. #ifdef TORQUE_DEBUG_NET_MOVES
  169. Con::printf("too few moves on server, padding with null move");
  170. #endif
  171. }
  172. if (numMoves)
  173. numMoves=1;
  174. if ( mMoveVec.size()>mMaxMoveListSize || (mAvgMoveQueueSize>mTargetMoveListSize+mMoveListSizeSlack && mMoveVec.size()>mTargetMoveListSize) )
  175. {
  176. U32 drop = mMoveVec.size()-mTargetMoveListSize;
  177. clearMoves(drop);
  178. mAvgMoveQueueSize = (F32)mTargetMoveListSize;
  179. #ifdef TORQUE_DEBUG_NET_MOVES
  180. Con::printf("too many moves on server, dropping moves (%i)",drop);
  181. #endif
  182. }
  183. mSuppressMove = numMoves == 0;
  184. // now clear move
  185. if (areMovesPending())
  186. clearMoves(1);
  187. }
  188. void HifiMoveList::clientWriteMovePacket(BitStream *bstream)
  189. {
  190. if (!serverTicksInitialized())
  191. resetMoveList();
  192. AssertFatal(mLastMoveAck == mFirstMoveIndex, "Invalid move index.");
  193. // enforce limit on number of moves sent
  194. if (mLastSentMove<mFirstMoveIndex)
  195. mLastSentMove=mFirstMoveIndex;
  196. U32 count = mLastSentMove-mFirstMoveIndex;
  197. Move * move = mMoveVec.address();
  198. U32 start = mLastMoveAck;
  199. U32 offset;
  200. for(offset = 0; offset < count; offset++)
  201. if(move[offset].sendCount < MAX_MOVE_PACKET_SENDS)
  202. break;
  203. if(offset == count && count != 0)
  204. offset--;
  205. start += offset;
  206. count -= offset;
  207. if (count > MaxMoveCount)
  208. count = MaxMoveCount;
  209. bstream->writeInt(start,32);
  210. bstream->writeInt(count,MoveCountBits);
  211. Move * prevMove = NULL;
  212. for (int i = 0; i < count; i++)
  213. {
  214. move[offset + i].sendCount++;
  215. move[offset + i].pack(bstream,prevMove);
  216. bstream->writeInt(move[offset + i].checksum,Move::ChecksumBits);
  217. prevMove = &move[offset+i];
  218. }
  219. }
  220. void HifiMoveList::serverReadMovePacket(BitStream *bstream)
  221. {
  222. // Server side packet read.
  223. U32 start = bstream->readInt(32);
  224. U32 count = bstream->readInt(MoveCountBits);
  225. Move * prevMove = NULL;
  226. Move prevMoveHolder;
  227. // Skip forward (must be starting up), or over the moves
  228. // we already have.
  229. int skip = mLastMoveAck - start;
  230. if (skip < 0)
  231. {
  232. mLastMoveAck = start;
  233. }
  234. else
  235. {
  236. if (skip > count)
  237. skip = count;
  238. for (int i = 0; i < skip; i++)
  239. {
  240. prevMoveHolder.unpack(bstream,prevMove);
  241. prevMoveHolder.checksum = bstream->readInt(Move::ChecksumBits);
  242. prevMove = &prevMoveHolder;
  243. S32 idx = mMoveVec.size()-skip+i;
  244. if (idx>=0)
  245. {
  246. #ifdef TORQUE_DEBUG_NET_MOVES
  247. if (mMoveVec[idx].checksum != prevMoveHolder.checksum)
  248. Con::printf("updated checksum on move %i from %i to %i",mMoveVec[idx].id,mMoveVec[idx].checksum,prevMoveHolder.checksum);
  249. #endif
  250. mMoveVec[idx].checksum = prevMoveHolder.checksum;
  251. }
  252. }
  253. start += skip;
  254. count = count - skip;
  255. }
  256. // Put the rest on the move list.
  257. int index = mMoveVec.size();
  258. mMoveVec.increment(count);
  259. while (index < mMoveVec.size())
  260. {
  261. mMoveVec[index].unpack(bstream,prevMove);
  262. mMoveVec[index].checksum = bstream->readInt(Move::ChecksumBits);
  263. prevMove = &mMoveVec[index];
  264. mMoveVec[index].id = start++;
  265. index ++;
  266. }
  267. mLastMoveAck += count;
  268. if (mMoveVec.size()>mMaxMoveListSize)
  269. {
  270. U32 drop = mMoveVec.size()-mTargetMoveListSize;
  271. clearMoves(drop);
  272. mAvgMoveQueueSize = (F32)mTargetMoveListSize;
  273. #ifdef TORQUE_DEBUG_NET_MOVES
  274. Con::printf("too many moves on server, dropping moves (%i)",drop);
  275. #endif
  276. }
  277. }
  278. void HifiMoveList::serverWriteMovePacket(BitStream * bstream)
  279. {
  280. #ifdef TORQUE_DEBUG_NET_MOVES
  281. Con::printf("ack %i minus %i",mLastMoveAck,mMoveVec.size());
  282. #endif
  283. // acknowledge only those moves that have been ticked
  284. bstream->writeInt(mLastMoveAck - mMoveVec.size(),32);
  285. // send over the current tick count on the server...
  286. bstream->writeInt(ServerProcessList::get()->getTotalTicks() & TotalTicksMask, TotalTicksBits);
  287. }
  288. void HifiMoveList::clientReadMovePacket(BitStream * bstream)
  289. {
  290. if (!serverTicksInitialized())
  291. resetMoveList();
  292. #ifdef TORQUE_DEBUG_NET_MOVES
  293. Con::printf("pre move ack: %i", mLastMoveAck);
  294. #endif
  295. mLastMoveAck = bstream->readInt(32);
  296. #ifdef TORQUE_DEBUG_NET_MOVES
  297. Con::printf("post move ack %i, first move %i, last move %i", mLastMoveAck, mFirstMoveIndex, mLastClientMove);
  298. #endif
  299. // This is how many times we've ticked since last ack -- before adjustments below
  300. S32 ourTicks = mLastMoveAck - mFirstMoveIndex;
  301. if (mLastMoveAck < mFirstMoveIndex)
  302. mLastMoveAck = mFirstMoveIndex;
  303. if(mLastMoveAck > mLastClientMove)
  304. {
  305. ourTicks -= mLastMoveAck-mLastClientMove;
  306. mLastClientMove = mLastMoveAck;
  307. }
  308. while(mFirstMoveIndex < mLastMoveAck)
  309. {
  310. if (mMoveVec.size())
  311. {
  312. mMoveVec.pop_front();
  313. mFirstMoveIndex++;
  314. }
  315. else
  316. {
  317. AssertWarn(1, "Popping off too many moves!");
  318. mFirstMoveIndex = mLastMoveAck;
  319. }
  320. }
  321. // get server ticks using total number of ticks on server to date...
  322. U32 serverTickNum = bstream->readInt(TotalTicksBits);
  323. S32 serverTicks = getServerTicks(serverTickNum);
  324. S32 tickDiff = serverTicks - ourTicks;
  325. #ifdef TORQUE_DEBUG_NET_MOVES
  326. Con::printf("server ticks: %i, client ticks: %i, diff: %i%s", serverTicks, ourTicks, tickDiff, !tickDiff ? "" : " (ticks mis-match)");
  327. #endif
  328. // Apply the first (of two) client-side synchronization mechanisms. Key is that
  329. // we need to both synchronize client/server move streams (so first move in list is made
  330. // at same "time" on both client and server) and maintain the "time" at which the most
  331. // recent move was made on the server. In both cases, "time" is the number of ticks
  332. // it took to get to that move.
  333. updateClientServerTickDiff(tickDiff);
  334. // Apply the second (and final) client-side synchronization mechanism. The tickDiff adjustments above
  335. // make sure time is preserved on client. But that assumes that a future (or previous) update will adjust
  336. // time in the other direction, so that we don't get too far behind or ahead of the server. The updateMoveSync
  337. // mechanism tracks us over time to make sure we eventually return to be in sync, and makes adjustments
  338. // if we don't after a certain time period (number of updates). Unlike the tickDiff mechanism, when
  339. // the updateMoveSync acts time is not preserved on the client.
  340. HifiClientProcessList * processList = dynamic_cast<HifiClientProcessList*>(ClientProcessList::get());
  341. if (processList)
  342. {
  343. processList->updateMoveSync(mLastSentMove-mLastClientMove);
  344. // set catchup parameters...
  345. U32 totalCatchup = mLastClientMove - mFirstMoveIndex;
  346. processList->ageTickCache(ourTicks + (tickDiff>0 ? tickDiff : 0), totalCatchup+1);
  347. processList->forceHifiReset(tickDiff!=0);
  348. processList->setCatchup(totalCatchup);
  349. }
  350. }
  351. void HifiMoveList::ghostPreRead(NetObject * nobj, bool newGhost)
  352. {
  353. GameBase* obj = dynamic_cast<GameBase*>(nobj);
  354. if ( obj && ( obj->getTypeMask() & GameBaseHiFiObjectType ) && !newGhost )
  355. {
  356. // set next cache entry to start
  357. obj->getTickCache().beginCacheList();
  358. // reset to old state because we are about to unpack (and then tick forward)
  359. TickCacheEntry * tce = obj->getTickCache().incCacheList(false);
  360. if (tce)
  361. {
  362. BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize);
  363. obj->readPacketData(mConnection, &bs);
  364. }
  365. }
  366. }
  367. void HifiMoveList::ghostReadExtra(NetObject * nobj, BitStream * bstream, bool newGhost)
  368. {
  369. // Receive additional per ghost information.
  370. // Get pending moves for ghosts that have them and add the moves to
  371. // the tick cache.
  372. GameBase* obj = dynamic_cast<GameBase*>(nobj);
  373. if ( obj && ( obj->getTypeMask() & GameBaseHiFiObjectType ) )
  374. {
  375. // mark ghost so that it updates correctly
  376. obj->setGhostUpdated(true);
  377. obj->setNewGhost(newGhost);
  378. // set next cache entry to start
  379. obj->getTickCache().beginCacheList();
  380. // save state for future update
  381. TickCacheEntry * tce = obj->getTickCache().incCacheList();
  382. BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize);
  383. obj->writePacketData(mConnection, &bs);
  384. }
  385. }