source-engine/game/shared/playerclass_info_parse.cpp

248 lines
6.9 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Weapon data file parsing, shared by game & client dlls.
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include <KeyValues.h>
#include <tier0/mem.h>
#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
2022-03-01 20:00:42 +00:00
KeyValues* ReadEncryptedKVPlayerClassFile( IFileSystem *filesystem, const char *szFilenameWithoutExtension, const unsigned char *pICEKey )
2020-04-22 16:56:21 +00:00
{
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);
2022-03-01 20:00:42 +00:00
if ( !pKV->LoadFromFile( filesystem, szFullName, "GAME" ) ) // try to load the normal .txt file first
2020-04-22 16:56:21 +00:00
{
if ( pICEKey )
{
Q_snprintf(szFullName,sizeof(szFullName), "%s.ctx", szFilenameWithoutExtension); // fall back to the .ctx file
2022-03-01 20:00:42 +00:00
FileHandle_t f = filesystem->Open( szFullName, "rb", "GAME");
2020-04-22 16:56:21 +00:00
if (!f)
{
pKV->deleteThis();
return NULL;
}
// load file into a null-terminated buffer
2022-03-01 20:00:42 +00:00
int fileSize = filesystem->Size(f);
2020-04-22 16:56:21 +00:00
char *buffer = (char*)MemAllocScratch(fileSize + 1);
Assert(buffer);
2022-03-01 20:00:42 +00:00
filesystem->Read(buffer, fileSize, f); // read into local buffer
2020-04-22 16:56:21 +00:00
buffer[fileSize] = 0; // null terminate file as EOF
2022-03-01 20:00:42 +00:00
filesystem->Close( f ); // close file after reading
2020-04-22 16:56:21 +00:00
UTIL_DecodeICE( (unsigned char*)buffer, fileSize, pICEKey );
2022-03-01 20:00:42 +00:00
bool retOK = pKV->LoadFromBuffer( szFullName, buffer, filesystem );
2020-04-22 16:56:21 +00:00
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
//-----------------------------------------------------------------------------
2022-03-01 20:00:42 +00:00
bool ReadPlayerClassDataFromFileForSlot( IFileSystem* filesystem, const char *szPlayerClassName, PLAYERCLASS_FILE_INFO_HANDLE *phandle, const unsigned char *pICEKey )
2020-04-22 16:56:21 +00:00
{
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 );
2022-03-01 20:00:42 +00:00
KeyValues *pKV = ReadEncryptedKVFile( filesystem, sz, pICEKey );
2020-04-22 16:56:21 +00:00
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
}