Compare commits

...

4 commits

Author SHA1 Message Date
76210e147a BinaryWriter: add a way to access the temp array.
That way, I'll be able to easily compute the CRC32 of it.
2022-02-13 15:09:07 +01:00
5e06c48492 BinaryWriter: fix an issue with writeValueToArray().
The view needs to be of type T, not U (which can potentially be T&).
2022-02-13 15:03:45 +01:00
2ff32c4c78 Add a CRC32 algorithm. 2022-02-13 15:02:08 +01:00
4000421a8c Mass,SaveTool: refactor even more code. 2022-02-13 10:31:55 +01:00
9 changed files with 197 additions and 72 deletions

View file

@ -136,7 +136,7 @@ add_executable(MassBuilderSaveTool WIN32
Mass/WeaponPart.h
Maps/Accessories.h
Maps/ArmourSets.h
Maps/ArmourSlots.h
Maps/ArmourSlots.hpp
Maps/DamageTypes.hpp
Maps/LastMissionId.h
Maps/StoryProgress.h
@ -144,6 +144,7 @@ add_executable(MassBuilderSaveTool WIN32
Maps/WeaponTypes.hpp
ToastQueue/ToastQueue.h
ToastQueue/ToastQueue.cpp
Utilities/Crc32.h
FontAwesome/IconsFontAwesome5.h
FontAwesome/IconsFontAwesome5Brands.h
resource.rc

View file

@ -1,61 +0,0 @@
#pragma once
// 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 <string>
#include <unordered_map>
static const std::unordered_map<std::string, const char*> armour_slots {
{"enuArmorSlots::NewEnumerator0", "Face"},
{"enuArmorSlots::NewEnumerator1", "Upper head"},
{"enuArmorSlots::NewEnumerator2", "Lower head"},
{"enuArmorSlots::NewEnumerator3", "Neck"},
{"enuArmorSlots::NewEnumerator4", "Upper body"},
{"enuArmorSlots::NewEnumerator5", "Middle body"},
{"enuArmorSlots::NewEnumerator23", "Backpack"},
{"enuArmorSlots::NewEnumerator6", "Lower body"},
{"enuArmorSlots::NewEnumerator7", "Front waist"},
{"enuArmorSlots::NewEnumerator8", "Left front skirt"},
{"enuArmorSlots::NewEnumerator9", "Right front skirt"},
{"enuArmorSlots::NewEnumerator10", "Left side skirt"},
{"enuArmorSlots::NewEnumerator11", "Right side skirt"},
{"enuArmorSlots::NewEnumerator12", "Left back skirt"},
{"enuArmorSlots::NewEnumerator13", "Right side skirt"},
{"enuArmorSlots::NewEnumerator14", "Back waist"},
{"enuArmorSlots::NewEnumerator15", "Left shoulder"},
{"enuArmorSlots::NewEnumerator16", "Right shoulder"},
{"enuArmorSlots::NewEnumerator17", "Left upper arm"},
{"enuArmorSlots::NewEnumerator18", "Right upper arm"},
{"enuArmorSlots::NewEnumerator19", "Left elbow"},
{"enuArmorSlots::NewEnumerator20", "Right elbow"},
{"enuArmorSlots::NewEnumerator21", "Left lower arm"},
{"enuArmorSlots::NewEnumerator22", "Right lower arm"},
{"enuArmorSlots::NewEnumerator24", "Left hand"},
{"enuArmorSlots::NewEnumerator25", "Right hand"},
{"enuArmorSlots::NewEnumerator26", "Left upper leg"},
{"enuArmorSlots::NewEnumerator27", "Right upper leg"},
{"enuArmorSlots::NewEnumerator28", "Left knee"},
{"enuArmorSlots::NewEnumerator29", "Right knee"},
{"enuArmorSlots::NewEnumerator30", "Left lower leg"},
{"enuArmorSlots::NewEnumerator31", "Right lower leg"},
{"enuArmorSlots::NewEnumerator32", "Left ankle"},
{"enuArmorSlots::NewEnumerator33", "Right ankle"},
{"enuArmorSlots::NewEnumerator34", "Left heel"},
{"enuArmorSlots::NewEnumerator35", "Right heel"},
{"enuArmorSlots::NewEnumerator36", "Left foot"},
{"enuArmorSlots::NewEnumerator37", "Right foot"},
};

56
src/Maps/ArmourSlots.hpp Normal file
View file

@ -0,0 +1,56 @@
// 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/>.
#ifdef c
c(Face, "enuArmorSlots::NewEnumerator0", "Face")
c(UpperHead, "enuArmorSlots::NewEnumerator1", "Upper head")
c(LowerHead, "enuArmorSlots::NewEnumerator2", "Lower head")
c(Neck, "enuArmorSlots::NewEnumerator3", "Neck")
c(UpperBody, "enuArmorSlots::NewEnumerator4", "Upper body")
c(MiddleBody, "enuArmorSlots::NewEnumerator5", "Middle body")
c(LowerBody, "enuArmorSlots::NewEnumerator6", "Lower body")
c(FrontWaist, "enuArmorSlots::NewEnumerator7", "Front waist")
c(LeftFrontSkirt, "enuArmorSlots::NewEnumerator8", "Left front skirt")
c(RightFrontSkirt, "enuArmorSlots::NewEnumerator9", "Right front skirt")
c(LeftSideSkirt, "enuArmorSlots::NewEnumerator10", "Left side skirt")
c(RightSideSkirt, "enuArmorSlots::NewEnumerator11", "Right side skirt")
c(LeftBackSkirt, "enuArmorSlots::NewEnumerator12", "Left back skirt")
c(RightBackSkirt, "enuArmorSlots::NewEnumerator13", "Right back skirt")
c(BackWaist, "enuArmorSlots::NewEnumerator14", "Back waist")
c(LeftShoulder, "enuArmorSlots::NewEnumerator15", "Left shoulder")
c(RightShoulder, "enuArmorSlots::NewEnumerator16", "Right shoulder")
c(LeftUpperArm, "enuArmorSlots::NewEnumerator17", "Left upper arm")
c(RightUpperArm, "enuArmorSlots::NewEnumerator18", "Right upper arm")
c(LeftElbow, "enuArmorSlots::NewEnumerator19", "Left elbow")
c(RightElbow, "enuArmorSlots::NewEnumerator20", "Right elbow")
c(LeftLowerArm, "enuArmorSlots::NewEnumerator21", "Left lower arm")
c(RightLowerArm, "enuArmorSlots::NewEnumerator22", "Right lower arm")
c(Backpack, "enuArmorSlots::NewEnumerator23", "Backpack")
c(LeftHand, "enuArmorSlots::NewEnumerator24", "Left hand")
c(RightHand, "enuArmorSlots::NewEnumerator25", "Right hand")
c(LeftUpperLeg, "enuArmorSlots::NewEnumerator26", "Left upper leg")
c(RightUpperLeg, "enuArmorSlots::NewEnumerator27", "Right upper leg")
c(LeftKnee, "enuArmorSlots::NewEnumerator28", "Left knee")
c(RightKnee, "enuArmorSlots::NewEnumerator29", "Right knee")
c(LeftLowerLeg, "enuArmorSlots::NewEnumerator30", "Left lower leg")
c(RightLowerLeg, "enuArmorSlots::NewEnumerator31", "Right lower leg")
c(LeftAnkle, "enuArmorSlots::NewEnumerator32", "Left ankle")
c(RightAnkle, "enuArmorSlots::NewEnumerator33", "Right ankle")
c(LeftHeel, "enuArmorSlots::NewEnumerator34", "Left heel")
c(RightHeel, "enuArmorSlots::NewEnumerator35", "Right heel")
c(LeftFoot, "enuArmorSlots::NewEnumerator36", "Left foot")
c(RightFoot, "enuArmorSlots::NewEnumerator37", "Right foot")
#endif

View file

@ -28,8 +28,49 @@
using namespace Corrade;
using namespace Magnum;
enum class ArmourSlot {
Face = 0,
UpperHead = 1,
LowerHead = 2,
Neck = 3,
UpperBody = 4,
MiddleBody = 5,
LowerBody = 6,
FrontWaist = 7,
LeftFrontSkirt = 8,
RightFrontSkirt = 9,
LeftSideSkirt = 10,
RightSideSkirt = 11,
LeftBackSkirt = 12,
RightBackSkirt = 13,
BackWaist = 14,
LeftShoulder = 15,
RightShoulder = 16,
LeftUpperArm = 17,
RightUpperArm = 18,
LeftElbow = 19,
RightElbow = 20,
LeftLowerArm = 21,
RightLowerArm = 22,
Backpack = 23,
LeftHand = 24,
RightHand = 25,
LeftUpperLeg = 26,
RightUpperLeg = 27,
LeftKnee = 28,
RightKnee = 29,
LeftLowerLeg = 30,
RightLowerLeg = 31,
LeftAnkle = 32,
RightAnkle = 33,
LeftHeel = 34,
RightHeel = 35,
LeftFoot = 36,
RightFoot = 37,
};
struct ArmourPart {
std::string slot;
ArmourSlot slot = ArmourSlot::Face;
Int id = 0;
Containers::StaticArray<4, Int> styles{ValueInit};
UnsignedInt demoDecals = 8;

View file

@ -583,7 +583,15 @@ void Mass::getArmourParts() {
auto part_prop = armour_array->at<GenericStructProperty>(i);
auto& part = _armour.parts[i];
part.slot = part_prop->at<ByteProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C")->enumValue;
auto& armour_slot = part_prop->at<ByteProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C")->enumValue;
#define c(enumerator, strenum, name) if(armour_slot == (strenum)) { part.slot = ArmourSlot::enumerator; } else
#include "../Maps/ArmourSlots.hpp"
#undef c
{
_state = State::Invalid;
Utility::Warning{} << "Invalid armour slot enum value in getArmourParts().";
}
part.id = part_prop->at<IntProperty>("ID_5_ACD101864D3481DE96EDACACC09BDD25")->value;
auto part_styles = part_prop->at<ArrayProperty>("Styles_47_3E31870441DFD7DB8BEE5C85C26B365B");
@ -644,8 +652,16 @@ auto Mass::writeArmourPart(UnsignedLong index) -> bool {
auto& part = _armour.parts[index];
if(part_prop->at<ByteProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C")->enumValue != part.slot) {
return false;
auto& armour_slot = part_prop->at<ByteProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C")->enumValue;
switch(part.slot) {
#define c(enumerator, strenum, name) case ArmourSlot::enumerator: \
if((strenum) != armour_slot) { \
_lastError = "Armour part slot doesn't match save file."; \
return false; \
} \
break;
#include "../Maps/ArmourSlots.hpp"
#undef c
}
part_prop->at<IntProperty>("ID_5_ACD101864D3481DE96EDACACC09BDD25")->value = part.id;

View file

@ -20,7 +20,6 @@
#include "../Maps/Accessories.h"
#include "../Maps/ArmourSets.h"
#include "../Maps/ArmourSlots.h"
#include "../Maps/StyleNames.h"
#include "../FontAwesome/IconsFontAwesome5.h"
@ -458,6 +457,12 @@ void SaveTool::drawArmour() {
return;
}
static const char* slot_labels[] = {
#define c(enumerator, strenum, name) name,
#include "../Maps/ArmourSlots.hpp"
#undef c
};
for(UnsignedInt i = 0; i < _currentMass->armourParts().size(); i++) {
ImGui::PushID(i);
@ -468,10 +473,10 @@ void SaveTool::drawArmour() {
std::memset(header, '\0', 129);
if(armour_sets.find(part.id) != armour_sets.cend()) {
std::snprintf(header, 128, "%s: %s###%s", armour_slots.at(part.slot), armour_sets.at(part.id).name, part.slot.c_str());
std::snprintf(header, 128, "%s: %s###%u", slot_labels[UnsignedInt(part.slot)], armour_sets.at(part.id).name, UnsignedInt(part.slot));
}
else {
std::snprintf(header, 128, "%s: %i###%s", armour_slots.at(part.slot), part.id, part.slot.c_str());
std::snprintf(header, 128, "%s: %i###%u", slot_labels[UnsignedInt(part.slot)], part.id, UnsignedInt(part.slot));
}
if(ImGui::CollapsingHeader(header)) {
@ -479,7 +484,7 @@ void SaveTool::drawArmour() {
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() * 0.491f);
if(ImGui::BeginListBox("##ChangePart")) {
if(std::strncmp("Neck", armour_slots.at(part.slot), 4) != 0) {
if(std::strncmp("Neck", slot_labels[UnsignedInt(part.slot)], 4) != 0) {
for(auto& set : armour_sets) {
if(ImGui::Selectable(set.second.name, set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) {
part.id = set.first;
@ -862,7 +867,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
}
ImGui::AlignTextToFramePadding();
const char* labels[] {
static const char* labels[] {
#define c(enumerator, strenum, name) name,
#include "../Maps/WeaponTypes.hpp"
#undef c

View file

@ -46,6 +46,10 @@ auto BinaryWriter::position() -> Long {
return _ftelli64(_file);
}
auto BinaryWriter::array() const -> Containers::ArrayView<const char> {
return _data;
}
auto BinaryWriter::arrayPosition() const -> UnsignedLong {
return _index;
}

View file

@ -45,6 +45,7 @@ class BinaryWriter {
auto position() -> Long;
auto array() const -> Containers::ArrayView<const char>;
auto arrayPosition() const -> UnsignedLong;
auto flushToFile() -> bool;
@ -74,7 +75,7 @@ class BinaryWriter {
template<typename T, typename U = std::conditional_t<std::is_trivially_copyable<T>::value, T, T&>>
auto writeValueToArray(U value) -> UnsignedLong {
Containers::ArrayView<U> view{&value, 1};
Containers::ArrayView<T> view{&value, 1};
return writeDataToArray(view);
}

62
src/Utilities/Crc32.h Normal file
View file

@ -0,0 +1,62 @@
#pragma once
// 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 <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/StaticArray.h>
#include <Magnum/Types.h>
using namespace Corrade;
using namespace Magnum;
struct Crc32 {
static const Containers::StaticArray<256, UnsignedInt> table;
static auto update(UnsignedInt initial, Containers::ArrayView<const void> data) -> UnsignedInt {
UnsignedInt c = initial ^ 0xFFFFFFFF;
auto u = Containers::arrayCast<const UnsignedByte>(data);
for(std::size_t i = 0; i < data.size(); ++i) {
c = table[(c ^ u[i]) & 0xFF] ^ (c >> 8);
}
return c ^ 0xFFFFFFFF;
}
};
const Containers::StaticArray<256, UnsignedInt> Crc32::table = []{
UnsignedInt polynomial = 0xEDB88320;
Containers::StaticArray<256, UnsignedInt> temp{ValueInit};
for(UnsignedInt i = 0; i < 256; i++) {
UnsignedInt c = i;
for(std::size_t j = 0; j < 8; j++) {
if(c & 1) {
c = polynomial ^ (c >> 1);
}
else {
c >>= 1;
}
}
temp[i] = c;
}
return temp;
}();