From c2d0fbd9413aba69798eaa4939af9a691012f31c Mon Sep 17 00:00:00 2001 From: William JCM Date: Mon, 27 Sep 2021 17:52:47 +0200 Subject: [PATCH] Mass: adapt to UESaveFile. --- src/CMakeLists.txt | 1 - src/Mass/Locators.h | 31 --- src/Mass/Mass.cpp | 525 +++++++++++++++++++++++++++----------------- src/Mass/Mass.h | 134 ++++++++++- 4 files changed, 443 insertions(+), 248 deletions(-) delete mode 100644 src/Mass/Locators.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9add043..ddee28b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -124,7 +124,6 @@ add_executable(MassBuilderSaveTool WIN32 Profile/ResourceIDs.h MassManager/MassManager.h MassManager/MassManager.cpp - Mass/Locators.h Mass/Mass.h Mass/Mass.cpp Maps/LastMissionId.h diff --git a/src/Mass/Locators.h b/src/Mass/Locators.h deleted file mode 100644 index 9eadd48..0000000 --- a/src/Mass/Locators.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -// MassBuilderSaveTool -// Copyright (C) 2021 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 . - -constexpr char mass_name_locator[] = "Name_45_A037C5D54E53456407BDF091344529BB\0\f\0\0\0StrProperty"; -constexpr char steamid_locator[] = "Account\0\f\0\0\0StrProperty"; - -constexpr char neck_slider_locator[] = "NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58\0\x0e\0\0\0FloatProperty"; -constexpr char body_slider_locator[] = "BodyLength_7_C16287754CBA96C93BAE36A5C154996A\0\x0e\0\0\0FloatProperty"; -constexpr char shoulders_slider_locator[] = "ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883\0\x0e\0\0\0FloatProperty"; -constexpr char hips_slider_locator[] = "HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818\0\x0e\0\0\0FloatProperty"; -constexpr char uarms_slider_locator[] = "ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE\0\x0e\0\0\0FloatProperty"; -constexpr char larms_slider_locator[] = "ArmLowerLength_12_ACD0F02745C28882619376926292FB36\0\x0e\0\0\0FloatProperty"; -constexpr char ulegs_slider_locator[] = "LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61\0\x0e\0\0\0FloatProperty"; -constexpr char llegs_slider_locator[] = "LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F\0\x0e\0\0\0FloatProperty"; - -constexpr char frame_styles_locator[] = "Styles_32_00A3B3284B37F1E7819458844A20EB48\0\x0e\0\0\0ArrayProperty\0\x14\0\0\0\0\0\0\0\f\0\0\0IntProperty\0\0\x04\0\0\0"; diff --git a/src/Mass/Mass.cpp b/src/Mass/Mass.cpp index 263dd5d..58309e1 100644 --- a/src/Mass/Mass.cpp +++ b/src/Mass/Mass.cpp @@ -21,7 +21,12 @@ #include #include -#include "Locators.h" +#include "../UESaveFile/Types/ArrayProperty.h" +#include "../UESaveFile/Types/ColourStructProperty.h" +#include "../UESaveFile/Types/FloatProperty.h" +#include "../UESaveFile/Types/GenericStructProperty.h" +#include "../UESaveFile/Types/IntProperty.h" +#include "../UESaveFile/Types/StringProperty.h" #include "Mass.h" @@ -38,256 +43,362 @@ auto Mass::lastError() -> std::string const& { return _lastError; } -auto Mass::getNameFromFile(const std::string& path) -> std::string { +auto Mass::getNameFromFile(const std::string& path) -> Containers::Optional { if(!Utility::Directory::exists(path)) { _lastError = path + " couldn't be found."; - return ""; + return Containers::NullOpt; } - std::string name; + UESaveFile mass{path}; - auto mmap = Utility::Directory::mapRead(path); - - auto iter = std::search(mmap.begin(), mmap.end(), &mass_name_locator[0], &mass_name_locator[56]); - - if(iter != mmap.end()) { - name = std::string{iter + 70}; - } - else { - _lastError = "The name couldn't be found in " + path; + if(!mass.valid()) { + _lastError = "The unit file seems to be corrupt."; + return Containers::NullOpt; } - return name; + auto unit_data = mass.at("UnitData"); + + if(!unit_data) { + _lastError = "Couldn't find unit data in the file."; + return Containers::NullOpt; + } + + auto name_prop = unit_data->at("Name_45_A037C5D54E53456407BDF091344529BB"); + + if(!name_prop) { + _lastError = "Couldn't find the name in the file."; + return Containers::NullOpt; + } + + return name_prop->value; } void Mass::refreshValues() { - getName(); - - if(_state != State::Valid) { + if(!Utility::Directory::exists(Utility::Directory::join(_folder, _filename))) { + _state = State::Empty; return; } - getFrameStyles(); - getJointSliders(); + if(!_mass) { + _mass.emplace(Utility::Directory::join(_folder, _filename)); + if(!_mass->valid()) { + _state = State::Invalid; + return; + } + } + else { + if(!_mass->reloadData()) { + _state = State::Invalid; + return; + } + } + + auto unit_data = _mass->at("UnitData"); + + if(!unit_data) { + _state = State::Invalid; + return; + } + + auto name_prop = unit_data->at("Name_45_A037C5D54E53456407BDF091344529BB"); + + if(!name_prop) { + _name = Containers::NullOpt; + _state = State::Invalid; + return; + } + + _name = name_prop->value; + + { + auto frame_prop = unit_data->at("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"); + + if(!frame_prop) { + _state = State::Invalid; + return; + } + + auto length = frame_prop->at("NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"); + _frame.joints.neck = (length ? length->value : 0.0f); + length = frame_prop->at("BodyLength_7_C16287754CBA96C93BAE36A5C154996A"); + _frame.joints.body = (length ? length->value : 0.0f); + length = frame_prop->at("ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"); + _frame.joints.shoulders = (length ? length->value : 0.0f); + length = frame_prop->at("HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"); + _frame.joints.hips = (length ? length->value : 0.0f); + length = frame_prop->at("ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"); + _frame.joints.upperArms = (length ? length->value : 0.0f); + length = frame_prop->at("ArmLowerLength_12_ACD0F02745C28882619376926292FB36"); + _frame.joints.lowerArms = (length ? length->value : 0.0f); + length = frame_prop->at("LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"); + _frame.joints.upperLegs = (length ? length->value : 0.0f); + length = frame_prop->at("LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"); + _frame.joints.lowerLegs = (length ? length->value : 0.0f); + + auto frame_styles = frame_prop->at("Styles_32_00A3B3284B37F1E7819458844A20EB48"); + + if(!frame_styles) { + _state = State::Invalid; + return; + } + + for(UnsignedInt i = 0; i < 4; i++) { + _frame.styles[i] = frame_styles->at(i)->value; + } + + auto eye_flare_prop = frame_prop->at("EyeFlareColor_36_AF79999C40FCA0E88A2F9A84488A38CA"); + if(!eye_flare_prop) { + _state = State::Invalid; + return; + } + + _frame.eyeFlare = Color4{eye_flare_prop->r, eye_flare_prop->g, eye_flare_prop->b, eye_flare_prop->a}; + } + + auto account_prop = _mass->at("Account"); + if(!account_prop) { + _state = State::Invalid; + return; + } + + _steamId = account_prop->value; + + _state = State::Valid; } auto Mass::filename() -> std::string const&{ return _filename; } -auto Mass::name() -> std::string const&{ +auto Mass::name() -> Containers::Optional const& { return _name; } +auto Mass::setName(std::string new_name) -> bool { + _name = new_name; + + auto unit_data = _mass->at("UnitData"); + + if(!unit_data) { + _state = State::Invalid; + return false; + } + + auto name_prop = unit_data->at("Name_45_A037C5D54E53456407BDF091344529BB"); + + if(!name_prop) { + _state = State::Invalid; + return false; + } + + name_prop->value = std::move(new_name); + + return _mass->saveToFile(); +} + auto Mass::state() -> State { return _state; } -auto Mass::jointSliders() -> Joints const& { - return _sliders; +auto Mass::dirty() const -> bool { + return _dirty; +} + +void Mass::setDirty(bool dirty) { + _dirty = dirty; +} + +auto Mass::jointSliders() const -> Joints const& { + return _frame.joints; +} + +auto Mass::setSliders(Joints joints) -> bool { + _frame.joints = joints; + + auto unit_data = _mass->at("UnitData"); + + if(!unit_data) { + _state = State::Invalid; + return false; + } + + auto frame_prop = unit_data->at("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"); + + if(!frame_prop) { + _state = State::Invalid; + return false; + } + + auto length = frame_prop->at("NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"); + if(!length && _frame.joints.neck != 0.0f) { + length = new FloatProperty; + auto length_prop = FloatProperty::ptr{length}; + length_prop->name.emplace("NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"); + arrayAppend(frame_prop->properties, std::move(length_prop)); + } + if(length) { + length->value = _frame.joints.neck; + } + + length = frame_prop->at("BodyLength_7_C16287754CBA96C93BAE36A5C154996A"); + if(!length && _frame.joints.body != 0.0f) { + length = new FloatProperty; + auto length_prop = FloatProperty::ptr{length}; + length_prop->name.emplace("BodyLength_7_C16287754CBA96C93BAE36A5C154996A"); + arrayAppend(frame_prop->properties, std::move(length_prop)); + } + if(length) { + length->value = _frame.joints.body; + } + + length = frame_prop->at("ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"); + if(!length && _frame.joints.shoulders != 0.0f) { + length = new FloatProperty; + auto length_prop = FloatProperty::ptr{length}; + length_prop->name.emplace("ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"); + arrayAppend(frame_prop->properties, std::move(length_prop)); + } + if(length) { + length->value = _frame.joints.shoulders; + } + + length = frame_prop->at("HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"); + if(!length && _frame.joints.hips != 0.0f) { + length = new FloatProperty; + auto length_prop = FloatProperty::ptr{length}; + length_prop->name.emplace("HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"); + arrayAppend(frame_prop->properties, std::move(length_prop)); + } + if(length) { + length->value = _frame.joints.hips; + } + + length = frame_prop->at("ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"); + if(!length && _frame.joints.upperArms != 0.0f) { + length = new FloatProperty; + auto length_prop = FloatProperty::ptr{length}; + length_prop->name.emplace("ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"); + arrayAppend(frame_prop->properties, std::move(length_prop)); + } + if(length) { + length->value = _frame.joints.upperArms; + } + + length = frame_prop->at("ArmLowerLength_12_ACD0F02745C28882619376926292FB36"); + if(!length && _frame.joints.lowerArms != 0.0f) { + length = new FloatProperty; + auto length_prop = FloatProperty::ptr{length}; + length_prop->name.emplace("ArmLowerLength_12_ACD0F02745C28882619376926292FB36"); + arrayAppend(frame_prop->properties, std::move(length_prop)); + } + if(length) { + length->value = _frame.joints.lowerArms; + } + + length = frame_prop->at("LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"); + if(!length && _frame.joints.upperLegs != 0.0f) { + length = new FloatProperty; + auto length_prop = FloatProperty::ptr{length}; + length_prop->name.emplace("LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"); + arrayAppend(frame_prop->properties, std::move(length_prop)); + } + if(length) { + length->value = _frame.joints.upperLegs; + } + + length = frame_prop->at("LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"); + if(!length && _frame.joints.lowerLegs != 0.0f) { + length = new FloatProperty; + auto length_prop = FloatProperty::ptr{length}; + length_prop->name.emplace("LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"); + arrayAppend(frame_prop->properties, std::move(length_prop)); + } + if(length) { + length->value = _frame.joints.lowerLegs; + } + + return _mass->saveToFile(); } auto Mass::frameStyles() -> Containers::StaticArrayView<4, Int> { - return _frameStyles; + return _frame.styles; } auto Mass::setFrameStyle(Int index, Int style_id) -> bool { - if(index < 0 || index > 3) { - _lastError = "Index is out of range in Mass::setFrameStyle()."; - return false; - } + _frame.styles[index] = style_id; - std::string path = Utility::Directory::join(_folder, _filename); - - if(!Utility::Directory::exists(path)) { - _lastError = path + " couldn't be found."; - _state = State::Empty; - return false; - } - - auto mmap = Utility::Directory::map(path); - - auto iter = std::search(mmap.begin(), mmap.end(), &frame_styles_locator[0], &frame_styles_locator[90]); - - if(iter != mmap.end()) { - iter += 0x5A; - *(reinterpret_cast(iter) + index) = style_id; - } - else { - _lastError = "Frame styles couldn't be found in " + path; + auto unit_data = _mass->at("UnitData"); + if(!unit_data) { _state = State::Invalid; return false; } - return true; + auto frame = unit_data->at("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"); + if(!frame) { + _state = State::Invalid; + return false; + } + + auto frame_styles = frame->at("Styles_32_00A3B3284B37F1E7819458844A20EB48"); + if(!frame_styles) { + _state = State::Invalid; + return false; + } + + frame_styles->at(index)->value = style_id; + + return _mass->saveToFile(); +} + +auto Mass::eyeFlareColour() const -> const Color4& { + return _frame.eyeFlare; +} + +auto Mass::setEyeFlareColour(Color4 new_colour) -> bool { + _frame.eyeFlare = new_colour; + + auto unit_data = _mass->at("UnitData"); + if(!unit_data) { + _state = State::Invalid; + return false; + } + + auto frame = unit_data->at("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"); + if(!frame) { + _state = State::Invalid; + return false; + } + + auto eye_flare_prop = frame->at("EyeFlareColor_36_AF79999C40FCA0E88A2F9A84488A38CA"); + if(!eye_flare_prop) { + _state = State::Invalid; + return false; + } + + eye_flare_prop->r = new_colour.r(); + eye_flare_prop->g = new_colour.g(); + eye_flare_prop->b = new_colour.b(); + eye_flare_prop->a = new_colour.a(); + + return _mass->saveToFile(); } auto Mass::updateSteamId(const std::string& steam_id) -> bool { - std::string path = Utility::Directory::join(_folder, _filename); + _steamId = steam_id; - if(!Utility::Directory::exists(path)) { - _lastError = path + " couldn't be found."; - _state = State::Empty; + auto unit_data = _mass->at("UnitData"); + if(!unit_data) { + _state = State::Invalid; return false; } - Utility::Directory::copy(path, path + ".tmp"); - - { - auto mmap = Utility::Directory::map(path + ".tmp"); - - auto iter = std::search(mmap.begin(), mmap.end(), &steamid_locator[0], &steamid_locator[23]); - - if(iter == mmap.end()) { - _lastError = "The M.A.S.S. file at " + path + " seems to be corrupt."; - Utility::Directory::rm(path + ".tmp"); - return false; - } - - iter += 37; - - if(std::strncmp(iter, steam_id.c_str(), steam_id.length()) != 0) { - for(int i = 0; i < 17; ++i) { - *(iter + i) = steam_id[i]; - } - } - } - - if(Utility::Directory::exists(path)) { - Utility::Directory::rm(path); - } - - Utility::Directory::move(path + ".tmp", path); - - return true; -} - -void Mass::getName() { - std::string path = Utility::Directory::join(_folder, _filename); - - if(!Utility::Directory::exists(path)) { - _lastError = path + " couldn't be found."; - _state = State::Empty; - return; - } - - auto mmap = Utility::Directory::mapRead(path); - - auto iter = std::search(mmap.begin(), mmap.end(), &mass_name_locator[0], &mass_name_locator[56]); - - if(iter != mmap.end()) { - _name = std::string{iter + 70}; - _state = State::Valid; - } - else { - _lastError = "The name couldn't be found in " + _filename; - _state = State::Invalid; - } -} - -void Mass::getJointSliders() { - std::string path = Utility::Directory::join(_folder, _filename); - - if(!Utility::Directory::exists(path)) { - _lastError = path + " couldn't be found."; - _state = State::Empty; - return; - } - - auto mmap = Utility::Directory::mapRead(path); - - auto iter = std::search(mmap.begin(), mmap.end(), &neck_slider_locator[0], &neck_slider_locator[63]); - - if(iter != mmap.end()) { - _sliders.neck = *reinterpret_cast(iter + 0x49); - } - else { - _sliders.neck = 0.0f; - } - - iter = std::search(mmap.begin(), mmap.end(), &body_slider_locator[0], &body_slider_locator[63]); - - if(iter != mmap.end()) { - _sliders.body = *reinterpret_cast(iter + 0x49); - } - else { - _sliders.body = 0.0f; - } - - iter = std::search(mmap.begin(), mmap.end(), &shoulders_slider_locator[0], &shoulders_slider_locator[67]); - - if(iter != mmap.end()) { - _sliders.shoulders = *reinterpret_cast(iter + 0x4D); - } - else { - _sliders.shoulders = 0.0f; - } - - iter = std::search(mmap.begin(), mmap.end(), &hips_slider_locator[0], &hips_slider_locator[63]); - - if(iter != mmap.end()) { - _sliders.hips = *reinterpret_cast(iter + 0x49); - } - else { - _sliders.hips = 0.0f; - } - - iter = std::search(mmap.begin(), mmap.end(), &uarms_slider_locator[0], &uarms_slider_locator[68]); - - if(iter != mmap.end()) { - _sliders.upperArms = *reinterpret_cast(iter + 0x4E); - } - else { - _sliders.upperArms = 0.0f; - } - - iter = std::search(mmap.begin(), mmap.end(), &larms_slider_locator[0], &larms_slider_locator[68]); - - if(iter != mmap.end()) { - _sliders.lowerArms = *reinterpret_cast(iter + 0x4E); - } - else { - _sliders.lowerArms = 0.0f; - } - - iter = std::search(mmap.begin(), mmap.end(), &ulegs_slider_locator[0], &ulegs_slider_locator[68]); - - if(iter != mmap.end()) { - _sliders.upperLegs = *reinterpret_cast(iter + 0x4E); - } - else { - _sliders.upperLegs = 0.0f; - } - - iter = std::search(mmap.begin(), mmap.end(), &llegs_slider_locator[0], &llegs_slider_locator[68]); - - if(iter != mmap.end()) { - _sliders.lowerLegs = *reinterpret_cast(iter + 0x4E); - } - else { - _sliders.lowerLegs = 0.0f; - } -} - -void Mass::getFrameStyles() { - std::string path = Utility::Directory::join(_folder, _filename); - - if(!Utility::Directory::exists(path)) { - _lastError = path + " couldn't be found."; - _state = State::Empty; - return; - } - - auto mmap = Utility::Directory::mapRead(path); - - auto iter = std::search(mmap.begin(), mmap.end(), &frame_styles_locator[0], &frame_styles_locator[90]); - - if(iter != mmap.end()) { - iter += 0x5A; - std::copy(reinterpret_cast(iter), reinterpret_cast(iter) + 4, _frameStyles.data()); - } - else { - _lastError = "Frame styles couldn't be found in " + path; + auto account_prop = unit_data->at("Account"); + if(!account_prop) { _state = State::Invalid; + return false; } + + account_prop->value = steam_id; + + return _mass->saveToFile(); } diff --git a/src/Mass/Mass.h b/src/Mass/Mass.h index 747941a..5bfe2b1 100644 --- a/src/Mass/Mass.h +++ b/src/Mass/Mass.h @@ -18,9 +18,16 @@ #include +#include +#include #include #include +#include +#include +#include + +#include "../UESaveFile/UESaveFile.h" using namespace Corrade; using namespace Magnum; @@ -36,6 +43,70 @@ struct Joints { Float lowerLegs = 0.0f; }; +struct CustomStyle { + std::string name; + Color4 colour{0.0f}; + Float metallic = 0.0f; + Float gloss = 0.0f; + + Int patternId = 0; + Float opacity = 0.0f; + Float offsetX = 0.0f; + Float rotation = 0.0f; + Float scale = 0.0f; +}; + +struct Decal { + Int id = -1; + Color4 colour{0.0f}; + Vector3 position{0.0f}; + Vector3 uAxis{0.0f}; + Vector3 vAxis{0.0f}; + Vector2 offset{0.5f}; + Float scale = 0.5f; + Float rotation = 0.0f; + bool flip = false; + bool wrap = false; +}; + +struct Accessory { + Int attachIndex = -1; + Int id = -1; + Containers::StaticArray<2, Int> styles{ValueInit}; + Vector3 relativePosition{0.0f}; + Vector3 relativePositionOffset{0.0f}; + Vector3 relativeRotation{0.0f}; + Vector3 relativeRotationOffset{0.0f}; + Vector3 localScale{1.0f}; +}; + +struct Armour { + std::string slot; + Int id = 0; + Containers::StaticArray<4, Int> styles{ValueInit}; + Containers::StaticArray<8, Decal> decals{ValueInit}; + Containers::StaticArray<8, Accessory> accessories{ValueInit}; +}; + +struct WeaponPart { + Int id = 0; + Containers::StaticArray<4, Int> styles{ValueInit}; + Containers::StaticArray<8, Decal> decals{ValueInit}; + Containers::StaticArray<8, Accessory> accessories{ValueInit}; +}; + +struct Weapon { + std::string name; + std::string type; + Containers::Array parts; + Containers::StaticArray<16, CustomStyle> customStyles{ValueInit}; + bool attached = false; + std::string damageType; + bool dualWield = false; + std::string effectColourMode; + Color4 effectColour{0.0f}; +}; + class Mass { public: enum class State : UnsignedByte { @@ -52,36 +123,81 @@ class Mass { static auto lastError() -> std::string const&; - static auto getNameFromFile(const std::string& path) -> std::string; + static auto getNameFromFile(const std::string& path) -> Containers::Optional; void refreshValues(); auto filename() -> std::string const&; - auto name() -> std::string const&; + auto name() -> Containers::Optional const&; + auto setName(std::string new_name) -> bool; auto state() -> State; - auto jointSliders() -> Joints const&; + auto dirty() const -> bool; + void setDirty(bool dirty = true); + + auto jointSliders() const -> Joints const&; + auto setSliders(Joints joints) -> bool; auto frameStyles() -> Containers::StaticArrayView<4, Int>; auto setFrameStyle(Int index, Int style_id) -> bool; + auto eyeFlareColour() const -> Color4 const&; + auto setEyeFlareColour(Color4 new_colour) -> bool; + auto updateSteamId(const std::string& steam_id) -> bool; private: - void getName(); - void getJointSliders(); - void getFrameStyles(); + Containers::Optional _mass; static std::string _lastError; std::string _folder; std::string _filename; - std::string _name; State _state = State::Empty; - Joints _sliders; + bool _dirty = false; - Containers::StaticArray<4, Int> _frameStyles; + Containers::Optional _name = Containers::NullOpt; + + struct { + Joints joints{}; + + Containers::StaticArray<4, Int> styles{ValueInit}; + + Color4 eyeFlare{0.0f}; + + Containers::StaticArray<16, CustomStyle> frameCustomStyles; + } _frame; + + struct { + Containers::StaticArray<38, Armour> parts; + + Containers::StaticArray<16, CustomStyle> armourCustomStyles; + } _armour; + + struct { + Containers::StaticArray<8, Weapon> meleeWeapons; + Containers::StaticArray<1, Weapon> shields; + Containers::StaticArray<4, Weapon> bulletShooters; + Containers::StaticArray<4, Weapon> energyShooters; + Containers::StaticArray<4, Weapon> bulletLaunchers; + Containers::StaticArray<4, Weapon> energyLaunchers; + } _weapons; + + Containers::StaticArray<16, CustomStyle> _globalStyles; + + struct { + Int engineId; + Containers::StaticArray<7, Int> gearIds; + + Int osId; + Containers::StaticArray<7, Int> moduleIds; + + Int archId; + Containers::StaticArray<7, Int> techIds; + } _tuning; + + std::string _steamId; };