summaryrefslogtreecommitdiff
path: root/hammer/loadsave_map.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/loadsave_map.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/loadsave_map.cpp')
-rw-r--r--hammer/loadsave_map.cpp1200
1 files changed, 1200 insertions, 0 deletions
diff --git a/hammer/loadsave_map.cpp b/hammer/loadsave_map.cpp
new file mode 100644
index 0000000..90acea3
--- /dev/null
+++ b/hammer/loadsave_map.cpp
@@ -0,0 +1,1200 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "stdafx.h"
+#include <io.h>
+#include "hammer.h"
+#include "GlobalFunctions.h"
+#include "MapErrorsDlg.h"
+#include "Options.h"
+#include "MapDoc.h"
+#include "MapEntity.h"
+#include "MapFace.h"
+#include "MapGroup.h"
+#include "MapSolid.h"
+#include "MapStudioModel.h"
+#include "MapWorld.h"
+#include "progdlg.h"
+#include "TextureSystem.h"
+#include "MapDisp.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+#pragma optimize("g", off)
+
+#pragma warning(disable: 4748) // buffer overrung with optimizations off - remove if we turn "g" back on
+
+#define TEXTURE_NAME_LEN 128
+
+// All files are opened in binary, and we want to save CR/LF
+#define ENDLINE "\r\n"
+
+
+enum
+{
+ fileOsError = -1, // big error!
+ fileError = -2, // problem
+ fileOk = -3, // loaded ok
+ fileDone = -4 // got not-my-kind of line
+};
+
+
+BOOL bSaveVisiblesOnly;
+
+
+static BOOL bErrors;
+static int nInvalidSolids;
+static CProgressDlg *pProgDlg;
+
+static MAPFORMAT MapFormat;
+
+static BOOL bStuffed;
+static char szStuffed[255];
+
+static UINT uMapVersion = 0;
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : buf -
+//-----------------------------------------------------------------------------
+static void StuffLine(char * buf)
+{
+ Assert(!bStuffed);
+ V_strcpy_safe(szStuffed, buf);
+ bStuffed = TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : file -
+// buf -
+//-----------------------------------------------------------------------------
+static void GetLine(std::fstream& file, char *buf)
+{
+ if(bStuffed)
+ {
+ if(buf)
+ strcpy(buf, szStuffed);
+ bStuffed = FALSE;
+ return;
+ }
+
+ char szBuf[1024];
+
+ while(1)
+ {
+ file >> std::ws;
+ file.getline(szBuf, 512);
+ if(file.eof())
+ return;
+ if(!strncmp(szBuf, "//", 2))
+ continue;
+ file >> std::ws;
+ if(buf)
+ {
+// char *p = strchr(szBuf, '\n');
+// if(p) p[0] = 0;
+// p = strchr(szBuf, '\r');
+// if(p) p[0] = 0;
+ strcpy(buf, szBuf);
+ }
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pObject -
+// file -
+// pIntersecting -
+// Output : int
+//-----------------------------------------------------------------------------
+static int SaveSolidChildrenOf(CMapClass *pObject, std::fstream& file, BoundBox *pIntersecting = NULL)
+{
+ CMapWorld *pWorld = (CMapWorld*) CMapClass::GetWorldObject(pObject);
+
+ //
+ // If we are only saving visible objects and this object isn't visible, don't save it.
+ //
+ if (bSaveVisiblesOnly && (pObject != pWorld) && !pObject->IsVisible())
+ {
+ return fileOk; // not an error - return ok
+ }
+
+ //
+ // If we are only saving objects within a particular bounding box and this object isn't, don't save it.
+ //
+ if (pIntersecting && !pObject->IsIntersectingBox(pIntersecting->bmins, pIntersecting->bmaxs))
+ {
+ return fileOk;
+ }
+
+
+ const CMapObjectList *pChildren = pObject->GetChildren();
+ FOR_EACH_OBJ( *pChildren, pos )
+ {
+ int iRvl = -1;
+ CMapClass *pChild = pChildren->Element(pos);
+
+ if (!pIntersecting || pChild->IsIntersectingBox(pIntersecting->bmins, pIntersecting->bmaxs))
+ {
+ if (pChild->IsMapClass(MAPCLASS_TYPE(CMapSolid)))
+ {
+ if (!bSaveVisiblesOnly || pChild->IsVisible())
+ {
+ iRvl = pChild->SerializeMAP(file, TRUE);
+ }
+ }
+ else if (pChild->IsMapClass(MAPCLASS_TYPE(CMapGroup)))
+ {
+ iRvl = SaveSolidChildrenOf(pChild, file, pIntersecting);
+ }
+
+ // return error if there is an error
+ if (iRvl != -1 && iRvl != fileOk)
+ {
+ return iRvl;
+ }
+ }
+ }
+
+ return fileOk; // ok.
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pObject -
+// file -
+// pIntersecting -
+// Output : int
+//-----------------------------------------------------------------------------
+static int SaveEntityChildrenOf(CMapClass *pObject, std::fstream& file, BoundBox *pIntersecting)
+{
+ CMapWorld *pWorld = (CMapWorld *)CMapClass::GetWorldObject(pObject);
+
+ if (bSaveVisiblesOnly && pObject != pWorld && !pObject->IsVisible())
+ {
+ return fileOk; // no error
+ }
+
+ if (pIntersecting && !pObject->IsIntersectingBox(pIntersecting->bmins, pIntersecting->bmaxs))
+ {
+ return fileOk;
+ }
+
+
+ const CMapObjectList *pChildren = pObject->GetChildren();
+ FOR_EACH_OBJ( *pChildren, pos )
+ {
+ int iRvl = -1;
+
+ CMapClass *pChild = pChildren->Element(pos);
+
+ if (!pIntersecting || pChild->IsIntersectingBox(pIntersecting->bmins, pIntersecting->bmaxs))
+ {
+ if (pChild->IsMapClass(MAPCLASS_TYPE(CMapEntity)))
+ {
+ if (!bSaveVisiblesOnly || pChild->IsVisible())
+ {
+ iRvl = pChild->SerializeMAP(file, TRUE);
+ }
+ }
+ else if (pChild->IsMapClass(MAPCLASS_TYPE(CMapGroup)))
+ {
+ iRvl = SaveEntityChildrenOf(pChild, file, pIntersecting);
+ }
+
+ // return error if there is an error
+ if (iRvl != -1 && iRvl != fileOk)
+ {
+ return iRvl;
+ }
+ }
+ }
+
+ return fileOk; // ok.
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pObject -
+// file -
+// Output : int
+//-----------------------------------------------------------------------------
+static int ReadSolids(CMapClass *pObject, std::fstream& file)
+{
+ int nSolids = 0;
+ char szBuf[128];
+
+ while(1)
+ {
+ GetLine(file, szBuf);
+ if(szBuf[0] != '{')
+ {
+ StuffLine(szBuf);
+ break;
+ }
+
+ CMapSolid *pSolid = new CMapSolid;
+ int iRvl = pSolid->SerializeMAP(file, FALSE);
+ if(iRvl == fileError)
+ {
+ // delete the solid
+ delete pSolid;
+ ++nInvalidSolids;
+ }
+ else if(iRvl == fileOsError)
+ {
+ // big problem
+ delete pSolid;
+ return fileOsError;
+ }
+ else
+ pObject->AddChild(pSolid);
+
+ ++nSolids;
+ }
+
+ return nSolids;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : file -
+// Output : int
+//-----------------------------------------------------------------------------
+static int PeekChar(std::fstream& file)
+{
+ if(bStuffed) // stuffed.. return first char
+ return szStuffed[0];
+ char szBuf[1024];
+ szBuf[0] = 0;
+ // get next line
+ GetLine(file, szBuf);
+
+ // still blank? return eof
+ if(szBuf[0] == 0)
+ return EOF;
+
+ // to get it next call to getline
+ StuffLine(szBuf);
+
+ return szBuf[0];
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the MAP format for saving.
+// Input : mf - MAP format to use when saving.
+//-----------------------------------------------------------------------------
+void SetMapFormat(MAPFORMAT mf)
+{
+ Assert((mf == mfHalfLife) || (mf == mfHalfLife2));
+ MapFormat = mf;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : file -
+// fIsStoring -
+// Output : int
+//-----------------------------------------------------------------------------
+int CMapClass::SerializeMAP(std::fstream& file, BOOL fIsStoring)
+{
+ // no info stored in MAPs ..
+ return fileOk;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : file -
+// fIsStoring -
+// Output : int
+//-----------------------------------------------------------------------------
+int CMapFace::SerializeMAP(std::fstream& file, BOOL fIsStoring)
+{
+ char szBuf[512];
+
+ if (fIsStoring)
+ {
+ char *pszTexture;
+ char szTexture[sizeof(texture.texture)+1];
+ szTexture[sizeof(texture.texture)] = 0;
+ memcpy(szTexture, texture.texture, sizeof texture.texture);
+ strlwr(szTexture);
+
+ if (MapFormat == mfQuake2)
+ {
+ pszTexture = strstr(szTexture, ".");
+ if (pszTexture)
+ {
+ *pszTexture = 0;
+ }
+ pszTexture = strstr(szTexture, "textures\\");
+ if (pszTexture == NULL)
+ {
+ pszTexture = szTexture;
+ }
+ else
+ {
+ pszTexture += strlen("textures\\");
+ }
+ }
+ else
+ {
+ pszTexture = szTexture;
+ }
+
+ strupr(szTexture);
+
+
+ //
+ // Reverse the slashes -- thank you id.
+ //
+ for (int i = strlen(pszTexture) - 1; i >= 0; i--)
+ {
+ if (pszTexture[i] == '\\')
+ pszTexture[i] = '/';
+ }
+
+ //
+ // Convert the plane points to integers.
+ //
+ for (int nPlane = 0; nPlane < 3; nPlane++)
+ {
+ plane.planepts[nPlane][0] = V_rint(plane.planepts[nPlane][0]);
+ plane.planepts[nPlane][1] = V_rint(plane.planepts[nPlane][1]);
+ plane.planepts[nPlane][2] = V_rint(plane.planepts[nPlane][2]);
+ }
+
+ //
+ // Check for duplicate plane points. All three plane points must be unique
+ // or it isn't a valid plane. Try to fix it if it isn't valid.
+ //
+ if (!CheckFace())
+ {
+ Fix();
+ }
+
+ sprintf(szBuf,
+ "( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) "
+ "%s "
+ "[ %g %g %g %g ] "
+ "[ %g %g %g %g ] "
+ "%g %g %g ",
+
+ plane.planepts[0][0], plane.planepts[0][1], plane.planepts[0][2],
+ plane.planepts[1][0], plane.planepts[1][1], plane.planepts[1][2],
+ plane.planepts[2][0], plane.planepts[2][1], plane.planepts[2][2],
+
+ pszTexture,
+
+ (double)texture.UAxis[0], (double)texture.UAxis[1], (double)texture.UAxis[2], (double)texture.UAxis[3],
+ (double)texture.VAxis[0], (double)texture.VAxis[1], (double)texture.VAxis[2], (double)texture.VAxis[3],
+
+ (double)texture.rotate,
+ (double)texture.scale[0],
+ (double)texture.scale[1]);
+
+ file << szBuf << ENDLINE;
+
+ return fileOk;
+ }
+ else
+ {
+ // load the plane
+ GetLine(file, szBuf);
+
+ if(szBuf[0] != '(')
+ {
+ StuffLine(szBuf);
+ return fileDone;
+ }
+
+ char szTexName[TEXTURE_NAME_LEN];
+ DWORD q2contents;
+ DWORD q2surface;
+ int nLightmapScale;
+ int nDummy;
+ int nRead;
+
+ if( uMapVersion >= 340 )
+ {
+ COMPILE_TIME_ASSERT( ARRAYSIZE(szTexName) == 128 );
+ nRead = sscanf(szBuf,
+ "( %f %f %f ) ( %f %f %f ) ( %f %f %f ) "
+ "%127s "
+ "[ %f %f %f %f ] "
+ "[ %f %f %f %f ] "
+ "%f %f %f "
+ "%u %u %u",
+
+ &plane.planepts[0][0], &plane.planepts[0][1], &plane.planepts[0][2],
+ &plane.planepts[1][0], &plane.planepts[1][1], &plane.planepts[1][2],
+ &plane.planepts[2][0], &plane.planepts[2][1], &plane.planepts[2][2],
+
+ szTexName,
+
+ &texture.UAxis[0], &texture.UAxis[1], &texture.UAxis[2], &texture.UAxis[3],
+ &texture.VAxis[0], &texture.VAxis[1], &texture.VAxis[2], &texture.VAxis[3],
+
+ &texture.rotate,
+ &texture.scale[0],
+ &texture.scale[1],
+
+ &q2contents,
+ &q2surface,
+ &nLightmapScale);
+ // Guarantee null-termination to keep /analyze happy.
+ szTexName[ ARRAYSIZE(szTexName) - 1 ] = 0;
+
+ if (nRead < 21)
+ {
+ bErrors = TRUE;
+ }
+ else if (nRead == 24)
+ {
+ // got q2 values - set them here
+ texture.q2contents = q2contents;
+ texture.q2surface = q2surface;
+ texture.nLightmapScale = nLightmapScale;
+ if (texture.nLightmapScale == 0)
+ {
+ texture.nLightmapScale = g_pGameConfig->GetDefaultLightmapScale();
+ }
+ }
+
+ //
+ // very cheesy HACK!!! -- this will be better when we have chunks
+ //
+ if( uMapVersion <= 350 )
+ {
+ if( ( file.peek() != '(' ) && ( file.peek() != '}' ) )
+ {
+ EditDispHandle_t handle = EditDispMgr()->Create();
+ SetDisp( handle );
+
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
+ pDisp->SerializedLoadMAP( file, this, uMapVersion );
+ }
+ }
+ }
+ else if (uMapVersion >= 220 )
+ {
+ COMPILE_TIME_ASSERT( ARRAYSIZE(szTexName) == 128 );
+ nRead = sscanf(szBuf,
+ "( %f %f %f ) ( %f %f %f ) ( %f %f %f ) "
+ "%127s "
+ "[ %f %f %f %f ] "
+ "[ %f %f %f %f ] "
+ "%f %f %f "
+ "%u %u %u",
+
+ &plane.planepts[0][0], &plane.planepts[0][1], &plane.planepts[0][2],
+ &plane.planepts[1][0], &plane.planepts[1][1], &plane.planepts[1][2],
+ &plane.planepts[2][0], &plane.planepts[2][1], &plane.planepts[2][2],
+
+ szTexName,
+
+ &texture.UAxis[0], &texture.UAxis[1], &texture.UAxis[2], &texture.UAxis[3],
+ &texture.VAxis[0], &texture.VAxis[1], &texture.VAxis[2], &texture.VAxis[3],
+
+ &texture.rotate,
+ &texture.scale[0],
+ &texture.scale[1],
+
+ &q2contents,
+ &q2surface,
+ &nDummy); // Pre-340 didn't have lightmap scale.
+ // Guarantee null-termination to keep /analyze happy.
+ szTexName[ ARRAYSIZE(szTexName) - 1 ] = 0;
+
+ if (nRead < 21)
+ {
+ bErrors = TRUE;
+ }
+ else if (nRead == 24)
+ {
+ // got q2 values - set them here
+ texture.q2contents = q2contents;
+ texture.q2surface = q2surface;
+ }
+ }
+ else
+ {
+ COMPILE_TIME_ASSERT( ARRAYSIZE(szTexName) == 128 );
+ nRead = sscanf(szBuf,
+ "( %f %f %f ) ( %f %f %f ) ( %f %f %f ) "
+ "%127s "
+ "%f %f %f "
+ "%f %f %u %u %u",
+
+ &plane.planepts[0][0], &plane.planepts[0][1], &plane.planepts[0][2],
+ &plane.planepts[1][0], &plane.planepts[1][1], &plane.planepts[1][2],
+ &plane.planepts[2][0], &plane.planepts[2][1], &plane.planepts[2][2],
+
+ szTexName,
+
+ &texture.UAxis[3],
+ &texture.VAxis[3],
+ &texture.rotate,
+ &texture.scale[0],
+ &texture.scale[1],
+
+ &q2contents,
+ &q2surface,
+ &nDummy); // Pre-340 didn't have lightmap scale.
+ // Guarantee null-termination to keep /analyze happy.
+ szTexName[ ARRAYSIZE(szTexName) - 1 ] = 0;
+
+ if (nRead < 15)
+ {
+ bErrors = TRUE;
+ }
+ else if (nRead == 18)
+ {
+ // got q2 values - set them here
+ texture.q2contents = q2contents;
+ texture.q2surface = q2surface;
+ }
+ }
+
+ if (g_pGameConfig->GetTextureFormat() != tfVMT)
+ {
+ // reverse the slashes -- thank you id
+ for (int i = strlen(szTexName) - 1; i >= 0; i--)
+ {
+ if (szTexName[i] == '/')
+ szTexName[i] = '\\';
+ }
+ }
+
+ SetTexture(szTexName);
+ }
+
+ if (file.fail())
+ {
+ return fileOsError;
+ }
+ return fileOk;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : file -
+// fIsStoring -
+// Output : int
+//-----------------------------------------------------------------------------
+int MDkeyvalue::SerializeMAP(std::fstream& file, BOOL fIsStoring)
+{
+ // load/save a keyvalue
+ char szBuf[1024];
+
+ if(fIsStoring)
+ {
+ // save a keyvalue
+ sprintf( szBuf,
+ "\"%s\" \"%s\"",
+
+ Key(), Value() );
+
+ file << szBuf << ENDLINE;
+ }
+ else
+ {
+ GetLine(file, szBuf);
+ if(szBuf[0] != '\"')
+ {
+ StuffLine(szBuf);
+ return fileDone;
+ }
+ char *p = strchr(szBuf, '\"');
+ p = strchr(p+1, '\"');
+ if(!p)
+ return fileError;
+ p[0] = 0;
+ V_strcpy_safe(szKey, szBuf+1);
+
+ // advance to start of value string
+ p = strchr(p+1, '\"');
+ if(!p)
+ return fileError;
+ // ocpy in value
+ strcpy(szValue, p+1);
+ // kill trailing "
+ p = strchr(szValue, '\"');
+ if(!p)
+ return fileError;
+ p[0] = 0;
+ }
+
+ return file.fail() ? fileOsError : fileOk;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : file -
+// fIsStoring -
+// Output : int
+//-----------------------------------------------------------------------------
+int CMapSolid::SerializeMAP(std::fstream& file, BOOL fIsStoring)
+{
+ CMapClass::SerializeMAP(file, fIsStoring);
+
+ // load/save a brush
+ if (fIsStoring)
+ {
+ // save the brush
+ file << "{" << ENDLINE;
+
+ // serialize the Faces
+ int nFaces = Faces.GetCount();
+ for(int i = 0; i < nFaces; i++)
+ {
+ if(!Faces[i].Points)
+ continue;
+ if(Faces[i].SerializeMAP(file, fIsStoring) == fileError)
+ return fileError;
+ }
+
+ // terminator
+ file << "}" << ENDLINE;
+ }
+ else
+ {
+ // caller skipped delimiter
+ Faces.SetCount(0);
+
+ // read Faces
+ for(int i = 0; ; i++)
+ {
+ // extract plane
+ if (Faces[i].SerializeMAP(file, fIsStoring) == fileDone)
+ {
+ // when fileDone is returned, no face was loaded
+ break;
+ }
+
+ Faces[i].CalcPlane();
+ }
+
+ GetLine(file, NULL); // ignore line
+
+ if (!file.fail())
+ {
+ //
+ // Create the solid using the planes that were read from the MAP file.
+ //
+ if (CreateFromPlanes() == FALSE)
+ {
+ bErrors = TRUE;
+ return(fileError);
+ }
+
+ //
+ // If we are reading from an old map file, the texture axes will need to be set up.
+ // Leave the rotation and shifts alone; they were read from the MAP file.
+ //
+ if (uMapVersion < 220)
+ {
+ InitializeTextureAxes(TEXTURE_ALIGN_QUAKE, INIT_TEXTURE_AXES | INIT_TEXTURE_FORCE);
+ }
+ }
+ else
+ {
+ return(fileOsError);
+ }
+
+ CalcBounds();
+
+ //
+ // Set solid type based on texture name.
+ //
+ m_eSolidType = HL1SolidTypeFromTextureName(Faces[0].texture.texture);
+ }
+
+ return(file.fail() ? fileOsError : fileOk);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : file -
+// fIsStoring -
+// Output : int
+//-----------------------------------------------------------------------------
+int CMapEntity::SerializeMAP(std::fstream &file, BOOL fIsStoring)
+{
+ CMapClass::SerializeMAP(file, fIsStoring);
+
+ // load/save an object
+ if (fIsStoring)
+ {
+ //
+ // If it's a solidentity but it doesn't have any solids,
+ // don't save it.
+ //
+ if (!IsPlaceholder() && !m_Children.Count())
+ {
+ return(fileOk);
+ }
+
+ //
+ // Save it.
+ //
+ file << "{" << ENDLINE;
+
+ //
+ // Save keyvalues & other data.
+ //
+ CEditGameClass::SerializeMAP(file, fIsStoring);
+
+ //
+ // If this is a placeholder and either has no class or is not a solid class,
+ // save our origin.
+ //
+ if (IsPlaceholder() && (!IsClass() || !IsSolidClass()))
+ {
+ MDkeyvalue tmpkv;
+ strcpy(tmpkv.szKey, "origin");
+
+ Vector Origin;
+ GetOrigin(Origin);
+ sprintf(tmpkv.szValue, "%.0f %.0f %.0f", Origin[0], Origin[1], Origin[2]);
+ tmpkv.SerializeMAP(file, fIsStoring);
+ }
+
+ if (!(IsPlaceholder()))
+ {
+ SaveSolidChildrenOf(this, file);
+ }
+
+ file << "}" << ENDLINE;
+ }
+ else
+ {
+ // load keyvalues
+ CEditGameClass::SerializeMAP(file, fIsStoring);
+
+ // solids
+ if (!ReadSolids(this, file))
+ {
+ flags |= flagPlaceholder;
+ }
+
+ // skip delimiter
+ GetLine(file, NULL);
+ }
+
+ return file.fail() ? fileOsError : fileOk;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : file -
+// fIsStoring -
+// Output : int
+//-----------------------------------------------------------------------------
+int CEditGameClass::SerializeMAP(std::fstream& file, BOOL fIsStoring)
+{
+ int iRvl;
+
+ if (!fIsStoring)
+ {
+ // loading
+ if (PeekChar(file) == '\"')
+ {
+ // read kv pairs
+ MDkeyvalue newkv;
+ while (1)
+ {
+ if (newkv.SerializeMAP(file, fIsStoring) != fileOk)
+ {
+ // fileDone means the keyvalue was not loaded
+ break;
+ }
+
+ if (!strcmp(newkv.szKey, "classname"))
+ {
+ m_KeyValues.SetValue(newkv.szKey, newkv.szValue);
+ }
+ else if (!strcmp(newkv.szKey, "angle"))
+ {
+ ImportAngle(atoi(newkv.szValue));
+ }
+ else if (strcmp(newkv.szKey, "wad"))
+ {
+ //
+ // All other keys are simply added to the keyvalue list.
+ //
+ m_KeyValues.SetValue(newkv.szKey, newkv.szValue);
+ }
+ }
+ }
+ }
+ else
+ {
+ // save keyvalues
+ MDkeyvalue tmpkv;
+
+ if (GetKeyValue("classname") == NULL)
+ {
+ tmpkv.Set("classname", m_szClass);
+ tmpkv.SerializeMAP(file, fIsStoring);
+ }
+
+ //
+ // Determine whether we have a game data class. This will help us decide which keys
+ // to write.
+ //
+ GDclass *pGameDataClass = NULL;
+ if (pGD != NULL)
+ {
+ pGameDataClass = pGD->ClassForName(m_szClass);
+ }
+
+ //
+ // Consider all the keyvalues in this object for serialization.
+ //
+ for ( int z=m_KeyValues.GetFirst(); z != m_KeyValues.GetInvalidIndex(); z=m_KeyValues.GetNext( z ) )
+ {
+ MDkeyvalue &KeyValue = m_KeyValues.GetKeyValue(z);
+
+ iRvl = KeyValue.SerializeMAP(file, fIsStoring);
+ if (iRvl != fileOk)
+ {
+ return(iRvl);
+ }
+ }
+
+ //
+ // If we have a base class, for each keyvalue in the class definition, write out all keys
+ // that are not present in the object and whose defaults are nonzero in the class definition.
+ //
+ if (pGameDataClass != NULL)
+ {
+ //
+ // For each variable from the base class...
+ //
+ int nVariableCount = pGameDataClass->GetVariableCount();
+ for (int i = 0; i < nVariableCount; i++)
+ {
+ GDinputvariable *pVar = pGameDataClass->GetVariableAt(i);
+ Assert(pVar != NULL);
+
+ if (pVar != NULL)
+ {
+ int iIndex;
+ MDkeyvalue *pKey;
+ LPCTSTR p = m_KeyValues.GetValue(pVar->GetName(), &iIndex);
+
+ //
+ // If the variable is not present in this object, write out the default value.
+ //
+ if (p == NULL)
+ {
+ pKey = &tmpkv;
+ pVar->ResetDefaults();
+ pVar->ToKeyValue(pKey);
+
+ //
+ // Only write the key value if it is non-zero.
+ //
+ if ((pKey->szKey[0] != 0) && (pKey->szValue[0] != 0) && (stricmp(pKey->szValue, "0")))
+ {
+ iRvl = pKey->SerializeMAP(file, fIsStoring);
+ if (iRvl != fileOk)
+ {
+ return(iRvl);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return(file.fail() ? fileOsError : fileOk);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : file -
+// fIsStoring -
+// pIntersecting -
+// Output : int
+//-----------------------------------------------------------------------------
+int CMapWorld::SerializeMAP(std::fstream &file, BOOL fIsStoring, BoundBox *pIntersecting)
+{
+ int iRvl;
+
+ bStuffed = FALSE;
+ bErrors = FALSE;
+ nInvalidSolids = 0;
+
+ // load/save a world
+ if (fIsStoring)
+ {
+ file << "{" << ENDLINE;
+
+ // save worldobject
+ CEditGameClass::SerializeMAP(file, fIsStoring);
+
+ if (MapFormat != mfQuake2)
+ {
+ MDkeyvalue tmpkv;
+
+ strcpy(tmpkv.szKey, "mapversion");
+ strcpy(tmpkv.szValue, "360");
+ tmpkv.SerializeMAP(file, fIsStoring);
+
+ // Save wad file line
+ strcpy(tmpkv.szKey, "wad");
+
+ // copy all texfiles into value
+ tmpkv.szValue[0] = 0;
+ BOOL bFirst = TRUE;
+ int nGraphicsFiles = g_Textures.FilesGetCount();
+ for (int i = 0; i < nGraphicsFiles; i++)
+ {
+ char szFile[MAX_PATH];
+ GRAPHICSFILESTRUCT gf;
+
+ g_Textures.FilesGetInfo(&gf, i);
+
+ //
+ // Don't save WAL files - they're never used.
+ //
+ if (gf.format != tfWAL)
+ {
+ //
+ // Also make sure this is the right kind of WAD file
+ // based on the game we're using.
+ //
+ if (gf.format == g_pGameConfig->GetTextureFormat())
+ {
+ //
+ // Append this WAD file to the WAD list.
+ //
+ strcpy(szFile, gf.filename);
+
+ // dvs: Strip off the path. This crashes VIS and QRAD!!
+ /*
+ char *pszSlash = strrchr(szFile, '\\');
+ if (pszSlash == NULL)
+ {
+ pszSlash = strrchr(szFile, '/');
+ }
+
+ if (pszSlash != NULL)
+ {
+ pszSlash++;
+ }
+ else
+ {
+ pszSlash = szFile;
+ }
+ */
+
+ char *pszSlash = szFile;
+
+ // Strip off any drive letter.
+ if (pszSlash[1] == ':')
+ {
+ pszSlash += 2;
+ }
+
+ // WAD names are semicolon delimited.
+ if (!bFirst)
+ {
+ strcat(tmpkv.szValue, ";");
+ }
+
+ strcat(tmpkv.szValue, pszSlash);
+ bFirst = FALSE;
+ }
+ }
+ }
+
+ if ( tmpkv.szValue[0] != '\0' )
+ {
+ tmpkv.SerializeMAP(file, fIsStoring);
+ }
+ }
+
+ //
+ // Save the brushes.
+ //
+ if (SaveSolidChildrenOf(this, file, pIntersecting) == fileOsError)
+ {
+ goto FatalError;
+ }
+
+ file << "}" << ENDLINE;
+
+ //
+ // Save the entities.
+ //
+ if (SaveEntityChildrenOf(this, file, pIntersecting) == fileOsError)
+ {
+ goto FatalError;
+ }
+
+ //
+ // Save paths (if paths are visible).
+ //
+ FOR_EACH_OBJ( m_Paths, pos )
+ {
+ CMapPath *pPath = m_Paths.Element(pos);
+ pPath->SerializeMAP(file, TRUE, pIntersecting);
+ }
+ }
+ else
+ {
+ pProgDlg = new CProgressDlg;
+ pProgDlg->Create();
+ pProgDlg->SetStep(1);
+
+ CString caption;
+ caption.LoadString(IDS_LOADINGFILE);
+ pProgDlg->SetWindowText(caption);
+
+ m_Render2DBox.ResetBounds();
+
+ // load world
+ GetLine(file, NULL); // ignore delimiter
+ CEditGameClass::SerializeMAP(file, fIsStoring);
+
+ const char* pszMapVersion;
+
+ pszMapVersion = m_KeyValues.GetValue("mapversion");
+ if (pszMapVersion != NULL)
+ {
+ uMapVersion = atoi(pszMapVersion);
+ }
+ else
+ {
+ uMapVersion = 0;
+ }
+
+ // read solids
+ if (ReadSolids(this, file) == fileOsError)
+ {
+ goto FatalError;
+ }
+
+ // skip end-of-entity marker
+ GetLine(file, NULL);
+
+ char szBuf[128];
+
+ // read entities
+ while (1)
+ {
+ GetLine(file, szBuf);
+ if (szBuf[0] != '{')
+ {
+ StuffLine(szBuf);
+ break;
+ }
+
+ if (PeekChar(file) == EOF)
+ {
+ break;
+ }
+
+ CMapEntity *pEntity;
+
+ pEntity = new CMapEntity;
+ iRvl = pEntity->SerializeMAP(file, fIsStoring);
+ AddChild(pEntity);
+
+ if (iRvl == fileError)
+ {
+ bErrors = TRUE;
+ }
+ else if (iRvl == fileOsError)
+ {
+ goto FatalError;
+ }
+ }
+
+ if (bErrors)
+ {
+ if (nInvalidSolids)
+ {
+ CString str;
+ str.Format("For your information, %d solids were not loaded\n"
+ "due to errors in the file.", nInvalidSolids);
+ AfxMessageBox(str);
+ }
+ else if (AfxMessageBox("There was a problem loading the MAP file. Do you\n"
+ "want to view the error report?", MB_YESNO) == IDYES)
+ {
+ CMapErrorsDlg dlg;
+ dlg.DoModal();
+ }
+ }
+
+ PostloadWorld();
+
+ if (g_pGameConfig->GetTextureFormat() == tfVMT)
+ {
+ // do batch search and replace of textures from trans.txt if it exists.
+ char translationFilename[MAX_PATH];
+ Q_snprintf( translationFilename, sizeof( translationFilename ), "materials/trans.txt" );
+ if( CMapDoc::GetActiveMapDoc() )
+ {
+ FileHandle_t searchReplaceFP = g_pFileSystem->Open( translationFilename, "r" );
+ if( searchReplaceFP )
+ {
+ CMapDoc::GetActiveMapDoc()->BatchReplaceTextures( searchReplaceFP );
+ g_pFileSystem->Close( searchReplaceFP );
+ }
+ }
+ }
+ }
+
+ if (pProgDlg)
+ {
+ pProgDlg->DestroyWindow();
+ delete pProgDlg;
+ pProgDlg = NULL;
+ }
+
+ return (bErrors && fIsStoring) ? -1 : 0;
+
+FatalError:
+
+ // OS error.
+ CString str;
+ str.Format("The OS reported an error %s the file: %s", fIsStoring ? "saving" : "loading", strerror(errno));
+ AfxMessageBox(str);
+
+ if (pProgDlg != NULL)
+ {
+ pProgDlg->DestroyWindow();
+ delete pProgDlg;
+ pProgDlg = NULL;
+ }
+
+ return -1;
+}
+