320 lines
13 KiB
C++
320 lines
13 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 "../UESaveFile/Types/ArrayProperty.h"
|
|
#include "../UESaveFile/Types/BoolProperty.h"
|
|
#include "../UESaveFile/Types/ByteProperty.h"
|
|
#include "../UESaveFile/Types/ColourStructProperty.h"
|
|
#include "../UESaveFile/Types/GenericStructProperty.h"
|
|
#include "../UESaveFile/Types/IntProperty.h"
|
|
#include "../UESaveFile/Types/StringProperty.h"
|
|
|
|
#include "Mass.h"
|
|
|
|
using namespace Containers::Literals;
|
|
|
|
auto Mass::meleeWeapons() -> Containers::ArrayView<Weapon> {
|
|
return _weapons.melee;
|
|
}
|
|
|
|
void Mass::getMeleeWeapons() {
|
|
getWeaponType("WeaponCC_22_0BBEC58C4A0EA1DB9E037B9339EE26A7"_s, _weapons.melee);
|
|
}
|
|
|
|
auto Mass::writeMeleeWeapons() -> bool {
|
|
return writeWeaponType("WeaponCC_22_0BBEC58C4A0EA1DB9E037B9339EE26A7"_s, _weapons.melee);
|
|
}
|
|
|
|
auto Mass::shields() -> Containers::ArrayView<Weapon> {
|
|
return _weapons.shields;
|
|
}
|
|
|
|
void Mass::getShields() {
|
|
getWeaponType("Shield_53_839BFD7945481BAEA3E43A9C5CA8E92E"_s, _weapons.shields);
|
|
}
|
|
|
|
auto Mass::writeShields() -> bool {
|
|
return writeWeaponType("Shield_53_839BFD7945481BAEA3E43A9C5CA8E92E"_s, _weapons.shields);
|
|
}
|
|
|
|
auto Mass::bulletShooters() -> Containers::ArrayView<Weapon> {
|
|
return _weapons.bulletShooters;
|
|
}
|
|
|
|
void Mass::getBulletShooters() {
|
|
getWeaponType("WeaponBS_35_6EF6E0104FD7A138DF47F88CB57A83ED"_s, _weapons.bulletShooters);
|
|
}
|
|
|
|
auto Mass::writeBulletShooters() -> bool {
|
|
return writeWeaponType("WeaponBS_35_6EF6E0104FD7A138DF47F88CB57A83ED"_s, _weapons.bulletShooters);
|
|
}
|
|
|
|
auto Mass::energyShooters() -> Containers::ArrayView<Weapon> {
|
|
return _weapons.energyShooters;
|
|
}
|
|
|
|
void Mass::getEnergyShooters() {
|
|
getWeaponType("WeaponES_37_1A295D544528623880A0B1AC2C7DEE99"_s, _weapons.energyShooters);
|
|
}
|
|
|
|
auto Mass::writeEnergyShooters() -> bool {
|
|
return writeWeaponType("WeaponES_37_1A295D544528623880A0B1AC2C7DEE99"_s, _weapons.energyShooters);
|
|
}
|
|
|
|
auto Mass::bulletLaunchers() -> Containers::ArrayView<Weapon> {
|
|
return _weapons.bulletLaunchers;
|
|
}
|
|
|
|
void Mass::getBulletLaunchers() {
|
|
getWeaponType("WeaponBL_36_5FD7C41E4613A75B44AB0E90B362846E"_s, _weapons.bulletLaunchers);
|
|
}
|
|
|
|
auto Mass::writeBulletLaunchers() -> bool {
|
|
return writeWeaponType("WeaponBL_36_5FD7C41E4613A75B44AB0E90B362846E"_s, _weapons.bulletLaunchers);
|
|
}
|
|
|
|
auto Mass::energyLaunchers() -> Containers::ArrayView<Weapon> {
|
|
return _weapons.energyLaunchers;
|
|
}
|
|
|
|
void Mass::getEnergyLaunchers() {
|
|
getWeaponType("WeaponEL_38_9D23F3884ACA15902C9E6CA6E4995995"_s, _weapons.energyLaunchers);
|
|
}
|
|
|
|
auto Mass::writeEnergyLaunchers() -> bool {
|
|
return writeWeaponType("WeaponEL_38_9D23F3884ACA15902C9E6CA6E4995995"_s, _weapons.energyLaunchers);
|
|
}
|
|
|
|
void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) {
|
|
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
|
if(!unit_data) {
|
|
_state = State::Invalid;
|
|
return;
|
|
}
|
|
|
|
auto prop = unit_data->at<ArrayProperty>(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<GenericStructProperty>(i);
|
|
auto& weapon = weapon_array[i];
|
|
|
|
weapon.name = weapon_prop->at<StringProperty>("Name_13_7BF0D31F4E50C50C47231BB36A485D92"_s)->value;
|
|
auto& weapon_type = weapon_prop->at<ByteProperty>("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976"_s)->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()."_s;
|
|
}
|
|
|
|
auto parts_prop = weapon_prop->at<ArrayProperty>("Element_6_8E4617CC4B2C1F1490435599784EC6E0"_s);
|
|
weapon.parts = Containers::Array<WeaponPart>{ValueInit, parts_prop->items.size()};
|
|
|
|
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
|
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
|
auto& part = weapon.parts[j];
|
|
|
|
part.id = part_prop->at<IntProperty>("ID_2_A74D75434308158E5926178822DD28EE"_s)->value;
|
|
|
|
auto part_styles = part_prop->at<ArrayProperty>("Styles_17_994C97C34A90667BE5B716BFD0B97588"_s);
|
|
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
|
part.styles[k] = part_styles->at<IntProperty>(k)->value;
|
|
}
|
|
|
|
auto part_decals = part_prop->at<ArrayProperty>("Decals_13_8B81112B453D7230C0CDE982185E14F1"_s);
|
|
if(part_decals->items.size() != part.decals.size()) {
|
|
part.decals = Containers::Array<Decal>{part_decals->items.size()};
|
|
}
|
|
|
|
getDecals(part.decals, part_decals);
|
|
|
|
auto part_accs = part_prop->at<ArrayProperty>("Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C"_s);
|
|
if(!part_accs) {
|
|
part.accessories = Containers::Array<Accessory>{0};
|
|
continue;
|
|
}
|
|
|
|
if(part_accs->items.size() != part.accessories.size()) {
|
|
part.accessories = Containers::Array<Accessory>{part_accs->items.size()};
|
|
}
|
|
getAccessories(part.accessories, part_accs);
|
|
}
|
|
|
|
auto custom_styles = weapon_prop->at<ArrayProperty>("Styles_10_8C3C82444B986AD7A99595AD4985912D"_s);
|
|
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<BoolProperty>("Attach_15_D00AABBD4AD6A04778D56D81E51927B3"_s)->value;
|
|
auto& damage_type = weapon_prop->at<ByteProperty>("DamageType_18_E1FFA53540591A9087EC698117A65C83"_s)->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()."_s;
|
|
}
|
|
weapon.dualWield = weapon_prop->at<BoolProperty>("DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222"_s)->value;
|
|
auto& effect_colour_mode = weapon_prop->at<ByteProperty>("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014"_s)->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()."_s;
|
|
}
|
|
auto effect_colour = weapon_prop->at<ColourStructProperty>("ColorEfx_26_D921B62946C493E487455A831F4520AC"_s);
|
|
weapon.effectColour = Color4{effect_colour->r, effect_colour->g, effect_colour->b, effect_colour->a};
|
|
}
|
|
}
|
|
|
|
auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool {
|
|
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
|
if(!unit_data) {
|
|
_state = State::Invalid;
|
|
_lastError = "No unit data in "_s + _filename;
|
|
return false;
|
|
}
|
|
|
|
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
|
if(!prop) {
|
|
_state = State::Invalid;
|
|
_lastError = prop_name + " not found in "_s + _filename;
|
|
return false;
|
|
}
|
|
|
|
if(prop->items.size() != weapon_array.size()) {
|
|
_state = State::Invalid;
|
|
_lastError = "Weapon type array size mismatch."_s;
|
|
return false;
|
|
}
|
|
|
|
for(UnsignedInt i = 0; i < weapon_array.size(); i++) {
|
|
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
|
auto& weapon = weapon_array[i];
|
|
|
|
weapon_prop->at<StringProperty>("Name_13_7BF0D31F4E50C50C47231BB36A485D92"_s)->value = weapon.name;
|
|
switch(weapon.type) {
|
|
#define c(enumerator, strenum, name) case WeaponType::enumerator: weapon_prop->at<ByteProperty>("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976"_s)->enumValue = strenum; break;
|
|
#include "../Maps/WeaponTypes.hpp"
|
|
#undef c
|
|
default:
|
|
Utility::Warning{} << "Invalid weapon type enum value in writeWeaponType()."_s;
|
|
}
|
|
|
|
auto parts_prop = weapon_prop->at<ArrayProperty>("Element_6_8E4617CC4B2C1F1490435599784EC6E0"_s);
|
|
if(parts_prop->items.size() != weapon.parts.size()) {
|
|
_state = State::Invalid;
|
|
_lastError = "Weapon parts array size mismatch."_s;
|
|
return false;
|
|
}
|
|
|
|
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
|
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
|
auto& part = weapon.parts[j];
|
|
|
|
part_prop->at<IntProperty>("ID_2_A74D75434308158E5926178822DD28EE"_s)->value = part.id;
|
|
|
|
auto part_styles = part_prop->at<ArrayProperty>("Styles_17_994C97C34A90667BE5B716BFD0B97588"_s);
|
|
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
|
part_styles->at<IntProperty>(k)->value = part.styles[k];
|
|
}
|
|
|
|
auto part_decals = part_prop->at<ArrayProperty>("Decals_13_8B81112B453D7230C0CDE982185E14F1"_s);
|
|
writeDecals(part.decals, part_decals);
|
|
|
|
auto part_accs = part_prop->at<ArrayProperty>("Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C"_s);
|
|
if(!part_accs) {
|
|
continue;
|
|
}
|
|
|
|
if(part_accs->items.size() != part.accessories.size()) {
|
|
_state = State::Invalid;
|
|
_lastError = "Accessories array size mismatch."_s;
|
|
return false;
|
|
}
|
|
|
|
writeAccessories(part.accessories, part_accs);
|
|
}
|
|
|
|
auto custom_styles = weapon_prop->at<ArrayProperty>("Styles_10_8C3C82444B986AD7A99595AD4985912D"_s);
|
|
if(!custom_styles) {
|
|
_state = State::Invalid;
|
|
_lastError = "No custom styles found for weapon."_s;
|
|
return false;
|
|
}
|
|
|
|
if(custom_styles->items.size() != weapon.customStyles.size()) {
|
|
_state = State::Invalid;
|
|
_lastError = "Custom styles array size mismatch."_s;
|
|
return false;
|
|
}
|
|
|
|
for(UnsignedInt j = 0; j < weapon.customStyles.size(); j++) {
|
|
writeCustomStyle(weapon.customStyles[j], j, custom_styles);
|
|
}
|
|
|
|
weapon_prop->at<BoolProperty>("Attach_15_D00AABBD4AD6A04778D56D81E51927B3"_s)->value = weapon.attached;
|
|
switch(weapon.damageType) {
|
|
#define c(enumerator, strenum) case DamageType::enumerator: weapon_prop->at<ByteProperty>("DamageType_18_E1FFA53540591A9087EC698117A65C83"_s)->enumValue = strenum; break;
|
|
#include "../Maps/DamageTypes.hpp"
|
|
#undef c
|
|
default:
|
|
Utility::Warning{} << "Unknown damage type enum value in writeWeaponType()."_s;
|
|
}
|
|
weapon_prop->at<BoolProperty>("DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222"_s)->value = weapon.dualWield;
|
|
switch(weapon.effectColourMode) {
|
|
#define c(enumerator, enumstr) case EffectColourMode::enumerator: \
|
|
weapon_prop->at<ByteProperty>("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014"_s)->enumValue = enumstr; \
|
|
break;
|
|
#include "../Maps/EffectColourModes.hpp"
|
|
#undef c
|
|
default:
|
|
Utility::Warning{} << "Unknown effect colour mode in writeWeaponType()."_s;
|
|
}
|
|
auto effect_colour = weapon_prop->at<ColourStructProperty>("ColorEfx_26_D921B62946C493E487455A831F4520AC"_s);
|
|
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;
|
|
}
|