MassBuilderSaveTool/src/SaveTool/SaveTool.h

298 lines
10 KiB
C++

#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 <https://www.gnu.org/licenses/>.
#include <string>
#include <thread>
#include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Configuration.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 "../ProfileManager/ProfileManager.h"
#include "../MassManager/MassManager.h"
#include "../ToastQueue/ToastQueue.h"
#ifdef SAVETOOL_DEBUG_BUILD
#define tw CORRADE_TWEAKABLE
#endif
using namespace Corrade;
using namespace Containers::Literals;
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);
enum UpdateCheckStatus : Int {
CurlInitFailed = 0,
CurlError = 1,
CurlTimeout = 2,
};
void updateCheckEvent(SDL_Event& event);
enum FileEventType: Int {
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();
auto initialiseToolDirectories() -> bool;
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<char> name_view) -> bool;
void drawGeneralInfo();
void drawResearchInventory();
template<typename Getter, typename Setter>
void drawMaterialRow(Containers::StringView name, Int tier, Getter getter, Setter setter);
void drawUnavailableMaterialRow(Containers::StringView name, Int tier);
void drawMassManager();
auto drawDeleteMassPopup(int mass_index) -> ImGuiID;
auto drawDeleteStagedMassPopup(Containers::StringView filename) -> ImGuiID;
void drawMassViewer();
void drawFrameInfo();
void drawJointSliders();
void drawFrameStyles();
void drawEyeColourPicker();
void drawCustomFrameStyles();
void drawArmour();
void drawCustomArmourStyles();
void drawWeapons();
void drawWeaponCategory(Containers::StringView name, Containers::ArrayView<Weapon> weapons_view, bool& dirty,
Containers::StringView payload_type, Containers::StringView payload_tooltip);
void drawWeaponEditor(Weapon& weapon);
void drawGlobalStyles();
void drawTuning();
void drawDecalEditor(Decal& decal);
void drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<CustomStyle> style_view);
auto getStyleName(Int id, Containers::ArrayView<CustomStyle> view) -> Containers::StringView;
enum DCSResult {
DCS_Fail,
DCS_ResetStyle,
DCS_Save
};
auto drawCustomStyle(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);
template<typename Functor, typename... Args>
auto drawUnsafeWidget(Functor func, Args... args) -> bool {
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::Configuration _conf{"MassBuilderSaveTool.ini"_s};
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;
UnsignedInt _initEventId;
UnsignedInt _updateEventId;
UnsignedInt _fileEventId;
Containers::String _lastError;
Containers::String _gameDataDir;
Containers::String _configDir;
Containers::String _saveDir;
Containers::String _screenshotsDir;
Containers::String _backupsDir;
Containers::String _stagingDir;
//Containers::String _armouryDir;
//Containers::String _armoursDir;
//Containers::String _weaponsDir;
//Containers::String _stylesDir;
enum class GameState : UnsignedByte {
Unknown, NotRunning, Running
} _gameState{GameState::Unknown};
SDL_TimerID _gameCheckTimerId = 0;
Containers::Pointer<ProfileManager> _profileManager;
Profile* _currentProfile{nullptr};
Containers::Pointer<MassManager> _massManager;
Mass* _currentMass{nullptr};
Weapon* _currentWeapon = nullptr;
Containers::Pointer<efsw::FileWatcher> _fileWatcher;
enum watchID {
SaveDir = 0,
StagingDir = 1
};
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
int _swapInterval = 1;
float _fpsCap = 60.0f;
bool _skipDisclaimer{false};
bool _checkUpdatesOnStartup{true};
bool _updateAvailable{false};
Containers::String _latestVersion;
Containers::String _releaseLink;
Containers::String _downloadLink;
bool _modifiedBySaveTool{false};
bool _jointsDirty{false};
bool _stylesDirty{false};
bool _eyeFlareDirty{false};
Containers::StaticArray<38, Int> _selectedArmourDecals{ValueInit};
Containers::StaticArray<38, Int> _selectedArmourAccessories{ValueInit};
Int _selectedBLPlacement{0};
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};
bool _advancedMode{false};
Timeline _timeline;
};