#pragma once // MassBuilderSaveTool // Copyright (C) 2021-2022 Guillaume Jacquemin // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include #include #include #include #include #include #include #include "../ProfileManager/ProfileManager.h" #include "../MassManager/MassManager.h" #include "../ToastQueue/ToastQueue.h" #ifdef SAVETOOL_DEBUG_BUILD #include #define tw CORRADE_TWEAKABLE #endif using namespace Corrade; using namespace Magnum; class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener { public: explicit SaveTool(const Arguments& arguments); ~SaveTool() 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: Int { InitSuccess, ProfileManagerFailure }; void initEvent(SDL_Event& event); void updateCheckEvent(SDL_Event& event); // Initialisation methods void initialiseConfiguration(); void initialiseGui(); void initialiseManager(); auto findGameDataDirectory() -> bool; void initialiseMassManager(); void initialiseFileWatcher(); // GUI-related methods void drawImGui(); void drawGui(); void drawMainMenu(); void drawDisclaimer(); void drawInitialisation(); void drawProfileManager(); auto drawBackupListPopup() -> ImGuiID; auto drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID; auto drawDeleteProfilePopup(std::size_t profile_index) -> ImGuiID; void drawManager(); auto drawIntEditPopup(int* value_to_edit, int max) -> bool; auto drawRenamePopup(Containers::ArrayView name_view) -> bool; void drawGeneralInfo(); void drawResearchInventory(); void drawMassManager(); auto drawDeleteMassPopup(int mass_index) -> ImGuiID; auto drawDeleteStagedMassPopup(const std::string& filename) -> ImGuiID; void drawMassViewer(); void drawFrameInfo(); void drawJointSliders(); void drawFrameStyles(); void drawEyeColourPicker(); void drawCustomFrameStyles(); void drawArmour(); void drawCustomArmourStyles(); void drawWeapons(); void drawWeaponEditor(Weapon& weapon); void drawGlobalStyles(); void drawTuning(); void drawDecalEditor(Decal& decal); void drawAccessoryEditor(Accessory& accessory, Containers::ArrayView style_view); auto getStyleName(Int id, Containers::ArrayView view) -> const char*; enum DCSResult { DCS_Fail, DCS_ResetStyle, DCS_Save }; auto drawCustomStyle(CustomStyle& style) -> DCSResult; void drawAbout(); void drawGameState(); // Convenience wrappers over ImGui stuff void drawHelpMarker(const char* text, Float wrap_pos = 0.0f); void drawTooltip(const char* text, Float wrap_pos = 0.0f); template auto drawUnsafeWidget(Functor func, Args... args) -> bool { GameState game_state = _gameState; // Copying the value to reduce the risk of a data race. if(!_unsafeMode && game_state != GameState::NotRunning) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5f); } bool result = func(std::forward(args)...); if(!_unsafeMode && game_state != GameState::NotRunning) { ImGui::PopItemFlag(); ImGui::PopStyleVar(); } 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 void drawUnsafeText(const char* text, Args... args) { // Alternative to the above, for ImGui::Text*() variants. if(!_unsafeMode && _gameState != GameState::NotRunning) { ImGui::TextDisabled(text, std::forward(args)...); } else { ImGui::Text(text, std::forward(args)...); } } void openUri(const std::string& uri); void checkGameState(); void checkForUpdates(); Utility::Configuration _conf{"MassBuilderSaveTool.ini"}; Utility::Resource _rs{"assets"}; // 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; UnsignedInt _initEventId; UnsignedInt _updateEventId; std::string _lastError; std::string _gameDataDir; std::string _configDir; std::string _saveDir; std::string _screenshotsDir; std::string _backupsDir; std::string _stagingDir; std::string _armouryDir; std::string _armoursDir; std::string _weaponsDir; std::string _stylesDir; enum class GameState : UnsignedByte { Unknown, NotRunning, Running } _gameState{GameState::Unknown}; SDL_TimerID _gameCheckTimerId = 0; Containers::Pointer _profileManager; Profile* _currentProfile{nullptr}; Containers::Pointer _massManager; Mass* _currentMass{nullptr}; Containers::Pointer _fileWatcher; enum watchID { SaveDir = 0, StagingDir = 1 }; Containers::StaticArray<2, efsw::WatchID> _watchIDs; enum class Framelimit: UnsignedByte { Vsync, HalfVsync, FpsCap } _framelimit{Framelimit::Vsync}; UnsignedInt _fpsCap{60}; bool _skipDisclaimer{false}; bool _checkUpdatesOnStartup{true}; bool _unsafeMode{false}; bool _updateAvailable{false}; std::string _latestVersion; std::string _releaseLink; std::string _downloadLink; bool _jointsDirty{false}; bool _stylesDirty{false}; bool _eyeFlareDirty{false}; Containers::StaticArray<38, Int> _selectedArmourDecals{ValueInit}; Containers::StaticArray<38, Int> _selectedArmourAccessories{ValueInit}; Int _selectedWeaponPart{0}; Int _selectedWeaponDecal{0}; Int _selectedWeaponAccessory{0}; bool _meleeDirty{false}; bool _shieldsDirty{false}; bool _bShootersDirty{false}; bool _eShootersDirty{false}; bool _bLaunchersDirty{false}; bool _eLaunchersDirty{false}; bool _cheatMode{false}; };