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.
991 lines
24 KiB
991 lines
24 KiB
//========= 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; |
|
} |
|
|
|
|
|
|