267 lines
10 KiB
C++
267 lines
10 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 <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 "../Managers/BackupManager.h"
|
|
#include "../Managers/MassManager.h"
|
|
#include "../Managers/ProfileManager.h"
|
|
#include "../Managers/StagedMassManager.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:
|
|
explicit Application(const Arguments& arguments);
|
|
|
|
virtual ~Application();
|
|
|
|
private:
|
|
// Events
|
|
void drawEvent() override;
|
|
void viewportEvent(ViewportEvent& event) override;
|
|
|
|
void keyPressEvent(KeyEvent& event) override;
|
|
void keyReleaseEvent(KeyEvent& 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;
|
|
|
|
enum InitStatus: std::int32_t {
|
|
InitSuccess,
|
|
ProfileManagerFailure
|
|
};
|
|
void initEvent(SDL_Event& event);
|
|
|
|
void updateCheckEvent(SDL_Event& event);
|
|
|
|
// Initialisation methods
|
|
void initialiseConfiguration();
|
|
void initialiseGui();
|
|
void initialiseManager();
|
|
void initialiseMassManager();
|
|
|
|
// GUI-related methods
|
|
void drawImGui();
|
|
void drawGui();
|
|
void drawMainMenu();
|
|
void drawDisclaimer();
|
|
void drawInitialisation();
|
|
|
|
void drawProfileManager();
|
|
void drawBackupListPopup();
|
|
void drawBackupFolder(const Managers::Vfs::Directory<Managers::Backup>& dir);
|
|
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 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, 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();
|
|
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);
|
|
void drawVector3Drag(Containers::StringView id, Vector3& vec, float speed, Vector3 min, Vector3 max,
|
|
const char* x_format, const char* y_format, const char* z_format,
|
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
|
void drawVector3dDrag(Containers::StringView id, Vector3d& vec, float speed, Vector3d min, Vector3d max,
|
|
const char* x_format, const char* y_format, const char* z_format,
|
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
|
void drawVector3Slider(Containers::StringView id, Vector3& vec, Vector3 min, Vector3 max, const char* x_format,
|
|
const char* y_format, const char* z_format,
|
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
|
void drawVector3dSlider(Containers::StringView id, Vector3d& vec, Vector3d min, Vector3d max,
|
|
const char* x_format, const char* y_format, const char* z_format,
|
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
|
void drawVector2Slider(Containers::StringView id, Vector2& vec, Vector2 min, Vector2 max, const char* x_format,
|
|
const char* y_format, ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
|
void drawVector2dSlider(Containers::StringView id, Vector2d& vec, Vector2d min, Vector2d max,
|
|
const char* x_format, const char* y_format,
|
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
|
|
|
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)...);
|
|
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;
|
|
|
|
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;
|
|
|
|
Containers::Pointer<Managers::StagedMassManager> _stagedMassManager;
|
|
|
|
GameObjects::Weapon* _currentWeapon = nullptr;
|
|
|
|
Containers::Optional<UpdateChecker> _checker{Containers::NullOpt};
|
|
std::mutex _checkerMutex;
|
|
|
|
bool _jointsDirty = false;
|
|
bool _stylesDirty = false;
|
|
bool _eyeFlareDirty = 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;
|
|
};
|
|
|
|
}
|