Compare commits

...

6 commits

8 changed files with 323 additions and 32 deletions

View file

@ -48,6 +48,7 @@ add_executable(MassBuilderSaveTool WIN32
Mass/Mass.cpp
Maps/LastMissionId.h
Maps/StoryProgress.h
Maps/StyleNames.h
ToastQueue/ToastQueue.h
ToastQueue/ToastQueue.cpp
FontAwesome/IconsFontAwesome5.h

154
src/Maps/StyleNames.h Normal file
View file

@ -0,0 +1,154 @@
#pragma once
// 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 <https://www.gnu.org/licenses/>.
#include <map>
#include <Magnum/Magnum.h>
using namespace Magnum;
static const std::map<Int, const char*> style_names {
{100, "Iron"},
{101, "Silver"},
{102, "Gold"},
{103, "Bronze"},
{104, "Copper"},
{105, "Nickel"},
{106, "Cobalt"},
{107, "Aluminium"},
{108, "Titanium"},
{109, "Platinum"},
{110, "Gun Metal"},
{111, "White"},
{112, "White Metal"},
{113, "White Gloss"},
{114, "Grey"},
{115, "Grey Metal"},
{116, "Grey Gloss"},
{117, "Dark Grey"},
{118, "Dark Grey Metal"},
{119, "Dark Grey Gloss"},
{120, "Black"},
{121, "Black Metal"},
{122, "Black Gloss"},
{123, "Red"},
{124, "Red Metal"},
{125, "Red Gloss"},
{126, "Dark Red"},
{127, "Dark Red Metal"},
{128, "Dark Red Gloss"},
{129, "Orange"},
{130, "Orange Metal"},
{131, "Orange Gloss"},
{132, "Dark Orange"},
{133, "Dark Orange Metal"},
{134, "Dark Orange Gloss"},
{135, "Yellow"},
{136, "Yellow Metal"},
{137, "Yellow Gloss"},
{138, "Brown"},
{139, "Brown Metal"},
{140, "Brown Gloss"},
{141, "Dark Brown"},
{142, "Dark Brown Metal"},
{143, "Dark Brown Gloss"},
{144, "Leafgreen"},
{145, "Leafgreen Metal"},
{146, "Leafgreen Gloss"},
{147, "Military Green"},
{148, "Military Green Metal"},
{149, "Military Green Gloss"},
{150, "Green"},
{151, "Green Metal"},
{152, "Green Gloss"},
{153, "Dark Green"},
{154, "Dark Green Metal"},
{155, "Dark Green Gloss"},
{156, "Teal"},
{157, "Teal Metal"},
{158, "Teal Gloss"},
{159, "Cyan"},
{160, "Cyan Metal"},
{161, "Cyan Gloss"},
{162, "Blue"},
{163, "Blue Metal"},
{164, "Blue Gloss"},
{165, "Blue Sky"},
{166, "Blue Sky Metal"},
{167, "Blue Sky Gloss"},
{168, "Dark Blue"},
{169, "Dark Blue Metal"},
{170, "Dark Blue Gloss"},
{171, "Purple"},
{172, "Purple Metal"},
{173, "Purple Gloss"},
{174, "Dark Purple"},
{175, "Dark Purple Metal"},
{176, "Dark Purple Gloss"},
{177, "Pink"},
{178, "Pink Metal"},
{179, "Pink Gloss"},
{180, "Rosy Brown"},
{181, "Rosy Brown Metal"},
{182, "Rosy Brown Gloss"},
{183, "Ivory"},
{184, "Ivory Metal"},
{185, "Ivory Gloss"},
{186, "Slate Brown"},
{187, "Slate Brown Metal"},
{188, "Slate Brown Gloss"},
{189, "Slate Green"},
{190, "Slate Green Metal"},
{191, "Slate Green Gloss"},
{192, "Slate Blue"},
{193, "Slate Blue Metal"},
{194, "Slate Blue Gloss"},
{195, "Slate Purple"},
{196, "Slate Purple Metal"},
{197, "Slate Purple Gloss"},
{198, "White Glow"},
{199, "White Radiance"},
{200, "Red Glow"},
{201, "Red Radiance"},
{202, "Orange Glow"},
{203, "Orange Radiance"},
{204, "Yellow Glow"},
{205, "Yellow Radiance"},
{206, "Leafgreen Glow"},
{207, "Leafgreen Radiance"},
{208, "Green Glow"},
{209, "Green Radiance"},
{210, "Teal Glow"},
{211, "Teal Radiance"},
{212, "Cyan Glow"},
{213, "Cyan Radiance"},
{214, "Blue Glow"},
{215, "Blue Radiance"},
{216, "Purple Glow"},
{217, "Purple Radiance"},
{218, "Pink Glow"},
{219, "Pink Radiance"},
{220, "Grey Camo"},
{221, "Dark Grey Camo"},
{222, "Green Camo"},
{223, "Dark Green Camo"},
{224, "Brown Camo"},
{225, "Dark Brown Camo"},
{226, "Blue Camo"},
{227, "Dark Blue Camo"},
};

View file

@ -18,3 +18,5 @@
constexpr char mass_name_locator[] = "Name_45_A037C5D54E53456407BDF091344529BB\0\f\0\0\0StrProperty";
constexpr char steamid_locator[] = "Account\0\f\0\0\0StrProperty";
constexpr char frame_styles_locator[] = "Styles_32_00A3B3284B37F1E7819458844A20EB48\0\x0e\0\0\0ArrayProperty\0\x14\0\0\0\0\0\0\0\f\0\0\0IntProperty\0\0\x04\0\0\0";

View file

@ -25,31 +25,13 @@
#include "Mass.h"
using namespace Corrade;
std::string Mass::_lastError;
Mass::Mass(const std::string& path) {
_folder = Utility::Directory::path(path);
_filename = Utility::Directory::filename(path);
if(!Utility::Directory::exists(path)) {
_lastError = path + " couldn't be found.";
return;
}
auto mmap = Utility::Directory::mapRead(path);
auto iter = std::search(mmap.begin(), mmap.end(), &mass_name_locator[0], &mass_name_locator[56]);
if(iter != mmap.end()) {
_name = std::string{iter + 70};
_state = MassState::Valid;
}
else {
_lastError = "The name couldn't be found in " + _filename;
_state = MassState::Invalid;
}
refreshValues();
}
auto Mass::lastError() -> std::string const& {
@ -78,6 +60,16 @@ auto Mass::getNameFromFile(const std::string& path) -> std::string {
return name;
}
void Mass::refreshValues() {
getName();
if(_state != State::Valid) {
return;
}
getFrameStyles();
}
auto Mass::filename() -> std::string const&{
return _filename;
}
@ -86,16 +78,51 @@ auto Mass::name() -> std::string const&{
return _name;
}
auto Mass::state() -> MassState {
auto Mass::state() -> State {
return _state;
}
auto Mass::frameStyles() -> Containers::StaticArrayView<4, Int> {
return _frameStyles;
}
auto Mass::setFrameStyle(Int index, Int style_id) -> bool {
if(index < 0 || index > 3) {
_lastError = "Index is out of range in Mass::setFrameStyle().";
return false;
}
std::string path = Utility::Directory::join(_folder, _filename);
if(!Utility::Directory::exists(path)) {
_lastError = path + " couldn't be found.";
_state = State::Empty;
return false;
}
auto mmap = Utility::Directory::map(path);
auto iter = std::search(mmap.begin(), mmap.end(), &frame_styles_locator[0], &frame_styles_locator[90]);
if(iter != mmap.end()) {
iter += 0x5A;
*(reinterpret_cast<Int*>(iter) + index) = style_id;
}
else {
_lastError = "Frame styles couldn't be found in " + path;
_state = State::Invalid;
return false;
}
return true;
}
auto Mass::updateSteamId(const std::string& steam_id) -> bool {
std::string path = Utility::Directory::join(_folder, _filename);
if(!Utility::Directory::exists(path)) {
_lastError = path + " couldn't be found.";
_state = MassState::Empty;
_state = State::Empty;
return false;
}
@ -129,3 +156,49 @@ auto Mass::updateSteamId(const std::string& steam_id) -> bool {
return true;
}
void Mass::getName() {
std::string path = Utility::Directory::join(_folder, _filename);
if(!Utility::Directory::exists(path)) {
_lastError = path + " couldn't be found.";
_state = State::Empty;
return;
}
auto mmap = Utility::Directory::mapRead(path);
auto iter = std::search(mmap.begin(), mmap.end(), &mass_name_locator[0], &mass_name_locator[56]);
if(iter != mmap.end()) {
_name = std::string{iter + 70};
_state = State::Valid;
}
else {
_lastError = "The name couldn't be found in " + _filename;
_state = State::Invalid;
}
}
void Mass::getFrameStyles() {
std::string path = Utility::Directory::join(_folder, _filename);
if(!Utility::Directory::exists(path)) {
_lastError = path + " couldn't be found.";
_state = State::Empty;
return;
}
auto mmap = Utility::Directory::mapRead(path);
auto iter = std::search(mmap.begin(), mmap.end(), &frame_styles_locator[0], &frame_styles_locator[90]);
if(iter != mmap.end()) {
iter += 0x5A;
std::copy(reinterpret_cast<const Int*>(iter), reinterpret_cast<const Int*>(iter) + 4, _frameStyles.data());
}
else {
_lastError = "Frame styles couldn't be found in " + path;
_state = State::Invalid;
}
}

View file

@ -18,16 +18,20 @@
#include <string>
#include <Corrade/Containers/StaticArray.h>
#include <Magnum/Magnum.h>
using namespace Corrade;
using namespace Magnum;
enum class MassState : UnsignedByte {
Empty, Invalid, Valid
};
class Mass {
public:
enum class State : UnsignedByte {
Empty, Invalid, Valid
};
explicit Mass(const std::string& path);
Mass(const Mass&) = delete;
@ -40,19 +44,29 @@ class Mass {
static auto getNameFromFile(const std::string& path) -> std::string;
void refreshValues();
auto filename() -> std::string const&;
auto name() -> std::string const&;
auto state() -> MassState;
auto state() -> State;
auto frameStyles() -> Containers::StaticArrayView<4, Int>;
auto setFrameStyle(Int index, Int style_id) -> bool;
auto updateSteamId(const std::string& steam_id) -> bool;
private:
void getName();
void getFrameStyles();
static std::string _lastError;
std::string _folder;
std::string _filename;
std::string _name;
MassState _state = MassState::Empty;
State _state = State::Empty;
Containers::StaticArray<4, Int> _frameStyles;
};

View file

@ -104,7 +104,7 @@ auto MassManager::exportMass(int hangar) -> bool {
return false;
}
if(_hangars[hangar].state() != MassState::Valid) {
if(_hangars[hangar].state() != Mass::State::Valid) {
_lastError = Utility::formatString("There is no valid data to export in hangar {:.2d}", hangar + 1);
return false;
}
@ -134,22 +134,22 @@ auto MassManager::moveMass(int source, int destination) -> bool {
std::string source_file = _hangars[source].filename();
std::string dest_file = _hangars[destination].filename();
MassState dest_state = _hangars[destination].state();
Mass::State dest_state = _hangars[destination].state();
switch(dest_state) {
case MassState::Empty:
case Mass::State::Empty:
break;
case MassState::Invalid:
case Mass::State::Invalid:
Utility::Directory::rm(dest_file);
break;
case MassState::Valid:
case Mass::State::Valid:
Utility::Directory::move(dest_file, dest_file + ".tmp");
break;
}
Utility::Directory::move(source_file, dest_file);
if(dest_state == MassState::Valid) {
if(dest_state == Mass::State::Valid) {
Utility::Directory::move(dest_file + ".tmp", source_file);
}

View file

@ -88,10 +88,12 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
void drawMainMenu();
void drawDisclaimer();
void drawInitialisation();
void drawProfileManager();
auto drawBackupListPopup() -> ImGuiID;
auto drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID;
auto drawDeleteProfilePopup(std::size_t profile_index) -> ImGuiID;
void drawManager();
auto drawIntEditPopup(int* value_to_edit, int max) -> bool;
auto drawRenamePopup(Containers::ArrayView<char> name_view) -> bool;
@ -100,7 +102,9 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
void drawMassManager();
auto drawDeleteMassPopup(int mass_index) -> ImGuiID;
auto drawDeleteStagedMassPopup(const std::string& filename) -> ImGuiID;
void drawMassViewer();
void drawAbout();
void drawGameState();

View file

@ -19,6 +19,12 @@
#include "SaveTool.h"
void SaveTool::drawMassViewer() {
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
_currentMass = nullptr;
_uiState = UiState::MainManager;
return;
}
ImGui::SetNextWindowPos({0.0f, ImGui::GetItemRectSize().y}, ImGuiCond_Always);
ImGui::SetNextWindowSize({Float(windowSize().x()), Float(windowSize().y()) - ImGui::GetItemRectSize().y},
ImGuiCond_Always);
@ -40,5 +46,42 @@ void SaveTool::drawMassViewer() {
_uiState = UiState::MainManager;
}
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
ImGui::SameLine();
ImGui::TextWrapped("WARNING: Colours in this app may look different from in-game colours, due to unavoidable differences in the rendering pipeline.");
if(ImGui::BeginChild("##MassInfo",
{ImGui::GetContentRegionAvailWidth() * 0.60f, 0.0f},
true, ImGuiWindowFlags_MenuBar))
{
if(ImGui::BeginMenuBar()) {
ImGui::TextUnformatted("M.A.S.S. Information");
ImGui::EndMenuBar();
}
if(ImGui::BeginTabBar("##MassTabBar")) {
if(ImGui::BeginTabItem("Frame")) {
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
ImGui::EndChild();
ImGui::SameLine();
if(ImGui::BeginChild("##GlobalStyles", {0.0f, 0.0f},
true, ImGuiWindowFlags_MenuBar))
{
if(ImGui::BeginMenuBar()) {
ImGui::TextUnformatted("Global styles");
ImGui::EndMenuBar();
}
ImGui::TextUnformatted("Placeholder");
}
ImGui::EndChild();
ImGui::End();
}