// MassBuilderSaveTool // Copyright (C) 2021-2022 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 "MassManager.h" using namespace Containers::Literals; MassManager::MassManager(Containers::StringView save_path, Containers::StringView account, bool demo, Containers::StringView staging_dir): _saveDirectory{save_path}, _account{account}, _demo{demo}, _stagingAreaDirectory{staging_dir} { Containers::String mass_filename = ""; for(UnsignedInt i = 0; i < _hangars.size(); i++) { mass_filename = Utility::Path::join(_saveDirectory, Utility::format("{}Unit{:.2d}{}.sav", demo ? "Demo"_s : ""_s, i, _account)); new(&_hangars[i]) Mass{mass_filename}; } refreshStagedMasses(); } auto MassManager::lastError() -> Containers::StringView { return _lastError; } auto MassManager::hangar(Int hangar) -> Mass& { return _hangars[hangar]; } void MassManager::refreshHangar(Int hangar) { if(hangar < 0 || hangar >= 32) { return; } Containers::String mass_filename = Utility::Path::join(_saveDirectory, Utility::format("{}Unit{:.2d}{}.sav", _demo ? "Demo" : "", hangar, _account)); _hangars[hangar] = Mass{mass_filename}; } auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bool { if(hangar < 0 || hangar >= 32) { _lastError = "Hangar out of range in MassManager::importMass()"_s; return false; } auto it = _stagedMasses.find(Containers::String::nullTerminatedView(staged_fn)); if(it == _stagedMasses.end()) { _lastError = "Couldn't find "_s + staged_fn + " in the staged M.A.S.S.es."_s; return false; } Containers::String source = Utility::Path::join(_stagingAreaDirectory, staged_fn); Utility::Path::copy(source, source + ".tmp"_s); { Mass mass{source + ".tmp"_s}; if(!mass.updateAccount(_account)) { _lastError = mass.lastError(); Utility::Path::remove(source + ".tmp"_s); return false; } } Containers::String dest = Utility::Path::join(_saveDirectory, _hangars[hangar].filename()); if(Utility::Path::exists(dest)) { Utility::Path::remove(dest); } if(!Utility::Path::move(source + ".tmp"_s, dest)) { _lastError = Utility::format("Couldn't move {} to hangar {:.2d}", staged_fn, hangar + 1); return false; } return true; } auto MassManager::exportMass(Int hangar) -> bool { if(hangar < 0 || hangar >= 32) { _lastError = "Hangar out of range in MassManager::exportMass()"_s; return false; } if(_hangars[hangar].state() != Mass::State::Valid) { _lastError = Utility::format("There is no valid data to export in hangar {:.2d}", hangar + 1); return false; } Containers::String source = Utility::Path::join(_saveDirectory, _hangars[hangar].filename()); Containers::String dest = Utility::Path::join(_stagingAreaDirectory, Utility::format("{}_{}.sav", _hangars[hangar].name(), _account)); if(!Utility::Path::copy(source, dest)) { _lastError = Utility::format("Couldn't export data from hangar {:.2d} to {}", hangar, dest); return false; } return true; } auto MassManager::moveMass(Int source, Int destination) -> bool { if(source < 0 || source >= 32) { _lastError = "Source hangar out of range."_s; return false; } if(destination < 0 || destination >= 32) { _lastError = "Destination hangar out of range."_s; return false; } Containers::String source_file = Utility::Path::join(_saveDirectory, _hangars[source].filename()); Containers::String dest_file = Utility::Path::join(_saveDirectory, _hangars[destination].filename()); Mass::State dest_state = _hangars[destination].state(); switch(dest_state) { case Mass::State::Empty: break; case Mass::State::Invalid: Utility::Path::remove(dest_file); break; case Mass::State::Valid: Utility::Path::move(dest_file, dest_file + ".tmp"_s); break; } Utility::Path::move(source_file, dest_file); if(dest_state == Mass::State::Valid) { Utility::Path::move(dest_file + ".tmp"_s, source_file); } return true; } auto MassManager::deleteMass(Int hangar) -> bool { if(hangar < 0 || hangar >= 32) { _lastError = "Hangar out of range."_s; return false; } if(!Utility::Path::remove(Utility::Path::join(_saveDirectory, _hangars[hangar].filename()))) { _lastError = Utility::format("Deletion failed: {}", std::strerror(errno)); return false; } return true; } auto MassManager::stagedMasses() -> std::map const& { return _stagedMasses; } void MassManager::refreshStagedMasses() { _stagedMasses.clear(); using Utility::Path::ListFlag; auto file_list = Utility::Path::list(_stagingAreaDirectory, ListFlag::SkipSpecial|ListFlag::SkipDirectories|ListFlag::SkipDotAndDotDot); if(!file_list) { Utility::Error{} << _stagingAreaDirectory << "couldn't be opened"; return; } auto iter = std::remove_if(file_list->begin(), file_list->end(), [](Containers::StringView file){ return !file.hasSuffix(".sav"_s); }); auto list_view = file_list->exceptSuffix(file_list->end() - iter); Utility::Debug{} << "Scanning for staged M.A.S.S.es..."; for(Containers::StringView file : list_view) { auto name = Mass::getNameFromFile(Utility::Path::join(_stagingAreaDirectory, file)); if(name) { Utility::Debug{} << "Found staged M.A.S.S.:" << *name; _stagedMasses[file] = *name; } else { Utility::Warning{} << "Skipped:" << file; } } } void MassManager::refreshStagedMass(Containers::StringView filename) { Utility::Debug{} << "Refreshing staged unit with filename" << filename; bool file_exists = Utility::Path::exists(Utility::Path::join(_stagingAreaDirectory, filename)); auto it = _stagedMasses.find(filename); if(file_exists) { auto name = Mass::getNameFromFile(Utility::Path::join(_stagingAreaDirectory, filename)); if(name) { _stagedMasses[filename] = *name; } else if(it != _stagedMasses.cend()) { _stagedMasses.erase(it); } } else if(it != _stagedMasses.cend()) { _stagedMasses.erase(it); } } auto MassManager::deleteStagedMass(Containers::StringView filename) -> bool { if(_stagedMasses.find(filename) == _stagedMasses.cend()) { _lastError = "The file "_s + filename + " couldn't be found in the list of staged M.A.S.S.es."_s; return false; } if(!Utility::Path::remove(Utility::Path::join(_stagingAreaDirectory, filename))) { _lastError = filename + " couldn't be deleted: " + std::strerror(errno); return false; } return true; }