Snapshot.cpp 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. idCVar net_verboseSnapshot( "net_verboseSnapshot", "0", CVAR_INTEGER|CVAR_NOCHEAT, "Verbose snapshot code to help debug snapshot problems. Greater the number greater the spam" );
  23. idCVar net_verboseSnapshotCompression( "net_verboseSnapshotCompression", "0", CVAR_INTEGER|CVAR_NOCHEAT, "Verbose snapshot code to help debug snapshot problems. Greater the number greater the spam" );
  24. idCVar net_verboseSnapshotReport( "net_verboseSnapshotReport", "0", CVAR_INTEGER|CVAR_NOCHEAT, "Verbose snapshot code to help debug snapshot problems. Greater the number greater the spam" );
  25. idCVar net_ssTemplateDebug( "net_ssTemplateDebug", "0", CVAR_BOOL, "Debug snapshot template states" );
  26. idCVar net_ssTemplateDebug_len( "net_ssTemplateDebug_len", "32", CVAR_INTEGER, "Offset to start template state debugging" );
  27. idCVar net_ssTemplateDebug_start( "net_ssTemplateDebug_start", "0", CVAR_INTEGER, "length of template state to print in debugging" );
  28. /*
  29. ========================
  30. InDebugRange
  31. Helper function for net_ssTemplateDebug debugging
  32. ========================
  33. */
  34. bool InDebugRange( int i ) {
  35. return ( i >= net_ssTemplateDebug_start.GetInteger() && i < net_ssTemplateDebug_start.GetInteger() + net_ssTemplateDebug_len.GetInteger() );
  36. }
  37. /*
  38. ========================
  39. PrintAlign
  40. Helper function for net_ssTemplateDebug debugging
  41. ========================
  42. */
  43. void PrintAlign( const char * text ) {
  44. idLib::Printf( "%25s: 0x", text );
  45. }
  46. /*
  47. ========================
  48. idSnapShot::objectState_t::Print
  49. Helper function for net_ssTemplateDebug debugging
  50. ========================
  51. */
  52. void idSnapShot::objectState_t::Print( const char * name ) {
  53. unsigned int start = (unsigned int)net_ssTemplateDebug_start.GetInteger();
  54. unsigned int end = Min( (unsigned int)buffer.Size(), start + net_ssTemplateDebug_len.GetInteger() );
  55. PrintAlign( va( "%s: [sz %d]", name, buffer.Size() ) );
  56. for ( unsigned int i = start; i < end; i++ ) {
  57. idLib::Printf( "%02X", buffer[i] );
  58. }
  59. idLib::Printf("\n");
  60. }
  61. /*
  62. ========================
  63. idSnapShot::objectBuffer_t::Alloc
  64. ========================
  65. */
  66. void idSnapShot::objectBuffer_t::Alloc( int s ) {
  67. //assert( mem.IsMapHeap() );
  68. if ( !verify( s < SIZE_NOT_STALE ) ) {
  69. idLib::FatalError( "s >= SIZE_NOT_STALE" );
  70. }
  71. _Release();
  72. data = (byte *)Mem_Alloc( s + 1, TAG_NETWORKING );
  73. size = s;
  74. data[size] = 1;
  75. }
  76. /*
  77. ========================
  78. idSnapShot::objectBuffer_t::AddRef
  79. ========================
  80. */
  81. void idSnapShot::objectBuffer_t::_AddRef() {
  82. if ( data != NULL ) {
  83. assert( size > 0 );
  84. assert( data[size] < 255 );
  85. data[size]++;
  86. }
  87. }
  88. /*
  89. ========================
  90. idSnapShot::objectBuffer_t::Release
  91. ========================
  92. */
  93. void idSnapShot::objectBuffer_t::_Release() {
  94. //assert( mem.IsMapHeap() );
  95. if ( data != NULL ) {
  96. assert( size > 0 );
  97. if ( --data[size] == 0 ) {
  98. Mem_Free( data );
  99. }
  100. data = NULL;
  101. size = 0;
  102. }
  103. }
  104. /*
  105. ========================
  106. idSnapShot::objectBuffer_t::operator=
  107. ========================
  108. */
  109. void idSnapShot::objectBuffer_t::operator=( const idSnapShot::objectBuffer_t & other ) {
  110. //assert( mem.IsMapHeap() );
  111. if ( this != &other ) {
  112. _Release();
  113. data = other.data;
  114. size = other.size;
  115. _AddRef();
  116. }
  117. }
  118. /*
  119. ========================
  120. idSnapShot::idSnapShot
  121. ========================
  122. */
  123. idSnapShot::idSnapShot() :
  124. time( 0 ),
  125. recvTime( 0 )
  126. {
  127. }
  128. /*
  129. ========================
  130. idSnapShot::idSnapShot
  131. ========================
  132. */
  133. idSnapShot::idSnapShot( const idSnapShot & other ) : time( 0 ), recvTime(0) {
  134. *this = other;
  135. }
  136. /*
  137. ========================
  138. idSnapShot::~idSnapShot
  139. ========================
  140. */
  141. idSnapShot::~idSnapShot() {
  142. Clear();
  143. }
  144. /*
  145. ========================
  146. idSnapShot::Clear
  147. ========================
  148. */
  149. void idSnapShot::Clear() {
  150. time = 0;
  151. recvTime = 0;
  152. for ( int i = 0; i < objectStates.Num(); i++ ) {
  153. FreeObjectState( i );
  154. }
  155. objectStates.Clear();
  156. allocatedObjs.Shutdown();
  157. }
  158. /*
  159. ========================
  160. idSnapShot::operator=
  161. ========================
  162. */
  163. void idSnapShot::operator=( const idSnapShot & other ) {
  164. //assert( mem.IsMapHeap() );
  165. if ( this != &other ) {
  166. for ( int i = other.objectStates.Num(); i < objectStates.Num(); i++ ) {
  167. FreeObjectState( i );
  168. }
  169. objectStates.AssureSize( other.objectStates.Num(), NULL );
  170. for ( int i = 0; i < objectStates.Num(); i++ ) {
  171. const objectState_t & otherState = *other.objectStates[i];
  172. if ( objectStates[i] == NULL ) {
  173. objectStates[i] = allocatedObjs.Alloc();
  174. }
  175. objectState_t & state = *objectStates[i];
  176. state.objectNum = otherState.objectNum;
  177. state.buffer = otherState.buffer;
  178. state.visMask = otherState.visMask;
  179. state.stale = otherState.stale;
  180. state.deleted = otherState.deleted;
  181. state.changedCount = otherState.changedCount;
  182. state.expectedSequence = otherState.expectedSequence;
  183. state.createdFromTemplate = otherState.createdFromTemplate;
  184. }
  185. time = other.time;
  186. recvTime = other.recvTime;
  187. }
  188. }
  189. /*
  190. ========================
  191. idSnapShot::PeekDeltaSequence
  192. ========================
  193. */
  194. void idSnapShot::PeekDeltaSequence( const char * deltaMem, int deltaSize, int & sequence, int & baseSequence ) {
  195. lzwCompressionData_t lzwData;
  196. idLZWCompressor lzwCompressor( &lzwData );
  197. lzwCompressor.Start( (uint8*)deltaMem, deltaSize );
  198. lzwCompressor.ReadAgnostic( sequence );
  199. lzwCompressor.ReadAgnostic( baseSequence );
  200. }
  201. /*
  202. ========================
  203. idSnapShot::ReadDeltaForJob
  204. ========================
  205. */
  206. bool idSnapShot::ReadDeltaForJob( const char * deltaMem, int deltaSize, int visIndex, idSnapShot * templateStates ) {
  207. bool report = net_verboseSnapshotReport.GetBool();
  208. net_verboseSnapshotReport.SetBool( false );
  209. lzwCompressionData_t lzwData;
  210. idZeroRunLengthCompressor rleCompressor;
  211. idLZWCompressor lzwCompressor( &lzwData );
  212. int bytesRead = 0; // how many uncompressed bytes we read in. Used to figure out compression ratio
  213. lzwCompressor.Start( (uint8*)deltaMem, deltaSize );
  214. // Skip past sequence and baseSequence
  215. int sequence = 0;
  216. int baseSequence = 0;
  217. lzwCompressor.ReadAgnostic( sequence );
  218. lzwCompressor.ReadAgnostic( baseSequence );
  219. lzwCompressor.ReadAgnostic( time );
  220. bytesRead += sizeof( int ) * 3;
  221. int objectNum = 0;
  222. uint16 delta = 0;
  223. while ( lzwCompressor.ReadAgnostic( delta, true ) == sizeof( delta ) ) {
  224. bytesRead += sizeof( delta );
  225. objectNum += delta;
  226. if ( objectNum >= 0xFFFF ) {
  227. // full delta
  228. if ( net_verboseSnapshotCompression.GetBool() ) {
  229. float compRatio = static_cast<float>( deltaSize ) / static_cast<float>( bytesRead );
  230. idLib::Printf( "Snapshot (%d/%d). ReadSize: %d DeltaSize: %d Ratio: %.3f\n", sequence, baseSequence, bytesRead, deltaSize, compRatio );
  231. }
  232. return true;
  233. }
  234. objectState_t & state = FindOrCreateObjectByID( objectNum );
  235. objectSize_t newsize = 0;
  236. lzwCompressor.ReadAgnostic( newsize );
  237. bytesRead += sizeof( newsize );
  238. if ( newsize == SIZE_STALE ) {
  239. NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d goes stale\n", objectNum );
  240. // sanity
  241. bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0;
  242. if ( !oldVisible ) {
  243. NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected already stale\n" );
  244. }
  245. state.visMask &= ~( 1 << visIndex );
  246. state.stale = true;
  247. // We need to make sure we haven't freed stale objects.
  248. assert( state.buffer.Size() > 0 );
  249. // no more data
  250. continue;
  251. } else if ( newsize == SIZE_NOT_STALE ) {
  252. NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d no longer stale\n", objectNum );
  253. // sanity
  254. bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0;
  255. if ( oldVisible ) {
  256. NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected not stale\n" );
  257. }
  258. state.visMask |= ( 1 << visIndex );
  259. state.stale = false;
  260. // the latest state is packed in, get the new size and continue reading the new state
  261. lzwCompressor.ReadAgnostic( newsize );
  262. bytesRead += sizeof( newsize );
  263. }
  264. objectState_t * objTemplateState = templateStates->FindObjectByID( objectNum );
  265. if ( newsize == 0 ) {
  266. // object deleted: reset state now so next one to use it doesn't have old data
  267. state.deleted = false;
  268. state.stale = false;
  269. state.changedCount = 0;
  270. state.expectedSequence = 0;
  271. state.visMask = 0;
  272. state.buffer._Release();
  273. state.createdFromTemplate = false;
  274. if ( objTemplateState != NULL && objTemplateState->buffer.Size() && objTemplateState->expectedSequence < baseSequence ) {
  275. idLib::PrintfIf( net_ssTemplateDebug.GetBool(), "Clearing old template state[%d] [%d<%d]\n", objectNum, objTemplateState->expectedSequence, baseSequence );
  276. objTemplateState->deleted = false;
  277. objTemplateState->stale = false;
  278. objTemplateState->changedCount = 0;
  279. objTemplateState->expectedSequence = 0;
  280. objTemplateState->visMask = 0;
  281. objTemplateState->buffer._Release();
  282. }
  283. } else {
  284. // new state?
  285. bool debug = false;
  286. if ( state.buffer.Size() == 0 ) {
  287. state.createdFromTemplate = true;
  288. // Brand new state
  289. if ( objTemplateState != NULL && objTemplateState->buffer.Size() > 0 && sequence >= objTemplateState->expectedSequence ) {
  290. idLib::PrintfIf( net_ssTemplateDebug.GetBool(), "\nAdding basestate for new object %d (for SS %d/%d. obj base created in ss %d) deltaSize: %d\n", objectNum, sequence, baseSequence, objTemplateState->expectedSequence, deltaSize );
  291. state.buffer = objTemplateState->buffer;
  292. if ( net_ssTemplateDebug.GetBool() ) {
  293. state.Print( "SPAWN STATE" );
  294. debug = true;
  295. PrintAlign( "DELTA STATE" );
  296. }
  297. } else if ( net_ssTemplateDebug.GetBool() ) {
  298. idLib::Printf("\nNew snapobject[%d] in snapshot %d/%d but no basestate found locally so creating new\n", objectNum, sequence, baseSequence );
  299. }
  300. } else {
  301. state.createdFromTemplate = false;
  302. }
  303. // the buffer shrank or stayed the same
  304. objectBuffer_t newbuffer( newsize );
  305. rleCompressor.Start( NULL, &lzwCompressor, newsize );
  306. objectSize_t compareSize = Min( state.buffer.Size(), newsize );
  307. for ( objectSize_t i = 0; i < compareSize; i++ ) {
  308. byte b = rleCompressor.ReadByte();
  309. newbuffer[i] = state.buffer[i] + b;
  310. if ( debug && InDebugRange( i ) ) {
  311. idLib::Printf( "%02X", b );
  312. }
  313. }
  314. // Catch leftover
  315. if ( newsize > compareSize ) {
  316. rleCompressor.ReadBytes( newbuffer.Ptr() + compareSize, newsize - compareSize );
  317. if ( debug ) {
  318. for ( objectSize_t i = compareSize; i < newsize; i++ ) {
  319. if ( InDebugRange( i ) ) {
  320. idLib::Printf( "%02X", newbuffer[i] );
  321. }
  322. }
  323. }
  324. }
  325. state.buffer = newbuffer;
  326. state.changedCount = sequence;
  327. bytesRead += sizeof( byte ) * newsize;
  328. if ( debug ) {
  329. idLib::Printf( "\n" );
  330. state.Print( "NEW STATE" );
  331. }
  332. if ( report ) {
  333. idLib::Printf( " Obj %d Compressed: Size %d \n", objectNum, rleCompressor.CompressedSize() );
  334. }
  335. }
  336. #ifdef SNAPSHOT_CHECKSUMS
  337. extern uint32 SnapObjChecksum( const uint8 * data, int length );
  338. if ( state.buffer.Size() > 0 ) {
  339. uint32 checksum = 0;
  340. lzwCompressor.ReadAgnostic( checksum );
  341. bytesRead += sizeof( checksum );
  342. if ( !verify( checksum == SnapObjChecksum( state.buffer.Ptr(), state.buffer.Size() ) ) ) {
  343. idLib::Error(" Invalid snapshot checksum" );
  344. }
  345. }
  346. #endif
  347. }
  348. // partial delta
  349. return false;
  350. }
  351. /*
  352. ========================
  353. idSnapShot::SubmitObjectJob
  354. ========================
  355. */
  356. void idSnapShot::SubmitObjectJob( const submitDeltaJobsInfo_t & submitDeltaJobsInfo,
  357. objectState_t * newState,
  358. objectState_t * oldState,
  359. objParms_t *& baseObjParm,
  360. objParms_t *& curObjParm,
  361. objHeader_t *& curHeader,
  362. uint8 *& curObjDest,
  363. lzwParm_t *& curlzwParm
  364. ) {
  365. assert( newState != NULL || oldState != NULL );
  366. assert_16_byte_aligned( curHeader );
  367. assert_16_byte_aligned( curObjDest );
  368. int32 dataSize = newState != NULL ? newState->buffer.Size() : 0;
  369. int totalSize = OBJ_DEST_SIZE_ALIGN16( dataSize );
  370. if ( curObjParm - submitDeltaJobsInfo.objParms >= submitDeltaJobsInfo.maxObjParms ) {
  371. idLib::Error( "Out of parms for snapshot jobs.\n");
  372. }
  373. // Check to see if we are out of dest write space, and need to flush the jobs
  374. bool needToSubmit = ( curObjDest - submitDeltaJobsInfo.objMemory ) + totalSize >= submitDeltaJobsInfo.maxObjMemory;
  375. needToSubmit |= ( curHeader - submitDeltaJobsInfo.headers >= submitDeltaJobsInfo.maxHeaders );
  376. if ( needToSubmit ) {
  377. // If this obj will put us over the limit, then submit the jobs now, and start over re-using the same buffers
  378. SubmitLZWJob( submitDeltaJobsInfo, baseObjParm, curObjParm, curlzwParm, true );
  379. curHeader = submitDeltaJobsInfo.headers;
  380. curObjDest = submitDeltaJobsInfo.objMemory;
  381. }
  382. // Setup obj parms
  383. assert( submitDeltaJobsInfo.visIndex < 256 );
  384. curObjParm->visIndex = submitDeltaJobsInfo.visIndex;
  385. curObjParm->destHeader = curHeader;
  386. curObjParm->dest = curObjDest;
  387. memset( &curObjParm->newState, 0, sizeof( curObjParm->newState ) );
  388. memset( &curObjParm->oldState, 0, sizeof( curObjParm->oldState ) );
  389. if ( newState != NULL ) {
  390. assert( newState->buffer.Size() <= 65535 );
  391. curObjParm->newState.valid = 1;
  392. curObjParm->newState.data = newState->buffer.Ptr();
  393. curObjParm->newState.size = newState->buffer.Size();
  394. curObjParm->newState.objectNum = newState->objectNum;
  395. curObjParm->newState.visMask = newState->visMask;
  396. }
  397. if ( oldState != NULL ) {
  398. assert( oldState->buffer.Size() <= 65535 );
  399. curObjParm->oldState.valid = 1;
  400. curObjParm->oldState.data = oldState->buffer.Ptr();
  401. curObjParm->oldState.size = oldState->buffer.Size();
  402. curObjParm->oldState.objectNum = oldState->objectNum;
  403. curObjParm->oldState.visMask = oldState->visMask;
  404. }
  405. assert_16_byte_aligned( curObjParm );
  406. assert_16_byte_aligned( curObjParm->newState.data );
  407. assert_16_byte_aligned( curObjParm->oldState.data );
  408. SnapshotObjectJob( curObjParm );
  409. // Advance past header + data
  410. curObjDest += totalSize;
  411. // Advance parm pointer
  412. curObjParm++;
  413. // Advance header pointer
  414. curHeader++;
  415. }
  416. /*
  417. ========================
  418. idSnapShot::SubmitLZWJob
  419. Take the current list of delta'd + zlre processed objects, and write them to the lzw stream.
  420. ========================
  421. */
  422. void idSnapShot::SubmitLZWJob(
  423. const submitDeltaJobsInfo_t & writeDeltaInfo,
  424. objParms_t *& baseObjParm, // Pointer to the first obj parm for the current stream
  425. objParms_t *& curObjParm, // Current obj parm
  426. lzwParm_t *& curlzwParm, // Current delta parm
  427. bool saveDictionary
  428. ) {
  429. int numObjects = curObjParm - baseObjParm;
  430. if ( numObjects == 0 ) {
  431. return; // Nothing to do
  432. }
  433. if ( curlzwParm - writeDeltaInfo.lzwParms >= writeDeltaInfo.maxDeltaParms ) {
  434. idLib::Error( "SubmitLZWJob: Not enough lzwParams.\n" );
  435. return; // Can't do anymore
  436. }
  437. curlzwParm->numObjects = numObjects;
  438. curlzwParm->headers = writeDeltaInfo.headers; // We always start grabbing from the beggining of the memory (it's reused, with fences to protect memory sharing)
  439. curlzwParm->curTime = this->GetTime();
  440. curlzwParm->baseTime = writeDeltaInfo.oldSnap->GetTime();
  441. curlzwParm->baseSequence = writeDeltaInfo.baseSequence;
  442. curlzwParm->fragmented = ( curlzwParm != writeDeltaInfo.lzwParms );
  443. curlzwParm->saveDictionary = saveDictionary;
  444. curlzwParm->ioData = writeDeltaInfo.lzwInOutData;
  445. LZWJob( curlzwParm );
  446. curlzwParm++;
  447. // Set base so it now points to where the parms start for the new stream
  448. baseObjParm = curObjParm;
  449. }
  450. /*
  451. ========================
  452. idSnapShot::GetTemplateState
  453. Helper function for getting template objectState.
  454. newState parameter is optional and is just used for debugging/printf comparison of the template and actual state
  455. ========================
  456. */
  457. idSnapShot::objectState_t * idSnapShot::GetTemplateState( int objNum, idSnapShot * templateStates, idSnapShot::objectState_t * newState /*=NULL*/ ) {
  458. objectState_t * oldState = NULL;
  459. int spawnedStateIndex = templateStates->FindObjectIndexByID( objNum );
  460. if ( spawnedStateIndex >= 0 ) {
  461. oldState = templateStates->objectStates[ spawnedStateIndex ];
  462. if ( net_ssTemplateDebug.GetBool() ) {
  463. idLib::Printf( "\nGetTemplateState[%d]\n", objNum );
  464. oldState->Print( "SPAWN STATE" );
  465. if ( newState != NULL ) {
  466. newState->Print( "CUR STATE" );
  467. }
  468. }
  469. }
  470. return oldState;
  471. }
  472. /*
  473. ========================
  474. idSnapShot::SubmitWriteDeltaToJobs
  475. ========================
  476. */
  477. void idSnapShot::SubmitWriteDeltaToJobs( const submitDeltaJobsInfo_t & submitDeltaJobInfo ) {
  478. objParms_t * curObjParms = submitDeltaJobInfo.objParms;
  479. objParms_t * baseObjParms = submitDeltaJobInfo.objParms;
  480. lzwParm_t * curlzwParms = submitDeltaJobInfo.lzwParms;
  481. objHeader_t * curHeader = submitDeltaJobInfo.headers;
  482. uint8 * curObjMemory = submitDeltaJobInfo.objMemory;
  483. submitDeltaJobInfo.lzwInOutData->numlzwDeltas = 0;
  484. submitDeltaJobInfo.lzwInOutData->lzwBytes = 0;
  485. submitDeltaJobInfo.lzwInOutData->fullSnap = false;
  486. int j = 0;
  487. int numOldStates = submitDeltaJobInfo.oldSnap->objectStates.Num();
  488. for ( int i = 0; i < objectStates.Num(); i++ ) {
  489. objectState_t & newState = *objectStates[i];
  490. if ( !verify( newState.buffer.Size() > 0 ) ) {
  491. // you CANNOT have a valid ss obj state w/ size = 0: this will be interpreted as a delete in ::ReadDelta and this will completely throw
  492. // off delta compression, eventually resulting in a checksum error that is a pain to track down.
  493. idLib::Warning( "Snap obj [%d] state.size <= 0... skipping ", newState.objectNum );
  494. continue;
  495. }
  496. if ( j >= numOldStates ) {
  497. // We no longer have old objects to compare to.
  498. // All objects are new from this point on.
  499. objectState_t * oldState = GetTemplateState( newState.objectNum, submitDeltaJobInfo.templateStates, &newState );
  500. SubmitObjectJob( submitDeltaJobInfo, &newState, oldState, baseObjParms, curObjParms, curHeader, curObjMemory, curlzwParms );
  501. continue;
  502. }
  503. // write any deleted entities up to this one
  504. for ( ; j < numOldStates && newState.objectNum > submitDeltaJobInfo.oldSnap->objectStates[j]->objectNum; j++ ) {
  505. objectState_t & oldState = *submitDeltaJobInfo.oldSnap->objectStates[j];
  506. if ( ( oldState.stale && !oldState.deleted ) || oldState.buffer.Size() <= 0 ) {
  507. continue; // Don't delete objects that are stale and not marked as deleted
  508. }
  509. SubmitObjectJob( submitDeltaJobInfo, NULL, &oldState, baseObjParms, curObjParms, curHeader, curObjMemory, curlzwParms );
  510. }
  511. if ( j >= numOldStates ) {
  512. continue; // Went past end of old list deleting objects
  513. }
  514. // Beyond this point, we may have old state to compare against
  515. objectState_t & submittedOldState = *submitDeltaJobInfo.oldSnap->objectStates[j];
  516. objectState_t * oldState = &submittedOldState;
  517. if ( newState.objectNum == oldState->objectNum ) {
  518. if ( oldState->buffer.Size() == 0 ) {
  519. // New state (even though snapObj existed, its size was zero)
  520. oldState = GetTemplateState( newState.objectNum, submitDeltaJobInfo.templateStates, &newState );
  521. }
  522. SubmitObjectJob( submitDeltaJobInfo, &newState, oldState, baseObjParms, curObjParms, curHeader, curObjMemory, curlzwParms );
  523. j++;
  524. } else {
  525. // Different object, this one is new,
  526. // Spawned
  527. oldState = GetTemplateState( newState.objectNum, submitDeltaJobInfo.templateStates, &newState );
  528. SubmitObjectJob( submitDeltaJobInfo, &newState, oldState, baseObjParms, curObjParms, curHeader, curObjMemory, curlzwParms );
  529. }
  530. }
  531. // Finally, remove any entities at the end
  532. for ( ; j < submitDeltaJobInfo.oldSnap->objectStates.Num(); j++ ) {
  533. objectState_t & oldState = *submitDeltaJobInfo.oldSnap->objectStates[j];
  534. if ( ( oldState.stale && !oldState.deleted ) || oldState.buffer.Size() <= 0 ) {
  535. continue; // Don't delete objects that are stale and not marked as deleted
  536. }
  537. SubmitObjectJob( submitDeltaJobInfo, NULL, &oldState, baseObjParms, curObjParms, curHeader, curObjMemory, curlzwParms );
  538. }
  539. // Submit any objects that are left over (will be all if they all fit up to this point)
  540. SubmitLZWJob( submitDeltaJobInfo, baseObjParms, curObjParms, curlzwParms, false );
  541. }
  542. /*
  543. ========================
  544. idSnapShot::ReadDelta
  545. ========================
  546. */
  547. bool idSnapShot::ReadDelta( idFile * file, int visIndex ) {
  548. file->ReadBig( time );
  549. int objectNum = 0;
  550. uint16 delta = 0;
  551. while ( file->ReadBig( delta ) == sizeof( delta ) ) {
  552. objectNum += delta;
  553. if ( objectNum >= 0xFFFF ) {
  554. // full delta
  555. return true;
  556. }
  557. objectState_t & state = FindOrCreateObjectByID( objectNum );
  558. objectSize_t newsize = 0;
  559. file->ReadBig( newsize );
  560. if ( newsize == SIZE_STALE ) {
  561. NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d goes stale\n", objectNum );
  562. // sanity
  563. bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0;
  564. if ( !oldVisible ) {
  565. NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected already stale\n" );
  566. }
  567. state.visMask &= ~( 1 << visIndex );
  568. state.stale = true;
  569. // We need to make sure we haven't freed stale objects.
  570. assert( state.buffer.Size() > 0 );
  571. // no more data
  572. continue;
  573. } else if ( newsize == SIZE_NOT_STALE ) {
  574. NET_VERBOSESNAPSHOT_PRINT( "read delta: object %d no longer stale\n", objectNum );
  575. // sanity
  576. bool oldVisible = ( state.visMask & ( 1 << visIndex ) ) != 0;
  577. if ( oldVisible ) {
  578. NET_VERBOSESNAPSHOT_PRINT( "ERROR: unexpected not stale\n" );
  579. }
  580. state.visMask |= ( 1 << visIndex );
  581. state.stale = false;
  582. // the latest state is packed in, get the new size and continue reading the new state
  583. file->ReadBig( newsize );
  584. }
  585. if ( newsize == 0 ) {
  586. // object deleted
  587. state.buffer._Release();
  588. } else {
  589. objectBuffer_t newbuffer( newsize );
  590. objectSize_t compareSize = Min( newsize, state.buffer.Size() );
  591. for ( objectSize_t i = 0; i < compareSize; i++ ) {
  592. uint8 delta = 0;
  593. file->ReadBig<byte>( delta );
  594. newbuffer[i] = state.buffer[i] + delta;
  595. }
  596. if ( newsize > compareSize ) {
  597. file->Read( newbuffer.Ptr() + compareSize, newsize - compareSize );
  598. }
  599. state.buffer = newbuffer;
  600. state.changedCount++;
  601. }
  602. #ifdef SNAPSHOT_CHECKSUMS
  603. if ( state.buffer.Size() > 0 ) {
  604. unsigned int checksum = 0;
  605. file->ReadBig( checksum );
  606. assert( checksum == MD5_BlockChecksum( state.buffer.Ptr(), state.buffer.Size() ) );
  607. }
  608. #endif
  609. }
  610. // partial delta
  611. return false;
  612. }
  613. /*
  614. ========================
  615. idSnapShot::WriteObject
  616. ========================
  617. */
  618. void idSnapShot::WriteObject( idFile * file, int visIndex, objectState_t * newState, objectState_t * oldState, int & lastobjectNum ) {
  619. assert( newState != NULL || oldState != NULL );
  620. bool visChange = false; // visibility changes will be signified with a 0xffff state size
  621. bool visSendState = false; // the state is sent when an entity is no longer stale
  622. // Compute visibility changes
  623. // (we need to do this before writing out object id, because we may not need to write out the id if we early out)
  624. // (when we don't write out the id, we assume this is an "ack" when we deserialize the objects)
  625. if ( newState != NULL && oldState != NULL ) {
  626. // Check visibility
  627. assert( newState->objectNum == oldState->objectNum );
  628. if ( visIndex > 0 ) {
  629. bool oldVisible = ( oldState->visMask & ( 1 << visIndex ) ) != 0;
  630. bool newVisible = ( newState->visMask & ( 1 << visIndex ) ) != 0;
  631. // Force visible if we need to either create or destroy this object
  632. newVisible |= ( newState->buffer.Size() == 0 ) != ( oldState->buffer.Size() == 0 );
  633. if ( !oldVisible && !newVisible ) {
  634. // object is stale and ack'ed for this client, write nothing (see 'same object' below)
  635. return;
  636. } else if ( oldVisible && !newVisible ) {
  637. NET_VERBOSESNAPSHOT_PRINT( "object %d to client %d goes stale\n", newState->objectNum, visIndex );
  638. visChange = true;
  639. visSendState = false;
  640. } else if ( !oldVisible && newVisible ) {
  641. NET_VERBOSESNAPSHOT_PRINT( "object %d to client %d no longer stale\n", newState->objectNum, visIndex );
  642. visChange = true;
  643. visSendState = true;
  644. }
  645. }
  646. // Same object, write a delta (never early out during vis changes)
  647. if ( !visChange && newState->buffer.Size() == oldState->buffer.Size() &&
  648. ( ( newState->buffer.Ptr() == oldState->buffer.Ptr() ) || memcmp( newState->buffer.Ptr(), oldState->buffer.Ptr(), newState->buffer.Size() ) == 0 ) ) {
  649. // same state, write nothing
  650. return;
  651. }
  652. }
  653. // Get the id of the object we are writing out
  654. uint16 objectNum;
  655. if ( newState != NULL ) {
  656. objectNum = newState->objectNum;
  657. } else if ( oldState != NULL ) {
  658. objectNum = oldState->objectNum;
  659. } else {
  660. objectNum = 0;
  661. }
  662. assert( objectNum == 0 || objectNum > lastobjectNum );
  663. // Write out object id (using delta)
  664. uint16 objectDelta = objectNum - lastobjectNum;
  665. file->WriteBig( objectDelta );
  666. lastobjectNum = objectNum;
  667. if ( newState == NULL ) {
  668. // Deleted, write 0 size
  669. assert( oldState != NULL );
  670. file->WriteBig<objectSize_t>( 0 );
  671. } else if ( oldState == NULL ) {
  672. // New object, write out full state
  673. assert( newState != NULL );
  674. // delta against an empty snap
  675. file->WriteBig( newState->buffer.Size() );
  676. file->Write( newState->buffer.Ptr(), newState->buffer.Size() );
  677. } else {
  678. // Compare to last object
  679. assert( newState != NULL && oldState != NULL );
  680. assert( newState->objectNum == oldState->objectNum );
  681. if ( visChange ) {
  682. // fake size indicates vis state change
  683. // NOTE: we may still send a real size and a state below, for 'no longer stale' transitions
  684. // TMP: send 0xFFFF for going stale and 0xFFFF - 1 for no longer stale
  685. file->WriteBig<objectSize_t>( visSendState ? SIZE_NOT_STALE : SIZE_STALE );
  686. }
  687. if ( !visChange || visSendState ) {
  688. objectSize_t compareSize = Min( newState->buffer.Size(), oldState->buffer.Size() ); // Get the number of bytes that overlap
  689. file->WriteBig( newState->buffer.Size() ); // Write new size
  690. // Compare bytes that overlap
  691. for ( objectSize_t b = 0; b < compareSize; b++ ) {
  692. file->WriteBig<byte>( ( 0xFF + 1 + newState->buffer[b] - oldState->buffer[b] ) & 0xFF );
  693. }
  694. // Write leftover
  695. if ( newState->buffer.Size() > compareSize ) {
  696. file->Write( newState->buffer.Ptr() + oldState->buffer.Size(), newState->buffer.Size() - compareSize );
  697. }
  698. }
  699. }
  700. #ifdef SNAPSHOT_CHECKSUMS
  701. if ( ( !visChange || visSendState ) && newState != NULL ) {
  702. assert( newState->buffer.Size() > 0 );
  703. unsigned int checksum = MD5_BlockChecksum( newState->buffer.Ptr(), newState->buffer.Size() );
  704. file->WriteBig( checksum );
  705. }
  706. #endif
  707. }
  708. /*
  709. ========================
  710. idSnapShot::PrintReport
  711. ========================
  712. */
  713. void idSnapShot::PrintReport() {
  714. }
  715. /*
  716. ========================
  717. idSnapShot::WriteDelta
  718. ========================
  719. */
  720. bool idSnapShot::WriteDelta( idSnapShot & old, int visIndex, idFile * file, int maxLength, int optimalLength ) {
  721. file->WriteBig( time );
  722. int objectHeaderSize = sizeof( uint16 ) + sizeof( objectSize_t );
  723. #ifdef SNAPSHOT_CHECKSUMS
  724. objectHeaderSize += sizeof( unsigned int );
  725. #endif
  726. int lastobjectNum = 0;
  727. int j = 0;
  728. for ( int i = 0; i < objectStates.Num(); i++ ) {
  729. objectState_t & newState = *objectStates[i];
  730. if ( optimalLength > 0 && file->Length() >= optimalLength ) {
  731. return false;
  732. }
  733. if ( !verify( newState.buffer.Size() < maxLength ) ) {
  734. // If the new state's size is > the max packet size, we'll never be able to send it!
  735. idLib::Warning( "Snap obj [%d] state.size > max packet length. Skipping... ", newState.objectNum );
  736. continue;
  737. } else if ( !verify( newState.buffer.Size() > 0 ) ) {
  738. // you CANNOT have a valid ss obj state w/ size = 0: this will be interpreted as a delete in ::ReadDelta and this will completely throw
  739. // off delta compression, eventually resulting in a checksum error that is a pain to track down.
  740. idLib::Warning( "Snap obj [%d] state.size <= 0... skipping ", newState.objectNum );
  741. continue;
  742. }
  743. if ( file->Length() + objectHeaderSize + newState.buffer.Size() >= maxLength ) {
  744. return false;
  745. }
  746. if ( j >= old.objectStates.Num() ) {
  747. // delta against an empty snap
  748. WriteObject( file, visIndex, &newState, NULL, lastobjectNum );
  749. continue;
  750. }
  751. // write any deleted entities up to this one
  752. for ( ; newState.objectNum > old.objectStates[j]->objectNum; j++ ) {
  753. if ( file->Length() + objectHeaderSize >= maxLength ) {
  754. return false;
  755. }
  756. objectState_t & oldState = *old.objectStates[j];
  757. WriteObject( file, visIndex, NULL, &oldState, lastobjectNum );
  758. }
  759. // Beyond this point, we have old state to compare against
  760. objectState_t & oldState = *old.objectStates[j];
  761. if ( newState.objectNum == oldState.objectNum ) {
  762. // FIXME: We don't need to early out if WriteObject determines that we won't send the object due to being stale
  763. if ( file->Length() + objectHeaderSize + newState.buffer.Size() >= maxLength ) {
  764. return false;
  765. }
  766. WriteObject( file, visIndex, &newState, &oldState, lastobjectNum );
  767. j++;
  768. } else {
  769. if ( file->Length() + objectHeaderSize + newState.buffer.Size() >= maxLength ) {
  770. return false;
  771. }
  772. // Different object, this one is new, write the full state
  773. WriteObject( file, visIndex, &newState, NULL, lastobjectNum );
  774. }
  775. }
  776. // Finally, remove any entities at the end
  777. for ( ; j < old.objectStates.Num(); j++ ) {
  778. if ( file->Length() + objectHeaderSize >= maxLength ) {
  779. return false;
  780. }
  781. if ( optimalLength > 0 && file->Length() >= optimalLength ) {
  782. return false;
  783. }
  784. objectState_t & oldState = *old.objectStates[j];
  785. WriteObject( file, visIndex, NULL, &oldState, lastobjectNum );
  786. }
  787. if ( file->Length() + 2 >= maxLength ) {
  788. return false;
  789. }
  790. uint16 objectDelta = 0xFFFF - lastobjectNum;
  791. file->WriteBig( objectDelta );
  792. return true;
  793. }
  794. /*
  795. ========================
  796. idSnapShot::AddObject
  797. ========================
  798. */
  799. idSnapShot::objectState_t * idSnapShot::S_AddObject( int objectNum, uint32 visMask, const char * data, int _size, const char * tag ) {
  800. objectSize_t size = _size;
  801. objectState_t & state = FindOrCreateObjectByID( objectNum );
  802. state.visMask = visMask;
  803. if ( state.buffer.Size() == size && state.buffer.NumRefs() == 1 ) {
  804. // re-use the same buffer
  805. memcpy( state.buffer.Ptr(), data, size );
  806. } else {
  807. objectBuffer_t buffer( size );
  808. memcpy( buffer.Ptr(), data, size );
  809. state.buffer = buffer;
  810. }
  811. return &state;
  812. }
  813. /*
  814. ========================
  815. idSnapShot::CopyObject
  816. ========================
  817. */
  818. bool idSnapShot::CopyObject( const idSnapShot & oldss, int objectNum, bool forceStale ) {
  819. int oldIndex = oldss.FindObjectIndexByID( objectNum );
  820. if ( oldIndex == -1 ) {
  821. return false;
  822. }
  823. const objectState_t & oldState = *oldss.objectStates[oldIndex];
  824. objectState_t & newState = FindOrCreateObjectByID( objectNum );
  825. newState.buffer = oldState.buffer;
  826. newState.visMask = oldState.visMask;
  827. newState.stale = oldState.stale;
  828. newState.deleted = oldState.deleted;
  829. newState.changedCount = oldState.changedCount;
  830. newState.expectedSequence = oldState.expectedSequence;
  831. newState.createdFromTemplate = oldState.createdFromTemplate;
  832. if ( forceStale ) {
  833. newState.visMask = 0;
  834. }
  835. return true;
  836. }
  837. /*
  838. ========================
  839. idSnapShot::CompareObject
  840. start, end, and oldStart can optionally be passed in to compare subsections of the object
  841. default parameters will compare entire object
  842. ========================
  843. */
  844. int idSnapShot::CompareObject( const idSnapShot * oldss, int objectNum, int start, int end, int oldStart ) {
  845. if ( oldss == NULL ) {
  846. return 0;
  847. }
  848. assert( FindObjectIndexByID( objectNum ) >= 0 );
  849. objectState_t & newState = FindOrCreateObjectByID( objectNum );
  850. int oldIndex = oldss->FindObjectIndexByID( objectNum );
  851. if ( oldIndex == -1 ) {
  852. return ( end == 0 ? newState.buffer.Size() : end - start ); // Didn't exist in the old state, so we take the hit on the entire size
  853. }
  854. objectState_t & oldState = const_cast< objectState_t & >( *oldss->objectStates[oldIndex] );
  855. int bytes = 0;
  856. int oldOffset = oldStart - start;
  857. int commonSize = ( newState.buffer.Size() <= oldState.buffer.Size() - oldOffset ) ? newState.buffer.Size() : oldState.buffer.Size() - oldOffset;
  858. if ( end == 0 ) {
  859. // default 0 means compare the whole thing
  860. end = commonSize;
  861. // Get leftover (if any)
  862. bytes = ( newState.buffer.Size() > oldState.buffer.Size() ) ? ( newState.buffer.Size() - oldState.buffer.Size() ) : 0;
  863. } else {
  864. // else only compare up to end or the max buffer and dont include leftover
  865. end = Min( commonSize, end );
  866. }
  867. for ( int b = start; b < end; b++ ) {
  868. if ( verify( b >= 0 && b < (int)newState.buffer.Size() && b + oldOffset >= 0 && b + oldOffset < (int)oldState.buffer.Size() ) ) {
  869. bytes += ( newState.buffer[b] != oldState.buffer[b + oldOffset] ) ? 1 : 0;
  870. }
  871. }
  872. return bytes;
  873. }
  874. /*
  875. ========================
  876. idSnapShot::GetObjectMsgByIndex
  877. ========================
  878. */
  879. int idSnapShot::GetObjectMsgByIndex( int i, idBitMsg & msg, bool ignoreIfStale ) const {
  880. if ( i < 0 || i >= objectStates.Num() ) {
  881. return -1;
  882. }
  883. objectState_t & state = *objectStates[i];
  884. if ( state.stale && ignoreIfStale ) {
  885. return -1;
  886. }
  887. msg.InitRead( state.buffer.Ptr(), state.buffer.Size() );
  888. return state.objectNum;
  889. }
  890. /*
  891. ========================
  892. idSnapShot::ObjectIsStaleByIndex
  893. ========================
  894. */
  895. bool idSnapShot::ObjectIsStaleByIndex( int i ) const {
  896. if ( i < 0 || i >= objectStates.Num() ) {
  897. return false;
  898. }
  899. return objectStates[i]->stale;
  900. }
  901. /*
  902. ========================
  903. idSnapShot::ObjectChangedCountByIndex
  904. ========================
  905. */
  906. int idSnapShot::ObjectChangedCountByIndex( int i ) const {
  907. if ( i < 0 || i >= objectStates.Num() ) {
  908. return false;
  909. }
  910. return objectStates[i]->changedCount;
  911. }
  912. /*
  913. ========================
  914. idSnapShot::FindObjectIndexByID
  915. ========================
  916. */
  917. int idSnapShot::FindObjectIndexByID( int objectNum ) const {
  918. int i = BinarySearch( objectNum );
  919. if ( i >= 0 && i < objectStates.Num() && objectStates[i]->objectNum == objectNum ) {
  920. return i;
  921. }
  922. return -1;
  923. }
  924. /*
  925. ========================
  926. idSnapShot::BinarySearch
  927. ========================
  928. */
  929. int idSnapShot::BinarySearch( int objectNum ) const {
  930. int lo = 0;
  931. int hi = objectStates.Num();
  932. while ( hi != lo ) {
  933. int mid = ( hi + lo ) >> 1;
  934. if ( objectStates[mid]->objectNum == objectNum ) {
  935. return mid; // Early out if we can
  936. }
  937. if ( objectStates[mid]->objectNum < objectNum ) {
  938. lo = mid + 1;
  939. } else {
  940. hi = mid;
  941. }
  942. }
  943. return hi;
  944. }
  945. /*
  946. ========================
  947. idSnapShot::FindOrCreateObjectByID
  948. ========================
  949. */
  950. idSnapShot::objectState_t & idSnapShot::FindOrCreateObjectByID( int objectNum ) {
  951. //assert( mem.IsMapHeap() );
  952. int i = BinarySearch( objectNum );
  953. if ( i >= 0 && i < objectStates.Num() && objectStates[i]->objectNum == objectNum ) {
  954. return *objectStates[i];
  955. }
  956. objectState_t * newstate = allocatedObjs.Alloc();
  957. newstate->objectNum = objectNum;
  958. objectStates.Insert( newstate, i );
  959. return *objectStates[i];
  960. }
  961. /*
  962. ========================
  963. idSnapShot::FindObjectByID
  964. ========================
  965. */
  966. idSnapShot::objectState_t * idSnapShot::FindObjectByID( int objectNum ) const {
  967. //assert( mem.IsMapHeap() );
  968. int i = BinarySearch( objectNum );
  969. if ( i >= 0 && i < objectStates.Num() && objectStates[i]->objectNum == objectNum ) {
  970. return objectStates[i];
  971. }
  972. return NULL;
  973. }
  974. /*
  975. ========================
  976. idSnapShot::CleanupEmptyStates
  977. ========================
  978. */
  979. void idSnapShot::CleanupEmptyStates() {
  980. for ( int i = objectStates.Num() - 1; i >= 0 ; i-- ) {
  981. if ( objectStates[i]->buffer.Size() == 0 ) {
  982. FreeObjectState( i );
  983. objectStates.RemoveIndex(i);
  984. }
  985. }
  986. }
  987. /*
  988. ========================
  989. idSnapShot::UpdateExpectedSeq
  990. ========================
  991. */
  992. void idSnapShot::UpdateExpectedSeq( int newSeq ) {
  993. for ( int i = 0; i < objectStates.Num(); i++ ) {
  994. if ( objectStates[i]->expectedSequence == -2 ) {
  995. objectStates[i]->expectedSequence = newSeq;
  996. }
  997. }
  998. }
  999. /*
  1000. ========================
  1001. idSnapShot::FreeObjectState
  1002. ========================
  1003. */
  1004. void idSnapShot::FreeObjectState( int index ) {
  1005. assert( objectStates[index] != NULL );
  1006. //assert( mem.IsMapHeap() );
  1007. objectStates[index]->buffer._Release();
  1008. allocatedObjs.Free( objectStates[index] );
  1009. objectStates[index] = NULL;
  1010. }
  1011. /*
  1012. ========================
  1013. idSnapShot::ApplyToExistingState
  1014. Take uncompressed state in msg and add it to existing state
  1015. ========================
  1016. */
  1017. void idSnapShot::ApplyToExistingState( int objId, idBitMsg & msg ) {
  1018. objectState_t * objectState = FindObjectByID( objId );
  1019. if ( !verify( objectState != NULL ) ) {
  1020. return;
  1021. }
  1022. if ( !objectState->createdFromTemplate ) {
  1023. // We were created this from a template, so we shouldn't be applying it again
  1024. if ( net_ssTemplateDebug.GetBool() ) {
  1025. idLib::Printf( "NOT ApplyToExistingState[%d] because object was created from existing base state. %d\n", objId, objectState->expectedSequence );
  1026. objectState->Print( "SS STATE" );
  1027. }
  1028. return;
  1029. }
  1030. // Debug print the template (spawn) and delta state
  1031. if ( net_ssTemplateDebug.GetBool() ) {
  1032. idLib::Printf( "\nApplyToExistingState[%d]. buffer size: %d msg size: %d\n", objId, objectState->buffer.Size(), msg.GetSize() );
  1033. objectState->Print( "DELTA STATE" );
  1034. PrintAlign( "SPAWN STATE" );
  1035. for ( int i = 0; i < msg.GetSize(); i++ ) {
  1036. if ( InDebugRange( i ) ) {
  1037. idLib::Printf( "%02X", msg.GetReadData()[i] );
  1038. }
  1039. }
  1040. idLib::Printf( "\n" );
  1041. }
  1042. // Actually apply it
  1043. for ( objectSize_t i = 0; i < Min( objectState->buffer.Size(), msg.GetSize() ); i++ ) {
  1044. objectState->buffer[i] += msg.GetReadData()[i];
  1045. }
  1046. // Debug print the final state
  1047. if ( net_ssTemplateDebug.GetBool() ) {
  1048. objectState->Print( "NEW STATE" );
  1049. idLib::Printf( "\n" );
  1050. }
  1051. }
  1052. #if 0
  1053. CONSOLE_COMMAND( serializeQTest, "Serialization Sanity Test", 0 ) {
  1054. byte buffer[1024];
  1055. memset( buffer, 0, sizeof( buffer ) );
  1056. float values[] = { 0.0001f, 0.001f, 0.01f, 0.1f, 0.2f, 0.3f, 0.4f, 0.5f, 0.6f, 0.7f, 0.8f, 0.9f, 0.999f,
  1057. 1.0f, 1.01f, 1.1f, 10.0f, 10.1f, 10.101f, 100.0f, 101.0f, 101.1f, 101.101f };
  1058. int num = sizeof(values) / sizeof(float);
  1059. idLib::Printf("\n^3Testing SerializeQ and SerializeUQ \n");
  1060. {
  1061. idBitMsg writeBitMsg;
  1062. writeBitMsg.InitWrite( buffer, sizeof(buffer) );
  1063. idSerializer writeSerializer( writeBitMsg, true );
  1064. for( int i = 0; i < num; i++ ) {
  1065. writeSerializer.SerializeUQ( values[i], 255.0f, 16 );
  1066. writeSerializer.SerializeQ( values[i], 128.0f, 16 );
  1067. }
  1068. }
  1069. {
  1070. idBitMsg readBitMsg;
  1071. readBitMsg.InitRead( buffer, sizeof( buffer ) );
  1072. idSerializer readSerializer( readBitMsg, false );
  1073. for( int i = 0; i < num; i++ ) {
  1074. float resultUQ = -999.0f;
  1075. float resultQ = -999.0f;
  1076. readSerializer.SerializeUQ( resultUQ, 255.0f, 16 );
  1077. readSerializer.SerializeQ( resultQ, 128.0f, 16 );
  1078. float errorUQ = idMath::Fabs( (resultUQ - values[i]) ) / values[i];
  1079. float errorQ = idMath::Fabs( (resultQ - values[i]) ) / values[i];
  1080. idLib::Printf( "%s%f SerializeUQ: %f. Error: %f \n", errorUQ > 0.1f ? "^1": "", values[i], resultUQ, errorUQ );
  1081. idLib::Printf( "%s%f SerializeQ: %f. Error: %f \n", errorQ > 0.1f ? "^1": "", values[i], resultQ, errorQ );
  1082. }
  1083. }
  1084. }
  1085. #endif