Compare commits
6 commits
597e9dfe98
...
a9a5bfb2af
Author | SHA1 | Date | |
---|---|---|---|
a9a5bfb2af | |||
5f4576a2bc | |||
f3318e0ed1 | |||
7fcf8b518e | |||
69021eacdf | |||
bd6e55826d |
8 changed files with 323 additions and 32 deletions
|
@ -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
154
src/Maps/StyleNames.h
Normal 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"},
|
||||
};
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue