1
This commit is contained in:
40
fgdlib/fgdlib.vpc
Normal file
40
fgdlib/fgdlib.vpc
Normal file
@ -0,0 +1,40 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// FGDLIB.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Macro SRCDIR ".."
|
||||
$Include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$AdditionalIncludeDirectories "$BASE,$SRCDIR\utils\common"
|
||||
}
|
||||
}
|
||||
|
||||
$Project "Fgdlib"
|
||||
{
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "gamedata.cpp"
|
||||
$File "gdclass.cpp"
|
||||
$File "gdvar.cpp"
|
||||
$File "inputoutput.cpp"
|
||||
$File "wckeyvalues.cpp"
|
||||
}
|
||||
|
||||
$Folder "Header Files"
|
||||
{
|
||||
$File "$SRCDIR\public\fgdlib\fgdlib.h"
|
||||
$File "$SRCDIR\public\fgdlib\gamedata.h"
|
||||
$File "$SRCDIR\public\fgdlib\gdclass.h"
|
||||
$File "$SRCDIR\public\fgdlib\gdvar.h"
|
||||
$File "$SRCDIR\public\fgdlib\helperinfo.h"
|
||||
$File "$SRCDIR\public\fgdlib\ieditortexture.h"
|
||||
$File "$SRCDIR\public\fgdlib\inputoutput.h"
|
||||
$File "$SRCDIR\public\fgdlib\wckeyvalues.h"
|
||||
}
|
||||
}
|
886
fgdlib/gamedata.cpp
Normal file
886
fgdlib/gamedata.cpp
Normal file
@ -0,0 +1,886 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include <windows.h>
|
||||
#include <tier0/dbg.h>
|
||||
#include <io.h>
|
||||
#include <WorldSize.h>
|
||||
#include "fgdlib/GameData.h"
|
||||
#include "fgdlib/HelperInfo.h"
|
||||
#include "KeyValues.h"
|
||||
#include "filesystem_tools.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "utlmap.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;
|
||||
|
||||
|
||||
static GameDataMessageFunc_t g_pMsgFunc = NULL;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets the function used for emitting error messages while loading gamedata files.
|
||||
//-----------------------------------------------------------------------------
|
||||
void GDSetMessageFunc(GameDataMessageFunc_t pFunc)
|
||||
{
|
||||
g_pMsgFunc = pFunc;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fetches the next token from the file.
|
||||
// Input : tr -
|
||||
// ppszStore - Destination buffer, one of the following:
|
||||
// pointer to NULL - token will be placed in an allocated buffer
|
||||
// pointer to non-NULL buffer - token will be placed in buffer
|
||||
// ttexpecting -
|
||||
// pszExpecting -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool DoGetToken(TokenReader &tr, char **ppszStore, int nSize, trtoken_t ttexpecting, const char *pszExpecting)
|
||||
{
|
||||
trtoken_t ttype;
|
||||
|
||||
if (*ppszStore != NULL)
|
||||
{
|
||||
// Reads the token into the given buffer.
|
||||
ttype = tr.NextToken(*ppszStore, nSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Allocates a buffer to hold the token.
|
||||
ttype = tr.NextTokenDynamic(ppszStore);
|
||||
}
|
||||
|
||||
if (ttype == TOKENSTRINGTOOLONG)
|
||||
{
|
||||
GDError(tr, "unterminated string or string too long");
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Check for a bad token type.
|
||||
//
|
||||
char *pszStore = *ppszStore;
|
||||
bool bBadTokenType = false;
|
||||
if ((ttype != ttexpecting) && (ttexpecting != TOKENNONE))
|
||||
{
|
||||
//
|
||||
// If we were expecting a string and got an integer, don't worry about it.
|
||||
// We can translate from integer to string.
|
||||
//
|
||||
if (!((ttexpecting == STRING) && (ttype == INTEGER)))
|
||||
{
|
||||
bBadTokenType = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bBadTokenType && (pszExpecting == NULL))
|
||||
{
|
||||
//
|
||||
// We didn't get the expected token type but no expected
|
||||
// string was specified.
|
||||
//
|
||||
char *pszTokenName;
|
||||
switch (ttexpecting)
|
||||
{
|
||||
case IDENT:
|
||||
{
|
||||
pszTokenName = "identifier";
|
||||
break;
|
||||
}
|
||||
|
||||
case INTEGER:
|
||||
{
|
||||
pszTokenName = "integer";
|
||||
break;
|
||||
}
|
||||
|
||||
case STRING:
|
||||
{
|
||||
pszTokenName = "string";
|
||||
break;
|
||||
}
|
||||
|
||||
case OPERATOR:
|
||||
default:
|
||||
{
|
||||
pszTokenName = "symbol";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GDError(tr, "expecting %s", pszTokenName);
|
||||
return false;
|
||||
}
|
||||
else if (bBadTokenType || ((pszExpecting != NULL) && !IsToken(pszStore, pszExpecting)))
|
||||
{
|
||||
//
|
||||
// An expected string was specified, and we got either the wrong type or
|
||||
// the right type but the wrong string,
|
||||
//
|
||||
GDError(tr, "expecting '%s', but found '%s'", pszExpecting, pszStore);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : tr -
|
||||
// error -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GDError(TokenReader &tr, const char *error, ...)
|
||||
{
|
||||
char szBuf[128];
|
||||
va_list vl;
|
||||
va_start(vl, error);
|
||||
vsprintf(szBuf, error, vl);
|
||||
va_end(vl);
|
||||
|
||||
if (g_pMsgFunc)
|
||||
{
|
||||
// HACK: should use an enumeration for error level
|
||||
g_pMsgFunc(1, tr.Error(szBuf));
|
||||
}
|
||||
|
||||
if (tr.GetErrorCount() >= MAX_ERRORS)
|
||||
{
|
||||
if (g_pMsgFunc)
|
||||
{
|
||||
// HACK: should use an enumeration for error level
|
||||
g_pMsgFunc(1, " - too many errors; aborting.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fetches the next token from the file.
|
||||
// Input : tr - The token reader object with which to fetch the token.
|
||||
// pszStore - Buffer in which to place the token, NULL to discard the token.
|
||||
// ttexpecting - The token type that we are expecting. If this is not TOKENNONE
|
||||
// and token type read is different, the operation will fail.
|
||||
// pszExpecting - The token string that we are expecting. If this string
|
||||
// is not NULL and the token string read is different, the operation will fail.
|
||||
// Output : Returns TRUE if the operation succeeded, FALSE if there was an error.
|
||||
// If there was an error, the error will be reported in the message window.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GDGetToken(TokenReader &tr, char *pszStore, int nSize, trtoken_t ttexpecting, const char *pszExpecting)
|
||||
{
|
||||
Assert(pszStore != NULL);
|
||||
if (pszStore != NULL)
|
||||
{
|
||||
return DoGetToken(tr, &pszStore, nSize, ttexpecting, pszExpecting);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fetches the next token from the file.
|
||||
// Input : tr - The token reader object with which to fetch the token.
|
||||
// pszStore - Buffer in which to place the token, NULL to discard the token.
|
||||
// ttexpecting - The token type that we are expecting. If this is not TOKENNONE
|
||||
// and token type read is different, the operation will fail.
|
||||
// pszExpecting - The token string that we are expecting. If this string
|
||||
// is not NULL and the token string read is different, the operation will fail.
|
||||
// Output : Returns TRUE if the operation succeeded, FALSE if there was an error.
|
||||
// If there was an error, the error will be reported in the message window.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GDSkipToken(TokenReader &tr, trtoken_t ttexpecting, const char *pszExpecting)
|
||||
{
|
||||
//
|
||||
// Read the next token into a buffer and discard it.
|
||||
//
|
||||
char szDiscardBuf[MAX_TOKEN];
|
||||
char *pszDiscardBuf = szDiscardBuf;
|
||||
return DoGetToken(tr, &pszDiscardBuf, sizeof(szDiscardBuf), ttexpecting, pszExpecting);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Fetches the next token from the file, allocating a buffer exactly
|
||||
// large enough to hold the token.
|
||||
// Input : tr -
|
||||
// ppszStore -
|
||||
// ttexpecting -
|
||||
// pszExpecting -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GDGetTokenDynamic(TokenReader &tr, char **ppszStore, trtoken_t ttexpecting, const char *pszExpecting)
|
||||
{
|
||||
if (ppszStore == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*ppszStore = NULL;
|
||||
return DoGetToken(tr, ppszStore, -1, ttexpecting, pszExpecting);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
GameData::GameData(void)
|
||||
{
|
||||
m_nMaxMapCoord = 8192;
|
||||
m_nMinMapCoord = -8192;
|
||||
m_InstanceClass = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
GameData::~GameData(void)
|
||||
{
|
||||
ClearData();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void GameData::ClearData(void)
|
||||
{
|
||||
// delete classes.
|
||||
int nCount = m_Classes.Count();
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
GDclass *pm = m_Classes.Element(i);
|
||||
delete pm;
|
||||
}
|
||||
m_Classes.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Loads a gamedata (FGD) file into this object.
|
||||
// Input : pszFilename -
|
||||
// Output : Returns TRUE on success, FALSE on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL GameData::Load(const char *pszFilename)
|
||||
{
|
||||
TokenReader tr;
|
||||
|
||||
if(GetFileAttributes(pszFilename) == 0xffffffff)
|
||||
return FALSE;
|
||||
|
||||
if(!tr.Open(pszFilename))
|
||||
return FALSE;
|
||||
|
||||
trtoken_t ttype;
|
||||
char szToken[128];
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (tr.GetErrorCount() >= MAX_ERRORS)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ttype = tr.NextToken(szToken, sizeof(szToken));
|
||||
|
||||
if(ttype == TOKENEOF)
|
||||
break;
|
||||
|
||||
if(ttype != OPERATOR || !IsToken(szToken, "@"))
|
||||
{
|
||||
if(!GDError(tr, "expected @"))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check what kind it is, and parse a new object
|
||||
if (tr.NextToken(szToken, sizeof(szToken)) != IDENT)
|
||||
{
|
||||
if(!GDError(tr, "expected identifier after @"))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (IsToken(szToken, "baseclass") || IsToken(szToken, "pointclass") || IsToken(szToken, "solidclass") || IsToken(szToken, "keyframeclass") ||
|
||||
IsToken(szToken, "moveclass") || IsToken(szToken, "npcclass") || IsToken(szToken, "filterclass"))
|
||||
{
|
||||
//
|
||||
// New class.
|
||||
//
|
||||
GDclass *pNewClass = new GDclass;
|
||||
if (!pNewClass->InitFromTokens(tr, this))
|
||||
{
|
||||
tr.IgnoreTill(OPERATOR, "@"); // go to next section
|
||||
delete pNewClass;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsToken(szToken, "baseclass")) // Not directly available to user.
|
||||
{
|
||||
pNewClass->SetBaseClass(true);
|
||||
}
|
||||
else if (IsToken(szToken, "pointclass")) // Generic point class.
|
||||
{
|
||||
pNewClass->SetPointClass(true);
|
||||
}
|
||||
else if (IsToken(szToken, "solidclass")) // Tied to solids.
|
||||
{
|
||||
pNewClass->SetSolidClass(true);
|
||||
}
|
||||
else if (IsToken(szToken, "npcclass")) // NPC class - can be spawned by npc_maker.
|
||||
{
|
||||
pNewClass->SetPointClass(true);
|
||||
pNewClass->SetNPCClass(true);
|
||||
}
|
||||
else if (IsToken(szToken, "filterclass")) // Filter class - can be used as a filter
|
||||
{
|
||||
pNewClass->SetPointClass(true);
|
||||
pNewClass->SetFilterClass(true);
|
||||
}
|
||||
else if (IsToken(szToken, "moveclass")) // Animating
|
||||
{
|
||||
pNewClass->SetMoveClass(true);
|
||||
pNewClass->SetPointClass(true);
|
||||
}
|
||||
else if (IsToken(szToken, "keyframeclass")) // Animation keyframes
|
||||
{
|
||||
pNewClass->SetKeyFrameClass(true);
|
||||
pNewClass->SetPointClass(true);
|
||||
}
|
||||
|
||||
// Check and see if this new class matches an existing one. If so we will override the previous definition.
|
||||
int nExistingClassIndex = 0;
|
||||
GDclass *pExistingClass = ClassForName(pNewClass->GetName(), &nExistingClassIndex);
|
||||
if (NULL != pExistingClass)
|
||||
{
|
||||
m_Classes.InsertAfter(nExistingClassIndex, pNewClass);
|
||||
m_Classes.Remove(nExistingClassIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Classes.AddToTail(pNewClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsToken(szToken, "include"))
|
||||
{
|
||||
if (GDGetToken(tr, szToken, sizeof(szToken), STRING))
|
||||
{
|
||||
// Let's assume it's in the same directory.
|
||||
char justPath[MAX_PATH], loadFilename[MAX_PATH];
|
||||
if ( Q_ExtractFilePath( pszFilename, justPath, sizeof( justPath ) ) )
|
||||
{
|
||||
Q_snprintf( loadFilename, sizeof( loadFilename ), "%s%s", justPath, szToken );
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_strncpy( loadFilename, szToken, sizeof( loadFilename ) );
|
||||
}
|
||||
|
||||
// First try our fully specified directory
|
||||
if (!Load(loadFilename))
|
||||
{
|
||||
// Failing that, try our start directory
|
||||
if (!Load(szToken))
|
||||
{
|
||||
GDError(tr, "error including file: %s", szToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsToken(szToken, "mapsize"))
|
||||
{
|
||||
if (!ParseMapSize(tr))
|
||||
{
|
||||
// Error in map size specifier, skip to next @ sign.
|
||||
tr.IgnoreTill(OPERATOR, "@");
|
||||
}
|
||||
}
|
||||
else if ( IsToken( szToken, "materialexclusion" ) )
|
||||
{
|
||||
if ( !LoadFGDMaterialExclusions( tr ) )
|
||||
{
|
||||
// FGD exclusions not defined; skip to next @ sign.
|
||||
tr.IgnoreTill(OPERATOR, "@");
|
||||
}
|
||||
}
|
||||
else if ( IsToken( szToken, "autovisgroup" ) )
|
||||
{
|
||||
if ( !LoadFGDAutoVisGroups( tr ) )
|
||||
{
|
||||
// FGD AutoVisGroups not defined; skip to next @ sign.
|
||||
tr.IgnoreTill(OPERATOR, "@");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GDError(tr, "unrecognized section name %s", szToken);
|
||||
tr.IgnoreTill(OPERATOR, "@");
|
||||
}
|
||||
}
|
||||
|
||||
if (tr.GetErrorCount() > 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tr.Close();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Parses the "mapsize" specifier, which should be of the form:
|
||||
//
|
||||
// mapsize(min, max)
|
||||
//
|
||||
// ex: mapsize(-8192, 8192)
|
||||
//
|
||||
// Input : tr -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GameData::ParseMapSize(TokenReader &tr)
|
||||
{
|
||||
if (!GDSkipToken(tr, OPERATOR, "("))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
char szToken[128];
|
||||
if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int nMin = atoi(szToken);
|
||||
|
||||
if (!GDSkipToken(tr, OPERATOR, ","))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int nMax = atoi(szToken);
|
||||
|
||||
if (nMin != nMax)
|
||||
{
|
||||
m_nMinMapCoord = min(nMin, nMax);
|
||||
m_nMaxMapCoord = max(nMin, nMax);
|
||||
}
|
||||
|
||||
if (!GDSkipToken(tr, OPERATOR, ")"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszName -
|
||||
// piIndex -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
GDclass *GameData::ClassForName(const char *pszName, int *piIndex)
|
||||
{
|
||||
int nCount = m_Classes.Count();
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
GDclass *mp = m_Classes.Element(i);
|
||||
if(!strcmp(mp->GetName(), pszName))
|
||||
{
|
||||
if(piIndex)
|
||||
piIndex[0] = i;
|
||||
return mp;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// These are 'standard' keys that every entity uses, but they aren't specified that way in the .fgd
|
||||
static const char *RequiredKeys[] =
|
||||
{
|
||||
"Origin",
|
||||
"Angles",
|
||||
NULL
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: this function will set up the initial class about to be instanced
|
||||
// Input : pszClassName - the class name of the entity to be instanced
|
||||
// pszInstancePrefix - the prefix to be used for all name fields
|
||||
// Origin - the origin offset of the instance
|
||||
// Angles - the angle rotation of the instance
|
||||
// Output : if successful, will return the game data class of the class name
|
||||
//-----------------------------------------------------------------------------
|
||||
GDclass *GameData::BeginInstanceRemap( const char *pszClassName, const char *pszInstancePrefix, Vector &Origin, QAngle &Angle )
|
||||
{
|
||||
m_InstanceOrigin = Origin;
|
||||
m_InstanceAngle = Angle;
|
||||
AngleMatrix( m_InstanceAngle, m_InstanceOrigin, m_InstanceMat );
|
||||
|
||||
strcpy( m_InstancePrefix, pszInstancePrefix );
|
||||
|
||||
if ( m_InstanceClass )
|
||||
{
|
||||
delete m_InstanceClass;
|
||||
m_InstanceClass = NULL;
|
||||
}
|
||||
|
||||
if ( strcmpi( pszClassName, "info_overlay_accessor" ) == 0 )
|
||||
{ // yucky hack for a made up entity in the bsp process
|
||||
pszClassName = "info_overlay";
|
||||
}
|
||||
|
||||
GDclass *BaseClass = ClassForName( pszClassName );
|
||||
if ( BaseClass )
|
||||
{
|
||||
m_InstanceClass = new GDclass();
|
||||
m_InstanceClass->Parent = this;
|
||||
m_InstanceClass->AddBase( BaseClass );
|
||||
|
||||
for( int i = 0; RequiredKeys[ i ]; i++ )
|
||||
{
|
||||
if ( m_InstanceClass->VarForName( RequiredKeys[ i ] ) == NULL )
|
||||
{
|
||||
BaseClass = ClassForName( RequiredKeys[ i ] );
|
||||
if ( BaseClass )
|
||||
{
|
||||
m_InstanceClass->AddBase( BaseClass );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_InstanceClass = NULL;
|
||||
}
|
||||
|
||||
return m_InstanceClass;
|
||||
}
|
||||
|
||||
|
||||
enum tRemapOperation
|
||||
{
|
||||
REMAP_NAME = 0,
|
||||
REMAP_POSITION,
|
||||
REMAP_ANGLE,
|
||||
REMAP_ANGLE_NEGATIVE_PITCH,
|
||||
};
|
||||
|
||||
|
||||
static CUtlMap< GDIV_TYPE, tRemapOperation > RemapOperation;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: function to sort the class type for the RemapOperations map
|
||||
// Input : type1 - the first type to compare against
|
||||
// type2 - the second type to compare against
|
||||
// Output : returns true if the first type is less than the second one
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool CUtlType_LessThan( const GDIV_TYPE &type1, const GDIV_TYPE &type2 )
|
||||
{
|
||||
return ( type1 < type2 );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: this function will attempt to remap a key's value
|
||||
// Input : pszKey - the name of the key
|
||||
// pszInvalue - the original value
|
||||
// AllowNameRemapping - only do name remapping if this parameter is true.
|
||||
// this is generally only false on the instance level.
|
||||
// Output : returns true if the value changed
|
||||
// pszOutValue - the new value if changed
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GameData::RemapKeyValue( const char *pszKey, const char *pszInValue, char *pszOutValue, TNameFixup NameFixup )
|
||||
{
|
||||
if ( RemapOperation.Count() == 0 )
|
||||
{
|
||||
RemapOperation.SetLessFunc( &CUtlType_LessThan );
|
||||
RemapOperation.Insert( ivAngle, REMAP_ANGLE );
|
||||
RemapOperation.Insert( ivTargetDest, REMAP_NAME );
|
||||
RemapOperation.Insert( ivTargetSrc, REMAP_NAME );
|
||||
RemapOperation.Insert( ivOrigin, REMAP_POSITION );
|
||||
RemapOperation.Insert( ivAxis, REMAP_ANGLE );
|
||||
RemapOperation.Insert( ivAngleNegativePitch, REMAP_ANGLE_NEGATIVE_PITCH );
|
||||
}
|
||||
|
||||
if ( !m_InstanceClass )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GDinputvariable *KVVar = m_InstanceClass->VarForName( pszKey );
|
||||
if ( !KVVar )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GDIV_TYPE KVType = KVVar->GetType();
|
||||
int KVRemapIndex = RemapOperation.Find( KVType );
|
||||
if ( KVRemapIndex == RemapOperation.InvalidIndex() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy( pszOutValue, pszInValue );
|
||||
|
||||
switch( RemapOperation[ KVRemapIndex ] )
|
||||
{
|
||||
case REMAP_NAME:
|
||||
if ( KVType != ivInstanceVariable )
|
||||
{
|
||||
RemapNameField( pszInValue, pszOutValue, NameFixup );
|
||||
}
|
||||
break;
|
||||
|
||||
case REMAP_POSITION:
|
||||
{
|
||||
Vector inPoint( 0.0f, 0.0f, 0.0f ), outPoint;
|
||||
|
||||
sscanf ( pszInValue, "%f %f %f", &inPoint.x, &inPoint.y, &inPoint.z );
|
||||
VectorTransform( inPoint, m_InstanceMat, outPoint );
|
||||
sprintf( pszOutValue, "%g %g %g", outPoint.x, outPoint.y, outPoint.z );
|
||||
}
|
||||
break;
|
||||
|
||||
case REMAP_ANGLE:
|
||||
if ( m_InstanceAngle.x != 0.0f || m_InstanceAngle.y != 0.0f || m_InstanceAngle.z != 0.0f )
|
||||
{
|
||||
QAngle inAngles( 0.0f, 0.0f, 0.0f ), outAngles;
|
||||
matrix3x4_t angToWorld, localMatrix;
|
||||
|
||||
sscanf ( pszInValue, "%f %f %f", &inAngles.x, &inAngles.y, &inAngles.z );
|
||||
|
||||
AngleMatrix( inAngles, angToWorld );
|
||||
MatrixMultiply( m_InstanceMat, angToWorld, localMatrix );
|
||||
MatrixAngles( localMatrix, outAngles );
|
||||
|
||||
sprintf( pszOutValue, "%g %g %g", outAngles.x, outAngles.y, outAngles.z );
|
||||
}
|
||||
break;
|
||||
|
||||
case REMAP_ANGLE_NEGATIVE_PITCH:
|
||||
if ( m_InstanceAngle.x != 0.0f || m_InstanceAngle.y != 0.0f || m_InstanceAngle.z != 0.0f )
|
||||
{
|
||||
QAngle inAngles( 0.0f, 0.0f, 0.0f ), outAngles;
|
||||
matrix3x4_t angToWorld, localMatrix;
|
||||
|
||||
sscanf ( pszInValue, "%f", &inAngles.x ); // just the pitch
|
||||
inAngles.x = -inAngles.x;
|
||||
|
||||
AngleMatrix( inAngles, angToWorld );
|
||||
MatrixMultiply( m_InstanceMat, angToWorld, localMatrix );
|
||||
MatrixAngles( localMatrix, outAngles );
|
||||
|
||||
sprintf( pszOutValue, "%g", -outAngles.x ); // just the pitch
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ( strcmpi( pszInValue, pszOutValue ) != 0 );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: this function will attempt to remap a name field.
|
||||
// Input : pszInvalue - the original value
|
||||
// AllowNameRemapping - only do name remapping if this parameter is true.
|
||||
// this is generally only false on the instance level.
|
||||
// Output : returns true if the value changed
|
||||
// pszOutValue - the new value if changed
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GameData::RemapNameField( const char *pszInValue, char *pszOutValue, TNameFixup NameFixup )
|
||||
{
|
||||
strcpy( pszOutValue, pszInValue );
|
||||
|
||||
if ( pszInValue[ 0 ] && pszInValue[ 0 ] != '@' )
|
||||
{ // ! at the start of a value means it is global and should not be remaped
|
||||
switch( NameFixup )
|
||||
{
|
||||
case NAME_FIXUP_PREFIX:
|
||||
sprintf( pszOutValue, "%s-%s", m_InstancePrefix, pszInValue );
|
||||
break;
|
||||
|
||||
case NAME_FIXUP_POSTFIX:
|
||||
sprintf( pszOutValue, "%s-%s", pszInValue, m_InstancePrefix );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ( strcmpi( pszInValue, pszOutValue ) != 0 );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gathers any FGD-defined material directory exclusions
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GameData::LoadFGDMaterialExclusions( TokenReader &tr )
|
||||
{
|
||||
if ( !GDSkipToken( tr, OPERATOR, "[" ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
while ( 1 )
|
||||
{
|
||||
char szToken[128];
|
||||
bool bMatchFound = false;
|
||||
|
||||
if ( tr.PeekTokenType( szToken, sizeof( szToken ) ) == OPERATOR )
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if ( GDGetToken( tr, szToken, sizeof( szToken ), STRING ) )
|
||||
{
|
||||
// Make sure we haven't loaded this from another FGD
|
||||
for ( int i = 0; i < m_FGDMaterialExclusions.Count(); i++ )
|
||||
{
|
||||
if ( !stricmp( szToken, m_FGDMaterialExclusions[i].szDirectory ) )
|
||||
{
|
||||
bMatchFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the string
|
||||
if ( bMatchFound == false )
|
||||
{
|
||||
int index = m_FGDMaterialExclusions.AddToTail();
|
||||
Q_strncpy( m_FGDMaterialExclusions[index].szDirectory, szToken, sizeof( m_FGDMaterialExclusions[index].szDirectory ) );
|
||||
m_FGDMaterialExclusions[index].bUserGenerated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Closing square brace.
|
||||
//
|
||||
if ( !GDSkipToken( tr, OPERATOR, "]" ) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gathers any FGD-defined Auto VisGroups
|
||||
// Input :
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
bool GameData::LoadFGDAutoVisGroups( TokenReader &tr )
|
||||
{
|
||||
int gindex = 0; // Index of AutoVisGroups
|
||||
int cindex = 0; // Index of Classes
|
||||
|
||||
char szToken[128];
|
||||
|
||||
// Handle the Parent -- World Geometry, Entities, World Detail
|
||||
if ( GDSkipToken( tr, OPERATOR, "=" ) )
|
||||
{
|
||||
// We expect a name
|
||||
if ( !GDGetToken( tr, szToken, sizeof( szToken ), STRING ) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
gindex = m_FGDAutoVisGroups.AddToTail();
|
||||
Q_strncpy( m_FGDAutoVisGroups[gindex].szParent, szToken, sizeof( m_FGDAutoVisGroups[gindex].szParent ) );
|
||||
|
||||
// We expect a Class
|
||||
if ( !GDSkipToken( tr, OPERATOR, "[" ) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the Class(es) -- Brush Entities, Occluders, Lights
|
||||
while ( 1 )
|
||||
{
|
||||
if ( GDGetToken( tr, szToken, sizeof( szToken ), STRING ) )
|
||||
{
|
||||
cindex = m_FGDAutoVisGroups[gindex].m_Classes.AddToTail();
|
||||
Q_strncpy( m_FGDAutoVisGroups[gindex].m_Classes[cindex].szClass, szToken, sizeof( m_FGDAutoVisGroups[gindex].m_Classes[cindex].szClass ) );
|
||||
|
||||
if ( !GDSkipToken( tr, OPERATOR, "[" ) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
// Parse objects/entities -- func_detail, point_template, light_spot
|
||||
while ( 1 )
|
||||
{
|
||||
if ( tr.PeekTokenType( szToken, sizeof( szToken ) ) == OPERATOR )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ( !GDGetToken( tr, szToken, sizeof( szToken ), STRING ) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
m_FGDAutoVisGroups[gindex].m_Classes[cindex].szEntities.CopyAndAddToTail( szToken );
|
||||
|
||||
}
|
||||
|
||||
if ( !GDSkipToken( tr, OPERATOR, "]" ) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
// See if we have another Class coming up
|
||||
if ( tr.PeekTokenType( szToken, sizeof( szToken ) ) == STRING )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If no more Classes, we now expect a terminating ']'
|
||||
if ( !GDSkipToken( tr, OPERATOR, "]" ) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
// We're done
|
||||
return true;
|
||||
}
|
||||
// We don't have another Class; look for a terminating brace
|
||||
else
|
||||
{
|
||||
if ( !GDSkipToken( tr, OPERATOR, "]" ) )
|
||||
{
|
||||
return( FALSE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Safety net
|
||||
GDError( tr, "Malformed AutoVisGroup -- Last processed: %s", szToken );
|
||||
return( FALSE );
|
||||
}
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgoff.h"
|
1041
fgdlib/gdclass.cpp
Normal file
1041
fgdlib/gdclass.cpp
Normal file
File diff suppressed because it is too large
Load Diff
729
fgdlib/gdvar.cpp
Normal file
729
fgdlib/gdvar.cpp
Normal file
@ -0,0 +1,729 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "fgdlib/fgdlib.h"
|
||||
#include "fgdlib/GameData.h"
|
||||
#include "fgdlib/WCKeyValues.h"
|
||||
#include "fgdlib/gdvar.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GDIV_TYPE eType; // The enumeration of this type.
|
||||
char *pszName; // The name of this type.
|
||||
trtoken_t eStoreAs; // How this type is stored (STRING, INTEGER, etc).
|
||||
} TypeMap_t;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Maps type names to type enums and parsing logic for values.
|
||||
//-----------------------------------------------------------------------------
|
||||
static TypeMap_t TypeMap[] =
|
||||
{
|
||||
{ ivAngle, "angle", STRING },
|
||||
{ ivChoices, "choices", STRING },
|
||||
{ ivColor1, "color1", STRING },
|
||||
{ ivColor255, "color255", STRING },
|
||||
{ ivDecal, "decal", STRING },
|
||||
{ ivFlags, "flags", INTEGER },
|
||||
{ ivInteger, "integer", INTEGER },
|
||||
{ ivSound, "sound", STRING },
|
||||
{ ivSprite, "sprite", STRING },
|
||||
{ ivString, "string", STRING },
|
||||
{ ivStudioModel, "studio", STRING },
|
||||
{ ivTargetDest, "target_destination", STRING },
|
||||
{ ivTargetSrc, "target_source", STRING },
|
||||
{ ivTargetNameOrClass, "target_name_or_class", STRING }, // Another version of target_destination that accepts class names
|
||||
{ ivVector, "vector", STRING },
|
||||
{ ivNPCClass, "npcclass", STRING },
|
||||
{ ivFilterClass, "filterclass", STRING },
|
||||
{ ivFloat, "float", STRING },
|
||||
{ ivMaterial, "material", STRING },
|
||||
{ ivScene, "scene", STRING },
|
||||
{ ivSide, "side", STRING },
|
||||
{ ivSideList, "sidelist", STRING },
|
||||
{ ivOrigin, "origin", STRING },
|
||||
{ ivAxis, "axis", STRING },
|
||||
{ ivVecLine, "vecline", STRING },
|
||||
{ ivPointEntityClass, "pointentityclass", STRING },
|
||||
{ ivNodeDest, "node_dest", INTEGER },
|
||||
{ ivInstanceFile, "instance_file", STRING },
|
||||
{ ivAngleNegativePitch, "angle_negative_pitch", STRING },
|
||||
{ ivInstanceVariable, "instance_variable", STRING },
|
||||
{ ivInstanceParm, "instance_parm", STRING },
|
||||
};
|
||||
|
||||
|
||||
char *GDinputvariable::m_pszEmpty = "";
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
GDinputvariable::GDinputvariable(void)
|
||||
{
|
||||
m_szDefault[0] = 0;
|
||||
m_nDefault = 0;
|
||||
m_szValue[0] = 0;
|
||||
m_bReportable = FALSE;
|
||||
m_bReadOnly = false;
|
||||
m_pszDescription = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: construct generally used for creating a temp instance parm type
|
||||
// Input : szType - the textual type of this variable
|
||||
// szName - the name description of this variable
|
||||
//-----------------------------------------------------------------------------
|
||||
GDinputvariable::GDinputvariable( const char *szType, const char *szName )
|
||||
{
|
||||
m_szDefault[0] = 0;
|
||||
m_nDefault = 0;
|
||||
m_szValue[0] = 0;
|
||||
m_bReportable = FALSE;
|
||||
m_bReadOnly = false;
|
||||
m_pszDescription = NULL;
|
||||
|
||||
m_eType = GetTypeFromToken( szType );
|
||||
strcpy( m_szName, szName );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
GDinputvariable::~GDinputvariable(void)
|
||||
{
|
||||
delete [] m_pszDescription;
|
||||
m_Items.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Implements the copy operator.
|
||||
//-----------------------------------------------------------------------------
|
||||
GDinputvariable &GDinputvariable::operator =(GDinputvariable &Other)
|
||||
{
|
||||
m_eType = Other.GetType();
|
||||
strcpy(m_szName, Other.m_szName);
|
||||
strcpy(m_szLongName, Other.m_szLongName);
|
||||
strcpy(m_szDefault, Other.m_szDefault);
|
||||
|
||||
//
|
||||
// Copy the description.
|
||||
//
|
||||
delete [] m_pszDescription;
|
||||
if (Other.m_pszDescription != NULL)
|
||||
{
|
||||
m_pszDescription = new char[strlen(Other.m_pszDescription) + 1];
|
||||
strcpy(m_pszDescription, Other.m_pszDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pszDescription = NULL;
|
||||
}
|
||||
|
||||
m_nDefault = Other.m_nDefault;
|
||||
m_bReportable = Other.m_bReportable;
|
||||
m_bReadOnly = Other.m_bReadOnly;
|
||||
|
||||
m_Items.RemoveAll();
|
||||
|
||||
int nCount = Other.m_Items.Count();
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
m_Items.AddToTail(Other.m_Items.Element(i));
|
||||
}
|
||||
|
||||
return(*this);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the storage format of a given variable type.
|
||||
// Input : pszToken - Sting containing the token.
|
||||
// Output : GDIV_TYPE corresponding to the token in the string, ivBadType if the
|
||||
// string does not correspond to a valid type.
|
||||
//-----------------------------------------------------------------------------
|
||||
trtoken_t GDinputvariable::GetStoreAsFromType(GDIV_TYPE eType)
|
||||
{
|
||||
for (int i = 0; i < sizeof(TypeMap) / sizeof(TypeMap[0]); i++)
|
||||
{
|
||||
if (TypeMap[i].eType == eType)
|
||||
{
|
||||
return(TypeMap[i].eStoreAs);
|
||||
}
|
||||
}
|
||||
|
||||
Assert(FALSE);
|
||||
return(STRING);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the enumerated type of a string token.
|
||||
// Input : pszToken - Sting containing the token.
|
||||
// Output : GDIV_TYPE corresponding to the token in the string, ivBadType if the
|
||||
// string does not correspond to a valid type.
|
||||
//-----------------------------------------------------------------------------
|
||||
GDIV_TYPE GDinputvariable::GetTypeFromToken(const char *pszToken)
|
||||
{
|
||||
for (int i = 0; i < sizeof(TypeMap) / sizeof(TypeMap[0]); i++)
|
||||
{
|
||||
if (IsToken(pszToken, TypeMap[i].pszName))
|
||||
{
|
||||
return(TypeMap[i].eType);
|
||||
}
|
||||
}
|
||||
|
||||
return(ivBadType);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns a string representing the type of this variable, eg. "integer".
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *GDinputvariable::GetTypeText(void)
|
||||
{
|
||||
for (int i = 0; i < sizeof(TypeMap) / sizeof(TypeMap[0]); i++)
|
||||
{
|
||||
if (TypeMap[i].eType == m_eType)
|
||||
{
|
||||
return(TypeMap[i].pszName);
|
||||
}
|
||||
}
|
||||
|
||||
return("unknown");
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : tr -
|
||||
// Output : Returns TRUE on success, FALSE on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL GDinputvariable::InitFromTokens(TokenReader& tr)
|
||||
{
|
||||
char szToken[128];
|
||||
|
||||
if (!GDGetToken(tr, m_szName, sizeof(m_szName), IDENT))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!GDSkipToken(tr, OPERATOR, "("))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check for "reportable" marker
|
||||
trtoken_t ttype = tr.NextToken(szToken, sizeof(szToken));
|
||||
if (ttype == OPERATOR)
|
||||
{
|
||||
if (!strcmp(szToken, "*"))
|
||||
{
|
||||
m_bReportable = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tr.Stuff(ttype, szToken);
|
||||
}
|
||||
|
||||
// get type
|
||||
if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!GDSkipToken(tr, OPERATOR, ")"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Check for known variable types.
|
||||
//
|
||||
m_eType = GetTypeFromToken(szToken);
|
||||
if (m_eType == ivBadType)
|
||||
{
|
||||
GDError(tr, "'%s' is not a valid variable type", szToken);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Look ahead at the next token.
|
||||
//
|
||||
ttype = tr.PeekTokenType(szToken,sizeof(szToken));
|
||||
|
||||
//
|
||||
// Check for the "readonly" specifier.
|
||||
//
|
||||
if ((ttype == IDENT) && IsToken(szToken, "readonly"))
|
||||
{
|
||||
tr.NextToken(szToken, sizeof(szToken));
|
||||
m_bReadOnly = true;
|
||||
|
||||
//
|
||||
// Look ahead at the next token.
|
||||
//
|
||||
ttype = tr.PeekTokenType(szToken,sizeof(szToken));
|
||||
}
|
||||
|
||||
//
|
||||
// Check for the ':' indicating a long name.
|
||||
//
|
||||
if (ttype == OPERATOR && IsToken(szToken, ":"))
|
||||
{
|
||||
//
|
||||
// Eat the ':'.
|
||||
//
|
||||
tr.NextToken(szToken, sizeof(szToken));
|
||||
|
||||
if (m_eType == ivFlags)
|
||||
{
|
||||
GDError(tr, "flag sets do not have long names");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//
|
||||
// Get the long name.
|
||||
//
|
||||
if (!GDGetToken(tr, m_szLongName, sizeof(m_szLongName), STRING))
|
||||
{
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
//
|
||||
// Look ahead at the next token.
|
||||
//
|
||||
ttype = tr.PeekTokenType(szToken,sizeof(szToken));
|
||||
|
||||
//
|
||||
// Check for the ':' indicating a default value.
|
||||
//
|
||||
if (ttype == OPERATOR && IsToken(szToken, ":"))
|
||||
{
|
||||
//
|
||||
// Eat the ':'.
|
||||
//
|
||||
tr.NextToken(szToken, sizeof(szToken));
|
||||
|
||||
//
|
||||
// Look ahead at the next token.
|
||||
//
|
||||
ttype = tr.PeekTokenType(szToken,sizeof(szToken));
|
||||
if (ttype == OPERATOR && IsToken(szToken, ":"))
|
||||
{
|
||||
//
|
||||
// No default value provided, skip to the description.
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Determine how to parse the default value. If this is a choices field, the
|
||||
// default could either be a string or an integer, so we must look ahead and
|
||||
// use whichever is there.
|
||||
//
|
||||
trtoken_t eStoreAs = GetStoreAsFromType(m_eType);
|
||||
|
||||
if (eStoreAs == STRING)
|
||||
{
|
||||
if (!GDGetToken(tr, m_szDefault, sizeof(m_szDefault), STRING))
|
||||
{
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
else if (eStoreAs == INTEGER)
|
||||
{
|
||||
if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
|
||||
{
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
m_nDefault = atoi(szToken);
|
||||
}
|
||||
|
||||
//
|
||||
// Look ahead at the next token.
|
||||
//
|
||||
ttype = tr.PeekTokenType(szToken,sizeof(szToken));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check for the ':' indicating a description.
|
||||
//
|
||||
if (ttype == OPERATOR && IsToken(szToken, ":"))
|
||||
{
|
||||
//
|
||||
// Eat the ':'.
|
||||
//
|
||||
tr.NextToken(szToken, sizeof(szToken));
|
||||
|
||||
//
|
||||
// Read the description.
|
||||
//
|
||||
|
||||
// If we've already read a description then free it to avoid memory leaks.
|
||||
if ( m_pszDescription )
|
||||
{
|
||||
delete [] m_pszDescription;
|
||||
m_pszDescription = NULL;
|
||||
}
|
||||
if (!GDGetTokenDynamic(tr, &m_pszDescription, STRING))
|
||||
{
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
//
|
||||
// Look ahead at the next token.
|
||||
//
|
||||
ttype = tr.PeekTokenType(szToken,sizeof(szToken));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Default long name is short name.
|
||||
//
|
||||
strcpy(m_szLongName, m_szName);
|
||||
}
|
||||
|
||||
//
|
||||
// Check for the ']' indicating the end of the class definition.
|
||||
//
|
||||
if ((ttype == OPERATOR && IsToken(szToken, "]")) || ttype != OPERATOR)
|
||||
{
|
||||
if (m_eType == ivFlags || m_eType == ivChoices)
|
||||
{
|
||||
//
|
||||
// Can't define a flags or choices variable without providing any flags or choices.
|
||||
//
|
||||
GDError(tr, "no %s specified", m_eType == ivFlags ? "flags" : "choices");
|
||||
return(FALSE);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
if (!GDSkipToken(tr, OPERATOR, "="))
|
||||
{
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (m_eType != ivFlags && m_eType != ivChoices)
|
||||
{
|
||||
GDError(tr, "didn't expect '=' here");
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
// should be '[' to start flags/choices
|
||||
if (!GDSkipToken(tr, OPERATOR, "["))
|
||||
{
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
// get flags?
|
||||
if (m_eType == ivFlags)
|
||||
{
|
||||
GDIVITEM ivi;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ttype = tr.PeekTokenType();
|
||||
if (ttype != INTEGER)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// store bitflag value
|
||||
GDGetToken(tr, szToken, sizeof(szToken), INTEGER);
|
||||
sscanf( szToken, "%lu", &ivi.iValue );
|
||||
|
||||
// colon..
|
||||
if (!GDSkipToken(tr, OPERATOR, ":"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get description
|
||||
if (!GDGetToken(tr, szToken, sizeof(szToken), STRING))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
strcpy(ivi.szCaption, szToken);
|
||||
|
||||
// colon..
|
||||
if (!GDSkipToken(tr, OPERATOR, ":"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get default setting
|
||||
if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
ivi.bDefault = atoi(szToken) ? TRUE : FALSE;
|
||||
|
||||
// add item to array of items
|
||||
m_Items.AddToTail(ivi);
|
||||
}
|
||||
|
||||
// Set the default value.
|
||||
unsigned long nDefault = 0;
|
||||
for (int i = 0; i < m_Items.Count(); i++)
|
||||
{
|
||||
if (m_Items[i].bDefault)
|
||||
nDefault |= m_Items[i].iValue;
|
||||
}
|
||||
m_nDefault = (int)nDefault;
|
||||
Q_snprintf( m_szDefault, sizeof( m_szDefault ), "%d", m_nDefault );
|
||||
}
|
||||
else if (m_eType == ivChoices)
|
||||
{
|
||||
GDIVITEM ivi;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ttype = tr.PeekTokenType();
|
||||
if ((ttype != INTEGER) && (ttype != STRING))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// store choice value
|
||||
GDGetToken(tr, szToken, sizeof(szToken), ttype);
|
||||
ivi.iValue = 0;
|
||||
strcpy(ivi.szValue, szToken);
|
||||
|
||||
// colon
|
||||
if (!GDSkipToken(tr, OPERATOR, ":"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// get description
|
||||
if (!GDGetToken(tr, szToken, sizeof(szToken), STRING))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
strcpy(ivi.szCaption, szToken);
|
||||
|
||||
m_Items.AddToTail(ivi);
|
||||
}
|
||||
}
|
||||
|
||||
if (!GDSkipToken(tr, OPERATOR, "]"))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Decodes a key value from a string.
|
||||
// Input : pkv - Pointer to the key value object containing string encoded value.
|
||||
//-----------------------------------------------------------------------------
|
||||
void GDinputvariable::FromKeyValue(MDkeyvalue *pkv)
|
||||
{
|
||||
trtoken_t eStoreAs = GetStoreAsFromType(m_eType);
|
||||
|
||||
if (eStoreAs == STRING)
|
||||
{
|
||||
strcpy(m_szValue, pkv->szValue);
|
||||
}
|
||||
else if (eStoreAs == INTEGER)
|
||||
{
|
||||
m_nValue = atoi(pkv->szValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Determines whether the given flag is set (assuming this is an ivFlags).
|
||||
// Input : uCheck - Flag to check.
|
||||
// Output : Returns TRUE if flag is set, FALSE if not.
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL GDinputvariable::IsFlagSet(unsigned int uCheck)
|
||||
{
|
||||
Assert(m_eType == ivFlags);
|
||||
return (((unsigned int)m_nValue & uCheck) == uCheck) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Combines the flags or choices items from another variable into our
|
||||
// list of flags or choices. Ours take priority if collisions occur.
|
||||
// Input : Other - The variable whose items are being merged with ours.
|
||||
//-----------------------------------------------------------------------------
|
||||
void GDinputvariable::Merge(GDinputvariable &Other)
|
||||
{
|
||||
//
|
||||
// Only valid if we are of the same type.
|
||||
//
|
||||
if (Other.GetType() != GetType())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Add Other's items to this ONLY if there is no same-value entry
|
||||
// for a specific item.
|
||||
//
|
||||
bool bFound = false;
|
||||
int nOurItems = m_Items.Count();
|
||||
for (int i = 0; i < Other.m_Items.Count(); i++)
|
||||
{
|
||||
GDIVITEM &TheirItem = Other.m_Items[i];
|
||||
for (int j = 0; j < nOurItems; j++)
|
||||
{
|
||||
GDIVITEM &OurItem = m_Items[j];
|
||||
if (TheirItem.iValue == OurItem.iValue)
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bFound)
|
||||
{
|
||||
//
|
||||
// Not found in our list - add their item to our list.
|
||||
//
|
||||
m_Items.AddToTail(TheirItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Determines whether the given flag is set (assuming this is an ivFlags).
|
||||
// Input : uFlags - Flags to set.
|
||||
// bSet - TRUE to set the flags, FALSE to clear them.
|
||||
//-----------------------------------------------------------------------------
|
||||
void GDinputvariable::SetFlag(unsigned int uFlags, BOOL bSet)
|
||||
{
|
||||
Assert(m_eType == ivFlags);
|
||||
if (bSet)
|
||||
{
|
||||
m_nValue |= uFlags;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nValue &= ~uFlags;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets this keyvalue to its default value.
|
||||
//-----------------------------------------------------------------------------
|
||||
void GDinputvariable::ResetDefaults(void)
|
||||
{
|
||||
if (m_eType == ivFlags)
|
||||
{
|
||||
m_nValue = 0;
|
||||
|
||||
//
|
||||
// Run thru flags and set any default flags.
|
||||
//
|
||||
int nCount = m_Items.Count();
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
if (m_Items[i].bDefault)
|
||||
{
|
||||
m_nValue |= GetFlagMask(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nValue = m_nDefault;
|
||||
strcpy(m_szValue, m_szDefault);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Encodes a key value as a string.
|
||||
// Input : pkv - Pointer to the key value object to receive the encoded string.
|
||||
//-----------------------------------------------------------------------------
|
||||
void GDinputvariable::ToKeyValue(MDkeyvalue *pkv)
|
||||
{
|
||||
strcpy(pkv->szKey, m_szName);
|
||||
|
||||
trtoken_t eStoreAs = GetStoreAsFromType(m_eType);
|
||||
|
||||
if (eStoreAs == STRING)
|
||||
{
|
||||
strcpy(pkv->szValue, m_szValue);
|
||||
}
|
||||
else if (eStoreAs == INTEGER)
|
||||
{
|
||||
itoa(m_nValue, pkv->szValue, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the description string that corresponds to a value string
|
||||
// for a choices list.
|
||||
// Input : pszString - The choices value string.
|
||||
// Output : Returns the description string.
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *GDinputvariable::ItemStringForValue(const char *szValue)
|
||||
{
|
||||
int nCount = m_Items.Count();
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
if (!stricmp(m_Items[i].szValue, szValue))
|
||||
{
|
||||
return(m_Items[i].szCaption);
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns the value string that corresponds to a description string
|
||||
// for a choices list.
|
||||
// Input : pszString - The choices description string.
|
||||
// Output : Returns the value string.
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *GDinputvariable::ItemValueForString(const char *szString)
|
||||
{
|
||||
int nCount = m_Items.Count();
|
||||
for (int i = 0; i < nCount; i++)
|
||||
{
|
||||
if (!strcmpi(m_Items[i].szCaption, szString))
|
||||
{
|
||||
return(m_Items[i].szValue);
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: this function will let you iterate through the text names of the variable types
|
||||
// Input : eType - the type to get the text of
|
||||
// Output : returns the textual name
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *GDinputvariable::GetVarTypeName( GDIV_TYPE eType )
|
||||
{
|
||||
return TypeMap[ eType ].pszName;
|
||||
}
|
||||
|
||||
|
171
fgdlib/inputoutput.cpp
Normal file
171
fgdlib/inputoutput.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
|
||||
#include <tier0/dbg.h>
|
||||
#include "fgdlib/InputOutput.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
InputOutputType_t eType; // The enumeration of this type.
|
||||
char *pszName; // The name of this type.
|
||||
} TypeMap_t;
|
||||
|
||||
|
||||
char *CClassInputOutputBase::g_pszEmpty = "";
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Maps type names to type enums for inputs and outputs.
|
||||
//-----------------------------------------------------------------------------
|
||||
static TypeMap_t TypeMap[] =
|
||||
{
|
||||
{ iotVoid, "void" },
|
||||
{ iotInt, "integer" },
|
||||
{ iotBool, "bool" },
|
||||
{ iotString, "string" },
|
||||
{ iotFloat, "float" },
|
||||
{ iotVector, "vector" },
|
||||
{ iotEHandle, "target_destination" },
|
||||
{ iotColor, "color255" },
|
||||
{ iotEHandle, "ehandle" }, // for backwards compatibility
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CClassInputOutputBase::CClassInputOutputBase(void)
|
||||
{
|
||||
m_eType = iotInvalid;
|
||||
m_pszDescription = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszName -
|
||||
// eType -
|
||||
//-----------------------------------------------------------------------------
|
||||
CClassInputOutputBase::CClassInputOutputBase(const char *pszName, InputOutputType_t eType)
|
||||
{
|
||||
m_pszDescription = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
CClassInputOutputBase::~CClassInputOutputBase(void)
|
||||
{
|
||||
delete m_pszDescription;
|
||||
m_pszDescription = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns a string representing the type of this I/O, eg. "integer".
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CClassInputOutputBase::GetTypeText(void)
|
||||
{
|
||||
for (int i = 0; i < sizeof(TypeMap) / sizeof(TypeMap[0]); i++)
|
||||
{
|
||||
if (TypeMap[i].eType == m_eType)
|
||||
{
|
||||
return(TypeMap[i].pszName);
|
||||
}
|
||||
}
|
||||
|
||||
return("unknown");
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : szType -
|
||||
// Output : InputOutputType_t
|
||||
//-----------------------------------------------------------------------------
|
||||
InputOutputType_t CClassInputOutputBase::SetType(const char *szType)
|
||||
{
|
||||
for (int i = 0; i < sizeof(TypeMap) / sizeof(TypeMap[0]); i++)
|
||||
{
|
||||
if (!stricmp(TypeMap[i].pszName, szType))
|
||||
{
|
||||
m_eType = TypeMap[i].eType;
|
||||
return(m_eType);
|
||||
}
|
||||
}
|
||||
|
||||
return(iotInvalid);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Assignment operator.
|
||||
//-----------------------------------------------------------------------------
|
||||
CClassInputOutputBase &CClassInputOutputBase::operator =(CClassInputOutputBase &Other)
|
||||
{
|
||||
strcpy(m_szName, Other.m_szName);
|
||||
m_eType = Other.m_eType;
|
||||
|
||||
//
|
||||
// Copy the description.
|
||||
//
|
||||
delete m_pszDescription;
|
||||
if (Other.m_pszDescription != NULL)
|
||||
{
|
||||
m_pszDescription = new char[strlen(Other.m_pszDescription) + 1];
|
||||
strcpy(m_pszDescription, Other.m_pszDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pszDescription = NULL;
|
||||
}
|
||||
|
||||
return(*this);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CClassInput::CClassInput(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszName -
|
||||
// eType -
|
||||
//-----------------------------------------------------------------------------
|
||||
CClassInput::CClassInput(const char *pszName, InputOutputType_t eType)
|
||||
: CClassInputOutputBase(pszName, eType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CClassOutput::CClassOutput(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszName -
|
||||
// eType -
|
||||
//-----------------------------------------------------------------------------
|
||||
CClassOutput::CClassOutput(const char *pszName, InputOutputType_t eType)
|
||||
: CClassInputOutputBase(pszName, eType)
|
||||
{
|
||||
}
|
282
fgdlib/wckeyvalues.cpp
Normal file
282
fgdlib/wckeyvalues.cpp
Normal file
@ -0,0 +1,282 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "fgdlib/WCKeyValues.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor.
|
||||
//-----------------------------------------------------------------------------
|
||||
MDkeyvalue::~MDkeyvalue(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Assignment operator.
|
||||
//-----------------------------------------------------------------------------
|
||||
MDkeyvalue &MDkeyvalue::operator =(const MDkeyvalue &other)
|
||||
{
|
||||
V_strcpy_safe(szKey, other.szKey);
|
||||
V_strcpy_safe(szValue, other.szValue);
|
||||
|
||||
return(*this);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void WCKVBase_Vector::RemoveKeyAt(int nIndex)
|
||||
{
|
||||
Assert(nIndex >= 0);
|
||||
Assert(nIndex < (int)m_KeyValues.Count());
|
||||
|
||||
if ((nIndex >= 0) && (nIndex < (int)m_KeyValues.Count()))
|
||||
{
|
||||
m_KeyValues.Remove(nIndex);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Adds the key to the keyvalue array. Allows duplicate keys.
|
||||
//
|
||||
// NOTE: This should only be used for keyvalue lists that do not require
|
||||
// unique key names! If you use this function then you should use GetCount
|
||||
// and GetKey/Value by index rather than GetValue by key name.
|
||||
//-----------------------------------------------------------------------------
|
||||
void WCKVBase_Vector::AddKeyValue(const char *pszKey, const char *pszValue)
|
||||
{
|
||||
if (!pszKey || !pszValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
char szTmpKey[KEYVALUE_MAX_KEY_LENGTH];
|
||||
char szTmpValue[KEYVALUE_MAX_VALUE_LENGTH];
|
||||
|
||||
V_strcpy_safe(szTmpKey, pszKey);
|
||||
V_strcpy_safe(szTmpValue, pszValue);
|
||||
|
||||
StripEdgeWhiteSpace(szTmpKey);
|
||||
StripEdgeWhiteSpace(szTmpValue);
|
||||
|
||||
//
|
||||
// Add the keyvalue to our list.
|
||||
//
|
||||
MDkeyvalue newkv;
|
||||
V_strcpy_safe(newkv.szKey, szTmpKey);
|
||||
V_strcpy_safe(newkv.szValue, szTmpValue);
|
||||
m_KeyValues.AddToTail(newkv);
|
||||
}
|
||||
|
||||
int WCKVBase_Vector::FindByKeyName( const char *pKeyName ) const
|
||||
{
|
||||
for ( int i=0; i < m_KeyValues.Count(); i++ )
|
||||
{
|
||||
if ( V_stricmp( m_KeyValues[i].szKey, pKeyName ) == 0 )
|
||||
return i;
|
||||
}
|
||||
return GetInvalidIndex();
|
||||
}
|
||||
|
||||
void WCKVBase_Vector::InsertKeyValue( const MDkeyvalue &kv )
|
||||
{
|
||||
m_KeyValues.AddToTail( kv );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
void WCKVBase_Dict::RemoveKeyAt(int nIndex)
|
||||
{
|
||||
m_KeyValues.RemoveAt(nIndex);
|
||||
}
|
||||
|
||||
|
||||
int WCKVBase_Dict::FindByKeyName( const char *pKeyName ) const
|
||||
{
|
||||
return m_KeyValues.Find( pKeyName );
|
||||
}
|
||||
|
||||
void WCKVBase_Dict::InsertKeyValue( const MDkeyvalue &kv )
|
||||
{
|
||||
m_KeyValues.Insert( kv.szKey, kv );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Constructor. Sets the initial size of the keyvalue array.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Base>
|
||||
WCKeyValuesT<Base>::WCKeyValuesT(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Destructor. Deletes the contents of this keyvalue array.
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Base>
|
||||
WCKeyValuesT<Base>::~WCKeyValuesT(void)
|
||||
{
|
||||
//int i = 0;
|
||||
//while (i < m_KeyValues.GetSize())
|
||||
//{
|
||||
// delete m_KeyValues.GetAt(i++);
|
||||
//}
|
||||
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Base>
|
||||
const char *WCKeyValuesT<Base>::GetValue(const char *pszKey, int *piIndex) const
|
||||
{
|
||||
int i = FindByKeyName( pszKey );
|
||||
if ( i == GetInvalidIndex() )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(piIndex)
|
||||
piIndex[0] = i;
|
||||
|
||||
return m_KeyValues[i].szValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Base>
|
||||
void WCKeyValuesT<Base>::RemoveKey(const char *pszKey)
|
||||
{
|
||||
SetValue(pszKey, (const char *)NULL);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Base>
|
||||
void WCKeyValuesT<Base>::SetValue(const char *pszKey, int iValue)
|
||||
{
|
||||
char szValue[100];
|
||||
itoa(iValue, szValue, 10);
|
||||
|
||||
SetValue(pszKey, szValue);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Strips leading and trailing whitespace from the string.
|
||||
// Input : psz -
|
||||
//-----------------------------------------------------------------------------
|
||||
void StripEdgeWhiteSpace(char *psz)
|
||||
{
|
||||
if (!psz || !*psz)
|
||||
return;
|
||||
|
||||
char *pszBase = psz;
|
||||
|
||||
while (V_isspace(*psz))
|
||||
{
|
||||
psz++;
|
||||
}
|
||||
|
||||
int iLen = strlen(psz) - 1;
|
||||
|
||||
if ( iLen >= 0 )
|
||||
{
|
||||
while (V_isspace(psz[iLen]))
|
||||
{
|
||||
psz[iLen--] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (psz != pszBase)
|
||||
{
|
||||
memmove(pszBase, psz, iLen + 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszKey -
|
||||
// pszValue -
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Base>
|
||||
void WCKeyValuesT<Base>::SetValue(const char *pszKey, const char *pszValue)
|
||||
{
|
||||
char szTmpKey[KEYVALUE_MAX_KEY_LENGTH];
|
||||
char szTmpValue[KEYVALUE_MAX_VALUE_LENGTH];
|
||||
|
||||
V_strcpy_safe(szTmpKey, pszKey);
|
||||
|
||||
if (pszValue != NULL)
|
||||
{
|
||||
V_strcpy_safe(szTmpValue, pszValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
szTmpValue[0] = 0;
|
||||
}
|
||||
|
||||
StripEdgeWhiteSpace(szTmpKey);
|
||||
StripEdgeWhiteSpace(szTmpValue);
|
||||
|
||||
int i = FindByKeyName( szTmpKey );
|
||||
if ( i == GetInvalidIndex() )
|
||||
{
|
||||
if ( pszValue )
|
||||
{
|
||||
//
|
||||
// Add the keyvalue to our list.
|
||||
//
|
||||
MDkeyvalue newkv;
|
||||
Q_strncpy( newkv.szKey, szTmpKey, sizeof( newkv.szKey ) );
|
||||
Q_strncpy( newkv.szValue, szTmpValue, sizeof( newkv.szValue ) );
|
||||
InsertKeyValue( newkv );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pszValue != NULL)
|
||||
{
|
||||
V_strncpy(m_KeyValues[i].szValue, szTmpValue, sizeof(m_KeyValues[i].szValue));
|
||||
}
|
||||
//
|
||||
// If we are setting to a NULL value, delete the key.
|
||||
//
|
||||
else
|
||||
{
|
||||
RemoveKeyAt( i );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
template<class Base>
|
||||
void WCKeyValuesT<Base>::RemoveAll(void)
|
||||
{
|
||||
m_KeyValues.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
// Explicit instantiations.
|
||||
template class WCKeyValuesT<WCKVBase_Dict>;
|
||||
template class WCKeyValuesT<WCKVBase_Vector>;
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user