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.
655 lines
16 KiB
655 lines
16 KiB
//========= Copyright 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 SWDS |
|
#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_ForceSimpleMaterial( const char *name ) |
|
{ |
|
DownloadListGenerator().ForceSimpleMaterial( name ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// 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 ) || IsX360() ) ); |
|
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 SWDS |
|
EngineVGui()->UpdateProgressBar(PROGRESS_PRECACHE); |
|
#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 ); |
|
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() ); |
|
}
|
|
|