You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1041 lines
22 KiB
1041 lines
22 KiB
//========= 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());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|