From aaf38469bdccb526329cf654be0e4749e7c4cbc8 Mon Sep 17 00:00:00 2001 From: William JCM Date: Fri, 10 Jan 2020 12:23:25 +0100 Subject: [PATCH] MainFrame: add game status checking. Dangerous operations are also blocked during that time. --- CMakeLists.txt | 3 +- GUI/EvtMainFrame.cpp | 92 ++++++++++++++++++++------- GUI/EvtMainFrame.h | 3 + GUI/MainFrame.cpp | 22 ++++++- GUI/MainFrame.fbp | 144 ++++++++++++++++++++++++++++++++++++++++++- GUI/MainFrame.h | 5 ++ 6 files changed, 244 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e68a3b0..d638b2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,4 +45,5 @@ target_link_libraries(wxMASSManager PRIVATE Corrade::Containers Corrade::Utility wx_baseu-3.0 - wx_mswu_core-3.0) + wx_mswu_core-3.0 + wtsapi32) diff --git a/GUI/EvtMainFrame.cpp b/GUI/EvtMainFrame.cpp index 53d5099..e9336c5 100644 --- a/GUI/EvtMainFrame.cpp +++ b/GUI/EvtMainFrame.cpp @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include + #include #include @@ -24,6 +26,7 @@ #define WIN32_LEAN_AND_MEAN #include +#include #include #include @@ -46,6 +49,8 @@ EvtMainFrame::EvtMainFrame(wxWindow* parent): MainFrame(parent) { getLocalSteamId(); initialiseListView(); + isGameRunning(); + _installedListView->Connect(wxEVT_LIST_ITEM_SELECTED, wxListEventHandler(EvtMainFrame::installedSelectionEvent), nullptr, this); _installedListView->Connect(wxEVT_LIST_ITEM_DESELECTED, wxListEventHandler(EvtMainFrame::installedSelectionEvent), nullptr, this); _installedListView->Connect(wxEVT_LIST_BEGIN_DRAG, wxListEventHandler(EvtMainFrame::listColumnDragEvent), nullptr, this); @@ -60,6 +65,8 @@ EvtMainFrame::EvtMainFrame(wxWindow* parent): MainFrame(parent) { _watcher.Connect(wxEVT_FSWATCHER, wxFileSystemWatcherEventHandler(EvtMainFrame::fileUpdateEvent), nullptr, this); _watcher.AddTree(wxFileName(Utility::Directory::toNativeSeparators(_saveDirectory), wxPATH_WIN), wxFSW_EVENT_CREATE|wxFSW_EVENT_DELETE|wxFSW_EVENT_MODIFY|wxFSW_EVENT_RENAME, wxString::Format("Unit??%s.sav", _localSteamId)); + + _gameCheckTimer.Start(3000); } EvtMainFrame::~EvtMainFrame() { @@ -98,6 +105,11 @@ void EvtMainFrame::importEvent(wxCommandEvent&) { return; } + if(_isGameRunning) { + errorMessage("The game is running. Aborting..."); + return; + } + const std::string dest_file = _saveDirectory + Utility::formatString("/Unit{:.2d}{}.sav", _installedListView->GetFirstSelected(), _localSteamId); if(Utility::Directory::exists(dest_file)) { @@ -135,6 +147,11 @@ void EvtMainFrame::moveEvent(wxCommandEvent&) { return; } + if(_isGameRunning) { + errorMessage("The game is running. Aborting..."); + return; + } + std::string orig_file = Utility::formatString("{}/Unit{:.2d}{}.sav", _saveDirectory, source_slot, _localSteamId); std::string dest_status = _installedListView->GetItemText(choice, 1).ToStdString(); std::string dest_file = Utility::formatString("{}/Unit{:.2d}{}.sav", _saveDirectory, choice, _localSteamId); @@ -159,6 +176,11 @@ void EvtMainFrame::deleteEvent(wxCommandEvent&) { return; } + if(_isGameRunning) { + errorMessage("The game is running. Aborting..."); + return; + } + std::string file = Utility::formatString("{}/Unit{:.2d}{}.sav", _saveDirectory, _installedListView->GetFirstSelected(), _localSteamId); if(Utility::Directory::exists(file)) { @@ -208,6 +230,10 @@ void EvtMainFrame::fileUpdateEvent(wxFileSystemWatcherEvent& event) { updateCommandsState(); } +void EvtMainFrame::gameCheckTimerEvent(wxTimerEvent&) { + isGameRunning(); +} + void EvtMainFrame::getSaveDirectory() { wchar_t h[MAX_PATH]; if(!SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, h))) { @@ -256,6 +282,44 @@ void EvtMainFrame::initialiseListView() { refreshListView(); } +void EvtMainFrame::isGameRunning() { + WTS_PROCESS_INFOW* process_infos = nullptr; + unsigned long process_count = 0; + + if(WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &process_infos, &process_count)) { + for(unsigned long i = 0; i < process_count; ++i) { + if(std::wcscmp(process_infos[i].pProcessName, L"MASS_Builder-Win64-Shipping.exe") == 0) { + _isGameRunning = true; + break; + } + else { + _isGameRunning = false; + } + } + + if(_isGameRunning) { + _gameStatus->SetLabel("running"); + _gameStatus->SetForegroundColour(wxColour("red")); + } + else { + _gameStatus->SetLabel("not running"); + _gameStatus->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_CAPTIONTEXT)); + } + } + else { + _isGameRunning = false; + _gameStatus->SetLabel("unknown"); + _gameStatus->SetForegroundColour(wxColour("orange")); + } + + if(process_infos != nullptr) { + WTSFreeMemory(process_infos); + process_infos = nullptr; + } + + updateCommandsState(); +} + void EvtMainFrame::refreshListView() { for(long i = 0; i < 32; i++) { _installedListView->SetItem(i, 1, getSlotMassName(i)); @@ -266,30 +330,14 @@ void EvtMainFrame::refreshListView() { void EvtMainFrame::updateCommandsState() { long selection = _installedListView->GetFirstSelected(); - + wxString state = ""; if(selection != -1) { - _importButton->Enable(); - - wxString state = _installedListView->GetItemText(selection, 1); - if(state != "" && state != "") { - _moveButton->Enable(); - } - else { - _moveButton->Disable(); - } - - if(state != "") { - _deleteButton->Enable(); - } - else { - _deleteButton->Disable(); - } - } - else { - _importButton->Disable(); - _moveButton->Disable(); - _deleteButton->Disable(); + state = _installedListView->GetItemText(selection, 1); } + + _importButton->Enable(selection != -1 && !_isGameRunning); + _moveButton->Enable(selection != -1 && !_isGameRunning && state != "" && state != ""); + _deleteButton->Enable(selection != -1 && !_isGameRunning && state != ""); } std::string EvtMainFrame::getSlotMassName(int index) { diff --git a/GUI/EvtMainFrame.h b/GUI/EvtMainFrame.h index ee9e397..9f99219 100644 --- a/GUI/EvtMainFrame.h +++ b/GUI/EvtMainFrame.h @@ -36,11 +36,13 @@ class EvtMainFrame: public MainFrame { void installedSelectionEvent(wxListEvent&); void listColumnDragEvent(wxListEvent&); void fileUpdateEvent(wxFileSystemWatcherEvent& event); + void gameCheckTimerEvent(wxTimerEvent&); private: void getSaveDirectory(); void getLocalSteamId(); void initialiseListView(); + void isGameRunning(); void refreshListView(); void updateCommandsState(); std::string getSlotMassName(int index); @@ -52,6 +54,7 @@ class EvtMainFrame: public MainFrame { std::string _saveDirectory; std::string _localSteamId; + bool _isGameRunning = false; wxFileSystemWatcher _watcher; int _lastWatcherEventType = 0; diff --git a/GUI/MainFrame.cpp b/GUI/MainFrame.cpp index 53f78e5..23d5e70 100644 --- a/GUI/MainFrame.cpp +++ b/GUI/MainFrame.cpp @@ -69,7 +69,24 @@ MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, co _riskLabel->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); _riskLabel->SetForegroundColour( wxColour( 255, 0, 0 ) ); - bSizerMain->Add( _riskLabel, 0, wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 ); + bSizerMain->Add( _riskLabel, 0, wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT, 5 ); + + wxBoxSizer* bSizerGameStatus; + bSizerGameStatus = new wxBoxSizer( wxHORIZONTAL ); + + _gameStatusLabel = new wxStaticText( this, wxID_ANY, wxT("Game status:"), wxDefaultPosition, wxDefaultSize, 0 ); + _gameStatusLabel->Wrap( -1 ); + bSizerGameStatus->Add( _gameStatusLabel, 1, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP|wxBOTTOM|wxLEFT, 5 ); + + _gameStatus = new wxStaticText( this, wxID_ANY, wxT("not running"), wxDefaultPosition, wxDefaultSize, 0 ); + _gameStatus->Wrap( -1 ); + _gameStatus->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) ); + _gameStatus->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_CAPTIONTEXT ) ); + + bSizerGameStatus->Add( _gameStatus, 0, wxALL, 5 ); + + + bSizerMain->Add( bSizerGameStatus, 0, wxALIGN_CENTER_HORIZONTAL, 5 ); _aboutText = new wxStaticText( this, wxID_ANY, wxT("This version of the application was tested on M.A.S.S. Builder early access version 0.2.4.\nIt may or may not work with other versions of the game.\nMade for the M.A.S.S. Builder community by Guillaume Jacquemin.\nhttps://github.com/williamjcm/wxMASSManager"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL ); _aboutText->Wrap( -1 ); @@ -79,6 +96,7 @@ MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, co this->SetSizer( bSizerMain ); this->Layout(); bSizerMain->Fit( this ); + _gameCheckTimer.SetOwner( this, wxID_ANY ); this->Centre( wxBOTH ); @@ -87,6 +105,7 @@ MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, co _moveButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::moveEvent ), NULL, this ); _deleteButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::deleteEvent ), NULL, this ); _openSaveDirButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::openSaveDirEvent ), NULL, this ); + this->Connect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( MainFrame::gameCheckTimerEvent ) ); } MainFrame::~MainFrame() @@ -96,5 +115,6 @@ MainFrame::~MainFrame() _moveButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::moveEvent ), NULL, this ); _deleteButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::deleteEvent ), NULL, this ); _openSaveDirButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( MainFrame::openSaveDirEvent ), NULL, this ); + this->Disconnect( wxID_ANY, wxEVT_TIMER, wxTimerEventHandler( MainFrame::gameCheckTimerEvent ) ); } diff --git a/GUI/MainFrame.fbp b/GUI/MainFrame.fbp index 18390ef..5109563 100644 --- a/GUI/MainFrame.fbp +++ b/GUI/MainFrame.fbp @@ -482,7 +482,7 @@ 5 - wxALIGN_CENTER_HORIZONTAL|wxEXPAND|wxTOP|wxRIGHT|wxLEFT + wxALIGN_CENTER_HORIZONTAL|wxTOP|wxRIGHT|wxLEFT 0 1 @@ -541,6 +541,139 @@ -1 + + 5 + wxALIGN_CENTER_HORIZONTAL + 0 + + + bSizerGameStatus + wxHORIZONTAL + none + + 5 + wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL|wxEXPAND|wxTOP|wxBOTTOM|wxLEFT + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Game status: + 0 + + 0 + + + 0 + + 1 + _gameStatusLabel + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 + wxALL + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + wxSYS_COLOUR_CAPTIONTEXT + 1 + ,90,92,-1,70,0 + 0 + 0 + wxID_ANY + not running + 0 + + 0 + + + 0 + + 1 + _gameStatus + 1 + + + protected + 1 + + Resizable + 1 + + + ; ; forward_declare + 0 + + + + + -1 + + + + 5 wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT @@ -603,6 +736,15 @@ + + 0 + wxID_ANY + _gameCheckTimer + 0 + 5000 + protected + gameCheckTimerEvent + diff --git a/GUI/MainFrame.h b/GUI/MainFrame.h index b95ff64..3e0a8e3 100644 --- a/GUI/MainFrame.h +++ b/GUI/MainFrame.h @@ -22,6 +22,7 @@ #include #include #include +#include #include /////////////////////////////////////////////////////////////////////////// @@ -41,13 +42,17 @@ class MainFrame : public wxFrame wxButton* _deleteButton; wxButton* _openSaveDirButton; wxStaticText* _riskLabel; + wxStaticText* _gameStatusLabel; + wxStaticText* _gameStatus; wxStaticText* _aboutText; + wxTimer _gameCheckTimer; // Virtual event handlers, overide them in your derived class virtual void importEvent( wxCommandEvent& event ) { event.Skip(); } virtual void moveEvent( wxCommandEvent& event ) { event.Skip(); } virtual void deleteEvent( wxCommandEvent& event ) { event.Skip(); } virtual void openSaveDirEvent( wxCommandEvent& event ) { event.Skip(); } + virtual void gameCheckTimerEvent( wxTimerEvent& event ) { event.Skip(); } public: