shutdown.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Commando *
  23. * *
  24. * $Archive:: /Commando/Code/Commando/shutdown.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 10/16/02 11:11a $*
  29. * *
  30. * $Revision:: 104 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "shutdown.h"
  36. #include "wwmath.h"
  37. #include "wwsaveload.h"
  38. #include "ww3d.h"
  39. #include "WWAudio.H"
  40. #include "wwphys.h"
  41. #include "debug.h"
  42. #include "assets.h"
  43. #include "ffactorylist.h"
  44. #include "input.h"
  45. #include "inputconfigmgr.h"
  46. #include "gamemode.h"
  47. //#include "gamesettings.h"
  48. #include "miscutil.h"
  49. #include "refcount.h"
  50. #include "cnetwork.h"
  51. #include "_globals.h"
  52. #include "systemsettings.h"
  53. #include "diagnostics.h"
  54. #include "translatedb.h"
  55. #include "pathmgr.h"
  56. #include "renegadedialogmgr.h"
  57. #include "campaign.h"
  58. #include "diaglog.h"
  59. #include "binkmovie.h"
  60. //#include "helptext.h"
  61. #include "init.h"
  62. #include "serverfps.h"
  63. #include "encyclopediamgr.h"
  64. #include "playermanager.h"
  65. #include "teammanager.h"
  66. #include "bandwidthgraph.h"
  67. #include "except.h"
  68. #include "skinpackagemgr.h"
  69. #include "modpackagemgr.h"
  70. #include "dx8wrapper.h"
  71. #include "pscene.h"
  72. #include "systeminfolog.h"
  73. #include "cpudetect.h"
  74. #include "dx8caps.h"
  75. #include "registry.h"
  76. #include "specialbuilds.h"
  77. #include <windows.h>
  78. #include <lmcons.h> // UNLEN
  79. extern SimpleFileFactoryClass RenegadeBaseFileFactory;
  80. #define SYSTEM_INFO_LOG_DISABLE "SystemInfoLogDisable"
  81. // These are copy-pasted from WWConfig
  82. //extern const char *KEY_NAME_SETTINGS;
  83. extern const char *VALUE_NAME_DYN_LOD;
  84. extern const char *VALUE_NAME_STATIC_LOD;
  85. extern const char *VALUE_NAME_DYN_SHADOWS;
  86. const char *VALUE_NAME_PRELIT_MODE = "Prelit_Mode";
  87. extern const char *VALUE_NAME_SHADOW_MODE;
  88. extern const char *VALUE_NAME_STATIC_SHADOWS;
  89. extern const char *VALUE_NAME_TEXTURE_RES;
  90. const char *VALUE_NAME_SURFACE_EFFECT = "Surface_Effect_Detail";
  91. extern const char *VALUE_NAME_PARTICLE_DETAIL;
  92. const char *VALUE_NAME_TEXTURE_FILTER_MODE="Texture_Filter_Mode";
  93. static void Get_Detail_String(StringClass& str)
  94. {
  95. str="";
  96. RegistryClass registry (APPLICATION_SUB_KEY_NAME_SYSTEM_SETTINGS);
  97. if (registry.Is_Valid ()) {
  98. //
  99. // Read the values from the registry
  100. //
  101. int dynamic_lod = registry.Get_Int (VALUE_NAME_DYN_LOD, 3000);
  102. int static_lod = registry.Get_Int (VALUE_NAME_STATIC_LOD, 3000);
  103. int dynamic_shadows = registry.Get_Int (VALUE_NAME_DYN_SHADOWS, 1);
  104. int static_shadows = registry.Get_Int (VALUE_NAME_STATIC_SHADOWS, 1);
  105. int texture_filter = registry.Get_Int (VALUE_NAME_TEXTURE_FILTER_MODE, TextureClass::TEXTURE_FILTER_BILINEAR);
  106. int prelit_mode = registry.Get_Int (VALUE_NAME_PRELIT_MODE, WW3D::PRELIT_MODE_LIGHTMAP_MULTI_TEXTURE);
  107. int shadow_mode = registry.Get_Int (VALUE_NAME_SHADOW_MODE, PhysicsSceneClass::SHADOW_MODE_BLOBS_PLUS);
  108. int texture_red = registry.Get_Int (VALUE_NAME_TEXTURE_RES, 0);
  109. int surface_effect = registry.Get_Int (VALUE_NAME_SURFACE_EFFECT, 1);
  110. int particle_detail = registry.Get_Int (VALUE_NAME_PARTICLE_DETAIL, 1);
  111. StringClass tmp;
  112. tmp.Format("Dynamic LOD budget: %d\r\n",dynamic_lod);
  113. str+=tmp;
  114. tmp.Format("Static LOD budget: %d\r\n",static_lod);
  115. str+=tmp;
  116. str+="Shadow Mode: ";
  117. switch (shadow_mode) {
  118. case PhysicsSceneClass::SHADOW_MODE_NONE: str+="None\r\n"; break;
  119. case PhysicsSceneClass::SHADOW_MODE_BLOBS: str+="Blobs\r\n"; break;
  120. case PhysicsSceneClass::SHADOW_MODE_BLOBS_PLUS: str+="Blobs Plus\r\n"; break;
  121. case PhysicsSceneClass::SHADOW_MODE_HARDWARE: str+="Hardware\r\n"; break;
  122. default: str+="???\r\n"; break;
  123. }
  124. tmp.Format("Dynamic Shadows: %s\r\n",dynamic_shadows ? "On" : "Off");
  125. str+=tmp;
  126. tmp.Format("Static Shadows: %s\r\n",static_shadows ? "On" : "Off");
  127. str+=tmp;
  128. str+="Prelit Mode: ";
  129. switch (prelit_mode) {
  130. case WW3D::PRELIT_MODE_VERTEX: str+="Vertex\r\n"; break;
  131. case WW3D::PRELIT_MODE_LIGHTMAP_MULTI_PASS: str+="Multipass\r\n"; break;
  132. case WW3D::PRELIT_MODE_LIGHTMAP_MULTI_TEXTURE: str+="Multitexture\r\n"; break;
  133. default: str+="???\r\n"; break;
  134. }
  135. tmp.Format("Texture Resolution: %d\r\n",texture_red);
  136. str+=tmp;
  137. tmp.Format("Surface Effects (0-2): %d\r\n",surface_effect);
  138. str+=tmp;
  139. tmp.Format("Particle Detail(0-2): %d\r\n",particle_detail);
  140. str+=tmp;
  141. str+="Texture Filter Mode: ";
  142. switch (texture_filter) {
  143. case TextureClass::TEXTURE_FILTER_BILINEAR: str+="Bilinear\r\n"; break;
  144. case TextureClass::TEXTURE_FILTER_TRILINEAR: str+="Trilinear\r\n"; break;
  145. case TextureClass::TEXTURE_FILTER_ANISOTROPIC: str+="Anisotropic\r\n"; break;
  146. default: str+="???\r\n"; break;
  147. }
  148. tmp.Format("Screen UV Bias: %s\r\n",WW3D::Is_Screen_UV_Biased() ? "Enabled" : "Disabled");
  149. str+=tmp;
  150. // NPatch level
  151. str+="NPatch level: ";
  152. if (DX8Wrapper::Get_Current_Caps() && DX8Wrapper::Get_Current_Caps()->Support_NPatches()) {
  153. if (WW3D::Get_NPatches_Level()<=1) {
  154. str+="Disabled\r\n";
  155. }
  156. else {
  157. tmp.Format("%d\r\n",WW3D::Get_NPatches_Level());
  158. str+=tmp;
  159. }
  160. }
  161. else {
  162. str+="Not supported\r\n";
  163. }
  164. int w;
  165. int h;
  166. int bits;
  167. bool windowed;
  168. WW3D::Get_Device_Resolution(w,h,bits,windowed);
  169. tmp.Format("Display mode: %d * %d, %d bits %s\r\n", w,h,bits,windowed ? "Windowed" : "Fullscreen");
  170. str+=tmp;
  171. str+="\r\n";
  172. const char *VALUE_NAME_SOUND_DEVICE_NAME = "device name";
  173. RegistryClass registry_sound( APPLICATION_SUB_KEY_NAME_SOUND );
  174. if ( registry_sound.Is_Valid() ) {
  175. char temp_buffer[256] = { 0 };
  176. registry.Get_String (VALUE_NAME_SOUND_DEVICE_NAME, temp_buffer, sizeof (temp_buffer));
  177. tmp.Format("Sound device: %s\r\n",temp_buffer);
  178. str+=tmp;
  179. }
  180. WWAudioClass* audio=WWAudioClass::Get_Instance();
  181. if (audio) {
  182. tmp.Format("Sound effects: %s\r\n",audio->Are_Sound_Effects_On() ? "Enabled" : "Disabled");
  183. str+=tmp;
  184. tmp.Format("Sound effects volume: %2.2f\r\n",audio->Get_Sound_Effects_Volume());
  185. str+=tmp;
  186. tmp.Format("Music: %s\r\n",audio->Is_Music_On() ? "Enabled" : "Disabled");
  187. str+=tmp;
  188. tmp.Format("Music volume: %2.2f\r\n",audio->Get_Music_Volume());
  189. str+=tmp;
  190. }
  191. }
  192. }
  193. void Get_Compact_Detail_String(StringClass& str)
  194. {
  195. str="";
  196. RegistryClass registry (APPLICATION_SUB_KEY_NAME_SYSTEM_SETTINGS);
  197. if (registry.Is_Valid ()) {
  198. //
  199. // Read the values from the registry
  200. //
  201. int dynamic_lod = registry.Get_Int (VALUE_NAME_DYN_LOD, 3000);
  202. int static_lod = registry.Get_Int (VALUE_NAME_STATIC_LOD, 3000);
  203. int dynamic_shadows = registry.Get_Int (VALUE_NAME_DYN_SHADOWS, 1);
  204. int static_shadows = registry.Get_Int (VALUE_NAME_STATIC_SHADOWS, 1);
  205. int texture_filter = registry.Get_Int (VALUE_NAME_TEXTURE_FILTER_MODE, TextureClass::TEXTURE_FILTER_BILINEAR);
  206. int prelit_mode = registry.Get_Int (VALUE_NAME_PRELIT_MODE, WW3D::PRELIT_MODE_LIGHTMAP_MULTI_TEXTURE);
  207. int shadow_mode = registry.Get_Int (VALUE_NAME_SHADOW_MODE, PhysicsSceneClass::SHADOW_MODE_BLOBS_PLUS);
  208. int texture_red = registry.Get_Int (VALUE_NAME_TEXTURE_RES, 0);
  209. int surface_effect = registry.Get_Int (VALUE_NAME_SURFACE_EFFECT, 1);
  210. int particle_detail = registry.Get_Int (VALUE_NAME_PARTICLE_DETAIL, 1);
  211. StringClass tmp;
  212. tmp.Format("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",dynamic_lod,static_lod,shadow_mode,dynamic_shadows,static_shadows,prelit_mode,texture_red,surface_effect,particle_detail,texture_filter);
  213. str+=tmp;
  214. tmp.Format("%d\t",1);//WW3D::Get_Texture_Compression_Mode());
  215. str+=tmp;
  216. int w;
  217. int h;
  218. int bits;
  219. bool windowed;
  220. WW3D::Get_Device_Resolution(w,h,bits,windowed);
  221. tmp.Format("%d\t%d\t%d\t%d\t",w,h,bits,windowed);
  222. str+=tmp;
  223. }
  224. }
  225. static class SysInfoCopyThreadClass : public ThreadClass
  226. {
  227. public:
  228. StringClass String;
  229. StringClass Filename;
  230. SysInfoCopyThreadClass()
  231. :
  232. ThreadClass("SysInfoCopyThread", &Exception_Handler) {}
  233. void Thread_Function()
  234. {
  235. DWORD written;
  236. HANDLE file = CreateFile(Filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  237. FILE_ATTRIBUTE_NORMAL, NULL);
  238. if (INVALID_HANDLE_VALUE != file) {
  239. WriteFile(file, String, strlen(String), &written, NULL);
  240. CloseHandle(file);
  241. }
  242. }
  243. } SysInfoCopyThread;
  244. // For debug purposes, log system information to \\Mordane\marketin\transfer\users\Jani\SYSINFO
  245. static void Log_System_Information()
  246. {
  247. if (!DX8Wrapper::Is_Initted()) {
  248. return;
  249. }
  250. if (DX8Wrapper::Get_Current_Caps() == NULL) {
  251. return;
  252. }
  253. char name[MAX_COMPUTERNAME_LENGTH + 1];
  254. DWORD size = sizeof(name);
  255. ::GetComputerName(name, &size);
  256. char user[UNLEN+1];
  257. DWORD userlen=sizeof(user);
  258. ::GetUserName(user, &userlen);
  259. StringClass string; // This will be a long string so don't allocate locally!
  260. string.Format("Computer name: %s\r\nUser name: %s\r\n\r\n",name,user);
  261. string+=CPUDetectClass::Get_Processor_Log();
  262. if (DX8Wrapper::Get_Current_Caps()) {
  263. string+=DX8Wrapper::Get_Current_Caps()->Get_Log();
  264. }
  265. string+="\r\n";
  266. string+="Compact tab-delimited version:\r\n";
  267. StringClass tmp; // This will be long so no local alloc needed
  268. string+=CPUDetectClass::Get_Compact_Log();
  269. if (DX8Wrapper::Get_Current_Caps()) {
  270. string+=DX8Wrapper::Get_Current_Caps()->Get_Compact_Log();
  271. }
  272. Get_Compact_Detail_String(tmp);
  273. string+=tmp;
  274. SystemInfoLog::Get_Compact_Log(tmp);
  275. string+=tmp;
  276. string+="\r\n";
  277. Get_Detail_String(tmp);
  278. string+=tmp;
  279. string+="\r\n";
  280. SystemInfoLog::Get_Log(tmp);
  281. string+=tmp;
  282. // Write log to network folder
  283. DWORD written;
  284. HANDLE file;
  285. #ifdef WWDEBUG
  286. RegistryClass registry( APPLICATION_SUB_KEY_NAME_DEBUG );
  287. if ( registry.Is_Valid() ) {
  288. int disable=registry.Get_Int( SYSTEM_INFO_LOG_DISABLE );
  289. if (!disable) {
  290. if (!SysInfoCopyThread.Is_Running()) {
  291. StringClass filename(0,true);
  292. // filename="\\\\havoc\\rock\\projects\\renegade\\logs\\";
  293. filename="\\\\tanya\\game\\Projects\\Renegade\\_sysinfo_logs\\";
  294. tmp.Format("%d_%d_",DX8Wrapper::Get_Current_Caps()->Get_Vendor(),DX8Wrapper::Get_Current_Caps()->Get_Device());
  295. filename+=tmp;
  296. filename+=name;
  297. filename+=".txt";
  298. SysInfoCopyThread.String=string;
  299. SysInfoCopyThread.Filename=filename;
  300. SysInfoCopyThread.Execute();
  301. }
  302. }
  303. }
  304. #endif
  305. // Write log to local work folder
  306. file = CreateFile("sysinfo.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  307. FILE_ATTRIBUTE_NORMAL, NULL);
  308. if (INVALID_HANDLE_VALUE != file) {
  309. WriteFile(file, string, strlen(string), &written, NULL);
  310. CloseHandle(file);
  311. }
  312. }
  313. /*
  314. **
  315. */
  316. void Debug_Refs(void);
  317. /*
  318. **
  319. */
  320. void Game_Shutdown(void)
  321. {
  322. Log_System_Information();
  323. BINKMovie::Shutdown();
  324. CampaignManager::Shutdown();
  325. SystemSettings::Shutdown();
  326. CombatManager::Shutdown();
  327. //Analyze_Soldier_Bandwidth();
  328. cNetwork::Onetime_Shutdown();
  329. cServerFps::Destroy_Instance();
  330. cPlayerManager::Onetime_Shutdown();
  331. cTeamManager::Onetime_Shutdown();
  332. cGameData::Onetime_Shutdown();
  333. cBandwidthGraph::Onetime_Shutdown();
  334. DebugManager::Set_Display_Handler( NULL );
  335. GameModeManager::Destroy_All();
  336. EncyclopediaMgrClass::Shutdown();
  337. RenegadeDialogMgrClass::Shutdown();
  338. // Free the sound library
  339. if (WWAudioClass::Get_Instance () != NULL) {
  340. //WWAudioClass::Get_Instance ()->Shutdown ();
  341. delete WWAudioClass::Get_Instance ();
  342. }
  343. //GameSettings::Shutdown();
  344. SkinPackageMgrClass::Shutdown ();
  345. ModPackageMgrClass::Shutdown ();
  346. TranslateDBClass::Shutdown();
  347. //
  348. // Shutdown the input control system
  349. //
  350. InputConfigMgrClass::Shutdown();
  351. Input::Save_Registry( APPLICATION_SUB_KEY_NAME_CONTROLS );
  352. Input::Shutdown();
  353. DiagLogClass::Shutdown();
  354. // CommandoAssetManager::Shutdown();
  355. WW3D::_Invalidate_Textures();
  356. WWASSERT( WW3DAssetManager::Get_Instance() );
  357. WW3DAssetManager::Delete_This();
  358. // if ( WW3DAssetManager::Get_Instance() ) {
  359. // delete WW3DAssetManager::Get_Instance();
  360. // }
  361. cDiagnostics::Close();
  362. //cHelpText::Close();
  363. PhysicsSceneClass * scene = PhysicsSceneClass::Get_Instance();
  364. scene->Set_Max_Simultaneous_Shadows(0);
  365. PathMgrClass::Shutdown();
  366. WWMath::Shutdown();
  367. WWSaveLoad::Shutdown();
  368. WW3D::Shutdown();
  369. WWPhys::Shutdown();
  370. // WW3DAssetManager::Get_Instance()->Free_Assets();
  371. Debug_Refs();
  372. DebugManager::Save_Registry_Settings( APPLICATION_SUB_KEY_NAME_DEBUG );
  373. DebugManager::Shutdown();
  374. WSA_CHECK(WSACleanup());
  375. /*
  376. ** Remove any old file factories still lying around.
  377. */
  378. if (FileFactoryListClass::Get_Instance() != NULL) {
  379. FileFactoryListClass::Get_Instance()->Remove_FileFactory(&RenegadeBaseFileFactory);
  380. }
  381. while (FileFactoryListClass::Get_Instance() != NULL) {
  382. FileFactoryClass * factory = FileFactoryListClass::Get_Instance()->Remove_FileFactory();
  383. if (factory != NULL) {
  384. WWDEBUG_SAY(("Removing pesky old file factory\n"));
  385. delete factory;
  386. } else {
  387. break;
  388. }
  389. }
  390. RegistryClass registry( APPLICATION_SUB_KEY_NAME_DEBUG );
  391. if ( registry.Is_Valid() ) {
  392. registry.Set_Int( VALUE_NAME_APPLICATION_CRASH_VERSION, 0 );
  393. }
  394. #ifdef FREEDEDICATEDSERVER
  395. Copy_Logs(DebugManager::Get_Version_Number());
  396. #endif //FREEDEDICATEDSERVER
  397. return ;
  398. }
  399. /*
  400. **
  401. */
  402. void Debug_Refs(void)
  403. {
  404. #ifndef NDEBUG
  405. // Debug_Say(("Detecting Active Refs...\r\n"));
  406. RefCountNodeClass * first = RefCountClass::ActiveRefList.First();
  407. RefCountNodeClass * node = first;
  408. while (node->Is_Valid())
  409. {
  410. RefCountClass * obj = node->Get();
  411. ActiveRefStruct * ref = &(obj->ActiveRefInfo);
  412. bool display = true;
  413. int count = 0;
  414. RefCountNodeClass * search = first;
  415. while (search->Is_Valid()) {
  416. if (search == node) { // if this is not the first one
  417. if (count != 0) {
  418. display = false;
  419. break;
  420. }
  421. }
  422. RefCountClass * search_obj = search->Get();
  423. ActiveRefStruct * search_ref = &(search_obj->ActiveRefInfo);
  424. if ( ref->File && search_ref->File &&
  425. !strcmp(search_ref->File, ref->File) &&
  426. (search_ref->Line == ref->Line) ) {
  427. count++;
  428. } else if ( (ref->File == NULL) && (search_ref->File == NULL) ) {
  429. count++;
  430. }
  431. search = search->Next();
  432. }
  433. if ( display ) {
  434. Debug_Say(( "%d Active Ref: %s %d %p\n", count, ref->File,ref->Line,obj));
  435. static int num_printed = 0;
  436. if (++num_printed > 20) {
  437. Debug_Say(( "And Many More......\n"));
  438. break;
  439. }
  440. }
  441. node = node->Next();
  442. }
  443. // Debug_Say(("Done.\r\n"));
  444. #endif
  445. }