Some early work on classes.

This commit is contained in:
Guillaume Jacquemin 2020-09-01 16:14:43 +02:00
parent 401d7d747e
commit 9ddea11b6e
9 changed files with 698 additions and 0 deletions

View file

@ -47,8 +47,16 @@ add_executable(wxMASSManager WIN32
GUI/NameChangeDialog.cpp GUI/NameChangeDialog.cpp
GUI/EvtNameChangeDialog.h GUI/EvtNameChangeDialog.h
GUI/EvtNameChangeDialog.cpp GUI/EvtNameChangeDialog.cpp
MassBuilderManager/MassBuilderManager.h
MassBuilderManager/MassBuilderManager.cpp
MassManager/MassManager.h MassManager/MassManager.h
MassManager/MassManager.cpp MassManager/MassManager.cpp
Profile/Profile.h
Profile/Profile.cpp
ProfileManager/ProfileManager.h
ProfileManager/ProfileManager.cpp
ScreenshotManager/ScreenshotManager.h
ScreenshotManager/ScreenshotManager.cpp
resource.rc) resource.rc)
target_compile_options(wxMASSManager PRIVATE -D_FILE_OFFSET_BITS=64 -D__WXMSW__ -fpermissive) target_compile_options(wxMASSManager PRIVATE -D_FILE_OFFSET_BITS=64 -D__WXMSW__ -fpermissive)

View file

@ -0,0 +1,87 @@
// wxMASSManager
// Copyright (C) 2020 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
#include <shlobj.h>
#include <wtsapi32.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/Unicode.h>
#include "MassBuilderManager.h"
using namespace Corrade;
MassBuilderManager::MassBuilderManager() {
_ready = findSaveDirectory();
}
auto MassBuilderManager::ready() -> bool {
return _ready;
}
auto MassBuilderManager::lastError() -> std::string const& {
return _lastError;
}
auto MassBuilderManager::saveDirectory() -> std::string const& {
return _saveDirectory;
}
auto MassBuilderManager::checkGameState() -> GameState {
WTS_PROCESS_INFOW* process_infos = nullptr;
unsigned long process_count = 0;
_gameState = GameState::Unknown;
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) {
_gameState = GameState::Running;
break;
}
else {
_gameState = GameState::NotRunning;
}
}
}
if(process_infos != nullptr) {
WTSFreeMemory(process_infos);
process_infos = nullptr;
}
return _gameState;
}
auto MassBuilderManager::gameState() -> GameState {
return _gameState;
}
auto MassBuilderManager::findSaveDirectory() -> bool {
wchar_t h[MAX_PATH];
if(!SUCCEEDED(SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA, nullptr, 0, h))) {
_lastError = "SHGetFolderPathW() failed in MassBuilderManager::findSaveDirectory()";
return false;
}
_saveDirectory = Utility::Directory::join(Utility::Directory::fromNativeSeparators(Utility::Unicode::narrow(h)), "MASS_Builder");
if(!Utility::Directory::exists(_saveDirectory)) {
_lastError = _saveDirectory + " wasn't found.";
return false;
}
return true;
}

View file

@ -0,0 +1,52 @@
#ifndef MASSBUILDERMANAGER_H
#define MASSBUILDERMANAGER_H
// wxMASSManager
// Copyright (C) 2020 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
#include <cstdint>
#include <string>
enum class GameState : std::uint8_t {
Unknown, NotRunning, Running
};
class MassBuilderManager {
public:
MassBuilderManager();
auto ready() -> bool;
auto lastError() -> std::string const&;
auto saveDirectory() -> std::string const&;
auto checkGameState() -> GameState;
auto gameState() -> GameState;
private:
auto findSaveDirectory() -> bool;
bool _ready = false;
std::string _lastError = "";
std::string _saveDirectory = "";
GameState _gameState = GameState::Unknown;
};
#endif //MASSBUILDERMANAGER_H

134
Profile/Profile.cpp Normal file
View file

@ -0,0 +1,134 @@
// wxMASSManager
// Copyright (C) 2020 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
#include <algorithm>
#include <Corrade/Containers/Array.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/String.h>
#include "Profile.h"
constexpr char company_name_locator[] = { 'C', 'o', 'm', 'p', 'a', 'n', 'y', 'N', 'a', 'm', 'e', '\0', 0x0C, '\0', '\0', '\0', 'S', 't', 'r', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' };
constexpr char active_slot_locator[] = { 'A', 'c', 't', 'i', 'v', 'e', 'F', 'r', 'a', 'm', 'e', 'S', 'l', 'o', 't', '\0', 0x0C, '\0', '\0', '\0', 'I', 'n', 't', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' };
constexpr char credits_locator[] = { 'C', 'r', 'e', 'd', 'i', 't', '\0', 0x0C, '\0', '\0', '\0', 'I', 'n', 't', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'y', '\0' };
using namespace Corrade;
Profile::Profile(const std::string& path) {
auto map = Utility::Directory::mapRead(path);
if(!map) {
_lastError = "Couldn't memory-map " + Utility::Directory::filename(path);
return;
}
_profileDirectory = Utility::Directory::path(path);
_filename = Utility::Directory::filename(path);
if(Utility::String::beginsWith(_filename, "Demo")) {
_type = ProfileType::Demo;
}
else {
_type = ProfileType::FullGame;
}
_steamId = Utility::String::ltrim(Utility::String::rtrim(_filename, ".sav"), (_type == ProfileType::Demo ? "Demo" : "") + std::string{"Profile"});
auto it = std::search(map.begin(), map.end(), &company_name_locator[0], &company_name_locator[27]);
if(it == map.end()) {
_lastError = "Couldn't find a company name in " + _filename;
return;
}
_companyName = std::string{it + 41};
_valid = true;
}
auto Profile::valid() const -> bool {
return _valid;
}
auto Profile::lastError() const -> std::string const& {
return _lastError;
}
auto Profile::filename() const -> std::string const& {
return _filename;
}
auto Profile::type() const -> ProfileType {
return _type;
}
auto Profile::steamId() const -> std::string const& {
return _steamId;
}
auto Profile::companyName() const -> std::string const& {
return _companyName;
}
auto Profile::activeFrameSlot() const -> std::int8_t {
return _activeFrameSlot;
}
auto Profile::getActiveFrameSlot() -> std::int8_t {
auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename));
auto iter = std::search(mmap.begin(), mmap.end(), &active_slot_locator[0], &active_slot_locator[31]);
if(iter == mmap.end()) {
if(std::search(mmap.begin(), mmap.end(), &credits_locator[0], &credits_locator[22]) != mmap.end()) {
_activeFrameSlot = 0;
}
else {
_lastError = "The profile save seems to be corrupted or the game didn't release the handle on the file.";
_activeFrameSlot = -1;
}
}
else {
_activeFrameSlot = *(iter + 41);
}
return _activeFrameSlot;
}
auto Profile::credits() const -> std::int32_t {
return _credits;
}
auto Profile::getCredits() -> std::int32_t {
auto mmap = Utility::Directory::mapRead(Utility::Directory::join(_profileDirectory, _filename));
auto iter = std::search(mmap.begin(), mmap.end(), &credits_locator[0], &credits_locator[22]);
if(iter != mmap.end()) {
_credits = ((*(iter + 0x20)) << 0) +
((*(iter + 0x21)) << 8) +
((*(iter + 0x22)) << 16) +
((*(iter + 0x23)) << 24);
}
else{
_credits = -1;
}
return _credits;
}

53
Profile/Profile.h Normal file
View file

@ -0,0 +1,53 @@
#ifndef PROFILE_H
#define PROFILE_H
#include <cstdint>
#include <string>
enum class ProfileType : std::uint8_t {
Demo,
FullGame
};
class Profile {
public:
explicit Profile(const std::string& path);
auto valid() const -> bool;
auto lastError() const -> std::string const&;
auto filename() const -> std::string const&;
auto type() const -> ProfileType;
auto steamId() const -> std::string const&;
auto companyName() const -> std::string const&;
auto activeFrameSlot() const -> std::int8_t;
auto getActiveFrameSlot() -> std::int8_t;
auto credits() const -> std::int32_t;
auto getCredits() -> std::int32_t;
private:
std::string _profileDirectory;
std::string _filename;
ProfileType _type;
std::string _steamId;
bool _valid = false;
std::string _lastError = "";
std::string _companyName;
std::int8_t _activeFrameSlot = 0;
std::int32_t _credits;
};
#endif //PROFILE_H

View file

@ -0,0 +1,100 @@
// wxMASSManager
// Copyright (C) 2020 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
#include <algorithm>
#include <regex>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/String.h>
#include "ProfileManager.h"
using namespace Corrade;
ProfileManager::ProfileManager(const std::string& base_path) {
_profileDirectory = Utility::Directory::join(base_path, "Saved/SaveGames");
if(Utility::Directory::exists(_profileDirectory) == false) {
_lastError = "Couldn't find the profile directory. Make sure you played enough of the game.";
return;
}
using Utility::Directory::Flag;
std::vector<std::string> files = Utility::Directory::list(_profileDirectory, Flag::SkipSpecial|Flag::SkipDirectories|Flag::SkipDotAndDotDot);
auto predicate = [](const std::string& file)->bool{
std::regex regex("(Demo)?Profile[0-9]{17}\\.sav", std::regex::nosubs);
std::cmatch m;
return !std::regex_match(file.c_str(), m, regex);
};
files.erase(std::remove_if(files.begin(), files.end(), predicate), files.end());
for(const std::string& file : files) {
Profile profile{Utility::Directory::join(_profileDirectory, file)};
if(profile.valid() == false) {
Utility::Warning{} << "Profile" << file.c_str() << "is invalid:" << profile.lastError().c_str();
continue;
}
_profiles.push_back(std::move(profile));
}
if(_profiles.size() == 0) {
_lastError = "No profiles were found.";
return;
}
_ready = true;
}
auto ProfileManager::ready() -> bool {
return _ready;
}
auto ProfileManager::lastError() -> std::string const& {
return _lastError;
}
auto ProfileManager::profileDirectory() -> std::string const& {
return _profileDirectory;
}
auto ProfileManager::profiles() -> std::vector<Profile> const& {
return _profiles;
}
auto ProfileManager::currentProfile() -> Profile* {
return _currentProfile;
}
auto ProfileManager::setProfile(std::size_t index) -> bool {
bool result = false;
try {
_currentProfile = &(_profiles.at(index));
result = true;
}
catch(const std::out_of_range&) {
_lastError = "Invalid profile index";
_currentProfile = nullptr;
}
return result;
}

View file

@ -0,0 +1,52 @@
#ifndef PROFILEMANAGER_H
#define PROFILEMANAGER_H
// wxMASSManager
// Copyright (C) 2020 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <vector>
#include "../Profile/Profile.h"
using namespace Corrade;
class ProfileManager {
public:
ProfileManager(const std::string& base_path);
auto ready() -> bool;
auto lastError() -> std::string const&;
auto profileDirectory() -> std::string const&;
auto profiles() -> std::vector<Profile> const&;
auto currentProfile() -> Profile*;
auto setProfile(std::size_t index) -> bool;
private:
bool _ready = false;
std::string _lastError = "";
std::string _profileDirectory;
std::vector<Profile> _profiles;
Profile* _currentProfile = nullptr;
};
#endif //PROFILEMANAGER_H

View file

@ -0,0 +1,145 @@
// wxMASSManager
// Copyright (C) 2020 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
#include <algorithm>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/String.h>
#include <wx/filename.h>
#include "ScreenshotManager.h"
using namespace Corrade;
ScreenshotManager::ScreenshotManager(const std::string& base_path) {
_screenshotDirectory = Utility::Directory::join(base_path, "Saved/Screenshots/WindowsNoEditor");
if(!Utility::Directory::exists(_screenshotDirectory)) {
Utility::Directory::mkpath(_screenshotDirectory);
}
using Utility::Directory::Flag;
std::vector<std::string> file_list = Utility::Directory::list(_screenshotDirectory, Flag::SkipSpecial|Flag::SkipDirectories|Flag::SkipDotAndDotDot);
auto iter = std::remove_if(file_list.begin(), file_list.end(), [](std::string& file){
return !Utility::String::endsWith(file, ".png");
});
file_list.erase(iter, file_list.end());
_screenshots.reserve(file_list.size());
for(const std::string& file : file_list) {
addScreenshot(file);
}
}
auto ScreenshotManager::screenshotDirectory() -> std::string const& {
return _screenshotDirectory;
}
auto ScreenshotManager::screenshots() -> std::vector<Screenshot> const& {
return _screenshots;
}
void ScreenshotManager::sortScreenshots(SortType type) {
_sortType = type;
sortScreenshots();
}
void ScreenshotManager::sortScreenshots(SortOrder order) {
_sortOrder = order;
sortScreenshots();
}
void ScreenshotManager::sortScreenshots() {
auto predicate = [this](const Screenshot& item_1, const Screenshot& item_2)->bool{
switch(_sortType) {
case SortType::Filename:
return wxString::FromUTF8(item_1._filename.c_str()).CmpNoCase(wxString::FromUTF8(item_2._filename.c_str())) < 0;
case SortType::CreationDate:
return item_1._creationDate.IsEarlierThan(item_2._creationDate);
}
return true;
};
switch(_sortOrder) {
case SortOrder::Ascending:
std::stable_sort(_screenshots.begin(), _screenshots.end(), predicate);
break;
case SortOrder::Descending:
std::stable_sort(_screenshots.rbegin(), _screenshots.rend(), predicate);
break;
}
}
auto ScreenshotManager::updateScreenshot(const std::string& filename) -> int {
addScreenshot(filename);
sortScreenshots();
int index = 0;
for(const Screenshot& s : _screenshots) {
if(s._filename == filename) {
return index;
}
}
return -1;
}
void ScreenshotManager::removeScreenshot(int index) {
if(static_cast<size_t>(index + 1) > _screenshots.size()) {
return;
}
auto it = _screenshots.begin() + index;
_screenshots.erase(it);
}
void ScreenshotManager::deleteScreenshot(int index) {
if(static_cast<size_t>(index + 1) > _screenshots.size()) {
return;
}
Utility::Directory::rm(Utility::Directory::join(_screenshotDirectory, _screenshots[index]._filename));
}
void ScreenshotManager::addScreenshot(const std::string& filename) {
std::string screenshot_path = Utility::Directory::toNativeSeparators(Utility::Directory::join(_screenshotDirectory, filename));
wxFileName screenshot_meta(screenshot_path);
wxDateTime creation_date;
screenshot_meta.GetTimes(nullptr, nullptr, &creation_date);
wxImage thumb{screenshot_path, wxBITMAP_TYPE_PNG};
wxSize size = thumb.GetSize();
if(size.GetWidth() > size.GetHeight()) {
size.Set(160, (size.GetHeight() * 160) / size.GetWidth());
}
else if(size.GetHeight() > size.GetWidth()) {
size.Set((size.GetWidth() * 160) / size.GetHeight(), 160);
}
else {
size.Set(160, 160);
}
thumb.Rescale(size.GetWidth(), size.GetHeight(), wxIMAGE_QUALITY_HIGH)
.Resize(wxSize{160, 160}, wxPoint{(160 - size.GetWidth()) / 2, (160 - size.GetHeight()) / 2});
_screenshots.push_back(Screenshot{filename, creation_date, thumb});
}

View file

@ -0,0 +1,67 @@
#ifndef SCREENSHOTMANAGER_H
#define SCREENSHOTMANAGER_H
// wxMASSManager
// Copyright (C) 2020 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <vector>
#include <wx/datetime.h>
#include <wx/image.h>
enum class SortType : uint8_t {
Filename, CreationDate
};
enum class SortOrder: uint8_t {
Ascending, Descending
};
struct Screenshot {
std::string _filename;
wxDateTime _creationDate;
wxImage _thumbnail;
};
class ScreenshotManager {
public:
ScreenshotManager(const std::string& base_path);
auto screenshotDirectory() -> std::string const&;
auto screenshots() -> std::vector<Screenshot> const&;
void sortScreenshots(SortType type);
void sortScreenshots(SortOrder order);
void sortScreenshots();
auto updateScreenshot(const std::string& filename) -> int;
void removeScreenshot(int index);
void deleteScreenshot(int index);
private:
void addScreenshot(const std::string& filename);
std::string _screenshotDirectory = "";
std::vector<Screenshot> _screenshots;
SortType _sortType = SortType::Filename;
SortOrder _sortOrder = SortOrder::Ascending;
};
#endif //SCREENSHOTMANAGER_H