diff options
| author | Narendra Umate <[email protected]> | 2013-12-02 23:36:05 -0800 |
|---|---|---|
| committer | Narendra Umate <[email protected]> | 2013-12-02 23:36:05 -0800 |
| commit | 8737f191f3b59f001a77bf6c08091109211c1c9f (patch) | |
| tree | dbbf05c004d9b026f2c1f23f06600fe0add82c36 /mp/src/fgdlib | |
| parent | Update .gitignore. (diff) | |
| parent | Make .xcconfigs text files too. (diff) | |
| download | source-sdk-2013-8737f191f3b59f001a77bf6c08091109211c1c9f.tar.xz source-sdk-2013-8737f191f3b59f001a77bf6c08091109211c1c9f.zip | |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'mp/src/fgdlib')
| -rw-r--r-- | mp/src/fgdlib/fgdlib.vpc | 80 | ||||
| -rw-r--r-- | mp/src/fgdlib/gamedata.cpp | 1772 | ||||
| -rw-r--r-- | mp/src/fgdlib/gdclass.cpp | 2082 | ||||
| -rw-r--r-- | mp/src/fgdlib/gdvar.cpp | 1458 | ||||
| -rw-r--r-- | mp/src/fgdlib/inputoutput.cpp | 342 | ||||
| -rw-r--r-- | mp/src/fgdlib/wckeyvalues.cpp | 564 |
6 files changed, 3149 insertions, 3149 deletions
diff --git a/mp/src/fgdlib/fgdlib.vpc b/mp/src/fgdlib/fgdlib.vpc index 6ff37694..a44915d9 100644 --- a/mp/src/fgdlib/fgdlib.vpc +++ b/mp/src/fgdlib/fgdlib.vpc @@ -1,40 +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"
- }
-}
+//----------------------------------------------------------------------------- +// 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" + } +} diff --git a/mp/src/fgdlib/gamedata.cpp b/mp/src/fgdlib/gamedata.cpp index cd94b23d..f3689ee9 100644 --- a/mp/src/fgdlib/gamedata.cpp +++ b/mp/src/fgdlib/gamedata.cpp @@ -1,886 +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"
+//========= 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" diff --git a/mp/src/fgdlib/gdclass.cpp b/mp/src/fgdlib/gdclass.cpp index be07610e..1de57b6a 100644 --- a/mp/src/fgdlib/gdclass.cpp +++ b/mp/src/fgdlib/gdclass.cpp @@ -1,1041 +1,1041 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================
-
-#include "fgdlib/GameData.h" // FGDLIB: eliminate dependency
-#include "fgdlib/GDClass.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include <tier0/memdbgon.h>
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor.
-//-----------------------------------------------------------------------------
-GDclass::GDclass(void)
-{
- m_nVariables = 0;
- m_bBase = false;
- m_bSolid = false;
- m_bBase = false;
- m_bSolid = false;
- m_bModel = false;
- m_bMove = false;
- m_bKeyFrame = false;
- m_bPoint = false;
- m_bNPC = false;
- m_bFilter = false;
-
- m_bHalfGridSnap = false;
-
- m_bGotSize = false;
- m_bGotColor = false;
-
- m_rgbColor.r = 220;
- m_rgbColor.g = 30;
- m_rgbColor.b = 220;
- m_rgbColor.a = 0;
-
- m_pszDescription = NULL;
-
- for (int i = 0; i < 3; i++)
- {
- m_bmins[i] = -8;
- m_bmaxs[i] = 8;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Destructor. Frees variable and helper lists.
-//-----------------------------------------------------------------------------
-GDclass::~GDclass(void)
-{
- //
- // Free variables.
- //
- int nCount = m_Variables.Count();
- for (int i = 0; i < nCount; i++)
- {
- GDinputvariable *pvi = m_Variables.Element(i);
- delete pvi;
- }
- m_Variables.RemoveAll();
-
- //
- // Free helpers.
- //
- nCount = m_Helpers.Count();
- for (int i = 0; i < nCount; i++)
- {
- CHelperInfo *pHelper = m_Helpers.Element(i);
- delete pHelper;
- }
- m_Helpers.RemoveAll();
-
- //
- // Free inputs.
- //
- nCount = m_Inputs.Count();
- for (int i = 0; i < nCount; i++)
- {
- CClassInput *pInput = m_Inputs.Element(i);
- delete pInput;
- }
- m_Inputs.RemoveAll();
-
- //
- // Free outputs.
- //
- nCount = m_Outputs.Count();
- for (int i = 0; i < nCount; i++)
- {
- CClassOutput *pOutput = m_Outputs.Element(i);
- delete pOutput;
- }
- m_Outputs.RemoveAll();
-
- delete m_pszDescription;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Adds the base class's variables to our variable list. Acquires the
-// base class's bounding box and color, if any.
-// Input : pszBase - Name of base class to add.
-//-----------------------------------------------------------------------------
-void GDclass::AddBase(GDclass *pBase)
-{
- int iBaseIndex;
- Parent->ClassForName(pBase->GetName(), &iBaseIndex);
-
- //
- // Add variables from base - update variable table
- //
- for (int i = 0; i < pBase->GetVariableCount(); i++)
- {
- GDinputvariable *pVar = pBase->GetVariableAt(i);
- AddVariable(pVar, pBase, iBaseIndex, i);
- }
-
- //
- // Add inputs from the base.
- // UNDONE: need to use references to inputs & outputs to conserve memory
- //
- int nCount = pBase->GetInputCount();
- for (int i = 0; i < nCount; i++)
- {
- CClassInput *pInput = pBase->GetInput(i);
-
- CClassInput *pNew = new CClassInput;
- *pNew = *pInput;
- AddInput(pNew);
- }
-
- //
- // Add outputs from the base.
- //
- nCount = pBase->GetOutputCount();
- for (int i = 0; i < nCount; i++)
- {
- CClassOutput *pOutput = pBase->GetOutput(i);
-
- CClassOutput *pNew = new CClassOutput;
- *pNew = *pOutput;
- AddOutput(pNew);
- }
-
- //
- // If we don't have a bounding box, try to get the base's box.
- //
- if (!m_bGotSize)
- {
- if (pBase->GetBoundBox(m_bmins, m_bmaxs))
- {
- m_bGotSize = true;
- }
- }
-
- //
- // If we don't have a color, use the base's color.
- //
- if (!m_bGotColor)
- {
- m_rgbColor = pBase->GetColor();
- m_bGotColor = true;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Adds the given GDInputVariable to this GDClass's list of variables.
-// Input : pVar -
-// pBase -
-// iBaseIndex -
-// iVarIndex -
-// Output : Returns TRUE if the pVar pointer was copied directly into this GDClass,
-// FALSE if not. If this function returns TRUE, pVar should not be
-// deleted by the caller.
-//-----------------------------------------------------------------------------
-BOOL GDclass::AddVariable(GDinputvariable *pVar, GDclass *pBase, int iBaseIndex, int iVarIndex)
-{
- int iThisIndex;
- GDinputvariable *pThisVar = VarForName(pVar->GetName(), &iThisIndex);
-
- //
- // Check to see if we are overriding an existing variable definition.
- //
- if (pThisVar != NULL)
- {
- //
- // Same name, different type. Flag this as an error.
- //
- if (pThisVar->GetType() != pVar->GetType())
- {
- return(false);
- }
-
- GDinputvariable *pAddVar;
- bool bReturn;
-
- //
- // Check to see if we need to combine a choices/flags array.
- //
- if (pVar->GetType() == ivFlags || pVar->GetType() == ivChoices)
- {
- //
- // Combine two variables' flags into a new variable. Add the new
- // variable to the local variable list and modify the old variable's
- // position in our variable map to reflect the new local variable.
- // This way, we can have multiple inheritance.
- //
- GDinputvariable *pNewVar = new GDinputvariable;
-
- *pNewVar = *pVar;
- pNewVar->Merge(*pThisVar);
-
- pAddVar = pNewVar;
- bReturn = false;
- }
- else
- {
- pAddVar = pVar;
- bReturn = true;
- }
-
- if (m_VariableMap[iThisIndex][0] == -1)
- {
- //
- // "pThisVar" is a leaf variable - we can remove since it is overridden.
- //
- int nIndex = m_Variables.Find(pThisVar);
- Assert(nIndex != -1);
- delete pThisVar;
-
- m_Variables.Element(nIndex) = pAddVar;
-
- //
- // No need to modify variable map - we just replaced
- // the pointer in the local variable list.
- //
- }
- else
- {
- //
- // "pThisVar" was declared in a base class - we can replace the reference in
- // our variable map with the new variable.
- //
- m_VariableMap[iThisIndex][0] = iBaseIndex;
-
- if (iBaseIndex == -1)
- {
- m_Variables.AddToTail(pAddVar);
- m_VariableMap[iThisIndex][1] = m_Variables.Count() - 1;
- }
- else
- {
- m_VariableMap[iThisIndex][1] = iVarIndex;
- }
- }
-
- return(bReturn);
- }
-
- //
- // New variable.
- //
- if (iBaseIndex == -1)
- {
- //
- // Variable declared in the leaf class definition - add it to the list.
- //
- m_Variables.AddToTail(pVar);
- }
-
- //
- // Too many variables already declared in this class definition - abort.
- //
- if (m_nVariables == GD_MAX_VARIABLES)
- {
- //CUtlString str;
- //str.Format("Too many gamedata variables for class \"%s\"", m_szName);
- //AfxMessageBox(str);
-
- return(false);
- }
-
- //
- // Add the variable to our list.
- //
- m_VariableMap[m_nVariables][0] = iBaseIndex;
- m_VariableMap[m_nVariables][1] = iVarIndex;
- ++m_nVariables;
-
- //
- // We added the pointer to our list of items (see Variables.AddToTail, above) so
- // we must return true here.
- //
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Finds an input by name.
-//-----------------------------------------------------------------------------
-CClassInput *GDclass::FindInput(const char *szName)
-{
- int nCount = GetInputCount();
- for (int i = 0; i < nCount; i++)
- {
- CClassInput *pInput = GetInput(i);
- if (!stricmp(pInput->GetName(), szName))
- {
- return(pInput);
- }
- }
-
- return(NULL);
-}
-
-
-//-----------------------------------------------------------------------------
-// Finds an output by name.
-//-----------------------------------------------------------------------------
-CClassOutput *GDclass::FindOutput(const char *szName)
-{
- int nCount = GetOutputCount();
- for (int i = 0; i < nCount; i++)
- {
- CClassOutput *pOutput = GetOutput(i);
- if (!stricmp(pOutput->GetName(), szName))
- {
- return(pOutput);
- }
- }
-
- return(NULL);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets the mins and maxs of the class's bounding box as read from the
-// FGD file. This controls the onscreen representation of any entities
-// derived from this class.
-// Input : pfMins - Receives minimum X, Y, and Z coordinates for the class.
-// pfMaxs - Receives maximum X, Y, and Z coordinates for the class.
-// Output : Returns TRUE if this class has a specified bounding box, FALSE if not.
-//-----------------------------------------------------------------------------
-BOOL GDclass::GetBoundBox(Vector& pfMins, Vector& pfMaxs)
-{
- if (m_bGotSize)
- {
- pfMins[0] = m_bmins[0];
- pfMins[1] = m_bmins[1];
- pfMins[2] = m_bmins[2];
-
- pfMaxs[0] = m_bmaxs[0];
- pfMaxs[1] = m_bmaxs[1];
- pfMaxs[2] = m_bmaxs[2];
- }
-
- return(m_bGotSize);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-CHelperInfo *GDclass::GetHelper(int nIndex)
-{
- return m_Helpers.Element(nIndex);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-CClassInput *GDclass::GetInput(int nIndex)
-{
- return m_Inputs.Element(nIndex);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-CClassOutput *GDclass::GetOutput(int nIndex)
-{
- return m_Outputs.Element(nIndex);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : tr -
-// pGD -
-// Output : Returns TRUE if worth continuing, FALSE otherwise.
-//-----------------------------------------------------------------------------
-BOOL GDclass::InitFromTokens(TokenReader& tr, GameData *pGD)
-{
- Parent = pGD;
-
- //
- // Initialize VariableMap
- //
- for (int i = 0; i < GD_MAX_VARIABLES; i++)
- {
- m_VariableMap[i][0] = -1;
- m_VariableMap[i][1] = -1;
- }
-
- //
- // Parse all specifiers (base, size, color, etc.)
- //
- if (!ParseSpecifiers(tr))
- {
- return(FALSE);
- }
-
- //
- // Specifiers should be followed by an "="
- //
- if (!GDSkipToken(tr, OPERATOR, "="))
- {
- return(FALSE);
- }
-
- //
- // Parse the class name.
- //
- if (!GDGetToken(tr, m_szName, sizeof(m_szName), IDENT))
- {
- return(FALSE);
- }
-
- //
- // Check next operator - if ":", we have a description - if "[",
- // we have no description.
- //
- char szToken[MAX_TOKEN];
- if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && IsToken(szToken, ":"))
- {
- // Skip ":"
- tr.NextToken(szToken, sizeof(szToken));
-
- //
- // Free any existing description and set the pointer to NULL so that GDGetToken
- // allocates memory for us.
- //
- delete m_pszDescription;
- m_pszDescription = NULL;
-
- // Load description
- if (!GDGetTokenDynamic(tr, &m_pszDescription, STRING))
- {
- return(FALSE);
- }
- }
-
- //
- // Opening square brace.
- //
- if (!GDSkipToken(tr, OPERATOR, "["))
- {
- return(FALSE);
- }
-
- //
- // Get class variables.
- //
- if (!ParseVariables(tr))
- {
- return(FALSE);
- }
-
- //
- // Closing square brace.
- //
- if (!GDSkipToken(tr, OPERATOR, "]"))
- {
- return(FALSE);
- }
-
- return(TRUE);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseBase(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- while (1)
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
- {
- return(false);
- }
-
- //
- // Find base class in list of classes.
- //
- GDclass *pBase = Parent->ClassForName(szToken);
- if (pBase == NULL)
- {
- GDError(tr, "undefined base class '%s", szToken);
- return(false);
- }
-
- AddBase(pBase);
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR))
- {
- return(false);
- }
-
- if (IsToken(szToken, ")"))
- {
- break;
- }
- else if (!IsToken(szToken, ","))
- {
- GDError(tr, "expecting ',' or ')', but found %s", szToken);
- return(false);
- }
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseColor(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- //
- // Red.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
- BYTE r = atoi(szToken);
-
- //
- // Green.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
- BYTE g = atoi(szToken);
-
- //
- // Blue.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
- BYTE b = atoi(szToken);
-
- m_rgbColor.r = r;
- m_rgbColor.g = g;
- m_rgbColor.b = b;
- m_rgbColor.a = 0;
-
- m_bGotColor = true;
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
- {
- return(false);
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Parses a helper from the FGD file. Helpers are of the following format:
-//
-// <helpername>(<parameter 0> <parameter 1> ... <parameter n>)
-//
-// When this function is called, the helper name has already been parsed.
-// Input : tr - Tokenreader to use for parsing.
-// pszHelperName - Name of the helper being declared.
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseHelper(TokenReader &tr, char *pszHelperName)
-{
- char szToken[MAX_TOKEN];
-
- CHelperInfo *pHelper = new CHelperInfo;
- pHelper->SetName(pszHelperName);
-
- bool bCloseParen = false;
- while (!bCloseParen)
- {
- trtoken_t eType = tr.PeekTokenType(szToken,sizeof(szToken));
-
- if (eType == OPERATOR)
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR))
- {
- delete pHelper;
- return(false);
- }
-
- if (IsToken(szToken, ")"))
- {
- bCloseParen = true;
- }
- else if (IsToken(szToken, "="))
- {
- delete pHelper;
- return(false);
- }
- }
- else
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), eType))
- {
- delete pHelper;
- return(false);
- }
- else
- {
- pHelper->AddParameter(szToken);
- }
- }
- }
-
- m_Helpers.AddToTail(pHelper);
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseSize(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- //
- // Mins.
- //
- for (int i = 0; i < 3; i++)
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
-
- m_bmins[i] = (float)atof(szToken);
- }
-
- if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR && IsToken(szToken, ","))
- {
- //
- // Skip ","
- //
- tr.NextToken(szToken, sizeof(szToken));
-
- //
- // Get maxes.
- //
- for (int i = 0; i < 3; i++)
- {
- if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER))
- {
- return(false);
- }
- m_bmaxs[i] = (float)atof(szToken);
- }
- }
- else
- {
- //
- // Split mins across origin.
- //
- for (int i = 0; i < 3; i++)
- {
- float div2 = m_bmins[i] / 2;
- m_bmaxs[i] = div2;
- m_bmins[i] = -div2;
- }
- }
-
- m_bGotSize = true;
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
- {
- return(false);
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseSpecifiers(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- while (tr.PeekTokenType() == IDENT)
- {
- tr.NextToken(szToken, sizeof(szToken));
-
- //
- // Handle specifiers that don't have any parens after them.
- //
- if (IsToken(szToken, "halfgridsnap"))
- {
- m_bHalfGridSnap = true;
- }
- else
- {
- //
- // Handle specifiers require parens after them.
- //
- if (!GDSkipToken(tr, OPERATOR, "("))
- {
- return(false);
- }
-
- if (IsToken(szToken, "base"))
- {
- if (!ParseBase(tr))
- {
- return(false);
- }
- }
- else if (IsToken(szToken, "size"))
- {
- if (!ParseSize(tr))
- {
- return(false);
- }
- }
- else if (IsToken(szToken, "color"))
- {
- if (!ParseColor(tr))
- {
- return(false);
- }
- }
- else if (!ParseHelper(tr, szToken))
- {
- return(false);
- }
- }
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Reads an input using a given token reader. If the input is
-// read successfully, the input is added to this class. If not, a
-// parsing failure is returned.
-// Input : tr - Token reader to use for parsing.
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseInput(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "input"))
- {
- return(false);
- }
-
- CClassInput *pInput = new CClassInput;
-
- bool bReturn = ParseInputOutput(tr, pInput);
- if (bReturn)
- {
- AddInput(pInput);
- }
- else
- {
- delete pInput;
- }
-
- return(bReturn);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Reads an input or output using a given token reader.
-// Input : tr - Token reader to use for parsing.
-// pInputOutput - Input or output to fill out.
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseInputOutput(TokenReader &tr, CClassInputOutputBase *pInputOutput)
-{
- char szToken[MAX_TOKEN];
-
- //
- // Read the name.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
- {
- return(false);
- }
-
- pInputOutput->SetName(szToken);
-
- //
- // Read the type.
- //
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, "("))
- {
- return(false);
- }
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT))
- {
- return(false);
- }
-
- InputOutputType_t eType = pInputOutput->SetType(szToken);
- if (eType == iotInvalid)
- {
- GDError(tr, "bad input/output type '%s'", szToken);
- return(false);
- }
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")"))
- {
- return(false);
- }
-
- //
- // Check the next operator - if ':', we have a description.
- //
- if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && (IsToken(szToken, ":")))
- {
- //
- // Skip the ":".
- //
- tr.NextToken(szToken, sizeof(szToken));
-
- //
- // Read the description.
- //
- char *pszDescription;
- if (!GDGetTokenDynamic(tr, &pszDescription, STRING))
- {
- return(false);
- }
-
- pInputOutput->SetDescription(pszDescription);
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Reads an output using a given token reader. If the output is
-// read successfully, the output is added to this class. If not, a
-// parsing failure is returned.
-// Input : tr - Token reader to use for parsing.
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseOutput(TokenReader &tr)
-{
- char szToken[MAX_TOKEN];
-
- if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "output"))
- {
- return(false);
- }
-
- CClassOutput *pOutput = new CClassOutput;
-
- bool bReturn = ParseInputOutput(tr, pOutput);
- if (bReturn)
- {
- AddOutput(pOutput);
- }
- else
- {
- delete pOutput;
- }
-
- return(bReturn);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &tr -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool GDclass::ParseVariables(TokenReader &tr)
-{
- while (1)
- {
- char szToken[MAX_TOKEN];
-
- if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR)
- {
- break;
- }
-
- if (!stricmp(szToken, "input"))
- {
- if (!ParseInput(tr))
- {
- return(false);
- }
-
- continue;
- }
-
- if (!stricmp(szToken, "output"))
- {
- if (!ParseOutput(tr))
- {
- return(false);
- }
-
- continue;
- }
-
- if (!stricmp(szToken, "key"))
- {
- GDGetToken(tr, szToken, sizeof(szToken));
- }
-
- GDinputvariable * var = new GDinputvariable;
- if (!var->InitFromTokens(tr))
- {
- delete var;
- return(false);
- }
-
- int nDupIndex;
- GDinputvariable *pDupVar = VarForName(var->GetName(), &nDupIndex);
-
- // check for duplicate variable definitions
- if (pDupVar)
- {
- // Same name, different type.
- if (pDupVar->GetType() != var->GetType())
- {
- char szError[_MAX_PATH];
-
- sprintf(szError, "%s: Variable '%s' is multiply defined with different types.", GetName(), var->GetName());
- GDError(tr, szError);
- }
- }
-
- if (!AddVariable(var, this, -1, m_Variables.Count()))
- {
- delete var;
- }
- }
-
- return(true);
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : iIndex -
-// Output : GDinputvariable *
-//-----------------------------------------------------------------------------
-GDinputvariable *GDclass::GetVariableAt(int iIndex)
-{
- if ( iIndex < 0 || iIndex >= m_nVariables )
- return NULL;
-
- if (m_VariableMap[iIndex][0] == -1)
- {
- return m_Variables.Element(m_VariableMap[iIndex][1]);
- }
-
- // find var's owner
- GDclass *pVarClass = Parent->GetClass(m_VariableMap[iIndex][0]);
-
- // find var in pVarClass
- return pVarClass->GetVariableAt(m_VariableMap[iIndex][1]);
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-GDinputvariable *GDclass::VarForName(const char *pszName, int *piIndex)
-{
- for(int i = 0; i < GetVariableCount(); i++)
- {
- GDinputvariable *pVar = GetVariableAt(i);
- if(!strcmpi(pVar->GetName(), pszName))
- {
- if(piIndex)
- piIndex[0] = i;
- return pVar;
- }
- }
-
- return NULL;
-}
-
-void GDclass::GetHelperForGDVar( GDinputvariable *pVar, CUtlVector<const char *> *pszHelperName )
-{
- const char *pszName = pVar->GetName();
- for( int i = 0; i < GetHelperCount(); i++ )
- {
- CHelperInfo *pHelper = GetHelper( i );
- int nParamCount = pHelper->GetParameterCount();
- for ( int j = 0; j < nParamCount; j++ )
- {
- if ( !strcmpi( pszName, pHelper->GetParameter( j ) ) )
- {
- pszHelperName->AddToTail(pHelper->GetName());
- }
- }
- }
-}
-
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "fgdlib/GameData.h" // FGDLIB: eliminate dependency +#include "fgdlib/GDClass.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> + + +//----------------------------------------------------------------------------- +// Purpose: Constructor. +//----------------------------------------------------------------------------- +GDclass::GDclass(void) +{ + m_nVariables = 0; + m_bBase = false; + m_bSolid = false; + m_bBase = false; + m_bSolid = false; + m_bModel = false; + m_bMove = false; + m_bKeyFrame = false; + m_bPoint = false; + m_bNPC = false; + m_bFilter = false; + + m_bHalfGridSnap = false; + + m_bGotSize = false; + m_bGotColor = false; + + m_rgbColor.r = 220; + m_rgbColor.g = 30; + m_rgbColor.b = 220; + m_rgbColor.a = 0; + + m_pszDescription = NULL; + + for (int i = 0; i < 3; i++) + { + m_bmins[i] = -8; + m_bmaxs[i] = 8; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor. Frees variable and helper lists. +//----------------------------------------------------------------------------- +GDclass::~GDclass(void) +{ + // + // Free variables. + // + int nCount = m_Variables.Count(); + for (int i = 0; i < nCount; i++) + { + GDinputvariable *pvi = m_Variables.Element(i); + delete pvi; + } + m_Variables.RemoveAll(); + + // + // Free helpers. + // + nCount = m_Helpers.Count(); + for (int i = 0; i < nCount; i++) + { + CHelperInfo *pHelper = m_Helpers.Element(i); + delete pHelper; + } + m_Helpers.RemoveAll(); + + // + // Free inputs. + // + nCount = m_Inputs.Count(); + for (int i = 0; i < nCount; i++) + { + CClassInput *pInput = m_Inputs.Element(i); + delete pInput; + } + m_Inputs.RemoveAll(); + + // + // Free outputs. + // + nCount = m_Outputs.Count(); + for (int i = 0; i < nCount; i++) + { + CClassOutput *pOutput = m_Outputs.Element(i); + delete pOutput; + } + m_Outputs.RemoveAll(); + + delete m_pszDescription; +} + + +//----------------------------------------------------------------------------- +// Purpose: Adds the base class's variables to our variable list. Acquires the +// base class's bounding box and color, if any. +// Input : pszBase - Name of base class to add. +//----------------------------------------------------------------------------- +void GDclass::AddBase(GDclass *pBase) +{ + int iBaseIndex; + Parent->ClassForName(pBase->GetName(), &iBaseIndex); + + // + // Add variables from base - update variable table + // + for (int i = 0; i < pBase->GetVariableCount(); i++) + { + GDinputvariable *pVar = pBase->GetVariableAt(i); + AddVariable(pVar, pBase, iBaseIndex, i); + } + + // + // Add inputs from the base. + // UNDONE: need to use references to inputs & outputs to conserve memory + // + int nCount = pBase->GetInputCount(); + for (int i = 0; i < nCount; i++) + { + CClassInput *pInput = pBase->GetInput(i); + + CClassInput *pNew = new CClassInput; + *pNew = *pInput; + AddInput(pNew); + } + + // + // Add outputs from the base. + // + nCount = pBase->GetOutputCount(); + for (int i = 0; i < nCount; i++) + { + CClassOutput *pOutput = pBase->GetOutput(i); + + CClassOutput *pNew = new CClassOutput; + *pNew = *pOutput; + AddOutput(pNew); + } + + // + // If we don't have a bounding box, try to get the base's box. + // + if (!m_bGotSize) + { + if (pBase->GetBoundBox(m_bmins, m_bmaxs)) + { + m_bGotSize = true; + } + } + + // + // If we don't have a color, use the base's color. + // + if (!m_bGotColor) + { + m_rgbColor = pBase->GetColor(); + m_bGotColor = true; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Adds the given GDInputVariable to this GDClass's list of variables. +// Input : pVar - +// pBase - +// iBaseIndex - +// iVarIndex - +// Output : Returns TRUE if the pVar pointer was copied directly into this GDClass, +// FALSE if not. If this function returns TRUE, pVar should not be +// deleted by the caller. +//----------------------------------------------------------------------------- +BOOL GDclass::AddVariable(GDinputvariable *pVar, GDclass *pBase, int iBaseIndex, int iVarIndex) +{ + int iThisIndex; + GDinputvariable *pThisVar = VarForName(pVar->GetName(), &iThisIndex); + + // + // Check to see if we are overriding an existing variable definition. + // + if (pThisVar != NULL) + { + // + // Same name, different type. Flag this as an error. + // + if (pThisVar->GetType() != pVar->GetType()) + { + return(false); + } + + GDinputvariable *pAddVar; + bool bReturn; + + // + // Check to see if we need to combine a choices/flags array. + // + if (pVar->GetType() == ivFlags || pVar->GetType() == ivChoices) + { + // + // Combine two variables' flags into a new variable. Add the new + // variable to the local variable list and modify the old variable's + // position in our variable map to reflect the new local variable. + // This way, we can have multiple inheritance. + // + GDinputvariable *pNewVar = new GDinputvariable; + + *pNewVar = *pVar; + pNewVar->Merge(*pThisVar); + + pAddVar = pNewVar; + bReturn = false; + } + else + { + pAddVar = pVar; + bReturn = true; + } + + if (m_VariableMap[iThisIndex][0] == -1) + { + // + // "pThisVar" is a leaf variable - we can remove since it is overridden. + // + int nIndex = m_Variables.Find(pThisVar); + Assert(nIndex != -1); + delete pThisVar; + + m_Variables.Element(nIndex) = pAddVar; + + // + // No need to modify variable map - we just replaced + // the pointer in the local variable list. + // + } + else + { + // + // "pThisVar" was declared in a base class - we can replace the reference in + // our variable map with the new variable. + // + m_VariableMap[iThisIndex][0] = iBaseIndex; + + if (iBaseIndex == -1) + { + m_Variables.AddToTail(pAddVar); + m_VariableMap[iThisIndex][1] = m_Variables.Count() - 1; + } + else + { + m_VariableMap[iThisIndex][1] = iVarIndex; + } + } + + return(bReturn); + } + + // + // New variable. + // + if (iBaseIndex == -1) + { + // + // Variable declared in the leaf class definition - add it to the list. + // + m_Variables.AddToTail(pVar); + } + + // + // Too many variables already declared in this class definition - abort. + // + if (m_nVariables == GD_MAX_VARIABLES) + { + //CUtlString str; + //str.Format("Too many gamedata variables for class \"%s\"", m_szName); + //AfxMessageBox(str); + + return(false); + } + + // + // Add the variable to our list. + // + m_VariableMap[m_nVariables][0] = iBaseIndex; + m_VariableMap[m_nVariables][1] = iVarIndex; + ++m_nVariables; + + // + // We added the pointer to our list of items (see Variables.AddToTail, above) so + // we must return true here. + // + return(true); +} + + +//----------------------------------------------------------------------------- +// Finds an input by name. +//----------------------------------------------------------------------------- +CClassInput *GDclass::FindInput(const char *szName) +{ + int nCount = GetInputCount(); + for (int i = 0; i < nCount; i++) + { + CClassInput *pInput = GetInput(i); + if (!stricmp(pInput->GetName(), szName)) + { + return(pInput); + } + } + + return(NULL); +} + + +//----------------------------------------------------------------------------- +// Finds an output by name. +//----------------------------------------------------------------------------- +CClassOutput *GDclass::FindOutput(const char *szName) +{ + int nCount = GetOutputCount(); + for (int i = 0; i < nCount; i++) + { + CClassOutput *pOutput = GetOutput(i); + if (!stricmp(pOutput->GetName(), szName)) + { + return(pOutput); + } + } + + return(NULL); +} + + +//----------------------------------------------------------------------------- +// Purpose: Gets the mins and maxs of the class's bounding box as read from the +// FGD file. This controls the onscreen representation of any entities +// derived from this class. +// Input : pfMins - Receives minimum X, Y, and Z coordinates for the class. +// pfMaxs - Receives maximum X, Y, and Z coordinates for the class. +// Output : Returns TRUE if this class has a specified bounding box, FALSE if not. +//----------------------------------------------------------------------------- +BOOL GDclass::GetBoundBox(Vector& pfMins, Vector& pfMaxs) +{ + if (m_bGotSize) + { + pfMins[0] = m_bmins[0]; + pfMins[1] = m_bmins[1]; + pfMins[2] = m_bmins[2]; + + pfMaxs[0] = m_bmaxs[0]; + pfMaxs[1] = m_bmaxs[1]; + pfMaxs[2] = m_bmaxs[2]; + } + + return(m_bGotSize); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +CHelperInfo *GDclass::GetHelper(int nIndex) +{ + return m_Helpers.Element(nIndex); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +CClassInput *GDclass::GetInput(int nIndex) +{ + return m_Inputs.Element(nIndex); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +CClassOutput *GDclass::GetOutput(int nIndex) +{ + return m_Outputs.Element(nIndex); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : tr - +// pGD - +// Output : Returns TRUE if worth continuing, FALSE otherwise. +//----------------------------------------------------------------------------- +BOOL GDclass::InitFromTokens(TokenReader& tr, GameData *pGD) +{ + Parent = pGD; + + // + // Initialize VariableMap + // + for (int i = 0; i < GD_MAX_VARIABLES; i++) + { + m_VariableMap[i][0] = -1; + m_VariableMap[i][1] = -1; + } + + // + // Parse all specifiers (base, size, color, etc.) + // + if (!ParseSpecifiers(tr)) + { + return(FALSE); + } + + // + // Specifiers should be followed by an "=" + // + if (!GDSkipToken(tr, OPERATOR, "=")) + { + return(FALSE); + } + + // + // Parse the class name. + // + if (!GDGetToken(tr, m_szName, sizeof(m_szName), IDENT)) + { + return(FALSE); + } + + // + // Check next operator - if ":", we have a description - if "[", + // we have no description. + // + char szToken[MAX_TOKEN]; + if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && IsToken(szToken, ":")) + { + // Skip ":" + tr.NextToken(szToken, sizeof(szToken)); + + // + // Free any existing description and set the pointer to NULL so that GDGetToken + // allocates memory for us. + // + delete m_pszDescription; + m_pszDescription = NULL; + + // Load description + if (!GDGetTokenDynamic(tr, &m_pszDescription, STRING)) + { + return(FALSE); + } + } + + // + // Opening square brace. + // + if (!GDSkipToken(tr, OPERATOR, "[")) + { + return(FALSE); + } + + // + // Get class variables. + // + if (!ParseVariables(tr)) + { + return(FALSE); + } + + // + // Closing square brace. + // + if (!GDSkipToken(tr, OPERATOR, "]")) + { + return(FALSE); + } + + return(TRUE); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &tr - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool GDclass::ParseBase(TokenReader &tr) +{ + char szToken[MAX_TOKEN]; + + while (1) + { + if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT)) + { + return(false); + } + + // + // Find base class in list of classes. + // + GDclass *pBase = Parent->ClassForName(szToken); + if (pBase == NULL) + { + GDError(tr, "undefined base class '%s", szToken); + return(false); + } + + AddBase(pBase); + + if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR)) + { + return(false); + } + + if (IsToken(szToken, ")")) + { + break; + } + else if (!IsToken(szToken, ",")) + { + GDError(tr, "expecting ',' or ')', but found %s", szToken); + return(false); + } + } + + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &tr - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool GDclass::ParseColor(TokenReader &tr) +{ + char szToken[MAX_TOKEN]; + + // + // Red. + // + if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER)) + { + return(false); + } + BYTE r = atoi(szToken); + + // + // Green. + // + if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER)) + { + return(false); + } + BYTE g = atoi(szToken); + + // + // Blue. + // + if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER)) + { + return(false); + } + BYTE b = atoi(szToken); + + m_rgbColor.r = r; + m_rgbColor.g = g; + m_rgbColor.b = b; + m_rgbColor.a = 0; + + m_bGotColor = true; + + if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")")) + { + return(false); + } + + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: Parses a helper from the FGD file. Helpers are of the following format: +// +// <helpername>(<parameter 0> <parameter 1> ... <parameter n>) +// +// When this function is called, the helper name has already been parsed. +// Input : tr - Tokenreader to use for parsing. +// pszHelperName - Name of the helper being declared. +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool GDclass::ParseHelper(TokenReader &tr, char *pszHelperName) +{ + char szToken[MAX_TOKEN]; + + CHelperInfo *pHelper = new CHelperInfo; + pHelper->SetName(pszHelperName); + + bool bCloseParen = false; + while (!bCloseParen) + { + trtoken_t eType = tr.PeekTokenType(szToken,sizeof(szToken)); + + if (eType == OPERATOR) + { + if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR)) + { + delete pHelper; + return(false); + } + + if (IsToken(szToken, ")")) + { + bCloseParen = true; + } + else if (IsToken(szToken, "=")) + { + delete pHelper; + return(false); + } + } + else + { + if (!GDGetToken(tr, szToken, sizeof(szToken), eType)) + { + delete pHelper; + return(false); + } + else + { + pHelper->AddParameter(szToken); + } + } + } + + m_Helpers.AddToTail(pHelper); + + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &tr - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool GDclass::ParseSize(TokenReader &tr) +{ + char szToken[MAX_TOKEN]; + + // + // Mins. + // + for (int i = 0; i < 3; i++) + { + if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER)) + { + return(false); + } + + m_bmins[i] = (float)atof(szToken); + } + + if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR && IsToken(szToken, ",")) + { + // + // Skip "," + // + tr.NextToken(szToken, sizeof(szToken)); + + // + // Get maxes. + // + for (int i = 0; i < 3; i++) + { + if (!GDGetToken(tr, szToken, sizeof(szToken), INTEGER)) + { + return(false); + } + m_bmaxs[i] = (float)atof(szToken); + } + } + else + { + // + // Split mins across origin. + // + for (int i = 0; i < 3; i++) + { + float div2 = m_bmins[i] / 2; + m_bmaxs[i] = div2; + m_bmins[i] = -div2; + } + } + + m_bGotSize = true; + + if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")")) + { + return(false); + } + + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &tr - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool GDclass::ParseSpecifiers(TokenReader &tr) +{ + char szToken[MAX_TOKEN]; + + while (tr.PeekTokenType() == IDENT) + { + tr.NextToken(szToken, sizeof(szToken)); + + // + // Handle specifiers that don't have any parens after them. + // + if (IsToken(szToken, "halfgridsnap")) + { + m_bHalfGridSnap = true; + } + else + { + // + // Handle specifiers require parens after them. + // + if (!GDSkipToken(tr, OPERATOR, "(")) + { + return(false); + } + + if (IsToken(szToken, "base")) + { + if (!ParseBase(tr)) + { + return(false); + } + } + else if (IsToken(szToken, "size")) + { + if (!ParseSize(tr)) + { + return(false); + } + } + else if (IsToken(szToken, "color")) + { + if (!ParseColor(tr)) + { + return(false); + } + } + else if (!ParseHelper(tr, szToken)) + { + return(false); + } + } + } + + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: Reads an input using a given token reader. If the input is +// read successfully, the input is added to this class. If not, a +// parsing failure is returned. +// Input : tr - Token reader to use for parsing. +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool GDclass::ParseInput(TokenReader &tr) +{ + char szToken[MAX_TOKEN]; + + if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "input")) + { + return(false); + } + + CClassInput *pInput = new CClassInput; + + bool bReturn = ParseInputOutput(tr, pInput); + if (bReturn) + { + AddInput(pInput); + } + else + { + delete pInput; + } + + return(bReturn); +} + + +//----------------------------------------------------------------------------- +// Purpose: Reads an input or output using a given token reader. +// Input : tr - Token reader to use for parsing. +// pInputOutput - Input or output to fill out. +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool GDclass::ParseInputOutput(TokenReader &tr, CClassInputOutputBase *pInputOutput) +{ + char szToken[MAX_TOKEN]; + + // + // Read the name. + // + if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT)) + { + return(false); + } + + pInputOutput->SetName(szToken); + + // + // Read the type. + // + if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, "(")) + { + return(false); + } + + if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT)) + { + return(false); + } + + InputOutputType_t eType = pInputOutput->SetType(szToken); + if (eType == iotInvalid) + { + GDError(tr, "bad input/output type '%s'", szToken); + return(false); + } + + if (!GDGetToken(tr, szToken, sizeof(szToken), OPERATOR, ")")) + { + return(false); + } + + // + // Check the next operator - if ':', we have a description. + // + if ((tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) && (IsToken(szToken, ":"))) + { + // + // Skip the ":". + // + tr.NextToken(szToken, sizeof(szToken)); + + // + // Read the description. + // + char *pszDescription; + if (!GDGetTokenDynamic(tr, &pszDescription, STRING)) + { + return(false); + } + + pInputOutput->SetDescription(pszDescription); + } + + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: Reads an output using a given token reader. If the output is +// read successfully, the output is added to this class. If not, a +// parsing failure is returned. +// Input : tr - Token reader to use for parsing. +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool GDclass::ParseOutput(TokenReader &tr) +{ + char szToken[MAX_TOKEN]; + + if (!GDGetToken(tr, szToken, sizeof(szToken), IDENT, "output")) + { + return(false); + } + + CClassOutput *pOutput = new CClassOutput; + + bool bReturn = ParseInputOutput(tr, pOutput); + if (bReturn) + { + AddOutput(pOutput); + } + else + { + delete pOutput; + } + + return(bReturn); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &tr - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool GDclass::ParseVariables(TokenReader &tr) +{ + while (1) + { + char szToken[MAX_TOKEN]; + + if (tr.PeekTokenType(szToken,sizeof(szToken)) == OPERATOR) + { + break; + } + + if (!stricmp(szToken, "input")) + { + if (!ParseInput(tr)) + { + return(false); + } + + continue; + } + + if (!stricmp(szToken, "output")) + { + if (!ParseOutput(tr)) + { + return(false); + } + + continue; + } + + if (!stricmp(szToken, "key")) + { + GDGetToken(tr, szToken, sizeof(szToken)); + } + + GDinputvariable * var = new GDinputvariable; + if (!var->InitFromTokens(tr)) + { + delete var; + return(false); + } + + int nDupIndex; + GDinputvariable *pDupVar = VarForName(var->GetName(), &nDupIndex); + + // check for duplicate variable definitions + if (pDupVar) + { + // Same name, different type. + if (pDupVar->GetType() != var->GetType()) + { + char szError[_MAX_PATH]; + + sprintf(szError, "%s: Variable '%s' is multiply defined with different types.", GetName(), var->GetName()); + GDError(tr, szError); + } + } + + if (!AddVariable(var, this, -1, m_Variables.Count())) + { + delete var; + } + } + + return(true); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : iIndex - +// Output : GDinputvariable * +//----------------------------------------------------------------------------- +GDinputvariable *GDclass::GetVariableAt(int iIndex) +{ + if ( iIndex < 0 || iIndex >= m_nVariables ) + return NULL; + + if (m_VariableMap[iIndex][0] == -1) + { + return m_Variables.Element(m_VariableMap[iIndex][1]); + } + + // find var's owner + GDclass *pVarClass = Parent->GetClass(m_VariableMap[iIndex][0]); + + // find var in pVarClass + return pVarClass->GetVariableAt(m_VariableMap[iIndex][1]); +} + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +GDinputvariable *GDclass::VarForName(const char *pszName, int *piIndex) +{ + for(int i = 0; i < GetVariableCount(); i++) + { + GDinputvariable *pVar = GetVariableAt(i); + if(!strcmpi(pVar->GetName(), pszName)) + { + if(piIndex) + piIndex[0] = i; + return pVar; + } + } + + return NULL; +} + +void GDclass::GetHelperForGDVar( GDinputvariable *pVar, CUtlVector<const char *> *pszHelperName ) +{ + const char *pszName = pVar->GetName(); + for( int i = 0; i < GetHelperCount(); i++ ) + { + CHelperInfo *pHelper = GetHelper( i ); + int nParamCount = pHelper->GetParameterCount(); + for ( int j = 0; j < nParamCount; j++ ) + { + if ( !strcmpi( pszName, pHelper->GetParameter( j ) ) ) + { + pszHelperName->AddToTail(pHelper->GetName()); + } + } + } +} + + + diff --git a/mp/src/fgdlib/gdvar.cpp b/mp/src/fgdlib/gdvar.cpp index 5b9a21be..fe8df025 100644 --- a/mp/src/fgdlib/gdvar.cpp +++ b/mp/src/fgdlib/gdvar.cpp @@ -1,729 +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;
-}
-
-
+//========= 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; +} + + diff --git a/mp/src/fgdlib/inputoutput.cpp b/mp/src/fgdlib/inputoutput.cpp index 11c97df0..ee2b6033 100644 --- a/mp/src/fgdlib/inputoutput.cpp +++ b/mp/src/fgdlib/inputoutput.cpp @@ -1,171 +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)
-{
-}
+//========= 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) +{ +} diff --git a/mp/src/fgdlib/wckeyvalues.cpp b/mp/src/fgdlib/wckeyvalues.cpp index d802eb42..83e52007 100644 --- a/mp/src/fgdlib/wckeyvalues.cpp +++ b/mp/src/fgdlib/wckeyvalues.cpp @@ -1,282 +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>;
-
-
-
+//========= 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>; + + + |