From db4632182a46dc73fa059102d5837da1c2985710 Mon Sep 17 00:00:00 2001 From: Guillaume Jacquemin Date: Sat, 20 Jul 2024 13:22:15 +0200 Subject: [PATCH] Managers: implement StagedMassManager. --- src/CMakeLists.txt | 3 + src/Managers/StagedMass.h | 30 ++++ src/Managers/StagedMassManager.cpp | 215 +++++++++++++++++++++++++++++ src/Managers/StagedMassManager.h | 52 +++++++ 4 files changed, 300 insertions(+) create mode 100644 src/Managers/StagedMass.h create mode 100644 src/Managers/StagedMassManager.cpp create mode 100644 src/Managers/StagedMassManager.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b57651c..c918b2c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -199,6 +199,9 @@ add_executable(MassBuilderSaveTool Managers/MassManager.cpp Managers/ProfileManager.h Managers/ProfileManager.cpp + Managers/StagedMass.h + Managers/StagedMassManager.h + Managers/StagedMassManager.cpp Managers/Vfs/Directory.h Maps/ArmourSlots.hpp Maps/BulletLauncherAttachmentStyles.hpp diff --git a/src/Managers/StagedMass.h b/src/Managers/StagedMass.h new file mode 100644 index 0000000..0d48fa9 --- /dev/null +++ b/src/Managers/StagedMass.h @@ -0,0 +1,30 @@ +#pragma once + +// MassBuilderSaveTool +// Copyright (C) 2021-2024 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 . + +#include + +using namespace Corrade; + +namespace mbst::Managers { + +struct StagedMass { + Containers::String filename; + Containers::String name; +}; + +} diff --git a/src/Managers/StagedMassManager.cpp b/src/Managers/StagedMassManager.cpp new file mode 100644 index 0000000..20bd5fa --- /dev/null +++ b/src/Managers/StagedMassManager.cpp @@ -0,0 +1,215 @@ +// MassBuilderSaveTool +// Copyright (C) 2021-2024 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 . + +#include + +#include +#include + +#include "../Configuration/Configuration.h" +#include "../GameObjects/Mass.h" +#include "../Logger/Logger.h" +#include "../Utilities/Temp.h" + +#include "StagedMassManager.h" + + +namespace mbst::Managers { + +StagedMassManager::StagedMassManager() { + refresh(); +} + +Containers::StringView +StagedMassManager::lastError() { + return _lastError; +} + +Containers::ArrayView +StagedMassManager::stagedMasses() const { + return _stagedMasses; +} + +const StagedMass& +StagedMassManager::at(Containers::StringView filename) const { + for(const auto& mass : _stagedMasses) { + if(mass.filename == filename) { + return mass; + } + } + + CORRADE_ASSERT_UNREACHABLE("Invalid staged M.A.S.S.!", StagedMass{}); +} + +void +StagedMassManager::refresh() { + _stagedMasses = Containers::Array{}; + + LOG_INFO("Scanning for staged M.A.S.S.es..."); + + scanSubdir(""_s); +} + +void +StagedMassManager::refreshMass(Containers::StringView filename) { + LOG_INFO_FORMAT("Refreshing staged unit with filename {}.", filename); + + bool file_exists = Utility::Path::exists(Utility::Path::join(conf().directories().staging, filename)); + auto index = _stagedMasses.size(); + for(std::size_t i = 0; i < _stagedMasses.size(); ++i) { + if(_stagedMasses[i].filename == filename) { + index = i; + break; + } + } + + if(file_exists) { + if(auto name = GameObjects::Mass::getNameFromFile(Utility::Path::join(conf().directories().staging, filename))) { + arrayAppend(_stagedMasses, StagedMass{filename, *name}); + std::sort(_stagedMasses.begin(), _stagedMasses.end(), + [](const StagedMass& a, const StagedMass& b)->bool{ + if(a.filename.contains('/') && !b.filename.contains('/')) { + return true; + } + return a.filename < b.filename; + } + ); + } + else if(index != _stagedMasses.size()) { + arrayRemove(_stagedMasses, index); + } + } + else if(index != _stagedMasses.size()) { + arrayRemove(_stagedMasses, index); + } +} + +bool +StagedMassManager::import(Containers::StringView filename, int index, Containers::StringView new_account, bool demo) { + if(index < 0 || index >= 32) { + LOG_ERROR(_lastError = "Hangar index out of range."_s); + return false; + } + + bool found = false; + for(auto& mass : _stagedMasses) { + if(mass.filename == filename) { + found = true; + break; + } + } + + if(!found) { + LOG_ERROR(_lastError = "Couldn't find "_s + filename + " in the staged M.A.S.S.es."_s); + return false; + } + + auto source = Utility::Path::join(conf().directories().staging, filename); + auto temp_path = Utilities::getTempPath(Utility::Path::split(filename).second()); + Utility::Path::copy(source, temp_path); + + { + GameObjects::Mass mass{temp_path}; + if(!mass.updateAccount(new_account)) { + LOG_ERROR(_lastError = mass.lastError()); + Utility::Path::remove(temp_path); + return false; + } + } + + auto dest = Utility::Path::join(conf().directories().gameSaves, + Utility::format("{}Unit{}{}.sav", demo ? "Demo" : "", index, new_account)); + + if(Utility::Path::exists(dest)) { + Utility::Path::remove(dest); + } + + if(!Utility::Path::move(temp_path, dest)) { + _lastError = Utility::format("Couldn't move {} to hangar {:.2d}", filename, index + 1); + LOG_ERROR(_lastError); + return false; + } + + return true; +} + +bool +StagedMassManager::remove(Containers::StringView filename) { + bool found = false; + for(auto& mass : _stagedMasses) { + if(mass.filename == filename) { + found = true; + break; + } + } + + if(!found || !Utility::Path::remove(Utility::Path::join(conf().directories().staging, filename))) { + LOG_ERROR(_lastError = Utility::format("{} couldn't be found.", filename)); + return false; + } + + return true; +} + +void +StagedMassManager::scanSubdir(Containers::StringView subdir) { + static std::uint8_t depth = 0; + + auto full_subdir = Utility::Path::join(conf().directories().staging, subdir); + + using Flag = Utility::Path::ListFlag; + auto files = Utility::Path::list(full_subdir, Flag::SkipSpecial|Flag::SkipDirectories); + + if(!files) { + LOG_ERROR_FORMAT("{} couldn't be opened.", full_subdir); + return; + } + + auto iter = std::remove_if(files->begin(), files->end(), [](Containers::StringView file){ + return !file.hasSuffix(".sav"_s); + }); + + auto files_view = files->exceptSuffix(files->end() - iter); + + for(Containers::StringView file : files_view) { + if(auto name = GameObjects::Mass::getNameFromFile(Utility::Path::join(full_subdir, file))) { + LOG_INFO_FORMAT("Found staged M.A.S.S.: {}", *name); + arrayAppend(_stagedMasses, InPlaceInit, file, *name); + } + else { + LOG_WARNING_FORMAT("Skipped {}.", file); + } + } + + if(depth == 5) { + return; + } + + auto subdirs = Utility::Path::list(full_subdir, Flag::SkipFiles|Flag::SkipSpecial|Flag::SkipDotAndDotDot); + if(!subdirs) { + LOG_ERROR_FORMAT("Couldn't list contents of {}.", full_subdir); + } + + depth++; + + for(auto& dir : *subdirs) { + scanSubdir(Utility::Path::join(subdir, dir)); + } + + depth--; +} + +} diff --git a/src/Managers/StagedMassManager.h b/src/Managers/StagedMassManager.h new file mode 100644 index 0000000..87b1630 --- /dev/null +++ b/src/Managers/StagedMassManager.h @@ -0,0 +1,52 @@ +#pragma once + +// MassBuilderSaveTool +// Copyright (C) 2021-2024 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 . + +#include +#include +#include +#include + +#include "StagedMass.h" + +using namespace Corrade; + +namespace mbst::Managers { + +class StagedMassManager { + public: + explicit StagedMassManager(); + + auto lastError() -> Containers::StringView; + + auto stagedMasses() const -> Containers::ArrayView; + auto at(Containers::StringView filename) const -> const StagedMass&; + + void refresh(); + void refreshMass(Containers::StringView filename); + bool import(Containers::StringView filename, int index, Containers::StringView new_account, bool demo); + bool remove(Containers::StringView filename); + + private: + void scanSubdir(Containers::StringView subdir); + + Containers::String _lastError; + + Containers::Array _stagedMasses; +}; + +}