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.
 
 
 
 
 
 

423 lines
12 KiB

//===== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======//
//
// Purpose:
//
//===========================================================================//
#include "matchext_swarm.h"
#include "swarm.spa.h"
#include "utlvector.h"
#include "utlstringmap.h"
#include "fmtstr.h"
#include "filesystem.h"
#define g_pFileSystem g_pFullFileSystem
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CMatchExtSwarm::CMatchExtSwarm()
{
m_pKeyValues = NULL;
}
CMatchExtSwarm::~CMatchExtSwarm()
{
if ( m_pKeyValues )
{
m_pKeyValues->deleteThis();
m_pKeyValues = NULL;
}
}
static CMatchExtSwarm g_MatchExtSwarm;
CMatchExtSwarm *g_pMatchExtSwarm = &g_MatchExtSwarm;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CMatchExtSwarm, IMatchExtSwarm,
IMATCHEXT_SWARM_INTERFACE, g_MatchExtSwarm );
//
// Implementation
//
void CMatchExtSwarm::ParseMissionFromFile( char const *szFile, bool bBuiltIn )
{
KeyValues *pMissionModes = m_pKeyValues->FindKey( "GameModes" );
KeyValues *pMissionsRoot = m_pKeyValues->FindKey( "Missions" );
if ( !pMissionsRoot || !pMissionModes )
return;
// See if we already have this mission
if ( m_mapFilesLoaded.Find( szFile ) != m_mapFilesLoaded.InvalidIndex() )
return;
m_mapFilesLoaded[ szFile ] = NULL;
KeyValues *missionKeys = new KeyValues( "mission" );
KeyValues::AutoDelete autodelete_missionKeys( missionKeys ); // allows for early error-return
bool bLoadResult = missionKeys->LoadFromFile( g_pFileSystem, szFile );
if ( !bLoadResult )
{
Warning( "MissionManager: Mission file \"%s\" is malformed, failed to parse.\n", szFile );
return;
}
const char *name = missionKeys->GetString( "name", NULL );
const char *campaignVersion = missionKeys->GetString( "version", NULL );
if ( !name || !campaignVersion )
{
Warning( "MissionManager: Mission file \"%s\" is missing name and version\n", szFile );
return;
}
// Check invalid characters
for ( char const *pCharCheck = name; *pCharCheck; ++ pCharCheck )
{
char const c = *pCharCheck;
if ( !( ( c >= 'a' && c <= 'z' ) ||
( c >= 'A' && c <= 'Z' ) ||
( c >= '0' && c <= '9' ) ) )
{
Warning( "MissionManager: Only alphanumeric characters allowed in mission name: \"%s\" in \"%s\"\n", name, szFile );
return;
}
}
for ( char const *pCharCheck = campaignVersion; *pCharCheck; ++ pCharCheck )
{
char const c = *pCharCheck;
if ( !( c >= '0' && c <= '9' ) )
{
Warning( "MissionManager: Only numeric characters allowed in mission version: \"%s\" in \"%s\"\n", campaignVersion, szFile );
return;
}
}
// Now go through the game modes
KeyValues *modes = missionKeys->FindKey( "modes" );
if ( !modes )
{
Warning( "MissionManager: Mission file \"%s\" is missing data for any game modes\n", szFile );
return;
}
CFmtStr sNameVersion( "%s_%s", name, campaignVersion );
// Don't allow duplicates
if ( m_mapMissionsLoaded.Find( name ) != m_mapMissionsLoaded.InvalidIndex() )
{
Warning( "MissionManager: Duplicate mission \"%s\" in file \"%s\", already loaded from \"%s\".\n",
name, szFile, m_mapMissionsLoaded[ name ]->GetString( "cfgfile" ) );
return;
}
DevMsg( "\tMission %s ver %s loading...\n", name, campaignVersion );
// Validate DisplayTitle and Description
char const *szDisplayTitle = missionKeys->GetString( "displaytitle" );
if ( !szDisplayTitle || !*szDisplayTitle )
missionKeys->SetString( "displaytitle", name );
// Set auto-generated fields
missionKeys->SetName( name );
missionKeys->SetInt( "builtin", bBuiltIn ? 1 : 0 );
missionKeys->SetString( "cfgfile", szFile );
missionKeys->SetString( "cfgtag", sNameVersion );
// Load game modes
int numGameModes = 0;
for ( KeyValues *modeName = pMissionModes->GetFirstTrueSubKey(); modeName; modeName = modeName->GetNextTrueSubKey() )
{
KeyValues *mode = modes->FindKey( modeName->GetName() );
if ( !mode )
continue;
int numChapters = 0;
while ( KeyValues *pChapterKey = mode->FindKey( CFmtStr( "%d", numChapters + 1 ) ) )
{
// Check required fields
char const *szMap = pChapterKey->GetString( "map" );
if ( !szMap || !*szMap )
{
Warning( "MissionManager: Mission file \"%s\" has invalid map specified for modes/%s/%s\n",
szFile, modeName->GetName(), pChapterKey->GetName() );
numChapters = 0;
break;
}
// DisplayName
char const *szDisplayName = pChapterKey->GetString( "displayname" );
if ( !szDisplayName || !*szDisplayName )
{
pChapterKey->SetString( "displayname", CFmtStr( "%s-%s", name, pChapterKey->GetName() ) );
}
// Image
char const *szImage = pChapterKey->GetString( "image" );
if ( !szImage || !*szImage )
{
pChapterKey->SetString( "image", "maps/unknown" );
}
// Set the automatic fields
pChapterKey->SetInt( "chapter", numChapters + 1 );
// This chapter was valid
++ numChapters;
}
if ( !numChapters )
{
modes->RemoveSubKey( mode );
mode->deleteThis();
mode = NULL;
Warning( "MissionManager: Mission file \"%s\" has invalid settings for game mode %s\n",
szFile, modeName->GetName() );
continue;
}
mode->SetInt( "chapters", numChapters );
DevMsg( "\t\tloaded %d %s chapters.\n", numChapters, modeName->GetName() );
++ numGameModes;
}
if ( !numGameModes )
{
Warning( "MissionManager: Mission file \"%s\" does not have valid data for any supported game mode\n", szFile );
return;
}
//
// Bind the loaded mission keys into the system
//
m_mapFilesLoaded[ szFile ] = missionKeys;
m_mapMissionsLoaded[ name ] = missionKeys;
pMissionsRoot->AddSubKey( missionKeys );
autodelete_missionKeys.Assign( NULL ); // prevent automatic deletion
// Register all the loaded game modes
for ( KeyValues *modeName = pMissionModes->GetFirstTrueSubKey(); modeName; modeName = modeName->GetNextTrueSubKey() )
{
KeyValues *mode = modes->FindKey( modeName->GetName() );
if ( !mode )
continue;
modeName->SetPtr( name, missionKeys );
}
DevMsg( "\tMission %s ver %s loaded %d game modes.\n", name, campaignVersion, numGameModes );
}
void CMatchExtSwarm::MakeGameModeCopy( char const *szGameMode, char const *szCopyName )
{
// Fix the GameModes key
if ( KeyValues *pKeyMode = m_pKeyValues->FindKey( CFmtStr( "GameModes/%s", szGameMode ) ) )
{
pKeyMode = pKeyMode->MakeCopy();
pKeyMode->SetName( szCopyName );
m_pKeyValues->FindKey( "GameModes" )->AddSubKey( pKeyMode );
}
// Fix all missions
KeyValues *pMission = GetAllMissions();
for ( pMission = pMission ? pMission->GetFirstTrueSubKey() : NULL;
pMission; pMission = pMission->GetNextTrueSubKey() )
{
if ( KeyValues *pKeyMode = pMission->FindKey( CFmtStr( "modes/%s", szGameMode ) ) )
{
pKeyMode = pKeyMode->MakeCopy();
pKeyMode->SetName( szCopyName );
pMission->FindKey( "modes" )->AddSubKey( pKeyMode );
}
}
}
void CMatchExtSwarm::Initialize()
{
DevMsg( "Loading Mission Data\n" );
MEM_ALLOC_CREDIT();
if ( m_pKeyValues )
{
m_pKeyValues->deleteThis();
m_pKeyValues = NULL;
}
m_mapFilesLoaded.Purge();
m_mapMissionsLoaded.Purge();
m_pKeyValues = KeyValues::FromString(
"AlienSwarm",
" GameModes { "
" coop { } "
#ifndef _DEMO
" versus { } "
" survival { } "
" scavenge { } "
#endif
" } "
" Missions { "
// read from mission files
" } "
);
//
// Parse built-in missions
//
#ifndef _DEMO
ParseMissionFromFile( "missions/campaign1.txt", true );
ParseMissionFromFile( "missions/campaign2.txt", true );
ParseMissionFromFile( "missions/campaign3.txt", true );
ParseMissionFromFile( "missions/campaign4.txt", true );
ParseMissionFromFile( "missions/campaign5.txt", true );
ParseMissionFromFile( "missions/credits.txt", true );
//
// Search missions using the wildcards
//
char szMissionPath[_MAX_PATH];
Q_snprintf( szMissionPath, sizeof( szMissionPath ), "missions/*.txt" );
Q_FixSlashes( szMissionPath );
FileFindHandle_t handle;
const char *pFoundFile = g_pFileSystem->FindFirst( szMissionPath, &handle );
while ( pFoundFile )
{
char pFilename[ MAX_PATH ];
V_snprintf( pFilename, ARRAYSIZE(pFilename), "missions/%s", pFoundFile );
pFoundFile = g_pFileSystem->FindNext( handle );
ParseMissionFromFile( pFilename, false );
}
#else
ParseMissionFromFile( "missions/demo.txt", true );
#endif
#ifndef _DEMO
// Make game mode copies
MakeGameModeCopy( "versus", "teamversus" );
MakeGameModeCopy( "scavenge", "teamscavenge" );
MakeGameModeCopy( "coop", "realism" );
#endif
DevMsg( "Loading Mission Data Finished\n" );
}
void CMatchExtSwarm::DebugPrint()
{
KeyValuesDumpAsDevMsg( m_pKeyValues, 1, 0 );
}
//--------------------------------------------------------------------------------------------------------
CON_COMMAND( mission_reload, "Reload mission metadata" )
{
g_MatchExtSwarm.Initialize();
}
CON_COMMAND_F( mission_debug_print, "Print all mission metadata", FCVAR_DEVELOPMENTONLY )
{
g_MatchExtSwarm.DebugPrint();
}
KeyValues * CMatchExtSwarm::GetAllMissions()
{
if ( !m_pKeyValues )
return NULL;
return m_pKeyValues->FindKey( "Missions" );
}
// Get server map information for the session settings
KeyValues * CMatchExtSwarm::GetMapInfo( KeyValues *pSettings, KeyValues **ppMissionInfo )
{
if ( !m_pKeyValues )
return NULL;
char const *szGameMode = pSettings->GetString( "game/mode", NULL );
if ( !szGameMode || !*szGameMode )
return NULL;
char const *szCampaign = pSettings->GetString( "game/campaign", NULL );
if ( !szCampaign || !*szCampaign )
return NULL;
int nMapNumber = pSettings->GetInt( "game/chapter", 0 );
if ( nMapNumber <= 0 )
return NULL;
// Find the campaign key
KeyValues *pMissionKey = ( KeyValues * ) m_pKeyValues->GetPtr( CFmtStr( "GameModes/%s/%s", szGameMode, szCampaign ), NULL );
if ( !pMissionKey )
return NULL;
// Find the total number of chapters in that mission's game mode
int numChapters = pMissionKey->GetInt( CFmtStr( "modes/%s/chapters", szGameMode ), 0 );
if ( nMapNumber > numChapters )
return NULL;
KeyValues *pChapterKey = pMissionKey->FindKey( CFmtStr( "modes/%s/%d", szGameMode, nMapNumber ) );
if ( !pChapterKey )
return NULL;
if ( ppMissionInfo )
*ppMissionInfo = pMissionKey;
return pChapterKey;
}
KeyValues * CMatchExtSwarm::GetMapInfoByBspName( KeyValues *pSettings, char const *szBspMapName, KeyValues **ppMissionInfo )
{
if ( !m_pKeyValues )
return NULL;
Assert( szBspMapName );
if ( !szBspMapName || !*szBspMapName )
return NULL;
char const *szGameMode = pSettings->GetString( "game/mode", NULL );
if ( !szGameMode || !*szGameMode )
return NULL;
// Walk all the missions in that game mode
KeyValues *pModeMissions = m_pKeyValues->FindKey( CFmtStr( "GameModes/%s", szGameMode ) );
if ( !pModeMissions )
return NULL;
for ( KeyValues *pMissionName = pModeMissions->GetFirstValue(); pMissionName; pMissionName = pMissionName->GetNextValue() )
{
KeyValues *pMission = ( KeyValues * ) pMissionName->GetPtr();
if ( !pMission )
continue;
KeyValues *pChapters = pMission->FindKey( CFmtStr( "modes/%s", szGameMode ) );
if ( !pChapters )
continue;
int numChapters = pChapters->GetInt( "chapters" );
for ( int k = 1; k <= numChapters; ++ k )
{
KeyValues *pMap = pChapters->FindKey( CFmtStr( "%d", k ) );
if ( !pMap )
break;
char const *szBspName = pMap->GetString( "map" );
if ( !Q_stricmp( szBspName, szBspMapName ) )
{
if ( ppMissionInfo )
*ppMissionInfo = pMission;
return pMap;
}
}
}
return NULL;
}