|
|
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ====
//
// Purpose:
//
//=============================================================================
#include "stdafx.h"
#include <direct.h>
#include <io.h>
#include <WorldSize.h>
#include "Gameconfig.h"
#include "GlobalFunctions.h"
#include "fgdlib/HelperInfo.h"
#include "hammer.h"
#include "KeyValues.h"
#include "MapDoc.h"
#include "MapDoc.h"
#include "MapEntity.h"
#include "MapInstance.h"
#include "MapWorld.h"
#include "filesystem_tools.h"
#include "TextureSystem.h"
#include "tier1/strtools.h"
#include "gridnav.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#pragma warning(disable:4244)
const int MAX_ERRORS = 5;
GameData *pGD; CGameConfig g_DefaultGameConfig; CGameConfig *g_pGameConfig = &g_DefaultGameConfig;
float g_MAX_MAP_COORD = 4096; float g_MIN_MAP_COORD = -4096;
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CGameConfig *CGameConfig::GetActiveGame(void) { return g_pGameConfig; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : pGame -
//-----------------------------------------------------------------------------
void CGameConfig::SetActiveGame(CGameConfig *pGame) { if (pGame != NULL) { g_pGameConfig = pGame; pGD = &pGame->GD;
if (pGame->mapformat == mfHalfLife) { g_MAX_MAP_COORD = 4096; g_MIN_MAP_COORD = -4096; } else { g_MAX_MAP_COORD = pGD->GetMaxMapCoord(); g_MIN_MAP_COORD = pGD->GetMinMapCoord(); }
CGridNav::Init( pGD->IsGridNavActive(), pGD->GetGridNavEdgeSize(), pGD->GetGridNavOffsetX(), pGD->GetGridNavOffsetY(), pGD->GetTraceHeight() ); } else { g_pGameConfig = &g_DefaultGameConfig; pGD = NULL;
g_MAX_MAP_COORD = 4096; g_MIN_MAP_COORD = -4096;
CGridNav::Init( false ); }
// Moved out of here for single config running, since we set the active
// game BEFORE initializing the file system and the texture system now.
//FileSystem_SetGame(g_pGameConfig->m_szModDir);
//g_Textures.SetActiveConfig(g_pGameConfig);
}
//-----------------------------------------------------------------------------
// Purpose: Constructor. Maintains a static counter uniquely identifying each
// game configuration.
//-----------------------------------------------------------------------------
CGameConfig::CGameConfig(void) { nGDFiles = 0; textureformat = tfNone; m_fDefaultTextureScale = DEFAULT_TEXTURE_SCALE; m_nDefaultLightmapScale = DEFAULT_LIGHTMAP_SCALE; m_MaterialExcludeCount = 0;
memset(szName, 0, sizeof(szName)); memset(szExecutable, 0, sizeof(szExecutable)); memset(szDefaultPoint, 0, sizeof(szDefaultPoint)); memset(szDefaultSolid, 0, sizeof(szDefaultSolid)); memset(szBSP, 0, sizeof(szBSP)); memset(szLIGHT, 0, sizeof(szLIGHT)); memset(szVIS, 0, sizeof(szVIS)); memset(szMapDir, 0, sizeof(szMapDir)); memset(m_szGameExeDir, 0, sizeof(m_szGameExeDir)); memset(szBSPDir, 0, sizeof(szBSPDir)); memset(m_szPrefabDir, 0, sizeof(m_szPrefabDir)); memset(m_szModDir, 0, sizeof(m_szModDir)); strcpy(m_szCordonTexture, "BLACK");
m_szSteamDir[0] = '\0'; m_szSteamAppID[0] = '\0';
static DWORD __dwID = 0; dwID = __dwID++; }
//-----------------------------------------------------------------------------
// Purpose: Imports an old binary GameCfg.wc file.
// Input : file -
// fVersion -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CGameConfig::Import(std::fstream& file, float fVersion) { file.read(szName, sizeof szName); file.read((char*)&nGDFiles, sizeof nGDFiles); file.read((char*)&textureformat, sizeof textureformat);
if (fVersion >= 1.1f) { file.read((char*)&mapformat, sizeof mapformat); } else { mapformat = mfQuake; }
//
// If reading an old (pre 1.4) format file, skip past the obselete palette
// file path.
//
if (fVersion < 1.4f) { char szPalette[128]; file.read(szPalette, sizeof szPalette); }
file.read(szExecutable, sizeof szExecutable); file.read(szDefaultSolid, sizeof szDefaultSolid); file.read(szDefaultPoint, sizeof szDefaultPoint);
if (fVersion >= 1.2f) { file.read(szBSP, sizeof szBSP); file.read(szLIGHT, sizeof szLIGHT); file.read(szVIS, sizeof szVIS); file.read(m_szGameExeDir, sizeof m_szGameExeDir); file.read(szMapDir, sizeof szMapDir); }
if (fVersion >= 1.3f) { file.read(szBSPDir, sizeof(szBSPDir)); }
if (fVersion >= 1.4f) { // CSG setting is gone now.
char szTempCSG[128]; file.read(szTempCSG, sizeof(szTempCSG));
file.read(m_szModDir, sizeof(m_szModDir)); // gamedir is gone now.
char tempGameDir[128]; file.read(tempGameDir, sizeof(tempGameDir)); }
// read game data files
char szBuf[128]; for(int i = 0; i < nGDFiles; i++) { file.read(szBuf, sizeof szBuf); GDFiles.Add(CString(szBuf)); }
LoadGDFiles(); return TRUE; }
//-----------------------------------------------------------------------------
// Purpose: Loads this game configuration from a keyvalue block.
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CGameConfig::Load(KeyValues *pkv) { char szKey[MAX_PATH];
// We should at least be able to get the game name and the game dir.
Q_strncpy(szName, pkv->GetName(), sizeof(szName)); Q_strncpy(m_szModDir, pkv->GetString("GameDir"), sizeof(m_szModDir));
// Try to get the Hammer settings.
KeyValues *pkvHammer = pkv->FindKey("Hammer"); if (!pkvHammer) return true;
//
// Load the game data filenames from the "GameData0..GameDataN" keys.
//
nGDFiles = 0; bool bAdded = true; do { sprintf(szKey, "GameData%d", nGDFiles); const char *pszGameData = pkvHammer->GetString(szKey); if (pszGameData[0] != '\0') { GDFiles.Add(pszGameData); nGDFiles++; } else { bAdded = false; }
} while (bAdded);
textureformat = (TEXTUREFORMAT)pkvHammer->GetInt("TextureFormat", tfVMT); mapformat = (MAPFORMAT)pkvHammer->GetInt("MapFormat", mfHalfLife2);
m_fDefaultTextureScale = pkvHammer->GetFloat("DefaultTextureScale", DEFAULT_TEXTURE_SCALE); if (m_fDefaultTextureScale == 0) { m_fDefaultTextureScale = DEFAULT_TEXTURE_SCALE; }
m_nDefaultLightmapScale = pkvHammer->GetInt("DefaultLightmapScale", DEFAULT_LIGHTMAP_SCALE);
Q_strncpy(szExecutable, pkvHammer->GetString("GameExe"), sizeof(szExecutable)); Q_strncpy(szDefaultSolid, pkvHammer->GetString("DefaultSolidEntity"), sizeof(szDefaultSolid)); Q_strncpy(szDefaultPoint, pkvHammer->GetString("DefaultPointEntity"), sizeof(szDefaultPoint));
Q_strncpy(szBSP, pkvHammer->GetString("BSP"), sizeof(szBSP)); Q_strncpy(szVIS, pkvHammer->GetString("Vis"), sizeof(szVIS)); Q_strncpy(szLIGHT, pkvHammer->GetString("Light"), sizeof(szLIGHT)); Q_strncpy(m_szGameExeDir, pkvHammer->GetString("GameExeDir"), sizeof(m_szGameExeDir)); Q_strncpy(szMapDir, pkvHammer->GetString("MapDir"), sizeof(szMapDir)); Q_strncpy(szBSPDir, pkvHammer->GetString("BSPDir"), sizeof(szBSPDir)); Q_strncpy(m_szPrefabDir, pkvHammer->GetString("PrefabDir"), sizeof(m_szPrefabDir));
SetCordonTexture( pkvHammer->GetString("CordonTexture", "BLACK") );
char szExcludeDir[MAX_PATH]; m_MaterialExcludeCount = pkvHammer->GetInt( "MaterialExcludeCount" ); for ( int i = 0; i < m_MaterialExcludeCount; i++ ) { sprintf( szExcludeDir, "-MaterialExcludeDir%d", i ); int index = m_MaterialExclusions.AddToTail(); Q_strncpy( m_MaterialExclusions[index].szDirectory, pkvHammer->GetString( szExcludeDir ), sizeof( m_MaterialExclusions[index].szDirectory ) ); Q_StripTrailingSlash( m_MaterialExclusions[index].szDirectory ); m_MaterialExclusions[index].bUserGenerated = true; } LoadGDFiles(); return(true); }
//-----------------------------------------------------------------------------
// Purpose: Saves this config's data into a keyvalues object.
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CGameConfig::Save(KeyValues *pkv) { pkv->SetName(szName); pkv->SetString("GameDir", m_szModDir);
// Try to get the Hammer settings.
KeyValues *pkvHammer = pkv->FindKey("Hammer"); if (pkvHammer) { pkv->RemoveSubKey(pkvHammer); pkvHammer->deleteThis(); }
pkvHammer = pkv->CreateNewKey(); if (!pkvHammer) return false;
pkvHammer->SetName("Hammer");
//
// Load the game data filenames from the "GameData0..GameDataN" keys.
//
for (int i = 0; i < nGDFiles; i++) { char szKey[MAX_PATH]; sprintf(szKey, "GameData%d", i); pkvHammer->SetString(szKey, GDFiles.GetAt(i)); }
pkvHammer->SetInt("TextureFormat", textureformat); pkvHammer->SetInt("MapFormat", mapformat); pkvHammer->SetFloat("DefaultTextureScale", m_fDefaultTextureScale); pkvHammer->SetInt("DefaultLightmapScale", m_nDefaultLightmapScale);
pkvHammer->SetString("GameExe", szExecutable); pkvHammer->SetString("DefaultSolidEntity", szDefaultSolid); pkvHammer->SetString("DefaultPointEntity", szDefaultPoint);
pkvHammer->SetString("BSP", szBSP); pkvHammer->SetString("Vis", szVIS); pkvHammer->SetString("Light", szLIGHT); pkvHammer->SetString("GameExeDir", m_szGameExeDir); pkvHammer->SetString("MapDir", szMapDir); pkvHammer->SetString("BSPDir", szBSPDir); pkvHammer->SetString("PrefabDir", m_szPrefabDir);
pkvHammer->SetString("CordonTexture", m_szCordonTexture);
char szExcludeDir[MAX_PATH]; pkvHammer->SetInt("MaterialExcludeCount", m_MaterialExcludeCount); for (int i = 0; i < m_MaterialExcludeCount; i++) { sprintf(szExcludeDir, "-MaterialExcludeDir%d", i ); pkvHammer->SetString(szExcludeDir, m_MaterialExclusions[i].szDirectory); }
return true; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : file -
//-----------------------------------------------------------------------------
void CGameConfig::Save(std::fstream &file) { file.write(szName, sizeof szName); file.write((char*)&nGDFiles, sizeof nGDFiles); file.write((char*)&textureformat, sizeof textureformat); file.write((char*)&mapformat, sizeof mapformat); file.write(szExecutable, sizeof szExecutable); file.write(szDefaultSolid, sizeof szDefaultSolid); file.write(szDefaultPoint, sizeof szDefaultPoint);
// 1.2
file.write(szBSP, sizeof szBSP); file.write(szLIGHT, sizeof szLIGHT); file.write(szVIS, sizeof szVIS); file.write(m_szGameExeDir, sizeof(m_szGameExeDir)); file.write(szMapDir, sizeof szMapDir); // 1.3
file.write(szBSPDir, sizeof szBSPDir);
// 1.4
char tempCSG[128] = ""; file.write(tempCSG, sizeof(tempCSG));
file.write(m_szModDir, sizeof(m_szModDir)); char tempGameDir[128] = ""; file.write(tempGameDir, sizeof(tempGameDir));
// write game data files
char szBuf[128]; for(int i = 0; i < nGDFiles; i++) { strcpy(szBuf, GDFiles[i]); file.write(szBuf, sizeof szBuf); } }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pConfig -
//-----------------------------------------------------------------------------
void CGameConfig::CopyFrom(CGameConfig *pConfig) { nGDFiles = pConfig->nGDFiles;
GDFiles.RemoveAll(); GDFiles.Append(pConfig->GDFiles);
strcpy(szName, pConfig->szName); strcpy(szExecutable, pConfig->szExecutable); strcpy(szDefaultPoint, pConfig->szDefaultPoint); strcpy(szDefaultSolid, pConfig->szDefaultSolid); strcpy(szBSP, pConfig->szBSP); strcpy(szLIGHT, pConfig->szLIGHT); strcpy(szVIS, pConfig->szVIS); strcpy(szMapDir, pConfig->szMapDir); strcpy(m_szGameExeDir, pConfig->m_szGameExeDir); strcpy(szBSPDir, pConfig->szBSPDir); strcpy(m_szModDir, pConfig->m_szModDir);
pConfig->m_MaterialExcludeCount = m_MaterialExcludeCount; for( int i = 0; i < m_MaterialExcludeCount; i++ ) { strcpy( m_MaterialExclusions[i].szDirectory, pConfig->m_MaterialExclusions[i].szDirectory ); } }
//-----------------------------------------------------------------------------
// Purpose:
// Input : pEntity -
// pGD -
// Output : Returns TRUE to keep enumerating.
//-----------------------------------------------------------------------------
static BOOL UpdateClassPointer(CMapEntity *pEntity, GameData *pGD) { GDclass *pClass = pGD->ClassForName(pEntity->GetClassName()); pEntity->SetClass(pClass); return(TRUE); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGameConfig::LoadGDFiles(void) { GD.ClearData(); // Save the old working directory
char szOldDir[MAX_PATH]; _getcwd( szOldDir, sizeof(szOldDir) );
// Set our working directory properly
char szAppDir[MAX_PATH]; APP()->GetDirectory( DIR_PROGRAM, szAppDir ); _chdir( szAppDir );
for (int i = 0; i < nGDFiles; i++) { GD.Load(GDFiles[i]); }
// Reset our old working directory
_chdir( szOldDir );
// All the class pointers have changed - now we have to
// reset all the class pointers in each map doc that
// uses this game.
for ( int i=0; i<CMapDoc::GetDocumentCount(); i++ ) { CMapDoc *pDoc = CMapDoc::GetDocument(i);
if (pDoc->GetGame() == this) { CMapWorld *pWorld = pDoc->GetMapWorld(); pWorld->SetClass(GD.ClassForName(pWorld->GetClassName())); pWorld->EnumChildren((ENUMMAPCHILDRENPROC)UpdateClassPointer, (DWORD)&GD, MAPCLASS_TYPE(CMapEntity)); } } }
//-----------------------------------------------------------------------------
// Purpose: Searches for the given filename, starting in szStartDir and looking
// up the directory tree.
// Input: szFile - the name of the file to search for.
// szStartDir - the folder to start searching from, towards the root.
// szFoundPath - receives the full path of the FOLDER where szFile was found.
// Output : Returns true if the file was found, false if not. If the file was
// found the full path (not including the filename) is returned in szFoundPath.
//-----------------------------------------------------------------------------
bool FindFileInTree(const char *szFile, const char *szStartDir, char *szFoundPath) { if ((szFile == NULL) || (szStartDir == NULL) || (szFoundPath == NULL)) { return false; }
char szRoot[MAX_PATH]; strcpy(szRoot, szStartDir); Q_AppendSlash(szRoot, sizeof(szRoot));
char szTemp[MAX_PATH]; do { strcpy(szTemp, szRoot); strcat(szTemp, szFile);
if (!_access(szTemp, 0)) { strcpy(szFoundPath, szRoot); Q_StripTrailingSlash(szFoundPath); return true; }
} while (Q_StripLastDir(szRoot, sizeof(szRoot)));
return false; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : *szDir -
// *szSteamDir -
// *szSteamUserDir -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool FindSteamUserDir(const char *szAppDir, const char *szSteamDir, char *szSteamUserDir) { if ((szAppDir == NULL) || (szSteamDir == NULL) || (szSteamUserDir == NULL)) { return false; }
// If the szAppDir was run from within the steam tree, we should be able to find the steam user dir.
int nSteamDirLen = strlen(szSteamDir); if (!Q_strnicmp(szAppDir, szSteamDir, nSteamDirLen ) && (szAppDir[nSteamDirLen] == '\\')) { strcpy(szSteamUserDir, szAppDir);
char *pszSlash = strchr(&szSteamUserDir[nSteamDirLen + 1], '\\'); if (pszSlash) { pszSlash++;
pszSlash = strchr(pszSlash, '\\'); if (pszSlash) { *pszSlash = '\0'; return true; } } }
szSteamUserDir[0] = '\0';
return false; }
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgoff.h"
//-----------------------------------------------------------------------------
// Purpose: Loads the settings from <mod dir>\gameinfo.txt into data members.
//-----------------------------------------------------------------------------
void CGameConfig::ParseGameInfo() { KeyValues *pkv = new KeyValues("gameinfo.txt"); if (!pkv->LoadFromFile(g_pFileSystem, "gameinfo.txt", "GAME")) { pkv->deleteThis(); return; }
KeyValues *pKey = pkv->FindKey("FileSystem"); if (pKey) { strcpy(m_szSteamAppID, pKey->GetString("SteamAppId", "")); }
const char *InstancePath = pkv->GetString( "InstancePath", NULL ); if ( InstancePath ) { CMapInstance::SetInstancePath( InstancePath ); }
pkv->deleteThis();
char szAppDir[MAX_PATH]; APP()->GetDirectory(DIR_PROGRAM, szAppDir); if (!FindFileInTree("steam.exe", szAppDir, m_szSteamDir)) { // Couldn't find steam.exe in the hammer tree
m_szSteamDir[0] = '\0'; }
if (!FindSteamUserDir(szAppDir, m_szSteamDir, m_szSteamUserDir)) { m_szSteamUserDir[0] = '\0'; } }
//-----------------------------------------------------------------------------
// Accessor methods to get at the mod + the game (*not* full paths)
//-----------------------------------------------------------------------------
const char *CGameConfig::GetMod() { // Strip path from modDir
char szModPath[MAX_PATH]; static char szMod[MAX_PATH]; Q_strncpy( szModPath, m_szModDir, MAX_PATH ); Q_StripTrailingSlash( szModPath ); if ( !szModPath[0] ) { Q_strcpy( szModPath, "hl2" ); }
Q_FileBase( szModPath, szMod, MAX_PATH );
return szMod; }
const char *CGameConfig::GetGame() { return "hl2";
// // Strip path from modDir
// char szGamePath[MAX_PATH];
// static char szGame[MAX_PATH];
// Q_strncpy( szGamePath, m_szGameDir, MAX_PATH );
// Q_StripTrailingSlash( szGamePath );
// Q_FileBase( szGamePath, szGame, MAX_PATH );
// return szGame;
}
|