From a0c29e7dd67abb15c74c85f07741784877edfdcd Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Mon, 2 Sep 2013 11:39:10 -0700 Subject: General: * Fixed a variety of server browser issues with mods based on this SDK * Fixed many warnings on various platforms * Added source code for fgdlib and raytrace * Updated many source files with the latest shared source from TF2. OSX: * Added support for Xcode 4.6 * Switched OSX builds to use Xcode instead of makefiles * Moved libs from src/lib/osx32 to src/lib/public/osx32 or src/lib/common/osx32 to match windows better. Linux: * Moved libs from src/lib/linux32 to src/lib/public/linux32 or src/lib/common/linux32 to match windows better. --- mp/src/fgdlib/gdclass.cpp | 1041 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1041 insertions(+) create mode 100644 mp/src/fgdlib/gdclass.cpp (limited to 'mp/src/fgdlib/gdclass.cpp') diff --git a/mp/src/fgdlib/gdclass.cpp b/mp/src/fgdlib/gdclass.cpp new file mode 100644 index 00000000..be07610e --- /dev/null +++ b/mp/src/fgdlib/gdclass.cpp @@ -0,0 +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 + + +//----------------------------------------------------------------------------- +// 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: +// +// ( ... ) +// +// 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 *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()); + } + } + } +} + + + -- cgit v1.2.3