MassBuilderSaveTool/src/Profile/Profile.cpp

436 lines
12 KiB
C++

// 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 <https://www.gnu.org/licenses/>.
#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 "../UESaveFile/Types/ArrayProperty.h"
#include "../UESaveFile/Types/ResourceItemValue.h"
#include "../UESaveFile/Types/IntProperty.h"
#include "../UESaveFile/Types/StringProperty.h"
#include "Profile.h"
using namespace Corrade;
using namespace Containers::Literals;
Profile::Profile(Containers::StringView path):
_profile(path)
{
if(!_profile.valid()) {
_lastError = _profile.lastError();
return;
}
_filename = Utility::Path::split(path).second();
if(_filename.hasPrefix("Demo"_s)) {
_type = ProfileType::Demo;
}
else {
_type = ProfileType::FullGame;
}
auto account_prop = _profile.at<StringProperty>("Account"_s);
if(!account_prop) {
_lastError = "Couldn't find an account ID in "_s + _filename;
_valid = false;
return;
}
_account = account_prop->value;
if(_account.hasPrefix("PMCSlot"_s)) {
_version = ProfileVersion::Normal;
}
else {
_version = ProfileVersion::Legacy;
}
refreshValues();
}
auto Profile::valid() const -> bool {
return _valid;
}
auto Profile::lastError() const -> Containers::StringView {
return _lastError;
}
auto Profile::filename() const -> Containers::StringView {
return _filename;
}
auto Profile::type() const -> ProfileType {
return _type;
}
auto Profile::version() const -> ProfileVersion {
return _version;
}
auto Profile::account() const -> Containers::StringView {
return _account;
}
void Profile::refreshValues() {
if(!_profile.reloadData()) {
_lastError = _profile.lastError();
_valid = false;
return;
}
auto name_prop = _profile.at<StringProperty>("CompanyName"_s);
if(!name_prop) {
_lastError = "No company name in "_s + _filename;
_valid = false;
return;
}
_name = name_prop->value;
auto prop = _profile.at<IntProperty>("ActiveFrameSlot"_s);
_activeFrameSlot = prop ? prop->value : 0;
prop = _profile.at<IntProperty>("Credit"_s);
_credits = prop ? prop->value : 0;
prop = _profile.at<IntProperty>("StoryProgress"_s);
_storyProgress = prop ? prop->value : 0;
prop = _profile.at<IntProperty>("LastMissionID"_s);
_lastMissionId = prop ? prop->value : 0;
_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("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("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("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;
}
auto Profile::companyName() const -> Containers::StringView {
return _name;
}
auto Profile::renameCompany(Containers::StringView new_name) -> bool {
auto name_prop = _profile.at<StringProperty>("CompanyName"_s);
if(!name_prop) {
_lastError = "No company name in "_s + _filename;
_valid = false;
return false;
}
name_prop->value = new_name;
if(!_profile.saveToFile()) {
_lastError = _profile.lastError();
return false;
}
return true;
}
auto Profile::activeFrameSlot() const -> Int {
return _activeFrameSlot;
}
auto Profile::credits() const -> Int {
return _credits;
}
auto Profile::setCredits(Int amount) -> bool {
auto credits_prop = _profile.at<IntProperty>("Credit"_s);
if(!credits_prop) {
credits_prop = new IntProperty;
credits_prop->name.emplace("Credit"_s);
_profile.appendProperty(IntProperty::ptr{credits_prop});
}
credits_prop->value = amount;
if(!_profile.saveToFile()) {
_lastError = _profile.lastError();
return false;
}
return true;
}
auto Profile::storyProgress() const -> Int {
return _storyProgress;
}
auto Profile::setStoryProgress(Int progress) -> bool {
auto story_progress_prop = _profile.at<IntProperty>("StoryProgress"_s);
if(!story_progress_prop) {
story_progress_prop = new IntProperty;
story_progress_prop->name.emplace("StoryProgress"_s);
_profile.appendProperty(IntProperty::ptr{story_progress_prop});
}
story_progress_prop->value = progress;
if(!_profile.saveToFile()) {
_lastError = _profile.lastError();
return false;
}
return true;
}
auto Profile::lastMissionId() const -> Int {
return _lastMissionId;
}
auto Profile::verseSteel() const -> Int {
return _verseSteel;
}
auto Profile::setVerseSteel(Int amount) -> bool {
return setResource("ResourceMaterial"_s, VerseSteel, amount);
}
auto Profile::undinium() const -> Int {
return _undinium;
}
auto Profile::setUndinium(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Undinium, amount);
}
auto Profile::necriumAlloy() const -> Int {
return _necriumAlloy;
}
auto Profile::setNecriumAlloy(Int amount) -> bool {
return setResource("ResourceMaterial"_s, NecriumAlloy, amount);
}
auto Profile::lunarite() const -> Int {
return _lunarite;
}
auto Profile::setLunarite(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Lunarite, amount);
}
auto Profile::asterite() const -> Int {
return _asterite;
}
auto Profile::setAsterite(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Asterite, amount);
}
auto Profile::ednil() const -> Int {
return _ednil;
}
auto Profile::setEdnil(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Ednil, amount);
}
auto Profile::nuflalt() const -> Int {
return _nuflalt;
}
auto Profile::setNuflalt(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Nuflalt, amount);
}
auto Profile::aurelene() const -> Int {
return _aurelene;
}
auto Profile::setAurelene(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Aurelene, amount);
}
auto Profile::soldus() const -> Int {
return _soldus;
}
auto Profile::setSoldus(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Soldus, amount);
}
auto Profile::synthesisedN() const -> Int {
return _synthesisedN;
}
auto Profile::setSynthesisedN(Int amount) -> bool {
return setResource("ResourceMaterial"_s, SynthesisedN, amount);
}
auto Profile::alcarbonite() const -> Int {
return _alcarbonite;
}
auto Profile::setAlcarbonite(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Alcarbonite, amount);
}
auto Profile::keriphene() const -> Int {
return _keriphene;
}
auto Profile::setKeriphene(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Keriphene, amount);
}
auto Profile::nitinolCM() const -> Int {
return _nitinolCM;
}
auto Profile::setNitinolCM(Int amount) -> bool {
return setResource("ResourceMaterial"_s, NitinolCM, amount);
}
auto Profile::quarkium() const -> Int {
return _quarkium;
}
auto Profile::setQuarkium(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Quarkium, amount);
}
auto Profile::alterene() const -> Int {
return _alterene;
}
auto Profile::setAlterene(Int amount) -> bool {
return setResource("ResourceMaterial"_s, Alterene, amount);
}
auto Profile::mixedComposition() const -> Int {
return _mixedComposition;
}
auto Profile::setMixedComposition(Int amount) -> bool {
return setResource("ResourceQuarkData"_s, MixedComposition, amount);
}
auto Profile::voidResidue() const -> Int {
return _voidResidue;
}
auto Profile::setVoidResidue(Int amount) -> bool {
return setResource("ResourceQuarkData"_s, VoidResidue, amount);
}
auto Profile::muscularConstruction() const -> Int {
return _muscularConstruction;
}
auto Profile::setMuscularConstruction(Int amount) -> bool {
return setResource("ResourceQuarkData"_s, MuscularConstruction, amount);
}
auto Profile::mineralExoskeletology() const -> Int {
return _mineralExoskeletology;
}
auto Profile::setMineralExoskeletology(Int amount) -> bool {
return setResource("ResourceQuarkData"_s, MineralExoskeletology, amount);
}
auto Profile::carbonisedSkin() const -> Int {
return _carbonisedSkin;
}
auto Profile::setCarbonisedSkin(Int amount) -> bool {
return setResource("ResourceQuarkData"_s, CarbonisedSkin, amount);
}
auto Profile::getResource(Containers::StringView container, MaterialID id) -> Int {
auto mats_prop = _profile.at<ArrayProperty>(container);
if(!mats_prop) {
return 0;
}
auto predicate = [&id](UnrealPropertyBase::ptr& prop){
auto res_prop = static_cast<ResourceItemValue*>(prop.get());
return res_prop->id == id;
};
auto it = std::find_if(mats_prop->items.begin(), mats_prop->items.end(), predicate);
return it != mats_prop->items.end() ? static_cast<ResourceItemValue*>(it->get())->quantity : 0;
}
auto Profile::setResource(Containers::StringView container, MaterialID id, Int amount) -> bool {
auto mats_prop = _profile.at<ArrayProperty>(container);
if(!mats_prop) {
_lastError = "Couldn't find "_s + container + " in "_s + _filename;
_valid = false;
return false;
}
auto predicate = [&id](UnrealPropertyBase::ptr& prop){
auto res_prop = static_cast<ResourceItemValue*>(prop.get());
return res_prop->id == id;
};
auto it = std::find_if(mats_prop->items.begin(), mats_prop->items.end(), predicate);
ResourceItemValue* res_prop;
if(it == mats_prop->items.end()) {
res_prop = new ResourceItemValue;
res_prop->id = id;
ResourceItemValue::ptr prop{res_prop};
arrayAppend(mats_prop->items, std::move(prop));
}
else {
res_prop = static_cast<ResourceItemValue*>(it->get());
}
res_prop->quantity = amount;
if(!_profile.saveToFile()) {
_lastError = _profile.lastError();
return false;
}
return true;
}