1.5: Fuckin' UE5... #38
11 changed files with 445 additions and 0 deletions
|
@ -128,6 +128,14 @@ set(Gvas_SOURCES
|
|||
Gvas/PropertySerialiser.cpp
|
||||
)
|
||||
|
||||
set(ImportExport_SOURCES
|
||||
ImportExport/Import.h
|
||||
ImportExport/Import.cpp
|
||||
ImportExport/Export.h
|
||||
ImportExport/Export.cpp
|
||||
ImportExport/Keys.h
|
||||
)
|
||||
|
||||
if(CORRADE_TARGET_WINDOWS)
|
||||
set(SAVETOOL_RC_FILE resource.rc)
|
||||
endif()
|
||||
|
@ -199,6 +207,7 @@ add_executable(MassBuilderSaveTool
|
|||
${Logger_SOURCES}
|
||||
${BinaryIo_SOURCES}
|
||||
${Gvas_SOURCES}
|
||||
${ImportExport_SOURCES}
|
||||
${SAVETOOL_RC_FILE}
|
||||
${Assets}
|
||||
)
|
||||
|
|
127
src/ImportExport/Export.cpp
Normal file
127
src/ImportExport/Export.cpp
Normal file
|
@ -0,0 +1,127 @@
|
|||
// 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 <Corrade/Utility/Format.h>
|
||||
#include <Corrade/Utility/Path.h>
|
||||
|
||||
#include "../Logger/Logger.h"
|
||||
#include "../BinaryIo/Writer.h"
|
||||
#include "../Configuration/Configuration.h"
|
||||
#include "../Utilities/Crc32.h"
|
||||
|
||||
#include "Keys.h"
|
||||
|
||||
#include "Export.h"
|
||||
|
||||
namespace mbst { namespace ImportExport {
|
||||
|
||||
static Containers::String last_export_error;
|
||||
|
||||
Containers::StringView
|
||||
lastExportError() {
|
||||
return last_export_error;
|
||||
}
|
||||
|
||||
bool
|
||||
exportStyle(Containers::StringView mass_name, mbst::GameObjects::CustomStyle& style) {
|
||||
Containers::String style_type_str;
|
||||
switch(style.type) {
|
||||
case GameObjects::CustomStyle::Type::Unknown:
|
||||
style_type_str = "Style";
|
||||
break;
|
||||
case GameObjects::CustomStyle::Type::Frame:
|
||||
style_type_str = "FrameStyle";
|
||||
break;
|
||||
case GameObjects::CustomStyle::Type::Armour:
|
||||
style_type_str = "ArmourStyle";
|
||||
break;
|
||||
case GameObjects::CustomStyle::Type::Weapon:
|
||||
style_type_str = "WeaponStyle";
|
||||
break;
|
||||
case GameObjects::CustomStyle::Type::Global:
|
||||
style_type_str = "GlobalStyle";
|
||||
break;
|
||||
}
|
||||
|
||||
auto filename = Utility::format("{}_{}_{}.style.mbst", mass_name, style_type_str, style.name);
|
||||
for(auto& c : filename) {
|
||||
if(c == ' ') {
|
||||
c = '_';
|
||||
}
|
||||
}
|
||||
|
||||
auto path = Utility::Path::join(conf().directories().styles, filename);
|
||||
BinaryIo::Writer writer{path};
|
||||
|
||||
if(!writer.open()) {
|
||||
last_export_error = path + " couldn't be opened.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!writer.writeString("MBSTSTYLE")) {
|
||||
LOG_ERROR(last_export_error = "Couldn't write magic bytes into " + filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::Name);
|
||||
writer.writeUEStringToArray(style.name);
|
||||
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::Colour);
|
||||
writer.writeValueToArray<Color4>(style.colour);
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::Metallic);
|
||||
writer.writeValueToArray<float>(style.metallic);
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::Gloss);
|
||||
writer.writeValueToArray<float>(style.gloss);
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::Glow);
|
||||
writer.writeValueToArray<bool>(style.glow);
|
||||
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::PatternId);
|
||||
writer.writeValueToArray<std::int32_t>(style.patternId);
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::PatternOpacity);
|
||||
writer.writeValueToArray<float>(style.opacity);
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::PatternOffset);
|
||||
writer.writeValueToArray<Vector2>(style.offset);
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::PatternRotation);
|
||||
writer.writeValueToArray<float>(style.rotation);
|
||||
writer.writeValueToArray<Keys::CustomStyle>(Keys::CustomStyle::PatternScale);
|
||||
writer.writeValueToArray<float>(style.scale);
|
||||
|
||||
if(!writer.writeUint64(writer.array().size())) {
|
||||
LOG_ERROR(last_export_error = "Couldn't write data size into " + filename);
|
||||
writer.closeFile();
|
||||
Utility::Path::remove(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto crc = Utilities::crc32(0, writer.array());
|
||||
if(!writer.writeUint32(crc)) {
|
||||
LOG_ERROR(last_export_error = "Couldn't write CRC32 checksum into " + filename);
|
||||
writer.closeFile();
|
||||
Utility::Path::remove(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!writer.flushToFile()) {
|
||||
LOG_ERROR(last_export_error = "Couldn't write data into " + filename);
|
||||
writer.closeFile();
|
||||
Utility::Path::remove(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}}
|
31
src/ImportExport/Export.h
Normal file
31
src/ImportExport/Export.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
// 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 <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "../Mass/CustomStyle.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
||||
namespace mbst { namespace ImportExport {
|
||||
|
||||
auto lastExportError() -> Containers::StringView;
|
||||
|
||||
bool exportStyle(Containers::StringView mass_name, GameObjects::CustomStyle& style);
|
||||
|
||||
}}
|
186
src/ImportExport/Import.cpp
Normal file
186
src/ImportExport/Import.cpp
Normal file
|
@ -0,0 +1,186 @@
|
|||
// 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 <cstring>
|
||||
|
||||
#include <Corrade/Containers/Array.h>
|
||||
#include <Corrade/Containers/Optional.h>
|
||||
#include <Corrade/Containers/String.h>
|
||||
#include <Corrade/Utility/Path.h>
|
||||
|
||||
#include "../BinaryIo/Reader.h"
|
||||
#include "../Configuration/Configuration.h"
|
||||
#include "../Logger/Logger.h"
|
||||
#include "../Utilities/Crc32.h"
|
||||
|
||||
#include "Keys.h"
|
||||
|
||||
#include "Import.h"
|
||||
|
||||
namespace mbst { namespace ImportExport {
|
||||
|
||||
static Containers::String last_import_error;
|
||||
|
||||
Containers::StringView
|
||||
lastImportError() {
|
||||
return last_import_error;
|
||||
}
|
||||
|
||||
Containers::Optional<GameObjects::CustomStyle>
|
||||
importStyle(Containers::StringView filename) {
|
||||
auto path = Utility::Path::join(conf().directories().styles, filename);
|
||||
if(!Utility::Path::exists(path)) {
|
||||
LOG_ERROR(last_import_error = path + " doesn't exist.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
BinaryIo::Reader reader{path};
|
||||
if(!reader.open()) {
|
||||
last_import_error = path + " couldn't be opened.";
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
Containers::Array<char> magic_bytes;
|
||||
if(!reader.readArray(magic_bytes, 9)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read the magic bytes.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
Containers::StringView magic_bytes_view = magic_bytes;
|
||||
static const auto expected_magic_bytes = "MBSTSTYLE"_s;
|
||||
if(magic_bytes_view != expected_magic_bytes) {
|
||||
LOG_ERROR(last_import_error = "Magic bytes are mismatched.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
std::size_t data_size;
|
||||
if(!reader.readUint64(data_size)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read data size.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
std::uint32_t crc;
|
||||
if(!reader.readUint32(crc)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read CRC-32 checksum.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
auto position = reader.position();
|
||||
|
||||
{
|
||||
Containers::Array<char> data;
|
||||
if(!reader.readArray(data, data_size)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read data.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
auto computed_crc = Utilities::crc32(0, data);
|
||||
if(computed_crc != crc) {
|
||||
LOG_ERROR(last_import_error = Utility::format("CRC-32 checksum doesn't match. "
|
||||
"Expected {}, got {} instead.",
|
||||
crc, computed_crc));
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
}
|
||||
|
||||
if(!reader.seek(position)) {
|
||||
LOG_ERROR(last_import_error = Utility::format("Couldn't seek to position {}.", position));
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
GameObjects::CustomStyle style{};
|
||||
|
||||
while(!reader.eof()) {
|
||||
Keys::CustomStyle key;
|
||||
if(!reader.readValue(key)) {
|
||||
if(reader.eof()) {
|
||||
break;
|
||||
}
|
||||
LOG_ERROR(last_import_error = "Couldn't read key.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
switch(key) {
|
||||
case Keys::Name:
|
||||
if(!reader.readUEString(style.name)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style name.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
case Keys::Colour:
|
||||
if(!reader.readValue<Color4>(style.colour)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style colour.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
case Keys::Metallic:
|
||||
if(!reader.readFloat(style.metallic)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style metallic.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
case Keys::Gloss:
|
||||
if(!reader.readFloat(style.gloss)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style gloss.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
case Keys::Glow:
|
||||
if(!reader.readValue(style.glow)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style glow.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
case Keys::PatternId:
|
||||
if(!reader.readInt32(style.patternId)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style pattern ID.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
case Keys::PatternOpacity:
|
||||
if(!reader.readFloat(style.opacity)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style pattern opacity.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
case Keys::PatternOffset:
|
||||
if(!reader.readValue(style.offset)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style pattern offset.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
case Keys::PatternRotation:
|
||||
if(!reader.readFloat(style.rotation)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style pattern rotation.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
case Keys::PatternScale:
|
||||
if(!reader.readFloat(style.scale)) {
|
||||
LOG_ERROR(last_import_error = "Couldn't read style pattern scale.");
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(last_import_error = Utility::format("Unknown key {}.", key));
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
}
|
||||
|
||||
return Utility::move(style);
|
||||
}
|
||||
|
||||
}}
|
31
src/ImportExport/Import.h
Normal file
31
src/ImportExport/Import.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
// 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 <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "../Mass/CustomStyle.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
||||
namespace mbst { namespace ImportExport {
|
||||
|
||||
auto lastImportError() -> Containers::StringView;
|
||||
|
||||
auto importStyle(Containers::StringView filename) -> Containers::Optional<GameObjects::CustomStyle>;
|
||||
|
||||
}}
|
36
src/ImportExport/Keys.h
Normal file
36
src/ImportExport/Keys.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
// 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 <cstdint>
|
||||
|
||||
namespace mbst { namespace ImportExport { namespace Keys {
|
||||
|
||||
enum CustomStyle: std::uint8_t {
|
||||
Name = 0, // type: string
|
||||
Colour = 1, // type: Magnum::Color4
|
||||
Metallic = 2, // type: float
|
||||
Gloss = 3, // type: float
|
||||
Glow = 4, // type: bool
|
||||
PatternId = 5, // type: std::int32_t
|
||||
PatternOpacity = 6, // type: float
|
||||
PatternOffset = 7, // type: Magnum::Vector2
|
||||
PatternRotation = 8, // type: float
|
||||
PatternScale = 9, // type: float
|
||||
};
|
||||
|
||||
}}}
|
|
@ -39,6 +39,15 @@ struct CustomStyle {
|
|||
Vector2 offset{0.5f};
|
||||
float rotation = 0.0f;
|
||||
float scale = 0.5f;
|
||||
|
||||
// This is only used to know which style array the current style is located in when exporting a standalone style.
|
||||
enum class Type: std::uint8_t {
|
||||
Unknown,
|
||||
Frame,
|
||||
Armour,
|
||||
Weapon,
|
||||
Global
|
||||
} type = Type::Unknown;
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -413,6 +413,10 @@ Mass::getArmourCustomStyles() {
|
|||
}
|
||||
|
||||
getCustomStyles(_armour.customStyles, armour_styles);
|
||||
|
||||
for(auto& style : _armour.customStyles) {
|
||||
style.type = CustomStyle::Type::Armour;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -373,6 +373,10 @@ Mass::getFrameCustomStyles() {
|
|||
}
|
||||
|
||||
getCustomStyles(_frame.customStyles, frame_styles);
|
||||
|
||||
for(auto& style : _frame.customStyles) {
|
||||
style.type = CustomStyle::Type::Frame;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -57,6 +57,10 @@ Mass::getGlobalStyles() {
|
|||
}
|
||||
|
||||
getCustomStyles(_globalStyles, global_styles);
|
||||
|
||||
for(auto& style : _globalStyles) {
|
||||
style.type = CustomStyle::Type::Global;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -219,6 +219,10 @@ Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weap
|
|||
|
||||
getCustomStyles(weapon.customStyles, custom_styles);
|
||||
|
||||
for(auto& style : weapon.customStyles) {
|
||||
style.type = CustomStyle::Type::Weapon;
|
||||
}
|
||||
|
||||
weapon.attached = weapon_prop->at<Gvas::Types::BoolProperty>(MASS_WEAPON_ATTACH)->value;
|
||||
auto& damage_type = weapon_prop->at<Gvas::Types::ByteProperty>(MASS_WEAPON_DAMAGE_TYPE)->enumValue;
|
||||
#define c(enumerator, strenum) if(damage_type == (strenum)) { weapon.damageType = Weapon::DamageType::enumerator; } else
|
||||
|
|
Loading…
Reference in a new issue