|
|
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "server_pch.h"
#include "sv_precache.h"
#include "host.h"
#include "tier0/icommandline.h"
#include "MapReslistGenerator.h"
#include "DownloadListGenerator.h"
#include "soundchars.h"
#ifndef DEDICATED
#include "vgui_baseui_interface.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
static ConVar sv_forcepreload( "sv_forcepreload", "0", FCVAR_ARCHIVE, "Force server side preloading.");
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// Output : int SV_ModelIndex
//-----------------------------------------------------------------------------
int SV_ModelIndex (const char *name) { return sv.LookupModelIndex( name ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// preload -
// Output : int
//-----------------------------------------------------------------------------
int SV_FindOrAddModel(const char *name, bool preload ) { // Look for a match or an empty slot...
int flags = RES_FATALIFMISSING; if ( preload ) { flags |= RES_PRELOAD; }
return sv.PrecacheModel( name, flags ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// Output : int
//-----------------------------------------------------------------------------
int SV_SoundIndex(const char *name) { return sv.LookupSoundIndex( name ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// preload -
// Output : int
//-----------------------------------------------------------------------------
int SV_FindOrAddSound(const char *name, bool preload ) { // Look for a match or an empty slot...
int flags = RES_FATALIFMISSING; if ( preload ) { flags |= RES_PRELOAD; }
return sv.PrecacheSound( name, flags ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// Output : int
//-----------------------------------------------------------------------------
int SV_GenericIndex(const char *name) { return sv.LookupGenericIndex( name ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// preload -
// Output : int
//-----------------------------------------------------------------------------
int SV_FindOrAddGeneric(const char *name, bool preload ) { // Look for a match or an empty slot...
int flags = RES_FATALIFMISSING; if ( preload ) { flags |= RES_PRELOAD; }
return sv.PrecacheGeneric( name, flags ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// Output : int
//-----------------------------------------------------------------------------
int SV_DecalIndex(const char *name) { return sv.LookupDecalIndex( name ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// preload -
// Output : int
//-----------------------------------------------------------------------------
int SV_FindOrAddDecal(const char *name, bool preload ) { // Look for a match or an empty slot...
int flags = RES_FATALIFMISSING; if ( preload ) { flags |= RES_PRELOAD; }
return sv.PrecacheDecal( name, flags ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
//-----------------------------------------------------------------------------
void SV_ForceExactFile( const char *name ) { DownloadListGenerator().ForceExactFile( name, CONSISTENCY_EXACT ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
//-----------------------------------------------------------------------------
void SV_ForceSimpleMaterial( const char *name ) { DownloadListGenerator().ForceExactFile( name, CONSISTENCY_SIMPLE_MATERIAL ); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// &mins -
// &maxs -
//-----------------------------------------------------------------------------
void SV_ForceModelBounds( const char *name, const Vector &mins, const Vector &maxs ) { DownloadListGenerator().ForceModelBounds( name, mins, maxs ); }
//-----------------------------------------------------------------------------
// Purpose:
// Output : TABLEID
//-----------------------------------------------------------------------------
INetworkStringTable *CGameServer::GetModelPrecacheTable( void ) const { return m_pModelPrecacheTable; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// flags -
// *model -
// Output : int
//-----------------------------------------------------------------------------
int CGameServer::PrecacheModel( char const *name, int flags, model_t *model /*=NULL*/ ) { if ( !m_pModelPrecacheTable ) return -1;
int idx = m_pModelPrecacheTable->AddString( true, name ); if ( idx == INVALID_STRING_INDEX ) { return -1; }
CPrecacheUserData p;
// first time, set file size & flags
CPrecacheUserData const *pExisting = (CPrecacheUserData const *)m_pModelPrecacheTable->GetStringUserData( idx, NULL ); if ( !pExisting ) { p.flags = flags; } else { // Just or in any new flags
p = *pExisting; p.flags |= flags; }
m_pModelPrecacheTable->SetStringUserData( idx, sizeof( p ), &p );
CPrecacheItem *slot = &model_precache[ idx ];
if ( model ) { slot->SetModel( model ); }
bool bLoadNow; bLoadNow = ( !slot->GetModel() && ( ( flags & RES_PRELOAD ) || IsGameConsole() ) ); if ( CommandLine()->FindParm( "-nopreload" ) || CommandLine()->FindParm( "-nopreloadmodels" )) { bLoadNow = false; } else if ( sv_forcepreload.GetInt() || CommandLine()->FindParm( "-preload" ) ) { bLoadNow = true; }
if ( idx != 0 ) { if ( bLoadNow ) { slot->SetModel( modelloader->GetModelForName( name, IModelLoader::FMODELLOADER_SERVER ) ); #ifndef DEDICATED
EngineVGui()->UpdateProgressBar(PROGRESS_DEFAULT); #endif
MapReslistGenerator().OnModelPrecached(name); } else { modelloader->ReferenceModel( name, IModelLoader::FMODELLOADER_SERVER ); slot->SetModel( NULL ); } }
return idx; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : model_t
//-----------------------------------------------------------------------------
model_t *CGameServer::GetModel( int index ) { if ( index <= 0 || !m_pModelPrecacheTable ) return NULL;
if ( index >= m_pModelPrecacheTable->GetNumStrings() ) { return NULL; }
CPrecacheItem *slot = &model_precache[ index ]; model_t *m = slot->GetModel(); if ( m ) { return m; }
char const *modelname = m_pModelPrecacheTable->GetString( index ); Assert( modelname );
if ( host_showcachemiss.GetBool() ) { ConDMsg( "server model cache miss on %s\n", modelname ); }
m = modelloader->GetModelForName( modelname, IModelLoader::FMODELLOADER_SERVER ); slot->SetModel( m );
return m; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// Output : int
//-----------------------------------------------------------------------------
int CGameServer::LookupModelIndex( char const *name ) { if ( !m_pModelPrecacheTable ) return -1;
int idx = m_pModelPrecacheTable->FindStringIndex( name ); return ( idx == INVALID_STRING_INDEX ) ? -1 : idx; }
//-----------------------------------------------------------------------------
// Purpose:
// Output : TABLEID
//-----------------------------------------------------------------------------
INetworkStringTable *CGameServer::GetSoundPrecacheTable( void ) const { return m_pSoundPrecacheTable; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// flags -
// Output : int
//-----------------------------------------------------------------------------
int CGameServer::PrecacheSound( char const *name, int flags ) { if ( !m_pSoundPrecacheTable ) return -1;
int idx = m_pSoundPrecacheTable->AddString( true, name ); if ( idx == INVALID_STRING_INDEX ) { return -1; }
// mark the sound as being precached, but check first that reslist generation is enabled to save on the va() call
if (MapReslistGenerator().IsEnabled() && name[0]) { MapReslistGenerator().OnResourcePrecached( va( "sound/%s", PSkipSoundChars( name ) ) ); }
// first time, set file size & flags
CPrecacheUserData p; CPrecacheUserData const *pExisting = (CPrecacheUserData const *)m_pSoundPrecacheTable->GetStringUserData( idx, NULL ); if ( !pExisting ) { p.flags = flags; } else { // Just or in any new flags
p = *pExisting; p.flags |= flags; }
m_pSoundPrecacheTable->SetStringUserData( idx, sizeof( p ), &p );
CPrecacheItem *slot = &sound_precache[ idx ]; slot->SetName( name );
return idx; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : char const
//-----------------------------------------------------------------------------
char const *CGameServer::GetSound( int index ) { if ( index <= 0 || !m_pSoundPrecacheTable ) { return NULL; }
if ( index >= m_pSoundPrecacheTable->GetNumStrings() ) { return NULL; }
CPrecacheItem *slot = &sound_precache[ index ]; return slot->GetName(); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// Output : int
//-----------------------------------------------------------------------------
int CGameServer::LookupSoundIndex( char const *name ) { if ( !m_pSoundPrecacheTable ) return 0;
int idx = m_pSoundPrecacheTable->FindStringIndex( name ); return ( idx == INVALID_STRING_INDEX ) ? 0 : idx; }
//-----------------------------------------------------------------------------
// Purpose:
// Output : TABLEID
//-----------------------------------------------------------------------------
INetworkStringTable *CGameServer::GetGenericPrecacheTable( void ) const { return m_pGenericPrecacheTable; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// flags -
// Output : int
//-----------------------------------------------------------------------------
int CGameServer::PrecacheGeneric( char const *name, int flags ) { if ( !m_pGenericPrecacheTable ) return -1;
int idx = m_pGenericPrecacheTable->AddString( true, name );
if ( idx == INVALID_STRING_INDEX ) { return -1; }
MapReslistGenerator().OnResourcePrecached( name );
CPrecacheUserData p;
// first time, set file size & flags
CPrecacheUserData const *pExisting = (CPrecacheUserData const *)m_pGenericPrecacheTable->GetStringUserData( idx, NULL ); if ( !pExisting ) { p.flags = flags; } else { // Just or in any new flags
p = *pExisting; p.flags |= flags; }
m_pGenericPrecacheTable->SetStringUserData( idx, sizeof( p ), &p );
CPrecacheItem *slot = &generic_precache[ idx ]; slot->SetGeneric( name );
// just precache particle files now
if ( ( flags & RES_PRELOAD ) && serverGameDLL && !V_stricmp( "pcf", V_GetFileExtensionSafe( name ) ) ) { serverGameDLL->PrecacheParticleSystemFile( name ); }
return idx; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : index -
// Output : char const
//-----------------------------------------------------------------------------
char const *CGameServer::GetGeneric( int index ) { // Bogus index
if ( index < 0 || !m_pGenericPrecacheTable ) return "";
if ( index >= m_pGenericPrecacheTable->GetNumStrings() ) { return ""; }
CPrecacheItem *slot = &generic_precache[ index ]; return slot->GetGeneric(); }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// Output : int
//-----------------------------------------------------------------------------
int CGameServer::LookupGenericIndex( char const *name ) { if ( !m_pGenericPrecacheTable ) return 0;
int idx = m_pGenericPrecacheTable->FindStringIndex( name );
return ( idx == INVALID_STRING_INDEX ) ? 0 : idx; }
//-----------------------------------------------------------------------------
// Purpose:
// Output : TABLEID
//-----------------------------------------------------------------------------
INetworkStringTable *CGameServer::GetDecalPrecacheTable( void ) const { return m_pDecalPrecacheTable; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// flags -
// Output : int
//-----------------------------------------------------------------------------
int CGameServer::PrecacheDecal( char const *name, int flags ) { if ( !m_pDecalPrecacheTable ) return -1;
int idx = m_pDecalPrecacheTable->AddString( true, name ); if ( idx == INVALID_STRING_INDEX ) { return -1; }
MapReslistGenerator().OnResourcePrecached(name);
CPrecacheUserData p;
// first time, set file size & flags
CPrecacheUserData const *pExisting = (CPrecacheUserData const *)m_pDecalPrecacheTable->GetStringUserData( idx, NULL ); if ( !pExisting ) { p.flags = flags; } else { // Just or in any new flags
p = *pExisting; p.flags |= flags; }
m_pDecalPrecacheTable->SetStringUserData( idx, sizeof( p ), &p );
CPrecacheItem *slot = &decal_precache[ idx ]; slot->SetDecal( name ); return idx; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *name -
// Output : int
//-----------------------------------------------------------------------------
int CGameServer::LookupDecalIndex( char const *name ) { if ( !m_pDecalPrecacheTable ) return -1;
int idx = m_pDecalPrecacheTable->FindStringIndex( name ); return ( idx == INVALID_STRING_INDEX ) ? -1 : idx; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameServer::DumpPrecacheStats( INetworkStringTable *table ) { if ( table == NULL ) { ConMsg( "Can only dump stats when active in a level\n" ); return; }
CPrecacheItem *items = NULL; if ( table == m_pModelPrecacheTable ) { items = model_precache; } else if ( table == m_pGenericPrecacheTable ) { items = generic_precache; } else if ( table == m_pSoundPrecacheTable ) { items = sound_precache; } else if ( table == m_pDecalPrecacheTable ) { items = decal_precache; }
if ( !items ) return;
int count = table->GetNumStrings(); int maxcount = table->GetMaxStrings();
ConMsg( "\n" ); ConMsg( "Precache table %s: %i of %i slots used\n", table->GetTableName(), count, maxcount );
for ( int i = 0; i < count; i++ ) { char const *name = table->GetString( i ); CPrecacheItem *slot = &items[ i ]; int testLength; const CPrecacheUserData *p = ( const CPrecacheUserData * )table->GetStringUserData( i, &testLength ); ErrorIfNot( testLength == sizeof( *p ), ("CGameServer::DumpPrecacheStats: invalid CPrecacheUserData length (%d)", testLength) );
if ( !name || !slot || !p ) continue;
ConMsg( "%03i: %s (%s): ", i, name, GetFlagString( p->flags ) );
if ( slot->GetReferenceCount() == 0 ) { ConMsg( " never used\n" ); } else { ConMsg( " %i refs, first %.2f mru %.2f\n", slot->GetReferenceCount(), slot->GetFirstReference(), slot->GetMostRecentReference() ); } }
ConMsg( "\n" ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CON_COMMAND( sv_precacheinfo, "Show precache info." ) { if ( args.ArgC() == 2 ) { char const *table = args[ 1 ];
bool dumped = true; if ( !Q_strcasecmp( table, "generic" ) ) { sv.DumpPrecacheStats( sv.GetGenericPrecacheTable() ); } else if ( !Q_strcasecmp( table, "sound" ) ) { sv.DumpPrecacheStats( sv.GetSoundPrecacheTable() ); } else if ( !Q_strcasecmp( table, "decal" ) ) { sv.DumpPrecacheStats( sv.GetDecalPrecacheTable() ); } else if ( !Q_strcasecmp( table, "model" ) ) { sv.DumpPrecacheStats( sv.GetModelPrecacheTable() ); } else { dumped = false; }
if ( dumped ) { return; } } // Show all data
sv.DumpPrecacheStats( sv.GetGenericPrecacheTable() ); sv.DumpPrecacheStats( sv.GetDecalPrecacheTable() ); sv.DumpPrecacheStats( sv.GetSoundPrecacheTable() ); sv.DumpPrecacheStats( sv.GetModelPrecacheTable() ); }
|