Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements a system for managing prefabs. There are two types
  4. // of prefabs implemented here: Half-Life style prefabs, and Half-Life 2
  5. // style prefabs.
  6. //
  7. // For Half-Life, prefab libraries are stored as binary .OL files, each of
  8. // which contains multiple .RMF files that are the prefabs.
  9. //
  10. // For Half-Life 2, prefabs are stored in a tree of folders, each folder
  11. // representing a library, and the each .VMF file in the folder containing
  12. // a single prefab.
  13. //
  14. //=============================================================================//
  15. #include "stdafx.h"
  16. #include "Prefabs.h"
  17. #include "Prefab3D.h"
  18. #include "hammer.h"
  19. #include <io.h>
  20. #include <fcntl.h>
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include <tier0/memdbgon.h>
  23. BOOL CPrefab::bCacheEnabled = TRUE;
  24. CPrefabList CPrefab::PrefabList;
  25. CPrefabList CPrefab::MRU;
  26. CPrefabLibraryList CPrefabLibrary::PrefabLibraryList;
  27. static char *pLibHeader = "Worldcraft Prefab Library\r\n\x1a";
  28. static float fLibVersion = 0.1f;
  29. typedef struct
  30. {
  31. DWORD dwOffset;
  32. DWORD dwSize;
  33. char szName[31];
  34. char szNotes[MAX_NOTES];
  35. int iType;
  36. } PrefabHeader;
  37. typedef struct
  38. {
  39. float fVersion;
  40. DWORD dwDirOffset;
  41. DWORD dwNumEntries;
  42. char szNotes[MAX_NOTES];
  43. } PrefabLibraryHeader;
  44. //-----------------------------------------------------------------------------
  45. // Purpose: Creates a prefab library from a given path.
  46. // Input : szFile -
  47. // Output :
  48. //-----------------------------------------------------------------------------
  49. CPrefabLibrary *CreatePrefabLibrary(const char *szFile)
  50. {
  51. CPrefabLibrary *pLibrary;
  52. if (stricmp(&szFile[strlen(szFile) - 2], ".ol") != 0)
  53. {
  54. pLibrary = new CPrefabLibraryVMF;
  55. }
  56. else
  57. {
  58. pLibrary = new CPrefabLibraryRMF;
  59. }
  60. if (pLibrary->Load(szFile) == -1)
  61. {
  62. delete pLibrary;
  63. return(NULL);
  64. }
  65. return(pLibrary);
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose:
  69. //-----------------------------------------------------------------------------
  70. CPrefab::CPrefab()
  71. {
  72. static DWORD dwRunningID = 1;
  73. // assign running ID
  74. dwID = dwRunningID++;
  75. PrefabList.AddTail(this);
  76. // assign blank name/notes
  77. szName[0] = szNotes[0] = 0;
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Purpose:
  81. //-----------------------------------------------------------------------------
  82. CPrefab::~CPrefab()
  83. {
  84. POSITION p = PrefabList.Find(this);
  85. if(p)
  86. PrefabList.RemoveAt(p);
  87. p = MRU.Find(this);
  88. if(p)
  89. MRU.RemoveAt(p);
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose:
  93. // Input : dwID -
  94. // Output : CPrefab *
  95. //-----------------------------------------------------------------------------
  96. CPrefab * CPrefab::FindID(DWORD dwID)
  97. {
  98. POSITION p = PrefabList.GetHeadPosition();
  99. while(p)
  100. {
  101. CPrefab *pPrefab = PrefabList.GetNext(p);
  102. if(pPrefab->dwID == dwID)
  103. return pPrefab;
  104. }
  105. return NULL;
  106. }
  107. //-----------------------------------------------------------------------------
  108. // Purpose:
  109. // Input : b -
  110. //-----------------------------------------------------------------------------
  111. void CPrefab::EnableCaching(BOOL b)
  112. {
  113. bCacheEnabled = b;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose:
  117. // Input : *pPrefab -
  118. //-----------------------------------------------------------------------------
  119. void CPrefab::AddMRU(CPrefab *pPrefab)
  120. {
  121. if(!bCacheEnabled)
  122. return;
  123. POSITION p = MRU.Find(pPrefab);
  124. if(p)
  125. {
  126. // remove there and add to head
  127. MRU.RemoveAt(p);
  128. }
  129. else if(MRU.GetCount() == 5)
  130. {
  131. // uncache tail object
  132. p = MRU.GetTailPosition();
  133. if(p) // might not be any yet
  134. {
  135. CPrefab *pUncache = MRU.GetAt(p);
  136. pUncache->FreeData();
  137. MRU.RemoveAt(p);
  138. }
  139. }
  140. // add to head
  141. MRU.AddHead(pPrefab);
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose:
  145. //-----------------------------------------------------------------------------
  146. void CPrefab::FreeAllData()
  147. {
  148. // free all prefab data memory
  149. POSITION p = PrefabList.GetHeadPosition();
  150. while(p)
  151. {
  152. CPrefab *pPrefab = PrefabList.GetNext(p);
  153. pPrefab->FreeData();
  154. }
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Purpose:
  158. // Input : pszFilename -
  159. // Output : CPrefab::pfiletype_t
  160. //-----------------------------------------------------------------------------
  161. CPrefab::pfiletype_t CPrefab::CheckFileType(LPCTSTR pszFilename)
  162. {
  163. // first check extensions
  164. const char *p = strrchr(pszFilename, '.');
  165. if(p)
  166. {
  167. if(!strcmpi(p, ".rmf"))
  168. return pftRMF;
  169. else if(!strcmpi(p, ".map"))
  170. return pftMAP;
  171. else if(!strcmpi(p, ".os"))
  172. return pftScript;
  173. }
  174. std::fstream file(pszFilename, std::ios::in | std::ios::binary);
  175. // read first 16 bytes of file
  176. char szBuf[255];
  177. file.read(szBuf, 16);
  178. // check 1: RMF
  179. float f = ((float*) szBuf)[0];
  180. // 0.8 was version at which RMF tag was started
  181. if(f <= 0.7f || !strncmp(szBuf+sizeof(float), "RMF", 3))
  182. {
  183. return pftRMF;
  184. }
  185. // check 2: script
  186. if(!strnicmp(szBuf, "[Script", 7))
  187. {
  188. return pftScript;
  189. }
  190. // check 3: MAP
  191. int i = 500;
  192. while(i--)
  193. {
  194. file >> std::ws;
  195. file.getline(szBuf, 255);
  196. if(szBuf[0] == '{')
  197. return pftMAP;
  198. if(file.eof())
  199. break;
  200. }
  201. return pftUnknown;
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Purpose:
  205. //-----------------------------------------------------------------------------
  206. CPrefabLibrary::CPrefabLibrary()
  207. {
  208. static DWORD dwRunningID = 1;
  209. // assign running ID
  210. dwID = dwRunningID++;
  211. m_szName[0] = '\0';
  212. szNotes[0] = '\0';
  213. }
  214. //-----------------------------------------------------------------------------
  215. // Purpose:
  216. //-----------------------------------------------------------------------------
  217. CPrefabLibrary::~CPrefabLibrary()
  218. {
  219. FreePrefabs();
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Purpose:
  223. //-----------------------------------------------------------------------------
  224. void CPrefabLibrary::FreePrefabs()
  225. {
  226. // nuke prefabs
  227. POSITION p = Prefabs.GetHeadPosition();
  228. while (p != NULL)
  229. {
  230. CPrefab *pPrefab = Prefabs.GetNext(p);
  231. delete pPrefab;
  232. }
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Purpose:
  236. // Input : *a -
  237. // *b -
  238. // Output : static int
  239. //-----------------------------------------------------------------------------
  240. static int __cdecl SortPrefabs(CPrefab *a, CPrefab *b)
  241. {
  242. return(strcmpi(a->GetName(), b->GetName()));
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Purpose:
  246. //-----------------------------------------------------------------------------
  247. void CPrefabLibrary::Sort(void)
  248. {
  249. int nPrefabs = Prefabs.GetCount();
  250. if (nPrefabs < 2)
  251. {
  252. return;
  253. }
  254. CPrefab **TmpPrefabArray = new CPrefab *[nPrefabs];
  255. //
  256. // Make an array we can pass to qsort.
  257. //
  258. POSITION p = ENUM_START;
  259. CPrefab *pPrefab = EnumPrefabs(p);
  260. int iPrefab = 0;
  261. while (pPrefab != NULL)
  262. {
  263. TmpPrefabArray[iPrefab++] = pPrefab;
  264. pPrefab = EnumPrefabs(p);
  265. }
  266. //
  267. // Sort the prefabs array by name.
  268. //
  269. qsort(TmpPrefabArray, nPrefabs, sizeof(CPrefab *), (int (__cdecl *)(const void *, const void *))SortPrefabs);
  270. //
  271. // Store back in list in sorted order.
  272. //
  273. Prefabs.RemoveAll();
  274. for (int i = 0; i < nPrefabs; i++)
  275. {
  276. Prefabs.AddTail(TmpPrefabArray[i]);
  277. }
  278. delete[] TmpPrefabArray;
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Purpose:
  282. // Input : pszFilename -
  283. //-----------------------------------------------------------------------------
  284. void CPrefabLibrary::SetNameFromFilename(LPCTSTR pszFilename)
  285. {
  286. const char *cp = strrchr(pszFilename, '\\');
  287. strcpy(m_szName, cp ? (cp + 1) : pszFilename);
  288. char *p = strchr(m_szName, '.');
  289. if (p != NULL)
  290. {
  291. p[0] = '\0';
  292. }
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose: Frees all the libraries in the prefab library list.
  296. //-----------------------------------------------------------------------------
  297. void CPrefabLibrary::FreeAllLibraries(void)
  298. {
  299. POSITION pos = PrefabLibraryList.GetHeadPosition();
  300. while (pos != NULL)
  301. {
  302. CPrefabLibrary *pPrefabLibrary = PrefabLibraryList.GetNext(pos);
  303. if (pPrefabLibrary != NULL)
  304. {
  305. delete pPrefabLibrary;
  306. }
  307. }
  308. PrefabLibraryList.RemoveAll();
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose: Load all libraries in the prefabs directory.
  312. //-----------------------------------------------------------------------------
  313. void CPrefabLibrary::LoadAllLibraries()
  314. {
  315. char szDir[MAX_PATH];
  316. char szFile[MAX_PATH];
  317. ((CHammer *)AfxGetApp())->GetDirectory(DIR_PREFABS, szDir);
  318. //
  319. // Add one prefab library for the root prefabs folder in case they put something there.
  320. //
  321. CPrefabLibrary *pLibrary = FindOpenLibrary(szDir);
  322. if (pLibrary == NULL)
  323. {
  324. pLibrary = CreatePrefabLibrary(szDir);
  325. if (pLibrary != NULL)
  326. {
  327. PrefabLibraryList.AddTail(pLibrary);
  328. }
  329. }
  330. else
  331. {
  332. pLibrary->Load(szDir);
  333. }
  334. strcat(szDir, "\\*.*");
  335. WIN32_FIND_DATA fd;
  336. HANDLE hnd = FindFirstFile(szDir, &fd);
  337. strrchr(szDir, '\\')[0] = 0; // truncate that
  338. if (hnd == INVALID_HANDLE_VALUE)
  339. {
  340. return; // no libraries
  341. }
  342. do
  343. {
  344. if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (fd.cFileName[0] != '.'))
  345. {
  346. sprintf(szFile, "%s\\%s", szDir, fd.cFileName);
  347. pLibrary = FindOpenLibrary(szFile);
  348. if (pLibrary == NULL)
  349. {
  350. pLibrary = CreatePrefabLibrary(szFile);
  351. if (pLibrary != NULL)
  352. {
  353. PrefabLibraryList.AddTail(pLibrary);
  354. }
  355. }
  356. else
  357. {
  358. pLibrary->Load(szDir);
  359. }
  360. }
  361. } while (FindNextFile(hnd, &fd));
  362. FindClose(hnd);
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Purpose:
  366. // Input : *pPrefab -
  367. //-----------------------------------------------------------------------------
  368. void CPrefabLibrary::Add(CPrefab *pPrefab)
  369. {
  370. if(!Prefabs.Find(pPrefab))
  371. Prefabs.AddTail(pPrefab);
  372. pPrefab->dwLibID = dwID;
  373. }
  374. //-----------------------------------------------------------------------------
  375. // Purpose:
  376. // Input : *pPrefab -
  377. //-----------------------------------------------------------------------------
  378. void CPrefabLibrary::Remove(CPrefab *pPrefab)
  379. {
  380. POSITION p = Prefabs.Find(pPrefab);
  381. if(p)
  382. Prefabs.RemoveAt(p);
  383. if(pPrefab->dwLibID == dwID) // make sure it doesn't reference this
  384. pPrefab->dwLibID = 0xffff;
  385. }
  386. //-----------------------------------------------------------------------------
  387. // Purpose:
  388. // Input : &p -
  389. // Output : CPrefab *
  390. //-----------------------------------------------------------------------------
  391. CPrefab * CPrefabLibrary::EnumPrefabs(POSITION &p)
  392. {
  393. if(p == ENUM_START)
  394. p = Prefabs.GetHeadPosition();
  395. if(!p)
  396. return NULL;
  397. return Prefabs.GetNext(p);
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Purpose:
  401. // Input : dwID -
  402. // Output : CPrefabLibrary *
  403. //-----------------------------------------------------------------------------
  404. CPrefabLibrary * CPrefabLibrary::FindID(DWORD dwID)
  405. {
  406. POSITION p = PrefabLibraryList.GetHeadPosition();
  407. while(p)
  408. {
  409. CPrefabLibrary *pPrefabLibrary = PrefabLibraryList.GetNext(p);
  410. if(pPrefabLibrary->dwID == dwID)
  411. return pPrefabLibrary;
  412. }
  413. return NULL;
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose:
  417. // Input : pszFilename -
  418. // Output :
  419. //-----------------------------------------------------------------------------
  420. CPrefabLibrary *CPrefabLibrary::FindOpenLibrary(LPCTSTR pszFilename)
  421. {
  422. // checks to see if a library is open under that filename
  423. POSITION p = ENUM_START;
  424. CPrefabLibrary *pLibrary = EnumLibraries(p);
  425. while (pLibrary != NULL)
  426. {
  427. if (pLibrary->IsFile(pszFilename))
  428. {
  429. return(pLibrary);
  430. }
  431. pLibrary = EnumLibraries(p);
  432. }
  433. return(NULL);
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose: Enumerates the prefab libraries of a given type.
  437. // Input : p - Iterator.
  438. // eType - Type of library to return, LibType_None returns all
  439. // library types.
  440. // Output : Returns the next library of the given type.
  441. //-----------------------------------------------------------------------------
  442. CPrefabLibrary *CPrefabLibrary::EnumLibraries(POSITION &p, LibraryType_t eType)
  443. {
  444. if (p == ENUM_START)
  445. {
  446. p = PrefabLibraryList.GetHeadPosition();
  447. }
  448. while (p != NULL)
  449. {
  450. CPrefabLibrary *pLibrary = PrefabLibraryList.GetNext(p);
  451. if ((eType == LibType_None) || pLibrary->IsType(eType))
  452. {
  453. return(pLibrary);
  454. }
  455. }
  456. return(NULL);
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Purpose:
  460. //-----------------------------------------------------------------------------
  461. CPrefabLibraryRMF::CPrefabLibraryRMF()
  462. {
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Purpose:
  466. //-----------------------------------------------------------------------------
  467. CPrefabLibraryRMF::~CPrefabLibraryRMF()
  468. {
  469. }
  470. //-----------------------------------------------------------------------------
  471. // Purpose: Returns true if this prefab represents the given filename, false if not.
  472. // Input : szFilename - Path of a prefab library or folder.
  473. //-----------------------------------------------------------------------------
  474. bool CPrefabLibraryRMF::IsFile(const char *szFilename)
  475. {
  476. return(strcmpi(m_strOpenFileName, szFilename) == 0);
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Purpose:
  480. // Input : pszFilename -
  481. // Output : int
  482. //-----------------------------------------------------------------------------
  483. int CPrefabLibraryRMF::Load(LPCTSTR pszFilename)
  484. {
  485. FreePrefabs();
  486. m_eType = LibType_HalfLife;
  487. // open file
  488. m_file.open(pszFilename, std::ios::in | std::ios::binary);
  489. m_strOpenFileName = pszFilename;
  490. if(!m_file.is_open())
  491. return -1;
  492. char szBuf[128];
  493. // read string header
  494. m_file.read(szBuf, strlen(pLibHeader));
  495. if(strncmp(szBuf, pLibHeader, strlen(pLibHeader)))
  496. {
  497. // return
  498. return -1;
  499. }
  500. // read binary header
  501. PrefabLibraryHeader plh;
  502. m_file.read((char*)&plh, sizeof(plh));
  503. strcpy(szNotes, plh.szNotes);
  504. // set name from filename
  505. SetNameFromFilename(pszFilename);
  506. // read directory
  507. PrefabHeader *ph = new PrefabHeader[plh.dwNumEntries];
  508. m_dwDirOffset = plh.dwDirOffset;
  509. m_file.seekg(plh.dwDirOffset);
  510. m_file.read((char*)ph, plh.dwNumEntries * sizeof(PrefabHeader));
  511. //
  512. // Read each prefab.
  513. //
  514. for(DWORD i = 0; i < plh.dwNumEntries; i++)
  515. {
  516. Assert(ph[i].iType == pt3D);
  517. CPrefabRMF *pPrefab = new CPrefabRMF;
  518. // seek to prefab
  519. m_file.seekg(ph[i].dwOffset);
  520. pPrefab->Init(m_file);
  521. // set its other info frm the dir entry
  522. pPrefab->SetName(ph[i].szName);
  523. pPrefab->SetNotes(ph[i].szNotes);
  524. pPrefab->dwFileSize = ph[i].dwSize;
  525. pPrefab->dwFileOffset = ph[i].dwOffset;
  526. Add(pPrefab);
  527. }
  528. // delete directory
  529. delete[] ph;
  530. return 1;
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Purpose: Removes this prefab library from disk.
  534. // Output : Returns true on success, false on failure.
  535. //-----------------------------------------------------------------------------
  536. bool CPrefabLibraryRMF::DeleteFile(void)
  537. {
  538. return(remove(m_strOpenFileName) == 0);
  539. }
  540. //-----------------------------------------------------------------------------
  541. // Purpose:
  542. // Input : pszFilename -
  543. // bIndexOnly -
  544. // Output : int
  545. //-----------------------------------------------------------------------------
  546. int CPrefabLibraryRMF::Save(LPCTSTR pszFilename, BOOL bIndexOnly)
  547. {
  548. // temp storage
  549. static char szFile[MAX_PATH];
  550. // if only saving index, special code -
  551. if(bIndexOnly && m_file.is_open())
  552. {
  553. // close file, reopen in binary write
  554. m_file.close();
  555. if(Prefabs.GetCount())
  556. {
  557. // change size of file first
  558. int iHandle = _open(m_strOpenFileName, _O_BINARY | _O_WRONLY);
  559. _chsize(iHandle, m_dwDirOffset);
  560. _close(iHandle);
  561. }
  562. std::fstream file(m_strOpenFileName, std::ios::binary | std::ios::out);
  563. // write string header
  564. file << pLibHeader;
  565. // write binary header (in case notes have changed)
  566. PrefabLibraryHeader plh;
  567. plh.dwNumEntries = Prefabs.GetCount();
  568. plh.fVersion = fLibVersion;
  569. plh.dwDirOffset = m_dwDirOffset;
  570. strcpy(plh.szNotes, szNotes);
  571. file.write((char*)&plh, sizeof plh);
  572. // recreate a directory and write it
  573. PrefabHeader *ph = new PrefabHeader[Prefabs.GetCount()];
  574. int iCur = 0;
  575. POSITION p = Prefabs.GetHeadPosition();
  576. while(p)
  577. {
  578. CPrefab *pPrefab = Prefabs.GetNext(p);
  579. // setup this dir entry
  580. ph[iCur].dwOffset = pPrefab->dwFileOffset;
  581. ph[iCur].dwSize = pPrefab->dwFileSize;
  582. V_strcpy_safe(ph[iCur].szName, pPrefab->GetName());
  583. V_strcpy_safe(ph[iCur].szNotes, pPrefab->GetNotes());
  584. ph[iCur].iType = pPrefab->GetType();
  585. ++iCur; // increase current directory entry
  586. }
  587. // write directory
  588. file.seekp(m_dwDirOffset);
  589. file.write((char*)ph, sizeof(*ph) * Prefabs.GetCount());
  590. file.close();
  591. // re-open
  592. m_file.open(m_strOpenFileName, std::ios::in | std::ios::binary);
  593. return 1;
  594. }
  595. if(pszFilename == NULL)
  596. {
  597. pszFilename = szFile;
  598. if(m_strOpenFileName.IsEmpty())
  599. {
  600. char szNewFilename[MAX_PATH];
  601. CHammer *pApp = (CHammer*) AfxGetApp();
  602. pApp->GetDirectory(DIR_PREFABS, szNewFilename);
  603. sprintf(szNewFilename + strlen(szNewFilename), "\\%s.ol", m_szName);
  604. // make a name
  605. m_strOpenFileName = szNewFilename;
  606. }
  607. strcpy(szFile, m_strOpenFileName);
  608. }
  609. else
  610. {
  611. strcpy(szFile, pszFilename);
  612. SetNameFromFilename(pszFilename);
  613. }
  614. // open temp file to save to.. then delete & rename old one.
  615. CString strTempFileName = "Temporary Prefab Library.$$$";
  616. std::fstream file;
  617. file.open(strTempFileName, std::ios::binary | std::ios::out);
  618. // write string header
  619. file << pLibHeader;
  620. // write binary header
  621. // save current position so we can seek back and rewrite it
  622. DWORD dwBinaryHeaderOffset = file.tellp();
  623. PrefabLibraryHeader plh;
  624. plh.dwNumEntries = Prefabs.GetCount();
  625. plh.fVersion = fLibVersion;
  626. strcpy(plh.szNotes, szNotes);
  627. file.write((char*)&plh, sizeof plh);
  628. // allocate memory for directory
  629. PrefabHeader *ph = new PrefabHeader[plh.dwNumEntries];
  630. int iCur = 0;
  631. char *pCopyBuf = new char[64000];
  632. // write each prefab
  633. POSITION p = Prefabs.GetHeadPosition();
  634. while (p)
  635. {
  636. CPrefabRMF *pPrefab = (CPrefabRMF *)Prefabs.GetNext(p);
  637. // setup this dir entry
  638. ph[iCur].dwOffset = file.tellp();
  639. V_strcpy_safe( ph[iCur].szName, pPrefab->GetName() );
  640. V_strcpy_safe( ph[iCur].szNotes, pPrefab->GetNotes() );
  641. ph[iCur].iType = pPrefab->GetType();
  642. if(pPrefab->IsLoaded())
  643. {
  644. // it's loaded - save in native method
  645. pPrefab->Save(file, CPrefab::lsUpdateFilePos);
  646. }
  647. else
  648. {
  649. // it's not loaded - save with quick method by copying
  650. // bytes directly from the existing file
  651. Assert(m_file.is_open());
  652. m_file.seekg(pPrefab->dwFileOffset);
  653. DWORD dwToRead = 64000, dwCopied = 0;
  654. while(dwToRead == 64000)
  655. {
  656. if(dwCopied + dwToRead > pPrefab->dwFileSize)
  657. dwToRead = pPrefab->dwFileSize - dwCopied;
  658. m_file.read(pCopyBuf, dwToRead);
  659. file.write(pCopyBuf, dwToRead);
  660. dwCopied += dwToRead;
  661. }
  662. }
  663. // set offset info HERE because we might use it above
  664. pPrefab->dwFileOffset = ph[iCur].dwOffset;
  665. // set size info
  666. ph[iCur].dwSize = pPrefab->dwFileSize =
  667. file.tellp() - (std::streamoff)ph[iCur].dwOffset;
  668. ++iCur; // increase current directory entry
  669. }
  670. // delete copy buf
  671. delete[] pCopyBuf;
  672. // rewrite binary header
  673. plh.dwDirOffset = m_dwDirOffset = file.tellp();
  674. file.seekp(dwBinaryHeaderOffset);
  675. file.write((char*)&plh, sizeof(plh));
  676. file.seekp(0, std::ios::end);
  677. // write directory
  678. file.write((char*)ph, sizeof(*ph) * plh.dwNumEntries);
  679. file.close(); // close temp file
  680. // delete original and rename
  681. m_file.close(); // might already be open.. might not.
  682. remove(m_strOpenFileName);
  683. m_strOpenFileName = szFile;
  684. rename(strTempFileName, m_strOpenFileName);
  685. // reopen original
  686. m_file.open(m_strOpenFileName, std::ios::in | std::ios::binary);
  687. return 1;
  688. }
  689. //-----------------------------------------------------------------------------
  690. // Purpose: A library's name is based on its filename. We set the name here
  691. // and rename the file if it exists, then re-open it.
  692. // Input : pszName -
  693. // Output : Returns zero on error, nonzero on success.
  694. //-----------------------------------------------------------------------------
  695. int CPrefabLibraryRMF::SetName(LPCTSTR pszName)
  696. {
  697. // set szName
  698. strcpy(m_szName, pszName);
  699. char szNewFilename[MAX_PATH];
  700. CHammer *pApp = (CHammer*) AfxGetApp();
  701. pApp->GetDirectory(DIR_PREFABS, szNewFilename);
  702. sprintf(szNewFilename + strlen(szNewFilename), "\\%s.ol", pszName);
  703. if(m_file.is_open())
  704. {
  705. // close it -
  706. m_file.close();
  707. }
  708. else
  709. {
  710. // ensure destination name doesn't exist already -
  711. if(GetFileAttributes(szNewFilename) != 0xFFFFFFFF)
  712. return 0; // exists.
  713. }
  714. // rename and reopen
  715. rename(m_strOpenFileName, szNewFilename);
  716. m_strOpenFileName = szNewFilename;
  717. m_file.open(m_strOpenFileName, std::ios::in | std::ios::binary);
  718. return 1;
  719. }
  720. //-----------------------------------------------------------------------------
  721. // Purpose:
  722. //-----------------------------------------------------------------------------
  723. CPrefabLibraryVMF::CPrefabLibraryVMF()
  724. {
  725. }
  726. //-----------------------------------------------------------------------------
  727. // Purpose:
  728. //-----------------------------------------------------------------------------
  729. CPrefabLibraryVMF::~CPrefabLibraryVMF()
  730. {
  731. }
  732. //-----------------------------------------------------------------------------
  733. // Purpose: Returns true if this prefab represents the given filename, false if not.
  734. // Input : szFilename - Path of a prefab library or folder.
  735. //-----------------------------------------------------------------------------
  736. bool CPrefabLibraryVMF::IsFile(const char *szFilename)
  737. {
  738. return(strcmpi(m_szFolderName, szFilename) == 0);
  739. }
  740. //-----------------------------------------------------------------------------
  741. // Purpose:
  742. // Input : pszFilename -
  743. // Output : int
  744. //-----------------------------------------------------------------------------
  745. int CPrefabLibraryVMF::Load(LPCTSTR pszFilename)
  746. {
  747. FreePrefabs();
  748. SetNameFromFilename(pszFilename);
  749. strcpy(m_szFolderName, pszFilename);
  750. m_eType = LibType_HalfLife2;
  751. // dvs: new prefab libs have no notes! who cares?
  752. //
  753. // Read the prefabs - they are stored as individual VMF files.
  754. //
  755. char szDir[MAX_PATH];
  756. strcpy(szDir, pszFilename);
  757. strcat(szDir, "\\*.vmf");
  758. WIN32_FIND_DATA fd;
  759. HANDLE hnd = FindFirstFile(szDir, &fd);
  760. if (hnd == INVALID_HANDLE_VALUE)
  761. {
  762. // No prefabs in this folder.
  763. return(1);
  764. }
  765. *strrchr(szDir, '*') = '\0';
  766. do
  767. {
  768. if (fd.cFileName[0] != '.')
  769. {
  770. //
  771. // Build the full path to the prefab file.
  772. //
  773. char szFile[MAX_PATH];
  774. strcpy(szFile, szDir);
  775. strcat(szFile, fd.cFileName);
  776. CPrefabVMF *pPrefab = new CPrefabVMF;
  777. pPrefab->SetFilename(szFile);
  778. Add(pPrefab);
  779. }
  780. } while (FindNextFile(hnd, &fd));
  781. FindClose(hnd);
  782. return 1;
  783. }
  784. //-----------------------------------------------------------------------------
  785. // Purpose: Removes this prefab library from disk.
  786. // Output : Returns true on success, false on failure.
  787. //-----------------------------------------------------------------------------
  788. bool CPrefabLibraryVMF::DeleteFile(void)
  789. {
  790. // dvs: can't remove the prefab folder yet
  791. return(false);
  792. }
  793. //-----------------------------------------------------------------------------
  794. // Purpose:
  795. // Input : pszFilename -
  796. // bIndexOnly -
  797. // Output : int
  798. //-----------------------------------------------------------------------------
  799. int CPrefabLibraryVMF::Save(LPCTSTR pszFilename, BOOL bIndexOnly)
  800. {
  801. return 1;
  802. }
  803. //-----------------------------------------------------------------------------
  804. // Purpose: Set's the library's name by renaming the folder.
  805. // Input : pszName -
  806. // Output : Returns zero on error, nonzero on success.
  807. //-----------------------------------------------------------------------------
  808. int CPrefabLibraryVMF::SetName(LPCTSTR pszName)
  809. {
  810. // dvs: rename the folder - or maybe don't implement for VMF prefabs
  811. strcpy(m_szName, pszName);
  812. return 1;
  813. }