Compare commits
26 commits
Author | SHA1 | Date | |
---|---|---|---|
ad6e39d22a | |||
3e98f8c8b0 | |||
5e2ca5e65b | |||
22f0dc1424 | |||
4dfc847113 | |||
57f1a3ccef | |||
826f53c26b | |||
71ca5d7625 | |||
7540f9c152 | |||
f77fde3aff | |||
90a3dc65bf | |||
08de4ef475 | |||
a3c2865e68 | |||
e425c81db6 | |||
6aba2bf8c5 | |||
f322cf4ab2 | |||
74e99d22b1 | |||
0e9b11b850 | |||
9629047fbc | |||
9469518a4e | |||
1337329efb | |||
f11c7828e5 | |||
3fb294ca4a | |||
c8daeb0656 | |||
c14673ad14 | |||
8cd43c2a89 |
32 changed files with 277 additions and 996 deletions
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -22,10 +22,6 @@
|
|||
path = third-party/libzip
|
||||
url = https://github.com/nih-at/libzip
|
||||
branch = main
|
||||
[submodule "efsw"]
|
||||
path = third-party/efsw
|
||||
url = https://github.com/SpartanJ/efsw
|
||||
branch = master
|
||||
[submodule "libcurl"]
|
||||
path = third-party/curl
|
||||
url = https://github.com/curl/curl
|
||||
|
|
|
@ -27,7 +27,6 @@ include(CMakeDependentOption)
|
|||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_CORRADE_MAGNUM "Use system-wide versions of Corrade and Magnum." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_SDL2 "Use a system-wide version of SDL2." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_LIBZIP "Use a system-wide version of libzip." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_EFSW "Use a system-wide version of EFSW." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_LIBCURL "Use a system-wide version of libcurl." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
|
||||
if(NOT SAVETOOL_USE_SYSTEM_LIBS OR NOT (SAVETOOL_USE_SYSTEM_CORRADE_MAGNUM AND SAVETOOL_USE_SYSTEM_SDL2 AND SAVETOOL_USE_SYSTEM_LIBZIP AND SAVETOOL_USE_SYSTEM_EFSW AND SAVETOOL_USE_SYSTEM_LIBCURL))
|
||||
|
@ -114,13 +113,6 @@ if(NOT SAVETOOL_USE_SYSTEM_LIBZIP)
|
|||
add_subdirectory(third-party/libzip EXCLUDE_FROM_ALL)
|
||||
endif(NOT SAVETOOL_USE_SYSTEM_LIBZIP)
|
||||
|
||||
if(NOT SAVETOOL_USE_SYSTEM_EFSW)
|
||||
set(VERBOSE OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_TEST_APP OFF CACHE BOOL "" FORCE)
|
||||
set(EFSW_INSTALL OFF CACHE BOOL "" FORCE)
|
||||
add_subdirectory(third-party/efsw EXCLUDE_FROM_ALL)
|
||||
endif(NOT SAVETOOL_USE_SYSTEM_EFSW)
|
||||
|
||||
if(NOT SAVETOOL_USE_SYSTEM_LIBCURL)
|
||||
set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE)
|
||||
set(ENABLE_UNICODE ON CACHE BOOL "" FORCE)
|
||||
|
|
|
@ -92,7 +92,6 @@ Application::Application(const Arguments& arguments):
|
|||
}
|
||||
|
||||
_updateEventId = _initEventId + 1;
|
||||
_fileEventId = _initEventId + 2;
|
||||
|
||||
LOG_INFO("Initialising the timer subsystem.");
|
||||
if(SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
|
||||
|
@ -191,23 +190,23 @@ Application::keyReleaseEvent(KeyEvent& event) {
|
|||
}
|
||||
|
||||
void
|
||||
Application::mousePressEvent(MouseEvent& event) {
|
||||
if(_imgui.handleMousePressEvent(event)) return;
|
||||
Application::pointerPressEvent(PointerEvent& event) {
|
||||
if(_imgui.handlePointerPressEvent(event)) return;
|
||||
}
|
||||
|
||||
void
|
||||
Application::mouseReleaseEvent(MouseEvent& event) {
|
||||
if(_imgui.handleMouseReleaseEvent(event)) return;
|
||||
Application::pointerReleaseEvent(PointerEvent& event) {
|
||||
if(_imgui.handlePointerReleaseEvent(event)) return;
|
||||
}
|
||||
|
||||
void
|
||||
Application::mouseMoveEvent(MouseMoveEvent& event) {
|
||||
if(_imgui.handleMouseMoveEvent(event)) return;
|
||||
Application::pointerMoveEvent(PointerMoveEvent& event) {
|
||||
if(_imgui.handlePointerMoveEvent(event)) return;
|
||||
}
|
||||
|
||||
void
|
||||
Application::mouseScrollEvent(MouseScrollEvent& event) {
|
||||
if(_imgui.handleMouseScrollEvent(event)) {
|
||||
Application::scrollEvent(ScrollEvent& event) {
|
||||
if(_imgui.handleScrollEvent(event)) {
|
||||
event.setAccepted();
|
||||
return;
|
||||
}
|
||||
|
@ -226,9 +225,6 @@ Application::anyEvent(SDL_Event& event) {
|
|||
else if(event.type == _updateEventId) {
|
||||
updateCheckEvent(event);
|
||||
}
|
||||
else if(event.type == _fileEventId) {
|
||||
fileUpdateEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <Corrade/Containers/Pointer.h>
|
||||
|
@ -35,8 +34,6 @@
|
|||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <efsw/efsw.hpp>
|
||||
|
||||
#include "../Managers/BackupManager.h"
|
||||
#include "../Managers/MassManager.h"
|
||||
#include "../Managers/ProfileManager.h"
|
||||
|
@ -54,17 +51,11 @@ using namespace Magnum;
|
|||
|
||||
namespace mbst {
|
||||
|
||||
class Application: public Platform::Sdl2Application, public efsw::FileWatchListener {
|
||||
class Application: public Platform::Sdl2Application {
|
||||
public:
|
||||
explicit Application(const Arguments& arguments);
|
||||
|
||||
~Application() override;
|
||||
|
||||
void handleFileAction(efsw::WatchID watch_id,
|
||||
const std::string& dir,
|
||||
const std::string& filename,
|
||||
efsw::Action action,
|
||||
std::string old_filename) override;
|
||||
virtual ~Application();
|
||||
|
||||
private:
|
||||
// Events
|
||||
|
@ -74,10 +65,10 @@ class Application: public Platform::Sdl2Application, public efsw::FileWatchListe
|
|||
void keyPressEvent(KeyEvent& event) override;
|
||||
void keyReleaseEvent(KeyEvent& event) override;
|
||||
|
||||
void mousePressEvent(MouseEvent& event) override;
|
||||
void mouseReleaseEvent(MouseEvent& event) override;
|
||||
void mouseMoveEvent(MouseMoveEvent& event) override;
|
||||
void mouseScrollEvent(MouseScrollEvent& event) override;
|
||||
void pointerPressEvent(PointerEvent& event) override;
|
||||
void pointerReleaseEvent(PointerEvent& event) override;
|
||||
void pointerMoveEvent(PointerMoveEvent& event) override;
|
||||
void scrollEvent(ScrollEvent& event) override;
|
||||
void textInputEvent(TextInputEvent& event) override;
|
||||
|
||||
void anyEvent(SDL_Event& event) override;
|
||||
|
@ -90,21 +81,11 @@ class Application: public Platform::Sdl2Application, public efsw::FileWatchListe
|
|||
|
||||
void updateCheckEvent(SDL_Event& event);
|
||||
|
||||
enum FileEventType: std::int32_t {
|
||||
FileAdded = efsw::Action::Add,
|
||||
FileDeleted = efsw::Action::Delete,
|
||||
FileModified = efsw::Action::Modified,
|
||||
FileMoved = efsw::Action::Moved,
|
||||
StagedUpdate = 1 << 3
|
||||
};
|
||||
void fileUpdateEvent(SDL_Event& event);
|
||||
|
||||
// Initialisation methods
|
||||
void initialiseConfiguration();
|
||||
void initialiseGui();
|
||||
void initialiseManager();
|
||||
void initialiseMassManager();
|
||||
void initialiseFileWatcher();
|
||||
|
||||
// GUI-related methods
|
||||
void drawImGui();
|
||||
|
@ -140,9 +121,9 @@ class Application: public Platform::Sdl2Application, public efsw::FileWatchListe
|
|||
void drawBLAttachment();
|
||||
void drawCustomArmourStyles();
|
||||
void drawWeapons();
|
||||
void drawWeaponCategory(Containers::StringView name, Containers::ArrayView<GameObjects::Weapon> weapons_view,
|
||||
bool& dirty, Containers::StringView payload_type,
|
||||
Containers::StringView payload_tooltip);
|
||||
void drawWeaponCategory(Containers::StringView name, GameObjects::Weapon::Type category,
|
||||
Containers::ArrayView<GameObjects::Weapon> weapons_view,
|
||||
Containers::StringView payload_type, Containers::StringView payload_tooltip);
|
||||
void drawWeaponEditor(GameObjects::Weapon& weapon);
|
||||
void drawGlobalStyles();
|
||||
void drawTuning();
|
||||
|
@ -186,6 +167,7 @@ class Application: public Platform::Sdl2Application, public efsw::FileWatchListe
|
|||
|
||||
template<typename Functor, typename... Args>
|
||||
bool drawUnsafeWidget(Functor func, Args... args) {
|
||||
static_assert(std::is_invocable_r_v<bool, Functor, Args...>);
|
||||
GameState game_state = _gameState; // Copying the value to reduce the risk of a data race.
|
||||
ImGui::BeginDisabled(game_state != GameState::NotRunning);
|
||||
bool result = func(std::forward<Args>(args)...);
|
||||
|
@ -243,7 +225,6 @@ class Application: public Platform::Sdl2Application, public efsw::FileWatchListe
|
|||
|
||||
std::uint32_t _initEventId;
|
||||
std::uint32_t _updateEventId;
|
||||
std::uint32_t _fileEventId;
|
||||
|
||||
Containers::String _lastError;
|
||||
|
||||
|
@ -265,26 +246,12 @@ class Application: public Platform::Sdl2Application, public efsw::FileWatchListe
|
|||
|
||||
GameObjects::Weapon* _currentWeapon = nullptr;
|
||||
|
||||
Containers::Pointer<efsw::FileWatcher> _fileWatcher;
|
||||
enum watchID {
|
||||
SaveDir = 0,
|
||||
StagingDir = 1
|
||||
};
|
||||
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
||||
|
||||
Containers::Optional<UpdateChecker> _checker{Containers::NullOpt};
|
||||
std::mutex _checkerMutex;
|
||||
|
||||
bool _modifiedBySaveTool = false;
|
||||
bool _jointsDirty = false;
|
||||
bool _stylesDirty = false;
|
||||
bool _eyeFlareDirty = false;
|
||||
bool _meleeDirty = false;
|
||||
bool _shieldsDirty = false;
|
||||
bool _bShootersDirty = false;
|
||||
bool _eShootersDirty = false;
|
||||
bool _bLaunchersDirty = false;
|
||||
bool _eLaunchersDirty = false;
|
||||
|
||||
Containers::Optional<std::size_t> _selectedArmourSlot{Containers::NullOpt};
|
||||
Containers::StaticArray<38, std::int32_t> _selectedArmourDecals{ValueInit};
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
// 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/Utility/Format.h>
|
||||
#include <Corrade/Utility/String.h>
|
||||
#include <Corrade/Utility/Unicode.h>
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_messagebox.h>
|
||||
|
||||
#include <fileapi.h>
|
||||
#include <handleapi.h>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
namespace mbst {
|
||||
|
||||
void
|
||||
Application::handleFileAction(efsw::WatchID watch_id, const std::string&, const std::string& filename,
|
||||
efsw::Action action, std::string old_filename)
|
||||
{
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
event.type = _fileEventId;
|
||||
|
||||
event.user.data1 = Containers::String{Containers::AllocatedInit, filename.c_str()}.release();
|
||||
|
||||
if(watch_id == _watchIDs[StagingDir] && Utility::String::endsWith(filename, ".sav")) {
|
||||
event.user.code = StagedUpdate | action;
|
||||
SDL_PushEvent(&event);
|
||||
return;
|
||||
}
|
||||
|
||||
if(Utility::String::endsWith(filename, "Config.sav")) {
|
||||
return;
|
||||
} // TODO: actually do something when config files will finally be handled
|
||||
|
||||
if(!Utility::String::endsWith(filename, Utility::format("Profile{}.sav", _currentProfile->account()).data()) &&
|
||||
filename.find("Unit") == std::string::npos)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
event.user.code = action;
|
||||
if(action == efsw::Actions::Moved) {
|
||||
event.user.data2 = Containers::String{Containers::AllocatedInit, old_filename.c_str()}.release();
|
||||
}
|
||||
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
void
|
||||
Application::fileUpdateEvent(SDL_Event& event) {
|
||||
Containers::String filename{static_cast<char*>(event.user.data1),
|
||||
std::strlen(static_cast<char*>(event.user.data1)), nullptr};
|
||||
|
||||
if((event.user.code & StagedUpdate) == StagedUpdate) {
|
||||
_stagedMassManager->refreshMass(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
Containers::String old_filename;
|
||||
|
||||
std::int32_t index = 0;
|
||||
std::int32_t old_index = 0;
|
||||
bool is_current_profile = filename == _currentProfile->filename();
|
||||
bool is_unit = filename.hasPrefix(_currentProfile->isDemo() ? "DemoUnit"_s : "Unit"_s);
|
||||
if(is_unit) {
|
||||
index = ((filename[_currentProfile->isDemo() ? 8 : 4] - 0x30) * 10) +
|
||||
(filename[_currentProfile->isDemo() ? 9 : 5] - 0x30);
|
||||
}
|
||||
|
||||
if(event.user.code == FileMoved) {
|
||||
old_filename = Containers::String{static_cast<char*>(event.user.data2),
|
||||
std::strlen(static_cast<char*>(event.user.data2)), nullptr};
|
||||
old_index = ((old_filename[_currentProfile->isDemo() ? 8 : 4] - 0x30) * 10) +
|
||||
(old_filename[_currentProfile->isDemo() ? 9 : 5] - 0x30);
|
||||
}
|
||||
|
||||
switch(event.user.code) {
|
||||
case FileAdded:
|
||||
if(is_unit) {
|
||||
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
|
||||
_massManager->refreshHangar(index);
|
||||
}
|
||||
else {
|
||||
_currentMass->setDirty();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FileDeleted:
|
||||
if(is_current_profile) {
|
||||
_currentProfile = nullptr;
|
||||
_uiState = UiState::ProfileManager;
|
||||
if(!_profileManager->refreshProfiles()) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_profileManager->lastError().data(), window());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else if(is_unit) {
|
||||
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
|
||||
_massManager->refreshHangar(index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FileModified:
|
||||
if(is_current_profile) {
|
||||
_currentProfile->refreshValues();
|
||||
}
|
||||
else if(is_unit) {
|
||||
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
|
||||
_massManager->refreshHangar(index);
|
||||
}
|
||||
else {
|
||||
if(_modifiedBySaveTool && _currentMass->filename() == filename) {
|
||||
auto handle = CreateFileW(Utility::Unicode::widen(Containers::StringView{filename}),
|
||||
GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if(handle && handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle);
|
||||
_modifiedBySaveTool = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
_currentMass->setDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FileMoved:
|
||||
if(is_unit) {
|
||||
if(old_filename.hasSuffix(".sav"_s)) {
|
||||
_massManager->refreshHangar(index);
|
||||
_massManager->refreshHangar(old_index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_queue.addToast(Toast::Type::Warning, "Unknown file action type"_s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include <cstring>
|
||||
|
||||
#include <Magnum/Math/Time.h>
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include <SDL_messagebox.h>
|
||||
|
||||
|
@ -52,7 +54,8 @@ Application::initialiseConfiguration() {
|
|||
LOG_INFO("Reading configuration file.");
|
||||
|
||||
setSwapInterval(conf().swapInterval());
|
||||
setMinimalLoopPeriod(0);
|
||||
using namespace Math::Literals;
|
||||
setMinimalLoopPeriod(0_nsec);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -119,8 +122,6 @@ Application::initialiseManager() {
|
|||
|
||||
_backupManager.emplace();
|
||||
|
||||
_stagedMassManager.emplace();
|
||||
|
||||
event.user.code = InitSuccess;
|
||||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
@ -129,15 +130,8 @@ void
|
|||
Application::initialiseMassManager() {
|
||||
LOG_INFO("Initialising the M.A.S.S. manager.");
|
||||
_massManager.emplace(_currentProfile->account(), _currentProfile->isDemo());
|
||||
}
|
||||
|
||||
void
|
||||
Application::initialiseFileWatcher() {
|
||||
LOG_INFO("Initialising the file watcher.");
|
||||
_fileWatcher.emplace();
|
||||
_watchIDs[SaveDir] = _fileWatcher->addWatch(conf().directories().gameSaves, this, false);
|
||||
_watchIDs[StagingDir] = _fileWatcher->addWatch(conf().directories().staging, this, false);
|
||||
_fileWatcher->watch();
|
||||
LOG_INFO("Initialising the staged M.A.S.S. manager.");
|
||||
_stagedMassManager.emplace();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,9 +55,20 @@ Application::drawManager() {
|
|||
if(ImGui::Button(ICON_FA_ARROW_LEFT " Back to profile manager")) {
|
||||
_currentProfile = nullptr;
|
||||
_massManager.reset();
|
||||
_fileWatcher.reset();
|
||||
_stagedMassManager.reset();
|
||||
_uiState = UiState::ProfileManager;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button(ICON_FA_SYNC_ALT " Refresh external changes")) {
|
||||
_currentProfile->refreshValues();
|
||||
if(!_currentProfile->valid()) {
|
||||
_currentProfile = nullptr;
|
||||
_profileManager->refreshProfiles();
|
||||
_queue.addToast(Toast::Type::Error, "The current profile isn't valid anymore."_s);
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(ImGui::BeginChild("##ProfileInfo",
|
||||
{ImGui::GetContentRegionAvail().x * 0.60f, 0.0f},
|
||||
|
@ -93,6 +104,11 @@ Application::drawManager() {
|
|||
if(ImGui::BeginMenuBar()) {
|
||||
ImGui::TextUnformatted("M.A.S.S. management");
|
||||
drawHelpMarker("To move, import, or export builds, drag-and-drop them.");
|
||||
if(ImGui::SmallButton(ICON_FA_SYNC_ALT " Refresh")) {
|
||||
for(int i = 0; i < 32 ; i++) {
|
||||
_massManager->refreshHangar(i);
|
||||
}
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
|
@ -527,10 +543,13 @@ Application::drawMassManager() {
|
|||
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::TextUnformatted("Staging area");
|
||||
ImGui::SameLine();
|
||||
if(ImGui::SmallButton(ICON_FA_FOLDER_OPEN " Open staging folder")) {
|
||||
openUri(Utility::Path::toNativeSeparators(conf().directories().staging));
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::SmallButton(ICON_FA_SYNC_ALT " Refresh")) {
|
||||
_stagedMassManager->refresh();
|
||||
}
|
||||
|
||||
for(const auto& mass : _stagedMassManager->stagedMasses()) {
|
||||
ImGui::TableNextRow();
|
||||
|
@ -575,6 +594,7 @@ Application::drawMassManager() {
|
|||
if(!_massManager->exportMass(index)) {
|
||||
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
||||
}
|
||||
_stagedMassManager->refresh();
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include "../GameData/Accessories.h"
|
||||
#define STYLENAMES_DEFINITION
|
||||
#include "../GameData/StyleNames.h"
|
||||
#include "../ImportExport/Export.h"
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
|
@ -73,16 +72,12 @@ Application::drawMassViewer() {
|
|||
drawTooltip(_currentMass->filename());
|
||||
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
if(_currentMass->dirty()) {
|
||||
ImGui::TextUnformatted("External changes detected");
|
||||
ImGui::SameLine();
|
||||
if(ImGui::SmallButton(ICON_FA_SYNC_ALT " Refresh")) {
|
||||
_currentMass->refreshValues();
|
||||
_currentMass->setDirty(false);
|
||||
_jointsDirty = false;
|
||||
_stylesDirty = false;
|
||||
_eyeFlareDirty = false;
|
||||
}
|
||||
if(ImGui::SmallButton(ICON_FA_SYNC_ALT " Refresh external changes")) {
|
||||
_currentMass->refreshValues();
|
||||
_currentMass->setDirty(false);
|
||||
_jointsDirty = false;
|
||||
_stylesDirty = false;
|
||||
_eyeFlareDirty = false;
|
||||
}
|
||||
|
||||
ImGui::TableSetColumnIndex(3);
|
||||
|
@ -191,9 +186,7 @@ Application::drawGlobalStyles() {
|
|||
_currentMass->getGlobalStyles();
|
||||
break;
|
||||
case DCS_Save:
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeGlobalStyle(i)) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
// 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 <imgui_internal.h>
|
||||
|
||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||
|
@ -197,9 +199,7 @@ Application::drawArmour() {
|
|||
ImGui::EndChild();
|
||||
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeArmourPart(part.slot)) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
}
|
||||
|
@ -357,11 +357,8 @@ Application::drawBLAttachment() {
|
|||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
_modifiedBySaveTool = true;
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeBulletLauncherAttachments()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
}
|
||||
|
@ -388,9 +385,7 @@ Application::drawCustomArmourStyles() {
|
|||
_currentMass->getArmourCustomStyles();
|
||||
break;
|
||||
case DCS_Save:
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeArmourCustomStyle(i)) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -149,9 +149,7 @@ Application::drawJointSliders() {
|
|||
}
|
||||
else {
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeJointSliders()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
_jointsDirty = false;
|
||||
|
@ -206,9 +204,7 @@ Application::drawFrameStyles() {
|
|||
}
|
||||
else {
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeFrameStyles()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
_stylesDirty = false;
|
||||
|
@ -240,9 +236,7 @@ Application::drawEyeColourPicker() {
|
|||
}
|
||||
else {
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeEyeFlareColour()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
_eyeFlareDirty = false;
|
||||
|
@ -276,9 +270,7 @@ Application::drawCustomFrameStyles() {
|
|||
_currentMass->getFrameCustomStyles();
|
||||
break;
|
||||
case DCS_Save:
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeFrameCustomStyle(i)) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "../GameData/WeaponParts.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "../Configuration/Configuration.h"
|
||||
|
||||
namespace mbst {
|
||||
|
||||
|
@ -32,13 +33,11 @@ Application::drawWeapons() {
|
|||
return;
|
||||
}
|
||||
|
||||
const float footer_height_to_reserve = ImGui::GetFrameHeightWithSpacing();
|
||||
|
||||
ImGui::BeginGroup();
|
||||
|
||||
if(!ImGui::BeginTable("##WeaponsList", 1,
|
||||
ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_BordersInnerH,
|
||||
{ImGui::GetContentRegionAvail().x * 0.2f, -footer_height_to_reserve}))
|
||||
{ImGui::GetContentRegionAvail().x * 0.2f, 0.0f}))
|
||||
{
|
||||
ImGui::EndGroup();
|
||||
return;
|
||||
|
@ -46,118 +45,20 @@ Application::drawWeapons() {
|
|||
|
||||
ImGui::TableSetupColumn("Weapon");
|
||||
|
||||
drawWeaponCategory("Melee weapons", _currentMass->meleeWeapons(), _meleeDirty, "MeleeWeapon", "Melee weapon");
|
||||
drawWeaponCategory("Shield", _currentMass->shields(), _shieldsDirty, "Shield", "Shield");
|
||||
drawWeaponCategory("Bullet shooters", _currentMass->bulletShooters(), _bShootersDirty, "BShooter", "Bullet shooter");
|
||||
drawWeaponCategory("Energy shooters", _currentMass->energyShooters(), _eShootersDirty, "EShooter", "Energy shooter");
|
||||
drawWeaponCategory("Bullet launchers", _currentMass->bulletLaunchers(), _bLaunchersDirty, "BLauncher", "Bullet launcher");
|
||||
drawWeaponCategory("Energy launchers", _currentMass->energyLaunchers(), _eLaunchersDirty, "ELauncher", "Energy launcher");
|
||||
drawWeaponCategory("Melee weapons", GameObjects::Weapon::Type::Melee, _currentMass->meleeWeapons(), "MeleeWeapon",
|
||||
"Melee weapon");
|
||||
drawWeaponCategory("Shield", GameObjects::Weapon::Type::Shield, _currentMass->shields(), "Shield", "Shield");
|
||||
drawWeaponCategory("Bullet shooters", GameObjects::Weapon::Type::BulletShooter, _currentMass->bulletShooters(),
|
||||
"BShooter", "Bullet shooter");
|
||||
drawWeaponCategory("Energy shooters", GameObjects::Weapon::Type::EnergyShooter, _currentMass->energyShooters(),
|
||||
"EShooter", "Energy shooter");
|
||||
drawWeaponCategory("Bullet launchers", GameObjects::Weapon::Type::BulletLauncher, _currentMass->bulletLaunchers(),
|
||||
"BLauncher", "Bullet launcher");
|
||||
drawWeaponCategory("Energy launchers", GameObjects::Weapon::Type::EnergyLauncher, _currentMass->energyLaunchers(),
|
||||
"ELauncher", "Energy launcher");
|
||||
|
||||
ImGui::EndTable();
|
||||
|
||||
bool dirty = _meleeDirty || _shieldsDirty || _bShootersDirty || _eShootersDirty || _bLaunchersDirty || _eLaunchersDirty;
|
||||
|
||||
ImGui::BeginDisabled(!dirty);
|
||||
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save order"); })) {
|
||||
if(_meleeDirty) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeMeleeWeapons()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
else {
|
||||
_meleeDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(_shieldsDirty) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeShields()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
else {
|
||||
_shieldsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(_bShootersDirty) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeBulletShooters()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
else {
|
||||
_bShootersDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(_eShootersDirty) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(_currentMass->writeEnergyShooters()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
else {
|
||||
_eShootersDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(_bLaunchersDirty) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(_currentMass->writeBulletLaunchers()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
else {
|
||||
_bLaunchersDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(_eLaunchersDirty) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(_currentMass->writeEnergyLaunchers()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
else {
|
||||
_eLaunchersDirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset")) {
|
||||
if(_meleeDirty) {
|
||||
_currentMass->getMeleeWeapons();
|
||||
_meleeDirty = false;
|
||||
}
|
||||
if(_shieldsDirty) {
|
||||
_currentMass->getShields();
|
||||
_shieldsDirty = false;
|
||||
}
|
||||
if(_bShootersDirty) {
|
||||
_currentMass->getBulletShooters();
|
||||
_bShootersDirty = false;
|
||||
}
|
||||
if(_eShootersDirty) {
|
||||
_currentMass->getEnergyShooters();
|
||||
_eShootersDirty = false;
|
||||
}
|
||||
if(_bLaunchersDirty) {
|
||||
_currentMass->getBulletLaunchers();
|
||||
_bLaunchersDirty = false;
|
||||
}
|
||||
if(_eLaunchersDirty) {
|
||||
_currentMass->getEnergyLaunchers();
|
||||
_eLaunchersDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
@ -169,7 +70,7 @@ Application::drawWeapons() {
|
|||
|
||||
ImGui::BeginGroup();
|
||||
|
||||
if(!ImGui::BeginChild("##WeaponChild", {0.0f, -footer_height_to_reserve})) {
|
||||
if(!ImGui::BeginChild("##WeaponChild")) {
|
||||
ImGui::EndChild();
|
||||
return;
|
||||
}
|
||||
|
@ -178,55 +79,61 @@ Application::drawWeapons() {
|
|||
|
||||
ImGui::EndChild();
|
||||
|
||||
if(drawUnsafeWidget([](){ return ImGui::Button(ICON_FA_SAVE " Save changes to weapon category"); })) {
|
||||
_modifiedBySaveTool = true;
|
||||
switch(_currentWeapon->type) {
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
void
|
||||
Application::drawWeaponCategory(Containers::StringView name, GameObjects::Weapon::Type category,
|
||||
Containers::ArrayView<GameObjects::Weapon> weapons_view,
|
||||
Containers::StringView payload_type, Containers::StringView payload_tooltip)
|
||||
{
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(name.cbegin(), name.cend());
|
||||
|
||||
ImGui::PushID(name.cbegin());
|
||||
|
||||
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_SAVE " Save")) {
|
||||
switch(category) {
|
||||
case GameObjects::Weapon::Type::Melee:
|
||||
if(!_currentMass->writeMeleeWeapons()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case GameObjects::Weapon::Type::Shield:
|
||||
if(!_currentMass->writeShields()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case GameObjects::Weapon::Type::BulletShooter:
|
||||
if(!_currentMass->writeBulletShooters()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case GameObjects::Weapon::Type::EnergyShooter:
|
||||
if(!_currentMass->writeEnergyShooters()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case GameObjects::Weapon::Type::BulletLauncher:
|
||||
if(!_currentMass->writeBulletLaunchers()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case GameObjects::Weapon::Type::EnergyLauncher:
|
||||
if(!_currentMass->writeEnergyLaunchers()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, "Unknown weapon type");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset weapon category")) {
|
||||
switch(_currentWeapon->type) {
|
||||
if(ImGui::SmallButton(ICON_FA_UNDO_ALT " Reset")) {
|
||||
switch(category) {
|
||||
case GameObjects::Weapon::Type::Melee:
|
||||
_currentMass->getMeleeWeapons();
|
||||
break;
|
||||
|
@ -250,19 +157,6 @@ Application::drawWeapons() {
|
|||
}
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
void
|
||||
Application::drawWeaponCategory(Containers::StringView name, Containers::ArrayView<GameObjects::Weapon> weapons_view, bool& dirty,
|
||||
Containers::StringView payload_type, Containers::StringView payload_tooltip)
|
||||
{
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(name.cbegin(), name.cend());
|
||||
|
||||
ImGui::PushID(payload_type.data());
|
||||
|
||||
for(std::uint32_t i = 0; i < weapons_view.size(); i++) {
|
||||
auto& weapon = weapons_view[i];
|
||||
|
||||
|
@ -301,7 +195,6 @@ Application::drawWeaponCategory(Containers::StringView name, Containers::ArrayVi
|
|||
else {
|
||||
weapons_view[i] = weapons_view[index];
|
||||
}
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
ImGui::EndDragDropTarget();
|
||||
|
@ -323,7 +216,7 @@ Application::drawWeaponEditor(GameObjects::Weapon& weapon) {
|
|||
return;
|
||||
}
|
||||
|
||||
static Containers::StringView labels[] {
|
||||
static constexpr Containers::StringView labels[] {
|
||||
#define c(enumerator, strenum, name) name,
|
||||
#include "../Maps/WeaponTypes.hpp"
|
||||
#undef c
|
||||
|
@ -345,9 +238,35 @@ Application::drawWeaponEditor(GameObjects::Weapon& weapon) {
|
|||
weapon.name = name_buf.data();
|
||||
}
|
||||
|
||||
if(weapon.type == GameObjects::Weapon::Type::BulletShooter) {
|
||||
ImGui::Button("Import energy shooter by dragging it here");
|
||||
if(ImGui::BeginDragDropTarget()) {
|
||||
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("EShooter")) {
|
||||
std::uint32_t index = *static_cast<std::uint32_t*>(payload->Data);
|
||||
weapon = _currentMass->energyShooters()[index];
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
}
|
||||
else if(weapon.type == GameObjects::Weapon::Type::EnergyShooter) {
|
||||
ImGui::Button("Import bullet shooter by dragging it here");
|
||||
if(ImGui::BeginDragDropTarget()) {
|
||||
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("BShooter")) {
|
||||
std::uint32_t index = *static_cast<std::uint32_t*>(payload->Data);
|
||||
weapon = _currentMass->bulletShooters()[index];
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::BeginGroup();
|
||||
drawAlignedText("Equipped:");
|
||||
|
||||
if(conf().advancedMode()) {
|
||||
drawAlignedText("Weapon type:");
|
||||
drawAlignedText("");
|
||||
}
|
||||
|
||||
if(weapon.type != GameObjects::Weapon::Type::Shield) {
|
||||
drawAlignedText("Damage type:");
|
||||
}
|
||||
|
@ -366,6 +285,47 @@ Application::drawWeaponEditor(GameObjects::Weapon& weapon) {
|
|||
ImGui::BeginGroup();
|
||||
ImGui::Checkbox("##EquippedCheckbox", &weapon.attached);
|
||||
|
||||
if(conf().advancedMode()) {
|
||||
if(ImGui::RadioButton("Melee##MeleeType", weapon.type == GameObjects::Weapon::Type::Melee)) {
|
||||
weapon.type = GameObjects::Weapon::Type::Melee;
|
||||
if(weapon.damageType == GameObjects::Weapon::DamageType::Piercing || weapon.damageType == GameObjects::Weapon::DamageType::Plasma) {
|
||||
weapon.damageType = GameObjects::Weapon::DamageType::Physical;
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::RadioButton("Shield##ShieldType", weapon.type == GameObjects::Weapon::Type::Shield)) {
|
||||
weapon.type = GameObjects::Weapon::Type::Shield;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::RadioButton("Bullet shooter##BShooterType", weapon.type == GameObjects::Weapon::Type::BulletShooter)) {
|
||||
weapon.type = GameObjects::Weapon::Type::BulletShooter;
|
||||
if(weapon.damageType == GameObjects::Weapon::DamageType::Physical || weapon.damageType == GameObjects::Weapon::DamageType::Plasma) {
|
||||
weapon.damageType = GameObjects::Weapon::DamageType::Piercing;
|
||||
}
|
||||
}
|
||||
|
||||
if(ImGui::RadioButton("Energy shooter##EShooterType", weapon.type == GameObjects::Weapon::Type::EnergyShooter)) {
|
||||
weapon.type = GameObjects::Weapon::Type::EnergyShooter;
|
||||
if(weapon.damageType == GameObjects::Weapon::DamageType::Physical || weapon.damageType == GameObjects::Weapon::DamageType::Piercing) {
|
||||
weapon.damageType = GameObjects::Weapon::DamageType::Plasma;
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::RadioButton("Bullet launcher##BLauncherType", weapon.type == GameObjects::Weapon::Type::BulletLauncher)) {
|
||||
weapon.type = GameObjects::Weapon::Type::BulletLauncher;
|
||||
if(weapon.damageType == GameObjects::Weapon::DamageType::Physical || weapon.damageType == GameObjects::Weapon::DamageType::Plasma) {
|
||||
weapon.damageType = GameObjects::Weapon::DamageType::Piercing;
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::RadioButton("Energy launcher##ELauncherType", weapon.type == GameObjects::Weapon::Type::EnergyLauncher)) {
|
||||
weapon.type = GameObjects::Weapon::Type::EnergyLauncher;
|
||||
if(weapon.damageType == GameObjects::Weapon::DamageType::Physical || weapon.damageType == GameObjects::Weapon::DamageType::Piercing) {
|
||||
weapon.damageType = GameObjects::Weapon::DamageType::Plasma;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(weapon.type != GameObjects::Weapon::Type::Shield) {
|
||||
if(weapon.type == GameObjects::Weapon::Type::Melee &&
|
||||
ImGui::RadioButton("Physical##NoElement", weapon.damageType == GameObjects::Weapon::DamageType::Physical))
|
||||
|
@ -425,7 +385,7 @@ Application::drawWeaponEditor(GameObjects::Weapon& weapon) {
|
|||
ImGui::Separator();
|
||||
|
||||
if(weapon.parts.isEmpty()) {
|
||||
ImGui::TextUnformatted("This weapon has no parts.");
|
||||
ImGui::TextUnformatted("This weapon has no parts. This is not normal.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -467,8 +427,8 @@ Application::drawWeaponEditor(GameObjects::Weapon& weapon) {
|
|||
if(map->find(part.id) != map->cend()) {
|
||||
ImGui::TextUnformatted(map->at(part.id).cbegin(), map->at(part.id).cend());
|
||||
}
|
||||
else if(part.id == -1) {
|
||||
ImGui::TextUnformatted("<none>");
|
||||
else if(part.id < 0) {
|
||||
ImGui::TextUnformatted("<invalid part ID>");
|
||||
}
|
||||
else{
|
||||
ImGui::Text("ID: %i", part.id);
|
||||
|
@ -496,20 +456,17 @@ Application::drawWeaponEditor(GameObjects::Weapon& weapon) {
|
|||
}
|
||||
}
|
||||
|
||||
if(weapon.type == GameObjects::Weapon::Type::Shield ||
|
||||
(weapon.type == GameObjects::Weapon::Type::BulletLauncher && _selectedWeaponPart != 0))
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if(ImGui::SmallButton("Unequip")) {
|
||||
part.id = -1;
|
||||
}
|
||||
if(weapon.type == GameObjects::Weapon::Type::Shield && _selectedWeaponPart == 0) {
|
||||
drawTooltip("This will make the whole shield and its accessories invisible.");
|
||||
}
|
||||
else {
|
||||
drawTooltip("This will make accessories invisible as well.");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::SmallButton("Hide part " ICON_FA_QUESTION_CIRCLE)) {
|
||||
part.id = 96 + part.id >= 0 ? (part.id / 100) * 100 : 0;
|
||||
}
|
||||
drawTooltip(_selectedWeaponPart == 0 ?
|
||||
"This will hide the selected part, but not its accessories. "
|
||||
"Parts attached to this one will also be hidden, though their accessories WON'T be visible. "
|
||||
"For parts that affect weapon stance/functionality, this feature will try to preserve that." :
|
||||
"This will hide the selected part, but not its accessories. "
|
||||
"For parts that affect weapon stance/functionality, this feature will try to preserve that.",
|
||||
static_cast<float>(windowSize().x()) * 0.4f);
|
||||
|
||||
if(ImGui::BeginChild("##PartDetails", {}, ImGuiChildFlags_Border)) {
|
||||
ImGui::TextUnformatted("Styles:");
|
||||
|
|
|
@ -91,7 +91,6 @@ Application::drawProfileManager() {
|
|||
{
|
||||
_currentProfile = _profileManager->getProfile(i);
|
||||
initialiseMassManager();
|
||||
initialiseFileWatcher();
|
||||
_uiState = UiState::MainManager;
|
||||
}
|
||||
|
||||
|
|
|
@ -101,8 +101,6 @@ Application::drawAbout() {
|
|||
if(ImGui::CollapsingHeader("Third-party components")) {
|
||||
ImGui::TextWrapped("This application uses the following third-party components:");
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, 0.0f);
|
||||
|
||||
if(ImGui::TreeNodeEx("Corrade", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::Text("Version used: %s", CORRADE_VERSION_STRING);
|
||||
auto corrade_website = "https://magnum.graphics/corrade";
|
||||
|
@ -195,23 +193,6 @@ Application::drawAbout() {
|
|||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if(ImGui::TreeNodeEx("Entropia File System Watcher (efsw)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
auto efsw_repo = "https://github.com/SpartanJ/efsw";
|
||||
drawAlignedText(ICON_FA_GITHUB " %s", efsw_repo);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
ImGui::SetClipboardText(efsw_repo);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Open in browser")) {
|
||||
openUri(efsw_repo);
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("Licence: MIT");
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if(ImGui::TreeNodeEx("libcurl", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||
ImGui::Text("Version used: %s", LIBCURL_VERSION);
|
||||
auto curl_website = "https://curl.se/libcurl";
|
||||
|
@ -264,8 +245,6 @@ Application::drawAbout() {
|
|||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include <Corrade/Utility/Path.h>
|
||||
|
||||
#include <Magnum/Math/Time.h>
|
||||
|
||||
#include "../Configuration/Configuration.h"
|
||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
||||
|
@ -66,28 +68,6 @@ Application::drawMainMenu() {
|
|||
openUri(Utility::Path::toNativeSeparators(conf().directories().staging));
|
||||
}
|
||||
|
||||
/*if(ImGui::BeginMenu(ICON_FA_BOXES " Armoury")) {
|
||||
if(ImGui::MenuItem(ICON_FA_SHIELD_ALT " Armour parts", nullptr, false,
|
||||
Utility::Path::exists(conf().directories().armours)))
|
||||
{
|
||||
openUri(Utility::Path::toNativeSeparators(conf().directories().armours));
|
||||
}
|
||||
|
||||
if(ImGui::MenuItem(ICON_FA_HAMMER " Weapons", nullptr, false,
|
||||
Utility::Path::exists(conf().directories().weapons)))
|
||||
{
|
||||
openUri(Utility::Path::toNativeSeparators(conf().directories().weapons));
|
||||
}
|
||||
|
||||
if(ImGui::MenuItem(ICON_FA_PALETTE " Custom styles", nullptr, false,
|
||||
Utility::Path::exists(conf().directories().styles)))
|
||||
{
|
||||
openUri(Utility::Path::toNativeSeparators(conf().directories().styles));
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}*/
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
|
@ -120,7 +100,8 @@ Application::drawMainMenu() {
|
|||
conf().setSwapInterval(i);
|
||||
setSwapInterval(i);
|
||||
if(i == 0) {
|
||||
setMinimalLoopPeriod(0);
|
||||
using namespace Math::Literals;
|
||||
setMinimalLoopPeriod(0_nsec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -149,12 +130,13 @@ Application::drawMainMenu() {
|
|||
drawHelpMarker("This gives access to save edition features that can be considered cheats.",
|
||||
float(windowSize().x()) * 0.4f);
|
||||
|
||||
if(drawCheckbox("Advanced mode", conf().advancedMode())) {
|
||||
if(drawCheckbox("Advanced fuckery mode", conf().advancedMode())) {
|
||||
conf().setAdvancedMode(!conf().advancedMode());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
drawHelpMarker("This gives access to editing values that have unknown purposes or are undocumented.",
|
||||
drawHelpMarker("This gives access to editing values that have unknown purposes or are undocumented. "
|
||||
"It also grants access to some special editing features allowing things the game is NOT designed for.",
|
||||
float(windowSize().x()) * 0.4f);
|
||||
|
||||
if(drawCheckbox("Check for updates on startup", conf().checkUpdatesOnStartup())) {
|
||||
|
@ -223,7 +205,7 @@ Application::drawMainMenu() {
|
|||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
//ImGui::EndDisabled();
|
||||
//if(conf().isRunningInWine() && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
|
||||
// ImGui::SetTooltip("Not available when running in Wine.");
|
||||
//}
|
||||
|
|
|
@ -18,7 +18,7 @@ set(CMAKE_CXX_STANDARD 17)
|
|||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
set(SAVETOOL_PROJECT_VERSION 1.5.3)
|
||||
set(SAVETOOL_PROJECT_VERSION 1.6.1)
|
||||
|
||||
find_package(Corrade REQUIRED Containers Utility)
|
||||
if(CORRADE_TARGET_WINDOWS)
|
||||
|
@ -31,10 +31,6 @@ if(SAVETOOL_USE_SYSTEM_LIBZIP)
|
|||
find_package(libzip REQUIRED)
|
||||
endif(SAVETOOL_USE_SYSTEM_LIBZIP)
|
||||
|
||||
if(SAVETOOL_USE_SYSTEM_EFSW)
|
||||
find_package(efsw REQUIRED)
|
||||
endif(SAVETOOL_USE_SYSTEM_EFSW)
|
||||
|
||||
if(SAVETOOL_USE_SYSTEM_LIBCURL)
|
||||
find_package(CURL REQUIRED HTTPS)
|
||||
endif(SAVETOOL_USE_SYSTEM_LIBCURL)
|
||||
|
@ -135,14 +131,6 @@ 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()
|
||||
|
@ -153,7 +141,6 @@ add_executable(MassBuilderSaveTool
|
|||
Application/Application.cpp
|
||||
Application/Application_drawAbout.cpp
|
||||
Application/Application_drawMainMenu.cpp
|
||||
Application/Application_FileWatcher.cpp
|
||||
Application/Application_Initialisation.cpp
|
||||
Application/Application_MainManager.cpp
|
||||
Application/Application_MassViewer.cpp
|
||||
|
@ -222,7 +209,6 @@ add_executable(MassBuilderSaveTool
|
|||
${Logger_SOURCES}
|
||||
${BinaryIo_SOURCES}
|
||||
${Gvas_SOURCES}
|
||||
${ImportExport_SOURCES}
|
||||
${SAVETOOL_RC_FILE}
|
||||
${Assets}
|
||||
)
|
||||
|
@ -234,10 +220,10 @@ endif()
|
|||
target_compile_definitions(MassBuilderSaveTool PRIVATE
|
||||
SAVETOOL_VERSION_STRING="${SAVETOOL_PROJECT_VERSION}"
|
||||
SAVETOOL_VERSION_MAJOR=1
|
||||
SAVETOOL_VERSION_MINOR=5
|
||||
SAVETOOL_VERSION_PATCH=3
|
||||
SAVETOOL_VERSION_MINOR=6
|
||||
SAVETOOL_VERSION_PATCH=1
|
||||
SAVETOOL_VERSION_PRERELEASE=false
|
||||
SAVETOOL_CODENAME="Friendly Valkyrie"
|
||||
SAVETOOL_CODENAME="Glorious Fuckery"
|
||||
SAVETOOL_SUPPORTED_GAME_VERSION="0.12.x"
|
||||
)
|
||||
|
||||
|
@ -271,12 +257,6 @@ else()
|
|||
target_link_libraries(MassBuilderSaveTool PRIVATE zip)
|
||||
endif()
|
||||
|
||||
if(SAVETOOL_USE_SYSTEM_EFSW)
|
||||
target_link_libraries(MassBuilderSaveTool PRIVATE efsw::efsw)
|
||||
else()
|
||||
target_link_libraries(MassBuilderSaveTool PRIVATE efsw)
|
||||
endif()
|
||||
|
||||
if(CORRADE_TARGET_WINDOWS)
|
||||
target_link_libraries(MassBuilderSaveTool PRIVATE
|
||||
Corrade::Main
|
||||
|
|
|
@ -119,10 +119,6 @@ Configuration::Configuration() {
|
|||
Containers::String executable_location = Utility::Path::split(*Utility::Path::executableLocation()).first();
|
||||
_directories.backups = Utility::Path::join(executable_location, "backups");
|
||||
_directories.staging = Utility::Path::join(executable_location, "staging");
|
||||
//auto armoury_dir = Utility::Path::join(executable_location, "armoury");
|
||||
//_directories.armours = Utility::Path::join(armoury_dir, "armours");
|
||||
//_directories.weapons = Utility::Path::join(armoury_dir, "weapons");
|
||||
//_directories.styles = Utility::Path::join(armoury_dir, "styles");
|
||||
_directories.temp = Utility::Path::join(executable_location, "temp");
|
||||
|
||||
if(!Utility::Path::exists(_directories.backups)) {
|
||||
|
@ -139,27 +135,6 @@ Configuration::Configuration() {
|
|||
return;
|
||||
}
|
||||
}
|
||||
//if(!Utility::Path::exists(_directories.armours)) {
|
||||
// LOG_WARNING("Armours directory not found, creating...");
|
||||
// if(!Utility::Path::make(_directories.armours)) {
|
||||
// LOG_ERROR(_lastError = "Couldn't create the armours directory.");
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
//if(!Utility::Path::exists(_directories.weapons)) {
|
||||
// LOG_WARNING("Weapons directory not found, creating...");
|
||||
// if(!Utility::Path::make(_directories.weapons)) {
|
||||
// LOG_ERROR(_lastError = "Couldn't create the weapons directory.");
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
//if(!Utility::Path::exists(_directories.styles)) {
|
||||
// LOG_WARNING("Styles directory not found, creating...");
|
||||
// if(!Utility::Path::make(_directories.styles)) {
|
||||
// LOG_ERROR(_lastError = "Couldn't create the styles directory.");
|
||||
// return;
|
||||
// }
|
||||
//}
|
||||
|
||||
if(!Utility::Path::exists(_directories.temp)) {
|
||||
LOG_WARNING("Temporary directory not found, creating...");
|
||||
|
|
|
@ -70,9 +70,6 @@ class Configuration {
|
|||
Containers::String gameScreenshots;
|
||||
Containers::String backups;
|
||||
Containers::String staging;
|
||||
Containers::String armours;
|
||||
Containers::String weapons;
|
||||
Containers::String styles;
|
||||
Containers::String temp;
|
||||
};
|
||||
auto directories() const -> Directories const&;
|
||||
|
|
|
@ -27,17 +27,21 @@ using namespace Containers::Literals;
|
|||
|
||||
namespace mbst::GameData {
|
||||
|
||||
// As of this writing (2024-12-07T12:08+01:00), the IDs ending in 96 are not valid IDs in the game, but are used by the
|
||||
// Save Tool to display a name instead of "ID: <number>".
|
||||
|
||||
// region Melee
|
||||
static const std::map<std::int32_t, Containers::StringView> melee_grips {
|
||||
{0, "Combat Grip (1H)"_s},
|
||||
{1, "Knuckle Guard Grip (1H)"_s},
|
||||
{2, "Dual Guard Grip (1H)"_s},
|
||||
{3, "Sepal Grip (1H)"_s},
|
||||
{4, "Warrior Grip (1H)"_s},
|
||||
{5, "Guardian Grip (1H)"_s},
|
||||
{6, "Knight Guard Grip (1H)"_s},
|
||||
{7, "Saber Guard Grip (1H)"_s},
|
||||
{8, "Base Grip (1H)"_s},
|
||||
{0, "Combat Grip (1H)"_s},
|
||||
{1, "Knuckle Guard Grip (1H)"_s},
|
||||
{2, "Dual Guard Grip (1H)"_s},
|
||||
{3, "Sepal Grip (1H)"_s},
|
||||
{4, "Warrior Grip (1H)"_s},
|
||||
{5, "Guardian Grip (1H)"_s},
|
||||
{6, "Knight Guard Grip (1H)"_s},
|
||||
{7, "Saber Guard Grip (1H)"_s},
|
||||
{8, "Base Grip (1H)"_s},
|
||||
{96, "<hidden grip> (1H)"_s},
|
||||
|
||||
{100, "Combat Side Grip (1H)"_s},
|
||||
{101, "Hollowed Side Grip (1H)"_s},
|
||||
|
@ -48,12 +52,14 @@ static const std::map<std::int32_t, Containers::StringView> melee_grips {
|
|||
{106, "Concave Side Grip (1H)"_s},
|
||||
{107, "Polehead Side Grip (1H)"_s},
|
||||
{108, "Base Side Grip (1H)"_s},
|
||||
{196, "<hidden side grip> (1H)"_s},
|
||||
|
||||
{200, "Combat Dual Grip (1H)"_s},
|
||||
{201, "Hollowed Dual Grip (1H)"_s},
|
||||
{202, "Plated Dual Grip (1H)"_s},
|
||||
{203, "Concave Dual Grip (1H)"_s},
|
||||
{204, "Polehead Dual Grip (1H)"_s},
|
||||
{296, "<hidden dual grip> (1H)"_s},
|
||||
|
||||
{400, "Combat Twin Grip (1H)"_s},
|
||||
{401, "Sepal Twin Grip (1H)"_s},
|
||||
|
@ -63,6 +69,7 @@ static const std::map<std::int32_t, Containers::StringView> melee_grips {
|
|||
{405, "Handguard Twin Grip (1H)"_s},
|
||||
{406, "Fullguard Twin Grip (1H)"_s},
|
||||
{407, "Base Twin Grip (1H)"_s},
|
||||
{496, "<hidden twin grip> (1H)"_s},
|
||||
|
||||
{1000, "Combat Knuckle (R/L)"_s},
|
||||
{1001, "Battle Fist (R/L)"_s},
|
||||
|
@ -70,6 +77,7 @@ static const std::map<std::int32_t, Containers::StringView> melee_grips {
|
|||
{1003, "Heavy Fist (R/L)"_s},
|
||||
{1004, "Thick Fist (R/L)"_s},
|
||||
{1005, "Base Fist (R/L)"_s},
|
||||
{1096, "<hidden fist> (R/L)"_s},
|
||||
|
||||
{2000, "Combat Polearm (2H)"_s},
|
||||
{2001, "Dual Guard Polearm (2H)"_s},
|
||||
|
@ -79,6 +87,7 @@ static const std::map<std::int32_t, Containers::StringView> melee_grips {
|
|||
{2005, "Sharp Polearm (2H)"_s},
|
||||
{2006, "Ring Polearm (2H)"_s},
|
||||
{2007, "Base Polearm (2H)"_s},
|
||||
{2096, "<hidden polearm> (2H)"_s},
|
||||
|
||||
{2100, "Combat Side Polearm (2H)"_s},
|
||||
{2101, "Plated Side Polearm (2H)"_s},
|
||||
|
@ -86,10 +95,12 @@ static const std::map<std::int32_t, Containers::StringView> melee_grips {
|
|||
{2103, "Fin Side Polearm (2H)"_s},
|
||||
{2104, "Heavy Side Polearm (2H)"_s},
|
||||
{2105, "Base Side Polearm (2H)"_s},
|
||||
{2196, "<hidden side polearm> (2H)"_s},
|
||||
|
||||
{2200, "Combat Dual Polearm (2H)"_s},
|
||||
{2201, "Studded Dual Polearm (2H)"_s},
|
||||
{2202, "Circular Dual Polearm (2H)"_s},
|
||||
{2296, "<hidden dual polearm> (2H)"_s},
|
||||
|
||||
{2400, "Combat Twin Blade (2H)"_s},
|
||||
{2401, "Guard Twin Blade (2H)"_s},
|
||||
|
@ -99,6 +110,7 @@ static const std::map<std::int32_t, Containers::StringView> melee_grips {
|
|||
{2405, "Holder Twin Blade (2H)"_s},
|
||||
{2406, "Ring Twin Blade (2H)"_s},
|
||||
{2407, "Base Twin Blade (2H)"_s},
|
||||
{2496, "<hidden twin blade> (2H)"_s},
|
||||
};
|
||||
|
||||
static const std::map<std::int32_t, Containers::StringView> melee_assaulters {
|
||||
|
@ -115,39 +127,35 @@ static const std::map<std::int32_t, Containers::StringView> melee_assaulters {
|
|||
{10, "Long Curved Blade"_s},
|
||||
{11, "Long Broad Blade"_s},
|
||||
{12, "Base L Sword"_s},
|
||||
|
||||
{20, "Long Combat Edge"_s},
|
||||
{21, "Long Attached Edge"_s},
|
||||
|
||||
{40, "Katana Blade"_s},
|
||||
{41, "Custom Katana Blade"_s},
|
||||
|
||||
{60, "Energy Blade (Motion)"_s},
|
||||
{61, "Powered Blade"_s},
|
||||
{96, "<hidden long blade>"_s},
|
||||
|
||||
{100, "Short Metal Blade"_s},
|
||||
{101, "Short Assault Blade"_s},
|
||||
{102, "Short Fin Blade"_s},
|
||||
{103, "Base S Sword"_s},
|
||||
|
||||
{120, "Short Combat Edge"_s},
|
||||
|
||||
{160, "Short Energy Blade (Motion)"_s},
|
||||
{161, "Short Powered Blade"_s},
|
||||
|
||||
{180, "Triclaw"_s},
|
||||
{181, "Straight Triclaw"_s},
|
||||
{182, "Griphold Claw"_s},
|
||||
{183, "Energy Claw"_s},
|
||||
{184, "Openhold Claw"_s},
|
||||
{185, "Hooktusk Claw"_s},
|
||||
{196, "<hidden short blade>"_s},
|
||||
|
||||
{200, "Bracer"_s},
|
||||
{201, "Custom Bracer"_s},
|
||||
{202, "Base Hammer"_s},
|
||||
|
||||
{210, "Expanded Bracer"_s},
|
||||
{211, "Expanded Custom Bracer"_s},
|
||||
{296, "<hidden bracer>"_s},
|
||||
|
||||
{300, "Heavy Smasher"_s},
|
||||
{301, "Heavy Basher"_s},
|
||||
|
@ -156,6 +164,7 @@ static const std::map<std::int32_t, Containers::StringView> melee_assaulters {
|
|||
{304, "Heavy Diamond Smasher"_s},
|
||||
{305, "Heavy Spinning Smasher (Motion)"_s},
|
||||
{306, "Base L Mace"_s},
|
||||
{396, "<hidden heavy mace>"_s},
|
||||
|
||||
{400, "Light Smasher"_s},
|
||||
{401, "Light Basher"_s},
|
||||
|
@ -164,14 +173,13 @@ static const std::map<std::int32_t, Containers::StringView> melee_assaulters {
|
|||
{404, "Light Diamond Smasher"_s},
|
||||
{405, "Light Spinning Smasher"_s},
|
||||
{406, "Base S Mace"_s},
|
||||
|
||||
{420, "War Hammer"_s},
|
||||
{421, "Great Hammer"_s},
|
||||
{422, "Spiked Hammer"_s},
|
||||
{423, "Broadhead Hammer"_s},
|
||||
|
||||
{440, "Morning Star"_s},
|
||||
{441, "Spike Ball"_s},
|
||||
{496, "<hidden light mace>"_s},
|
||||
|
||||
{500, "Combat Lance"_s},
|
||||
{501, "Gouger Lance"_s},
|
||||
|
@ -179,6 +187,7 @@ static const std::map<std::int32_t, Containers::StringView> melee_assaulters {
|
|||
{503, "Spinning Pointy Lance (Motion)"_s},
|
||||
{504, "Crystal Lance"_s},
|
||||
{510, "Piercer"_s},
|
||||
{596, "<hidden lance>"_s},
|
||||
|
||||
{600, "Short Combat Lance"_s},
|
||||
{601, "Short Pointy Lance"_s},
|
||||
|
@ -186,6 +195,7 @@ static const std::map<std::int32_t, Containers::StringView> melee_assaulters {
|
|||
{603, "Short Crystal Lance"_s},
|
||||
{605, "Short Combat Drill (Motion)"_s},
|
||||
{610, "Short Piercer"_s},
|
||||
{696, "<hidden short lance>"_s},
|
||||
|
||||
{700, "Combat Axe"_s},
|
||||
{701, "Custom Combat Axe"_s},
|
||||
|
@ -193,57 +203,60 @@ static const std::map<std::int32_t, Containers::StringView> melee_assaulters {
|
|||
{703, "Frontbreak Axe"_s},
|
||||
{704, "Maiming Axe"_s},
|
||||
{705, "Delta Axe"_s},
|
||||
{796, "<hidden axe>"_s},
|
||||
|
||||
{800, "Combat Scythe"_s},
|
||||
{801, "Reaper Blade"_s},
|
||||
{802, "Clawtooth Scythe"_s},
|
||||
{803, "Wingpoint Scythe"_s},
|
||||
{804, "Snakebone Scythe"_s},
|
||||
{896, "<hidden scythe>"_s},
|
||||
|
||||
{900, "Short Combat Scythe"_s},
|
||||
{901, "Short Reaper Blade"_s},
|
||||
{902, "Short Clawtooth Scythe"_s},
|
||||
{903, "Short Wingpoint Scythe"_s},
|
||||
{904, "Short Snakebone Scythe"_s},
|
||||
{996, "<hidden short scythe>"_s},
|
||||
};
|
||||
// endregion
|
||||
|
||||
// region Shields
|
||||
static const std::map<std::int32_t, Containers::StringView> shield_handles {
|
||||
{0, "Balanced Handle"_s},
|
||||
{1, "Expanded Handle"_s},
|
||||
{2, "Lowguard Handle"_s},
|
||||
{3, "Longblocker Handle"_s},
|
||||
{4, "Winged Handle"_s},
|
||||
{5, "Stopper Handle"_s},
|
||||
{6, "Layered Handle"_s},
|
||||
{7, "Riotguard Handle"_s},
|
||||
{8, "Blitz Handle"_s},
|
||||
{9, "Foldable Handle"_s},
|
||||
{10, "Board Handle"_s},
|
||||
{11, "Knight Handle"_s},
|
||||
{12, "Cargwall Handle"_s},
|
||||
|
||||
{0, "Balanced Handle"_s},
|
||||
{1, "Expanded Handle"_s},
|
||||
{2, "Lowguard Handle"_s},
|
||||
{3, "Longblocker Handle"_s},
|
||||
{4, "Winged Handle"_s},
|
||||
{5, "Stopper Handle"_s},
|
||||
{6, "Layered Handle"_s},
|
||||
{7, "Riotguard Handle"_s},
|
||||
{8, "Blitz Handle"_s},
|
||||
{9, "Foldable Handle"_s},
|
||||
{10, "Board Handle"_s},
|
||||
{11, "Knight Handle"_s},
|
||||
{12, "Cargwall Handle"_s},
|
||||
{96, "<hidden handle>"_s},
|
||||
{100, "Buckler Handle"_s},
|
||||
{101, "Star Handle"_s},
|
||||
};
|
||||
|
||||
static const std::map<std::int32_t, Containers::StringView> shield_shells {
|
||||
{0, "Balanced Shell"_s},
|
||||
{1, "Compass Shell"_s},
|
||||
{2, "Uppoint Shell"_s},
|
||||
{3, "Pointed Shell"_s},
|
||||
{4, "Padded Shell"_s},
|
||||
{5, "Pincer Shell"_s},
|
||||
{6, "Fang Shell"_s},
|
||||
{7, "Holder Shell"_s},
|
||||
{8, "Composite Shell"_s},
|
||||
{9, "Mechanical Shell"_s},
|
||||
{10, "Layered Shell"_s},
|
||||
{11, "Parted Shell"_s},
|
||||
{12, "Tapst Shell"_s},
|
||||
{13, "Sidloc Shell"_s},
|
||||
|
||||
{0, "Balanced Shell"_s},
|
||||
{1, "Compass Shell"_s},
|
||||
{2, "Uppoint Shell"_s},
|
||||
{3, "Pointed Shell"_s},
|
||||
{4, "Padded Shell"_s},
|
||||
{5, "Pincer Shell"_s},
|
||||
{6, "Fang Shell"_s},
|
||||
{7, "Holder Shell"_s},
|
||||
{8, "Composite Shell"_s},
|
||||
{9, "Mechanical Shell"_s},
|
||||
{10, "Layered Shell"_s},
|
||||
{11, "Parted Shell"_s},
|
||||
{12, "Tapst Shell"_s},
|
||||
{13, "Sidloc Shell"_s},
|
||||
{96, "<hidden shell>"_s},
|
||||
{100, "V-Cross Shell"_s},
|
||||
};
|
||||
// endregion
|
||||
|
@ -257,6 +270,7 @@ static const std::map<std::int32_t, Containers::StringView> bshooter_triggers {
|
|||
{4, "Longhold Trigger (1H)"_s},
|
||||
{5, "Downhold Trigger (1H)"_s},
|
||||
{6, "Cellblock Trigger (1H)"_s},
|
||||
{96, "<hidden trigger> (1H)"_s},
|
||||
{99, "Base Trigger (1H)"_s},
|
||||
|
||||
{100, "BL-Machine Trigger (2H)"_s},
|
||||
|
@ -264,6 +278,7 @@ static const std::map<std::int32_t, Containers::StringView> bshooter_triggers {
|
|||
{102, "Shielded Trigger (2H)"_s},
|
||||
{103, "Platedframe Trigger (2H)"_s},
|
||||
{104, "Sidebox Trigger (2H) (Motion)"_s},
|
||||
{196, "<hidden trigger> (2H)"_s},
|
||||
{199, "2H Base Trigger (2H)"_s},
|
||||
};
|
||||
|
||||
|
@ -273,6 +288,7 @@ static const std::map<std::int32_t, Containers::StringView> bshooter_barrels {
|
|||
{2, "Muzzlemod Barrel (1 shot)"_s},
|
||||
{3, "Triangular Barrel (1 shot)"_s},
|
||||
{4, "Recoilblock Barrel (1 shot) (Motion)"_s},
|
||||
{96, "<hidden barrel> (1 shot)"_s},
|
||||
{97, "Short S Base Barrel (1 shot)"_s},
|
||||
{98, "Medium S Base Barrel (1 shot)"_s},
|
||||
{99, "Long S Base Barrel (1 shot)"_s},
|
||||
|
@ -281,6 +297,7 @@ static const std::map<std::int32_t, Containers::StringView> bshooter_barrels {
|
|||
{101, "Modded Six-Barrel Gatling (Auto) (Motion)"_s},
|
||||
{102, "Four-Barrel Gatling (Auto) (Motion)"_s},
|
||||
{103, "Retro Style Gatling (Auto) (Motion)"_s},
|
||||
{196, "<hidden barrel> (Auto)"_s},
|
||||
{197, "Short G Base Barrel (Auto)"_s},
|
||||
{198, "Medium G Base Barrel (Auto)"_s},
|
||||
{199, "Long G Base Barrel (Auto)"_s},
|
||||
|
@ -289,6 +306,7 @@ static const std::map<std::int32_t, Containers::StringView> bshooter_barrels {
|
|||
{201, "Wideblast Barrel (Spread) (Motion)"_s},
|
||||
{202, "Pelleter Barrel (Spread) (Motion)"_s},
|
||||
{203, "Lockhold Barrel (Spread) (Motion)"_s},
|
||||
{296, "<hidden barrel> (Spread)"_s},
|
||||
{297, "Short B Base Barrel (Spread)"_s},
|
||||
{298, "Medium B Base Barrel (Spread)"_s},
|
||||
{299, "Long B Base Barrel (Spread)"_s},
|
||||
|
@ -297,6 +315,7 @@ static const std::map<std::int32_t, Containers::StringView> bshooter_barrels {
|
|||
{301, "Roundbox Barrel (Detonate)"_s},
|
||||
{302, "ShieldDet Barrel (Detonate)"_s},
|
||||
{303, "RecoilDet Barrel (Detonate) (Motion)"_s},
|
||||
{396, "<hidden barrel> (Detonate)"_s},
|
||||
{397, "Short D Base Barrel (Detonate)"_s},
|
||||
{398, "Medium D Base Barrel (Detonate)"_s},
|
||||
{399, "Long D Base Barrel (Detonate)"_s},
|
||||
|
@ -304,6 +323,7 @@ static const std::map<std::int32_t, Containers::StringView> bshooter_barrels {
|
|||
{400, "Heavy Burst Barrel (Pile Bunker) (Motion)"_s},
|
||||
{401, "Under Guard Barrel (Pile Bunker) (Motion)"_s},
|
||||
{402, "Facthold Barrel (Pile Bunker) (Motion)"_s},
|
||||
{496, "<hidden barrel> (Pile Bunker)"_s},
|
||||
{499, "Long P Base Barrel (Pile Bunker) (Motion)"_s},
|
||||
};
|
||||
// endregion
|
||||
|
@ -317,6 +337,7 @@ static const std::map<std::int32_t, Containers::StringView> eshooter_triggers {
|
|||
{4, "EN-Needler Trigger (1H)"_s},
|
||||
{5, "Angular Trigger (1H)"_s},
|
||||
{6, "Exposed Trigger (1H)"_s},
|
||||
{96, "<hidden trigger> (1H)"_s},
|
||||
{99, "Base EnTrigger (1H)"_s},
|
||||
|
||||
{100, "EN-Combat Trigger (2H)"_s},
|
||||
|
@ -324,6 +345,7 @@ static const std::map<std::int32_t, Containers::StringView> eshooter_triggers {
|
|||
{102, "Framed Trigger (2H) (Motion)"_s},
|
||||
{103, "Stabilised Trigger (2H)"_s},
|
||||
{104, "EN-Heavy Trigger (2H)"_s},
|
||||
{196, "<hidden trigger> (2H)"_s},
|
||||
{199, "2H Base EnTrigger (2H)"_s},
|
||||
};
|
||||
|
||||
|
@ -332,6 +354,7 @@ static const std::map<std::int32_t, Containers::StringView> eshooter_busters {
|
|||
{1, "Delta Cycler (1 shot) (Motion)"_s},
|
||||
{2, "EN-Longbarrel Buster (1 shot)"_s},
|
||||
{3, "Kinetic Buster (1 shot) (Motion)"_s},
|
||||
{96, "<hidden buster> (1 shot)"_s},
|
||||
{97, "Short S Base Buster (1 shot)"_s},
|
||||
{98, "Medium S Base Buster (1 shot)"_s},
|
||||
{99, "Long S Base Buster (1 shot)"_s},
|
||||
|
@ -340,6 +363,7 @@ static const std::map<std::int32_t, Containers::StringView> eshooter_busters {
|
|||
{101, "EN-Focus Buster (Auto)"_s},
|
||||
{102, "Machinist Buster (Auto)"_s},
|
||||
{103, "EN-Precision Buster (Auto) (Motion)"_s},
|
||||
{196, "<hidden buster> (Auto)"_s},
|
||||
{197, "Short A Base Buster (Auto)"_s},
|
||||
{198, "Medium A Base Buster (Auto)"_s},
|
||||
{199, "Long A Base Buster (Auto)"_s},
|
||||
|
@ -348,6 +372,7 @@ static const std::map<std::int32_t, Containers::StringView> eshooter_busters {
|
|||
{201, "Clawcharge Buster (Ray)"_s},
|
||||
{202, "Twizelcharge Buster (Ray)"_s},
|
||||
{203, "Deltacharge Buster (Ray)"_s},
|
||||
{296, "<hidden buster> (Ray)"_s},
|
||||
{297, "Short R Base Buster (Ray)"_s},
|
||||
{298, "Medium R Base Buster (Ray)"_s},
|
||||
{299, "Long R Base Buster (Ray)"_s},
|
||||
|
@ -356,6 +381,7 @@ static const std::map<std::int32_t, Containers::StringView> eshooter_busters {
|
|||
{301, "Amplifier Buster (Wave) (Motion)"_s},
|
||||
{302, "Cyclonwave Buster (Wave)"_s},
|
||||
{303, "Warhorn Buster (Wave) (Motion)"_s},
|
||||
{396, "<hidden buster> (Wave)"_s},
|
||||
{397, "Short W Base Buster (Wave)"_s},
|
||||
{398, "Medium W Base Buster (Wave)"_s},
|
||||
{399, "Long W Base Buster (Wave)"_s},
|
||||
|
@ -363,6 +389,7 @@ static const std::map<std::int32_t, Containers::StringView> eshooter_busters {
|
|||
{400, "Wiredcharge Buster (Prism) (Motion)"_s},
|
||||
{402, "Heavyclamp Buster (Prism) (Motion)"_s},
|
||||
{402, "Curlescent Buster (Prism) (Motion)"_s},
|
||||
{496, "<hidden buster> (Prism)"_s},
|
||||
{499, "Long P Base Buster (Prism) (Motion)"_s},
|
||||
};
|
||||
// endregion
|
||||
|
@ -374,6 +401,7 @@ static const std::map<std::int32_t, Containers::StringView> blauncher_pods {
|
|||
{2, "Detector Launcher (Missile x12)"_s},
|
||||
{3, "BL-Triplet Pack Launcher (Missile x12)"_s},
|
||||
{4, "Shielded Launcher (Missile x12)"_s},
|
||||
{96, "<hidden launcher> (Missile x12)"_s},
|
||||
{99, "H Base Pod (Missile x12)"_s},
|
||||
|
||||
{100, "Warhead Pod (Nuke x2)"_s},
|
||||
|
@ -381,6 +409,7 @@ static const std::map<std::int32_t, Containers::StringView> blauncher_pods {
|
|||
{102, "Triangular Warhead Pod (Nuke x2)"_s},
|
||||
{103, "Expanded Warhead Pod (Nuke x2)"_s},
|
||||
{104, "Shielded Warhead Pod (Nuke x2)"_s},
|
||||
{196, "<hidden launcher> (Nuke x2)"_s},
|
||||
{199, "N Base Pod (Nuke x2)"_s},
|
||||
|
||||
{200, "Widepack Launcher (Salvo x24)"_s},
|
||||
|
@ -388,6 +417,7 @@ static const std::map<std::int32_t, Containers::StringView> blauncher_pods {
|
|||
{202, "Double Delta Launcher (Salvo x24)"_s},
|
||||
{203, "Hexagonal Launcher (Salvo x24)"_s},
|
||||
{204, "Shielded Six Launcher (Salvo x24)"_s},
|
||||
{296, "<hidden launcher> (Salvo x24)"_s},
|
||||
{299, "S Base Pod (Salvo x24)"_s},
|
||||
|
||||
{300, "Sentinel Cluster Pod (Cluster x40)"_s},
|
||||
|
@ -395,15 +425,17 @@ static const std::map<std::int32_t, Containers::StringView> blauncher_pods {
|
|||
{302, "Elliptical Cluster Pod (Cluster x40)"_s},
|
||||
{303, "Sawed Cluster Pod (Cluster x40)"_s},
|
||||
{304, "Pentagonal Cluster Pod (Cluster x40)"_s},
|
||||
{396, "<hidden launcher> (Cluster x40)"_s},
|
||||
{399, "C Base Pod (Cluster x40)"_s},
|
||||
};
|
||||
|
||||
static const std::map<std::int32_t, Containers::StringView> blauncher_projectiles {
|
||||
{0, "Flathead Missile"_s},
|
||||
{1, "Warhead Missile"_s},
|
||||
{2, "Pointhead Missile"_s},
|
||||
{3, "Marker Missile"_s},
|
||||
{4, "ArB Missile"_s},
|
||||
{0, "Flathead Missile"_s},
|
||||
{1, "Warhead Missile"_s},
|
||||
{2, "Pointhead Missile"_s},
|
||||
{3, "Marker Missile"_s},
|
||||
{4, "ArB Missile"_s},
|
||||
{96, "<hidden missile>"_s},
|
||||
};
|
||||
// endregion
|
||||
|
||||
|
@ -437,7 +469,8 @@ static const std::map<std::int32_t, Containers::StringView> elauncher_generators
|
|||
{25, "Carrier Unit"_s},
|
||||
{26, "Compartment Unit"_s},
|
||||
{27, "Flatedge Unit"_s},
|
||||
{99, "Base Generator"},
|
||||
{96, "<hidden generator>"_s},
|
||||
{99, "Base Generator"_s},
|
||||
};
|
||||
|
||||
static const std::map<std::int32_t, Containers::StringView> elauncher_pods {
|
||||
|
@ -448,6 +481,7 @@ static const std::map<std::int32_t, Containers::StringView> elauncher_pods {
|
|||
{4, "EN-Needler Launcher (Echo)"_s},
|
||||
{5, "Spark Launcher (Echo)"_s},
|
||||
{6, "Pinpoint Launcher (Echo)"_s},
|
||||
{96, "<hidden pod> (Echo)"_s},
|
||||
{99, "E Base EPod (Echo)"_s},
|
||||
|
||||
{100, "Raystream Launcher (Beam)"_s},
|
||||
|
@ -457,6 +491,7 @@ static const std::map<std::int32_t, Containers::StringView> elauncher_pods {
|
|||
{104, "Crosshair Launcher (Beam)"_s},
|
||||
{105, "Powerlined Launcher (Beam)"_s},
|
||||
{106, "Attached Launcher (Beam)"_s},
|
||||
{196, "<hidden pod> (Beam)"_s},
|
||||
{199, "B Base EPod (Beam)"_s},
|
||||
|
||||
{200, "Hilt Launcher (Slash) (Motion)"_s},
|
||||
|
@ -466,6 +501,7 @@ static const std::map<std::int32_t, Containers::StringView> elauncher_pods {
|
|||
{204, "Spike Launcher (Slash)"_s},
|
||||
{205, "Tri-Pronged Launcher (Slash) (Motion)"_s},
|
||||
{206, "Heavyblade Launcher (Slash)"_s},
|
||||
{296, "<hidden pod> (Slash)"_s},
|
||||
{299, "S Base EPod (Slash)"_s},
|
||||
|
||||
{300, "Covering Launcher (Photon)"_s},
|
||||
|
@ -475,6 +511,7 @@ static const std::map<std::int32_t, Containers::StringView> elauncher_pods {
|
|||
{304, "Shelled Launcher (Photon)"_s},
|
||||
{305, "Widearm Launcher (Photon)"_s},
|
||||
{306, "Wingspan Launcher (Photon)"_s},
|
||||
{396, "<hidden pod> (Photon)"_s},
|
||||
{399, "P Base EPod (Photon)"_s},
|
||||
};
|
||||
// endregion
|
||||
|
|
|
@ -293,7 +293,7 @@ Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayView<We
|
|||
auto parts_prop = weapon_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_ELEMENT);
|
||||
if(parts_prop->items.size() != weapon.parts.size()) {
|
||||
LOG_ERROR(_lastError = Utility::format("Weapon part arrays are not of the same size. Expected {}, got {} instead.",
|
||||
weapon.parts.size(), parts_prop->items.size()));
|
||||
weapon.parts.size(), parts_prop->items.size()));
|
||||
_state = State::Invalid;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
// 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::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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#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 "../GameObjects/CustomStyle.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
||||
namespace mbst::ImportExport {
|
||||
|
||||
auto lastExportError() -> Containers::StringView;
|
||||
|
||||
bool exportStyle(Containers::StringView mass_name, GameObjects::CustomStyle& style);
|
||||
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
// 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::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);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
#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 "../GameObjects/CustomStyle.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
||||
namespace mbst::ImportExport {
|
||||
|
||||
auto lastImportError() -> Containers::StringView;
|
||||
|
||||
auto importStyle(Containers::StringView filename) -> Containers::Optional<GameObjects::CustomStyle>;
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
#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::ImportExport::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
|
||||
};
|
||||
|
||||
}
|
2
third-party/SDL
vendored
2
third-party/SDL
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 1fa6142903b88007c7b77d324ee78fad9966871a
|
||||
Subproject commit 9791069d78747bbb0aeb9e62b18ecd62e728c466
|
2
third-party/corrade
vendored
2
third-party/corrade
vendored
|
@ -1 +1 @@
|
|||
Subproject commit f966f918bd7dec95002921227b6bd68ccbdda113
|
||||
Subproject commit 0b13b42ca0ca437152961b42639615264a2d3a52
|
2
third-party/curl
vendored
2
third-party/curl
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 9287563e86a5b2007fb67f68c075a87a93825861
|
||||
Subproject commit aed732acb1252dcd096c295ef28391c99422d2fb
|
1
third-party/efsw
vendored
1
third-party/efsw
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit 0c70ed2cd069a18d534989e8ae1c25ee39cba1f1
|
2
third-party/imgui
vendored
2
third-party/imgui
vendored
|
@ -1 +1 @@
|
|||
Subproject commit a8e96ae21a4ec10e5f02b19dd865dfffe8a98e67
|
||||
Subproject commit 1d069cf43527bdf81b42289f7c385efac129c3a0
|
2
third-party/libzip
vendored
2
third-party/libzip
vendored
|
@ -1 +1 @@
|
|||
Subproject commit aa90b70e552709316cd2144837c3dd13b5fa1ec3
|
||||
Subproject commit 6ba97d4167023c3421e37d3420490b467410d9b8
|
2
third-party/magnum
vendored
2
third-party/magnum
vendored
|
@ -1 +1 @@
|
|||
Subproject commit a40020f3fff91dc9c59148f52adb0d48203799eb
|
||||
Subproject commit 1d2a1c1b3e979ff3b8bd5eacadc780e3c1359945
|
2
third-party/magnum-integration
vendored
2
third-party/magnum-integration
vendored
|
@ -1 +1 @@
|
|||
Subproject commit bf09698491f2061733dc263f375da1f02f41d8ec
|
||||
Subproject commit 697ddd2cccf17aa03987da9a2213af99cd6d4cd3
|
Loading…
Reference in a new issue