281 lines
9.9 KiB
C++
281 lines
9.9 KiB
C++
#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 <mutex>
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
#include <Corrade/Containers/Pointer.h>
|
|
#include <Corrade/Containers/String.h>
|
|
#include <Corrade/Utility/Resource.h>
|
|
#ifdef SAVETOOL_DEBUG_BUILD
|
|
#include <Corrade/Utility/Tweakable.h>
|
|
#endif
|
|
|
|
#include <Magnum/Timeline.h>
|
|
#include <Magnum/Platform/Sdl2Application.h>
|
|
#include <Magnum/ImGuiIntegration/Context.h>
|
|
|
|
#include <SDL_timer.h>
|
|
|
|
#include <imgui.h>
|
|
#include <imgui_internal.h>
|
|
|
|
#include <efsw/efsw.hpp>
|
|
|
|
#include "../Managers/BackupManager.h"
|
|
#include "../Managers/MassManager.h"
|
|
#include "../Managers/ProfileManager.h"
|
|
#include "../ToastQueue/ToastQueue.h"
|
|
#include "../UpdateChecker/UpdateChecker.h"
|
|
|
|
#ifdef SAVETOOL_DEBUG_BUILD
|
|
#define tw CORRADE_TWEAKABLE
|
|
#endif
|
|
|
|
using namespace Corrade;
|
|
using namespace Containers::Literals;
|
|
using namespace Magnum;
|
|
|
|
namespace mbst {
|
|
|
|
class Application: public Platform::Sdl2Application, public efsw::FileWatchListener {
|
|
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;
|
|
|
|
private:
|
|
// Events
|
|
void drawEvent() override;
|
|
void viewportEvent(ViewportEvent& event) override;
|
|
|
|
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 textInputEvent(TextInputEvent& event) override;
|
|
|
|
void anyEvent(SDL_Event& event) override;
|
|
|
|
enum InitStatus: std::int32_t {
|
|
InitSuccess,
|
|
ProfileManagerFailure
|
|
};
|
|
void initEvent(SDL_Event& event);
|
|
|
|
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();
|
|
void drawGui();
|
|
void drawMainMenu();
|
|
void drawDisclaimer();
|
|
void drawInitialisation();
|
|
|
|
void drawProfileManager();
|
|
void drawBackupListPopup();
|
|
void drawBackupRestorePopup(std::size_t backup_index);
|
|
void drawBackupDeletePopup(std::size_t backup_index);
|
|
void drawDeleteProfilePopup(std::size_t profile_index);
|
|
|
|
void drawManager();
|
|
bool drawIntEditPopup(int* value_to_edit, int max);
|
|
bool drawRenamePopup(Containers::ArrayView<char> name_view);
|
|
void drawGeneralInfo();
|
|
void drawResearchInventory();
|
|
void drawMaterialRow(Containers::StringView name, std::int32_t tier, GameData::MaterialID id);
|
|
void drawUnavailableMaterialRow(Containers::StringView name, std::int32_t tier);
|
|
void drawMassManager();
|
|
void drawDeleteMassPopup(int mass_index);
|
|
void drawDeleteStagedMassPopup(Containers::StringView filename);
|
|
|
|
void drawMassViewer();
|
|
void drawFrameInfo();
|
|
void drawJointSliders();
|
|
void drawFrameStyles();
|
|
void drawEyeColourPicker();
|
|
void drawCustomFrameStyles();
|
|
void drawArmour();
|
|
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 drawWeaponEditor(GameObjects::Weapon& weapon);
|
|
void drawGlobalStyles();
|
|
void drawTuning();
|
|
void drawDecalEditor(GameObjects::Decal& decal);
|
|
void drawAccessoryEditor(GameObjects::Accessory& accessory,
|
|
Containers::ArrayView<GameObjects::CustomStyle> style_view);
|
|
auto getStyleName(std::int32_t id, Containers::ArrayView<GameObjects::CustomStyle> view)
|
|
-> Containers::StringView;
|
|
|
|
enum DCSResult {
|
|
DCS_Fail,
|
|
DCS_ResetStyle,
|
|
DCS_Save
|
|
};
|
|
auto drawCustomStyle(GameObjects::CustomStyle& style) -> DCSResult;
|
|
|
|
void drawAbout();
|
|
void drawGameState();
|
|
|
|
// Convenience wrappers over ImGui stuff
|
|
void drawHelpMarker(Containers::StringView text, float wrap_pos = 0.0f);
|
|
void drawTooltip(Containers::StringView text, float wrap_pos = 0.0f);
|
|
bool drawCheckbox(Containers::StringView label, bool value);
|
|
|
|
template<typename Functor, typename... Args>
|
|
bool drawUnsafeWidget(Functor func, Args... 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)...);
|
|
ImGui::EndDisabled();
|
|
return result;
|
|
} // Obviously, should only be used with ImGui widgets that return a bool.
|
|
// Also, func should be a lambda if there are any default arguments, like ImGui::Button(), etc...
|
|
|
|
template<typename... Args>
|
|
void drawUnsafeText(const char* text, Args... args) { // Alternative to the above, for ImGui::Text*() variants.
|
|
if(_gameState != GameState::NotRunning) {
|
|
ImGui::TextDisabled(text, std::forward<Args>(args)...);
|
|
}
|
|
else {
|
|
ImGui::Text(text, std::forward<Args>(args)...);
|
|
}
|
|
}
|
|
|
|
template<typename... Args>
|
|
void drawAlignedText(Containers::StringView text, Args... args) {
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::Text(text.data(), std::forward<Args>(args)...);
|
|
}
|
|
|
|
void openUri(Containers::StringView uri);
|
|
|
|
void checkGameState();
|
|
|
|
void checkForUpdates();
|
|
|
|
Utility::Resource _rs{"assets"_s};
|
|
|
|
// GUI-related members
|
|
ImGuiIntegration::Context _imgui{NoCreate};
|
|
|
|
enum class UiState: uint8_t {
|
|
Disclaimer,
|
|
Initialising,
|
|
ProfileManager,
|
|
MainManager,
|
|
MassViewer
|
|
} _uiState{UiState::Disclaimer};
|
|
|
|
bool _aboutPopup = false;
|
|
#ifdef SAVETOOL_DEBUG_BUILD
|
|
bool _demoWindow = false;
|
|
bool _styleEditor = false;
|
|
bool _metricsWindow = false;
|
|
#endif
|
|
|
|
ToastQueue _queue;
|
|
|
|
std::thread _initThread;
|
|
std::thread _updateThread;
|
|
|
|
std::uint32_t _initEventId;
|
|
std::uint32_t _updateEventId;
|
|
std::uint32_t _fileEventId;
|
|
|
|
Containers::String _lastError;
|
|
|
|
enum class GameState : std::uint8_t {
|
|
Unknown, NotRunning, Running
|
|
} _gameState{GameState::Unknown};
|
|
|
|
SDL_TimerID _gameCheckTimerId = 0;
|
|
|
|
Containers::Pointer<Managers::ProfileManager> _profileManager;
|
|
GameObjects::Profile* _currentProfile = nullptr;
|
|
|
|
Containers::Pointer<Managers::BackupManager> _backupManager;
|
|
|
|
Containers::Pointer<Managers::MassManager> _massManager;
|
|
GameObjects::Mass* _currentMass = nullptr;
|
|
|
|
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};
|
|
Containers::StaticArray<38, std::int32_t> _selectedArmourAccessories{ValueInit};
|
|
std::uint32_t _selectedBLPlacement = 0;
|
|
std::int32_t _selectedWeaponPart = 0;
|
|
std::int32_t _selectedWeaponDecal = 0;
|
|
std::int32_t _selectedWeaponAccessory = 0;
|
|
|
|
Timeline _timeline;
|
|
};
|
|
|
|
}
|