// 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 "../BinaryReader.h" #include "../BinaryWriter.h" #include "../PropertySerialiser.h" #include "../Types/NoneProperty.h" #include "MapPropertySerialiser.h" auto MapPropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr { auto prop = Containers::pointer(); if(!reader.readUEString(prop->keyType)) { return nullptr; } if(!reader.readUEString(prop->valueType)) { return nullptr; } char terminator; if(!reader.readChar(terminator) || terminator != '\0') { return nullptr; } UnsignedInt null; if(!reader.readUnsignedInt(null) || null != 0u) { return nullptr; } UnsignedInt count; if(!reader.readUnsignedInt(count)) { return nullptr; } // Begin dirty code because the MapProperty format doesn't seem to match any of the GVAS reading stuff I've found, // so I'm just gonna write stuff that matches the only MapProperty I can find in MB's save files. arrayReserve(prop->map, count); for(UnsignedInt i = 0; i < count; i++) { MapProperty::KeyValuePair pair; if(prop->keyType == "IntProperty" || prop->keyType == "StrProperty") { pair.key = serialiser.readItem(reader, prop->keyType, -1, name); if(pair.key == nullptr) { return nullptr; } } else { // Add other branches depending on key type, should more maps appear in the future. return nullptr; } UnrealPropertyBase::ptr value_item; if(prop->valueType == "StructProperty") { while((value_item = serialiser.read(reader)) != nullptr) { arrayAppend(pair.values, std::move(value_item)); if(pair.values.back()->name == "None" && pair.values.back()->propertyType == "NoneProperty" && dynamic_cast(pair.values.back().get()) != nullptr) { break; } } } else if(prop->valueType == "ByteProperty") { if((value_item = serialiser.readItem(reader, prop->valueType, -1, name)) == nullptr) { return nullptr; } arrayAppend(pair.values, std::move(value_item)); } arrayAppend(prop->map, std::move(pair)); } // End dirty code return prop; } auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool { auto map_prop = dynamic_cast(prop.get()); if(!map_prop) { return false; } writer.writeUEStringToArray(map_prop->keyType); writer.writeUEStringToArray(map_prop->valueType); writer.writeValueToArray('\0'); UnsignedLong value_start = writer.arrayPosition(); writer.writeValueToArray(0u); writer.writeValueToArray(UnsignedInt(map_prop->map.size())); UnsignedLong dummy_bytes_written = 0; for(auto& pair : map_prop->map) { if(!serialiser.writeItem(pair.key, map_prop->keyType, dummy_bytes_written, writer)) { return false; } for(auto& value : pair.values) { if(!serialiser.write(value, dummy_bytes_written, writer)) { return false; } } } bytes_written += (writer.arrayPosition() - value_start); return true; }