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.

295 lines
8.6 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "BasePanel.h"
  7. #include "SaveGameDialog.h"
  8. #include "winlite.h" // FILETIME
  9. #include "vgui/ILocalize.h"
  10. #include "vgui/ISurface.h"
  11. #include "vgui/ISystem.h"
  12. #include "vgui/IVGui.h"
  13. #include "vgui_controls/AnimationController.h"
  14. #include "vgui_controls/ImagePanel.h"
  15. #include "filesystem.h"
  16. #include "KeyValues.h"
  17. #include "ModInfo.h"
  18. #include "EngineInterface.h"
  19. #include "GameUI_Interface.h"
  20. #include "vstdlib/random.h"
  21. #include "BaseSaveGameDialog.h"
  22. #include "SaveGameBrowserDialog.h"
  23. using namespace vgui;
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include "tier0/memdbgon.h"
  26. #include "vgui_controls/Frame.h"
  27. #include "utlvector.h"
  28. extern const char *COM_GetModDirectory();
  29. using namespace vgui;
  30. CSaveGameDialogXbox::CSaveGameDialogXbox( vgui::Panel *parent )
  31. : BaseClass( parent ),
  32. m_bGameSaving ( false ),
  33. m_bNewSaveAvailable( false )
  34. {
  35. m_bFilterAutosaves = true;
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Purpose:
  39. //-----------------------------------------------------------------------------
  40. void CSaveGameDialogXbox::PerformSelectedAction( void )
  41. {
  42. BaseClass::PerformSelectedAction();
  43. // If there are no panels, don't allow this
  44. if ( GetNumPanels() == 0 )
  45. return;
  46. SetControlDisabled( true );
  47. // Decide if this is an overwrite or a new save game
  48. bool bNewSave = ( GetActivePanelIndex() == 0 ) && m_bNewSaveAvailable;
  49. if ( bNewSave )
  50. {
  51. OnCommand( "SaveGame" );
  52. }
  53. else
  54. {
  55. BasePanel()->ShowMessageDialog( MD_SAVE_OVERWRITE, this );
  56. }
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Purpose:
  60. // Input : bNewSaveSelected -
  61. //-----------------------------------------------------------------------------
  62. void CSaveGameDialogXbox::UpdateFooterOptions( void )
  63. {
  64. CFooterPanel *pFooter = GetFooterPanel();
  65. // Show available buttons
  66. pFooter->ClearButtons();
  67. bool bSavePanelsActive = ( GetNumPanels() != 0 );
  68. if ( bSavePanelsActive )
  69. {
  70. bool bNewSaveSelected = ( GetActivePanelIndex() == 0 ) && m_bNewSaveAvailable;
  71. if ( bNewSaveSelected )
  72. {
  73. pFooter->AddNewButtonLabel( "#GameUI_SaveGame_NewSave", "#GameUI_Icons_A_BUTTON" );
  74. }
  75. else
  76. {
  77. pFooter->AddNewButtonLabel( "#GameUI_SaveGame_Overwrite", "#GameUI_Icons_A_BUTTON" );
  78. }
  79. }
  80. // Always available
  81. pFooter->AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
  82. pFooter->AddNewButtonLabel( "#GameUI_Console_StorageChange", "#GameUI_Icons_Y_BUTTON" );
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose: perfrom the save on a separate thread
  86. //-----------------------------------------------------------------------------
  87. class CAsyncCtxSaveGame : public CBasePanel::CAsyncJobContext
  88. {
  89. public:
  90. explicit CAsyncCtxSaveGame( CSaveGameDialogXbox *pDlg );
  91. ~CAsyncCtxSaveGame() {}
  92. public:
  93. virtual void ExecuteAsync();
  94. virtual void Completed();
  95. public:
  96. char m_szFilename[MAX_PATH];
  97. CSaveGameDialogXbox *m_pSaveGameDlg;
  98. };
  99. CAsyncCtxSaveGame::CAsyncCtxSaveGame( CSaveGameDialogXbox *pDlg ) :
  100. CBasePanel::CAsyncJobContext( 3.0f ), // Storage device info for at least 3 seconds
  101. m_pSaveGameDlg( pDlg )
  102. {
  103. NULL;
  104. }
  105. void CAsyncCtxSaveGame::ExecuteAsync()
  106. {
  107. // Sit and wait for the async save to finish
  108. for ( ; ; )
  109. {
  110. if ( !engine->IsSaveInProgress() )
  111. // Save operation is no longer in progress
  112. break;
  113. else
  114. ThreadSleep( 50 );
  115. }
  116. }
  117. void CAsyncCtxSaveGame::Completed()
  118. {
  119. m_pSaveGameDlg->SaveCompleted( this );
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose: kicks off the async save (called on the main thread)
  123. //-----------------------------------------------------------------------------
  124. void CSaveGameDialogXbox::InitiateSaving()
  125. {
  126. // Determine whether this is a new save or overwrite
  127. bool bNewSave = ( GetActivePanelIndex() == 0 ) && m_bNewSaveAvailable;
  128. // Allocate the async context for saving
  129. CAsyncCtxSaveGame *pAsyncCtx = new CAsyncCtxSaveGame( this );
  130. // If this is an overwrite then there was an overwrite warning displayed
  131. if ( !bNewSave )
  132. BasePanel()->CloseMessageDialog( DIALOG_STACK_IDX_WARNING );
  133. // Now display the saving warning
  134. BasePanel()->ShowMessageDialog( MD_SAVING_WARNING, this );
  135. // Kick off saving
  136. char *szFilename = pAsyncCtx->m_szFilename;
  137. const int maxFilenameLen = sizeof( pAsyncCtx->m_szFilename );
  138. char szCmd[MAX_PATH];
  139. // See if this is the "new save game" slot
  140. if ( bNewSave )
  141. {
  142. // Create a new save game (name is created from the current time, which should be pretty unique)
  143. #ifdef WIN32
  144. FILETIME currentTime;
  145. GetSystemTimeAsFileTime( &currentTime );
  146. Q_snprintf( szFilename, maxFilenameLen, "%s_%u", COM_GetModDirectory(), currentTime.dwLowDateTime );
  147. #else
  148. time_t currentTime = time( NULL );
  149. Q_snprintf( szFilename, maxFilenameLen, "%s_%u", COM_GetModDirectory(), (unsigned)currentTime );
  150. #endif
  151. Q_snprintf( szCmd, sizeof( szCmd ), "xsave %s", szFilename );
  152. engine->ExecuteClientCmd( szCmd );
  153. Q_strncat( szFilename, ".360.sav", maxFilenameLen );
  154. }
  155. else
  156. {
  157. const SaveGameDescription_t *pDesc = GetActivePanelSaveDescription();
  158. Q_strncpy( szFilename, pDesc->szShortName, maxFilenameLen );
  159. Q_snprintf( szCmd, sizeof( szCmd ), "xsave %s", szFilename );
  160. engine->ExecuteClientCmd( szCmd );
  161. }
  162. // Enqueue waiting
  163. BasePanel()->ExecuteAsync( pAsyncCtx );
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Purpose: handles the end of async save (called on the main thread)
  167. //-----------------------------------------------------------------------------
  168. void CSaveGameDialogXbox::SaveCompleted( CAsyncCtxSaveGame *pCtx )
  169. {
  170. char const *szFilename = pCtx->m_szFilename;
  171. // We should now be saved so get the new desciption back from the file
  172. char szDirectory[MAX_PATH];
  173. Q_snprintf( szDirectory, sizeof( szDirectory ), "%s:/%s", COM_GetModDirectory(), szFilename );
  174. ParseSaveData( szDirectory, szFilename, &m_NewSaveDesc );
  175. // Close the progress dialog
  176. BasePanel()->CloseMessageDialog( DIALOG_STACK_IDX_WARNING );
  177. bool bNewSave = ( GetActivePanelIndex() == 0 ) && m_bNewSaveAvailable;
  178. if ( bNewSave )
  179. {
  180. AnimateInsertNewPanel( &m_NewSaveDesc );
  181. }
  182. else
  183. {
  184. AnimateOverwriteActivePanel( &m_NewSaveDesc );
  185. }
  186. m_bGameSaving = false;
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Purpose: handles button commands
  190. //-----------------------------------------------------------------------------
  191. void CSaveGameDialogXbox::OnCommand( const char *command )
  192. {
  193. m_KeyRepeat.Reset();
  194. if ( !Q_stricmp( command, "SaveGame" ) )
  195. {
  196. if ( m_bGameSaving )
  197. return;
  198. m_bGameSaving = true;
  199. SetControlDisabled( true );
  200. // Initiate the saving operation
  201. InitiateSaving();
  202. }
  203. else if ( !Q_stricmp( command, "SaveSuccess" ) )
  204. {
  205. vgui::surface()->PlaySound( "UI/buttonclick.wav" );
  206. GameUI().SetSavedThisMenuSession( true );
  207. }
  208. else if ( !Q_stricmp( command, "CloseAndSelectResume" ) )
  209. {
  210. BasePanel()->ArmFirstMenuItem();
  211. OnCommand( "Close" );
  212. }
  213. else if ( !Q_stricmp( command, "OverwriteGameCancelled" ) )
  214. {
  215. SetControlDisabled( false );
  216. }
  217. else if ( !Q_stricmp( command, "RefreshSaveGames" ) )
  218. {
  219. RefreshSaveGames();
  220. }
  221. else if ( !Q_stricmp( command, "ReleaseModalWindow" ) )
  222. {
  223. vgui::surface()->RestrictPaintToSinglePanel( NULL );
  224. }
  225. else if ( !m_bGameSaving )
  226. {
  227. BaseClass::OnCommand(command);
  228. }
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose: On completion of scanning, prepend a utility slot on the stack
  232. //-----------------------------------------------------------------------------
  233. void CSaveGameDialogXbox::OnDoneScanningSaveGames( void )
  234. {
  235. ConVarRef save_history_count("save_history_count" );
  236. m_bNewSaveAvailable = false;
  237. #ifdef _X360
  238. if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED )
  239. return;
  240. // We only allow 10 save games minus the number of autosaves, autosavedangerous, and autosave0?'s at once
  241. if ( GetNumPanels() >= 10 - ( 2 + (unsigned)save_history_count.GetInt() ) )
  242. return;
  243. if ( GetStorageSpaceUsed() + XBX_SAVEGAME_BYTES > XBX_PERSISTENT_BYTES_NEEDED )
  244. return;
  245. m_bNewSaveAvailable = true;
  246. SaveGameDescription_t bogusDesc = { "#GameUI_SaveGame_NewSavedGame", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", 0, 0 };
  247. CGameSavePanel *newSavePanel = SETUP_PANEL( new CGameSavePanel( this, &bogusDesc, true ) );
  248. AddPanel( newSavePanel );
  249. #endif // _X360
  250. }