// 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 "../UESaveFile/Types/ArrayProperty.h" #include "../UESaveFile/Types/BoolProperty.h" #include "../UESaveFile/Types/ByteProperty.h" #include "../UESaveFile/Types/ColourStructProperty.h" #include "../UESaveFile/Types/FloatProperty.h" #include "../UESaveFile/Types/GenericStructProperty.h" #include "../UESaveFile/Types/IntProperty.h" #include "../UESaveFile/Types/RotatorStructProperty.h" #include "../UESaveFile/Types/StringProperty.h" #include "../UESaveFile/Types/VectorStructProperty.h" #include "../UESaveFile/Types/Vector2DStructProperty.h" #include "Mass.h" Mass::Mass(const std::string& path) { _folder = Utility::Directory::path(path); _filename = Utility::Directory::filename(path); refreshValues(); } auto Mass::lastError() -> std::string const& { return _lastError; } auto Mass::getNameFromFile(const std::string& path) -> Containers::Optional { if(!Utility::Directory::exists(path)) { Utility::Error{} << path.c_str() << "couldn't be found."; return Containers::NullOpt; } UESaveFile mass{path}; if(!mass.valid()) { Utility::Error{} << "The unit file seems to be corrupt."; return Containers::NullOpt; } auto unit_data = mass.at("UnitData"); if(!unit_data) { Utility::Error{} << "Couldn't find unit data in the file."; return Containers::NullOpt; } auto name_prop = unit_data->at("Name_45_A037C5D54E53456407BDF091344529BB"); if(!name_prop) { Utility::Error{} << "Couldn't find the name in the file."; return Containers::NullOpt; } return name_prop->value; } void Mass::refreshValues() { if(!Utility::Directory::exists(Utility::Directory::join(_folder, _filename))) { _state = State::Empty; return; } 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; getJointSliders(); if(_state == State::Invalid) { return; } getFrameStyles(); if(_state == State::Invalid) { return; } getEyeFlareColour(); if(_state == State::Invalid) { return; } getFrameCustomStyles(); if(_state == State::Invalid) { return; } getArmourParts(); if(_state == State::Invalid) { return; } getArmourCustomStyles(); if(_state == State::Invalid) { return; } getMeleeWeapons(); if(_state == State::Invalid) { return; } getShields(); if(_state == State::Invalid) { return; } getBulletShooters(); if(_state == State::Invalid) { return; } getEnergyShooters(); if(_state == State::Invalid) { return; } getBulletLaunchers(); if(_state == State::Invalid) { return; } getEnergyLaunchers(); if(_state == State::Invalid) { return; } getGlobalStyles(); if(_state == State::Invalid) { return; } getTuning(); if(_state == State::Invalid) { return; } auto account_prop = _mass->at("Account"); if(!account_prop) { _state = State::Invalid; return; } _account = account_prop->value; _state = State::Valid; } auto Mass::filename() -> std::string const&{ return _filename; } 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::dirty() const -> bool { return _dirty; } void Mass::setDirty(bool dirty) { _dirty = dirty; } auto Mass::jointSliders() -> Joints& { return _frame.joints; } void Mass::getJointSliders() { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return; } 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 Mass::writeJointSliders() -> bool { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; _lastError = "No unit data in " + _filename; return false; } auto frame_prop = unit_data->at("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"); if(!frame_prop) { _state = State::Invalid; _lastError = "No frame data in " + _filename; return false; } Containers::Array temp; auto length = frame_prop->atMove("NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"); if(_frame.joints.neck != 0.0f) { if(!length) { length.emplace(); length->name.emplace("NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"); } length->value = _frame.joints.neck; arrayAppend(temp, std::move(length)); } length = frame_prop->atMove("BodyLength_7_C16287754CBA96C93BAE36A5C154996A"); if(_frame.joints.body != 0.0f) { if(!length) { length.emplace(); length->name.emplace("BodyLength_7_C16287754CBA96C93BAE36A5C154996A"); } length->value = _frame.joints.body; arrayAppend(temp, std::move(length)); } length = frame_prop->atMove("ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"); if(_frame.joints.shoulders != 0.0f) { if(!length) { length.emplace(); length->name.emplace("ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"); } length->value = _frame.joints.shoulders; arrayAppend(temp, std::move(length)); } length = frame_prop->atMove("ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"); if(_frame.joints.upperArms != 0.0f) { if(!length) { length.emplace(); length->name.emplace("ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"); } length->value = _frame.joints.upperArms; arrayAppend(temp, std::move(length)); } length = frame_prop->atMove("ArmLowerLength_12_ACD0F02745C28882619376926292FB36"); if(_frame.joints.lowerArms != 0.0f) { if(!length) { length.emplace(); length->name.emplace("ArmLowerLength_12_ACD0F02745C28882619376926292FB36"); } length->value = _frame.joints.lowerArms; arrayAppend(temp, std::move(length)); } length = frame_prop->atMove("HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"); if(_frame.joints.hips != 0.0f) { if(!length) { length.emplace(); length->name.emplace("HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"); } length->value = _frame.joints.hips; arrayAppend(temp, std::move(length)); } length = frame_prop->atMove("LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"); if(_frame.joints.upperLegs != 0.0f) { if(!length) { length.emplace(); length->name.emplace("LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"); } length->value = _frame.joints.upperLegs; arrayAppend(temp, std::move(length)); } length = frame_prop->atMove("LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"); if(_frame.joints.lowerLegs != 0.0f) { if(!length) { length.emplace(); length->name.emplace("LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"); } length->value = _frame.joints.lowerLegs; arrayAppend(temp, std::move(length)); } arrayAppend(temp, std::move(frame_prop->properties[frame_prop->properties.size() - 3])); arrayAppend(temp, std::move(frame_prop->properties[frame_prop->properties.size() - 2])); arrayAppend(temp, std::move(frame_prop->properties[frame_prop->properties.size() - 1])); frame_prop->properties = std::move(temp); if(!_mass->saveToFile()) { _lastError = _mass->lastError(); return false; } return true; } auto Mass::frameStyles() -> Containers::ArrayView { return _frame.styles; } void Mass::getFrameStyles() { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return; } auto frame_prop = unit_data->at("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"); if(!frame_prop) { _state = State::Invalid; return; } auto frame_styles = frame_prop->at("Styles_32_00A3B3284B37F1E7819458844A20EB48"); if(!frame_styles) { _state = State::Invalid; return; } if(frame_styles->items.size() != _frame.styles.size()) { _state = State::Invalid; return; } for(UnsignedInt i = 0; i < frame_styles->items.size(); i++) { _frame.styles[i] = frame_styles->at(i)->value; } } auto Mass::writeFrameStyles() -> bool { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; _lastError = "No unit data in " + _filename; return false; } auto frame = unit_data->at("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"); if(!frame) { _state = State::Invalid; _lastError = "No frame data in " + _filename; return false; } auto frame_styles = frame->at("Styles_32_00A3B3284B37F1E7819458844A20EB48"); if(!frame_styles) { _state = State::Invalid; _lastError = "No frame styles in " + _filename; return false; } for(UnsignedInt i = 0; i < frame_styles->items.size(); i++) { frame_styles->at(i)->value = _frame.styles[i]; } if(!_mass->saveToFile()) { _lastError = _mass->lastError(); return false; } return true; } auto Mass::eyeFlareColour() -> Color4& { return _frame.eyeFlare; } void Mass::getEyeFlareColour() { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return; } auto frame_prop = unit_data->at("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"); if(!frame_prop) { _state = State::Invalid; return; } 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 Mass::writeEyeFlareColour() -> bool { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; _lastError = "No unit data in " + _filename; return false; } auto frame = unit_data->at("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"); if(!frame) { _state = State::Invalid; _lastError = "No frame data in " + _filename; return false; } auto eye_flare_prop = frame->at("EyeFlareColor_36_AF79999C40FCA0E88A2F9A84488A38CA"); if(!eye_flare_prop) { _state = State::Invalid; _lastError = "No eye flare property in " + _filename; return false; } eye_flare_prop->r = _frame.eyeFlare.r(); eye_flare_prop->g = _frame.eyeFlare.g(); eye_flare_prop->b = _frame.eyeFlare.b(); eye_flare_prop->a = _frame.eyeFlare.a(); if(!_mass->saveToFile()) { _lastError = _mass->lastError(); return false; } return true; } auto Mass::frameCustomStyles() -> Containers::ArrayView { return _frame.customStyles; } void Mass::getFrameCustomStyles() { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return; } auto frame_styles = unit_data->at("FrameStyle_44_04A44C9440363CCEC5443D98BFAF22AA"); if(!frame_styles) { _state = State::Invalid; return; } if(frame_styles->items.size() != _frame.customStyles.size()) { _state = State::Invalid; return; } getCustomStyles(_frame.customStyles, frame_styles); } auto Mass::writeFrameCustomStyle(UnsignedLong index) -> bool { if(index > _frame.customStyles.size()) { _lastError = "Style index out of range."; return false; } auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; _lastError = "No unit data in " + _filename; return false; } auto frame_styles = unit_data->at("FrameStyle_44_04A44C9440363CCEC5443D98BFAF22AA"); if(!frame_styles) { _state = State::Invalid; _lastError = "No frame styles in " + _filename; return false; } return setCustomStyle(_frame.customStyles[index], index, frame_styles); } auto Mass::armourParts() -> Containers::ArrayView { return _armour.parts; } void Mass::getArmourParts() { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return; } auto armour_array = unit_data->at("Armor_10_12E266C44116DDAF57E99ABB575A4B3C"); if(!armour_array) { _state = State::Invalid; return; } if(armour_array->items.size() != _armour.parts.size()) { _state = State::Invalid; return; } for(UnsignedInt i = 0; i < armour_array->items.size(); i++) { auto part_prop = armour_array->at(i); auto& part = _armour.parts[i]; auto& armour_slot = part_prop->at("Slot_3_408BA56F4C9605C7E805CF91B642249C")->enumValue; #define c(enumerator, strenum, name) if(armour_slot == (strenum)) { part.slot = ArmourSlot::enumerator; } else #include "../Maps/ArmourSlots.hpp" #undef c { _state = State::Invalid; Utility::Warning{} << "Invalid armour slot enum value in getArmourParts()."; } part.id = part_prop->at("ID_5_ACD101864D3481DE96EDACACC09BDD25")->value; auto part_styles = part_prop->at("Styles_47_3E31870441DFD7DB8BEE5C85C26B365B"); if(!part_styles) { _state = State::Invalid; return; } if(part_styles->items.size() != part.styles.size()) { _state = State::Invalid; return; } for(UnsignedInt j = 0; j < part_styles->items.size(); j++) { part.styles[j] = part_styles->at(j)->value; } auto decals_array = part_prop->at("Decals_42_F358794A4F18497970F56BA9627D3603"); if(!decals_array) { _state = State::Invalid; return; } part.decals = Containers::Array{decals_array->items.size()}; getDecals(part.decals, decals_array); auto accs_array = part_prop->at("Accessories_52_D902DD4241FA0050C2529596255153F3"); if(!accs_array) { part.accessories = Containers::Array{}; continue; } if(part.accessories.size() != accs_array->items.size()) { part.accessories = Containers::Array{accs_array->items.size()}; } getAccessories(part.accessories, accs_array); } } auto Mass::writeArmourPart(ArmourSlot slot) -> bool { auto& part = *std::find_if(_armour.parts.begin(), _armour.parts.end(), [&slot](const ArmourPart& part){ return slot == part.slot; }); auto unit_data = _mass->at("UnitData"); auto armour_array = unit_data->at("Armor_10_12E266C44116DDAF57E99ABB575A4B3C"); const char* slot_str = nullptr; switch(slot) { #define c(enumerator, strenum, name) case ArmourSlot::enumerator: \ slot_str = strenum; \ break; #include "../Maps/ArmourSlots.hpp" #undef c } GenericStructProperty* part_prop = nullptr; for(UnsignedInt i = 0; i < armour_array->items.size(); i++) { part_prop = armour_array->at(i); if(slot_str != part_prop->at("Slot_3_408BA56F4C9605C7E805CF91B642249C")->value) { part_prop = nullptr; } } if(!part_prop) { _lastError = "Couldn't find the armour part for slot "; switch(slot) { #define c(enumerator, strenum, name) case ArmourSlot::enumerator: \ _lastError += "ArmourSlot::" #enumerator "."; \ break; #include "../Maps/ArmourSlots.hpp" #undef c } return false; } part_prop->at("ID_5_ACD101864D3481DE96EDACACC09BDD25")->value = part.id; auto part_styles = part_prop->at("Styles_47_3E31870441DFD7DB8BEE5C85C26B365B"); for(UnsignedInt i = 0; i < part.styles.size(); i++) { part_styles->at(i)->value = part.styles[i]; } auto decals_array = part_prop->at("Decals_42_F358794A4F18497970F56BA9627D3603"); writeDecals(part.decals, decals_array); if(part.accessories.size() != 0) { auto accs_array = part_prop->at("Accessories_52_D902DD4241FA0050C2529596255153F3"); writeAccessories(part.accessories, accs_array); } if(!_mass->saveToFile()) { _lastError = _mass->lastError(); return false; } return true; } auto Mass::armourCustomStyles() -> Containers::ArrayView { return _armour.customStyles; } void Mass::getArmourCustomStyles() { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return; } auto armour_styles = unit_data->at("ArmorStyle_42_E2F6AC3647788CB366BD469B3B7E899E"); if(!armour_styles) { _state = State::Invalid; return; } if(armour_styles->items.size() != _armour.customStyles.size()) { _state = State::Invalid; return; } getCustomStyles(_armour.customStyles, armour_styles); } auto Mass::writeArmourCustomStyle(UnsignedLong index) -> bool { if(index > _armour.customStyles.size()) { _lastError = "Style index out of range."; return false; } auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; _lastError = "Couldn't find unit data in " + _filename; return false; } auto armour_styles = unit_data->at("ArmorStyle_42_E2F6AC3647788CB366BD469B3B7E899E"); if(!armour_styles) { _lastError = "Couldn't find armour custom styles in " + _filename; _state = State::Invalid; return false; } return setCustomStyle(_armour.customStyles[index], index, armour_styles); } auto Mass::meleeWeapons() -> Containers::ArrayView { return _weapons.melee; } void Mass::getMeleeWeapons() { getWeaponType("WeaponCC_22_0BBEC58C4A0EA1DB9E037B9339EE26A7", _weapons.melee); } auto Mass::writeMeleeWeapons() -> bool { return writeWeaponType("WeaponCC_22_0BBEC58C4A0EA1DB9E037B9339EE26A7", _weapons.melee); } auto Mass::shields() -> Containers::ArrayView { return _weapons.shields; } void Mass::getShields() { getWeaponType("Shield_53_839BFD7945481BAEA3E43A9C5CA8E92E", _weapons.shields); } auto Mass::writeShields() -> bool { return writeWeaponType("Shield_53_839BFD7945481BAEA3E43A9C5CA8E92E", _weapons.shields); } auto Mass::bulletShooters() -> Containers::ArrayView { return _weapons.bulletShooters; } void Mass::getBulletShooters() { getWeaponType("WeaponBS_35_6EF6E0104FD7A138DF47F88CB57A83ED", _weapons.bulletShooters); } auto Mass::writeBulletShooters() -> bool { return writeWeaponType("WeaponBS_35_6EF6E0104FD7A138DF47F88CB57A83ED", _weapons.bulletShooters); } auto Mass::energyShooters() -> Containers::ArrayView { return _weapons.energyShooters; } void Mass::getEnergyShooters() { getWeaponType("WeaponES_37_1A295D544528623880A0B1AC2C7DEE99", _weapons.energyShooters); } auto Mass::writeEnergyShooters() -> bool { return writeWeaponType("WeaponES_37_1A295D544528623880A0B1AC2C7DEE99", _weapons.energyShooters); } auto Mass::bulletLaunchers() -> Containers::ArrayView { return _weapons.bulletLaunchers; } void Mass::getBulletLaunchers() { getWeaponType("WeaponBL_36_5FD7C41E4613A75B44AB0E90B362846E", _weapons.bulletLaunchers); } auto Mass::writeBulletLaunchers() -> bool { return writeWeaponType("WeaponBL_36_5FD7C41E4613A75B44AB0E90B362846E", _weapons.bulletLaunchers); } auto Mass::energyLaunchers() -> Containers::ArrayView { return _weapons.energyLaunchers; } void Mass::getEnergyLaunchers() { getWeaponType("WeaponEL_38_9D23F3884ACA15902C9E6CA6E4995995", _weapons.energyLaunchers); } auto Mass::writeEnergyLaunchers() -> bool { return writeWeaponType("WeaponEL_38_9D23F3884ACA15902C9E6CA6E4995995", _weapons.energyLaunchers); } auto Mass::globalStyles() -> Containers::ArrayView { return _globalStyles; } void Mass::getGlobalStyles() { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return; } auto global_styles = unit_data->at("GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B"); if(!global_styles) { _globalStyles = Containers::Array{0}; return; } if(global_styles->items.size() != _globalStyles.size()) { _globalStyles = Containers::Array{global_styles->items.size()}; } getCustomStyles(_globalStyles, global_styles); } auto Mass::writeGlobalStyle(UnsignedLong index) -> bool { if(index > _globalStyles.size()) { _lastError = "Global style index out of range"; return false; } auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; _lastError = "No unit data found in " + _filename; return false; } auto global_styles = unit_data->at("GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B"); if(!global_styles) { _state = State::Invalid; _lastError = "No global styles found in " + _filename; return false; } return setCustomStyle(_globalStyles[index], index, global_styles); } void Mass::getTuning() { getTuningCategory("Engine", _tuning.engineId, "Gears", _tuning.gearIds); if(_state == State::Invalid) { return; } getTuningCategory("OS", _tuning.osId, "Modules", _tuning.moduleIds); if(_state == State::Invalid) { return; } getTuningCategory("Architect", _tuning.archId, "Techs", _tuning.techIds); if(_state == State::Invalid) { return; } } auto Mass::engine() -> Int& { return _tuning.engineId; } auto Mass::gears() -> Containers::ArrayView { return _tuning.gearIds; } auto Mass::os() -> Int& { return _tuning.osId; } auto Mass::modules() -> Containers::ArrayView { return _tuning.moduleIds; } auto Mass::architecture() -> Int& { return _tuning.archId; } auto Mass::techs() -> Containers::ArrayView { return _tuning.techIds; } auto Mass::account() -> const std::string& { return _account; } auto Mass::updateAccount(const std::string& new_account) -> bool { _account = new_account; auto account = _mass->at("Account"); if(!account) { _state = State::Invalid; _lastError = "Couldn't find the account property."; return false; } account->value = new_account; if(!_mass->saveToFile()) { _lastError = _mass->lastError(); return false; } return true; } void Mass::getCustomStyles(Containers::ArrayView styles, ArrayProperty* style_array) { for(UnsignedInt i = 0; i < style_array->items.size(); i++) { auto style_prop = style_array->at(i); auto& style = styles[i]; style.name = style_prop->at("Name_27_1532115A46EF2B2FA283908DF561A86B")->value; auto colour_prop = style_prop->at("Color_5_F0D383DF40474C9464AE48A0984A212E"); style.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a}; style.metallic = style_prop->at("Metallic_10_0A4CD1E4482CBF41CA61D0A856DE90B9")->value; style.gloss = style_prop->at("Gloss_11_9769599842CC275A401C4282A236E240")->value; style.glow = colour_prop->a == 0.0f ? false : true; style.patternId = style_prop->at("PatternID_14_516DB85641DAF8ECFD2920BE2BDF1311")->value; style.opacity = style_prop->at("Opacity_30_53BD060B4DFCA1C92302D6A0F7831131")->value; style.offset = Vector2{ style_prop->at("OffsetX_23_70FC2E814C64BBB82452748D2AF9CD48")->value, style_prop->at("OffsetY_24_5E1F866C4C054D9B2EE337ADC180C17F")->value }; style.rotation = style_prop->at("Rotation_25_EC2DFAD84AD0A6BD3FA841ACD52EDD6D")->value; style.scale = style_prop->at("Scale_26_19DF0708409262183E1247B317137671")->value; } } auto Mass::setCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool { if(!style_array) { _lastError = "Mass::setCustomStyle(): style_array is null."; return false; } auto style_prop = style_array->at(index); if(!style_prop) { _lastError = "Style index is out of range in " + _filename; return false; } style_prop->at("Name_27_1532115A46EF2B2FA283908DF561A86B")->value = style.name; auto colour_prop = style_prop->at("Color_5_F0D383DF40474C9464AE48A0984A212E"); colour_prop->r = style.colour.r(); colour_prop->g = style.colour.g(); colour_prop->b = style.colour.b(); colour_prop->a = style.glow ? 1.0f : 0.0f; style_prop->at("Metallic_10_0A4CD1E4482CBF41CA61D0A856DE90B9")->value = style.metallic; style_prop->at("Gloss_11_9769599842CC275A401C4282A236E240")->value = style.gloss; style_prop->at("PatternID_14_516DB85641DAF8ECFD2920BE2BDF1311")->value = style.patternId; style_prop->at("Opacity_30_53BD060B4DFCA1C92302D6A0F7831131")->value = style.opacity; style_prop->at("OffsetX_23_70FC2E814C64BBB82452748D2AF9CD48")->value = style.offset.x(); style_prop->at("OffsetY_24_5E1F866C4C054D9B2EE337ADC180C17F")->value = style.offset.y(); style_prop->at("Rotation_25_EC2DFAD84AD0A6BD3FA841ACD52EDD6D")->value = style.rotation; style_prop->at("Scale_26_19DF0708409262183E1247B317137671")->value = style.scale; if(!_mass->saveToFile()) { _lastError = _mass->lastError(); return false; } return true; } void Mass::getDecals(Containers::ArrayView decals, ArrayProperty* decal_array) { for(UnsignedInt i = 0; i < decal_array->items.size(); i++) { auto decal_prop = decal_array->at(i); auto& decal = decals[i]; decal.id = decal_prop->at("ID_3_694C0B35404D8A3168AEC89026BC8CF9")->value; auto colour_prop = decal_prop->at("Color_8_1B0B9D2B43DA6AAB9FA549B374D3E606"); decal.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a}; auto pos_prop = decal_prop->at("Position_41_022C8FE84E1AAFE587261E88F2C72250"); decal.position = Vector3{pos_prop->x, pos_prop->y, pos_prop->z}; auto u_prop = decal_prop->at("UAxis_37_EBEB715F45491AECACCC07A1AE4646D1"); decal.uAxis = Vector3{u_prop->x, u_prop->y, u_prop->z}; auto v_prop = decal_prop->at("VAxis_39_C31EB2664EE202CAECFBBB84100B5E35"); decal.vAxis = Vector3{v_prop->x, v_prop->y, v_prop->z}; auto offset_prop = decal_prop->at("Offset_29_B02BBBB74FC60F5EDBEBAB8020738020"); decal.offset = Vector2{offset_prop->x, offset_prop->y}; decal.scale = decal_prop->at("Scale_32_959D1C2747AFD8D62808468235CBBA40")->value; decal.rotation = decal_prop->at("Rotation_27_12D7C314493D203D5C2326A03C5F910F")->value; decal.flip = decal_prop->at("Flip_35_CECCFB184CCD9412BD93FE9A8B656BE1")->value; decal.wrap = decal_prop->at("Wrap_43_A7C68CDF4A92AF2ECDA53F953EE7CA62")->value; } } void Mass::writeDecals(Containers::ArrayView decals, ArrayProperty* decal_array) { for(UnsignedInt i = 0; i < decal_array->items.size(); i++) { auto decal_prop = decal_array->at(i); auto& decal = decals[i]; decal_prop->at("ID_3_694C0B35404D8A3168AEC89026BC8CF9")->value = decal.id; auto colour_prop = decal_prop->at("Color_8_1B0B9D2B43DA6AAB9FA549B374D3E606"); colour_prop->r = decal.colour.r(); colour_prop->g = decal.colour.g(); colour_prop->b = decal.colour.b(); colour_prop->a = decal.colour.a(); auto pos_prop = decal_prop->at("Position_41_022C8FE84E1AAFE587261E88F2C72250"); pos_prop->x = decal.position.x(); pos_prop->y = decal.position.y(); pos_prop->z = decal.position.z(); auto u_prop = decal_prop->at("UAxis_37_EBEB715F45491AECACCC07A1AE4646D1"); u_prop->x = decal.uAxis.x(); u_prop->y = decal.uAxis.y(); u_prop->z = decal.uAxis.z(); auto v_prop = decal_prop->at("VAxis_39_C31EB2664EE202CAECFBBB84100B5E35"); v_prop->x = decal.vAxis.x(); v_prop->y = decal.vAxis.y(); v_prop->z = decal.vAxis.z(); auto offset_prop = decal_prop->at("Offset_29_B02BBBB74FC60F5EDBEBAB8020738020"); offset_prop->x = decal.offset.x(); offset_prop->y = decal.offset.y(); decal_prop->at("Scale_32_959D1C2747AFD8D62808468235CBBA40")->value = decal.scale; decal_prop->at("Rotation_27_12D7C314493D203D5C2326A03C5F910F")->value = decal.rotation; decal_prop->at("Flip_35_CECCFB184CCD9412BD93FE9A8B656BE1")->value = decal.flip; decal_prop->at("Wrap_43_A7C68CDF4A92AF2ECDA53F953EE7CA62")->value = decal.wrap; } } void Mass::getAccessories(Containers::ArrayView accessories, ArrayProperty* accessory_array) { for(UnsignedInt i = 0; i < accessory_array->items.size(); i++) { auto acc_prop = accessory_array->at(i); auto& accessory = accessories[i]; accessory.attachIndex = acc_prop->at("AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20")->value; accessory.id = acc_prop->at("ID_4_5757B32647BAE263266259B8A7DFFFC1")->value; auto acc_styles = acc_prop->at("Styles_7_91DEB0F24E24D13FC9472882C11D0DFD"); for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) { accessory.styles[j] = acc_styles->at(j)->value; } auto rel_pos_prop = acc_prop->at("RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1"); accessory.relativePosition = Vector3{rel_pos_prop->x, rel_pos_prop->y, rel_pos_prop->z}; auto rel_pos_offset_prop = acc_prop->at("RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6"); accessory.relativePositionOffset = Vector3{rel_pos_offset_prop->x, rel_pos_offset_prop->y, rel_pos_offset_prop->z}; auto rel_rot_prop = acc_prop->at("RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0"); accessory.relativeRotation = Vector3{rel_rot_prop->x, rel_rot_prop->y, rel_rot_prop->z}; auto rel_rot_offset_prop = acc_prop->at("RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA"); accessory.relativeRotationOffset = Vector3{rel_rot_offset_prop->x, rel_rot_offset_prop->y, rel_rot_offset_prop->z}; auto local_scale_prop = acc_prop->at("LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53"); accessory.localScale = Vector3{local_scale_prop->x, local_scale_prop->y, local_scale_prop->z}; } } void Mass::writeAccessories(Containers::ArrayView accessories, ArrayProperty* accs_array) { for(UnsignedInt i = 0; i < accs_array->items.size(); i++) { auto acc_prop = accs_array->at(i); auto& accessory = accessories[i]; acc_prop->at("AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20")->value = accessory.attachIndex; acc_prop->at("ID_4_5757B32647BAE263266259B8A7DFFFC1")->value = accessory.id; auto acc_styles = acc_prop->at("Styles_7_91DEB0F24E24D13FC9472882C11D0DFD"); for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) { acc_styles->at(j)->value = accessory.styles[j]; } auto rel_pos_prop = acc_prop->at("RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1"); rel_pos_prop->x = accessory.relativePosition.x(); rel_pos_prop->y = accessory.relativePosition.y(); rel_pos_prop->z = accessory.relativePosition.z(); auto rel_pos_offset_prop = acc_prop->at("RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6"); rel_pos_offset_prop->x = accessory.relativePositionOffset.x(); rel_pos_offset_prop->y = accessory.relativePositionOffset.y(); rel_pos_offset_prop->z = accessory.relativePositionOffset.z(); auto rel_rot_prop = acc_prop->at("RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0"); rel_rot_prop->x = accessory.relativeRotation.x(); rel_rot_prop->y = accessory.relativeRotation.y(); rel_rot_prop->z = accessory.relativeRotation.z(); auto rel_rot_offset_prop = acc_prop->at("RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA"); rel_rot_offset_prop->x = accessory.relativeRotationOffset.x(); rel_rot_offset_prop->y = accessory.relativeRotationOffset.y(); rel_rot_offset_prop->z = accessory.relativeRotationOffset.z(); auto local_scale_prop = acc_prop->at("LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53"); local_scale_prop->x = accessory.localScale.x(); local_scale_prop->y = accessory.localScale.y(); local_scale_prop->z = accessory.localScale.z(); } } void Mass::getWeaponType(const char* prop_name, Containers::ArrayView weapon_array) { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return; } auto prop = unit_data->at(prop_name); if(!prop) { _state = State::Invalid; return; } if(prop->items.size() != weapon_array.size()) { _state = State::Invalid; return; } for(UnsignedInt i = 0; i < weapon_array.size(); i++) { auto weapon_prop = prop->at(i); auto& weapon = weapon_array[i]; weapon.name = weapon_prop->at("Name_13_7BF0D31F4E50C50C47231BB36A485D92")->value; auto& weapon_type = weapon_prop->at("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976")->enumValue; #define c(enumerator, strenum, name) if(weapon_type == (strenum)) { weapon.type = WeaponType::enumerator; } else #include "../Maps/WeaponTypes.hpp" #undef c { _state = State::Invalid; Utility::Warning{} << "Invalid weapon type enum value in getWeaponType()."; } auto parts_prop = weapon_prop->at("Element_6_8E4617CC4B2C1F1490435599784EC6E0"); weapon.parts = Containers::Array{ValueInit, parts_prop->items.size()}; for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) { auto part_prop = parts_prop->at(j); auto& part = weapon.parts[j]; part.id = part_prop->at("ID_2_A74D75434308158E5926178822DD28EE")->value; auto part_styles = part_prop->at("Styles_17_994C97C34A90667BE5B716BFD0B97588"); for(UnsignedInt k = 0; k < part_styles->items.size(); k++) { part.styles[k] = part_styles->at(k)->value; } auto part_decals = part_prop->at("Decals_13_8B81112B453D7230C0CDE982185E14F1"); if(part_decals->items.size() != part.decals.size()) { part.decals = Containers::Array{part_decals->items.size()}; } getDecals(part.decals, part_decals); auto part_accs = part_prop->at("Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C"); if(!part_accs) { part.accessories = Containers::Array{0}; continue; } if(part_accs->items.size() != part.accessories.size()) { part.accessories = Containers::Array{part_accs->items.size()}; } getAccessories(part.accessories, part_accs); } auto custom_styles = weapon_prop->at("Styles_10_8C3C82444B986AD7A99595AD4985912D"); if(!custom_styles) { _state = State::Invalid; return; } if(custom_styles->items.size() != weapon.customStyles.size()) { _state = State::Invalid; return; } getCustomStyles(weapon.customStyles, custom_styles); weapon.attached = weapon_prop->at("Attach_15_D00AABBD4AD6A04778D56D81E51927B3")->value; auto& damage_type = weapon_prop->at("DamageType_18_E1FFA53540591A9087EC698117A65C83")->enumValue; #define c(enumerator, strenum) if(damage_type == (strenum)) { weapon.damageType = DamageType::enumerator; } else #include "../Maps/DamageTypes.hpp" #undef c { _state = State::Invalid; Utility::Warning{} << "Invalid damage type enum value in getWeaponType()."; } weapon.dualWield = weapon_prop->at("DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222")->value; auto& effect_colour_mode = weapon_prop->at("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014")->enumValue; #define c(enumerator, strenum) if(effect_colour_mode == (strenum)) { weapon.effectColourMode = EffectColourMode::enumerator; } else #include "../Maps/EffectColourModes.hpp" #undef c { _state = State::Invalid; Utility::Warning{} << "Invalid effect colour mode in getWeaponType()."; } auto effect_colour = weapon_prop->at("ColorEfx_26_D921B62946C493E487455A831F4520AC"); weapon.effectColour = Color4{effect_colour->r, effect_colour->g, effect_colour->b, effect_colour->a}; } } auto Mass::writeWeaponType(const char* prop_name, Containers::ArrayView weapon_array) -> bool { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; _lastError = "No unit data in " + _filename; return false; } auto prop = unit_data->at(prop_name); if(!prop) { _state = State::Invalid; _lastError = std::string{prop_name} + " not found in " + _filename; return false; } if(prop->items.size() != weapon_array.size()) { _state = State::Invalid; _lastError = "Weapon type array size mismatch."; return false; } for(UnsignedInt i = 0; i < weapon_array.size(); i++) { auto weapon_prop = prop->at(i); auto& weapon = weapon_array[i]; weapon_prop->at("Name_13_7BF0D31F4E50C50C47231BB36A485D92")->value = weapon.name; switch(weapon.type) { #define c(enumerator, strenum, name) case WeaponType::enumerator: weapon_prop->at("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976")->enumValue = strenum; break; #include "../Maps/WeaponTypes.hpp" #undef c default: Utility::Warning{} << "Invalid weapon type enum value in writeWeaponType()."; } auto parts_prop = weapon_prop->at("Element_6_8E4617CC4B2C1F1490435599784EC6E0"); if(parts_prop->items.size() != weapon.parts.size()) { _state = State::Invalid; _lastError = "Weapon parts array size mismatch."; return false; } for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) { auto part_prop = parts_prop->at(j); auto& part = weapon.parts[j]; part_prop->at("ID_2_A74D75434308158E5926178822DD28EE")->value = part.id; auto part_styles = part_prop->at("Styles_17_994C97C34A90667BE5B716BFD0B97588"); for(UnsignedInt k = 0; k < part_styles->items.size(); k++) { part_styles->at(k)->value = part.styles[k]; } auto part_decals = part_prop->at("Decals_13_8B81112B453D7230C0CDE982185E14F1"); writeDecals(part.decals, part_decals); auto part_accs = part_prop->at("Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C"); if(!part_accs) { continue; } if(part_accs->items.size() != part.accessories.size()) { _state = State::Invalid; _lastError = "Accessories array size mismatch."; return false; } writeAccessories(part.accessories, part_accs); } auto custom_styles = weapon_prop->at("Styles_10_8C3C82444B986AD7A99595AD4985912D"); if(!custom_styles) { _state = State::Invalid; _lastError = "No custom styles found for weapon."; return false; } if(custom_styles->items.size() != weapon.customStyles.size()) { _state = State::Invalid; _lastError = "Custom styles array size mismatch."; return false; } for(UnsignedInt j = 0; j < weapon.customStyles.size(); j++) { setCustomStyle(weapon.customStyles[j], j, custom_styles); } weapon_prop->at("Attach_15_D00AABBD4AD6A04778D56D81E51927B3")->value = weapon.attached; switch(weapon.damageType) { #define c(enumerator, strenum) case DamageType::enumerator: weapon_prop->at("DamageType_18_E1FFA53540591A9087EC698117A65C83")->enumValue = strenum; break; #include "../Maps/DamageTypes.hpp" #undef c default: Utility::Warning{} << "Unknown damage type enum value in writeWeaponType()."; } weapon_prop->at("DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222")->value = weapon.dualWield; switch(weapon.effectColourMode) { #define c(enumerator, enumstr) case EffectColourMode::enumerator: \ weapon_prop->at("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014")->enumValue = enumstr; \ break; #include "../Maps/EffectColourModes.hpp" #undef c default: Utility::Warning{} << "Unknown effect colour mode in writeWeaponType()."; } auto effect_colour = weapon_prop->at("ColorEfx_26_D921B62946C493E487455A831F4520AC"); effect_colour->r = weapon.effectColour.r(); effect_colour->g = weapon.effectColour.g(); effect_colour->b = weapon.effectColour.b(); effect_colour->a = weapon.effectColour.a(); } if(!_mass->saveToFile()) { _lastError = _mass->lastError(); return false; } return true; } void Mass::getTuningCategory(const char* big_node_prop_name, Int& big_node_id, const char* small_nodes_prop_name, Containers::ArrayView small_nodes_ids) { auto node_id = _mass->at(big_node_prop_name); if(!node_id) { _state = State::Invalid; return; } big_node_id = node_id->value; auto node_ids = _mass->at(small_nodes_prop_name); if(!node_ids) { _state = State::Invalid; return; } if(node_ids->items.size() != small_nodes_ids.size()) { _state = State::Invalid; return; } for(UnsignedInt i = 0; i < small_nodes_ids.size(); i++) { auto small_node_id = node_ids->at(i); CORRADE_INTERNAL_ASSERT(small_node_id); small_nodes_ids[i] = small_node_id->value; } }