// 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 . #include #include #include #include #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" std::string Mass::_lastError; 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)) { _lastError = path + " couldn't be found."; return Containers::NullOpt; } UESaveFile mass{path}; if(!mass.valid()) { _lastError = "The unit file seems to be corrupt."; return Containers::NullOpt; } 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() { 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; } // region MassName { auto name_prop = unit_data->at("Name_45_A037C5D54E53456407BDF091344529BB"); if(!name_prop) { _name = Containers::NullOpt; _state = State::Invalid; return; } _name = name_prop->value; } // endregion // region FrameData { 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; } if(frame_styles->items.size() != 4) { _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}; } // endregion // region FrameStyles { auto frame_styles = unit_data->at("FrameStyle_44_04A44C9440363CCEC5443D98BFAF22AA"); if(!frame_styles) { _state = State::Invalid; return; } if(frame_styles->items.size() != 16) { _state = State::Invalid; return; } for(UnsignedInt i = 0; i < frame_styles->items.size(); i++) { auto style_prop = frame_styles->at(i); CustomStyle style; 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; _frame.customStyles[i] = std::move(style); } } // endregion // TODO: armour // region ArmourStyles { auto armour_styles = unit_data->at("ArmorStyle_42_E2F6AC3647788CB366BD469B3B7E899E"); if(!armour_styles) { _state = State::Invalid; return; } if(armour_styles->items.size() != 16) { _state = State::Invalid; return; } for(UnsignedInt i = 0; i < armour_styles->items.size(); i++) { auto style_prop = armour_styles->at(i); CustomStyle style; 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; _armour.customStyles[i] = std::move(style); } } // endregion // TODO: weapons // region GlobalStyles { auto global_styles = unit_data->at("GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B"); if(!global_styles) { _state = State::Invalid; return; } if(global_styles->items.size() != 16) { _state = State::Invalid; return; } for(UnsignedInt i = 0; i < global_styles->items.size(); i++) { auto style_prop = global_styles->at(i); CustomStyle style; 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; _globalStyles[i] = std::move(style); } } // endregion // TODO: tuning 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() -> 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() 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 _frame.styles; } auto Mass::setFrameStyle(Int index, Int style_id) -> bool { _frame.styles[index] = style_id; 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 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::frameCustomStyles() -> Containers::StaticArrayView<16, CustomStyle> { return _frame.customStyles; } auto Mass::setFrameCustomStyle(CustomStyle style, UnsignedLong index) -> bool { if(index > _frame.customStyles.size()) { return false; } _frame.customStyles[index] = std::move(style); return setCustomStyle(_frame.customStyles[index], index, "FrameStyle_44_04A44C9440363CCEC5443D98BFAF22AA"); } auto Mass::armourCustomStyles() -> Containers::StaticArrayView<16, CustomStyle> { return _armour.customStyles; } auto Mass::setArmourCustomStyle(CustomStyle style, UnsignedLong index) -> bool { if(index > _armour.customStyles.size()) { return false; } _armour.customStyles[index] = std::move(style); return setCustomStyle(_armour.customStyles[index], index, "ArmorStyle_42_E2F6AC3647788CB366BD469B3B7E899E"); } auto Mass::globalStyles() -> Containers::StaticArrayView<16, CustomStyle> { return _globalStyles; } auto Mass::setGlobalStyle(CustomStyle style, UnsignedLong index) -> bool { if(index > _globalStyles.size()) { return false; } _globalStyles[index] = std::move(style); return setCustomStyle(_globalStyles[index], index, "GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B"); } auto Mass::updateSteamId(const std::string& steam_id) -> bool { _steamId = steam_id; auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return false; } auto account_prop = unit_data->at("Account"); if(!account_prop) { _state = State::Invalid; return false; } account_prop->value = steam_id; return _mass->saveToFile(); } auto Mass::setCustomStyle(const CustomStyle& style, UnsignedLong index, const char* prop_name) -> bool { auto unit_data = _mass->at("UnitData"); if(!unit_data) { _state = State::Invalid; return false; } auto frame_styles = unit_data->at(prop_name); if(!frame_styles) { _state = State::Invalid; return false; } auto style_prop = frame_styles->at(index); 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; return _mass->saveToFile(); }