diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt
index f14cfac5fb..640c1c4521 100644
--- a/pcsx2/CMakeLists.txt
+++ b/pcsx2/CMakeLists.txt
@@ -343,6 +343,7 @@ set(pcsx2GuiHeaders
gui/Panels/MemoryCardPanels.h
gui/pxEventThread.h
gui/RecentIsoList.h
+ gui/Saveslots.h
)
# Warning: the declaration of the .h are mandatory in case of resources files. It will ensure the creation
diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp
index 7a9d28240c..78c73d0c14 100644
--- a/pcsx2/System/SysCoreThread.cpp
+++ b/pcsx2/System/SysCoreThread.cpp
@@ -236,6 +236,7 @@ void SysCoreThread::GameStartingInThread()
sApp.PostAppMethod(&Pcsx2App::resetDebugger);
ApplyLoadedPatches(PPT_ONCE_ON_LOAD);
+ UI_UpdateSysControls();
}
bool SysCoreThread::StateCheckInThread()
diff --git a/pcsx2/gui/AppSaveStates.h b/pcsx2/gui/AppSaveStates.h
index 8fee5eb198..2925f39e2f 100644
--- a/pcsx2/gui/AppSaveStates.h
+++ b/pcsx2/gui/AppSaveStates.h
@@ -17,6 +17,7 @@
#include "App.h"
#include "SaveState.h"
+#include "Saveslots.h"
// --------------------------------------------------------------------------------------
// SysExecEvent_SaveSinglePlugin
@@ -60,15 +61,3 @@ extern void StateCopy_SaveToFile( const wxString& file );
extern void StateCopy_LoadFromFile( const wxString& file );
extern void StateCopy_SaveToSlot( uint num );
extern void StateCopy_LoadFromSlot( uint slot, bool isFromBackup = false );
-
-extern void States_registerLoadBackupMenuItem( wxMenuItem* loadBackupMenuItem );
-
-extern bool States_isSlotUsed(int num);
-extern void States_DefrostCurrentSlotBackup();
-extern void States_DefrostCurrentSlot();
-extern void States_FreezeCurrentSlot();
-extern void States_CycleSlotForward();
-extern void States_CycleSlotBackward();
-
-extern void States_SetCurrentSlot( int slot );
-extern int States_GetCurrentSlot();
diff --git a/pcsx2/gui/MainFrame.cpp b/pcsx2/gui/MainFrame.cpp
index 66fb797bff..892373bfdf 100644
--- a/pcsx2/gui/MainFrame.cpp
+++ b/pcsx2/gui/MainFrame.cpp
@@ -28,6 +28,7 @@
#include "AppAccelerators.h"
#include "svnrev.h"
+#include "Saveslots.h"
// ------------------------------------------------------------------------
wxMenu* MainEmuFrame::MakeStatesSubMenu( int baseid, int loadBackupId ) const
@@ -36,18 +37,18 @@ wxMenu* MainEmuFrame::MakeStatesSubMenu( int baseid, int loadBackupId ) const
for (int i = 0; i < 10; i++)
{
- mnuSubstates->Append( baseid+i+1, wxsFormat(_("Slot %d"), i) );
+ // Will be changed once an iso is loaded.
+ mnuSubstates->Append(baseid + i + 1, wxsFormat(_("Slot %d"), i));
}
- if( loadBackupId>=0 )
+
+ if (loadBackupId >= 0)
{
mnuSubstates->AppendSeparator();
- wxMenuItem* m = mnuSubstates->Append( loadBackupId, _("Backup") );
+ wxMenuItem* m = mnuSubstates->Append(loadBackupId, _("Backup"));
m->Enable( false );
- States_registerLoadBackupMenuItem( m );
}
- //mnuSubstates->Append( baseid - 1, _("Other...") );
return mnuSubstates;
}
@@ -787,4 +788,3 @@ void PerPluginMenuInfo::OnLoaded()
);
MyMenu.Enable( GetPluginMenuId_Settings(PluginId), true );
}
-
diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h
index 07abbb17ac..3f8c47e490 100644
--- a/pcsx2/gui/MainFrame.h
+++ b/pcsx2/gui/MainFrame.h
@@ -137,6 +137,7 @@ public:
void UpdateIsoSrcSelection();
void RemoveCdvdMenu();
void EnableMenuItem( int id, bool enable );
+ void SetMenuItemLabel(int id, wxString str);
void EnableCdvdPluginSubmenu(bool isEnable = true);
bool Destroy();
diff --git a/pcsx2/gui/Saveslots.cpp b/pcsx2/gui/Saveslots.cpp
index 3c86f369c6..57a11dc2f2 100644
--- a/pcsx2/gui/Saveslots.cpp
+++ b/pcsx2/gui/Saveslots.cpp
@@ -17,11 +17,13 @@
#include "App.h"
#include "AppSaveStates.h"
#include "ConsoleLogger.h"
+#include "MainFrame.h"
#include "Common.h"
#include "GS.h"
#include "Elfheader.h"
+#include "Saveslots.h"
// --------------------------------------------------------------------------------------
// Saveslot Section
@@ -29,15 +31,7 @@
static int StatesC = 0;
static const int StateSlotsCount = 10;
-static wxMenuItem* g_loadBackupMenuItem =NULL;
-
-bool States_isSlotUsed(int num)
-{
- if (ElfCRC == 0)
- return false;
- else
- return wxFileExists( SaveStateBase::GetFilename( num ) );
-}
+Saveslot saveslot_cache[10] = {{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}};
// FIXME : Use of the IsSavingOrLoading flag is mostly a hack until we implement a
// complete thread to manage queuing savestate tasks, and zipping states to disk. --air
@@ -49,90 +43,101 @@ public:
wxString GetEventName() const { return L"ClearSavingLoadingFlag"; }
virtual ~SysExecEvent_ClearSavingLoadingFlag() = default;
- SysExecEvent_ClearSavingLoadingFlag()
- {
- }
-
- SysExecEvent_ClearSavingLoadingFlag* Clone() const { return new SysExecEvent_ClearSavingLoadingFlag(); }
+ SysExecEvent_ClearSavingLoadingFlag() { }
+ SysExecEvent_ClearSavingLoadingFlag *Clone() const { return new SysExecEvent_ClearSavingLoadingFlag(); }
protected:
void InvokeEvent()
{
IsSavingOrLoading = false;
+ UI_UpdateSysControls();
}
};
-void Sstates_updateLoadBackupMenuItem( bool isBeforeSave = false);
+void Sstates_updateLoadBackupMenuItem(bool isBeforeSave);
void States_FreezeCurrentSlot()
{
// FIXME : Use of the IsSavingOrLoading flag is mostly a hack until we implement a
// complete thread to manage queuing savestate tasks, and zipping states to disk. --air
- if( !SysHasValidState() )
+ if (!SysHasValidState())
{
- Console.WriteLn( "Save state: Aborting (VM is not active)." );
+ Console.WriteLn("Save state: Aborting (VM is not active).");
return;
}
- if( wxGetApp().HasPendingSaves() || IsSavingOrLoading.exchange(true) )
+ if (wxGetApp().HasPendingSaves() || IsSavingOrLoading.exchange(true))
{
- Console.WriteLn( "Load or save action is already pending." );
+ Console.WriteLn("Load or save action is already pending.");
return;
}
- Sstates_updateLoadBackupMenuItem( true );
+ Sstates_updateLoadBackupMenuItem(true);
- GSchangeSaveState( StatesC, SaveStateBase::GetFilename( StatesC ).ToUTF8() );
- StateCopy_SaveToSlot( StatesC );
-
- GetSysExecutorThread().PostIdleEvent( SysExecEvent_ClearSavingLoadingFlag() );
+ GSchangeSaveState(StatesC, SaveStateBase::GetFilename(StatesC).ToUTF8());
+ StateCopy_SaveToSlot(StatesC);
+
+ // Hack: Update the saveslot saying it's filled *right now* because it's still writing the file and we don't have a timestamp.
+ saveslot_cache[StatesC].empty = false;
+ saveslot_cache[StatesC].updated = wxDateTime::Now();
+ saveslot_cache[StatesC].crc = ElfCRC;
+
+ GetSysExecutorThread().PostIdleEvent(SysExecEvent_ClearSavingLoadingFlag());
}
-void _States_DefrostCurrentSlot( bool isFromBackup )
+void _States_DefrostCurrentSlot(bool isFromBackup)
{
- if( !SysHasValidState() )
+ if (!SysHasValidState())
{
- Console.WriteLn( "Load state: Aborting (VM is not active)." );
+ Console.WriteLn("Load state: Aborting (VM is not active).");
return;
}
- if( IsSavingOrLoading.exchange(true) )
+ if (IsSavingOrLoading.exchange(true))
{
- Console.WriteLn( "Load or save action is already pending." );
+ Console.WriteLn("Load or save action is already pending.");
return;
}
- GSchangeSaveState( StatesC, SaveStateBase::GetFilename( StatesC ).ToUTF8() );
- StateCopy_LoadFromSlot( StatesC, isFromBackup );
+ GSchangeSaveState(StatesC, SaveStateBase::GetFilename(StatesC).ToUTF8());
+ StateCopy_LoadFromSlot(StatesC, isFromBackup);
- GetSysExecutorThread().PostIdleEvent( SysExecEvent_ClearSavingLoadingFlag() );
+ GetSysExecutorThread().PostIdleEvent(SysExecEvent_ClearSavingLoadingFlag());
- Sstates_updateLoadBackupMenuItem();
+ Sstates_updateLoadBackupMenuItem(false);
}
void States_DefrostCurrentSlot()
{
- _States_DefrostCurrentSlot( false );
+ _States_DefrostCurrentSlot(false);
}
void States_DefrostCurrentSlotBackup()
{
- _States_DefrostCurrentSlot( true );
+ _States_DefrostCurrentSlot(true);
}
-
-void States_registerLoadBackupMenuItem( wxMenuItem* loadBackupMenuItem )
+// I'd keep an eye on this function, as it may still be problematic.
+void Sstates_updateLoadBackupMenuItem(bool isBeforeSave)
{
- g_loadBackupMenuItem = loadBackupMenuItem;
+ wxString file = SaveStateBase::GetFilename(StatesC);
+
+ if (!(isBeforeSave && g_Conf->EmuOptions.BackupSavestate))
+ {
+ file = file + L".backup";
+ }
+
+ sMainFrame.EnableMenuItem(MenuId_State_LoadBackup, wxFileExists(file));
+ sMainFrame.SetMenuItemLabel(MenuId_State_LoadBackup, wxsFormat(L"%s %d", _("Backup"), StatesC));
}
static void OnSlotChanged()
{
- OSDlog( Color_StrongGreen, true, " > Selected savestate slot %d", StatesC );
+ OSDlog(Color_StrongGreen, true, " > Selected savestate slot %d", StatesC);
- if( GSchangeSaveState != NULL )
+ if (GSchangeSaveState != NULL)
GSchangeSaveState(StatesC, SaveStateBase::GetFilename(StatesC).utf8_str());
- Sstates_updateLoadBackupMenuItem();
+ Sstates_updateLoadBackupMenuItem(false);
}
int States_GetCurrentSlot()
@@ -140,33 +145,20 @@ int States_GetCurrentSlot()
return StatesC;
}
-void Sstates_updateLoadBackupMenuItem( bool isBeforeSave )
+void States_SetCurrentSlot(int slot)
{
- if( !g_loadBackupMenuItem ) return;
-
- int slot = States_GetCurrentSlot();
- wxString file = SaveStateBase::GetFilename( slot );
- g_loadBackupMenuItem->Enable( wxFileExists( isBeforeSave && g_Conf->EmuOptions.BackupSavestate ? file : file + L".backup" ) );
- wxString label;
- label.Printf(L"%s %d", _("Backup"), slot );
- g_loadBackupMenuItem->SetItemLabel( label );
-}
-
-void States_SetCurrentSlot( int slot )
-{
- StatesC = std::min( std::max( slot, 0 ), StateSlotsCount );
+ StatesC = std::min(std::max(slot, 0), StateSlotsCount);
OnSlotChanged();
}
void States_CycleSlotForward()
{
- StatesC = (StatesC+1) % StateSlotsCount;
+ StatesC = (StatesC + 1) % StateSlotsCount;
OnSlotChanged();
}
void States_CycleSlotBackward()
{
- StatesC = (StatesC+StateSlotsCount-1) % StateSlotsCount;
+ StatesC = (StatesC + StateSlotsCount - 1) % StateSlotsCount;
OnSlotChanged();
}
-
diff --git a/pcsx2/gui/Saveslots.h b/pcsx2/gui/Saveslots.h
new file mode 100644
index 0000000000..3886d76c48
--- /dev/null
+++ b/pcsx2/gui/Saveslots.h
@@ -0,0 +1,100 @@
+/* PCSX2 - PS2 Emulator for PCs
+ * Copyright (C) 2002-2018 PCSX2 Dev Team
+ *
+ * PCSX2 is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU Lesser General Public License as published by the Free Software Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with PCSX2.
+ * If not, see .
+ */
+
+
+#pragma once
+
+#include "PS2Edefs.h"
+#include "System.h"
+#include "Elfheader.h"
+
+class Saveslot
+{
+public:
+ u32 slot_num;
+ bool empty;
+ wxDateTime updated;
+ u32 crc;
+
+ Saveslot()
+ {
+ slot_num = 0;
+ empty = true;
+ updated = wxInvalidDateTime;
+ crc = ElfCRC;
+ }
+
+ Saveslot(int i)
+ {
+ slot_num = i;
+ empty = true;
+ updated = wxInvalidDateTime;
+ crc = ElfCRC;
+ }
+
+ bool isUsed()
+ {
+ return wxFileExists(SaveStateBase::GetFilename(slot_num));
+ }
+
+ wxDateTime GetTimestamp()
+ {
+ if (!isUsed()) return wxInvalidDateTime;
+
+ return wxDateTime(wxFileModificationTime(SaveStateBase::GetFilename(slot_num)));
+ }
+
+ void UpdateCache()
+ {
+ empty = !isUsed();
+ updated = GetTimestamp();
+ crc = ElfCRC;
+ }
+
+ wxString SlotName()
+ {
+ if (empty) return wxsFormat(_("Slot %d - Empty"), slot_num);
+
+ if (updated != wxInvalidDateTime) return wxsFormat(_("Slot %d - %s %s"), slot_num, updated.FormatDate(), updated.FormatTime());
+
+ return wxsFormat(_("Slot %d - Unknown Time"), slot_num);
+ }
+
+ void ConsoleDump()
+ {
+ Console.WriteLn("Slot %i information:", slot_num);
+ Console.WriteLn("Internal CRC = %i; Current CRC = %i.", crc, ElfCRC);
+ if (empty)
+ Console.WriteLn("Slot cache says it is empty.");
+ else
+ Console.WriteLn("Slot cache says it is used.");
+
+ if (updated != wxInvalidDateTime)
+ Console.WriteLn(wxsFormat(_("Write time is %s %s."), updated.FormatDate(), updated.FormatTime()));
+
+ if (isUsed())
+ Console.WriteLn(wxsFormat(_("The disk has a file on it dated %s %s."), GetTimestamp().FormatDate(), GetTimestamp().FormatTime()));
+ }
+};
+
+extern Saveslot saveslot_cache[10];
+extern void States_DefrostCurrentSlotBackup();
+extern void States_DefrostCurrentSlot();
+extern void States_FreezeCurrentSlot();
+extern void States_CycleSlotForward();
+extern void States_CycleSlotBackward();
+extern void States_SetCurrentSlot(int slot);
+extern int States_GetCurrentSlot();
+extern void Sstates_updateLoadBackupMenuItem(bool isBeforeSave);
\ No newline at end of file
diff --git a/pcsx2/gui/SysState.cpp b/pcsx2/gui/SysState.cpp
index 11dceb9e23..caeec947ab 100644
--- a/pcsx2/gui/SysState.cpp
+++ b/pcsx2/gui/SysState.cpp
@@ -476,6 +476,7 @@ protected:
void CleanupEvent()
{
+ UI_UpdateSysControls();
}
};
@@ -674,6 +675,7 @@ void StateCopy_SaveToSlot( uint num )
Console.Indent().WriteLn( Color_StrongGreen, L"filename: %s", WX_STR(file) );
StateCopy_SaveToFile( file );
+ UI_UpdateSysControls();
}
void StateCopy_LoadFromSlot( uint slot, bool isFromBackup )
@@ -690,4 +692,5 @@ void StateCopy_LoadFromSlot( uint slot, bool isFromBackup )
Console.Indent().WriteLn( Color_StrongGreen, L"filename: %s", WX_STR(file) );
StateCopy_LoadFromFile( file );
+ UI_UpdateSysControls();
}
diff --git a/pcsx2/gui/UpdateUI.cpp b/pcsx2/gui/UpdateUI.cpp
index 5397e2a96b..01b439d6d4 100644
--- a/pcsx2/gui/UpdateUI.cpp
+++ b/pcsx2/gui/UpdateUI.cpp
@@ -19,84 +19,119 @@
// General Notes:
// * It's very important that we re-discover menu items by ID every time we change them,
-// because the modern era of configurable GUIs means that we can't be assured the IDs
-// exist anymore.
+// because the modern era of configurable GUIs means that we can't be assured the IDs
+// exist anymore.
// This is necessary because this stupid wxWidgets thing has implicit debug errors
// in the FindItem call that asserts if the menu options are missing. This is bad
// mojo for configurable/dynamic menus. >_<
-void MainEmuFrame::EnableMenuItem( int id, bool enable )
+void MainEmuFrame::EnableMenuItem(int id, bool enable)
{
- if( wxMenuItem* item = m_menubar.FindItem(id) )
- item->Enable( enable );
+ if (wxMenuItem *item = m_menubar.FindItem(id))
+ item->Enable(enable);
}
-static void _SaveLoadStuff( bool enabled )
+void MainEmuFrame::SetMenuItemLabel(int id, wxString str)
{
- sMainFrame.EnableMenuItem( MenuId_Sys_LoadStates, enabled );
- sMainFrame.EnableMenuItem( MenuId_Sys_SaveStates, enabled );
+ if (wxMenuItem *item = m_menubar.FindItem(id))
+ item->SetItemLabel(str);
+}
+
+static void _SaveLoadStuff(bool enabled)
+{
+ sMainFrame.EnableMenuItem(MenuId_Sys_LoadStates, enabled);
+ sMainFrame.EnableMenuItem(MenuId_Sys_SaveStates, enabled);
+
+ for (int i = 0; i < 10; i++)
+ {
+ int load_menu_item = MenuId_State_Load01 + i + 1;
+ int save_menu_item = MenuId_State_Save01 + i + 1;
+
+ // If the cache is out of sync with the actual files, we need to update things. First update, the cache'll be blank, and this will populate everything.
+ if (saveslot_cache[i].empty == saveslot_cache[i].isUsed())
+ {
+ // If there is actually a file there, or the cache was for a different game, we force an update.
+ // If the cache says there's a saveslot for the current game that there isn't a file for, writing it is done in a different thread,
+ // so it might not be written yet. Which is why I cache to begin with.
+ if (saveslot_cache[i].isUsed() || (saveslot_cache[i].crc != ElfCRC))
+ {
+ saveslot_cache[i].UpdateCache();
+ }
+ }
+
+ sMainFrame.EnableMenuItem(load_menu_item, !saveslot_cache[i].empty);
+ sMainFrame.SetMenuItemLabel(load_menu_item, saveslot_cache[i].SlotName());
+ sMainFrame.SetMenuItemLabel(save_menu_item, saveslot_cache[i].SlotName());
+ }
+ Sstates_updateLoadBackupMenuItem(false);
}
// Updates the enable/disable status of all System related controls: menus, toolbars,
// etc. Typically called by SysEvtHandler whenever the message pump becomes idle.
void UI_UpdateSysControls()
{
- if( wxGetApp().Rpc_TryInvokeAsync( &UI_UpdateSysControls ) ) return;
+ if (wxGetApp().Rpc_TryInvokeAsync(&UI_UpdateSysControls))
+ return;
- sApp.PostAction( CoreThreadStatusEvent( CoreThread_Indeterminate ) );
+ sApp.PostAction(CoreThreadStatusEvent(CoreThread_Indeterminate));
- //_SaveLoadStuff( true );
- _SaveLoadStuff( SysHasValidState() );
+ _SaveLoadStuff(SysHasValidState());
}
void UI_DisableSysShutdown()
{
- if( wxGetApp().Rpc_TryInvokeAsync( &UI_DisableSysShutdown ) ) return;
+ if (wxGetApp().Rpc_TryInvokeAsync(&UI_DisableSysShutdown))
+ return;
- sMainFrame.EnableMenuItem( MenuId_Sys_Shutdown, false );
+ sMainFrame.EnableMenuItem(MenuId_Sys_Shutdown, false);
sMainFrame.EnableMenuItem(MenuId_IsoBrowse, !g_Conf->AskOnBoot);
wxGetApp().GetRecentIsoManager().EnableItems(!g_Conf->AskOnBoot);
}
void UI_EnableSysShutdown()
{
- if( wxGetApp().Rpc_TryInvokeAsync( &UI_EnableSysShutdown ) ) return;
+ if (wxGetApp().Rpc_TryInvokeAsync(&UI_EnableSysShutdown))
+ return;
- sMainFrame.EnableMenuItem( MenuId_Sys_Shutdown, true );
+ sMainFrame.EnableMenuItem(MenuId_Sys_Shutdown, true);
}
void UI_DisableSysActions()
{
- if( wxGetApp().Rpc_TryInvokeAsync( &UI_DisableSysActions ) ) return;
+ if (wxGetApp().Rpc_TryInvokeAsync(&UI_DisableSysActions))
+ return;
- sMainFrame.EnableMenuItem( MenuId_Sys_Shutdown, false );
-
- _SaveLoadStuff( false );
+ sMainFrame.EnableMenuItem(MenuId_Sys_Shutdown, false);
+
+ _SaveLoadStuff(false);
}
void UI_EnableSysActions()
{
- if( wxGetApp().Rpc_TryInvokeAsync( &UI_EnableSysActions ) ) return;
+ if (wxGetApp().Rpc_TryInvokeAsync(&UI_EnableSysActions))
+ return;
- sMainFrame.EnableMenuItem( MenuId_Sys_Shutdown, true );
+ sMainFrame.EnableMenuItem(MenuId_Sys_Shutdown, true);
sMainFrame.EnableMenuItem(MenuId_IsoBrowse, true);
wxGetApp().GetRecentIsoManager().EnableItems(true);
-
- _SaveLoadStuff( true );
+
+ _SaveLoadStuff(true);
}
void UI_DisableStateActions()
{
- if( wxGetApp().Rpc_TryInvokeAsync( &UI_DisableStateActions ) ) return;
- _SaveLoadStuff( false );
+ if (wxGetApp().Rpc_TryInvokeAsync(&UI_DisableStateActions))
+ return;
+
+ _SaveLoadStuff(false);
}
void UI_EnableStateActions()
{
- if( wxGetApp().Rpc_TryInvokeAsync( &UI_EnableStateActions ) ) return;
- _SaveLoadStuff( true );
+ if (wxGetApp().Rpc_TryInvokeAsync(&UI_EnableStateActions))
+ return;
+
+ _SaveLoadStuff(true);
}
-
-
diff --git a/pcsx2/windows/VCprojects/pcsx2.vcxproj b/pcsx2/windows/VCprojects/pcsx2.vcxproj
index 6318f431eb..3f79092097 100644
--- a/pcsx2/windows/VCprojects/pcsx2.vcxproj
+++ b/pcsx2/windows/VCprojects/pcsx2.vcxproj
@@ -427,6 +427,7 @@
+
diff --git a/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters b/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters
index 0243efc87a..f781ab956b 100644
--- a/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters
+++ b/pcsx2/windows/VCprojects/pcsx2.vcxproj.filters
@@ -1197,6 +1197,9 @@
AppHost\Include
+
+ AppHost\Include
+
AppHost\Cheats