//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Weapon data file parsing, shared by game & client dlls. // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include #include #include "filesystem.h" #include "utldict.h" #include "ammodef.h" #include "playerclass_info_parse.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" static CUtlDict< FilePlayerClassInfo_t*, unsigned short > m_PlayerClassInfoDatabase; #define MAX_PLAYERCLASSES 32 #ifdef _DEBUG // used to track whether or not two player classes have been mistakenly assigned the same slot bool g_bUsedPlayerClassSlots[MAX_PLAYERCLASSES] = { 0 }; #endif #ifdef DEBUG void CC_ReloadPlayerClasses_f (void) { //ResetFilePlayerClassInfoDatabase(); } static ConCommand dod_reloadplayerclasses("dod_reloadplayerclasses", CC_ReloadPlayerClasses_f, "Reset player class info cache" ); #endif //----------------------------------------------------------------------------- // Purpose: // Input : *name - // Output : FilePlayerClassInfo_t //----------------------------------------------------------------------------- static PLAYERCLASS_FILE_INFO_HANDLE FindPlayerClassInfoSlot( const char *name ) { // Complain about duplicately defined metaclass names... unsigned short lookup = m_PlayerClassInfoDatabase.Find( name ); if ( lookup != m_PlayerClassInfoDatabase.InvalidIndex() ) { return lookup; } FilePlayerClassInfo_t *insert = CreatePlayerClassInfo(); lookup = m_PlayerClassInfoDatabase.Insert( name, insert ); Assert( lookup != m_PlayerClassInfoDatabase.InvalidIndex() ); return lookup; } // Find a class slot, assuming the weapon's data has already been loaded. PLAYERCLASS_FILE_INFO_HANDLE LookupPlayerClassInfoSlot( const char *name ) { return m_PlayerClassInfoDatabase.Find( name ); } // FIXME, handle differently? static FilePlayerClassInfo_t gNullPlayerClassInfo; //----------------------------------------------------------------------------- // Purpose: // Input : handle - // Output : FilePlayerClassInfo_t //----------------------------------------------------------------------------- FilePlayerClassInfo_t *GetFilePlayerClassInfoFromHandle( PLAYERCLASS_FILE_INFO_HANDLE handle ) { if ( handle == GetInvalidPlayerClassInfoHandle() ) { Assert( !"bad index into playerclass info UtlDict" ); return &gNullPlayerClassInfo; } return m_PlayerClassInfoDatabase[ handle ]; } //----------------------------------------------------------------------------- // Purpose: // Output : PLAYERCLASS_FILE_INFO_HANDLE //----------------------------------------------------------------------------- PLAYERCLASS_FILE_INFO_HANDLE GetInvalidPlayerClassInfoHandle( void ) { return (PLAYERCLASS_FILE_INFO_HANDLE)m_PlayerClassInfoDatabase.InvalidIndex(); } void ResetFilePlayerClassInfoDatabase( void ) { m_PlayerClassInfoDatabase.PurgeAndDeleteElements(); #ifdef _DEBUG memset(g_bUsedPlayerClassSlots, 0, sizeof(g_bUsedPlayerClassSlots)); #endif } #ifndef _XBOX KeyValues* ReadEncryptedKVPlayerClassFile( IFileSystem *pFilesystem, const char *szFilenameWithoutExtension, const unsigned char *pICEKey ) { Assert( strchr( szFilenameWithoutExtension, '.' ) == NULL ); char szFullName[512]; // Open the weapon data file, and abort if we can't KeyValues *pKV = new KeyValues( "PlayerClassDatafile" ); Q_snprintf(szFullName,sizeof(szFullName), "%s.txt", szFilenameWithoutExtension); if ( !pKV->LoadFromFile( pFilesystem, szFullName, "GAME" ) ) // try to load the normal .txt file first { if ( pICEKey ) { Q_snprintf(szFullName,sizeof(szFullName), "%s.ctx", szFilenameWithoutExtension); // fall back to the .ctx file FileHandle_t f = pFilesystem->Open( szFullName, "rb", "GAME"); if (!f) { pKV->deleteThis(); return NULL; } // load file into a null-terminated buffer int fileSize = pFilesystem->Size(f); char *buffer = (char*)MemAllocScratch(fileSize + 1); Assert(buffer); pFilesystem->Read(buffer, fileSize, f); // read into local buffer buffer[fileSize] = 0; // null terminate file as EOF pFilesystem->Close( f ); // close file after reading UTIL_DecodeICE( (unsigned char*)buffer, fileSize, pICEKey ); bool retOK = pKV->LoadFromBuffer( szFullName, buffer, pFilesystem ); MemFreeScratch(); if ( !retOK ) { pKV->deleteThis(); return NULL; } } else { pKV->deleteThis(); return NULL; } } return pKV; } #endif //----------------------------------------------------------------------------- // Purpose: Read data on weapon from script file // Output: true - if data2 successfully read // false - if data load fails //----------------------------------------------------------------------------- bool ReadPlayerClassDataFromFileForSlot( IFileSystem* pFilesystem, const char *szPlayerClassName, PLAYERCLASS_FILE_INFO_HANDLE *phandle, const unsigned char *pICEKey ) { if ( !phandle ) { Assert( 0 ); return false; } *phandle = FindPlayerClassInfoSlot( szPlayerClassName ); FilePlayerClassInfo_t *pFileInfo = GetFilePlayerClassInfoFromHandle( *phandle ); Assert( pFileInfo ); if ( pFileInfo->m_bParsedScript ) return true; char sz[128]; Q_snprintf( sz, sizeof( sz ), "scripts/playerclass_%s", szPlayerClassName ); KeyValues *pKV = ReadEncryptedKVFile( pFilesystem, sz, pICEKey ); if ( !pKV ) return false; pFileInfo->Parse( pKV, szPlayerClassName ); pKV->deleteThis(); return true; } //----------------------------------------------------------------------------- // FilePlayerClassInfo_t implementation. //----------------------------------------------------------------------------- FilePlayerClassInfo_t::FilePlayerClassInfo_t() { m_bParsedScript = false; m_szPlayerClassName[0] = 0; m_szPrintName[0] = 0; m_szPlayerModel[0] = 0; m_szSelectCmd[0] = 0; } void FilePlayerClassInfo_t::Parse( KeyValues *pKeyValuesData, const char *szPlayerClassName ) { // Okay, we tried at least once to look this up... m_bParsedScript = true; // Classname Q_strncpy( m_szPlayerClassName, szPlayerClassName, MAX_WEAPON_STRING ); // Printable name Q_strncpy( m_szPrintName, pKeyValuesData->GetString( "printname", "!! Missing printname on Player Class" ), MAX_PLAYERCLASS_NAME_LENGTH ); // Player Model Q_strncpy( m_szPlayerModel, pKeyValuesData->GetString( "playermodel", "!! Missing playermodel on Player Class" ), MAX_PLAYERCLASS_NAME_LENGTH ); // Select command Q_strncpy( m_szSelectCmd, pKeyValuesData->GetString( "selectcmd", "!! Missing selectcmd on Player Class" ), 32 ); #if defined(_DEBUG) && defined(HL2_CLIENT_DLL) // Use this for class select keys /* // make sure two weapons aren't in the same slot & position if (g_bUsedPlayerClassSlots[iSlot]) { Msg( "Weapon slot info: %s (%d, %d)\n", szPrintName, iSlot, iPosition ); Warning( "Duplicately assigned weapon to slots in selection hud\n" ); } g_bUsedPlayerClassSlots[iSlot][iPosition] = true; */ #endif }