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.
721 lines
16 KiB
721 lines
16 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#include "stdafx.h"
|
|
#include "MapPath.h"
|
|
#include "hammer.h"
|
|
#include "EditPathDlg.h"
|
|
#include "MapEntity.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include <tier0/memdbgon.h>
|
|
|
|
|
|
float GetFileVersion(void);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
CMapPath::CMapPath(void)
|
|
{
|
|
m_iDirection = dirOneway;
|
|
SetName("");
|
|
SetClass("path_corner");
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
CMapPath::~CMapPath(void)
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
CMapPathNode::CMapPathNode(void)
|
|
{
|
|
bSelected = FALSE;
|
|
szName[0] = 0;
|
|
}
|
|
|
|
CMapPathNode::CMapPathNode(const CMapPathNode& src)
|
|
{
|
|
*this = src;
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : src -
|
|
// Output : CMapPathNode
|
|
//-----------------------------------------------------------------------------
|
|
CMapPathNode &CMapPathNode::operator=(const CMapPathNode &src)
|
|
{
|
|
// we don't care.
|
|
Q_strncpy( szName, src.szName, sizeof(szName) );
|
|
bSelected = src.bSelected;
|
|
kv.RemoveAll();
|
|
for ( int i=src.kv.GetFirst(); i != src.kv.GetInvalidIndex(); i=src.kv.GetNext( i ) )
|
|
{
|
|
MDkeyvalue KeyValue = src.kv.GetKeyValue(i);
|
|
kv.SetValue(KeyValue.szKey, KeyValue.szValue);
|
|
}
|
|
pos = src.pos;
|
|
dwID = src.dwID;
|
|
|
|
return *this;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : dwID -
|
|
// piIndex -
|
|
// Output : CMapPathNode *
|
|
//-----------------------------------------------------------------------------
|
|
CMapPathNode *CMapPath::NodeForID(DWORD dwID, int* piIndex)
|
|
{
|
|
for(int iNode = 0; iNode < m_Nodes.Count(); iNode++)
|
|
{
|
|
if(m_Nodes[iNode].dwID == dwID)
|
|
{
|
|
if(piIndex)
|
|
piIndex[0] = iNode;
|
|
return &m_Nodes[iNode];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : DWORD
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CMapPath::GetNewNodeID(void)
|
|
{
|
|
DWORD dwNewID = 1;
|
|
while(true)
|
|
{
|
|
int iNode;
|
|
for(iNode = 0; iNode < m_Nodes.Count(); iNode++)
|
|
{
|
|
if(m_Nodes[iNode].dwID == dwNewID)
|
|
break;
|
|
}
|
|
|
|
if(iNode == m_Nodes.Count())
|
|
return dwNewID;
|
|
|
|
++dwNewID;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : dwAfterID -
|
|
// vecPos -
|
|
// Output :
|
|
//-----------------------------------------------------------------------------
|
|
DWORD CMapPath::AddNode(DWORD dwAfterID, const Vector &vecPos)
|
|
{
|
|
int iPos;
|
|
|
|
if(dwAfterID == ADD_START)
|
|
iPos = 0;
|
|
else if(dwAfterID == ADD_END)
|
|
iPos = m_Nodes.Count();
|
|
else if(!NodeForID(dwAfterID, &iPos))
|
|
return 0; // not found!
|
|
|
|
CMapPathNode node;
|
|
node.pos = vecPos;
|
|
node.bSelected = FALSE;
|
|
node.dwID = GetNewNodeID();
|
|
|
|
if(iPos == m_Nodes.Count())
|
|
{
|
|
// add at tail
|
|
m_Nodes.AddToTail(node);
|
|
}
|
|
else
|
|
{
|
|
m_Nodes.InsertBefore( iPos, node );
|
|
}
|
|
|
|
return node.dwID;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : dwID -
|
|
// *pt -
|
|
//-----------------------------------------------------------------------------
|
|
void CMapPath::SetNodePosition(DWORD dwID, Vector& pt)
|
|
{
|
|
int iIndex;
|
|
NodeForID(dwID, &iIndex);
|
|
|
|
m_Nodes[iIndex].pos = pt;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : dwID -
|
|
//-----------------------------------------------------------------------------
|
|
void CMapPath::DeleteNode(DWORD dwID)
|
|
{
|
|
int iIndex;
|
|
if ( NodeForID(dwID, &iIndex) )
|
|
{
|
|
m_Nodes.Remove(iIndex);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : file -
|
|
// fIsStoring -
|
|
//-----------------------------------------------------------------------------
|
|
void CMapPath::SerializeRMF(std::fstream& file, BOOL fIsStoring)
|
|
{
|
|
int iSize;
|
|
|
|
if(fIsStoring)
|
|
{
|
|
// save!!
|
|
file.write(m_szName, 128);
|
|
file.write(m_szClass, 128);
|
|
file.write((char*) &m_iDirection, sizeof(m_iDirection));
|
|
|
|
iSize = m_Nodes.Count();
|
|
file.write((char*) &iSize, sizeof iSize);
|
|
for(int i = 0; i < m_Nodes.Count(); i++)
|
|
{
|
|
CMapPathNode& node = m_Nodes[i];
|
|
// store each node
|
|
file.write((char*) &node.pos[0], 3 * sizeof(float));
|
|
file.write((char*) &node.dwID, sizeof(node.dwID));
|
|
file.write((char*) &node.szName, sizeof(node.szName));
|
|
|
|
//
|
|
// Write keyvalue count.
|
|
//
|
|
WCKeyValues &kv = node.kv;
|
|
iSize = 0;
|
|
for ( int z=kv.GetFirst(); z != kv.GetInvalidIndex(); z=kv.GetNext( z ) )
|
|
{
|
|
++iSize;
|
|
}
|
|
file.write((char*) &iSize, sizeof(iSize));
|
|
|
|
//
|
|
// Write keyvalues.
|
|
//
|
|
for (int k = kv.GetFirst(); k != kv.GetInvalidIndex(); k=kv.GetNext( k ) )
|
|
{
|
|
MDkeyvalue &KeyValue = kv.GetKeyValue(k);
|
|
if (KeyValue.szKey[0] != '\0')
|
|
{
|
|
KeyValue.SerializeRMF(file, TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// load!!
|
|
file.read(m_szName, 128);
|
|
file.read(m_szClass, 128);
|
|
file.read((char*) &m_iDirection, sizeof m_iDirection);
|
|
|
|
file.read((char*) &iSize, sizeof iSize);
|
|
int nNodes = iSize;
|
|
m_Nodes.RemoveAll();
|
|
|
|
// read nodes
|
|
for(int i = 0; i < nNodes; i++)
|
|
{
|
|
CMapPathNode node;
|
|
// store each node
|
|
file.read((char*) &node.pos[0], 3 * sizeof(float));
|
|
file.read((char*) &node.dwID, sizeof(node.dwID));
|
|
if(GetFileVersion() >= 1.6f)
|
|
{
|
|
file.read((char*) &node.szName, sizeof(node.szName));
|
|
|
|
// read keyvalues
|
|
file.read((char*) &iSize, sizeof(iSize));
|
|
WCKeyValues &kv = node.kv;
|
|
for (int k = 0; k < iSize; k++)
|
|
{
|
|
MDkeyvalue KeyValue;
|
|
KeyValue.SerializeRMF(file, FALSE);
|
|
kv.SetValue( KeyValue.szKey, KeyValue.szValue );
|
|
}
|
|
}
|
|
|
|
m_Nodes.AddToTail(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : iIndex -
|
|
// iName -
|
|
// str -
|
|
//-----------------------------------------------------------------------------
|
|
void CMapPath::GetNodeName(int iIndex, int iName, CString& str)
|
|
{
|
|
if(m_Nodes[iIndex].szName[0])
|
|
str = m_Nodes[iIndex].szName;
|
|
else
|
|
{
|
|
if(iName)
|
|
str.Format("%s%02d", m_szName, iName);
|
|
else
|
|
str = m_szName;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : file -
|
|
// fIsStoring -
|
|
// *pIntersecting -
|
|
//-----------------------------------------------------------------------------
|
|
void CMapPath::SerializeMAP(std::fstream& file, BOOL fIsStoring, BoundBox *pIntersecting)
|
|
{
|
|
if( m_Nodes.Count() == 0)
|
|
return;
|
|
|
|
// if saving WITHIN a box, check all nodes to see if they all
|
|
// fit within that box. if not, don't save ANY of the path.
|
|
if(pIntersecting)
|
|
{
|
|
for(int i = 0; i < m_Nodes.Count(); i++)
|
|
{
|
|
if (!pIntersecting->ContainsPoint(m_Nodes[i].pos))
|
|
{
|
|
return; // doesn't intersect - don't save path
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Assert(fIsStoring);
|
|
|
|
CString strTemp;
|
|
MDkeyvalue kvTemp;
|
|
|
|
// initialize nodes for saving
|
|
for(int i = 0; i < m_Nodes.Count(); i++)
|
|
{
|
|
m_Nodes[i].nTargets = 0;
|
|
}
|
|
|
|
int iDirec = 1;
|
|
int iCurNode = 0;
|
|
int iMax = m_Nodes.Count()-1;
|
|
int iName = 0;
|
|
|
|
// resolve targets
|
|
int iLastNodeIndex = -1;
|
|
BOOL bFirstPass = TRUE;
|
|
|
|
ResolveNamesAgain:
|
|
while(1)
|
|
{
|
|
// store targetname
|
|
GetNodeName(iCurNode, iName, strTemp);
|
|
|
|
// store our name in the previous node (if not -1)
|
|
if(iLastNodeIndex != -1)
|
|
{
|
|
CMapPathNode &prevNode = m_Nodes[iLastNodeIndex];
|
|
strcpy(prevNode.szTargets[prevNode.nTargets++], strTemp);
|
|
}
|
|
|
|
++iName;
|
|
|
|
iLastNodeIndex = iCurNode;
|
|
|
|
if(iCurNode == iMax)
|
|
break;
|
|
iCurNode += iDirec;
|
|
}
|
|
|
|
if(bFirstPass && m_iDirection == dirPingpong && m_Nodes.Count() > 2)
|
|
{
|
|
// redo loop
|
|
bFirstPass = FALSE;
|
|
iDirec = -1;
|
|
iCurNode = m_Nodes.Count()-2;
|
|
iMax = 0;
|
|
goto ResolveNamesAgain;
|
|
}
|
|
else if (m_iDirection == dirCircular)
|
|
{
|
|
//
|
|
// Connect the last node to the first node.
|
|
//
|
|
CMapPathNode &LastNode = m_Nodes[iMax];
|
|
GetNodeName(iCurNode, 0, strTemp);
|
|
strcpy(LastNode.szTargets[LastNode.nTargets], strTemp);
|
|
LastNode.nTargets++;
|
|
}
|
|
|
|
iDirec = 1;
|
|
iCurNode = 0;
|
|
iMax = m_Nodes.Count()-1;
|
|
iName = 0;
|
|
|
|
SaveAgain:
|
|
while(1)
|
|
{
|
|
file << "{" << "\r\n";
|
|
|
|
// store name
|
|
kvTemp.Set("classname", m_szClass);
|
|
kvTemp.SerializeMAP(file, TRUE);
|
|
|
|
CMapPathNode &node = m_Nodes[iCurNode];
|
|
|
|
// store location
|
|
strTemp.Format("%.0f %.0f %.0f", node.pos[0], node.pos[1],
|
|
node.pos[2]);
|
|
kvTemp.Set("origin", strTemp);
|
|
kvTemp.SerializeMAP(file, TRUE);
|
|
|
|
// store targetname
|
|
GetNodeName(iCurNode, iName, strTemp);
|
|
kvTemp.Set("targetname", strTemp);
|
|
kvTemp.SerializeMAP(file, TRUE);
|
|
|
|
// store target (if not last)
|
|
BOOL bStoreTarget = TRUE;
|
|
if(iCurNode == iMax && m_iDirection == dirOneway)
|
|
bStoreTarget = FALSE;
|
|
|
|
if (bStoreTarget)
|
|
{
|
|
kvTemp.Set("target", (iDirec == 1) ? node.szTargets[0] : node.szTargets[1]);
|
|
kvTemp.SerializeMAP(file, TRUE);
|
|
}
|
|
|
|
// other keyvalues
|
|
WCKeyValues &kv = node.kv;
|
|
for (int k = kv.GetFirst(); k != kv.GetInvalidIndex(); k=kv.GetNext( k ) )
|
|
{
|
|
MDkeyvalue &KeyValue = kv.GetKeyValue(k);
|
|
if (KeyValue.szKey[0] != '\0')
|
|
{
|
|
KeyValue.SerializeMAP(file, TRUE);
|
|
}
|
|
}
|
|
|
|
file << "}" << "\r\n";
|
|
|
|
++iName;
|
|
iLastNodeIndex = iCurNode;
|
|
|
|
if(iCurNode == iMax)
|
|
break;
|
|
iCurNode += iDirec;
|
|
}
|
|
|
|
if(iDirec == 1 && m_iDirection == dirPingpong && m_Nodes.Count() > 2)
|
|
{
|
|
// redo loop
|
|
iDirec = -1;
|
|
iCurNode = m_Nodes.Count()-2;
|
|
iMax = 1;
|
|
goto SaveAgain;
|
|
}
|
|
}
|
|
|
|
// Edit
|
|
|
|
void CMapPath::EditInfo()
|
|
{
|
|
CEditPathDlg dlg;
|
|
dlg.m_strName = m_szName;
|
|
dlg.m_strClass = m_szClass;
|
|
dlg.m_iDirection = m_iDirection;
|
|
|
|
if(dlg.DoModal() != IDOK)
|
|
return;
|
|
|
|
SetName(dlg.m_strName);
|
|
SetClass(dlg.m_strClass);
|
|
m_iDirection = dlg.m_iDirection;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : dwNodeID -
|
|
// Output : CMapEntity *
|
|
//-----------------------------------------------------------------------------
|
|
CMapEntity *CMapPath::CreateEntityForNode(DWORD dwNodeID)
|
|
{
|
|
int iIndex;
|
|
CMapPathNode *pNode = NodeForID(dwNodeID, &iIndex);
|
|
if (pNode == NULL)
|
|
{
|
|
return NULL; // no node, no entity!
|
|
}
|
|
|
|
CMapEntity *pEntity = new CMapEntity;
|
|
|
|
for (int k = pNode->kv.GetFirst(); k != pNode->kv.GetInvalidIndex(); k=pNode->kv.GetNext( k ) )
|
|
{
|
|
pEntity->SetKeyValue(pNode->kv.GetKey(k), pNode->kv.GetValue(k));
|
|
}
|
|
|
|
// store target/targetname properties:
|
|
CString str;
|
|
str.Format("%s%02d", m_szName, iIndex);
|
|
pEntity->SetKeyValue("targetname", str);
|
|
|
|
int iNext = iIndex + 1;
|
|
if(iNext != -1)
|
|
{
|
|
str.Format("%s%02d", m_szName, iNext);
|
|
pEntity->SetKeyValue("target", str);
|
|
}
|
|
|
|
pEntity->SetClass(m_szClass);
|
|
|
|
return pEntity;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : dwNodeID -
|
|
// *pEntity -
|
|
//-----------------------------------------------------------------------------
|
|
void CMapPath::CopyNodeFromEntity(DWORD dwNodeID, CMapEntity *pEntity)
|
|
{
|
|
CMapPathNode *pNode = NodeForID(dwNodeID);
|
|
if (!pNode)
|
|
{
|
|
return; // no node, no copy!
|
|
}
|
|
|
|
pNode->kv.RemoveAll();
|
|
|
|
//
|
|
// Copy all the keys except target and targetname from the entity to the pathnode.
|
|
//
|
|
for ( int i=pEntity->GetFirstKeyValue(); i != pEntity->GetInvalidKeyValue(); i=pEntity->GetNextKeyValue( i ) )
|
|
{
|
|
if (!strcmp(pEntity->GetKey(i), "target") || !strcmp(pEntity->GetKey(i), "targetname"))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pNode->kv.SetValue(pEntity->GetKey(i), pEntity->GetKeyValue(i));
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *szKey -
|
|
// *szValue -
|
|
// *pNode -
|
|
// Output : CChunkFileResult_t
|
|
//-----------------------------------------------------------------------------
|
|
|
|
UNDONE: Nobody uses the path tool because the user interface is so poor.
|
|
Path support has been pulled until the tool itself can be fixed or replaced.
|
|
|
|
CChunkFileResult_t CMapPathNode::LoadKeyCallback(const char *szKey, const char *szValue, CMapPathNode *pNode)
|
|
{
|
|
if (!stricmp(szKey, "origin"))
|
|
{
|
|
CChunkFile::ReadKeyValueVector3(szValue, pNode->pos);
|
|
}
|
|
else if (!stricmp(szKey, "id"))
|
|
{
|
|
CChunkFile::ReadKeyValueInt(szValue, &pNode->dwID);
|
|
}
|
|
else if (!stricmp(szKey, "name"))
|
|
{
|
|
strcpy(pNode->szName, szValue);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *pFile -
|
|
// Output : ChunkFileResult_t
|
|
//-----------------------------------------------------------------------------
|
|
ChunkFileResult_t CMapPathNode::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
|
|
{
|
|
ChunkFileResult_t eResult = pFile->BeginChunk("node");
|
|
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->WriteKeyValueVector3("origin", node.pos);
|
|
}
|
|
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->WriteKeyValueInt("id", node.dwID);
|
|
}
|
|
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->WriteKeyValue("name", node.szName);
|
|
}
|
|
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->BeginChunk("keys");
|
|
}
|
|
|
|
//
|
|
// Write keyvalues.
|
|
//
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
iSize = kv.GetCount();
|
|
for (int k = 0; k < iSize; k++)
|
|
{
|
|
MDkeyvalue &KeyValue = kv.GetKeyValue(k);
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->WriteKeyValue(KeyValue.GetKey(), KeyValue.GetValue());
|
|
}
|
|
}
|
|
}
|
|
|
|
// End the keys chunk.
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->EndChunk();
|
|
}
|
|
|
|
// End the node chunk.
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->EndChunk();
|
|
}
|
|
|
|
return(eResult);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *szKey -
|
|
// *szValue -
|
|
// *pPath -
|
|
// Output : CChunkFileResult_t
|
|
//-----------------------------------------------------------------------------
|
|
CChunkFileResult_t CMapPath::LoadKeyCallback(const char *szKey, const char *szValue, CMapPath *pPath)
|
|
{
|
|
if (!stricmp(szKey, "name"))
|
|
{
|
|
pPath->SetName(szValue);
|
|
}
|
|
else if (!stricmp(szKey, "classname"))
|
|
{
|
|
pPath->SetClass(szValue);
|
|
}
|
|
else if (!stricmp(szKey, "direction"))
|
|
{
|
|
CChunkFile::ReadKeyValueInt(szValue, &pPath->m_iDirection);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *pFile -
|
|
//-----------------------------------------------------------------------------
|
|
void CMapPath::LoadVMF(CChunkFile *pFile)
|
|
{
|
|
file.read((char*) &iSize, sizeof iSize);
|
|
m_nNodes = iSize;
|
|
m_Nodes.SetSize(m_nNodes);
|
|
|
|
// read nodes
|
|
for (int i = 0; i < m_nNodes; i++)
|
|
{
|
|
CMapPathNode &node = m_Nodes[i];
|
|
|
|
// read keyvalues
|
|
file.read((char*) &iSize, sizeof(iSize));
|
|
KeyValues &kv = node.kv;
|
|
kv.SetSize(iSize);
|
|
for (int k = 0; k < iSize; k++)
|
|
{
|
|
MDkeyvalue &KeyValue = kv.GetKeyValue(k);
|
|
KeyValue.SerializeRMF(file, FALSE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *pFile -
|
|
//-----------------------------------------------------------------------------
|
|
void CMapPath::SaveVMF(CChunkFile *pFile, CSaveInfo *pSaveInfo)
|
|
{
|
|
int iSize;
|
|
|
|
ChunkFileResult_t eResult = pFile->BeginChunk("path");
|
|
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile-WriteKeyValue("name", m_szName);
|
|
}
|
|
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->WriteKeyValue("classname", m_szClass);
|
|
}
|
|
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->WriteKeyValueInt("direction", m_iDirection);
|
|
}
|
|
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
for (int i = 0; i < m_nNodes; i++)
|
|
{
|
|
CMapPathNode &node = m_Nodes[i];
|
|
eResult = node.SaveVMF(pFile, pSaveInfo);
|
|
}
|
|
}
|
|
|
|
if (eResult == ChunkFile_Ok)
|
|
{
|
|
eResult = pFile->EndChunk();
|
|
}
|
|
}
|
|
*/
|