Compare commits
No commits in common. "fa81d2428e56c4d0feb19f8dac5a1b52631897da" and "44656b32d50a1bc3def7ec7226b694051d895e48" have entirely different histories.
fa81d2428e
...
44656b32d5
9 changed files with 124 additions and 158 deletions
|
@ -143,7 +143,6 @@ add_executable(MassBuilderSaveTool WIN32
|
|||
ProfileManager/ProfileManager.cpp
|
||||
Profile/Profile.h
|
||||
Profile/Profile.cpp
|
||||
Profile/PropertyNames.h
|
||||
Profile/ResourceIDs.h
|
||||
MassManager/MassManager.h
|
||||
MassManager/MassManager.cpp
|
||||
|
|
|
@ -19,20 +19,16 @@
|
|||
#include <Corrade/Utility/Format.h>
|
||||
#include <Corrade/Utility/Path.h>
|
||||
|
||||
#include "../Logger/Logger.h"
|
||||
|
||||
#include "MassManager.h"
|
||||
|
||||
using namespace Containers::Literals;
|
||||
|
||||
MassManager::MassManager(Containers::StringView save_path, Containers::StringView account, bool demo,
|
||||
Containers::StringView staging_dir):
|
||||
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));
|
||||
mass_filename = Utility::Path::join(_saveDirectory, Utility::format("{}Unit{:.2d}{}.sav", demo ? "Demo"_s : ""_s, i, _account));
|
||||
new(&_hangars[i]) Mass{mass_filename};
|
||||
}
|
||||
|
||||
|
@ -49,8 +45,6 @@ auto MassManager::hangar(Int hangar) -> Mass& {
|
|||
|
||||
void MassManager::refreshHangar(Int hangar) {
|
||||
if(hangar < 0 || hangar >= 32) {
|
||||
_lastError = "Hangar index out of range.";
|
||||
LOG_ERROR(_lastError);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -62,8 +56,7 @@ void MassManager::refreshHangar(Int hangar) {
|
|||
|
||||
auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bool {
|
||||
if(hangar < 0 || hangar >= 32) {
|
||||
_lastError = "Hangar index out of range.";
|
||||
LOG_ERROR(_lastError);
|
||||
_lastError = "Hangar out of range in MassManager::importMass()"_s;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -71,7 +64,6 @@ auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bo
|
|||
|
||||
if(it == _stagedMasses.end()) {
|
||||
_lastError = "Couldn't find "_s + staged_fn + " in the staged M.A.S.S.es."_s;
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -95,7 +87,6 @@ auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bo
|
|||
|
||||
if(!Utility::Path::move(source + ".tmp"_s, dest)) {
|
||||
_lastError = Utility::format("Couldn't move {} to hangar {:.2d}", staged_fn, hangar + 1);
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -104,14 +95,12 @@ auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bo
|
|||
|
||||
auto MassManager::exportMass(Int hangar) -> bool {
|
||||
if(hangar < 0 || hangar >= 32) {
|
||||
_lastError = "Hangar index out of range."_s;
|
||||
LOG_ERROR(_lastError);
|
||||
_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);
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -121,7 +110,6 @@ auto MassManager::exportMass(Int hangar) -> bool {
|
|||
|
||||
if(!Utility::Path::copy(source, dest)) {
|
||||
_lastError = Utility::format("Couldn't export data from hangar {:.2d} to {}", hangar, dest);
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -130,14 +118,12 @@ auto MassManager::exportMass(Int hangar) -> bool {
|
|||
|
||||
auto MassManager::moveMass(Int source, Int destination) -> bool {
|
||||
if(source < 0 || source >= 32) {
|
||||
_lastError = "Source hangar index out of range."_s;
|
||||
LOG_ERROR(_lastError);
|
||||
_lastError = "Source hangar out of range."_s;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(destination < 0 || destination >= 32) {
|
||||
_lastError = "Destination hangar index out of range."_s;
|
||||
LOG_ERROR(_lastError);
|
||||
_lastError = "Destination hangar out of range."_s;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -167,14 +153,12 @@ auto MassManager::moveMass(Int source, Int destination) -> bool {
|
|||
|
||||
auto MassManager::deleteMass(Int hangar) -> bool {
|
||||
if(hangar < 0 || hangar >= 32) {
|
||||
_lastError = "Hangar index out of range."_s;
|
||||
LOG_ERROR(_lastError);
|
||||
_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));
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -189,11 +173,10 @@ void MassManager::refreshStagedMasses() {
|
|||
_stagedMasses.clear();
|
||||
|
||||
using Utility::Path::ListFlag;
|
||||
auto file_list = Utility::Path::list(_stagingAreaDirectory,
|
||||
ListFlag::SkipSpecial|ListFlag::SkipDirectories|ListFlag::SkipDotAndDotDot);
|
||||
auto file_list = Utility::Path::list(_stagingAreaDirectory, ListFlag::SkipSpecial|ListFlag::SkipDirectories|ListFlag::SkipDotAndDotDot);
|
||||
|
||||
if(!file_list) {
|
||||
LOG_ERROR_FORMAT("{} couldn't be opened.", _stagingAreaDirectory);
|
||||
Utility::Error{} << _stagingAreaDirectory << "couldn't be opened";
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -240,13 +223,11 @@ void MassManager::refreshStagedMass(Containers::StringView filename) {
|
|||
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;
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!Utility::Path::remove(Utility::Path::join(_stagingAreaDirectory, filename))) {
|
||||
_lastError = filename + " couldn't be deleted: " + std::strerror(errno);
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,11 +16,12 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include <Corrade/Containers/Array.h>
|
||||
#include <Corrade/Containers/Pair.h>
|
||||
#include <Corrade/Containers/StaticArray.h>
|
||||
#include <Corrade/Utility/Path.h>
|
||||
#include <Corrade/Utility/Format.h>
|
||||
|
||||
#include "PropertyNames.h"
|
||||
#include "../Logger/Logger.h"
|
||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||
#include "../UESaveFile/Types/ResourceItemValue.h"
|
||||
#include "../UESaveFile/Types/IntProperty.h"
|
||||
|
@ -34,11 +35,8 @@ using namespace Containers::Literals;
|
|||
Profile::Profile(Containers::StringView path):
|
||||
_profile(path)
|
||||
{
|
||||
LOG_INFO_FORMAT("Reading profile at {}.", path);
|
||||
|
||||
if(!_profile.valid()) {
|
||||
_lastError = _profile.lastError();
|
||||
_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -51,7 +49,7 @@ Profile::Profile(Containers::StringView path):
|
|||
_type = ProfileType::FullGame;
|
||||
}
|
||||
|
||||
auto account_prop = _profile.at<StringProperty>(PROFILE_ACCOUNT);
|
||||
auto account_prop = _profile.at<StringProperty>("Account"_s);
|
||||
if(!account_prop) {
|
||||
_lastError = "Couldn't find an account ID in "_s + _filename;
|
||||
_valid = false;
|
||||
|
@ -59,6 +57,13 @@ Profile::Profile(Containers::StringView path):
|
|||
}
|
||||
_account = account_prop->value;
|
||||
|
||||
if(_account.hasPrefix("PMCSlot"_s)) {
|
||||
_version = ProfileVersion::Normal;
|
||||
}
|
||||
else {
|
||||
_version = ProfileVersion::Legacy;
|
||||
}
|
||||
|
||||
refreshValues();
|
||||
}
|
||||
|
||||
|
@ -82,73 +87,72 @@ auto Profile::isDemo() const -> bool {
|
|||
return _type == ProfileType::Demo;
|
||||
}
|
||||
|
||||
auto Profile::version() const -> ProfileVersion {
|
||||
return _version;
|
||||
}
|
||||
|
||||
auto Profile::isLegacy() const -> bool {
|
||||
return _version == ProfileVersion::Legacy;
|
||||
}
|
||||
|
||||
auto Profile::account() const -> Containers::StringView {
|
||||
return _account;
|
||||
}
|
||||
|
||||
void Profile::refreshValues() {
|
||||
if(!_profile.reloadData()) {
|
||||
LOG_ERROR(_profile.lastError());
|
||||
_lastError = _profile.lastError();
|
||||
_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if(_profile.saveType() != "/Game/Core/Save/bpSaveGameProfile.bpSaveGameProfile_C"_s) {
|
||||
LOG_ERROR_FORMAT("{} is not a valid profile save.", _filename);
|
||||
_valid = false;
|
||||
return;
|
||||
Utility::Error{} << _filename << "is not a valid profile save.";
|
||||
}
|
||||
|
||||
LOG_INFO("Getting the company name.");
|
||||
auto name_prop = _profile.at<StringProperty>(PROFILE_NAME);
|
||||
auto name_prop = _profile.at<StringProperty>("CompanyName"_s);
|
||||
if(!name_prop) {
|
||||
_lastError = "No company name in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
_valid = false;
|
||||
return;
|
||||
}
|
||||
_name = name_prop->value;
|
||||
|
||||
LOG_INFO("Getting the active frame slot.");
|
||||
auto prop = _profile.at<IntProperty>(PROFILE_ACTIVE_FRAME_SLOT);
|
||||
auto prop = _profile.at<IntProperty>("ActiveFrameSlot"_s);
|
||||
_activeFrameSlot = prop ? prop->value : 0;
|
||||
|
||||
LOG_INFO("Getting the credits.");
|
||||
prop = _profile.at<IntProperty>(PROFILE_CREDITS);
|
||||
prop = _profile.at<IntProperty>("Credit"_s);
|
||||
_credits = prop ? prop->value : 0;
|
||||
|
||||
LOG_INFO("Getting the story progress.");
|
||||
prop = _profile.at<IntProperty>(PROFILE_STORY_PROGRESS);
|
||||
prop = _profile.at<IntProperty>("StoryProgress"_s);
|
||||
_storyProgress = prop ? prop->value : 0;
|
||||
|
||||
LOG_INFO("Getting the last mission ID.");
|
||||
prop = _profile.at<IntProperty>(PROFILE_LAST_MISSION_ID);
|
||||
prop = _profile.at<IntProperty>("LastMissionID"_s);
|
||||
_lastMissionId = prop ? prop->value : 0;
|
||||
|
||||
LOG_INFO("Getting the materials.");
|
||||
_verseSteel = getResource(PROFILE_MATERIAL, VerseSteel);
|
||||
_undinium = getResource(PROFILE_MATERIAL, Undinium);
|
||||
_necriumAlloy = getResource(PROFILE_MATERIAL, NecriumAlloy);
|
||||
_lunarite = getResource(PROFILE_MATERIAL, Lunarite);
|
||||
_asterite = getResource(PROFILE_MATERIAL, Asterite);
|
||||
_verseSteel = getResource("ResourceMaterial"_s, VerseSteel);
|
||||
_undinium = getResource("ResourceMaterial"_s, Undinium);
|
||||
_necriumAlloy = getResource("ResourceMaterial"_s, NecriumAlloy);
|
||||
_lunarite = getResource("ResourceMaterial"_s, Lunarite);
|
||||
_asterite = getResource("ResourceMaterial"_s, Asterite);
|
||||
|
||||
_ednil = getResource(PROFILE_MATERIAL, Ednil);
|
||||
_nuflalt = getResource(PROFILE_MATERIAL, Nuflalt);
|
||||
_aurelene = getResource(PROFILE_MATERIAL, Aurelene);
|
||||
_soldus = getResource(PROFILE_MATERIAL, Soldus);
|
||||
_synthesisedN = getResource(PROFILE_MATERIAL, SynthesisedN);
|
||||
_ednil = getResource("ResourceMaterial"_s, Ednil);
|
||||
_nuflalt = getResource("ResourceMaterial"_s, Nuflalt);
|
||||
_aurelene = getResource("ResourceMaterial"_s, Aurelene);
|
||||
_soldus = getResource("ResourceMaterial"_s, Soldus);
|
||||
_synthesisedN = getResource("ResourceMaterial"_s, SynthesisedN);
|
||||
|
||||
_alcarbonite = getResource(PROFILE_MATERIAL, Alcarbonite);
|
||||
_keriphene = getResource(PROFILE_MATERIAL, Keriphene);
|
||||
_nitinolCM = getResource(PROFILE_MATERIAL, NitinolCM);
|
||||
_quarkium = getResource(PROFILE_MATERIAL, Quarkium);
|
||||
_alterene = getResource(PROFILE_MATERIAL, Alterene);
|
||||
_alcarbonite = getResource("ResourceMaterial"_s, Alcarbonite);
|
||||
_keriphene = getResource("ResourceMaterial"_s, Keriphene);
|
||||
_nitinolCM = getResource("ResourceMaterial"_s, NitinolCM);
|
||||
_quarkium = getResource("ResourceMaterial"_s, Quarkium);
|
||||
_alterene = getResource("ResourceMaterial"_s, Alterene);
|
||||
|
||||
_mixedComposition = getResource(PROFILE_QUARK_DATA, MixedComposition);
|
||||
_voidResidue = getResource(PROFILE_QUARK_DATA, VoidResidue);
|
||||
_muscularConstruction = getResource(PROFILE_QUARK_DATA, MuscularConstruction);
|
||||
_mineralExoskeletology = getResource(PROFILE_QUARK_DATA, MineralExoskeletology);
|
||||
_carbonisedSkin = getResource(PROFILE_QUARK_DATA, CarbonisedSkin);
|
||||
_mixedComposition = getResource("ResourceQuarkData"_s, MixedComposition);
|
||||
_voidResidue = getResource("ResourceQuarkData"_s, VoidResidue);
|
||||
_muscularConstruction = getResource("ResourceQuarkData"_s, MuscularConstruction);
|
||||
_mineralExoskeletology = getResource("ResourceQuarkData"_s, MineralExoskeletology);
|
||||
_carbonisedSkin = getResource("ResourceQuarkData"_s, CarbonisedSkin);
|
||||
|
||||
_valid = true;
|
||||
}
|
||||
|
@ -158,10 +162,9 @@ auto Profile::companyName() const -> Containers::StringView {
|
|||
}
|
||||
|
||||
auto Profile::renameCompany(Containers::StringView new_name) -> bool {
|
||||
auto name_prop = _profile.at<StringProperty>(PROFILE_NAME);
|
||||
auto name_prop = _profile.at<StringProperty>("CompanyName"_s);
|
||||
if(!name_prop) {
|
||||
_lastError = "No company name in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
_valid = false;
|
||||
return false;
|
||||
}
|
||||
|
@ -185,12 +188,11 @@ auto Profile::credits() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setCredits(Int amount) -> bool {
|
||||
auto credits_prop = _profile.at<IntProperty>(PROFILE_CREDITS);
|
||||
auto credits_prop = _profile.at<IntProperty>("Credit"_s);
|
||||
|
||||
if(!credits_prop) {
|
||||
credits_prop = new IntProperty;
|
||||
credits_prop->name.emplace("Credit"_s);
|
||||
credits_prop->valueLength = sizeof(Int);
|
||||
_profile.appendProperty(IntProperty::ptr{credits_prop});
|
||||
}
|
||||
|
||||
|
@ -214,7 +216,6 @@ auto Profile::setStoryProgress(Int progress) -> bool {
|
|||
if(!story_progress_prop) {
|
||||
story_progress_prop = new IntProperty;
|
||||
story_progress_prop->name.emplace("StoryProgress"_s);
|
||||
story_progress_prop->valueLength = sizeof(Int);
|
||||
_profile.appendProperty(IntProperty::ptr{story_progress_prop});
|
||||
}
|
||||
|
||||
|
@ -237,7 +238,7 @@ auto Profile::verseSteel() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setVerseSteel(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, VerseSteel, amount);
|
||||
return setResource("ResourceMaterial"_s, VerseSteel, amount);
|
||||
}
|
||||
|
||||
auto Profile::undinium() const -> Int {
|
||||
|
@ -245,7 +246,7 @@ auto Profile::undinium() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setUndinium(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Undinium, amount);
|
||||
return setResource("ResourceMaterial"_s, Undinium, amount);
|
||||
}
|
||||
|
||||
auto Profile::necriumAlloy() const -> Int {
|
||||
|
@ -253,7 +254,7 @@ auto Profile::necriumAlloy() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setNecriumAlloy(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, NecriumAlloy, amount);
|
||||
return setResource("ResourceMaterial"_s, NecriumAlloy, amount);
|
||||
}
|
||||
|
||||
auto Profile::lunarite() const -> Int {
|
||||
|
@ -261,7 +262,7 @@ auto Profile::lunarite() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setLunarite(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Lunarite, amount);
|
||||
return setResource("ResourceMaterial"_s, Lunarite, amount);
|
||||
}
|
||||
|
||||
auto Profile::asterite() const -> Int {
|
||||
|
@ -269,7 +270,7 @@ auto Profile::asterite() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setAsterite(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Asterite, amount);
|
||||
return setResource("ResourceMaterial"_s, Asterite, amount);
|
||||
}
|
||||
|
||||
auto Profile::ednil() const -> Int {
|
||||
|
@ -277,7 +278,7 @@ auto Profile::ednil() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setEdnil(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Ednil, amount);
|
||||
return setResource("ResourceMaterial"_s, Ednil, amount);
|
||||
}
|
||||
|
||||
auto Profile::nuflalt() const -> Int {
|
||||
|
@ -285,7 +286,7 @@ auto Profile::nuflalt() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setNuflalt(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Nuflalt, amount);
|
||||
return setResource("ResourceMaterial"_s, Nuflalt, amount);
|
||||
}
|
||||
|
||||
auto Profile::aurelene() const -> Int {
|
||||
|
@ -293,7 +294,7 @@ auto Profile::aurelene() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setAurelene(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Aurelene, amount);
|
||||
return setResource("ResourceMaterial"_s, Aurelene, amount);
|
||||
}
|
||||
|
||||
auto Profile::soldus() const -> Int {
|
||||
|
@ -301,7 +302,7 @@ auto Profile::soldus() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setSoldus(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Soldus, amount);
|
||||
return setResource("ResourceMaterial"_s, Soldus, amount);
|
||||
}
|
||||
|
||||
auto Profile::synthesisedN() const -> Int {
|
||||
|
@ -309,7 +310,7 @@ auto Profile::synthesisedN() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setSynthesisedN(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, SynthesisedN, amount);
|
||||
return setResource("ResourceMaterial"_s, SynthesisedN, amount);
|
||||
}
|
||||
|
||||
auto Profile::alcarbonite() const -> Int {
|
||||
|
@ -317,7 +318,7 @@ auto Profile::alcarbonite() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setAlcarbonite(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Alcarbonite, amount);
|
||||
return setResource("ResourceMaterial"_s, Alcarbonite, amount);
|
||||
}
|
||||
|
||||
auto Profile::keriphene() const -> Int {
|
||||
|
@ -325,7 +326,7 @@ auto Profile::keriphene() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setKeriphene(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Keriphene, amount);
|
||||
return setResource("ResourceMaterial"_s, Keriphene, amount);
|
||||
}
|
||||
|
||||
auto Profile::nitinolCM() const -> Int {
|
||||
|
@ -333,7 +334,7 @@ auto Profile::nitinolCM() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setNitinolCM(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, NitinolCM, amount);
|
||||
return setResource("ResourceMaterial"_s, NitinolCM, amount);
|
||||
}
|
||||
|
||||
auto Profile::quarkium() const -> Int {
|
||||
|
@ -341,7 +342,7 @@ auto Profile::quarkium() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setQuarkium(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Quarkium, amount);
|
||||
return setResource("ResourceMaterial"_s, Quarkium, amount);
|
||||
}
|
||||
|
||||
auto Profile::alterene() const -> Int {
|
||||
|
@ -349,7 +350,7 @@ auto Profile::alterene() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setAlterene(Int amount) -> bool {
|
||||
return setResource(PROFILE_MATERIAL, Alterene, amount);
|
||||
return setResource("ResourceMaterial"_s, Alterene, amount);
|
||||
}
|
||||
|
||||
auto Profile::mixedComposition() const -> Int {
|
||||
|
@ -357,7 +358,7 @@ auto Profile::mixedComposition() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setMixedComposition(Int amount) -> bool {
|
||||
return setResource(PROFILE_QUARK_DATA, MixedComposition, amount);
|
||||
return setResource("ResourceQuarkData"_s, MixedComposition, amount);
|
||||
}
|
||||
|
||||
auto Profile::voidResidue() const -> Int {
|
||||
|
@ -365,7 +366,7 @@ auto Profile::voidResidue() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setVoidResidue(Int amount) -> bool {
|
||||
return setResource(PROFILE_QUARK_DATA, VoidResidue, amount);
|
||||
return setResource("ResourceQuarkData"_s, VoidResidue, amount);
|
||||
}
|
||||
|
||||
auto Profile::muscularConstruction() const -> Int {
|
||||
|
@ -373,7 +374,7 @@ auto Profile::muscularConstruction() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setMuscularConstruction(Int amount) -> bool {
|
||||
return setResource(PROFILE_QUARK_DATA, MuscularConstruction, amount);
|
||||
return setResource("ResourceQuarkData"_s, MuscularConstruction, amount);
|
||||
}
|
||||
|
||||
auto Profile::mineralExoskeletology() const -> Int {
|
||||
|
@ -381,7 +382,7 @@ auto Profile::mineralExoskeletology() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setMineralExoskeletology(Int amount) -> bool {
|
||||
return setResource(PROFILE_QUARK_DATA, MineralExoskeletology, amount);
|
||||
return setResource("ResourceQuarkData"_s, MineralExoskeletology, amount);
|
||||
}
|
||||
|
||||
auto Profile::carbonisedSkin() const -> Int {
|
||||
|
@ -389,7 +390,7 @@ auto Profile::carbonisedSkin() const -> Int {
|
|||
}
|
||||
|
||||
auto Profile::setCarbonisedSkin(Int amount) -> bool {
|
||||
return setResource(PROFILE_QUARK_DATA, CarbonisedSkin, amount);
|
||||
return setResource("ResourceQuarkData"_s, CarbonisedSkin, amount);
|
||||
}
|
||||
|
||||
auto Profile::getResource(Containers::StringView container, MaterialID id) -> Int {
|
||||
|
@ -412,9 +413,9 @@ auto Profile::setResource(Containers::StringView container, MaterialID id, Int a
|
|||
auto mats_prop = _profile.at<ArrayProperty>(container);
|
||||
|
||||
if(!mats_prop) {
|
||||
mats_prop = new ArrayProperty;
|
||||
mats_prop->name.emplace(container);
|
||||
_profile.appendProperty(ArrayProperty::ptr{mats_prop});
|
||||
_lastError = "Couldn't find "_s + container + " in "_s + _filename;
|
||||
_valid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto predicate = [&id](UnrealPropertyBase::ptr& prop){
|
||||
|
|
|
@ -33,6 +33,11 @@ enum class ProfileType : UnsignedByte {
|
|||
FullGame
|
||||
};
|
||||
|
||||
enum class ProfileVersion : UnsignedByte {
|
||||
Legacy, // pre-0.8
|
||||
Normal // 0.8 and later
|
||||
};
|
||||
|
||||
class Profile {
|
||||
public:
|
||||
explicit Profile(Containers::StringView path);
|
||||
|
@ -46,6 +51,9 @@ class Profile {
|
|||
auto type() const -> ProfileType;
|
||||
auto isDemo() const -> bool;
|
||||
|
||||
auto version() const -> ProfileVersion;
|
||||
auto isLegacy() const -> bool;
|
||||
|
||||
auto account() const -> Containers::StringView;
|
||||
|
||||
void refreshValues();
|
||||
|
@ -130,6 +138,7 @@ class Profile {
|
|||
Containers::String _filename;
|
||||
|
||||
ProfileType _type;
|
||||
ProfileVersion _version;
|
||||
|
||||
UESaveFile _profile;
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define PROFILE_NAME "CompanyName"
|
||||
#define PROFILE_ACTIVE_FRAME_SLOT "ActiveFrameSlot"
|
||||
#define PROFILE_CREDITS "Credit"
|
||||
#define PROFILE_STORY_PROGRESS "StoryProgress"
|
||||
#define PROFILE_LAST_MISSION_ID "LastMissionID"
|
||||
#define PROFILE_MATERIAL "ResourceMaterial"
|
||||
#define PROFILE_QUARK_DATA "ResourceQuarkData"
|
||||
#define PROFILE_ACCOUNT "Account"
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <regex>
|
||||
|
||||
#include <Corrade/Containers/ScopeGuard.h>
|
||||
#include <Corrade/Containers/StaticArray.h>
|
||||
|
@ -27,8 +29,6 @@
|
|||
|
||||
#include <zip.h>
|
||||
|
||||
#include "../Logger/Logger.h"
|
||||
|
||||
#include "ProfileManager.h"
|
||||
|
||||
using namespace Containers::Literals;
|
||||
|
@ -53,8 +53,6 @@ auto ProfileManager::profiles() -> Containers::ArrayView<Profile> {
|
|||
}
|
||||
|
||||
auto ProfileManager::refreshProfiles() -> bool {
|
||||
LOG_INFO("Refreshing profiles.");
|
||||
|
||||
_profiles = Containers::Array<Profile>{};
|
||||
|
||||
using Utility::Path::ListFlag;
|
||||
|
@ -63,12 +61,14 @@ auto ProfileManager::refreshProfiles() -> bool {
|
|||
|
||||
if(!files) {
|
||||
_lastError = _saveDirectory + " can't be opened.";
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto predicate = [](Containers::StringView file)->bool{
|
||||
return !((file.hasPrefix("DemoProfile") || file.hasPrefix("Profile")) && file.hasSuffix(".sav"));
|
||||
std::regex legacy_regex("(Demo)?Profile[0-9]{17}\\.sav", std::regex::nosubs);
|
||||
std::regex new_regex("(Demo)?ProfilePMCSlot[0-9]{3}\\.sav", std::regex::nosubs);
|
||||
std::cmatch m;
|
||||
return !std::regex_match(file.data(), m, legacy_regex) && !std::regex_match(file.data(), m, new_regex);
|
||||
};
|
||||
|
||||
auto files_view = files->exceptSuffix(files->end() - std::remove_if(files->begin(), files->end(), predicate));
|
||||
|
@ -77,7 +77,7 @@ auto ProfileManager::refreshProfiles() -> bool {
|
|||
Profile profile{Utility::Path::join(_saveDirectory, file)};
|
||||
|
||||
if(!profile.valid()) {
|
||||
LOG_WARNING_FORMAT("Profile {} is invalid: {}", file, profile.lastError());
|
||||
Utility::Warning{} << "Profile"_s << file << "is invalid:"_s << profile.lastError();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,6 @@ auto ProfileManager::refreshProfiles() -> bool {
|
|||
|
||||
if(_profiles.isEmpty()) {
|
||||
_lastError = "No valid profiles were found."_s;
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -102,7 +101,6 @@ auto ProfileManager::deleteProfile(std::size_t index, bool delete_builds) -> boo
|
|||
_lastError = Utility::format("Couldn't delete {} (filename: {}).",
|
||||
_profiles[index].companyName(),
|
||||
_profiles[index].filename());
|
||||
LOG_ERROR(_lastError);
|
||||
refreshProfiles();
|
||||
return false;
|
||||
}
|
||||
|
@ -131,7 +129,7 @@ auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> boo
|
|||
std::tm* time = std::localtime(×tamp);
|
||||
auto& profile = _profiles[index];
|
||||
|
||||
auto filename = Utility::format("{}_{}{:.2d}{:.2d}_{:.2d}{:.2d}{:.2d}.backup.mbst",
|
||||
auto filename = Utility::format("{}_{}{:.2d}{:.2d}_{:.2d}{:.2d}{:.2d}.mbprofbackup",
|
||||
Utility::String::replaceAll(profile.companyName().data(), " ", "_").c_str(),
|
||||
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
|
@ -142,28 +140,26 @@ auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> boo
|
|||
if(zip == nullptr) {
|
||||
zip_error_init_with_code(&error, error_code);
|
||||
_lastError = zip_error_strerror(&error);
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
zip_source_t* profile_source = zip_source_file(zip, Utility::Path::toNativeSeparators(Utility::Path::join(_saveDirectory, profile.filename())).data(), 0, 0);
|
||||
if(profile_source == nullptr) {
|
||||
_lastError = zip_strerror(zip);
|
||||
LOG_ERROR(_lastError);
|
||||
zip_source_free(profile_source);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(zip_file_add(zip, profile.filename().data(), profile_source, ZIP_FL_ENC_UTF_8) == -1) {
|
||||
_lastError = zip_strerror(zip);
|
||||
LOG_ERROR(_lastError);
|
||||
zip_source_free(profile_source);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto comment = Utility::format("{}|{}|{}-{:.2d}-{:.2d}-{:.2d}-{:.2d}-{:.2d}",
|
||||
auto comment = Utility::format("{}|{}{}|{}-{:.2d}-{:.2d}-{:.2d}-{:.2d}-{:.2d}",
|
||||
profile.companyName(),
|
||||
profile.isDemo() ? "demo"_s : "full"_s,
|
||||
profile.isLegacy() ? ""_s : "_new"_s,
|
||||
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
zip_set_archive_comment(zip, comment.data(), comment.size());
|
||||
|
@ -193,7 +189,6 @@ auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> boo
|
|||
|
||||
if(zip_close(zip) == -1) {
|
||||
_lastError = zip_strerror(zip);
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -215,12 +210,11 @@ void ProfileManager::refreshBackups() {
|
|||
|
||||
if(!files) {
|
||||
_lastError = _backupsDirectory + " can't be opened.";
|
||||
LOG_ERROR(_lastError);
|
||||
return;
|
||||
}
|
||||
|
||||
auto predicate = [](Containers::StringView file)->bool{
|
||||
return !(file.hasSuffix(".mbprofbackup"_s) || file.hasSuffix(".backup.mbst"));
|
||||
return !file.hasSuffix(".mbprofbackup"_s);
|
||||
};
|
||||
|
||||
auto files_view = files->exceptSuffix(files->end() - std::remove_if(files->begin(), files->end(), predicate));
|
||||
|
@ -258,11 +252,21 @@ void ProfileManager::refreshBackups() {
|
|||
|
||||
backup.company = info[0];
|
||||
|
||||
if(info[1].hasPrefix("full")) {
|
||||
if(info[1] == "full") {
|
||||
backup.type = ProfileType::FullGame;
|
||||
backup.version = ProfileVersion::Legacy;
|
||||
}
|
||||
else if(info[1].hasPrefix("demo")) {
|
||||
else if(info[1] == "demo") {
|
||||
backup.type = ProfileType::Demo;
|
||||
backup.version = ProfileVersion::Legacy;
|
||||
}
|
||||
else if(info[1] == "full_new") {
|
||||
backup.type = ProfileType::FullGame;
|
||||
backup.version = ProfileVersion::Normal;
|
||||
}
|
||||
else if(info[1] == "demo_new") {
|
||||
backup.type = ProfileType::Demo;
|
||||
backup.version = ProfileVersion::Normal;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
|
@ -293,7 +297,6 @@ void ProfileManager::refreshBackups() {
|
|||
auto ProfileManager::deleteBackup(std::size_t index) -> bool {
|
||||
if(!Utility::Path::remove(Utility::Path::join(_backupsDirectory, _backups[index].filename))) {
|
||||
_lastError = "Couldn't delete " + _backups[index].filename;
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -320,7 +323,6 @@ auto ProfileManager::restoreBackup(std::size_t index) -> bool {
|
|||
zip_error_t error;
|
||||
zip_error_init_with_code(&error, error_code);
|
||||
_lastError = zip_error_strerror(&error);
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -330,7 +332,6 @@ auto ProfileManager::restoreBackup(std::size_t index) -> bool {
|
|||
FILE* out = std::fopen(Utility::Path::join(_saveDirectory, file).data(), "wb");
|
||||
if(out == nullptr) {
|
||||
_lastError = Utility::format(error_format.data(), file, std::strerror(errno));
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -339,7 +340,6 @@ auto ProfileManager::restoreBackup(std::size_t index) -> bool {
|
|||
zip_file_t* zf = zip_fopen(zip, file.data(), ZIP_FL_ENC_GUESS);
|
||||
if(zf == nullptr) {
|
||||
_lastError = Utility::format(error_format.data(), file, zip_strerror(zip));
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -351,14 +351,12 @@ auto ProfileManager::restoreBackup(std::size_t index) -> bool {
|
|||
while((bytes_read = zip_fread(zf, buf.data(), buf.size())) > 0) {
|
||||
if(std::fwrite(buf.data(), sizeof(char), bytes_read, out) < static_cast<std::size_t>(bytes_read)) {
|
||||
_lastError = Utility::format(error_format.data(), file, "not enough bytes written.");
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(bytes_read == -1) {
|
||||
_lastError = Utility::format(error_format.data(), file, "couldn't read bytes from archive.");
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ struct Backup {
|
|||
Containers::String filename;
|
||||
Containers::String company;
|
||||
ProfileType type;
|
||||
ProfileVersion version;
|
||||
struct {
|
||||
int year;
|
||||
int month;
|
||||
|
|
|
@ -14,12 +14,10 @@
|
|||
// 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 <Corrade/Utility/Format.h>
|
||||
#include <Corrade/Utility/String.h>
|
||||
#include <Corrade/Utility/Unicode.h>
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_messagebox.h>
|
||||
|
||||
#include <fileapi.h>
|
||||
#include <handleapi.h>
|
||||
|
@ -100,11 +98,7 @@ void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
|||
if(is_current_profile) {
|
||||
_currentProfile = nullptr;
|
||||
_uiState = UiState::ProfileManager;
|
||||
if(!_profileManager->refreshProfiles()) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_profileManager->lastError().data(), window());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
_profileManager->refreshProfiles();
|
||||
}
|
||||
else if(is_unit) {
|
||||
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
|
||||
|
|
|
@ -52,8 +52,7 @@ void SaveTool::drawProfileManager() {
|
|||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::SmallButton("Refresh")) {
|
||||
if(!_profileManager->refreshProfiles()) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_profileManager->lastError().data(), window());
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error in ProfileManager", _profileManager->lastError().data(), window());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +95,9 @@ void SaveTool::drawProfileManager() {
|
|||
}
|
||||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::TextUnformatted(profile.isDemo() ? "Demo" : "Full");
|
||||
ImGui::Text("%s%s",
|
||||
profile.isDemo() ? "Demo" : "Full",
|
||||
profile.isLegacy() ? " (legacy)" : "");
|
||||
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
if(ImGui::SmallButton(ICON_FA_FILE_ARCHIVE)) {
|
||||
|
@ -160,11 +161,7 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
|||
if(!_profileManager->restoreBackup(backup_index)) {
|
||||
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
||||
}
|
||||
if(!_profileManager->refreshProfiles()) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_profileManager->lastError().data(), window());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
_profileManager->refreshProfiles();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
@ -281,7 +278,9 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
|||
backup.timestamp.second);
|
||||
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
ImGui::TextUnformatted(backup.type == ProfileType::Demo ? "Demo" : "Full");
|
||||
ImGui::Text("%s%s",
|
||||
backup.type == ProfileType::Demo ? "Demo" : "Full",
|
||||
backup.version == ProfileVersion::Legacy ? " (legacy)" : "");
|
||||
|
||||
ImGui::TableSetColumnIndex(3);
|
||||
ImGui::PushID(i);
|
||||
|
@ -341,18 +340,12 @@ auto SaveTool::drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID {
|
|||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::Button("Yes")) {
|
||||
if(!_profileManager->backupProfile(profile_index, true)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_profileManager->lastError().data(), window());
|
||||
}
|
||||
_profileManager->backupProfile(profile_index, true);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("No", ImGui::GetItemRectSize())) {
|
||||
if(!_profileManager->backupProfile(profile_index, false)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_profileManager->lastError().data(), window());
|
||||
}
|
||||
_profileManager->backupProfile(profile_index, false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
|
Loading…
Reference in a new issue