EditorSaveLoad.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : LevelEdit *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/LevelEdit/EditorSaveLoad.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 3/05/02 3:30p $*
  29. * *
  30. * $Revision:: 37 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "stdafx.h"
  36. #include "leveleditdoc.h"
  37. #include "editorsaveload.h"
  38. #include "persist.h"
  39. #include "persistfactory.h"
  40. #include "preset.h"
  41. #include "utils.h"
  42. #include "definition.h"
  43. #include "editorchunkids.h"
  44. #include "physstaticsavesystem.h"
  45. #include "chunkio.h"
  46. #include "cameramgr.h"
  47. #include "filemgr.h"
  48. #include "matrix3d.h"
  49. #include "rawfile.h"
  50. #include "nodemgr.h"
  51. #include "sceneeditor.h"
  52. #include "node.h"
  53. #include "lightambientform.h"
  54. #include "soundscene.h"
  55. #include "backgroundmgr.h"
  56. #include "conversationmgr.h"
  57. #include "weathermgr.h"
  58. #include "combat.h"
  59. #include "mapmgr.h"
  60. #include "pathfind.h"
  61. #include "lightsolvesavesystem.h"
  62. #include "heightfieldmgr.h"
  63. ///////////////////////////////////////////////////////////////////////
  64. // Global singleton instance
  65. ///////////////////////////////////////////////////////////////////////
  66. EditorSaveLoadClass _TheEditorSaveLoadSubsystem;
  67. PathfindImportExportSaveLoadClass _ThePathfindImporterExporter;
  68. ///////////////////////////////////////////////////////////////////////
  69. // Static member initialization
  70. ///////////////////////////////////////////////////////////////////////
  71. bool EditorSaveLoadClass::m_LoadedValidVis = true;
  72. ///////////////////////////////////////////////////////////////////////
  73. // Constants
  74. ///////////////////////////////////////////////////////////////////////
  75. enum
  76. {
  77. CHUNKID_MICRO_CHUNKS = 0x10140738,
  78. CHUNKID_OBSOLETE,
  79. CHUNKID_PATHFIND_DATA
  80. };
  81. enum
  82. {
  83. VARID_INCLUDE_FILE = 0x01,
  84. VARID_CAMERA_TM,
  85. VARID_OBSOLETE_0,
  86. VARID_BACK_MUSIC,
  87. VARID_AMBIENT_LIGHT,
  88. VARID_OBSOLETE_1,
  89. VARID_OBSOLETE_2,
  90. VARID_FAR_CLIP_PLANE_DOUBLE,
  91. VARID_FOG_COLOR,
  92. VARID_FOG_PLANES,
  93. VARID_FOG_ENABLED,
  94. VARID_FAR_CLIP_PLANE,
  95. VARID_RESTART_SCRIPT_NAME,
  96. VARID_RESPAWN_SCRIPT_NAME,
  97. };
  98. enum
  99. {
  100. CHUNKID_LVL_DATA = 304021447,
  101. CHUNKID_LIGHT_SOLVE,
  102. };
  103. ///////////////////////////////////////////////////////////////////////
  104. //
  105. // Chunk_ID
  106. //
  107. ///////////////////////////////////////////////////////////////////////
  108. uint32
  109. EditorSaveLoadClass::Chunk_ID (void) const
  110. {
  111. return CHUNKID_EDITOR_SAVELOAD;
  112. }
  113. ///////////////////////////////////////////////////////////////////////
  114. //
  115. // Contains_Data
  116. //
  117. ///////////////////////////////////////////////////////////////////////
  118. bool
  119. EditorSaveLoadClass::Contains_Data (void) const
  120. {
  121. return true;
  122. }
  123. ///////////////////////////////////////////////////////////////////////
  124. //
  125. // Save
  126. //
  127. ///////////////////////////////////////////////////////////////////////
  128. bool
  129. EditorSaveLoadClass::Save (ChunkSaveClass &csave)
  130. {
  131. bool retval = true;
  132. int index;
  133. csave.Begin_Chunk (CHUNKID_MICRO_CHUNKS);
  134. //
  135. // Write the camera transform to the chunk
  136. //
  137. Matrix3D camera_tm = ::Get_Camera_Mgr ()->Get_Camera ()->Get_Transform ();
  138. WRITE_MICRO_CHUNK (csave, VARID_CAMERA_TM, camera_tm);
  139. //
  140. // Write the miscellaneous level settings to the chunk
  141. //
  142. Vector3 ambient_light = ::Get_Scene_Editor ()->Get_Ambient_Light ();
  143. WRITE_MICRO_CHUNK (csave, VARID_AMBIENT_LIGHT, ambient_light);
  144. //
  145. // Save the fog settings
  146. //
  147. bool fog_enabled = false;
  148. struct
  149. {
  150. float z_near;
  151. float z_far;
  152. } fog_planes = { 50.0F, 100.0F };
  153. Vector3 fog_color (0, 0, 0);
  154. ::Get_Scene_Editor ()->Get_Fog_Range (&fog_planes.z_near, &fog_planes.z_far);
  155. fog_color = ::Get_Scene_Editor ()->Get_Fog_Color ();
  156. fog_enabled = ::Get_Scene_Editor ()->Get_Fog_Enable ();
  157. WRITE_MICRO_CHUNK (csave, VARID_FOG_ENABLED, fog_enabled);
  158. WRITE_MICRO_CHUNK (csave, VARID_FOG_COLOR, fog_color);
  159. WRITE_MICRO_CHUNK (csave, VARID_FOG_PLANES, fog_planes);
  160. //
  161. // Save the restart and respawn script names
  162. //
  163. StringClass restart_script_name = CombatManager::Get_Start_Script ();
  164. StringClass respawn_script_name = CombatManager::Get_Respawn_Script ();
  165. WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_RESTART_SCRIPT_NAME, restart_script_name);
  166. WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_RESPAWN_SCRIPT_NAME, respawn_script_name);
  167. //
  168. // Save the far clip plane...
  169. //
  170. float znear = 0;
  171. float zfar = 0;
  172. ::Get_Camera_Mgr ()->Get_Camera ()->Get_Clip_Planes (znear, zfar);
  173. WRITE_MICRO_CHUNK (csave, VARID_FAR_CLIP_PLANE, zfar);
  174. //
  175. // Write the background music filename out to the chunk
  176. //
  177. CString filename = ::Get_Scene_Editor ()->Get_Background_Music_Filename ();
  178. CString path = ::Get_File_Mgr ()->Make_Relative_Path (filename);
  179. WRITE_MICRO_CHUNK_STRING (csave, VARID_BACK_MUSIC, (LPCTSTR)path);
  180. //
  181. // Write the list of include files for the level to the chunk.
  182. //
  183. STRING_LIST &include_list = ::Get_File_Mgr ()->Get_Include_File_List ();
  184. for (index = 0; index < include_list.Count (); index ++) {
  185. StringClass filename = (LPCTSTR)include_list[index];
  186. WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_INCLUDE_FILE, filename);
  187. }
  188. csave.End_Chunk ();
  189. return retval;
  190. }
  191. ///////////////////////////////////////////////////////////////////////
  192. //
  193. // Load
  194. //
  195. ///////////////////////////////////////////////////////////////////////
  196. bool
  197. EditorSaveLoadClass::Load (ChunkLoadClass &cload)
  198. {
  199. bool retval = true;
  200. while (cload.Open_Chunk ()) {
  201. switch (cload.Cur_Chunk_ID ()) {
  202. //
  203. // Load all the presets from this chunk
  204. //
  205. case CHUNKID_MICRO_CHUNKS:
  206. retval &= Load_Micro_Chunks (cload);
  207. break;
  208. }
  209. cload.Close_Chunk ();
  210. }
  211. SaveLoadSystemClass::Register_Post_Load_Callback (this);
  212. return retval;
  213. }
  214. ///////////////////////////////////////////////////////////////////////
  215. //
  216. // Load_Micro_Chunks
  217. //
  218. ///////////////////////////////////////////////////////////////////////
  219. bool
  220. EditorSaveLoadClass::Load_Micro_Chunks (ChunkLoadClass &cload)
  221. {
  222. bool retval = true;
  223. Vector3 fog_color (0, 0, 0);
  224. bool fog_enabled = false;
  225. StringClass restart_script_name;
  226. StringClass respawn_script_name;
  227. while (cload.Open_Micro_Chunk ()) {
  228. switch (cload.Cur_Micro_Chunk_ID ()) {
  229. //
  230. // Read the camera's transformation matrix from the chunk
  231. // and pass it onto the camera.
  232. //
  233. case VARID_CAMERA_TM:
  234. {
  235. Matrix3D camera_tm;
  236. cload.Read(&camera_tm,sizeof (camera_tm));
  237. ::Get_Camera_Mgr ()->Get_Camera ()->Set_Transform (camera_tm);
  238. }
  239. break;
  240. //
  241. // Read the include file from the chunk and add it to the list
  242. // of level include files.
  243. //
  244. case VARID_INCLUDE_FILE:
  245. {
  246. StringClass filename;
  247. cload.Read(filename.Get_Buffer(cload.Cur_Micro_Chunk_Length()),cload.Cur_Micro_Chunk_Length());
  248. ::Get_File_Mgr ()->Get_Include_File_List ().Add ((LPCTSTR)filename);
  249. }
  250. break;
  251. case VARID_FAR_CLIP_PLANE_DOUBLE:
  252. {
  253. float znear = 0;
  254. float zfar = 0;
  255. ::Get_Camera_Mgr ()->Get_Camera ()->Get_Clip_Planes (znear, zfar);
  256. double double_zfar = 0;
  257. cload.Read (&double_zfar, sizeof (double_zfar));
  258. zfar = double_zfar;
  259. ::Get_Camera_Mgr ()->Get_Camera ()->Set_Clip_Planes (znear, zfar);
  260. }
  261. break;
  262. case VARID_FAR_CLIP_PLANE:
  263. {
  264. float znear = 0;
  265. float zfar = 0;
  266. ::Get_Camera_Mgr ()->Get_Camera ()->Get_Clip_Planes (znear, zfar);
  267. cload.Read (&zfar, sizeof (zfar));
  268. ::Get_Camera_Mgr ()->Get_Camera ()->Set_Clip_Planes (znear, zfar);
  269. }
  270. break;
  271. case VARID_AMBIENT_LIGHT:
  272. {
  273. Vector3 ambient_light;
  274. cload.Read (&ambient_light, sizeof (ambient_light));
  275. ::Get_Scene_Editor ()->Set_Ambient_Light (ambient_light);
  276. ::Get_Scene_Editor ()->Update_Lighting ();
  277. LightAmbientFormClass *light_form = Get_Ambient_Light_Form ();
  278. light_form->Update_Settings ();
  279. }
  280. break;
  281. READ_MICRO_CHUNK (cload, VARID_FOG_ENABLED, fog_enabled);
  282. READ_MICRO_CHUNK (cload, VARID_FOG_COLOR, fog_color);
  283. READ_MICRO_CHUNK_WWSTRING (cload, VARID_RESTART_SCRIPT_NAME, restart_script_name);
  284. READ_MICRO_CHUNK_WWSTRING (cload, VARID_RESPAWN_SCRIPT_NAME, respawn_script_name);
  285. case VARID_FOG_PLANES:
  286. {
  287. struct
  288. {
  289. float z_near;
  290. float z_far;
  291. } fog_planes = { 50.0F, 100.0F };
  292. cload.Read (&fog_planes, sizeof (fog_planes));
  293. ::Get_Scene_Editor ()->Set_Fog_Range (fog_planes.z_near, fog_planes.z_far);
  294. }
  295. break;
  296. case VARID_BACK_MUSIC:
  297. {
  298. StringClass filename;
  299. cload.Read(filename.Get_Buffer(cload.Cur_Micro_Chunk_Length()),cload.Cur_Micro_Chunk_Length());
  300. ::Get_Scene_Editor ()->Set_Background_Music (filename);
  301. }
  302. break;
  303. }
  304. cload.Close_Micro_Chunk ();
  305. }
  306. //
  307. // Apply the script settings
  308. //
  309. CombatManager::Set_Start_Script (restart_script_name);
  310. CombatManager::Set_Respawn_Script (respawn_script_name);
  311. //
  312. // Apply the fog settings
  313. //
  314. ::Get_Scene_Editor ()->Set_Fog_Color (fog_color);
  315. ::Get_Scene_Editor ()->Set_Fog_Enable (fog_enabled);
  316. return retval;
  317. }
  318. ///////////////////////////////////////////////////////////////////////
  319. //
  320. // Save_Level
  321. //
  322. ///////////////////////////////////////////////////////////////////////
  323. void
  324. EditorSaveLoadClass::Save_Level (LPCTSTR filename)
  325. {
  326. //
  327. // Create the file
  328. //
  329. HANDLE hfile = ::CreateFile (filename,
  330. GENERIC_WRITE,
  331. 0,
  332. NULL,
  333. CREATE_ALWAYS,
  334. 0L,
  335. NULL);
  336. ASSERT (hfile != INVALID_HANDLE_VALUE);
  337. if (hfile != INVALID_HANDLE_VALUE) {
  338. RawFileClass file_obj;
  339. file_obj.Attach (hfile);
  340. ChunkSaveClass chunk_save (&file_obj);
  341. //
  342. // (gth) March 4, 2002 - modifying this function to embed two "save files" into this
  343. // file. The first chunk will contain an entire save for the normal level data. The second
  344. // chunk will contain the lighting save
  345. //
  346. chunk_save.Begin_Chunk(CHUNKID_LVL_DATA);
  347. Save_Level_Data(chunk_save);
  348. chunk_save.End_Chunk();
  349. chunk_save.Begin_Chunk(CHUNKID_LIGHT_SOLVE);
  350. Save_Light_Solve(chunk_save);
  351. chunk_save.End_Chunk();
  352. //
  353. // Remember that we are now up-to-date
  354. //
  355. Set_Modified (false);
  356. }
  357. return ;
  358. }
  359. ///////////////////////////////////////////////////////////////////////
  360. //
  361. // Save_Level_Data - saves the level data for an LVL file
  362. //
  363. ///////////////////////////////////////////////////////////////////////
  364. void
  365. EditorSaveLoadClass::Save_Level_Data(ChunkSaveClass & chunk_save)
  366. {
  367. //
  368. // Repartition the static culling systems
  369. // (gth) can't re-partition the object culling systems or
  370. // we'll lose hierarchical vis
  371. //
  372. ::Get_Scene_Editor ()->Re_Partition_Static_Lights ();
  373. ::Get_Scene_Editor ()->Re_Partition_Audio_System ();
  374. //
  375. // Basically just save the list of nodes and some other
  376. // miscellaneous information (camera, sky, etc).
  377. //
  378. SaveLoadSystemClass::Save (chunk_save, _PhysStaticDataSaveSystem);
  379. SaveLoadSystemClass::Save (chunk_save, _TheNodeMgr);
  380. SaveLoadSystemClass::Save (chunk_save, _TheEditorSaveLoadSubsystem);
  381. SaveLoadSystemClass::Save (chunk_save, _TheBackgroundMgr);
  382. SaveLoadSystemClass::Save (chunk_save, _TheWeatherMgr);
  383. SaveLoadSystemClass::Save (chunk_save, _TheMapMgrSaveLoadSubsystem);
  384. SaveLoadSystemClass::Save (chunk_save, _TheHeightfieldMgrSaveLoadSubsystem);
  385. //
  386. // Save the level-specific conversations
  387. //
  388. _ConversationMgrSaveLoad.Set_Category_To_Save (ConversationMgrClass::CATEGORY_LEVEL);
  389. SaveLoadSystemClass::Save (chunk_save, _ConversationMgrSaveLoad);
  390. return ;
  391. }
  392. ///////////////////////////////////////////////////////////////////////
  393. //
  394. // Save_Light_Solve - saves the light-solve data for an LVL file
  395. //
  396. ///////////////////////////////////////////////////////////////////////
  397. void EditorSaveLoadClass::Save_Light_Solve(ChunkSaveClass & chunk_save)
  398. {
  399. SaveLoadSystemClass::Save( chunk_save, _TheLightSolveSaveSystem);
  400. return ;
  401. }
  402. ///////////////////////////////////////////////////////////////////////
  403. //
  404. // Load_Level
  405. //
  406. ///////////////////////////////////////////////////////////////////////
  407. void
  408. EditorSaveLoadClass::Load_Level (LPCTSTR filename)
  409. {
  410. //
  411. // Create the file
  412. //
  413. HANDLE hfile = ::CreateFile (filename,
  414. GENERIC_READ,
  415. FILE_SHARE_READ,
  416. NULL,
  417. OPEN_EXISTING,
  418. 0L,
  419. NULL);
  420. ASSERT (hfile != INVALID_HANDLE_VALUE);
  421. if (hfile != INVALID_HANDLE_VALUE) {
  422. RawFileClass file_obj;
  423. file_obj.Attach (hfile);
  424. ChunkLoadClass chunk_load (&file_obj);
  425. SoundSceneClass *sound_scene = WWAudioClass::Get_Instance ()->Get_Sound_Scene ();
  426. if (sound_scene != NULL) {
  427. sound_scene->Set_Batch_Mode (true);
  428. }
  429. //
  430. // Get the save-load subsystem to load
  431. //
  432. m_LoadedValidVis = true;
  433. NodeMgrClass::Free_Nodes ();
  434. //
  435. // (gth) March 4, 2002 - LVL files are now two independent save-load operations,
  436. // one for the normal level data and one for the light solve data. Here, we
  437. // detect whether we are loading a file that was created before this change.
  438. //
  439. uint32 id,size;
  440. if (chunk_load.Peek_Next_Chunk(&id,&size) && (id == CHUNKID_LVL_DATA)) {
  441. // Current file format, multiple saves embedded into this file
  442. while (chunk_load.Open_Chunk()) {
  443. switch (chunk_load.Cur_Chunk_ID()) {
  444. case CHUNKID_LVL_DATA:
  445. case CHUNKID_LIGHT_SOLVE:
  446. SaveLoadSystemClass::Load (chunk_load);
  447. break;
  448. default:
  449. break;
  450. }
  451. chunk_load.Close_Chunk();
  452. }
  453. } else {
  454. // Legacy file format support
  455. SaveLoadSystemClass::Load (chunk_load);
  456. }
  457. //
  458. // Repartition the static culling systems
  459. // (gth) can't re-partition the object culling systems or
  460. // we'll lose hierarchical vis
  461. //
  462. ::Get_Scene_Editor ()->Re_Partition_Static_Lights ();
  463. ::Get_Scene_Editor ()->Re_Partition_Audio_System ();
  464. //
  465. // Now create any embedded nodes (nodes that are embedded inside
  466. // the preset of any nodes that are currently in the level).
  467. //
  468. NodeMgrClass::Create_All_Embedded_Nodes ();
  469. //
  470. // Validate VIS information if necessary
  471. //
  472. if (m_LoadedValidVis) {
  473. ::Get_Scene_Editor ()->Validate_Vis ();
  474. ::Get_Scene_Editor ()->Update_Culling_System_Bounding_Boxes ();
  475. } else {
  476. ::MessageBox (NULL, "Static geometry has changed since the last time this level was loaded. All previously generated VIS data has been discarded.", "Vis Discarded", MB_ICONEXCLAMATION | MB_OK);
  477. ::Get_Scene_Editor ()->Discard_Vis ();
  478. }
  479. if (sound_scene != NULL) {
  480. sound_scene->Set_Batch_Mode (false);
  481. }
  482. //
  483. // Remember that we are now up-to-date
  484. //
  485. Set_Modified (false);
  486. }
  487. return ;
  488. }
  489. ///////////////////////////////////////////////////////////////////////
  490. //
  491. // Export_Dynamic_Objects
  492. //
  493. ///////////////////////////////////////////////////////////////////////
  494. void
  495. EditorSaveLoadClass::Export_Dynamic_Objects (LPCTSTR filename)
  496. {
  497. //
  498. // Create the file
  499. //
  500. HANDLE hfile = ::CreateFile (filename,
  501. GENERIC_WRITE,
  502. 0,
  503. NULL,
  504. CREATE_ALWAYS,
  505. 0L,
  506. NULL);
  507. ASSERT (hfile != INVALID_HANDLE_VALUE);
  508. if (hfile != INVALID_HANDLE_VALUE) {
  509. RawFileClass file_obj;
  510. file_obj.Attach (hfile);
  511. ChunkSaveClass chunk_save (&file_obj);
  512. //
  513. // Remove the static objects from the level, save the nodes,
  514. // then put the static objects back
  515. //
  516. NODE_LIST static_obj_list;
  517. NodeMgrClass::Remove_Static_Objects (static_obj_list);
  518. SaveLoadSystemClass::Save (chunk_save, _TheNodeMgr);
  519. NodeMgrClass::Put_Objects_Back (static_obj_list);
  520. }
  521. return ;
  522. }
  523. ///////////////////////////////////////////////////////////////////////
  524. //
  525. // Import_Dynamic_Objects
  526. //
  527. ///////////////////////////////////////////////////////////////////////
  528. void
  529. EditorSaveLoadClass::Import_Dynamic_Objects (LPCTSTR filename)
  530. {
  531. //
  532. // Create the file
  533. //
  534. HANDLE hfile = ::CreateFile (filename,
  535. GENERIC_READ,
  536. FILE_SHARE_READ,
  537. NULL,
  538. OPEN_EXISTING,
  539. 0L,
  540. NULL);
  541. ASSERT (hfile != INVALID_HANDLE_VALUE);
  542. if (hfile != INVALID_HANDLE_VALUE) {
  543. RawFileClass file_obj;
  544. file_obj.Attach (hfile);
  545. ChunkLoadClass chunk_load (&file_obj);
  546. //
  547. // Find the largest used ID
  548. //
  549. uint32 start_id = (NodeMgrClass::Get_Max_Used_ID () + 1);
  550. //
  551. // Remove the dynamic objects from the level and load the new objects.
  552. //
  553. NODE_LIST dynamic_obj_list;
  554. NodeMgrClass::Remove_Dynamic_Objects (dynamic_obj_list);
  555. SaveLoadSystemClass::Load (chunk_load);
  556. ::Output_Message ("Resetting existing static node IDs.\r\n");
  557. //
  558. // Re-assign IDs to the existing static nodes
  559. //
  560. for ( NodeClass *node = NodeMgrClass::Get_First ();
  561. node != NULL;
  562. node = NodeMgrClass::Get_Next (node))
  563. {
  564. if (node->Is_Static ()) {
  565. node->Set_ID (start_id++);
  566. }
  567. }
  568. //
  569. // Check all the dynamic objects for ID collision
  570. //
  571. CString id_collision_msg = "The following dynamic object IDs collided on import:\n\n";
  572. bool show_msg = false;
  573. DynamicVectorClass<NodeClass *> bad_node_list;
  574. for (int index = 0; index < dynamic_obj_list.Count (); index ++) {
  575. NodeClass *node = dynamic_obj_list[index];
  576. if (NodeMgrClass::Find_Node (node->Get_ID ()) != NULL) {
  577. CString entry;
  578. entry.Format ("Object %d\n", node->Get_ID ());
  579. id_collision_msg += entry;
  580. bad_node_list.Add (node);
  581. show_msg = true;
  582. }
  583. }
  584. //
  585. // Put the original objects back
  586. //
  587. NodeMgrClass::Put_Objects_Back (dynamic_obj_list);
  588. NodeMgrClass::Reset_New_ID ();
  589. //
  590. // Let the user know we had ID collision (if necessary)
  591. //
  592. if (show_msg) {
  593. ::MessageBox (NULL, id_collision_msg, "ID Collision", MB_ICONERROR | MB_OK);
  594. //
  595. // Ask the user if we should fix the collisions or not
  596. //
  597. if (::MessageBox (NULL, "Would you like to repair the newly imported objects with ambiguous IDs?", "ID Collision", MB_ICONQUESTION | MB_YESNO) == IDYES) {
  598. //
  599. // Repair all collisions
  600. //
  601. for (int index = 0; index < bad_node_list.Count (); index ++) {
  602. NodeClass *node = bad_node_list[index];
  603. if (node != NULL) {
  604. node->Set_ID (NodeMgrClass::Get_Node_ID (node->Get_Type ()));
  605. }
  606. }
  607. }
  608. }
  609. }
  610. return ;
  611. }
  612. ///////////////////////////////////////////////////////////////////////
  613. //
  614. // On_Post_Load
  615. //
  616. ///////////////////////////////////////////////////////////////////////
  617. void
  618. EditorSaveLoadClass::On_Post_Load (void)
  619. {
  620. }
  621. ///////////////////////////////////////////////////////////////////////
  622. //
  623. // Export_Pathfind
  624. //
  625. ///////////////////////////////////////////////////////////////////////
  626. void
  627. PathfindImportExportSaveLoadClass::Export_Pathfind (LPCTSTR filename)
  628. {
  629. //
  630. // Create the file
  631. //
  632. HANDLE hfile = ::CreateFile (filename,
  633. GENERIC_WRITE,
  634. 0,
  635. NULL,
  636. CREATE_ALWAYS,
  637. 0L,
  638. NULL);
  639. ASSERT (hfile != INVALID_HANDLE_VALUE);
  640. if (hfile != INVALID_HANDLE_VALUE) {
  641. RawFileClass file_obj;
  642. file_obj.Attach (hfile);
  643. ChunkSaveClass chunk_save (&file_obj);
  644. //
  645. //
  646. // Basically just save the list of nodes and some other
  647. // miscellaneous information (camera, sky, etc).
  648. //
  649. SaveLoadSystemClass::Save (chunk_save, _ThePathfindImporterExporter);
  650. }
  651. return ;
  652. }
  653. ///////////////////////////////////////////////////////////////////////
  654. //
  655. // Import_Pathfind
  656. //
  657. ///////////////////////////////////////////////////////////////////////
  658. void
  659. PathfindImportExportSaveLoadClass::Import_Pathfind (LPCTSTR filename)
  660. {
  661. //
  662. // Create the file
  663. //
  664. HANDLE hfile = ::CreateFile (filename,
  665. GENERIC_READ,
  666. FILE_SHARE_READ,
  667. NULL,
  668. OPEN_EXISTING,
  669. 0L,
  670. NULL);
  671. ASSERT (hfile != INVALID_HANDLE_VALUE);
  672. if (hfile != INVALID_HANDLE_VALUE) {
  673. RawFileClass file_obj;
  674. file_obj.Attach (hfile);
  675. ChunkLoadClass chunk_load (&file_obj);
  676. //
  677. // Get the save-load subsystem to load
  678. //
  679. SaveLoadSystemClass::Load (chunk_load);
  680. }
  681. return ;
  682. }
  683. ///////////////////////////////////////////////////////////////////////
  684. //
  685. // Save
  686. //
  687. ///////////////////////////////////////////////////////////////////////
  688. bool
  689. PathfindImportExportSaveLoadClass::Save (ChunkSaveClass &csave)
  690. {
  691. //
  692. // Save the pathfind data
  693. //
  694. csave.Begin_Chunk (CHUNKID_PATHFIND_DATA);
  695. PathfindClass::Get_Instance()->Save (csave);
  696. csave.End_Chunk ();
  697. return true;
  698. }
  699. ///////////////////////////////////////////////////////////////////////
  700. //
  701. // Load
  702. //
  703. ///////////////////////////////////////////////////////////////////////
  704. bool
  705. PathfindImportExportSaveLoadClass::Load (ChunkLoadClass &cload)
  706. {
  707. while (cload.Open_Chunk ()) {
  708. switch (cload.Cur_Chunk_ID ()) {
  709. //
  710. // Import the pathfind data...
  711. //
  712. case CHUNKID_PATHFIND_DATA:
  713. PathfindClass::Get_Instance()->Load (cload);
  714. break;
  715. }
  716. cload.Close_Chunk ();
  717. }
  718. return true;
  719. }