MassBuilderSaveTool/src/Gvas/Serialisers/MapProperty.cpp

160 lines
5.5 KiB
C++

// MassBuilderSaveTool
// Copyright (C) 2021-2024 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 "../../BinaryIo/Reader.h"
#include "../../BinaryIo/Writer.h"
#include "../PropertySerialiser.h"
#include "../Types/NoneProperty.h"
#include "../../Logger/Logger.h"
#include "MapProperty.h"
using namespace Containers::Literals;
namespace Gvas { namespace Serialisers {
Types::UnrealPropertyBase::ptr
MapProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
{
auto prop = Containers::pointer<Types::MapProperty>();
if(!reader.readUEString(prop->keyType)) {
LOG_ERROR_FORMAT("Couldn't read map property {}'s key type.", name);
return nullptr;
}
if(!reader.readUEString(prop->valueType)) {
LOG_ERROR_FORMAT("Couldn't read map property {}'s value type.", name);
return nullptr;
}
char terminator;
if(!reader.readChar(terminator) || terminator != '\0') {
LOG_ERROR_FORMAT("Couldn't read a null byte in map property {}.", name);
return nullptr;
}
std::uint32_t null;
if(!reader.readUint32(null) || null != 0u) {
LOG_ERROR_FORMAT("Couldn't read a null int in map property {}.", name);
return nullptr;
}
std::uint32_t count;
if(!reader.readUint32(count)) {
LOG_ERROR_FORMAT("Couldn't read map property {}'s item count.", name);
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(std::uint32_t i = 0; i < count; i++) {
Types::MapProperty::KeyValuePair pair;
if(prop->keyType == "IntProperty"_s || prop->keyType == "StrProperty"_s) {
pair.key = serialiser.readItem(reader, prop->keyType, -1, name);
if(pair.key == nullptr) {
LOG_ERROR_FORMAT("Couldn't read a valid key in map property {}.", name);
return nullptr;
}
}
else { // Add other branches depending on key type, should more maps appear in the future.
LOG_ERROR_FORMAT("Key type {} not implemented.", prop->keyType);
return nullptr;
}
Types::UnrealPropertyBase::ptr value_item;
if(prop->valueType == "StructProperty"_s) {
while((value_item = serialiser.read(reader)) != nullptr) {
arrayAppend(pair.values, Utility::move(value_item));
if(pair.values.back()->name == "None"_s &&
pair.values.back()->propertyType == "NoneProperty"_s &&
dynamic_cast<Types::NoneProperty*>(pair.values.back().get()) != nullptr)
{
break;
}
}
}
else if(prop->valueType == "ByteProperty"_s) {
if((value_item = serialiser.readItem(reader, prop->valueType, -1, name)) == nullptr) {
return nullptr;
}
arrayAppend(pair.values, Utility::move(value_item));
}
arrayAppend(prop->map, Utility::move(pair));
}
// End dirty code
return prop;
}
bool
MapProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
{
auto map_prop = dynamic_cast<Types::MapProperty*>(prop.get());
if(!map_prop) {
LOG_ERROR("The property is not a valid map property.");
return false;
}
writer.writeUEStringToArray(map_prop->keyType);
writer.writeUEStringToArray(map_prop->valueType);
writer.writeValueToArray<char>('\0');
std::size_t value_start = writer.arrayPosition();
writer.writeValueToArray<std::uint32_t>(0u);
writer.writeValueToArray<std::uint32_t>(std::uint32_t(map_prop->map.size()));
std::size_t dummy_bytes_written = 0;
for(auto& pair : map_prop->map) {
if(!serialiser.writeItem(pair.key, map_prop->keyType, dummy_bytes_written, writer)) {
LOG_ERROR("Couldn't write a key.");
return false;
}
for(auto& value : pair.values) {
if(map_prop->valueType == "StructProperty"_s) {
if(!serialiser.write(value, dummy_bytes_written, writer)) {
LOG_ERROR("Couldn't write a value.");
return false;
}
}
else {
if(!serialiser.writeItem(value, map_prop->valueType, dummy_bytes_written, writer)) {
LOG_ERROR("Couldn't write a value.");
return false;
}
}
}
}
bytes_written += (writer.arrayPosition() - value_start);
return true;
}
}}