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.

672 lines
17 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "server_pch.h"
  8. #include "sv_precache.h"
  9. #include "host.h"
  10. #include "tier0/icommandline.h"
  11. #include "MapReslistGenerator.h"
  12. #include "DownloadListGenerator.h"
  13. #include "soundchars.h"
  14. #ifndef DEDICATED
  15. #include "vgui_baseui_interface.h"
  16. #endif
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. static ConVar sv_forcepreload( "sv_forcepreload", "0", FCVAR_ARCHIVE, "Force server side preloading.");
  20. //-----------------------------------------------------------------------------
  21. // Purpose:
  22. // Input : *name -
  23. // Output : int SV_ModelIndex
  24. //-----------------------------------------------------------------------------
  25. int SV_ModelIndex (const char *name)
  26. {
  27. return sv.LookupModelIndex( name );
  28. }
  29. //-----------------------------------------------------------------------------
  30. // Purpose:
  31. // Input : *name -
  32. // preload -
  33. // Output : int
  34. //-----------------------------------------------------------------------------
  35. int SV_FindOrAddModel(const char *name, bool preload )
  36. {
  37. // Look for a match or an empty slot...
  38. int flags = RES_FATALIFMISSING;
  39. if ( preload )
  40. {
  41. flags |= RES_PRELOAD;
  42. }
  43. return sv.PrecacheModel( name, flags );
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Purpose:
  47. // Input : *name -
  48. // Output : int
  49. //-----------------------------------------------------------------------------
  50. int SV_SoundIndex(const char *name)
  51. {
  52. return sv.LookupSoundIndex( name );
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Purpose:
  56. // Input : *name -
  57. // preload -
  58. // Output : int
  59. //-----------------------------------------------------------------------------
  60. int SV_FindOrAddSound(const char *name, bool preload )
  61. {
  62. // Look for a match or an empty slot...
  63. int flags = RES_FATALIFMISSING;
  64. if ( preload )
  65. {
  66. flags |= RES_PRELOAD;
  67. }
  68. return sv.PrecacheSound( name, flags );
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Purpose:
  72. // Input : *name -
  73. // Output : int
  74. //-----------------------------------------------------------------------------
  75. int SV_GenericIndex(const char *name)
  76. {
  77. return sv.LookupGenericIndex( name );
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Purpose:
  81. // Input : *name -
  82. // preload -
  83. // Output : int
  84. //-----------------------------------------------------------------------------
  85. int SV_FindOrAddGeneric(const char *name, bool preload )
  86. {
  87. // Look for a match or an empty slot...
  88. int flags = RES_FATALIFMISSING;
  89. if ( preload )
  90. {
  91. flags |= RES_PRELOAD;
  92. }
  93. return sv.PrecacheGeneric( name, flags );
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Purpose:
  97. // Input : *name -
  98. // Output : int
  99. //-----------------------------------------------------------------------------
  100. int SV_DecalIndex(const char *name)
  101. {
  102. return sv.LookupDecalIndex( name );
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Purpose:
  106. // Input : *name -
  107. // preload -
  108. // Output : int
  109. //-----------------------------------------------------------------------------
  110. int SV_FindOrAddDecal(const char *name, bool preload )
  111. {
  112. // Look for a match or an empty slot...
  113. int flags = RES_FATALIFMISSING;
  114. if ( preload )
  115. {
  116. flags |= RES_PRELOAD;
  117. }
  118. return sv.PrecacheDecal( name, flags );
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose:
  122. // Input : *name -
  123. //-----------------------------------------------------------------------------
  124. void SV_ForceExactFile( const char *name )
  125. {
  126. DownloadListGenerator().ForceExactFile( name, CONSISTENCY_EXACT );
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose:
  130. // Input : *name -
  131. //-----------------------------------------------------------------------------
  132. void SV_ForceSimpleMaterial( const char *name )
  133. {
  134. DownloadListGenerator().ForceExactFile( name, CONSISTENCY_SIMPLE_MATERIAL );
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose:
  138. // Input : *name -
  139. // &mins -
  140. // &maxs -
  141. //-----------------------------------------------------------------------------
  142. void SV_ForceModelBounds( const char *name, const Vector &mins, const Vector &maxs )
  143. {
  144. DownloadListGenerator().ForceModelBounds( name, mins, maxs );
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Purpose:
  148. // Output : TABLEID
  149. //-----------------------------------------------------------------------------
  150. INetworkStringTable *CGameServer::GetModelPrecacheTable( void ) const
  151. {
  152. return m_pModelPrecacheTable;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose:
  156. // Input : *name -
  157. // flags -
  158. // *model -
  159. // Output : int
  160. //-----------------------------------------------------------------------------
  161. int CGameServer::PrecacheModel( char const *name, int flags, model_t *model /*=NULL*/ )
  162. {
  163. if ( !m_pModelPrecacheTable )
  164. return -1;
  165. int idx = m_pModelPrecacheTable->AddString( true, name );
  166. if ( idx == INVALID_STRING_INDEX )
  167. {
  168. return -1;
  169. }
  170. CPrecacheUserData p;
  171. // first time, set file size & flags
  172. CPrecacheUserData const *pExisting = (CPrecacheUserData const *)m_pModelPrecacheTable->GetStringUserData( idx, NULL );
  173. if ( !pExisting )
  174. {
  175. p.flags = flags;
  176. }
  177. else
  178. {
  179. // Just or in any new flags
  180. p = *pExisting;
  181. p.flags |= flags;
  182. }
  183. m_pModelPrecacheTable->SetStringUserData( idx, sizeof( p ), &p );
  184. CPrecacheItem *slot = &model_precache[ idx ];
  185. if ( model )
  186. {
  187. slot->SetModel( model );
  188. }
  189. bool bLoadNow;
  190. bLoadNow = ( !slot->GetModel() && ( ( flags & RES_PRELOAD ) || IsGameConsole() ) );
  191. if ( CommandLine()->FindParm( "-nopreload" ) || CommandLine()->FindParm( "-nopreloadmodels" ))
  192. {
  193. bLoadNow = false;
  194. }
  195. else if ( sv_forcepreload.GetInt() || CommandLine()->FindParm( "-preload" ) )
  196. {
  197. bLoadNow = true;
  198. }
  199. if ( idx != 0 )
  200. {
  201. if ( bLoadNow )
  202. {
  203. slot->SetModel( modelloader->GetModelForName( name, IModelLoader::FMODELLOADER_SERVER ) );
  204. #ifndef DEDICATED
  205. EngineVGui()->UpdateProgressBar(PROGRESS_DEFAULT);
  206. #endif
  207. MapReslistGenerator().OnModelPrecached(name);
  208. }
  209. else
  210. {
  211. modelloader->ReferenceModel( name, IModelLoader::FMODELLOADER_SERVER );
  212. slot->SetModel( NULL );
  213. }
  214. }
  215. return idx;
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Purpose:
  219. // Input : index -
  220. // Output : model_t
  221. //-----------------------------------------------------------------------------
  222. model_t *CGameServer::GetModel( int index )
  223. {
  224. if ( index <= 0 || !m_pModelPrecacheTable )
  225. return NULL;
  226. if ( index >= m_pModelPrecacheTable->GetNumStrings() )
  227. {
  228. return NULL;
  229. }
  230. CPrecacheItem *slot = &model_precache[ index ];
  231. model_t *m = slot->GetModel();
  232. if ( m )
  233. {
  234. return m;
  235. }
  236. char const *modelname = m_pModelPrecacheTable->GetString( index );
  237. Assert( modelname );
  238. if ( host_showcachemiss.GetBool() )
  239. {
  240. ConDMsg( "server model cache miss on %s\n", modelname );
  241. }
  242. m = modelloader->GetModelForName( modelname, IModelLoader::FMODELLOADER_SERVER );
  243. slot->SetModel( m );
  244. return m;
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose:
  248. // Input : *name -
  249. // Output : int
  250. //-----------------------------------------------------------------------------
  251. int CGameServer::LookupModelIndex( char const *name )
  252. {
  253. if ( !m_pModelPrecacheTable )
  254. return -1;
  255. int idx = m_pModelPrecacheTable->FindStringIndex( name );
  256. return ( idx == INVALID_STRING_INDEX ) ? -1 : idx;
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose:
  260. // Output : TABLEID
  261. //-----------------------------------------------------------------------------
  262. INetworkStringTable *CGameServer::GetSoundPrecacheTable( void ) const
  263. {
  264. return m_pSoundPrecacheTable;
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Purpose:
  268. // Input : *name -
  269. // flags -
  270. // Output : int
  271. //-----------------------------------------------------------------------------
  272. int CGameServer::PrecacheSound( char const *name, int flags )
  273. {
  274. if ( !m_pSoundPrecacheTable )
  275. return -1;
  276. int idx = m_pSoundPrecacheTable->AddString( true, name );
  277. if ( idx == INVALID_STRING_INDEX )
  278. {
  279. return -1;
  280. }
  281. // mark the sound as being precached, but check first that reslist generation is enabled to save on the va() call
  282. if (MapReslistGenerator().IsEnabled() && name[0])
  283. {
  284. MapReslistGenerator().OnResourcePrecached( va( "sound/%s", PSkipSoundChars( name ) ) );
  285. }
  286. // first time, set file size & flags
  287. CPrecacheUserData p;
  288. CPrecacheUserData const *pExisting = (CPrecacheUserData const *)m_pSoundPrecacheTable->GetStringUserData( idx, NULL );
  289. if ( !pExisting )
  290. {
  291. p.flags = flags;
  292. }
  293. else
  294. {
  295. // Just or in any new flags
  296. p = *pExisting;
  297. p.flags |= flags;
  298. }
  299. m_pSoundPrecacheTable->SetStringUserData( idx, sizeof( p ), &p );
  300. CPrecacheItem *slot = &sound_precache[ idx ];
  301. slot->SetName( name );
  302. return idx;
  303. }
  304. //-----------------------------------------------------------------------------
  305. // Purpose:
  306. // Input : index -
  307. // Output : char const
  308. //-----------------------------------------------------------------------------
  309. char const *CGameServer::GetSound( int index )
  310. {
  311. if ( index <= 0 || !m_pSoundPrecacheTable )
  312. {
  313. return NULL;
  314. }
  315. if ( index >= m_pSoundPrecacheTable->GetNumStrings() )
  316. {
  317. return NULL;
  318. }
  319. CPrecacheItem *slot = &sound_precache[ index ];
  320. return slot->GetName();
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Purpose:
  324. // Input : *name -
  325. // Output : int
  326. //-----------------------------------------------------------------------------
  327. int CGameServer::LookupSoundIndex( char const *name )
  328. {
  329. if ( !m_pSoundPrecacheTable )
  330. return 0;
  331. int idx = m_pSoundPrecacheTable->FindStringIndex( name );
  332. return ( idx == INVALID_STRING_INDEX ) ? 0 : idx;
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Purpose:
  336. // Output : TABLEID
  337. //-----------------------------------------------------------------------------
  338. INetworkStringTable *CGameServer::GetGenericPrecacheTable( void ) const
  339. {
  340. return m_pGenericPrecacheTable;
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Purpose:
  344. // Input : *name -
  345. // flags -
  346. // Output : int
  347. //-----------------------------------------------------------------------------
  348. int CGameServer::PrecacheGeneric( char const *name, int flags )
  349. {
  350. if ( !m_pGenericPrecacheTable )
  351. return -1;
  352. int idx = m_pGenericPrecacheTable->AddString( true, name );
  353. if ( idx == INVALID_STRING_INDEX )
  354. {
  355. return -1;
  356. }
  357. MapReslistGenerator().OnResourcePrecached( name );
  358. CPrecacheUserData p;
  359. // first time, set file size & flags
  360. CPrecacheUserData const *pExisting = (CPrecacheUserData const *)m_pGenericPrecacheTable->GetStringUserData( idx, NULL );
  361. if ( !pExisting )
  362. {
  363. p.flags = flags;
  364. }
  365. else
  366. {
  367. // Just or in any new flags
  368. p = *pExisting;
  369. p.flags |= flags;
  370. }
  371. m_pGenericPrecacheTable->SetStringUserData( idx, sizeof( p ), &p );
  372. CPrecacheItem *slot = &generic_precache[ idx ];
  373. slot->SetGeneric( name );
  374. // just precache particle files now
  375. if ( ( flags & RES_PRELOAD ) && serverGameDLL && !V_stricmp( "pcf", V_GetFileExtensionSafe( name ) ) )
  376. {
  377. serverGameDLL->PrecacheParticleSystemFile( name );
  378. }
  379. return idx;
  380. }
  381. //-----------------------------------------------------------------------------
  382. // Purpose:
  383. // Input : index -
  384. // Output : char const
  385. //-----------------------------------------------------------------------------
  386. char const *CGameServer::GetGeneric( int index )
  387. {
  388. // Bogus index
  389. if ( index < 0 || !m_pGenericPrecacheTable )
  390. return "";
  391. if ( index >= m_pGenericPrecacheTable->GetNumStrings() )
  392. {
  393. return "";
  394. }
  395. CPrecacheItem *slot = &generic_precache[ index ];
  396. return slot->GetGeneric();
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Purpose:
  400. // Input : *name -
  401. // Output : int
  402. //-----------------------------------------------------------------------------
  403. int CGameServer::LookupGenericIndex( char const *name )
  404. {
  405. if ( !m_pGenericPrecacheTable )
  406. return 0;
  407. int idx = m_pGenericPrecacheTable->FindStringIndex( name );
  408. return ( idx == INVALID_STRING_INDEX ) ? 0 : idx;
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Purpose:
  412. // Output : TABLEID
  413. //-----------------------------------------------------------------------------
  414. INetworkStringTable *CGameServer::GetDecalPrecacheTable( void ) const
  415. {
  416. return m_pDecalPrecacheTable;
  417. }
  418. //-----------------------------------------------------------------------------
  419. // Purpose:
  420. // Input : *name -
  421. // flags -
  422. // Output : int
  423. //-----------------------------------------------------------------------------
  424. int CGameServer::PrecacheDecal( char const *name, int flags )
  425. {
  426. if ( !m_pDecalPrecacheTable )
  427. return -1;
  428. int idx = m_pDecalPrecacheTable->AddString( true, name );
  429. if ( idx == INVALID_STRING_INDEX )
  430. {
  431. return -1;
  432. }
  433. MapReslistGenerator().OnResourcePrecached(name);
  434. CPrecacheUserData p;
  435. // first time, set file size & flags
  436. CPrecacheUserData const *pExisting = (CPrecacheUserData const *)m_pDecalPrecacheTable->GetStringUserData( idx, NULL );
  437. if ( !pExisting )
  438. {
  439. p.flags = flags;
  440. }
  441. else
  442. {
  443. // Just or in any new flags
  444. p = *pExisting;
  445. p.flags |= flags;
  446. }
  447. m_pDecalPrecacheTable->SetStringUserData( idx, sizeof( p ), &p );
  448. CPrecacheItem *slot = &decal_precache[ idx ];
  449. slot->SetDecal( name );
  450. return idx;
  451. }
  452. //-----------------------------------------------------------------------------
  453. // Purpose:
  454. // Input : *name -
  455. // Output : int
  456. //-----------------------------------------------------------------------------
  457. int CGameServer::LookupDecalIndex( char const *name )
  458. {
  459. if ( !m_pDecalPrecacheTable )
  460. return -1;
  461. int idx = m_pDecalPrecacheTable->FindStringIndex( name );
  462. return ( idx == INVALID_STRING_INDEX ) ? -1 : idx;
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Purpose:
  466. //-----------------------------------------------------------------------------
  467. void CGameServer::DumpPrecacheStats( INetworkStringTable *table )
  468. {
  469. if ( table == NULL )
  470. {
  471. ConMsg( "Can only dump stats when active in a level\n" );
  472. return;
  473. }
  474. CPrecacheItem *items = NULL;
  475. if ( table == m_pModelPrecacheTable )
  476. {
  477. items = model_precache;
  478. }
  479. else if ( table == m_pGenericPrecacheTable )
  480. {
  481. items = generic_precache;
  482. }
  483. else if ( table == m_pSoundPrecacheTable )
  484. {
  485. items = sound_precache;
  486. }
  487. else if ( table == m_pDecalPrecacheTable )
  488. {
  489. items = decal_precache;
  490. }
  491. if ( !items )
  492. return;
  493. int count = table->GetNumStrings();
  494. int maxcount = table->GetMaxStrings();
  495. ConMsg( "\n" );
  496. ConMsg( "Precache table %s: %i of %i slots used\n", table->GetTableName(),
  497. count, maxcount );
  498. for ( int i = 0; i < count; i++ )
  499. {
  500. char const *name = table->GetString( i );
  501. CPrecacheItem *slot = &items[ i ];
  502. int testLength;
  503. const CPrecacheUserData *p = ( const CPrecacheUserData * )table->GetStringUserData( i, &testLength );
  504. ErrorIfNot( testLength == sizeof( *p ),
  505. ("CGameServer::DumpPrecacheStats: invalid CPrecacheUserData length (%d)", testLength)
  506. );
  507. if ( !name || !slot || !p )
  508. continue;
  509. ConMsg( "%03i: %s (%s): ",
  510. i,
  511. name,
  512. GetFlagString( p->flags ) );
  513. if ( slot->GetReferenceCount() == 0 )
  514. {
  515. ConMsg( " never used\n" );
  516. }
  517. else
  518. {
  519. ConMsg( " %i refs, first %.2f mru %.2f\n",
  520. slot->GetReferenceCount(),
  521. slot->GetFirstReference(),
  522. slot->GetMostRecentReference() );
  523. }
  524. }
  525. ConMsg( "\n" );
  526. }
  527. //-----------------------------------------------------------------------------
  528. // Purpose:
  529. //-----------------------------------------------------------------------------
  530. CON_COMMAND( sv_precacheinfo, "Show precache info." )
  531. {
  532. if ( args.ArgC() == 2 )
  533. {
  534. char const *table = args[ 1 ];
  535. bool dumped = true;
  536. if ( !Q_strcasecmp( table, "generic" ) )
  537. {
  538. sv.DumpPrecacheStats( sv.GetGenericPrecacheTable() );
  539. }
  540. else if ( !Q_strcasecmp( table, "sound" ) )
  541. {
  542. sv.DumpPrecacheStats( sv.GetSoundPrecacheTable() );
  543. }
  544. else if ( !Q_strcasecmp( table, "decal" ) )
  545. {
  546. sv.DumpPrecacheStats( sv.GetDecalPrecacheTable() );
  547. }
  548. else if ( !Q_strcasecmp( table, "model" ) )
  549. {
  550. sv.DumpPrecacheStats( sv.GetModelPrecacheTable() );
  551. }
  552. else
  553. {
  554. dumped = false;
  555. }
  556. if ( dumped )
  557. {
  558. return;
  559. }
  560. }
  561. // Show all data
  562. sv.DumpPrecacheStats( sv.GetGenericPrecacheTable() );
  563. sv.DumpPrecacheStats( sv.GetDecalPrecacheTable() );
  564. sv.DumpPrecacheStats( sv.GetSoundPrecacheTable() );
  565. sv.DumpPrecacheStats( sv.GetModelPrecacheTable() );
  566. }