Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
13 KiB

  1. //========= Copyright � 1996-2007, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "blob_networkbypass.h"
  9. #include "ispsharedmemory.h"
  10. #ifndef CLIENT_DLL
  11. #include "npc_surface.h"
  12. #endif
  13. #include "tier0/memdbgon.h"
  14. BlobNetworkBypass_t *g_pBlobNetworkBypass;
  15. #ifdef CLIENT_DLL
  16. CInterpolatedVar< Vector > s_PositionInterpolators[BLOB_MAX_LEVEL_PARTICLES];
  17. CInterpolatedVar< float > s_RadiusInterpolators[BLOB_MAX_LEVEL_PARTICLES];
  18. CInterpolatedVar< Vector > s_ClosestSurfDirInterpolators[BLOB_MAX_LEVEL_PARTICLES];
  19. BlobParticleInterpolation_t g_BlobParticleInterpolation;
  20. void BlobNetworkBypass_CustomDemoDataCallback( uint8 *pData, size_t iSize );
  21. #endif
  22. class CBlobParticleNetworkBypassAutoGame : public CAutoGameSystemPerFrame
  23. {
  24. public:
  25. virtual bool Init()
  26. {
  27. m_pSharedMemory = engine->GetSinglePlayerSharedMemorySpace( "BlobParticleNetworkBypass" );
  28. m_pSharedMemory->Init( sizeof( BlobNetworkBypass_t ) );
  29. g_pBlobNetworkBypass = (BlobNetworkBypass_t *)m_pSharedMemory->Base();
  30. #ifdef CLIENT_DLL
  31. float fInterpAmount = TICK_INTERVAL * (C_BaseEntity::IsSimulatingOnAlternateTicks()?2:1);
  32. for( int i = 0; i != BLOB_MAX_LEVEL_PARTICLES; ++i )
  33. {
  34. s_PositionInterpolators[i].Setup( &g_BlobParticleInterpolation.vInterpolatedPositions[i], LATCH_ANIMATION_VAR ); //LATCH_SIMULATION_VAR, LATCH_ANIMATION_VAR
  35. s_PositionInterpolators[i].SetInterpolationAmount( fInterpAmount ); //fInterpAmount
  36. s_RadiusInterpolators[i].Setup( &g_BlobParticleInterpolation.vInterpolatedRadii[i], LATCH_ANIMATION_VAR ); //LATCH_SIMULATION_VAR, LATCH_ANIMATION_VAR
  37. s_RadiusInterpolators[i].SetInterpolationAmount( fInterpAmount ); //fInterpAmount
  38. s_ClosestSurfDirInterpolators[i].Setup( &g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[i], LATCH_ANIMATION_VAR ); //LATCH_SIMULATION_VAR, LATCH_ANIMATION_VAR
  39. s_ClosestSurfDirInterpolators[i].SetInterpolationAmount( fInterpAmount ); //fInterpAmount
  40. }
  41. m_iOldHighestIndexUsed = 0;
  42. memset( &m_bOldInUse, 0, sizeof( m_bOldInUse ) );
  43. engine->RegisterDemoCustomDataCallback( MAKE_STRING( "BlobNetworkBypass_CustomDemoDataCallback" ), BlobNetworkBypass_CustomDemoDataCallback );
  44. #endif
  45. return true;
  46. }
  47. virtual void Shutdown()
  48. {
  49. m_pSharedMemory->Release();
  50. m_pSharedMemory = NULL;
  51. g_pBlobNetworkBypass = NULL;
  52. }
  53. #ifdef CLIENT_DLL
  54. virtual void PreRender( void );
  55. unsigned int m_iOldHighestIndexUsed;
  56. CBitVec<BLOB_MAX_LEVEL_PARTICLES> m_bOldInUse;
  57. #else
  58. virtual void PreClientUpdate()
  59. {
  60. CNPC_Surface::UpdateBypassParticleData();
  61. }
  62. #endif
  63. ISPSharedMemory *m_pSharedMemory;
  64. };
  65. static CBlobParticleNetworkBypassAutoGame s_CBPNBAG;
  66. #ifndef CLIENT_DLL
  67. int AllocateBlobNetworkBypassIndex( void )
  68. {
  69. int retval;
  70. if( g_pBlobNetworkBypass->iNumParticlesAllocated == g_pBlobNetworkBypass->iHighestIndexUsed )
  71. {
  72. //no holes in the allocations, allocate from the end
  73. retval = g_pBlobNetworkBypass->iHighestIndexUsed;
  74. ++g_pBlobNetworkBypass->iHighestIndexUsed;
  75. }
  76. else
  77. {
  78. CBitVec<BLOB_MAX_LEVEL_PARTICLES> notUsed;
  79. g_pBlobNetworkBypass->bCurrentlyInUse.Not( &notUsed );
  80. retval = notUsed.FindNextSetBit( 0 );
  81. Assert( retval < (int)g_pBlobNetworkBypass->iHighestIndexUsed );
  82. }
  83. ++g_pBlobNetworkBypass->iNumParticlesAllocated;
  84. g_pBlobNetworkBypass->bCurrentlyInUse.Set( retval );
  85. return retval;
  86. }
  87. void ReleaseBlobNetworkBypassIndex( int iIndex )
  88. {
  89. Assert( g_pBlobNetworkBypass->bCurrentlyInUse.IsBitSet( iIndex ) );
  90. g_pBlobNetworkBypass->bCurrentlyInUse.Clear( iIndex );
  91. g_pBlobNetworkBypass->vParticlePositions[iIndex] = vec3_origin;
  92. g_pBlobNetworkBypass->vParticleRadii[iIndex] = 1.0f;
  93. g_pBlobNetworkBypass->vParticleClosestSurfDir[iIndex] = vec3_origin;
  94. --g_pBlobNetworkBypass->iNumParticlesAllocated;
  95. Assert( iIndex < (int)g_pBlobNetworkBypass->iHighestIndexUsed );
  96. if( iIndex == ((int)g_pBlobNetworkBypass->iHighestIndexUsed - 1) )
  97. {
  98. //search for newest high index
  99. int iOldHighestIntUsed = g_pBlobNetworkBypass->iHighestIndexUsed / BITS_PER_INT;
  100. for( int i = iOldHighestIntUsed; i >= 0; --i )
  101. {
  102. if( (g_pBlobNetworkBypass->bCurrentlyInUse.GetDWord( i ) & (-1)) != 0 )
  103. {
  104. int iLowBit = i * BITS_PER_INT;
  105. int iHighBit = iLowBit + BITS_PER_INT;
  106. for( int j = iHighBit; --j >= iLowBit; )
  107. {
  108. if( g_pBlobNetworkBypass->bCurrentlyInUse.IsBitSet( j ) )
  109. {
  110. g_pBlobNetworkBypass->iHighestIndexUsed = (uint32)j + 1;
  111. break;
  112. }
  113. }
  114. break;
  115. }
  116. }
  117. }
  118. Assert( g_pBlobNetworkBypass->iHighestIndexUsed >= g_pBlobNetworkBypass->iNumParticlesAllocated );
  119. }
  120. #else
  121. void CBlobParticleNetworkBypassAutoGame::PreRender( void )
  122. {
  123. if( engine->IsRecordingDemo() && g_pBlobNetworkBypass->bDataUpdated )
  124. {
  125. //record the update, TODO: compress the data by omitting the holes
  126. int iMaxIndex = MAX(g_pBlobNetworkBypass->iHighestIndexUsed, m_iOldHighestIndexUsed);
  127. int iBitMax = (iMaxIndex / BITS_PER_INT) + 1;
  128. size_t iDataSize = sizeof( int ) + sizeof( float ) + sizeof( int ) + sizeof( int ) + (sizeof( int ) * iBitMax) +
  129. iMaxIndex*( sizeof( Vector ) + sizeof( float ) + sizeof( Vector ) );
  130. uint8 *pData = new uint8 [iDataSize];
  131. uint8 *pWrite = pData;
  132. //let the receiver know how much of each array to expect
  133. *(int *)pWrite = LittleDWord( iMaxIndex );
  134. pWrite += sizeof( int );
  135. //write the update timestamp
  136. *(float *)pWrite = g_pBlobNetworkBypass->fTimeDataUpdated;
  137. pWrite += sizeof( float );
  138. //record usage information, also helps us effectively compress the subsequent data by omitting the holes.
  139. *(int *)pWrite = LittleDWord( g_pBlobNetworkBypass->iHighestIndexUsed );
  140. pWrite += sizeof( int );
  141. *(int *)pWrite = LittleDWord( g_pBlobNetworkBypass->iNumParticlesAllocated );
  142. pWrite += sizeof( int );
  143. int *pIntParser = (int *)&g_pBlobNetworkBypass->bCurrentlyInUse;
  144. for( int i = 0; i != iBitMax; ++i )
  145. {
  146. //convert and write the bitfield integers
  147. *(int *)pWrite = LittleDWord( *pIntParser );
  148. pWrite += sizeof( int );
  149. ++pIntParser;
  150. }
  151. //write positions
  152. memcpy( pWrite, g_pBlobNetworkBypass->vParticlePositions, sizeof( Vector ) * iMaxIndex );
  153. pWrite += sizeof( Vector ) * iMaxIndex;
  154. //write radii
  155. memcpy( pWrite, g_pBlobNetworkBypass->vParticleRadii, sizeof( float ) * iMaxIndex );
  156. pWrite += sizeof( float ) * iMaxIndex;
  157. //write closest surface direction
  158. memcpy( pWrite, g_pBlobNetworkBypass->vParticleClosestSurfDir, sizeof( Vector ) * iMaxIndex );
  159. pWrite += sizeof( Vector ) * iMaxIndex;
  160. engine->RecordDemoCustomData( BlobNetworkBypass_CustomDemoDataCallback, pData, iDataSize );
  161. Assert( pWrite == (pData + iDataSize) );
  162. delete []pData;
  163. }
  164. //invalidate interpolation on freed indices, do a quick update for brand new indices
  165. {
  166. //operate on smaller chunks based on the assumption that LARGE portions of the end of the bitvecs are empty
  167. CBitVec<BITS_PER_INT> *pCurrentlyInUse = (CBitVec<BITS_PER_INT> *)&g_pBlobNetworkBypass->bCurrentlyInUse;
  168. CBitVec<BITS_PER_INT> *pOldInUse = (CBitVec<BITS_PER_INT> *)&m_bOldInUse;
  169. int iStop = (MAX(g_pBlobNetworkBypass->iHighestIndexUsed, m_iOldHighestIndexUsed) / BITS_PER_INT) + 1;
  170. int iBaseIndex = 0;
  171. //float fNewIndicesUpdateTime = g_pBlobNetworkBypass->bPositionsUpdated ? g_pBlobNetworkBypass->fTimeDataUpdated : gpGlobals->curtime;
  172. for( int i = 0; i != iStop; ++i )
  173. {
  174. CBitVec<BITS_PER_INT> bInUseXOR;
  175. pCurrentlyInUse->Xor( *pOldInUse, &bInUseXOR ); //find bits that changed
  176. int j = 0;
  177. while( (j = bInUseXOR.FindNextSetBit( j )) != -1 )
  178. {
  179. int iChangedUsageIndex = iBaseIndex + j;
  180. if( pOldInUse->IsBitSet( iChangedUsageIndex ) )
  181. {
  182. //index no longer used
  183. g_BlobParticleInterpolation.vInterpolatedPositions[iChangedUsageIndex] = vec3_origin;
  184. s_PositionInterpolators[iChangedUsageIndex].ClearHistory();
  185. g_BlobParticleInterpolation.vInterpolatedRadii[iChangedUsageIndex] = 1.0f;
  186. s_RadiusInterpolators[iChangedUsageIndex].ClearHistory();
  187. g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[iChangedUsageIndex] = vec3_origin;
  188. s_ClosestSurfDirInterpolators[iChangedUsageIndex].ClearHistory();
  189. }
  190. else
  191. {
  192. //index just started being used. Assume we got an out of band update to the position
  193. g_BlobParticleInterpolation.vInterpolatedPositions[iChangedUsageIndex] = g_pBlobNetworkBypass->vParticlePositions[iChangedUsageIndex];
  194. s_PositionInterpolators[iChangedUsageIndex].Reset( gpGlobals->curtime );
  195. g_BlobParticleInterpolation.vInterpolatedRadii[iChangedUsageIndex] = g_pBlobNetworkBypass->vParticleRadii[iChangedUsageIndex];
  196. s_RadiusInterpolators[iChangedUsageIndex].Reset( gpGlobals->curtime );
  197. g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[iChangedUsageIndex] = g_pBlobNetworkBypass->vParticleClosestSurfDir[iChangedUsageIndex];
  198. s_ClosestSurfDirInterpolators[iChangedUsageIndex].Reset( gpGlobals->curtime );
  199. //s_PositionInterpolators[iChangedUsageIndex].NoteChanged( gpGlobals->curtime, fNewIndicesUpdateTime, true );
  200. }
  201. ++j;
  202. if( j == BITS_PER_INT )
  203. break;
  204. }
  205. iBaseIndex += BITS_PER_INT;
  206. ++pCurrentlyInUse;
  207. ++pOldInUse;
  208. }
  209. memcpy( &m_bOldInUse, &g_pBlobNetworkBypass->bCurrentlyInUse, sizeof( m_bOldInUse ) );
  210. m_iOldHighestIndexUsed = g_pBlobNetworkBypass->iHighestIndexUsed;
  211. }
  212. if( g_pBlobNetworkBypass->iHighestIndexUsed == 0 )
  213. return;
  214. static ConVarRef cl_interpREF( "cl_interp" );
  215. //now do the interpolation of positions still in use
  216. {
  217. float fInterpTime = gpGlobals->curtime - cl_interpREF.GetFloat();
  218. CBitVec<BITS_PER_INT> *pIntParser = (CBitVec<BITS_PER_INT> *)&g_pBlobNetworkBypass->bCurrentlyInUse;
  219. int iStop = (g_pBlobNetworkBypass->iHighestIndexUsed / BITS_PER_INT) + 1;
  220. int iBaseIndex = 0;
  221. for( int i = 0; i != iStop; ++i )
  222. {
  223. int j = 0;
  224. while( (j = pIntParser->FindNextSetBit( j )) != -1 )
  225. {
  226. int iUpdateIndex = iBaseIndex + j;
  227. if( g_pBlobNetworkBypass->bDataUpdated )
  228. {
  229. g_BlobParticleInterpolation.vInterpolatedPositions[iUpdateIndex] = g_pBlobNetworkBypass->vParticlePositions[iUpdateIndex];
  230. s_PositionInterpolators[iUpdateIndex].NoteChanged( gpGlobals->curtime, g_pBlobNetworkBypass->fTimeDataUpdated, true );
  231. g_BlobParticleInterpolation.vInterpolatedRadii[iUpdateIndex] = g_pBlobNetworkBypass->vParticleRadii[iUpdateIndex];
  232. s_RadiusInterpolators[iUpdateIndex].NoteChanged( gpGlobals->curtime, g_pBlobNetworkBypass->fTimeDataUpdated, true );
  233. g_BlobParticleInterpolation.vInterpolatedClosestSurfDir[iUpdateIndex] = g_pBlobNetworkBypass->vParticleClosestSurfDir[iUpdateIndex];
  234. s_ClosestSurfDirInterpolators[iUpdateIndex].NoteChanged( gpGlobals->curtime, g_pBlobNetworkBypass->fTimeDataUpdated, true );
  235. //s_PositionInterpolators[iUpdateIndex].AddToHead( gpGlobals->curtime, &g_pBlobNetworkBypass->vParticlePositions[iUpdateIndex], false );
  236. }
  237. s_PositionInterpolators[iUpdateIndex].Interpolate( fInterpTime );
  238. s_RadiusInterpolators[iUpdateIndex].Interpolate( fInterpTime );
  239. s_ClosestSurfDirInterpolators[iUpdateIndex].Interpolate( fInterpTime );
  240. ++j;
  241. if( j == BITS_PER_INT )
  242. break;
  243. }
  244. iBaseIndex += BITS_PER_INT;
  245. ++pIntParser;
  246. }
  247. g_pBlobNetworkBypass->bDataUpdated = false;
  248. }
  249. }
  250. void BlobNetworkBypass_CustomDemoDataCallback( uint8 *pData, size_t iSize )
  251. {
  252. // FIXME: need a version number!
  253. uint8 *pParse = pData;
  254. int iMaxIndex = LittleDWord( *(int *)pParse );
  255. pParse += sizeof( int );
  256. int iBitMax = (iMaxIndex / BITS_PER_INT) + 1;
  257. Assert( iSize == (sizeof( int ) + sizeof( float ) + sizeof( int ) + sizeof( int ) + (sizeof( int ) * iBitMax) +
  258. iMaxIndex*( sizeof( Vector ) + sizeof( float ) + sizeof( Vector ) )) );
  259. g_pBlobNetworkBypass->fTimeDataUpdated = *(float *)pParse;
  260. pParse += sizeof( float );
  261. g_pBlobNetworkBypass->iHighestIndexUsed = LittleDWord( *(int *)pParse );
  262. pParse += sizeof( int );
  263. g_pBlobNetworkBypass->iNumParticlesAllocated = LittleDWord( *(int *)pParse );
  264. pParse += sizeof( int );
  265. int *pIntParser = (int *)&g_pBlobNetworkBypass->bCurrentlyInUse;
  266. for( int i = 0; i != iBitMax; ++i )
  267. {
  268. //read and convert the bitfield integers
  269. *pIntParser = LittleDWord( *(int *)pParse );
  270. pParse += sizeof( int );
  271. ++pIntParser;
  272. }
  273. //read positions
  274. memcpy( g_pBlobNetworkBypass->vParticlePositions, pParse, sizeof( Vector ) * iMaxIndex );
  275. pParse += sizeof( Vector ) * iMaxIndex;
  276. //read radii
  277. memcpy( g_pBlobNetworkBypass->vParticleRadii, pParse, sizeof( float ) * iMaxIndex );
  278. pParse += sizeof( float ) * iMaxIndex;
  279. //read closest surface direction
  280. memcpy( g_pBlobNetworkBypass->vParticleClosestSurfDir, pParse, sizeof( Vector ) * iMaxIndex );
  281. pParse += sizeof( Vector ) * iMaxIndex;
  282. g_pBlobNetworkBypass->bDataUpdated = true;
  283. Assert( pParse == (pData + iSize) );
  284. }
  285. #endif