mirror of
https://github.com/celisej567/source-engine.git
synced 2026-01-04 18:09:53 +03:00
1
This commit is contained in:
991
hammer/prefabs.cpp
Normal file
991
hammer/prefabs.cpp
Normal file
@@ -0,0 +1,991 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implements a system for managing prefabs. There are two types
|
||||
// of prefabs implemented here: Half-Life style prefabs, and Half-Life 2
|
||||
// style prefabs.
|
||||
//
|
||||
// For Half-Life, prefab libraries are stored as binary .OL files, each of
|
||||
// which contains multiple .RMF files that are the prefabs.
|
||||
//
|
||||
// For Half-Life 2, prefabs are stored in a tree of folders, each folder
|
||||
// representing a library, and the each .VMF file in the folder containing
|
||||
// a single prefab.
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "Prefabs.h"
|
||||
#include "Prefab3D.h"
|
||||
#include "hammer.h"
|
||||
#include <io.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include <tier0/memdbgon.h>
|
||||
|
||||
|
||||
BOOL CPrefab::bCacheEnabled = TRUE;
|
||||
CPrefabList CPrefab::PrefabList;
|
||||
CPrefabList CPrefab::MRU;
|
||||
CPrefabLibraryList CPrefabLibrary::PrefabLibraryList;
|
||||
|
||||
|
||||
static char *pLibHeader = "Worldcraft Prefab Library\r\n\x1a";
|
||||
static float fLibVersion = 0.1f;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DWORD dwOffset;
|
||||
DWORD dwSize;
|
||||
char szName[31];
|
||||
char szNotes[MAX_NOTES];
|
||||
int iType;
|
||||
} PrefabHeader;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float fVersion;
|
||||
DWORD dwDirOffset;
|
||||
DWORD dwNumEntries;
|
||||
char szNotes[MAX_NOTES];
|
||||
} PrefabLibraryHeader;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Creates a prefab library from a given path.
|
||||
// Input : szFile -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibrary *CreatePrefabLibrary(const char *szFile)
|
||||
{
|
||||
CPrefabLibrary *pLibrary;
|
||||
|
||||
if (stricmp(&szFile[strlen(szFile) - 2], ".ol") != 0)
|
||||
{
|
||||
pLibrary = new CPrefabLibraryVMF;
|
||||
}
|
||||
else
|
||||
{
|
||||
pLibrary = new CPrefabLibraryRMF;
|
||||
}
|
||||
|
||||
if (pLibrary->Load(szFile) == -1)
|
||||
{
|
||||
delete pLibrary;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
return(pLibrary);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefab::CPrefab()
|
||||
{
|
||||
static DWORD dwRunningID = 1;
|
||||
// assign running ID
|
||||
dwID = dwRunningID++;
|
||||
PrefabList.AddTail(this);
|
||||
|
||||
// assign blank name/notes
|
||||
szName[0] = szNotes[0] = 0;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefab::~CPrefab()
|
||||
{
|
||||
POSITION p = PrefabList.Find(this);
|
||||
if(p)
|
||||
PrefabList.RemoveAt(p);
|
||||
p = MRU.Find(this);
|
||||
if(p)
|
||||
MRU.RemoveAt(p);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : dwID -
|
||||
// Output : CPrefab *
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefab * CPrefab::FindID(DWORD dwID)
|
||||
{
|
||||
POSITION p = PrefabList.GetHeadPosition();
|
||||
while(p)
|
||||
{
|
||||
CPrefab *pPrefab = PrefabList.GetNext(p);
|
||||
if(pPrefab->dwID == dwID)
|
||||
return pPrefab;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : b -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefab::EnableCaching(BOOL b)
|
||||
{
|
||||
bCacheEnabled = b;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pPrefab -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefab::AddMRU(CPrefab *pPrefab)
|
||||
{
|
||||
if(!bCacheEnabled)
|
||||
return;
|
||||
|
||||
POSITION p = MRU.Find(pPrefab);
|
||||
if(p)
|
||||
{
|
||||
// remove there and add to head
|
||||
MRU.RemoveAt(p);
|
||||
}
|
||||
else if(MRU.GetCount() == 5)
|
||||
{
|
||||
// uncache tail object
|
||||
p = MRU.GetTailPosition();
|
||||
if(p) // might not be any yet
|
||||
{
|
||||
CPrefab *pUncache = MRU.GetAt(p);
|
||||
pUncache->FreeData();
|
||||
MRU.RemoveAt(p);
|
||||
}
|
||||
}
|
||||
|
||||
// add to head
|
||||
MRU.AddHead(pPrefab);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefab::FreeAllData()
|
||||
{
|
||||
// free all prefab data memory
|
||||
POSITION p = PrefabList.GetHeadPosition();
|
||||
while(p)
|
||||
{
|
||||
CPrefab *pPrefab = PrefabList.GetNext(p);
|
||||
pPrefab->FreeData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszFilename -
|
||||
// Output : CPrefab::pfiletype_t
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefab::pfiletype_t CPrefab::CheckFileType(LPCTSTR pszFilename)
|
||||
{
|
||||
// first check extensions
|
||||
const char *p = strrchr(pszFilename, '.');
|
||||
if(p)
|
||||
{
|
||||
if(!strcmpi(p, ".rmf"))
|
||||
return pftRMF;
|
||||
else if(!strcmpi(p, ".map"))
|
||||
return pftMAP;
|
||||
else if(!strcmpi(p, ".os"))
|
||||
return pftScript;
|
||||
}
|
||||
|
||||
std::fstream file(pszFilename, std::ios::in | std::ios::binary);
|
||||
|
||||
// read first 16 bytes of file
|
||||
char szBuf[255];
|
||||
file.read(szBuf, 16);
|
||||
|
||||
// check 1: RMF
|
||||
float f = ((float*) szBuf)[0];
|
||||
|
||||
// 0.8 was version at which RMF tag was started
|
||||
if(f <= 0.7f || !strncmp(szBuf+sizeof(float), "RMF", 3))
|
||||
{
|
||||
return pftRMF;
|
||||
}
|
||||
|
||||
// check 2: script
|
||||
if(!strnicmp(szBuf, "[Script", 7))
|
||||
{
|
||||
return pftScript;
|
||||
}
|
||||
|
||||
// check 3: MAP
|
||||
int i = 500;
|
||||
while(i--)
|
||||
{
|
||||
file >> std::ws;
|
||||
file.getline(szBuf, 255);
|
||||
if(szBuf[0] == '{')
|
||||
return pftMAP;
|
||||
if(file.eof())
|
||||
break;
|
||||
}
|
||||
|
||||
return pftUnknown;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibrary::CPrefabLibrary()
|
||||
{
|
||||
static DWORD dwRunningID = 1;
|
||||
// assign running ID
|
||||
dwID = dwRunningID++;
|
||||
m_szName[0] = '\0';
|
||||
szNotes[0] = '\0';
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibrary::~CPrefabLibrary()
|
||||
{
|
||||
FreePrefabs();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefabLibrary::FreePrefabs()
|
||||
{
|
||||
// nuke prefabs
|
||||
POSITION p = Prefabs.GetHeadPosition();
|
||||
while (p != NULL)
|
||||
{
|
||||
CPrefab *pPrefab = Prefabs.GetNext(p);
|
||||
delete pPrefab;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *a -
|
||||
// *b -
|
||||
// Output : static int
|
||||
//-----------------------------------------------------------------------------
|
||||
static int __cdecl SortPrefabs(CPrefab *a, CPrefab *b)
|
||||
{
|
||||
return(strcmpi(a->GetName(), b->GetName()));
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefabLibrary::Sort(void)
|
||||
{
|
||||
int nPrefabs = Prefabs.GetCount();
|
||||
if (nPrefabs < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CPrefab **TmpPrefabArray = new CPrefab *[nPrefabs];
|
||||
|
||||
//
|
||||
// Make an array we can pass to qsort.
|
||||
//
|
||||
POSITION p = ENUM_START;
|
||||
CPrefab *pPrefab = EnumPrefabs(p);
|
||||
int iPrefab = 0;
|
||||
while (pPrefab != NULL)
|
||||
{
|
||||
TmpPrefabArray[iPrefab++] = pPrefab;
|
||||
pPrefab = EnumPrefabs(p);
|
||||
}
|
||||
|
||||
//
|
||||
// Sort the prefabs array by name.
|
||||
//
|
||||
qsort(TmpPrefabArray, nPrefabs, sizeof(CPrefab *), (int (__cdecl *)(const void *, const void *))SortPrefabs);
|
||||
|
||||
//
|
||||
// Store back in list in sorted order.
|
||||
//
|
||||
Prefabs.RemoveAll();
|
||||
for (int i = 0; i < nPrefabs; i++)
|
||||
{
|
||||
Prefabs.AddTail(TmpPrefabArray[i]);
|
||||
}
|
||||
|
||||
delete[] TmpPrefabArray;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszFilename -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefabLibrary::SetNameFromFilename(LPCTSTR pszFilename)
|
||||
{
|
||||
const char *cp = strrchr(pszFilename, '\\');
|
||||
strcpy(m_szName, cp ? (cp + 1) : pszFilename);
|
||||
char *p = strchr(m_szName, '.');
|
||||
if (p != NULL)
|
||||
{
|
||||
p[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Frees all the libraries in the prefab library list.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefabLibrary::FreeAllLibraries(void)
|
||||
{
|
||||
POSITION pos = PrefabLibraryList.GetHeadPosition();
|
||||
while (pos != NULL)
|
||||
{
|
||||
CPrefabLibrary *pPrefabLibrary = PrefabLibraryList.GetNext(pos);
|
||||
if (pPrefabLibrary != NULL)
|
||||
{
|
||||
delete pPrefabLibrary;
|
||||
}
|
||||
}
|
||||
|
||||
PrefabLibraryList.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Load all libraries in the prefabs directory.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefabLibrary::LoadAllLibraries()
|
||||
{
|
||||
char szDir[MAX_PATH];
|
||||
char szFile[MAX_PATH];
|
||||
((CHammer *)AfxGetApp())->GetDirectory(DIR_PREFABS, szDir);
|
||||
|
||||
//
|
||||
// Add one prefab library for the root prefabs folder in case they put something there.
|
||||
//
|
||||
CPrefabLibrary *pLibrary = FindOpenLibrary(szDir);
|
||||
if (pLibrary == NULL)
|
||||
{
|
||||
pLibrary = CreatePrefabLibrary(szDir);
|
||||
if (pLibrary != NULL)
|
||||
{
|
||||
PrefabLibraryList.AddTail(pLibrary);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pLibrary->Load(szDir);
|
||||
}
|
||||
|
||||
strcat(szDir, "\\*.*");
|
||||
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hnd = FindFirstFile(szDir, &fd);
|
||||
strrchr(szDir, '\\')[0] = 0; // truncate that
|
||||
|
||||
if (hnd == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return; // no libraries
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (fd.cFileName[0] != '.'))
|
||||
{
|
||||
sprintf(szFile, "%s\\%s", szDir, fd.cFileName);
|
||||
|
||||
pLibrary = FindOpenLibrary(szFile);
|
||||
if (pLibrary == NULL)
|
||||
{
|
||||
pLibrary = CreatePrefabLibrary(szFile);
|
||||
if (pLibrary != NULL)
|
||||
{
|
||||
PrefabLibraryList.AddTail(pLibrary);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pLibrary->Load(szDir);
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hnd, &fd));
|
||||
|
||||
FindClose(hnd);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pPrefab -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefabLibrary::Add(CPrefab *pPrefab)
|
||||
{
|
||||
if(!Prefabs.Find(pPrefab))
|
||||
Prefabs.AddTail(pPrefab);
|
||||
pPrefab->dwLibID = dwID;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : *pPrefab -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPrefabLibrary::Remove(CPrefab *pPrefab)
|
||||
{
|
||||
POSITION p = Prefabs.Find(pPrefab);
|
||||
if(p)
|
||||
Prefabs.RemoveAt(p);
|
||||
if(pPrefab->dwLibID == dwID) // make sure it doesn't reference this
|
||||
pPrefab->dwLibID = 0xffff;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : &p -
|
||||
// Output : CPrefab *
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefab * CPrefabLibrary::EnumPrefabs(POSITION &p)
|
||||
{
|
||||
if(p == ENUM_START)
|
||||
p = Prefabs.GetHeadPosition();
|
||||
if(!p)
|
||||
return NULL;
|
||||
return Prefabs.GetNext(p);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : dwID -
|
||||
// Output : CPrefabLibrary *
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibrary * CPrefabLibrary::FindID(DWORD dwID)
|
||||
{
|
||||
POSITION p = PrefabLibraryList.GetHeadPosition();
|
||||
while(p)
|
||||
{
|
||||
CPrefabLibrary *pPrefabLibrary = PrefabLibraryList.GetNext(p);
|
||||
if(pPrefabLibrary->dwID == dwID)
|
||||
return pPrefabLibrary;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszFilename -
|
||||
// Output :
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibrary *CPrefabLibrary::FindOpenLibrary(LPCTSTR pszFilename)
|
||||
{
|
||||
// checks to see if a library is open under that filename
|
||||
POSITION p = ENUM_START;
|
||||
CPrefabLibrary *pLibrary = EnumLibraries(p);
|
||||
while (pLibrary != NULL)
|
||||
{
|
||||
if (pLibrary->IsFile(pszFilename))
|
||||
{
|
||||
return(pLibrary);
|
||||
}
|
||||
pLibrary = EnumLibraries(p);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Enumerates the prefab libraries of a given type.
|
||||
// Input : p - Iterator.
|
||||
// eType - Type of library to return, LibType_None returns all
|
||||
// library types.
|
||||
// Output : Returns the next library of the given type.
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibrary *CPrefabLibrary::EnumLibraries(POSITION &p, LibraryType_t eType)
|
||||
{
|
||||
if (p == ENUM_START)
|
||||
{
|
||||
p = PrefabLibraryList.GetHeadPosition();
|
||||
}
|
||||
|
||||
while (p != NULL)
|
||||
{
|
||||
CPrefabLibrary *pLibrary = PrefabLibraryList.GetNext(p);
|
||||
if ((eType == LibType_None) || pLibrary->IsType(eType))
|
||||
{
|
||||
return(pLibrary);
|
||||
}
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibraryRMF::CPrefabLibraryRMF()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibraryRMF::~CPrefabLibraryRMF()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if this prefab represents the given filename, false if not.
|
||||
// Input : szFilename - Path of a prefab library or folder.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPrefabLibraryRMF::IsFile(const char *szFilename)
|
||||
{
|
||||
return(strcmpi(m_strOpenFileName, szFilename) == 0);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszFilename -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPrefabLibraryRMF::Load(LPCTSTR pszFilename)
|
||||
{
|
||||
FreePrefabs();
|
||||
|
||||
m_eType = LibType_HalfLife;
|
||||
|
||||
// open file
|
||||
m_file.open(pszFilename, std::ios::in | std::ios::binary);
|
||||
m_strOpenFileName = pszFilename;
|
||||
|
||||
if(!m_file.is_open())
|
||||
return -1;
|
||||
|
||||
char szBuf[128];
|
||||
|
||||
// read string header
|
||||
m_file.read(szBuf, strlen(pLibHeader));
|
||||
if(strncmp(szBuf, pLibHeader, strlen(pLibHeader)))
|
||||
{
|
||||
// return
|
||||
return -1;
|
||||
}
|
||||
|
||||
// read binary header
|
||||
PrefabLibraryHeader plh;
|
||||
m_file.read((char*)&plh, sizeof(plh));
|
||||
strcpy(szNotes, plh.szNotes);
|
||||
|
||||
// set name from filename
|
||||
SetNameFromFilename(pszFilename);
|
||||
|
||||
// read directory
|
||||
PrefabHeader *ph = new PrefabHeader[plh.dwNumEntries];
|
||||
m_dwDirOffset = plh.dwDirOffset;
|
||||
m_file.seekg(plh.dwDirOffset);
|
||||
m_file.read((char*)ph, plh.dwNumEntries * sizeof(PrefabHeader));
|
||||
|
||||
//
|
||||
// Read each prefab.
|
||||
//
|
||||
for(DWORD i = 0; i < plh.dwNumEntries; i++)
|
||||
{
|
||||
Assert(ph[i].iType == pt3D);
|
||||
CPrefabRMF *pPrefab = new CPrefabRMF;
|
||||
|
||||
// seek to prefab
|
||||
m_file.seekg(ph[i].dwOffset);
|
||||
pPrefab->Init(m_file);
|
||||
|
||||
// set its other info frm the dir entry
|
||||
pPrefab->SetName(ph[i].szName);
|
||||
pPrefab->SetNotes(ph[i].szNotes);
|
||||
pPrefab->dwFileSize = ph[i].dwSize;
|
||||
pPrefab->dwFileOffset = ph[i].dwOffset;
|
||||
|
||||
Add(pPrefab);
|
||||
}
|
||||
|
||||
// delete directory
|
||||
delete[] ph;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Removes this prefab library from disk.
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPrefabLibraryRMF::DeleteFile(void)
|
||||
{
|
||||
return(remove(m_strOpenFileName) == 0);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszFilename -
|
||||
// bIndexOnly -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPrefabLibraryRMF::Save(LPCTSTR pszFilename, BOOL bIndexOnly)
|
||||
{
|
||||
// temp storage
|
||||
static char szFile[MAX_PATH];
|
||||
|
||||
// if only saving index, special code -
|
||||
if(bIndexOnly && m_file.is_open())
|
||||
{
|
||||
// close file, reopen in binary write
|
||||
m_file.close();
|
||||
if(Prefabs.GetCount())
|
||||
{
|
||||
// change size of file first
|
||||
int iHandle = _open(m_strOpenFileName, _O_BINARY | _O_WRONLY);
|
||||
_chsize(iHandle, m_dwDirOffset);
|
||||
_close(iHandle);
|
||||
}
|
||||
|
||||
std::fstream file(m_strOpenFileName, std::ios::binary | std::ios::out);
|
||||
|
||||
// write string header
|
||||
file << pLibHeader;
|
||||
// write binary header (in case notes have changed)
|
||||
PrefabLibraryHeader plh;
|
||||
plh.dwNumEntries = Prefabs.GetCount();
|
||||
plh.fVersion = fLibVersion;
|
||||
plh.dwDirOffset = m_dwDirOffset;
|
||||
strcpy(plh.szNotes, szNotes);
|
||||
file.write((char*)&plh, sizeof plh);
|
||||
|
||||
// recreate a directory and write it
|
||||
PrefabHeader *ph = new PrefabHeader[Prefabs.GetCount()];
|
||||
int iCur = 0;
|
||||
|
||||
POSITION p = Prefabs.GetHeadPosition();
|
||||
while(p)
|
||||
{
|
||||
CPrefab *pPrefab = Prefabs.GetNext(p);
|
||||
|
||||
// setup this dir entry
|
||||
ph[iCur].dwOffset = pPrefab->dwFileOffset;
|
||||
ph[iCur].dwSize = pPrefab->dwFileSize;
|
||||
V_strcpy_safe(ph[iCur].szName, pPrefab->GetName());
|
||||
V_strcpy_safe(ph[iCur].szNotes, pPrefab->GetNotes());
|
||||
ph[iCur].iType = pPrefab->GetType();
|
||||
|
||||
++iCur; // increase current directory entry
|
||||
}
|
||||
|
||||
// write directory
|
||||
file.seekp(m_dwDirOffset);
|
||||
file.write((char*)ph, sizeof(*ph) * Prefabs.GetCount());
|
||||
file.close();
|
||||
|
||||
// re-open
|
||||
m_file.open(m_strOpenFileName, std::ios::in | std::ios::binary);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(pszFilename == NULL)
|
||||
{
|
||||
pszFilename = szFile;
|
||||
|
||||
if(m_strOpenFileName.IsEmpty())
|
||||
{
|
||||
char szNewFilename[MAX_PATH];
|
||||
CHammer *pApp = (CHammer*) AfxGetApp();
|
||||
pApp->GetDirectory(DIR_PREFABS, szNewFilename);
|
||||
|
||||
sprintf(szNewFilename + strlen(szNewFilename), "\\%s.ol", m_szName);
|
||||
|
||||
// make a name
|
||||
m_strOpenFileName = szNewFilename;
|
||||
}
|
||||
|
||||
strcpy(szFile, m_strOpenFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(szFile, pszFilename);
|
||||
SetNameFromFilename(pszFilename);
|
||||
}
|
||||
|
||||
// open temp file to save to.. then delete & rename old one.
|
||||
CString strTempFileName = "Temporary Prefab Library.$$$";
|
||||
std::fstream file;
|
||||
file.open(strTempFileName, std::ios::binary | std::ios::out);
|
||||
|
||||
// write string header
|
||||
file << pLibHeader;
|
||||
|
||||
// write binary header
|
||||
// save current position so we can seek back and rewrite it
|
||||
DWORD dwBinaryHeaderOffset = file.tellp();
|
||||
PrefabLibraryHeader plh;
|
||||
plh.dwNumEntries = Prefabs.GetCount();
|
||||
plh.fVersion = fLibVersion;
|
||||
strcpy(plh.szNotes, szNotes);
|
||||
file.write((char*)&plh, sizeof plh);
|
||||
|
||||
// allocate memory for directory
|
||||
PrefabHeader *ph = new PrefabHeader[plh.dwNumEntries];
|
||||
int iCur = 0;
|
||||
|
||||
char *pCopyBuf = new char[64000];
|
||||
|
||||
// write each prefab
|
||||
POSITION p = Prefabs.GetHeadPosition();
|
||||
while (p)
|
||||
{
|
||||
CPrefabRMF *pPrefab = (CPrefabRMF *)Prefabs.GetNext(p);
|
||||
|
||||
// setup this dir entry
|
||||
ph[iCur].dwOffset = file.tellp();
|
||||
V_strcpy_safe( ph[iCur].szName, pPrefab->GetName() );
|
||||
V_strcpy_safe( ph[iCur].szNotes, pPrefab->GetNotes() );
|
||||
ph[iCur].iType = pPrefab->GetType();
|
||||
|
||||
if(pPrefab->IsLoaded())
|
||||
{
|
||||
// it's loaded - save in native method
|
||||
pPrefab->Save(file, CPrefab::lsUpdateFilePos);
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's not loaded - save with quick method by copying
|
||||
// bytes directly from the existing file
|
||||
Assert(m_file.is_open());
|
||||
m_file.seekg(pPrefab->dwFileOffset);
|
||||
DWORD dwToRead = 64000, dwCopied = 0;
|
||||
while(dwToRead == 64000)
|
||||
{
|
||||
if(dwCopied + dwToRead > pPrefab->dwFileSize)
|
||||
dwToRead = pPrefab->dwFileSize - dwCopied;
|
||||
m_file.read(pCopyBuf, dwToRead);
|
||||
file.write(pCopyBuf, dwToRead);
|
||||
dwCopied += dwToRead;
|
||||
}
|
||||
}
|
||||
|
||||
// set offset info HERE because we might use it above
|
||||
pPrefab->dwFileOffset = ph[iCur].dwOffset;
|
||||
|
||||
// set size info
|
||||
ph[iCur].dwSize = pPrefab->dwFileSize =
|
||||
file.tellp() - (std::streamoff)ph[iCur].dwOffset;
|
||||
|
||||
++iCur; // increase current directory entry
|
||||
}
|
||||
|
||||
// delete copy buf
|
||||
delete[] pCopyBuf;
|
||||
|
||||
// rewrite binary header
|
||||
plh.dwDirOffset = m_dwDirOffset = file.tellp();
|
||||
file.seekp(dwBinaryHeaderOffset);
|
||||
file.write((char*)&plh, sizeof(plh));
|
||||
file.seekp(0, std::ios::end);
|
||||
|
||||
// write directory
|
||||
file.write((char*)ph, sizeof(*ph) * plh.dwNumEntries);
|
||||
file.close(); // close temp file
|
||||
|
||||
// delete original and rename
|
||||
m_file.close(); // might already be open.. might not.
|
||||
remove(m_strOpenFileName);
|
||||
|
||||
m_strOpenFileName = szFile;
|
||||
rename(strTempFileName, m_strOpenFileName);
|
||||
|
||||
// reopen original
|
||||
m_file.open(m_strOpenFileName, std::ios::in | std::ios::binary);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: A library's name is based on its filename. We set the name here
|
||||
// and rename the file if it exists, then re-open it.
|
||||
// Input : pszName -
|
||||
// Output : Returns zero on error, nonzero on success.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPrefabLibraryRMF::SetName(LPCTSTR pszName)
|
||||
{
|
||||
// set szName
|
||||
strcpy(m_szName, pszName);
|
||||
|
||||
char szNewFilename[MAX_PATH];
|
||||
CHammer *pApp = (CHammer*) AfxGetApp();
|
||||
pApp->GetDirectory(DIR_PREFABS, szNewFilename);
|
||||
|
||||
sprintf(szNewFilename + strlen(szNewFilename), "\\%s.ol", pszName);
|
||||
|
||||
if(m_file.is_open())
|
||||
{
|
||||
// close it -
|
||||
m_file.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ensure destination name doesn't exist already -
|
||||
if(GetFileAttributes(szNewFilename) != 0xFFFFFFFF)
|
||||
return 0; // exists.
|
||||
}
|
||||
|
||||
// rename and reopen
|
||||
rename(m_strOpenFileName, szNewFilename);
|
||||
m_strOpenFileName = szNewFilename;
|
||||
m_file.open(m_strOpenFileName, std::ios::in | std::ios::binary);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibraryVMF::CPrefabLibraryVMF()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CPrefabLibraryVMF::~CPrefabLibraryVMF()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns true if this prefab represents the given filename, false if not.
|
||||
// Input : szFilename - Path of a prefab library or folder.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPrefabLibraryVMF::IsFile(const char *szFilename)
|
||||
{
|
||||
return(strcmpi(m_szFolderName, szFilename) == 0);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszFilename -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPrefabLibraryVMF::Load(LPCTSTR pszFilename)
|
||||
{
|
||||
FreePrefabs();
|
||||
|
||||
SetNameFromFilename(pszFilename);
|
||||
strcpy(m_szFolderName, pszFilename);
|
||||
|
||||
m_eType = LibType_HalfLife2;
|
||||
|
||||
// dvs: new prefab libs have no notes! who cares?
|
||||
|
||||
//
|
||||
// Read the prefabs - they are stored as individual VMF files.
|
||||
//
|
||||
char szDir[MAX_PATH];
|
||||
strcpy(szDir, pszFilename);
|
||||
strcat(szDir, "\\*.vmf");
|
||||
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hnd = FindFirstFile(szDir, &fd);
|
||||
if (hnd == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// No prefabs in this folder.
|
||||
return(1);
|
||||
}
|
||||
|
||||
*strrchr(szDir, '*') = '\0';
|
||||
|
||||
do
|
||||
{
|
||||
if (fd.cFileName[0] != '.')
|
||||
{
|
||||
//
|
||||
// Build the full path to the prefab file.
|
||||
//
|
||||
char szFile[MAX_PATH];
|
||||
strcpy(szFile, szDir);
|
||||
strcat(szFile, fd.cFileName);
|
||||
|
||||
CPrefabVMF *pPrefab = new CPrefabVMF;
|
||||
pPrefab->SetFilename(szFile);
|
||||
|
||||
Add(pPrefab);
|
||||
}
|
||||
} while (FindNextFile(hnd, &fd));
|
||||
|
||||
FindClose(hnd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Removes this prefab library from disk.
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CPrefabLibraryVMF::DeleteFile(void)
|
||||
{
|
||||
// dvs: can't remove the prefab folder yet
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : pszFilename -
|
||||
// bIndexOnly -
|
||||
// Output : int
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPrefabLibraryVMF::Save(LPCTSTR pszFilename, BOOL bIndexOnly)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Set's the library's name by renaming the folder.
|
||||
// Input : pszName -
|
||||
// Output : Returns zero on error, nonzero on success.
|
||||
//-----------------------------------------------------------------------------
|
||||
int CPrefabLibraryVMF::SetName(LPCTSTR pszName)
|
||||
{
|
||||
// dvs: rename the folder - or maybe don't implement for VMF prefabs
|
||||
strcpy(m_szName, pszName);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user