inputconfigmgr.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  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 : Combat *
  23. * *
  24. * $Archive:: /Commando/Code/commando/inputconfigmgr.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 1/09/02 11:40a $*
  29. * *
  30. * $Revision:: 6 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "inputconfigmgr.h"
  36. #include "dlgcontrols.h"
  37. #include "input.h"
  38. #include "rawfile.h"
  39. #include "ffactory.h"
  40. #include "registry.h"
  41. #include "chunkio.h"
  42. #include "debug.h"
  43. #include "translatedb.h"
  44. #include "string_ids.h"
  45. #include "slavemaster.h"
  46. ////////////////////////////////////////////////////////////////
  47. // Local constants
  48. ////////////////////////////////////////////////////////////////
  49. static const char *CFG_DICTIONARY_FILENAME = "CONFIG.DAT";
  50. ////////////////////////////////////////////////////////////////
  51. // Registry key names
  52. ////////////////////////////////////////////////////////////////
  53. //static const char *REGISTRY_SUB_KEY = "Software\\Westwood\\Renegade\\Input";
  54. static const char *REG_CURRENT_CONFIG = "Current Config";
  55. ////////////////////////////////////////////////////////////////
  56. // Static member initialization
  57. ////////////////////////////////////////////////////////////////
  58. DynamicVectorClass<InputConfigClass> InputConfigMgrClass::ConfigList;
  59. int InputConfigMgrClass::CurrentConfigIndex = -1;
  60. ////////////////////////////////////////////////////////////////
  61. // Save/load constants
  62. ////////////////////////////////////////////////////////////////
  63. enum
  64. {
  65. CHUNKID_CONFIG_LIST = 0x07181105,
  66. CHUNKID_VARIABLES,
  67. CHUNKID_CONFIG_OBJ,
  68. };
  69. enum
  70. {
  71. VARID_CURRENT_CONFIG = 1,
  72. };
  73. ////////////////////////////////////////////////////////////////
  74. //
  75. // Initialize
  76. //
  77. ////////////////////////////////////////////////////////////////
  78. void
  79. InputConfigMgrClass::Initialize (void)
  80. {
  81. //
  82. // Build the configuration list and load the current configuration
  83. //
  84. Load ();
  85. Load_Current_Configuration ();
  86. return ;
  87. }
  88. ////////////////////////////////////////////////////////////////
  89. //
  90. // Shutdown
  91. //
  92. ////////////////////////////////////////////////////////////////
  93. void
  94. InputConfigMgrClass::Shutdown (void)
  95. {
  96. //
  97. // Save our current configuration list
  98. //
  99. if (!SlaveMaster.Am_I_Slave()) {
  100. Save ();
  101. }
  102. //
  103. // Reset our data
  104. //
  105. ConfigList.Delete_All ();
  106. CurrentConfigIndex = -1;
  107. return ;
  108. }
  109. ////////////////////////////////////////////////////////////////
  110. //
  111. // Get_Current_Configuration
  112. //
  113. ////////////////////////////////////////////////////////////////
  114. bool
  115. InputConfigMgrClass::Get_Current_Configuration (InputConfigClass &config)
  116. {
  117. if (CurrentConfigIndex < 0 || CurrentConfigIndex >= ConfigList.Count ()) {
  118. return false;
  119. }
  120. //
  121. // Simply index into the config list and return the object to the caller
  122. //
  123. config = ConfigList[CurrentConfigIndex];
  124. return true;
  125. }
  126. ////////////////////////////////////////////////////////////////
  127. //
  128. // Load_Current_Configuration
  129. //
  130. ////////////////////////////////////////////////////////////////
  131. void
  132. InputConfigMgrClass::Load_Current_Configuration (void)
  133. {
  134. if (CurrentConfigIndex < 0 || CurrentConfigIndex >= ConfigList.Count ()) {
  135. //
  136. // The current configuration is invalid, so load the
  137. // default configuration
  138. //
  139. Load_Default_Configuration ();
  140. } else {
  141. //
  142. // Load this configuration
  143. //
  144. Load_Configuration (ConfigList[CurrentConfigIndex]);
  145. }
  146. return ;
  147. }
  148. ////////////////////////////////////////////////////////////////
  149. //
  150. // Save_Current_Configuration
  151. //
  152. ////////////////////////////////////////////////////////////////
  153. void
  154. InputConfigMgrClass::Save_Current_Configuration (void)
  155. {
  156. if (CurrentConfigIndex < 0 || CurrentConfigIndex >= ConfigList.Count ()) {
  157. return ;
  158. }
  159. //
  160. // Save this configuration
  161. //
  162. Save_Configuration (ConfigList[CurrentConfigIndex]);
  163. return ;
  164. }
  165. ////////////////////////////////////////////////////////////////
  166. //
  167. // Add_Configuration
  168. //
  169. ////////////////////////////////////////////////////////////////
  170. int
  171. InputConfigMgrClass::Add_Configuration (const WCHAR *display_name)
  172. {
  173. //
  174. // Get a filename for the configuration
  175. //
  176. StringClass filename;
  177. Get_Unique_Config_Filename (filename);
  178. //
  179. // Build a new input config object
  180. //
  181. InputConfigClass config;
  182. config.Set_Display_Name (display_name);
  183. config.Set_Filename (filename);
  184. config.Set_Is_Custom (true);
  185. //
  186. // Add the object to our list
  187. //
  188. CurrentConfigIndex = ConfigList.Add (config);
  189. //
  190. // Now save the current configuration to this file
  191. //
  192. Save_Configuration (config);
  193. return CurrentConfigIndex;
  194. }
  195. ////////////////////////////////////////////////////////////////
  196. //
  197. // Delete_Configuration
  198. //
  199. ////////////////////////////////////////////////////////////////
  200. void
  201. InputConfigMgrClass::Delete_Configuration (int index)
  202. {
  203. if (index < 0 || index >= ConfigList.Count ()) {
  204. return ;
  205. }
  206. //
  207. // Reset the current configuration (if necessary)
  208. //
  209. bool load_default = false;
  210. if (index == CurrentConfigIndex) {
  211. CurrentConfigIndex = -1;
  212. load_default = true;
  213. }
  214. //
  215. // Get the local path of the configuration files
  216. //
  217. StringClass config_path;
  218. Get_Config_Path (config_path);
  219. StringClass full_path;
  220. full_path.Format ("%s\\%s", config_path, ConfigList[index].Get_Filename ());
  221. //
  222. // Delete the configuration file
  223. //
  224. ::DeleteFile (full_path);
  225. //
  226. // Now remove this entry from the list
  227. //
  228. ConfigList.Delete (index);
  229. //
  230. // Load the default configuration is we just deleted the current configuration
  231. //
  232. if (load_default) {
  233. Load_Default_Configuration ();
  234. }
  235. return ;
  236. }
  237. ////////////////////////////////////////////////////////////////
  238. //
  239. // Delete_Configuration
  240. //
  241. ////////////////////////////////////////////////////////////////
  242. void
  243. InputConfigMgrClass::Delete_Configuration (const char *filename)
  244. {
  245. //
  246. // Try to find the configuration in our list
  247. //
  248. int index = Find_Configuration (filename);
  249. if (index != -1) {
  250. //
  251. // We've found the conversation, so delete it
  252. //
  253. Delete_Configuration (index);
  254. }
  255. return ;
  256. }
  257. ////////////////////////////////////////////////////////////////
  258. //
  259. // Find_Configuration
  260. //
  261. ////////////////////////////////////////////////////////////////
  262. int
  263. InputConfigMgrClass::Find_Configuration (const char *filename)
  264. {
  265. int retval = -1;
  266. for (int index = 0; index < ConfigList.Count (); index ++) {
  267. //
  268. // Is this the entry we're looking for?
  269. //
  270. if (::lstrcmpi (ConfigList[index].Get_Filename (), filename) == 0) {
  271. retval = index;
  272. break;
  273. }
  274. }
  275. return retval;
  276. }
  277. ////////////////////////////////////////////////////////////////
  278. //
  279. // Load_Default_Configuration
  280. //
  281. ////////////////////////////////////////////////////////////////
  282. void
  283. InputConfigMgrClass::Load_Default_Configuration (void)
  284. {
  285. for (int index = 0; index < ConfigList.Count (); index ++) {
  286. //
  287. // Is this the default configuration?
  288. //
  289. if (ConfigList[index].Is_Default ()) {
  290. Load_Configuration (ConfigList[index]);
  291. break;
  292. }
  293. }
  294. return ;
  295. }
  296. ////////////////////////////////////////////////////////////////
  297. //
  298. // Load_Configuration
  299. //
  300. ////////////////////////////////////////////////////////////////
  301. void
  302. InputConfigMgrClass::Load_Configuration (const InputConfigClass &config)
  303. {
  304. //
  305. // Anytime we loada configuration, it becomes our current config
  306. //
  307. CurrentConfigIndex = Find_Configuration (config.Get_Filename ());
  308. //
  309. // Load the configuration into memory
  310. //
  311. Input::Load_Configuration (config.Get_Filename ());
  312. //
  313. // Reload the UI (if necessary)
  314. //
  315. if (ControlsMenuClass::Get_Instance () != NULL) {
  316. ControlsMenuClass::Get_Instance ()->Reload ();
  317. }
  318. return ;
  319. }
  320. ////////////////////////////////////////////////////////////////
  321. //
  322. // Save_Configuration
  323. //
  324. ////////////////////////////////////////////////////////////////
  325. void
  326. InputConfigMgrClass::Save_Configuration (const InputConfigClass &config)
  327. {
  328. //
  329. // We can only save custom configurations
  330. //
  331. if (config.Is_Custom ()) {
  332. //
  333. // Anytime we save a configuration, it becomes our current config...
  334. //
  335. CurrentConfigIndex = Find_Configuration (config.Get_Filename ());
  336. Input::Save_Configuration (config.Get_Filename ());
  337. //
  338. // Update the copy of this config in our internal list
  339. //
  340. if (CurrentConfigIndex != -1) {
  341. ConfigList[CurrentConfigIndex] = config;
  342. }
  343. } else {
  344. //
  345. // Make a name for a new configuration
  346. //
  347. WideStringClass new_name = TRANSLATE (IDS_MENU_CUSTOM);
  348. new_name += config.Get_Display_Name ();
  349. //
  350. // Add a new configuration to list (this saves the new
  351. // configuration as well)
  352. //
  353. Add_Configuration (new_name);
  354. }
  355. return ;
  356. }
  357. ////////////////////////////////////////////////////////////////
  358. //
  359. // Get_Unique_Config_Filename
  360. //
  361. ////////////////////////////////////////////////////////////////
  362. void
  363. InputConfigMgrClass::Get_Unique_Config_Filename (StringClass &filename)
  364. {
  365. //
  366. // Get the local path of the configuration files
  367. //
  368. StringClass config_path;
  369. Get_Config_Path (config_path);
  370. int slot = 1;
  371. StringClass full_path;
  372. do
  373. {
  374. //
  375. // Build this filename
  376. //
  377. filename.Format ("input%.2d.cfg", slot ++);
  378. //
  379. // Check to see if this file exists
  380. //
  381. full_path.Format ("%s\\%s", (const char *)config_path, filename);
  382. } while (::GetFileAttributes (full_path) != 0xFFFFFFFF);
  383. return ;
  384. }
  385. ////////////////////////////////////////////////////////////////
  386. //
  387. // Save
  388. //
  389. ////////////////////////////////////////////////////////////////
  390. void
  391. InputConfigMgrClass::Save (void)
  392. {
  393. FileClass *file = _TheFileFactory->Get_File (CFG_DICTIONARY_FILENAME);
  394. WWASSERT (file != NULL);
  395. if (file == NULL) {
  396. return ;
  397. }
  398. //
  399. // Open the file for writing
  400. //
  401. file->Open (FileClass::WRITE);
  402. ChunkSaveClass csave(file);
  403. //
  404. // Save the config list to its own chunk
  405. //
  406. csave.Begin_Chunk (CHUNKID_CONFIG_LIST);
  407. Save_Config_List (csave);
  408. csave.End_Chunk ();
  409. //
  410. // Save the
  411. //
  412. csave.Begin_Chunk (CHUNKID_VARIABLES);
  413. Save_Variables (csave);
  414. csave.End_Chunk ();
  415. //
  416. // Close the file
  417. //
  418. file->Close ();
  419. _TheFileFactory->Return_File (file);
  420. return ;
  421. }
  422. ////////////////////////////////////////////////////////////////
  423. //
  424. // Load
  425. //
  426. ////////////////////////////////////////////////////////////////
  427. void
  428. InputConfigMgrClass::Load (void)
  429. {
  430. FileClass *file = _TheFileFactory->Get_File (CFG_DICTIONARY_FILENAME);
  431. WWASSERT (file != NULL);
  432. if (file == NULL) {
  433. return ;
  434. }
  435. //
  436. // Open the file for reading
  437. //
  438. file->Open (FileClass::READ);
  439. ChunkLoadClass cload(file);
  440. //
  441. // Read all the chunks stored in this file
  442. //
  443. while (cload.Open_Chunk ()) {
  444. switch(cload.Cur_Chunk_ID ()) {
  445. case CHUNKID_CONFIG_LIST:
  446. Load_Config_List (cload);
  447. break;
  448. case CHUNKID_VARIABLES:
  449. Load_Variables (cload);
  450. break;
  451. default:
  452. Debug_Say (("Unrecognized InputConfigMgrClass Chunk ID\n"));
  453. break;
  454. }
  455. cload.Close_Chunk ();
  456. }
  457. //
  458. // If the configuration list is empty, then add the default
  459. // configuration file to the list
  460. //
  461. if (ConfigList.Count () == 0) {
  462. InputConfigClass config;
  463. config.Set_Display_Name (TRANSLATE (IDS_MENU_DEFAULT_SETTINGS));
  464. config.Set_Filename (DEFAULT_INPUT_FILENAME);
  465. config.Set_Is_Custom (false);
  466. config.Set_Is_Default (true);
  467. ConfigList.Add (config);
  468. CurrentConfigIndex = 0;
  469. }
  470. //
  471. // Close the file
  472. //
  473. file->Close ();
  474. _TheFileFactory->Return_File (file);
  475. return ;
  476. }
  477. ////////////////////////////////////////////////////////////////
  478. //
  479. // Save_Config_List
  480. //
  481. ////////////////////////////////////////////////////////////////
  482. void
  483. InputConfigMgrClass::Save_Config_List (ChunkSaveClass &csave)
  484. {
  485. for (int index = 0; index < ConfigList.Count (); index ++) {
  486. //
  487. // Save this configuration object to its own chunk
  488. //
  489. csave.Begin_Chunk (CHUNKID_CONFIG_OBJ);
  490. ConfigList[index].Save (csave);
  491. csave.End_Chunk ();
  492. }
  493. return ;
  494. }
  495. ////////////////////////////////////////////////////////////////
  496. //
  497. // Load_Config_List
  498. //
  499. ////////////////////////////////////////////////////////////////
  500. void
  501. InputConfigMgrClass::Load_Config_List (ChunkLoadClass &cload)
  502. {
  503. //
  504. // Read all the sub-chunks
  505. //
  506. while (cload.Open_Chunk ()) {
  507. switch (cload.Cur_Chunk_ID ()) {
  508. case CHUNKID_CONFIG_OBJ:
  509. {
  510. //
  511. // Load this configuration object
  512. //
  513. InputConfigClass config;
  514. config.Load (cload);
  515. //
  516. // Add the object to our list
  517. //
  518. ConfigList.Add (config);
  519. break;
  520. }
  521. default:
  522. Debug_Say (("Unrecognized InputConfigMgrClass::Load_Config_List Chunk ID\n"));
  523. break;
  524. }
  525. cload.Close_Chunk ();
  526. }
  527. return ;
  528. }
  529. ////////////////////////////////////////////////////////////////
  530. //
  531. // Save_Variables
  532. //
  533. ////////////////////////////////////////////////////////////////
  534. void
  535. InputConfigMgrClass::Save_Variables (ChunkSaveClass &csave)
  536. {
  537. //
  538. // Determine what the filename of the current configuration is
  539. //
  540. StringClass filename;
  541. if (CurrentConfigIndex != -1) {
  542. filename = ConfigList[CurrentConfigIndex].Get_Filename ();
  543. } else {
  544. filename = DEFAULT_INPUT_FILENAME;
  545. }
  546. WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_CURRENT_CONFIG, filename);
  547. return ;
  548. }
  549. ////////////////////////////////////////////////////////////////
  550. //
  551. // Load_Variables
  552. //
  553. ////////////////////////////////////////////////////////////////
  554. void
  555. InputConfigMgrClass::Load_Variables (ChunkLoadClass &cload)
  556. {
  557. StringClass filename;
  558. //
  559. // Read all the microchunks
  560. //
  561. while (cload.Open_Micro_Chunk ()) {
  562. switch(cload.Cur_Micro_Chunk_ID ()) {
  563. READ_MICRO_CHUNK_WWSTRING (cload, VARID_CURRENT_CONFIG, filename);
  564. }
  565. cload.Close_Micro_Chunk ();
  566. }
  567. //
  568. // Store the index of this configuration
  569. //
  570. CurrentConfigIndex = Find_Configuration (filename);
  571. return ;
  572. }
  573. ////////////////////////////////////////////////////////////////
  574. //
  575. // Get_Config_Path
  576. //
  577. ////////////////////////////////////////////////////////////////
  578. void
  579. InputConfigMgrClass::Get_Config_Path (StringClass &full_path)
  580. {
  581. //
  582. // Lookup the path of the executable
  583. //
  584. char path[MAX_PATH] = { 0 };
  585. ::GetModuleFileName (NULL, path, sizeof (path));
  586. //
  587. // Strip off the filename
  588. //
  589. char *filename_portion = ::strrchr (path, '\\');
  590. if (filename_portion != NULL) {
  591. filename_portion[0] = 0;
  592. }
  593. //
  594. // Build the full path from the EXE's directory
  595. //
  596. full_path.Format ("%s\\data\\config", path);
  597. return ;
  598. }