Compare commits
113 Commits
Author | SHA1 | Date |
---|---|---|
Guillaume Jacquemin | 7b64d78b5b | |
Guillaume Jacquemin | 59aa006611 | |
Guillaume Jacquemin | 81b35476a0 | |
Guillaume Jacquemin | b909f0ac13 | |
Guillaume Jacquemin | aff84ccc96 | |
Guillaume Jacquemin | 8177d61755 | |
Guillaume Jacquemin | c0943bd084 | |
Guillaume Jacquemin | 6fa21128ab | |
Guillaume Jacquemin | a8ab212931 | |
Guillaume Jacquemin | 9a7aaaeaca | |
Guillaume Jacquemin | b3bf75918e | |
Guillaume Jacquemin | 9de6766750 | |
Guillaume Jacquemin | 90ff680aff | |
Guillaume Jacquemin | 07fca7b0d0 | |
Guillaume Jacquemin | 4ea694ea6e | |
Guillaume Jacquemin | 722cc511d6 | |
Guillaume Jacquemin | 924838ecb4 | |
Guillaume Jacquemin | dfd0d56ab0 | |
Guillaume Jacquemin | 89a10ff98d | |
Guillaume Jacquemin | 71fde374a9 | |
Guillaume Jacquemin | c7cc3ba76c | |
Guillaume Jacquemin | 0aa933e766 | |
Guillaume Jacquemin | 5ea6f1e3a7 | |
Guillaume Jacquemin | 32046d9bf8 | |
Guillaume Jacquemin | 3c4dfbda9a | |
Guillaume Jacquemin | d1712bf8cb | |
Guillaume Jacquemin | 567546489f | |
Guillaume Jacquemin | c054169124 | |
Guillaume Jacquemin | b58ff5a763 | |
Guillaume Jacquemin | 28eb40f6b4 | |
Guillaume Jacquemin | d0a3375d7a | |
Guillaume Jacquemin | 393ec4a372 | |
Guillaume Jacquemin | 83e9169dae | |
Guillaume Jacquemin | 8625f8835c | |
Guillaume Jacquemin | c3a9c8dd31 | |
Guillaume Jacquemin | 51b25ea9c5 | |
Guillaume Jacquemin | 1421257c4f | |
Guillaume Jacquemin | df5fa7a39e | |
Guillaume Jacquemin | c5b4747685 | |
Guillaume Jacquemin | 7ddc8e0748 | |
Guillaume Jacquemin | 7392d961c7 | |
Guillaume Jacquemin | fa81d2428e | |
Guillaume Jacquemin | 79c97733db | |
Guillaume Jacquemin | 060daebe17 | |
Guillaume Jacquemin | 8cf5351f0b | |
Guillaume Jacquemin | e795e276da | |
Guillaume Jacquemin | bf820f65ec | |
Guillaume Jacquemin | fb6246cff7 | |
Guillaume Jacquemin | 7257b9865c | |
Guillaume Jacquemin | 45bc2b97d9 | |
Guillaume Jacquemin | 9de62db449 | |
Guillaume Jacquemin | 44656b32d5 | |
Guillaume Jacquemin | 9ec88fa521 | |
Guillaume Jacquemin | ee540b601e | |
Guillaume Jacquemin | fe10bbb3f3 | |
Guillaume Jacquemin | bb066d3134 | |
Guillaume Jacquemin | e21e7a1aba | |
Guillaume Jacquemin | 714d8cc6bb | |
Guillaume Jacquemin | a33cbdfad6 | |
Guillaume Jacquemin | b7cd78ca21 | |
Guillaume Jacquemin | 453c5391a4 | |
Guillaume Jacquemin | 05611d59b1 | |
Guillaume Jacquemin | a5a8db289a | |
Guillaume Jacquemin | 6130734764 | |
Guillaume Jacquemin | 16b8807eb7 | |
Guillaume Jacquemin | f1ea2bda25 | |
Guillaume Jacquemin | 42cec59c71 | |
Guillaume Jacquemin | 5c6a83c03b | |
Guillaume Jacquemin | e6c597ffbc | |
Guillaume Jacquemin | 6cb52761be | |
Guillaume Jacquemin | 6f2b19dbc3 | |
Guillaume Jacquemin | e61d4bba85 | |
Guillaume Jacquemin | 38532d8c35 | |
Guillaume Jacquemin | 8ba8ec3219 | |
Guillaume Jacquemin | 55eb367eb2 | |
Guillaume Jacquemin | b6398f3373 | |
Guillaume Jacquemin | b598476809 | |
Guillaume Jacquemin | 0ce03f5395 | |
Guillaume Jacquemin | 0fd157f33c | |
Guillaume Jacquemin | 1bbbf3cbfd | |
Guillaume Jacquemin | 918ead0733 | |
Guillaume Jacquemin | 42b4974b43 | |
Guillaume Jacquemin | c35735b2fc | |
Guillaume Jacquemin | 32a1a6d014 | |
Guillaume Jacquemin | 71d38f4a91 | |
Guillaume Jacquemin | 869ca07b20 | |
Guillaume Jacquemin | c1ae793800 | |
Guillaume Jacquemin | 70ddb0ce39 | |
Guillaume Jacquemin | 704f6e2f49 | |
Guillaume Jacquemin | dbc52ec28f | |
Guillaume Jacquemin | 11c089d408 | |
Guillaume Jacquemin | 6b280b2668 | |
Guillaume Jacquemin | 213269521d | |
Guillaume Jacquemin | b6ad795383 | |
Guillaume Jacquemin | 94979907b1 | |
Guillaume Jacquemin | a36d9134bf | |
Guillaume Jacquemin | 0e3e3145b7 | |
Guillaume Jacquemin | 3be094febc | |
Guillaume Jacquemin | a166948aec | |
Guillaume Jacquemin | b909aa85b7 | |
Guillaume Jacquemin | 94f6192aa8 | |
Guillaume Jacquemin | 5705f408a5 | |
Guillaume Jacquemin | 4ed7aff835 | |
Guillaume Jacquemin | 718a6fd754 | |
Guillaume Jacquemin | 677bf21c9f | |
Guillaume Jacquemin | b287c827d2 | |
Guillaume Jacquemin | 2c2e5ad936 | |
Guillaume Jacquemin | ef05c075ba | |
Guillaume Jacquemin | 14d75e0e83 | |
Guillaume Jacquemin | 63a8cf7075 | |
Guillaume Jacquemin | bf3288772e | |
Guillaume Jacquemin | bde6fc41a0 | |
Guillaume Jacquemin | ac1276761e |
|
@ -1,4 +1,4 @@
|
||||||
build*/
|
*build*/
|
||||||
.idea/
|
.idea/
|
||||||
*.kdev4
|
*.kdev4
|
||||||
*~
|
*~
|
||||||
|
|
|
@ -26,11 +26,7 @@
|
||||||
path = third-party/efsw
|
path = third-party/efsw
|
||||||
url = https://github.com/SpartanJ/efsw
|
url = https://github.com/SpartanJ/efsw
|
||||||
branch = master
|
branch = master
|
||||||
[submodule "third-party/cpr"]
|
[submodule "libcurl"]
|
||||||
path = third-party/cpr
|
path = third-party/curl
|
||||||
url = https://github.com/whoshuu/cpr
|
url = https://github.com/curl/curl
|
||||||
branch = master
|
|
||||||
[submodule "json.hpp"]
|
|
||||||
path = third-party/json
|
|
||||||
url = https://github.com/nlohmann/json
|
|
||||||
branch = master
|
branch = master
|
||||||
|
|
|
@ -21,16 +21,20 @@ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/modules/" ${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
||||||
|
|
||||||
set(BUILD_STATIC ON CACHE BOOL "" FORCE)
|
set(CORRADE_BUILD_DEPRECATED OFF CACHE BOOL "" FORCE)
|
||||||
set(BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
|
set(CORRADE_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
||||||
set(BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
|
set(CORRADE_BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_INTERCONNECT ON CACHE BOOL "" FORCE)
|
set(CORRADE_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_PLUGINMANAGER ON CACHE BOOL "" FORCE)
|
set(CORRADE_WITH_INTERCONNECT OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_TESTSUITE OFF CACHE BOOL "" FORCE)
|
set(CORRADE_WITH_PLUGINMANAGER OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_MAIN ON CACHE BOOL "" FORCE)
|
set(CORRADE_WITH_TESTSUITE OFF CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_WITH_MAIN ON CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_UTILITY_USE_ANSI_COLORS ON CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/corrade EXCLUDE_FROM_ALL)
|
add_subdirectory(third-party/corrade EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(DIRECTX OFF CACHE BOOL "" FORCE) # We use OpenGL.
|
||||||
set(SDL_ATOMIC OFF CACHE BOOL "" FORCE)
|
set(SDL_ATOMIC OFF CACHE BOOL "" FORCE)
|
||||||
set(SDL_CPUINFO OFF CACHE BOOL "" FORCE)
|
set(SDL_CPUINFO OFF CACHE BOOL "" FORCE)
|
||||||
set(SDL_EVENTS ON CACHE BOOL "" FORCE)
|
set(SDL_EVENTS ON CACHE BOOL "" FORCE)
|
||||||
|
@ -46,26 +50,34 @@ set(SDL_TIMERS ON CACHE BOOL "" FORCE)
|
||||||
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
|
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/SDL EXCLUDE_FROM_ALL)
|
add_subdirectory(third-party/SDL EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
set(TARGET_GL ON CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
||||||
set(TARGET_GLES OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
|
||||||
set(TARGET_VK OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_AUDIO OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_DEPRECATED OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_DEBUGTOOLS OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_GL ON CACHE BOOL "" FORCE)
|
|
||||||
set(WITH_MESHTOOLS OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_TARGET_GL ON CACHE BOOL "" FORCE)
|
||||||
set(WITH_PRIMITIVES OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_TARGET_GLES OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_SCENEGRAPH OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_TARGET_VK OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_SHADERS ON CACHE BOOL "" FORCE)
|
set(MAGNUM_WITH_AUDIO OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_SHADERTOOLS OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_WITH_DEBUGTOOLS OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_TEXT OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_WITH_GL ON CACHE BOOL "" FORCE)
|
||||||
set(WITH_TEXTURETOOLS OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_WITH_MATERIALTOOLS OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_TRADE OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_WITH_MESHTOOLS OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_VK OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_WITH_PRIMITIVES OFF CACHE BOOL "" FORCE)
|
||||||
set(WITH_SDL2APPLICATION ON CACHE BOOL "" FORCE)
|
set(MAGNUM_WITH_SCENEGRAPH OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_SCENETOOLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_SHADERS ON CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_SHADERTOOLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_TEXT OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_TEXTURETOOLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_TRADE OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_VK OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_SDL2APPLICATION ON CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/magnum EXCLUDE_FROM_ALL)
|
add_subdirectory(third-party/magnum EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third-party/imgui)
|
set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third-party/imgui)
|
||||||
set(WITH_IMGUI ON CACHE BOOL "" FORCE)
|
set(MAGNUM_WITH_IMGUI ON CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/magnum-integration EXCLUDE_FROM_ALL)
|
add_subdirectory(third-party/magnum-integration EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
|
set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
|
||||||
|
@ -80,7 +92,6 @@ set(BUILD_TOOLS OFF CACHE BOOL "" FORCE)
|
||||||
set(BUILD_REGRESS OFF CACHE BOOL "" FORCE)
|
set(BUILD_REGRESS OFF CACHE BOOL "" FORCE)
|
||||||
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||||
set(BUILD_DOC OFF CACHE BOOL "" FORCE)
|
set(BUILD_DOC OFF CACHE BOOL "" FORCE)
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
|
||||||
add_subdirectory(third-party/libzip EXCLUDE_FROM_ALL)
|
add_subdirectory(third-party/libzip EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
set(VERBOSE OFF CACHE BOOL "" FORCE)
|
set(VERBOSE OFF CACHE BOOL "" FORCE)
|
||||||
|
@ -88,11 +99,20 @@ set(BUILD_TEST_APP OFF CACHE BOOL "" FORCE)
|
||||||
set(EFSW_INSTALL OFF CACHE BOOL "" FORCE)
|
set(EFSW_INSTALL OFF CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/efsw EXCLUDE_FROM_ALL)
|
add_subdirectory(third-party/efsw EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
set(CPR_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
||||||
set(CMAKE_USE_LIBSSH2 OFF CACHE BOOL "" FORCE) # For some reason, even when HTTP_ONLY is set to ON, libcurl will try to link to libssh2.
|
set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/cpr EXCLUDE_FROM_ALL)
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_UNICODE ON CACHE BOOL "" FORCE)
|
||||||
set(JSON_BuildTests OFF CACHE BOOL "" FORCE)
|
set(ENABLE_INET_PTON OFF CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/json)
|
set(ENABLE_DEBUG OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_THREADED_RESOLVER OFF CACHE BOOL "" FORCE)
|
||||||
|
set(HTTP_ONLY ON CACHE BOOL "" FORCE)
|
||||||
|
set(USE_LIBIDN2 OFF CACHE BOOL "" FORCE)
|
||||||
|
set(USE_WIN32_IDN ON CACHE BOOL "" FORCE)
|
||||||
|
set(CURL_USE_LIBPSL OFF CACHE BOOL "" FORCE)
|
||||||
|
set(CURL_STATIC_CRT OFF CACHE BOOL "" FORCE)
|
||||||
|
set(CURL_USE_SCHANNEL ON CACHE BOOL "" FORCE)
|
||||||
|
set(CURL_USE_LIBSSH2 OFF CACHE BOOL "" FORCE) # For some reason, even when HTTP_ONLY is set to ON, libcurl will try to link to libssh2.
|
||||||
|
add_subdirectory(third-party/curl EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
14
README.md
14
README.md
|
@ -1,16 +1,20 @@
|
||||||
# M.A.S.S. Builder Save Tool
|
# M.A.S.S. Builder Save Tool
|
||||||
|
|
||||||
A save file manager and editor for M.A.S.S. Builder. Based on [wxMASSManager](https://williamjcm.ovh/git/williamjcm/wxMASSManager), this is a fork using Magnum and ImGui for the UI.
|
A save file manager and editor for M.A.S.S. Builder. Based on [wxMASSManager](https://git.williamjcm.ovh/williamjcm/wxMASSManager),
|
||||||
|
this is a fork using Magnum and ImGui for the UI.
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
Get the `MassBuilderSaveTool-<version>.zip` file from the [Releases](https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool/releases) page, and extract it somewhere. Then, launch `MassBuilderSaveTool.exe`.
|
Get the `MassBuilderSaveTool-<version>.zip` file from the [the main website](https://williamjcm.ovh/mbst) or on the
|
||||||
|
[Releases](https://git.williamjcm.ovh/williamjcm/MassBuilderSaveTool/releases) page, and extract it somewhere. Then,
|
||||||
|
launch `MassBuilderSaveTool-<version>.exe`.
|
||||||
|
|
||||||
## Building on MSYS2 - IGNORE IF YOU JUST WANT TO USE THE APP!
|
## Building on MSYS2 - IGNORE IF YOU JUST WANT TO USE THE APP!
|
||||||
|
|
||||||
1. Install the 64-bit (`x86_64`) version of [MSYS2](https://www.msys2.org/) in its default path (`C:\msys64`), and update it fully.
|
1. Install the 64-bit (`x86_64`) version of [MSYS2](https://www.msys2.org/) in its default path (`C:\msys64`), and
|
||||||
2. Run `pacman -S git mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja`.
|
update it fully.
|
||||||
3. In a `MINGW64` shell, type `git clone https://github.com/williamjcm/MassBuilderSaveTool`.
|
2. Run `pacman -S git mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja`.
|
||||||
|
3. In a `URCT64` shell, type `git clone https://github.com/williamjcm/MassBuilderSaveTool`.
|
||||||
4. Type `cd MassBuilderSaveTool && git submodule init && git submodule update && mkdir build && cd build`.
|
4. Type `cd MassBuilderSaveTool && git submodule init && git submodule update && mkdir build && cd build`.
|
||||||
5. Type `cmake -GNinja -DCMAKE_BUILD_TYPE=Release ..`
|
5. Type `cmake -GNinja -DCMAKE_BUILD_TYPE=Release ..`
|
||||||
6. Type `ninja`
|
6. Type `ninja`
|
||||||
|
|
|
@ -11,4 +11,16 @@
|
||||||
/>
|
/>
|
||||||
</dependentAssembly>
|
</dependentAssembly>
|
||||||
</dependency>
|
</dependency>
|
||||||
</assembly>
|
<asmv3:application>
|
||||||
|
<asmv3:windowsSettings>
|
||||||
|
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
|
||||||
|
UTF-8
|
||||||
|
</activeCodePage>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
|
||||||
|
true/pm</dpiAware> <!-- legacy -->
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||||
|
permonitorv2,permonitor
|
||||||
|
</dpiAwareness> <!-- falls back to pm if pmv2 is not available -->
|
||||||
|
</asmv3:windowsSettings>
|
||||||
|
</asmv3:application>
|
||||||
|
</assembly>
|
||||||
|
|
|
@ -18,9 +18,9 @@ set(CMAKE_CXX_STANDARD 14)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
set(SAVETOOL_PROJECT_VERSION 1.3.1)
|
set(SAVETOOL_PROJECT_VERSION 1.4.3)
|
||||||
|
|
||||||
find_package(Corrade REQUIRED Main Containers Utility Interconnect)
|
find_package(Corrade REQUIRED Main Containers Utility)
|
||||||
find_package(Magnum REQUIRED GL Sdl2Application)
|
find_package(Magnum REQUIRED GL Sdl2Application)
|
||||||
find_package(MagnumIntegration REQUIRED ImGui)
|
find_package(MagnumIntegration REQUIRED ImGui)
|
||||||
|
|
||||||
|
@ -28,85 +28,101 @@ set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON)
|
||||||
|
|
||||||
corrade_add_resource(Assets assets.conf)
|
corrade_add_resource(Assets assets.conf)
|
||||||
|
|
||||||
|
add_library(Logger STATIC EXCLUDE_FROM_ALL
|
||||||
|
Logger/Logger.h
|
||||||
|
Logger/Logger.cpp
|
||||||
|
Logger/EntryType.h
|
||||||
|
Logger/MagnumLogBuffer.h
|
||||||
|
Logger/MagnumLogBuffer.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(Logger PRIVATE
|
||||||
|
Corrade::Utility
|
||||||
|
Magnum::Magnum
|
||||||
|
)
|
||||||
|
|
||||||
add_library(UESaveFile STATIC EXCLUDE_FROM_ALL
|
add_library(UESaveFile STATIC EXCLUDE_FROM_ALL
|
||||||
UESaveFile/Serialisers/AbstractUnrealCollectionPropertySerialiser.h
|
UESaveFile/Serialisers/AbstractUnrealCollectionPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/AbstractUnrealPropertySerialiser.h
|
UESaveFile/Serialisers/AbstractUnrealPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/AbstractUnrealStructSerialiser.h
|
UESaveFile/Serialisers/AbstractUnrealStructSerialiser.h
|
||||||
UESaveFile/Serialisers/ArrayPropertySerialiser.h
|
UESaveFile/Serialisers/ArrayPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/ArrayPropertySerialiser.cpp
|
UESaveFile/Serialisers/ArrayPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/BoolPropertySerialiser.h
|
UESaveFile/Serialisers/BoolPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/BoolPropertySerialiser.cpp
|
UESaveFile/Serialisers/BoolPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/BytePropertySerialiser.h
|
UESaveFile/Serialisers/BytePropertySerialiser.h
|
||||||
UESaveFile/Serialisers/BytePropertySerialiser.cpp
|
UESaveFile/Serialisers/BytePropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/ColourPropertySerialiser.h
|
UESaveFile/Serialisers/ColourPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/ColourPropertySerialiser.cpp
|
UESaveFile/Serialisers/ColourPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/DateTimePropertySerialiser.h
|
UESaveFile/Serialisers/DateTimePropertySerialiser.h
|
||||||
UESaveFile/Serialisers/DateTimePropertySerialiser.cpp
|
UESaveFile/Serialisers/DateTimePropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/EnumPropertySerialiser.h
|
UESaveFile/Serialisers/EnumPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/EnumPropertySerialiser.cpp
|
UESaveFile/Serialisers/EnumPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/FloatPropertySerialiser.h
|
UESaveFile/Serialisers/FloatPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/FloatPropertySerialiser.cpp
|
UESaveFile/Serialisers/FloatPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/GuidPropertySerialiser.h
|
UESaveFile/Serialisers/GuidPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/GuidPropertySerialiser.cpp
|
UESaveFile/Serialisers/GuidPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/IntPropertySerialiser.h
|
UESaveFile/Serialisers/IntPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/IntPropertySerialiser.cpp
|
UESaveFile/Serialisers/IntPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/MapPropertySerialiser.h
|
UESaveFile/Serialisers/MapPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/MapPropertySerialiser.cpp
|
UESaveFile/Serialisers/MapPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/ResourcePropertySerialiser.h
|
UESaveFile/Serialisers/ResourcePropertySerialiser.h
|
||||||
UESaveFile/Serialisers/ResourcePropertySerialiser.cpp
|
UESaveFile/Serialisers/ResourcePropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/RotatorPropertySerialiser.h
|
UESaveFile/Serialisers/RotatorPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/RotatorPropertySerialiser.cpp
|
UESaveFile/Serialisers/RotatorPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/StringPropertySerialiser.h
|
UESaveFile/Serialisers/StringPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/StringPropertySerialiser.cpp
|
UESaveFile/Serialisers/StringPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/SetPropertySerialiser.h
|
UESaveFile/Serialisers/SetPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/SetPropertySerialiser.cpp
|
UESaveFile/Serialisers/SetPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/StructSerialiser.h
|
UESaveFile/Serialisers/StructSerialiser.h
|
||||||
UESaveFile/Serialisers/StructSerialiser.cpp
|
UESaveFile/Serialisers/StructSerialiser.cpp
|
||||||
UESaveFile/Serialisers/TextPropertySerialiser.h
|
UESaveFile/Serialisers/TextPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/TextPropertySerialiser.cpp
|
UESaveFile/Serialisers/TextPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/UnrealPropertySerialiser.h
|
UESaveFile/Serialisers/UnrealPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/VectorPropertySerialiser.h
|
UESaveFile/Serialisers/VectorPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/VectorPropertySerialiser.cpp
|
UESaveFile/Serialisers/VectorPropertySerialiser.cpp
|
||||||
UESaveFile/Serialisers/Vector2DPropertySerialiser.h
|
UESaveFile/Serialisers/Vector2DPropertySerialiser.h
|
||||||
UESaveFile/Serialisers/Vector2DPropertySerialiser.cpp
|
UESaveFile/Serialisers/Vector2DPropertySerialiser.cpp
|
||||||
|
|
||||||
UESaveFile/Types/ArrayProperty.h
|
UESaveFile/Types/ArrayProperty.h
|
||||||
UESaveFile/Types/BoolProperty.h
|
UESaveFile/Types/BoolProperty.h
|
||||||
UESaveFile/Types/ByteProperty.h
|
UESaveFile/Types/ByteProperty.h
|
||||||
UESaveFile/Types/ColourStructProperty.h
|
UESaveFile/Types/ColourStructProperty.h
|
||||||
UESaveFile/Types/DateTimeStructProperty.h
|
UESaveFile/Types/DateTimeStructProperty.h
|
||||||
UESaveFile/Types/EnumProperty.h
|
UESaveFile/Types/EnumProperty.h
|
||||||
UESaveFile/Types/FloatProperty.h
|
UESaveFile/Types/FloatProperty.h
|
||||||
UESaveFile/Types/GenericStructProperty.h
|
UESaveFile/Types/GenericStructProperty.h
|
||||||
UESaveFile/Types/GuidStructProperty.h
|
UESaveFile/Types/GuidStructProperty.h
|
||||||
UESaveFile/Types/IntProperty.h
|
UESaveFile/Types/IntProperty.h
|
||||||
UESaveFile/Types/MapProperty.h
|
UESaveFile/Types/MapProperty.h
|
||||||
UESaveFile/Types/NoneProperty.h
|
UESaveFile/Types/NoneProperty.h
|
||||||
UESaveFile/Types/RotatorStructProperty.h
|
UESaveFile/Types/RotatorStructProperty.h
|
||||||
UESaveFile/Types/SetProperty.h
|
UESaveFile/Types/SetProperty.h
|
||||||
UESaveFile/Types/StringProperty.h
|
UESaveFile/Types/StringProperty.h
|
||||||
UESaveFile/Types/StructProperty.h
|
UESaveFile/Types/StructProperty.h
|
||||||
UESaveFile/Types/ResourceItemValue.h
|
UESaveFile/Types/ResourceItemValue.h
|
||||||
UESaveFile/Types/TextProperty.h
|
UESaveFile/Types/TextProperty.h
|
||||||
UESaveFile/Types/UnrealProperty.h
|
UESaveFile/Types/UnrealProperty.h
|
||||||
UESaveFile/Types/UnrealPropertyBase.h
|
UESaveFile/Types/UnrealPropertyBase.h
|
||||||
UESaveFile/Types/VectorStructProperty.h
|
UESaveFile/Types/VectorStructProperty.h
|
||||||
|
|
||||||
UESaveFile/Debug.h
|
UESaveFile/Debug.h
|
||||||
UESaveFile/Debug.cpp
|
UESaveFile/Debug.cpp
|
||||||
UESaveFile/UESaveFile.h
|
UESaveFile/UESaveFile.h
|
||||||
UESaveFile/UESaveFile.cpp
|
UESaveFile/UESaveFile.cpp
|
||||||
UESaveFile/BinaryReader.h
|
UESaveFile/BinaryReader.h
|
||||||
UESaveFile/BinaryReader.cpp
|
UESaveFile/BinaryReader.cpp
|
||||||
UESaveFile/BinaryWriter.h
|
UESaveFile/BinaryWriter.h
|
||||||
UESaveFile/BinaryWriter.cpp
|
UESaveFile/BinaryWriter.cpp
|
||||||
UESaveFile/PropertySerialiser.h
|
UESaveFile/PropertySerialiser.h
|
||||||
UESaveFile/PropertySerialiser.cpp)
|
UESaveFile/PropertySerialiser.cpp
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(UESaveFile PRIVATE
|
target_link_libraries(UESaveFile PRIVATE
|
||||||
Corrade::Containers
|
Corrade::Containers
|
||||||
Corrade::Utility
|
Corrade::Utility
|
||||||
Magnum::Magnum)
|
Magnum::Magnum
|
||||||
|
Logger
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(MassBuilderSaveTool WIN32
|
add_executable(MassBuilderSaveTool WIN32
|
||||||
main.cpp
|
main.cpp
|
||||||
|
@ -114,16 +130,20 @@ add_executable(MassBuilderSaveTool WIN32
|
||||||
SaveTool/SaveTool.cpp
|
SaveTool/SaveTool.cpp
|
||||||
SaveTool/SaveTool_drawAbout.cpp
|
SaveTool/SaveTool_drawAbout.cpp
|
||||||
SaveTool/SaveTool_drawMainMenu.cpp
|
SaveTool/SaveTool_drawMainMenu.cpp
|
||||||
|
SaveTool/SaveTool_FileWatcher.cpp
|
||||||
|
SaveTool/SaveTool_Initialisation.cpp
|
||||||
SaveTool/SaveTool_MainManager.cpp
|
SaveTool/SaveTool_MainManager.cpp
|
||||||
SaveTool/SaveTool_MassViewer.cpp
|
SaveTool/SaveTool_MassViewer.cpp
|
||||||
SaveTool/SaveTool_MassViewer_Frame.cpp
|
SaveTool/SaveTool_MassViewer_Frame.cpp
|
||||||
SaveTool/SaveTool_MassViewer_Armour.cpp
|
SaveTool/SaveTool_MassViewer_Armour.cpp
|
||||||
SaveTool/SaveTool_MassViewer_Weapons.cpp
|
SaveTool/SaveTool_MassViewer_Weapons.cpp
|
||||||
SaveTool/SaveTool_ProfileManager.cpp
|
SaveTool/SaveTool_ProfileManager.cpp
|
||||||
|
SaveTool/SaveTool_UpdateChecker.cpp
|
||||||
ProfileManager/ProfileManager.h
|
ProfileManager/ProfileManager.h
|
||||||
ProfileManager/ProfileManager.cpp
|
ProfileManager/ProfileManager.cpp
|
||||||
Profile/Profile.h
|
Profile/Profile.h
|
||||||
Profile/Profile.cpp
|
Profile/Profile.cpp
|
||||||
|
Profile/PropertyNames.h
|
||||||
Profile/ResourceIDs.h
|
Profile/ResourceIDs.h
|
||||||
MassManager/MassManager.h
|
MassManager/MassManager.h
|
||||||
MassManager/MassManager.cpp
|
MassManager/MassManager.cpp
|
||||||
|
@ -140,6 +160,7 @@ add_executable(MassBuilderSaveTool WIN32
|
||||||
Mass/Mass_Weapons.cpp
|
Mass/Mass_Weapons.cpp
|
||||||
Mass/Mass_Styles.cpp
|
Mass/Mass_Styles.cpp
|
||||||
Mass/Mass_DecalsAccessories.cpp
|
Mass/Mass_DecalsAccessories.cpp
|
||||||
|
Mass/PropertyNames.h
|
||||||
Mass/Weapon.h
|
Mass/Weapon.h
|
||||||
Mass/Weapon.cpp
|
Mass/Weapon.cpp
|
||||||
Mass/WeaponPart.h
|
Mass/WeaponPart.h
|
||||||
|
@ -153,6 +174,7 @@ add_executable(MassBuilderSaveTool WIN32
|
||||||
Maps/LastMissionId.h
|
Maps/LastMissionId.h
|
||||||
Maps/StoryProgress.h
|
Maps/StoryProgress.h
|
||||||
Maps/StyleNames.h
|
Maps/StyleNames.h
|
||||||
|
Maps/WeaponParts.h
|
||||||
Maps/WeaponTypes.hpp
|
Maps/WeaponTypes.hpp
|
||||||
ToastQueue/ToastQueue.h
|
ToastQueue/ToastQueue.h
|
||||||
ToastQueue/ToastQueue.cpp
|
ToastQueue/ToastQueue.cpp
|
||||||
|
@ -160,14 +182,17 @@ add_executable(MassBuilderSaveTool WIN32
|
||||||
FontAwesome/IconsFontAwesome5.h
|
FontAwesome/IconsFontAwesome5.h
|
||||||
FontAwesome/IconsFontAwesome5Brands.h
|
FontAwesome/IconsFontAwesome5Brands.h
|
||||||
resource.rc
|
resource.rc
|
||||||
${Assets})
|
${Assets}
|
||||||
|
)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||||
add_compile_definitions(SAVETOOL_DEBUG_BUILD)
|
add_compile_definitions(SAVETOOL_DEBUG_BUILD)
|
||||||
endif()
|
endif()
|
||||||
add_compile_definitions(SAVETOOL_VERSION="${SAVETOOL_PROJECT_VERSION}"
|
add_compile_definitions(
|
||||||
SAVETOOL_CODENAME="Dickish Cyclops"
|
SAVETOOL_VERSION="${SAVETOOL_PROJECT_VERSION}"
|
||||||
SUPPORTED_GAME_VERSION="0.8.6")
|
SAVETOOL_CODENAME="Enigmatic Ellenier"
|
||||||
|
SUPPORTED_GAME_VERSION="0.9.x"
|
||||||
|
)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL Release)
|
if(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||||
set_target_properties(MassBuilderSaveTool PROPERTIES OUTPUT_NAME MassBuilderSaveTool-${SAVETOOL_PROJECT_VERSION})
|
set_target_properties(MassBuilderSaveTool PROPERTIES OUTPUT_NAME MassBuilderSaveTool-${SAVETOOL_PROJECT_VERSION})
|
||||||
|
@ -182,16 +207,16 @@ endif()
|
||||||
target_link_libraries(MassBuilderSaveTool PRIVATE
|
target_link_libraries(MassBuilderSaveTool PRIVATE
|
||||||
Corrade::Containers
|
Corrade::Containers
|
||||||
Corrade::Utility
|
Corrade::Utility
|
||||||
Corrade::Interconnect
|
|
||||||
Corrade::Main
|
Corrade::Main
|
||||||
Magnum::Magnum
|
Magnum::Magnum
|
||||||
Magnum::GL
|
Magnum::GL
|
||||||
Magnum::Sdl2Application
|
Magnum::Sdl2Application
|
||||||
MagnumIntegration::ImGui
|
MagnumIntegration::ImGui
|
||||||
|
Logger
|
||||||
UESaveFile
|
UESaveFile
|
||||||
efsw
|
efsw
|
||||||
zip
|
zip
|
||||||
cpr::cpr
|
libcurl
|
||||||
nlohmann_json::nlohmann_json
|
|
||||||
imm32
|
imm32
|
||||||
wtsapi32)
|
wtsapi32
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#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/>.
|
||||||
|
|
||||||
|
enum class EntryType {
|
||||||
|
Info,
|
||||||
|
Warning,
|
||||||
|
Error,
|
||||||
|
};
|
|
@ -0,0 +1,112 @@
|
||||||
|
// 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 <iostream>
|
||||||
|
|
||||||
|
#include <Corrade/Utility/Debug.h>
|
||||||
|
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
using Containers::Array;
|
||||||
|
using Utility::Debug;
|
||||||
|
using Utility::Warning;
|
||||||
|
using Utility::Error;
|
||||||
|
|
||||||
|
using namespace Magnum;
|
||||||
|
|
||||||
|
Logger&
|
||||||
|
Logger::instance() {
|
||||||
|
static Logger logger;
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Logger::initialise() {
|
||||||
|
#ifndef SAVETOOL_DEBUG_BUILD
|
||||||
|
_logFile.open("SaveToolLog.txt", std::ios::trunc);
|
||||||
|
_logFile << "In case you encounter a bug:\n" <<
|
||||||
|
"1. Do not run the Save Tool again, as this log will be cleared.\n" <<
|
||||||
|
"2. Go to either the official Sekai Project Discord guild, or the community M.A.S.S. Builder one.\n" <<
|
||||||
|
"3. Mention me (William JCM#2301) to get my attention, with a description of the bug.\n"
|
||||||
|
" Please include as many details as possible, I don't want to play \"20 questions\", and neither do you.\n" <<
|
||||||
|
"4. Send me this file _when I ask for it_, preferably in DMs.\n" <<
|
||||||
|
std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Logger::indent() {
|
||||||
|
_indentLevel++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Logger::unindent() {
|
||||||
|
if(_indentLevel > 0) {
|
||||||
|
_indentLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Logger::log(EntryType type, StringView location, StringView message) {
|
||||||
|
Debug d{
|
||||||
|
#ifndef SAVETOOL_DEBUG_BUILD
|
||||||
|
&_logFile
|
||||||
|
#else
|
||||||
|
&std::cout
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
|
#define COLOURED_TEXT(colour, text) Debug::color(Debug::Color::colour) << (text) << Debug::resetColor
|
||||||
|
#else
|
||||||
|
#define COLOURED_TEXT(colour, text) (text)
|
||||||
|
#endif
|
||||||
|
switch(type) {
|
||||||
|
case EntryType::Info:
|
||||||
|
d << COLOURED_TEXT(Default, "[ INFO]"_s);
|
||||||
|
break;
|
||||||
|
case EntryType::Warning:
|
||||||
|
d << COLOURED_TEXT(Yellow, "[WARNING]"_s);
|
||||||
|
break;
|
||||||
|
case EntryType::Error:
|
||||||
|
d << COLOURED_TEXT(Red, "[ ERROR]"_s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#undef COLOURED_TEXT
|
||||||
|
|
||||||
|
d << "["_s << Debug::nospace << location << Debug::nospace << "]";
|
||||||
|
|
||||||
|
for(UnsignedInt i = 0; i < _indentLevel; i++) {
|
||||||
|
d << Debug::nospace << " "_s << Debug::nospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
d << ((message.back() == '\n') ? message.exceptSuffix(1) : message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Logger::lockMutex() {
|
||||||
|
_logMutex.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Logger::unlockMutex() {
|
||||||
|
_logMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger&
|
||||||
|
logger() {
|
||||||
|
return Logger::instance();
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
#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 <ctime>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#ifndef SAVETOOL_DEBUG_BUILD
|
||||||
|
#include <fstream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Corrade/Containers/String.h>
|
||||||
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
|
#include <Corrade/Utility/Format.h>
|
||||||
|
|
||||||
|
#include <Magnum/Types.h>
|
||||||
|
|
||||||
|
#include "EntryType.h"
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
|
||||||
|
using Containers::ArrayView;
|
||||||
|
using Containers::String;
|
||||||
|
using Containers::StringView;
|
||||||
|
|
||||||
|
using namespace Magnum;
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
public:
|
||||||
|
Logger(const Logger&) = delete;
|
||||||
|
Logger& operator=(const Logger&) = delete;
|
||||||
|
|
||||||
|
Logger(Logger&&) = delete;
|
||||||
|
Logger& operator=(Logger&&) = delete;
|
||||||
|
|
||||||
|
static auto instance() -> Logger&;
|
||||||
|
|
||||||
|
void initialise();
|
||||||
|
|
||||||
|
void indent();
|
||||||
|
void unindent();
|
||||||
|
|
||||||
|
void log(EntryType type, StringView location, StringView message);
|
||||||
|
|
||||||
|
void lockMutex();
|
||||||
|
void unlockMutex();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logger() = default;
|
||||||
|
|
||||||
|
#ifndef SAVETOOL_DEBUG_BUILD
|
||||||
|
std::ofstream _logFile;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UnsignedInt _indentLevel = 0;
|
||||||
|
|
||||||
|
std::mutex _logMutex{};
|
||||||
|
};
|
||||||
|
|
||||||
|
auto logger() -> Logger&;
|
||||||
|
|
||||||
|
#define LOG(entry_type, message) logger().lockMutex(); \
|
||||||
|
logger().log(EntryType::entry_type, \
|
||||||
|
Utility::format("{}:{}", StringView{__builtin_FILE()}.find("src"_s).data() + 4, __builtin_LINE()), \
|
||||||
|
message); \
|
||||||
|
logger().unlockMutex()
|
||||||
|
|
||||||
|
#define LOG_INFO(message) LOG(Info, message)
|
||||||
|
#define LOG_WARNING(message) LOG(Warning, message)
|
||||||
|
#define LOG_ERROR(message) LOG(Error, message)
|
||||||
|
|
||||||
|
#define LOG_INFO_FORMAT(message, ...) LOG_INFO(Utility::format(message, __VA_ARGS__))
|
||||||
|
#define LOG_WARNING_FORMAT(message, ...) LOG_WARNING(Utility::format(message, __VA_ARGS__))
|
||||||
|
#define LOG_ERROR_FORMAT(message, ...) LOG_ERROR(Utility::format(message, __VA_ARGS__))
|
|
@ -0,0 +1,30 @@
|
||||||
|
// 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 "MagnumLogBuffer.h"
|
||||||
|
|
||||||
|
MagnumLogBuffer::MagnumLogBuffer(EntryType type): std::stringbuf(std::ios_base::out), _type{type} {}
|
||||||
|
|
||||||
|
MagnumLogBuffer::~MagnumLogBuffer() = default;
|
||||||
|
|
||||||
|
int
|
||||||
|
MagnumLogBuffer::sync() {
|
||||||
|
logger().lockMutex();
|
||||||
|
logger().log(_type, "Corrade/Magnum"_s, str().c_str());
|
||||||
|
logger().unlockMutex();
|
||||||
|
str({});
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
#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 <sstream>
|
||||||
|
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
#include "EntryType.h"
|
||||||
|
|
||||||
|
class MagnumLogBuffer : public std::stringbuf {
|
||||||
|
public:
|
||||||
|
explicit MagnumLogBuffer(EntryType type);
|
||||||
|
~MagnumLogBuffer();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int sync() override;
|
||||||
|
|
||||||
|
EntryType _type;
|
||||||
|
};
|
|
@ -26,53 +26,659 @@ using namespace Corrade;
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
|
||||||
static const std::map<Int, Containers::StringView> accessories {
|
enum AccessorySize {
|
||||||
// Primitives
|
S,
|
||||||
{1, "Cube (S)"_s},
|
M,
|
||||||
{2, "Pentagon (S)"_s},
|
L,
|
||||||
{3, "Hexagon (S)"_s},
|
XL
|
||||||
{4, "Cylinder (S)"_s},
|
};
|
||||||
{5, "Sphere (S)"_s},
|
|
||||||
{6, "TriPyramid (S)"_s},
|
struct AccessoryData{
|
||||||
{7, "SquPyramid (S)"_s},
|
Containers::StringView name;
|
||||||
{8, "PenPyramid (S)"_s},
|
AccessorySize size = AccessorySize::S;
|
||||||
{9, "HexPyramid (S)"_s},
|
};
|
||||||
{10, "Cone (S)"_s},
|
|
||||||
{11, "SquStick (S)"_s},
|
static const std::map<Int, AccessoryData> accessories {
|
||||||
{12, "PenStick (S)"_s},
|
// region Primitives
|
||||||
{13, "HexStick (S)"_s},
|
{1, {"Cube"_s, AccessorySize::S}},
|
||||||
{14, "CycStick (S)"_s},
|
{2, {"Pentagon"_s, AccessorySize::S}},
|
||||||
{15, "Capsule (S)"_s},
|
{3, {"Hexagon"_s, AccessorySize::S}},
|
||||||
{16, "Decal Pad 01 (S)"_s},
|
{4, {"Cylinder"_s, AccessorySize::S}},
|
||||||
{17, "Decal Pad 02 (S)"_s},
|
{5, {"Sphere"_s, AccessorySize::S}},
|
||||||
{18, "Decal Pad 03 (S)"_s},
|
{6, {"TriPyramid"_s, AccessorySize::S}},
|
||||||
{19, "Decal Pad 04 (S)"_s},
|
{7, {"SquPyramid"_s, AccessorySize::S}},
|
||||||
{20, "Decal Pad 05 (S)"_s},
|
{8, {"PenPyramid"_s, AccessorySize::S}},
|
||||||
|
{9, {"HexPyramid"_s, AccessorySize::S}},
|
||||||
{51, "SquBevel (S)"_s},
|
{10, {"Cone"_s, AccessorySize::S}},
|
||||||
{52, "TriBevel (S)"_s},
|
{11, {"SquStick"_s, AccessorySize::S}},
|
||||||
{53, "PenBevel (S)"_s},
|
{12, {"PenStick"_s, AccessorySize::S}},
|
||||||
{54, "HexBevel (S)"_s},
|
{13, {"HexStick"_s, AccessorySize::S}},
|
||||||
{55, "CycBevel (S)"_s},
|
{14, {"CycStick"_s, AccessorySize::S}},
|
||||||
{56, "RecBevel (S)"_s},
|
{15, {"Capsule"_s, AccessorySize::S}},
|
||||||
{57, "DaiBevel (S)"_s},
|
{16, {"Decal Pad 01"_s, AccessorySize::S}},
|
||||||
{58, "MonBevel (S)"_s},
|
{17, {"Decal Pad 02"_s, AccessorySize::S}},
|
||||||
{59, "CofBevel (S)"_s},
|
{18, {"Decal Pad 03"_s, AccessorySize::S}},
|
||||||
{60, "JevBevel (S)"_s},
|
{19, {"Decal Pad 04"_s, AccessorySize::S}},
|
||||||
{61, "SquEmboss (S)"_s},
|
{20, {"Decal Pad 05"_s, AccessorySize::S}},
|
||||||
{62, "TriEmboss (S)"_s},
|
{21, {"Triangle"_s, AccessorySize::S}},
|
||||||
{63, "PenEmboss (S)"_s},
|
{22, {"ThinStar"_s, AccessorySize::S}},
|
||||||
{64, "HexEmboss (S)"_s},
|
{23, {"Star"_s, AccessorySize::S}},
|
||||||
{65, "CycEmboss (S)"_s},
|
{24, {"SixSideStar"_s, AccessorySize::S}},
|
||||||
{66, "RecEmboss (S)"_s},
|
{25, {"Asterisk"_s, AccessorySize::S}},
|
||||||
{67, "DaiEmboss (S)"_s},
|
{26, {"Ring"_s, AccessorySize::S}},
|
||||||
{68, "MonEmboss (S)"_s},
|
{27, {"SawedRing"_s, AccessorySize::S}},
|
||||||
{69, "CofEmboss (S)"_s},
|
{28, {"HalfRing"_s, AccessorySize::S}},
|
||||||
{70, "JevEmboss (S)"_s},
|
{29, {"Cresent"_s, AccessorySize::S}},
|
||||||
|
{30, {"Donut"_s, AccessorySize::S}},
|
||||||
// Armours
|
{31, {"FiveCogWheel"_s, AccessorySize::S}},
|
||||||
|
{32, {"SixCogWheel"_s, AccessorySize::S}},
|
||||||
// Components
|
{33, {"SevenCogWheel"_s, AccessorySize::S}},
|
||||||
|
{34, {"EightCogWheel"_s, AccessorySize::S}},
|
||||||
// Connectors
|
{35, {"TwelveCogWheel"_s, AccessorySize::S}},
|
||||||
|
|
||||||
|
{51, {"SquBevel"_s, AccessorySize::S}},
|
||||||
|
{52, {"TriBevel"_s, AccessorySize::S}},
|
||||||
|
{53, {"PenBevel"_s, AccessorySize::S}},
|
||||||
|
{54, {"HexBevel"_s, AccessorySize::S}},
|
||||||
|
{55, {"CycBevel"_s, AccessorySize::S}},
|
||||||
|
{56, {"RecBevel"_s, AccessorySize::S}},
|
||||||
|
{57, {"DaiBevel"_s, AccessorySize::S}},
|
||||||
|
{58, {"MonBevel"_s, AccessorySize::S}},
|
||||||
|
{59, {"CofBevel"_s, AccessorySize::S}},
|
||||||
|
{60, {"JevBevel"_s, AccessorySize::S}},
|
||||||
|
{61, {"SquEmboss"_s, AccessorySize::S}},
|
||||||
|
{62, {"TriEmboss"_s, AccessorySize::S}},
|
||||||
|
{63, {"PenEmboss"_s, AccessorySize::S}},
|
||||||
|
{64, {"HexEmboss"_s, AccessorySize::S}},
|
||||||
|
{65, {"CycEmboss"_s, AccessorySize::S}},
|
||||||
|
{66, {"RecEmboss"_s, AccessorySize::S}},
|
||||||
|
{67, {"DaiEmboss"_s, AccessorySize::S}},
|
||||||
|
{68, {"MonEmboss"_s, AccessorySize::S}},
|
||||||
|
{69, {"CofEmboss"_s, AccessorySize::S}},
|
||||||
|
{70, {"JevEmboss"_s, AccessorySize::S}},
|
||||||
|
|
||||||
|
{101, {"Flat Hex Pin"_s, AccessorySize::S}},
|
||||||
|
{102, {"Cross Circle Pin"_s, AccessorySize::S}},
|
||||||
|
{103, {"Flat Circle Pin"_s, AccessorySize::S}},
|
||||||
|
{104, {"Hex Circle Pin"_s, AccessorySize::S}},
|
||||||
|
{105, {"Circle Button Pin"_s, AccessorySize::S}},
|
||||||
|
{106, {"Hexagon Pin"_s, AccessorySize::S}},
|
||||||
|
{107, {"Cross Square Pin"_s, AccessorySize::S}},
|
||||||
|
{108, {"Flat Square Pin"_s, AccessorySize::S}},
|
||||||
|
{109, {"Quad Corner Pin"_s, AccessorySize::S}},
|
||||||
|
{110, {"Bi Corner Pin"_s, AccessorySize::S}},
|
||||||
|
{111, {"Circle Pin"_s, AccessorySize::S}},
|
||||||
|
{112, {"Flat End Pin"_s, AccessorySize::S}},
|
||||||
|
{113, {"Flat Cut Pin"_s, AccessorySize::S}},
|
||||||
|
{114, {"Radial Pin"_s, AccessorySize::S}},
|
||||||
|
{115, {"Diamiter Pin"_s, AccessorySize::S}},
|
||||||
|
|
||||||
|
{151, {"TriPoint"_s, AccessorySize::S}},
|
||||||
|
{152, {"SquPoint"_s, AccessorySize::S}},
|
||||||
|
{153, {"PenPoint"_s, AccessorySize::S}},
|
||||||
|
{154, {"HexPoint"_s, AccessorySize::S}},
|
||||||
|
{155, {"CycPoint"_s, AccessorySize::S}},
|
||||||
|
{156, {"Bevel SquCutPoint"_s, AccessorySize::S}},
|
||||||
|
{157, {"Bevel HexCutPoint"_s, AccessorySize::S}},
|
||||||
|
{158, {"Bevel HexPoint"_s, AccessorySize::S}},
|
||||||
|
{159, {"Bevel CycCutPoint"_s, AccessorySize::S}},
|
||||||
|
{160, {"Bevel CycPoint"_s, AccessorySize::S}},
|
||||||
|
|
||||||
|
{201, {"Shaped Edge 01"_s, AccessorySize::M}},
|
||||||
|
{202, {"Shaped Edge 02"_s, AccessorySize::M}},
|
||||||
|
{203, {"Shaped Edge 03"_s, AccessorySize::M}},
|
||||||
|
{204, {"Shaped Edge 04"_s, AccessorySize::M}},
|
||||||
|
{205, {"Shaped Edge 05"_s, AccessorySize::M}},
|
||||||
|
{206, {"Shaped Edge 06"_s, AccessorySize::M}},
|
||||||
|
{207, {"Shaped Edge 07"_s, AccessorySize::M}},
|
||||||
|
{208, {"Shaped Edge 08"_s, AccessorySize::M}},
|
||||||
|
{209, {"Shaped Edge 09"_s, AccessorySize::M}},
|
||||||
|
{210, {"Shaped Edge 10"_s, AccessorySize::M}},
|
||||||
|
{211, {"Shaped Edge 11"_s, AccessorySize::M}},
|
||||||
|
{212, {"Shaped Edge 12"_s, AccessorySize::M}},
|
||||||
|
{213, {"Shaped Edge 13"_s, AccessorySize::M}},
|
||||||
|
{214, {"Shaped Edge 14"_s, AccessorySize::M}},
|
||||||
|
{215, {"Shaped Edge 15"_s, AccessorySize::M}},
|
||||||
|
{216, {"Shaped Edge 16"_s, AccessorySize::M}},
|
||||||
|
{217, {"Shaped Edge 17"_s, AccessorySize::M}},
|
||||||
|
{218, {"Shaped Edge 18"_s, AccessorySize::M}},
|
||||||
|
{219, {"Shaped Edge 19"_s, AccessorySize::M}},
|
||||||
|
{220, {"Shaped Edge 20"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{251, {"Fish Tail 01"_s, AccessorySize::M}},
|
||||||
|
{252, {"Fish Tail 02"_s, AccessorySize::M}},
|
||||||
|
{253, {"Fish Tail 03"_s, AccessorySize::M}},
|
||||||
|
{254, {"Fish Tail 04"_s, AccessorySize::M}},
|
||||||
|
{255, {"Fish Tail 05"_s, AccessorySize::M}},
|
||||||
|
{256, {"Based Separator 01"_s, AccessorySize::M}},
|
||||||
|
{257, {"Based Separator 02"_s, AccessorySize::M}},
|
||||||
|
{258, {"Based Separator 03"_s, AccessorySize::M}},
|
||||||
|
{259, {"Based Separator 04"_s, AccessorySize::M}},
|
||||||
|
{260, {"Based Separator 05"_s, AccessorySize::M}},
|
||||||
|
{261, {"Based Separator 06"_s, AccessorySize::M}},
|
||||||
|
{262, {"Based Separator 07"_s, AccessorySize::M}},
|
||||||
|
{263, {"Based Separator 08"_s, AccessorySize::M}},
|
||||||
|
{264, {"Based Separator 09"_s, AccessorySize::M}},
|
||||||
|
{265, {"Based Separator 10"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{301, {"Rectangular Box 01"_s, AccessorySize::M}},
|
||||||
|
{302, {"Rectangular Box 02"_s, AccessorySize::M}},
|
||||||
|
{303, {"Rectangular Box 03"_s, AccessorySize::M}},
|
||||||
|
{304, {"Rectangular Box 04"_s, AccessorySize::M}},
|
||||||
|
{305, {"Rectangular Box 05"_s, AccessorySize::M}},
|
||||||
|
{306, {"CofBox 01"_s, AccessorySize::M}},
|
||||||
|
{307, {"CofBox 02"_s, AccessorySize::M}},
|
||||||
|
{308, {"CofBox 03"_s, AccessorySize::M}},
|
||||||
|
{309, {"CofBox 04"_s, AccessorySize::M}},
|
||||||
|
{310, {"CofBox 05"_s, AccessorySize::M}},
|
||||||
|
{311, {"Triangular Box 01"_s, AccessorySize::M}},
|
||||||
|
{312, {"Triangular Box 02"_s, AccessorySize::M}},
|
||||||
|
{313, {"Triangular Box 03"_s, AccessorySize::M}},
|
||||||
|
{314, {"Triangular Box 04"_s, AccessorySize::M}},
|
||||||
|
{315, {"Triangular Box 05"_s, AccessorySize::M}},
|
||||||
|
{316, {"Diagonal Box A01"_s, AccessorySize::M}},
|
||||||
|
{317, {"Diagonal Box A02"_s, AccessorySize::M}},
|
||||||
|
{318, {"Diagonal Box A03"_s, AccessorySize::M}},
|
||||||
|
{319, {"Diagonal Box A04"_s, AccessorySize::M}},
|
||||||
|
{320, {"Diagonal Box A05"_s, AccessorySize::M}},
|
||||||
|
{321, {"Diagonal Box B01"_s, AccessorySize::M}},
|
||||||
|
{322, {"Diagonal Box B02"_s, AccessorySize::M}},
|
||||||
|
{323, {"Diagonal Box B03"_s, AccessorySize::M}},
|
||||||
|
{324, {"Diagonal Box B04"_s, AccessorySize::M}},
|
||||||
|
{325, {"Diagonal Box B05"_s, AccessorySize::M}},
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Armours
|
||||||
|
{1001, {"Short Layer 01"_s, AccessorySize::M}},
|
||||||
|
{1002, {"Short Layer 02"_s, AccessorySize::M}},
|
||||||
|
{1003, {"Short Layer 03"_s, AccessorySize::M}},
|
||||||
|
{1004, {"Short Layer 04"_s, AccessorySize::M}},
|
||||||
|
{1005, {"Short Layer 05"_s, AccessorySize::M}},
|
||||||
|
{1006, {"Long Layer 01"_s, AccessorySize::M}},
|
||||||
|
{1007, {"Long Layer 02"_s, AccessorySize::M}},
|
||||||
|
{1008, {"Long Layer 03"_s, AccessorySize::M}},
|
||||||
|
{1009, {"Long Layer 04"_s, AccessorySize::M}},
|
||||||
|
{1010, {"Long Layer 05"_s, AccessorySize::M}},
|
||||||
|
{1011, {"Diagonal Long Layer 01"_s, AccessorySize::M}},
|
||||||
|
{1012, {"Diagonal Long Layer 02"_s, AccessorySize::M}},
|
||||||
|
{1013, {"Diagonal Long Layer 03"_s, AccessorySize::M}},
|
||||||
|
{1014, {"Diagonal Long Layer 04"_s, AccessorySize::M}},
|
||||||
|
{1015, {"Diagonal Long Layer 05"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{1051, {"Sloped Layer 01"_s, AccessorySize::M}},
|
||||||
|
{1052, {"Sloped Layer 02"_s, AccessorySize::M}},
|
||||||
|
{1053, {"Sloped Layer 03"_s, AccessorySize::M}},
|
||||||
|
{1054, {"Sloped Layer 04"_s, AccessorySize::M}},
|
||||||
|
{1055, {"Sloped Layer 05"_s, AccessorySize::M}},
|
||||||
|
{1056, {"Sloped Layer 06"_s, AccessorySize::M}},
|
||||||
|
{1057, {"Sloped Layer 07"_s, AccessorySize::M}},
|
||||||
|
{1058, {"Sloped Layer 08"_s, AccessorySize::M}},
|
||||||
|
{1059, {"Sloped Layer 09"_s, AccessorySize::M}},
|
||||||
|
{1060, {"Sloped Layer 10"_s, AccessorySize::M}},
|
||||||
|
{1061, {"Sloped Layer 11"_s, AccessorySize::M}},
|
||||||
|
{1062, {"Sloped Layer 12"_s, AccessorySize::M}},
|
||||||
|
{1063, {"Sloped Layer 13"_s, AccessorySize::M}},
|
||||||
|
{1064, {"Sloped Layer 14"_s, AccessorySize::M}},
|
||||||
|
{1065, {"Sloped Layer 15"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{1101, {"Raised Center 01"_s, AccessorySize::M}},
|
||||||
|
{1102, {"Raised Center 02"_s, AccessorySize::M}},
|
||||||
|
{1103, {"Raised Center 03"_s, AccessorySize::M}},
|
||||||
|
{1104, {"Raised Center 04"_s, AccessorySize::M}},
|
||||||
|
{1105, {"Raised Center 05"_s, AccessorySize::M}},
|
||||||
|
{1106, {"Raised Block 01"_s, AccessorySize::M}},
|
||||||
|
{1107, {"Raised Block 02"_s, AccessorySize::M}},
|
||||||
|
{1108, {"Raised Block 03"_s, AccessorySize::M}},
|
||||||
|
{1109, {"Raised Pointed"_s, AccessorySize::M}},
|
||||||
|
{1110, {"Raised Cover"_s, AccessorySize::M}},
|
||||||
|
{1111, {"Raised Slant 01"_s, AccessorySize::M}},
|
||||||
|
{1112, {"Raised Slant 02"_s, AccessorySize::M}},
|
||||||
|
{1113, {"Raised Slant 03"_s, AccessorySize::M}},
|
||||||
|
{1114, {"Raised Slant 04"_s, AccessorySize::M}},
|
||||||
|
{1115, {"Raised Slant 05"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{1151, {"Wide Patch 01"_s, AccessorySize::L}},
|
||||||
|
{1152, {"Wide Patch 02"_s, AccessorySize::L}},
|
||||||
|
{1153, {"Wide Patch 03"_s, AccessorySize::L}},
|
||||||
|
{1154, {"Wide Patch 04"_s, AccessorySize::L}},
|
||||||
|
{1155, {"Wide Patch 05"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{1201, {"Pointed Armour 01"_s, AccessorySize::L}},
|
||||||
|
{1202, {"Pointed Armour 02"_s, AccessorySize::L}},
|
||||||
|
{1203, {"Pointed Armour 03"_s, AccessorySize::L}},
|
||||||
|
{1204, {"Pointed Armour 04"_s, AccessorySize::L}},
|
||||||
|
{1205, {"Pointed Armour 05"_s, AccessorySize::L}},
|
||||||
|
{1206, {"Pointed Armour 06"_s, AccessorySize::L}},
|
||||||
|
{1207, {"Pointed Armour 07"_s, AccessorySize::L}},
|
||||||
|
{1208, {"Pointed Armour 08"_s, AccessorySize::L}},
|
||||||
|
{1209, {"Pointed Armour 09"_s, AccessorySize::L}},
|
||||||
|
{1210, {"Pointed Armour 10"_s, AccessorySize::L}},
|
||||||
|
{1211, {"Pointed Armour 11"_s, AccessorySize::L}},
|
||||||
|
{1212, {"Pointed Armour 12"_s, AccessorySize::L}},
|
||||||
|
{1213, {"Pointed Armour 13"_s, AccessorySize::L}},
|
||||||
|
{1214, {"Pointed Armour 14"_s, AccessorySize::L}},
|
||||||
|
{1215, {"Pointed Armour 15"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{1251, {"E Limb Cover 01"_s, AccessorySize::L}},
|
||||||
|
{1252, {"E Limb Cover 02"_s, AccessorySize::L}},
|
||||||
|
{1253, {"E Limb Cover 03"_s, AccessorySize::L}},
|
||||||
|
{1254, {"E Limb Cover 04"_s, AccessorySize::L}},
|
||||||
|
{1255, {"E Limb Cover 05"_s, AccessorySize::L}},
|
||||||
|
{1256, {"E Limb Cover 06"_s, AccessorySize::L}},
|
||||||
|
{1257, {"E Limb Cover 07"_s, AccessorySize::L}},
|
||||||
|
{1258, {"E Limb Cover 08"_s, AccessorySize::L}},
|
||||||
|
{1259, {"E Limb Cover 09"_s, AccessorySize::L}},
|
||||||
|
{1260, {"E Limb Cover 10"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{1301, {"C Limb Cover 01"_s, AccessorySize::L}},
|
||||||
|
{1302, {"C Limb Cover 02"_s, AccessorySize::L}},
|
||||||
|
{1303, {"C Limb Cover 03"_s, AccessorySize::L}},
|
||||||
|
{1304, {"C Limb Cover 04"_s, AccessorySize::L}},
|
||||||
|
{1305, {"C Limb Cover 05"_s, AccessorySize::L}},
|
||||||
|
{1306, {"C Limb Cover 06"_s, AccessorySize::L}},
|
||||||
|
{1307, {"C Limb Cover 07"_s, AccessorySize::L}},
|
||||||
|
{1308, {"C Limb Cover 08"_s, AccessorySize::L}},
|
||||||
|
{1309, {"C Limb Cover 09"_s, AccessorySize::L}},
|
||||||
|
{1310, {"C Limb Cover 10"_s, AccessorySize::L}},
|
||||||
|
{1311, {"C Limb Cover 11"_s, AccessorySize::L}},
|
||||||
|
{1312, {"C Limb Cover 12"_s, AccessorySize::L}},
|
||||||
|
{1313, {"C Limb Cover 13"_s, AccessorySize::L}},
|
||||||
|
{1314, {"C Limb Cover 14"_s, AccessorySize::L}},
|
||||||
|
{1315, {"C Limb Cover 15"_s, AccessorySize::L}},
|
||||||
|
{1316, {"C Limb Cover 16"_s, AccessorySize::L}},
|
||||||
|
{1317, {"C Limb Cover 17"_s, AccessorySize::L}},
|
||||||
|
{1318, {"C Limb Cover 18"_s, AccessorySize::L}},
|
||||||
|
{1319, {"C Limb Cover 19"_s, AccessorySize::L}},
|
||||||
|
{1320, {"C Limb Cover 20"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{1351, {"P Limb Cover 01"_s, AccessorySize::XL}},
|
||||||
|
{1352, {"P Limb Cover 02"_s, AccessorySize::XL}},
|
||||||
|
{1353, {"P Limb Cover 03"_s, AccessorySize::XL}},
|
||||||
|
{1354, {"P Limb Cover 04"_s, AccessorySize::XL}},
|
||||||
|
{1355, {"P Limb Cover 05"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{1401, {"Flat Cover 01"_s, AccessorySize::XL}},
|
||||||
|
{1402, {"Flat Cover 02"_s, AccessorySize::XL}},
|
||||||
|
{1403, {"Flat Cover 03"_s, AccessorySize::XL}},
|
||||||
|
{1404, {"Flat Cover 04"_s, AccessorySize::XL}},
|
||||||
|
{1405, {"Flat Cover 05"_s, AccessorySize::XL}},
|
||||||
|
{1406, {"Flat Cover 06"_s, AccessorySize::XL}},
|
||||||
|
{1407, {"Flat Cover 07"_s, AccessorySize::XL}},
|
||||||
|
{1408, {"Flat Cover 08"_s, AccessorySize::XL}},
|
||||||
|
{1409, {"Flat Cover 09"_s, AccessorySize::XL}},
|
||||||
|
{1410, {"Flat Cover 10"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{1451, {"L Side Opening 01"_s, AccessorySize::XL}},
|
||||||
|
{1452, {"L Side Opening 02"_s, AccessorySize::XL}},
|
||||||
|
{1453, {"L Side Opening 03"_s, AccessorySize::XL}},
|
||||||
|
{1454, {"L Side Opening 04"_s, AccessorySize::XL}},
|
||||||
|
{1455, {"L Side Opening 05"_s, AccessorySize::XL}},
|
||||||
|
{1456, {"L Side Opening 06"_s, AccessorySize::XL}},
|
||||||
|
{1457, {"L Side Opening 07"_s, AccessorySize::XL}},
|
||||||
|
{1458, {"L Side Opening 08"_s, AccessorySize::XL}},
|
||||||
|
{1459, {"L Side Opening 09"_s, AccessorySize::XL}},
|
||||||
|
{1460, {"L Side Opening 10"_s, AccessorySize::XL}},
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Components
|
||||||
|
{2001, {"Disc Padding 01"_s, AccessorySize::M}},
|
||||||
|
{2002, {"Disc Padding 02"_s, AccessorySize::M}},
|
||||||
|
{2003, {"Disc Padding 03"_s, AccessorySize::M}},
|
||||||
|
{2004, {"Disc Padding 04"_s, AccessorySize::M}},
|
||||||
|
{2005, {"Disc Padding 05"_s, AccessorySize::M}},
|
||||||
|
{2006, {"Thin Padding 01"_s, AccessorySize::M}},
|
||||||
|
{2007, {"Thin Padding 02"_s, AccessorySize::M}},
|
||||||
|
{2008, {"Thin Padding 03"_s, AccessorySize::M}},
|
||||||
|
{2009, {"Thin Padding 04"_s, AccessorySize::M}},
|
||||||
|
{2010, {"Thin Padding 05"_s, AccessorySize::M}},
|
||||||
|
{2011, {"Thick Padding 01"_s, AccessorySize::M}},
|
||||||
|
{2012, {"Thick Padding 02"_s, AccessorySize::M}},
|
||||||
|
{2013, {"Thick Padding 03"_s, AccessorySize::M}},
|
||||||
|
{2014, {"Thick Padding 04"_s, AccessorySize::M}},
|
||||||
|
{2015, {"Thick Padding 05"_s, AccessorySize::M}},
|
||||||
|
{2016, {"Thick Padding 06"_s, AccessorySize::M}},
|
||||||
|
{2017, {"Thick Padding 07"_s, AccessorySize::M}},
|
||||||
|
{2018, {"Thick Padding 08"_s, AccessorySize::M}},
|
||||||
|
{2019, {"Thick Padding 09"_s, AccessorySize::M}},
|
||||||
|
{2020, {"Thick Padding 10"_s, AccessorySize::M}},
|
||||||
|
{2021, {"CSide Padding 01"_s, AccessorySize::M}},
|
||||||
|
{2022, {"CSide Padding 02"_s, AccessorySize::M}},
|
||||||
|
{2023, {"CSide Padding 03"_s, AccessorySize::M}},
|
||||||
|
{2024, {"CSide Padding 04"_s, AccessorySize::M}},
|
||||||
|
{2025, {"CSide Padding 05"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{2051, {"Container 01"_s, AccessorySize::L}},
|
||||||
|
{2052, {"Container 02"_s, AccessorySize::L}},
|
||||||
|
{2053, {"Container 03"_s, AccessorySize::L}},
|
||||||
|
{2054, {"Container 04"_s, AccessorySize::L}},
|
||||||
|
{2055, {"Container 05"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{2101, {"Plating 01"_s, AccessorySize::L}},
|
||||||
|
{2102, {"Plating 02"_s, AccessorySize::L}},
|
||||||
|
{2103, {"Plating 03"_s, AccessorySize::L}},
|
||||||
|
{2104, {"Plating 04"_s, AccessorySize::L}},
|
||||||
|
{2105, {"Plating 05"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{2151, {"Complex Base 01"_s, AccessorySize::L}},
|
||||||
|
{2152, {"Complex Base 02"_s, AccessorySize::L}},
|
||||||
|
{2153, {"Complex Base 03"_s, AccessorySize::L}},
|
||||||
|
{2154, {"Complex Base 04"_s, AccessorySize::L}},
|
||||||
|
{2155, {"Complex Base 05"_s, AccessorySize::L}},
|
||||||
|
{2156, {"Complex Base 06"_s, AccessorySize::L}},
|
||||||
|
{2157, {"Complex Base 07"_s, AccessorySize::L}},
|
||||||
|
{2158, {"Complex Base 08"_s, AccessorySize::L}},
|
||||||
|
{2159, {"Complex Base 09"_s, AccessorySize::L}},
|
||||||
|
{2160, {"Complex Base 10"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{2201, {"Long Base 01"_s, AccessorySize::XL}},
|
||||||
|
{2202, {"Long Base 02"_s, AccessorySize::XL}},
|
||||||
|
{2203, {"Long Base 03"_s, AccessorySize::XL}},
|
||||||
|
{2204, {"Long Base 04"_s, AccessorySize::XL}},
|
||||||
|
{2205, {"Long Base 05"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{2251, {"Straight Wing 01"_s, AccessorySize::XL}},
|
||||||
|
{2252, {"Straight Wing 02"_s, AccessorySize::XL}},
|
||||||
|
{2253, {"Straight Wing 03"_s, AccessorySize::XL}},
|
||||||
|
{2254, {"Straight Wing 04"_s, AccessorySize::XL}},
|
||||||
|
{2255, {"Straight Wing 05"_s, AccessorySize::XL}},
|
||||||
|
{2256, {"Straight Wing 06"_s, AccessorySize::XL}},
|
||||||
|
{2257, {"Straight Wing 07"_s, AccessorySize::XL}},
|
||||||
|
{2258, {"Straight Wing 08"_s, AccessorySize::XL}},
|
||||||
|
{2259, {"Straight Wing 09"_s, AccessorySize::XL}},
|
||||||
|
{2260, {"Straight Wing 10"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{2301, {"Triangular Wing 01"_s, AccessorySize::XL}},
|
||||||
|
{2302, {"Triangular Wing 02"_s, AccessorySize::XL}},
|
||||||
|
{2303, {"Triangular Wing 03"_s, AccessorySize::XL}},
|
||||||
|
{2304, {"Triangular Wing 04"_s, AccessorySize::XL}},
|
||||||
|
{2305, {"Triangular Wing 05"_s, AccessorySize::XL}},
|
||||||
|
{2306, {"Triangular Wing 06"_s, AccessorySize::XL}},
|
||||||
|
{2307, {"Triangular Wing 07"_s, AccessorySize::XL}},
|
||||||
|
{2308, {"Triangular Wing 08"_s, AccessorySize::XL}},
|
||||||
|
{2309, {"Triangular Wing 09"_s, AccessorySize::XL}},
|
||||||
|
{2310, {"Triangular Wing 10"_s, AccessorySize::XL}},
|
||||||
|
{2311, {"Triangular Wing 11"_s, AccessorySize::L}},
|
||||||
|
{2312, {"Triangular Wing 12"_s, AccessorySize::L}},
|
||||||
|
{2313, {"Triangular Wing 13"_s, AccessorySize::L}},
|
||||||
|
{2314, {"Triangular Wing 14"_s, AccessorySize::L}},
|
||||||
|
{2315, {"Triangular Wing 15"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{2351, {"Complex Wing 01"_s, AccessorySize::XL}},
|
||||||
|
{2352, {"Complex Wing 02"_s, AccessorySize::XL}},
|
||||||
|
{2353, {"Complex Wing 03"_s, AccessorySize::XL}},
|
||||||
|
{2354, {"Complex Wing 04"_s, AccessorySize::XL}},
|
||||||
|
{2355, {"Complex Wing 05"_s, AccessorySize::XL}},
|
||||||
|
{2356, {"Complex Wing 06"_s, AccessorySize::L}},
|
||||||
|
{2357, {"Complex Wing 07"_s, AccessorySize::L}},
|
||||||
|
{2358, {"Complex Wing 08"_s, AccessorySize::L}},
|
||||||
|
{2359, {"Complex Wing 09"_s, AccessorySize::L}},
|
||||||
|
{2360, {"Complex Wing 10"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{2401, {"Blade 01"_s, AccessorySize::XL}},
|
||||||
|
{2402, {"Blade 02"_s, AccessorySize::XL}},
|
||||||
|
{2403, {"Blade 03"_s, AccessorySize::XL}},
|
||||||
|
{2404, {"Blade 04"_s, AccessorySize::XL}},
|
||||||
|
{2405, {"Blade 05"_s, AccessorySize::XL}},
|
||||||
|
{2406, {"Blade 06"_s, AccessorySize::XL}},
|
||||||
|
{2407, {"Blade 07"_s, AccessorySize::XL}},
|
||||||
|
{2408, {"Blade 08"_s, AccessorySize::XL}},
|
||||||
|
{2409, {"Blade 09"_s, AccessorySize::XL}},
|
||||||
|
{2410, {"Blade 10"_s, AccessorySize::XL}},
|
||||||
|
{2411, {"Blade 11"_s, AccessorySize::XL}},
|
||||||
|
{2412, {"Blade 12"_s, AccessorySize::XL}},
|
||||||
|
{2413, {"Blade 13"_s, AccessorySize::XL}},
|
||||||
|
{2414, {"Blade 14"_s, AccessorySize::XL}},
|
||||||
|
{2415, {"Blade 15"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{2426, {"Curved Blade 01"_s, AccessorySize::XL}},
|
||||||
|
{2427, {"Curved Blade 02"_s, AccessorySize::XL}},
|
||||||
|
{2428, {"Curved Blade 03"_s, AccessorySize::XL}},
|
||||||
|
{2429, {"Curved Blade 04"_s, AccessorySize::XL}},
|
||||||
|
{2430, {"Curved Blade 05"_s, AccessorySize::XL}},
|
||||||
|
{2431, {"Axe Head 01"_s, AccessorySize::XL}},
|
||||||
|
{2432, {"Axe Head 02"_s, AccessorySize::XL}},
|
||||||
|
{2433, {"Axe Head 03"_s, AccessorySize::XL}},
|
||||||
|
{2434, {"Axe Head 04"_s, AccessorySize::XL}},
|
||||||
|
{2435, {"Axe Head 05"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{2451, {"Horn 01"_s, AccessorySize::M}},
|
||||||
|
{2452, {"Horn 02"_s, AccessorySize::M}},
|
||||||
|
{2453, {"Horn 03"_s, AccessorySize::M}},
|
||||||
|
{2454, {"Horn 04"_s, AccessorySize::M}},
|
||||||
|
{2455, {"Horn 05"_s, AccessorySize::M}},
|
||||||
|
{2456, {"Horn 06"_s, AccessorySize::M}},
|
||||||
|
{2457, {"Horn 07"_s, AccessorySize::M}},
|
||||||
|
{2458, {"Horn 08"_s, AccessorySize::M}},
|
||||||
|
{2459, {"Horn 09"_s, AccessorySize::M}},
|
||||||
|
{2460, {"Horn 10"_s, AccessorySize::M}},
|
||||||
|
{2461, {"Horn 11"_s, AccessorySize::M}},
|
||||||
|
{2462, {"Horn 12"_s, AccessorySize::M}},
|
||||||
|
{2463, {"Horn 13"_s, AccessorySize::M}},
|
||||||
|
{2464, {"Horn 14"_s, AccessorySize::M}},
|
||||||
|
{2465, {"Horn 15"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{2471, {"Mask"_s, AccessorySize::M}},
|
||||||
|
{2472, {"Droplet"_s, AccessorySize::M}},
|
||||||
|
{2473, {"Thigh"_s, AccessorySize::M}},
|
||||||
|
{2474, {"LegS"_s, AccessorySize::M}},
|
||||||
|
{2475, {"LegTH"_s, AccessorySize::M}},
|
||||||
|
{2476, {"Plume 01"_s, AccessorySize::M}},
|
||||||
|
{2477, {"Plume 02"_s, AccessorySize::M}},
|
||||||
|
{2478, {"Plume 03"_s, AccessorySize::M}},
|
||||||
|
{2479, {"Plume 04"_s, AccessorySize::M}},
|
||||||
|
{2480, {"Plume 05"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{2491, {"Tail 01"_s, AccessorySize::XL}},
|
||||||
|
{2492, {"Tail 02"_s, AccessorySize::XL}},
|
||||||
|
{2493, {"Tail 03"_s, AccessorySize::XL}},
|
||||||
|
{2494, {"Tail 04"_s, AccessorySize::XL}},
|
||||||
|
{2495, {"Tail 05"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{2501, {"Finger 01"_s, AccessorySize::M}},
|
||||||
|
{2502, {"Finger 02"_s, AccessorySize::M}},
|
||||||
|
{2503, {"Finger 03"_s, AccessorySize::M}},
|
||||||
|
{2504, {"Finger 04"_s, AccessorySize::M}},
|
||||||
|
{2505, {"Finger 05"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{2510, {"Clamp 01"_s, AccessorySize::M}},
|
||||||
|
{2511, {"Clamp 02"_s, AccessorySize::M}},
|
||||||
|
{2512, {"Clamp 03"_s, AccessorySize::M}},
|
||||||
|
{2513, {"Clamp 04"_s, AccessorySize::M}},
|
||||||
|
{2514, {"Clamp 05"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{2521, {"Fabric 01"_s, AccessorySize::XL}},
|
||||||
|
{2522, {"Fabric 02"_s, AccessorySize::XL}},
|
||||||
|
{2523, {"Fabric 03"_s, AccessorySize::XL}},
|
||||||
|
{2524, {"Fabric 04"_s, AccessorySize::XL}},
|
||||||
|
{2525, {"Fabric 05"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{2551, {"Energy Barrel 01"_s, AccessorySize::XL}},
|
||||||
|
{2552, {"Energy Barrel 02"_s, AccessorySize::XL}},
|
||||||
|
{2553, {"Energy Barrel 03"_s, AccessorySize::XL}},
|
||||||
|
{2554, {"Energy Barrel 04"_s, AccessorySize::XL}},
|
||||||
|
{2555, {"Energy Barrel 05"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{2601, {"L Bullet Barrel 01"_s, AccessorySize::XL}},
|
||||||
|
{2602, {"L Bullet Barrel 02"_s, AccessorySize::XL}},
|
||||||
|
{2603, {"L Bullet Barrel 03"_s, AccessorySize::XL}},
|
||||||
|
{2604, {"L Bullet Barrel 04"_s, AccessorySize::XL}},
|
||||||
|
{2605, {"L Bullet Barrel 05"_s, AccessorySize::XL}},
|
||||||
|
{2606, {"S Bullet Barrel 01"_s, AccessorySize::XL}},
|
||||||
|
{2607, {"S Bullet Barrel 02"_s, AccessorySize::XL}},
|
||||||
|
{2608, {"S Bullet Barrel 03"_s, AccessorySize::XL}},
|
||||||
|
{2609, {"S Bullet Barrel 04"_s, AccessorySize::XL}},
|
||||||
|
{2610, {"S Bullet Barrel 05"_s, AccessorySize::XL}},
|
||||||
|
{2611, {"B Bullet Barrel 01"_s, AccessorySize::XL}},
|
||||||
|
{2612, {"B Bullet Barrel 02"_s, AccessorySize::XL}},
|
||||||
|
{2613, {"B Bullet Barrel 03"_s, AccessorySize::XL}},
|
||||||
|
{2614, {"B Bullet Barrel 04"_s, AccessorySize::XL}},
|
||||||
|
{2615, {"B Bullet Barrel 05"_s, AccessorySize::XL}},
|
||||||
|
{2616, {"B Bullet Barrel 06"_s, AccessorySize::XL}},
|
||||||
|
{2617, {"B Bullet Barrel 07"_s, AccessorySize::XL}},
|
||||||
|
{2618, {"B Bullet Barrel 08"_s, AccessorySize::XL}},
|
||||||
|
{2619, {"B Bullet Barrel 09"_s, AccessorySize::XL}},
|
||||||
|
{2620, {"B Bullet Barrel 10"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{2651, {"Cylinder Scope 01"_s, AccessorySize::M}},
|
||||||
|
{2652, {"Cylinder Scope 02"_s, AccessorySize::M}},
|
||||||
|
{2653, {"Cylinder Scope 03"_s, AccessorySize::M}},
|
||||||
|
{2654, {"Cylinder Scope 04"_s, AccessorySize::M}},
|
||||||
|
{2655, {"Cylinder Scope 05"_s, AccessorySize::M}},
|
||||||
|
{2656, {"Elec Scope 01"_s, AccessorySize::M}},
|
||||||
|
{2657, {"Elec Scope 02"_s, AccessorySize::M}},
|
||||||
|
{2658, {"Elec Scope 03"_s, AccessorySize::M}},
|
||||||
|
{2659, {"Elec Scope 04"_s, AccessorySize::M}},
|
||||||
|
{2660, {"Elec Scope 05"_s, AccessorySize::M}},
|
||||||
|
{2661, {"Mark Scope 01"_s, AccessorySize::S}},
|
||||||
|
{2662, {"Mark Scope 02"_s, AccessorySize::S}},
|
||||||
|
{2663, {"Mark Scope 03"_s, AccessorySize::S}},
|
||||||
|
{2664, {"Mark Scope 04"_s, AccessorySize::S}},
|
||||||
|
{2665, {"Mark Scope 05"_s, AccessorySize::S}},
|
||||||
|
|
||||||
|
{2701, {"S Single Weaponry"_s, AccessorySize::M}},
|
||||||
|
{2702, {"S Packed Weaponry 01"_s, AccessorySize::M}},
|
||||||
|
{2703, {"S Packed Weaponry 02"_s, AccessorySize::M}},
|
||||||
|
{2704, {"S Packed Weaponry 03"_s, AccessorySize::M}},
|
||||||
|
{2705, {"S Packed Weaponry 04"_s, AccessorySize::M}},
|
||||||
|
{2706, {"L Single Weaponry"_s, AccessorySize::XL}},
|
||||||
|
{2707, {"L Packed Weaponry 01"_s, AccessorySize::XL}},
|
||||||
|
{2708, {"L Packed Weaponry 02"_s, AccessorySize::XL}},
|
||||||
|
{2709, {"L Packed Weaponry 03"_s, AccessorySize::XL}},
|
||||||
|
{2710, {"L Packed Weaponry 04"_s, AccessorySize::XL}},
|
||||||
|
{2711, {"Atk Single Weaponry"_s, AccessorySize::XL}},
|
||||||
|
{2712, {"Atk Packed Weaponry 01"_s, AccessorySize::XL}},
|
||||||
|
{2713, {"Atk Packed Weaponry 02"_s, AccessorySize::XL}},
|
||||||
|
{2714, {"Atk Packed Weaponry 03"_s, AccessorySize::XL}},
|
||||||
|
{2715, {"Atk Packed Weaponry 04"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{2751, {"Vent 01"_s, AccessorySize::M}},
|
||||||
|
{2752, {"Vent 02"_s, AccessorySize::M}},
|
||||||
|
{2753, {"Vent 03"_s, AccessorySize::M}},
|
||||||
|
{2754, {"Vent 04"_s, AccessorySize::M}},
|
||||||
|
{2755, {"Vent 05"_s, AccessorySize::M}},
|
||||||
|
{2756, {"Vent 06"_s, AccessorySize::M}},
|
||||||
|
{2757, {"Vent 07"_s, AccessorySize::M}},
|
||||||
|
{2758, {"Vent 08"_s, AccessorySize::M}},
|
||||||
|
{2759, {"Vent 09"_s, AccessorySize::M}},
|
||||||
|
{2760, {"Vent 10"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{2901, {"Complex Construct 01"_s, AccessorySize::L}},
|
||||||
|
{2902, {"Complex Construct 02"_s, AccessorySize::L}},
|
||||||
|
{2903, {"Complex Construct 03"_s, AccessorySize::L}},
|
||||||
|
{2904, {"Complex Construct 04"_s, AccessorySize::L}},
|
||||||
|
{2905, {"Complex Construct 05"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{2950, {"Q Mask 01"_s, AccessorySize::M}},
|
||||||
|
{2951, {"Q Mask 02"_s, AccessorySize::M}},
|
||||||
|
{2952, {"Q Mask 03"_s, AccessorySize::M}},
|
||||||
|
{2953, {"Q Mask 04"_s, AccessorySize::M}},
|
||||||
|
{2954, {"Q Mask 05"_s, AccessorySize::M}},
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Connectors
|
||||||
|
{3001, {"Circular Vent 01"_s, AccessorySize::M}},
|
||||||
|
{3002, {"Circular Vent 02"_s, AccessorySize::M}},
|
||||||
|
{3003, {"Circular Vent 03"_s, AccessorySize::M}},
|
||||||
|
{3004, {"Circular Vent 04"_s, AccessorySize::M}},
|
||||||
|
{3005, {"Circular Vent 05"_s, AccessorySize::M}},
|
||||||
|
{3006, {"Circular Vent 06"_s, AccessorySize::M}},
|
||||||
|
{3007, {"Circular Vent 07"_s, AccessorySize::M}},
|
||||||
|
{3008, {"Circular Vent 08"_s, AccessorySize::M}},
|
||||||
|
{3009, {"Circular Vent 09"_s, AccessorySize::M}},
|
||||||
|
{3010, {"Circular Vent 10"_s, AccessorySize::M}},
|
||||||
|
{3011, {"Circular Vent 11"_s, AccessorySize::M}},
|
||||||
|
{3012, {"Circular Vent 12"_s, AccessorySize::M}},
|
||||||
|
{3013, {"Circular Vent 13"_s, AccessorySize::M}},
|
||||||
|
{3014, {"Circular Vent 14"_s, AccessorySize::M}},
|
||||||
|
{3015, {"Circular Vent 15"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{3051, {"Reactor 01"_s, AccessorySize::L}},
|
||||||
|
{3052, {"Reactor 02"_s, AccessorySize::L}},
|
||||||
|
{3053, {"Reactor 03"_s, AccessorySize::L}},
|
||||||
|
{3054, {"Reactor 04"_s, AccessorySize::L}},
|
||||||
|
{3055, {"Reactor 05"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{3101, {"Connecting Tube 01"_s, AccessorySize::XL}},
|
||||||
|
{3102, {"Connecting Tube 02"_s, AccessorySize::XL}},
|
||||||
|
{3103, {"Connecting Tube 03"_s, AccessorySize::XL}},
|
||||||
|
{3104, {"Connecting Tube 04"_s, AccessorySize::XL}},
|
||||||
|
{3105, {"Connecting Tube 05"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{3151, {"Latch 01"_s, AccessorySize::M}},
|
||||||
|
{3152, {"Latch 02"_s, AccessorySize::M}},
|
||||||
|
{3153, {"Latch 03"_s, AccessorySize::M}},
|
||||||
|
{3154, {"Latch 04"_s, AccessorySize::M}},
|
||||||
|
{3155, {"Latch 05"_s, AccessorySize::M}},
|
||||||
|
{3156, {"Latch 06"_s, AccessorySize::M}},
|
||||||
|
{3157, {"Latch 07"_s, AccessorySize::M}},
|
||||||
|
{3158, {"Latch 08"_s, AccessorySize::M}},
|
||||||
|
{3159, {"Latch 09"_s, AccessorySize::M}},
|
||||||
|
{3160, {"Latch 10"_s, AccessorySize::M}},
|
||||||
|
{3161, {"Latch 11"_s, AccessorySize::M}},
|
||||||
|
{3162, {"Latch 12"_s, AccessorySize::M}},
|
||||||
|
{3163, {"Latch 13"_s, AccessorySize::M}},
|
||||||
|
{3164, {"Latch 14"_s, AccessorySize::M}},
|
||||||
|
{3165, {"Latch 15"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{3201, {"Short Connector 01"_s, AccessorySize::M}},
|
||||||
|
{3202, {"Short Connector 02"_s, AccessorySize::M}},
|
||||||
|
{3203, {"Short Connector 03"_s, AccessorySize::M}},
|
||||||
|
{3204, {"Short Connector 04"_s, AccessorySize::M}},
|
||||||
|
{3205, {"Short Connector 05"_s, AccessorySize::M}},
|
||||||
|
{3206, {"Antenna 01"_s, AccessorySize::S}},
|
||||||
|
{3207, {"Antenna 02"_s, AccessorySize::S}},
|
||||||
|
{3208, {"Antenna 03"_s, AccessorySize::S}},
|
||||||
|
{3209, {"Antenna 04"_s, AccessorySize::S}},
|
||||||
|
{3210, {"Antenna 05"_s, AccessorySize::S}},
|
||||||
|
|
||||||
|
{3226, {"Long Connector 01"_s, AccessorySize::XL}},
|
||||||
|
{3227, {"Long Connector 02"_s, AccessorySize::XL}},
|
||||||
|
{3228, {"Long Connector 03"_s, AccessorySize::XL}},
|
||||||
|
{3229, {"Long Connector 04"_s, AccessorySize::XL}},
|
||||||
|
{3230, {"Long Connector 05"_s, AccessorySize::XL}},
|
||||||
|
{3231, {"Long Connector 06"_s, AccessorySize::XL}},
|
||||||
|
{3232, {"Long Connector 07"_s, AccessorySize::XL}},
|
||||||
|
{3233, {"Long Connector 08"_s, AccessorySize::XL}},
|
||||||
|
{3234, {"Long Connector 09"_s, AccessorySize::XL}},
|
||||||
|
{3235, {"Long Connector 10"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{3251, {"Complex Connector 01"_s, AccessorySize::XL}},
|
||||||
|
{3252, {"Complex Connector 02"_s, AccessorySize::XL}},
|
||||||
|
{3253, {"Complex Connector 03"_s, AccessorySize::XL}},
|
||||||
|
{3254, {"Complex Connector 04"_s, AccessorySize::XL}},
|
||||||
|
{3255, {"Complex Connector 05"_s, AccessorySize::XL}},
|
||||||
|
|
||||||
|
{3301, {"Tube Line 01"_s, AccessorySize::L}},
|
||||||
|
{3302, {"Tube Line 02"_s, AccessorySize::L}},
|
||||||
|
{3303, {"Tube Line 03"_s, AccessorySize::L}},
|
||||||
|
{3304, {"Tube Line 04"_s, AccessorySize::XL}},
|
||||||
|
{3305, {"Tube Line 05"_s, AccessorySize::XL}},
|
||||||
|
{3306, {"Tube Line 06"_s, AccessorySize::M}},
|
||||||
|
{3307, {"Tube Line 07"_s, AccessorySize::M}},
|
||||||
|
{3308, {"Tube Line 08"_s, AccessorySize::M}},
|
||||||
|
{3309, {"Tube Line 09"_s, AccessorySize::L}},
|
||||||
|
{3310, {"Tube Line 10"_s, AccessorySize::L}},
|
||||||
|
|
||||||
|
{3351, {"Radar Plate 01"_s, AccessorySize::M}},
|
||||||
|
{3352, {"Radar Plate 02"_s, AccessorySize::M}},
|
||||||
|
{3353, {"Radar Plate 03"_s, AccessorySize::M}},
|
||||||
|
{3354, {"Radar Plate 04"_s, AccessorySize::M}},
|
||||||
|
{3355, {"Radar Plate 05"_s, AccessorySize::M}},
|
||||||
|
{3356, {"Radar Pod 01"_s, AccessorySize::M}},
|
||||||
|
{3357, {"Radar Pod 02"_s, AccessorySize::M}},
|
||||||
|
{3358, {"Radar Pod 03"_s, AccessorySize::M}},
|
||||||
|
{3359, {"Radar Pod 04"_s, AccessorySize::M}},
|
||||||
|
{3360, {"Radar Pod 05"_s, AccessorySize::M}},
|
||||||
|
|
||||||
|
{3401, {"Tri Pod 01"_s, AccessorySize::M}},
|
||||||
|
{3402, {"Tri Pod 02"_s, AccessorySize::M}},
|
||||||
|
{3403, {"Tri Pod 03"_s, AccessorySize::M}},
|
||||||
|
{3404, {"Tri Pod 04"_s, AccessorySize::M}},
|
||||||
|
{3405, {"Tri Pod 05"_s, AccessorySize::M}},
|
||||||
|
{3406, {"Signal Pod 01"_s, AccessorySize::M}},
|
||||||
|
{3407, {"Signal Pod 02"_s, AccessorySize::M}},
|
||||||
|
{3408, {"Signal Pod 03"_s, AccessorySize::M}},
|
||||||
|
{3409, {"Signal Pod 04"_s, AccessorySize::M}},
|
||||||
|
{3410, {"Signal Pod 05"_s, AccessorySize::M}},
|
||||||
|
// endregion
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,6 +43,8 @@ static const std::map<Int, Containers::StringView> mission_id_map {{
|
||||||
{0x0070, "Mission 13 - The Sandstorm Glutton"_s},
|
{0x0070, "Mission 13 - The Sandstorm Glutton"_s},
|
||||||
{0x0071, "Mission 14 - An Icy Investigation"_s},
|
{0x0071, "Mission 14 - An Icy Investigation"_s},
|
||||||
{0x0072, "Mission 15 - Outposts Line of Defense"_s},
|
{0x0072, "Mission 15 - Outposts Line of Defense"_s},
|
||||||
|
{0x0073, "Mission 16 - Hidden in the Pass"_s},
|
||||||
|
{0x0074, "Mission 17 - Homebase Security"_s},
|
||||||
|
|
||||||
// Hunting grounds
|
// Hunting grounds
|
||||||
{0x00C8, "Hunt 1 - Desert Pathway Safety"_s},
|
{0x00C8, "Hunt 1 - Desert Pathway Safety"_s},
|
||||||
|
@ -50,6 +52,7 @@ static const std::map<Int, Containers::StringView> mission_id_map {{
|
||||||
{0x00CA, "Hunt 3 - Abandoned Valley Raid"_s},
|
{0x00CA, "Hunt 3 - Abandoned Valley Raid"_s},
|
||||||
{0x00CB, "Hunt 4 - Depths of the Machineries"_s},
|
{0x00CB, "Hunt 4 - Depths of the Machineries"_s},
|
||||||
{0x00CC, "Hunt 5 - Crater Crashers"_s},
|
{0x00CC, "Hunt 5 - Crater Crashers"_s},
|
||||||
|
{0x00CD, "Hunt 6 - Prototype Performance Tests"_s},
|
||||||
|
|
||||||
// Challenges
|
// Challenges
|
||||||
{0x012C, "Challenge 1 - Redline Battlefront"_s},
|
{0x012C, "Challenge 1 - Redline Battlefront"_s},
|
||||||
|
|
|
@ -92,16 +92,23 @@ static const Corrade::Containers::Array<StoryProgressPoint> story_progress
|
||||||
{0x0515, "Chapter 2"_s, "Returned to hangar"_s, "After mission 12"_s},
|
{0x0515, "Chapter 2"_s, "Returned to hangar"_s, "After mission 12"_s},
|
||||||
{0x0516, "Chapter 2"_s, "Got hunt 4 and mission 13 briefing"_s, "After mission 12"_s},
|
{0x0516, "Chapter 2"_s, "Got hunt 4 and mission 13 briefing"_s, "After mission 12"_s},
|
||||||
|
|
||||||
{0x0578, "Chapter 3"_s, "Chapter start, talking with Reina"_s, "After mission 13"_s},
|
{0x0578, "Chapter 3"_s, "Chapter start, talking with Reina"_s, "After mission 13"_s},
|
||||||
{0x0579, "Chapter 3"_s, "Returned to hangar"_s, "After mission 13"_s},
|
{0x0579, "Chapter 3"_s, "Returned to hangar"_s, "After mission 13"_s},
|
||||||
{0x057A, "Chapter 3"_s, "Talked with Reina in development section"_s, "After mission 13"_s},
|
{0x057A, "Chapter 3"_s, "Talked with Reina in development section"_s, "After mission 13"_s},
|
||||||
{0x057B, "Chapter 3"_s, "Got briefing for challenges 1, 2, and 3"_s, "After mission 13"_s},
|
{0x057B, "Chapter 3"_s, "Got briefing for challenges 1, 2, and 3"_s, "After mission 13"_s},
|
||||||
{0x057C, "Chapter 3"_s, "Talked with Reina about device"_s, "After mission 13"_s},
|
{0x057C, "Chapter 3"_s, "Talked with Reina about device"_s, "After mission 13"_s},
|
||||||
{0x057D, "Chapter 3"_s, "Got mission 14 briefing"_s, "After mission 13"_s},
|
{0x057D, "Chapter 3"_s, "Got mission 14 briefing"_s, "After mission 13"_s},
|
||||||
{0x05DC, "Chapter 3"_s, "Talking with Reina and Nier"_s, "After mission 14"_s},
|
{0x05DC, "Chapter 3"_s, "Talking with Reina and Nier"_s, "After mission 14"_s},
|
||||||
{0x05DD, "Chapter 3"_s, "Returned to hangar"_s, "After mission 14"_s},
|
{0x05DD, "Chapter 3"_s, "Returned to hangar"_s, "After mission 14"_s},
|
||||||
{0x05DE, "Chapter 3"_s, "Got briefing for mission 15 and hunt 5"_s, "After mission 14"_s},
|
{0x05DE, "Chapter 3"_s, "Got briefing for mission 15 and hunt 5"_s, "After mission 14"_s},
|
||||||
{0x0640, "Chapter 3"_s, "Talking with Nier and Kazu, and Reina"_s, "After mission 15"_s},
|
{0x0640, "Chapter 3"_s, "Talking with Nier and Kazu, and Reina"_s, "After mission 15"_s},
|
||||||
{0x0641, "Chapter 3"_s, "Returned to hangar"_s, "After mission 15"_s},
|
{0x0641, "Chapter 3"_s, "Returned to hangar"_s, "After mission 15"_s},
|
||||||
|
{0x0642, "Chapter 3"_s, "Talked with Reina and Nier in dev section"_s, "After mission 15"_s},
|
||||||
|
{0x0643, "Chapter 3"_s, "Got briefing for mission 16"_s, "After mission 15"_s},
|
||||||
|
{0x06A4, "Chapter 3"_s, "Talking with Kunai"_s, "After mission 16"_s},
|
||||||
|
{0x06A5, "Chapter 3"_s, "Returned to hangar"_s, "After mission 16"_s},
|
||||||
|
{0x06A6, "Chapter 3"_s, "Got mission 17 briefing"_s, "After mission 16"_s},
|
||||||
|
{0x0708, "Chapter 3"_s, "Debriefing"_s, "After mission 17"_s},
|
||||||
|
{0x070A, "Chapter 3"_s, "Got hunt 6 briefing"_s, "After mission 17"_s},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,433 @@
|
||||||
|
#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 <map>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
|
#include <Magnum/Types.h>
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
using namespace Magnum;
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
// region Melee
|
||||||
|
static const std::map<Int, 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},
|
||||||
|
|
||||||
|
{100, "Combat Side Grip (1H)"_s},
|
||||||
|
{101, "Hollowed Side Grip (1H)"_s},
|
||||||
|
{102, "Pulled Back Side Grip (1H)"_s},
|
||||||
|
{103, "Plated Side Grip (1H)"_s},
|
||||||
|
{104, "Locked Side Grip (1H)"_s},
|
||||||
|
{105, "Longpoint Side Grip (1H)"_s},
|
||||||
|
|
||||||
|
{200, "Combat Dual Grip (1H)"_s},
|
||||||
|
{201, "Hollowed Dual Grip (1H)"_s},
|
||||||
|
{202, "Plated Dual Grip (1H)"_s},
|
||||||
|
|
||||||
|
{400, "Combat Twin Grip (1H)"_s},
|
||||||
|
{401, "Sepal Twin Grip (1H)"_s},
|
||||||
|
{402, "Hollowed Twin Grip (1H)"_s},
|
||||||
|
{403, "Knuckle Guard Twin Grip (1H)"_s},
|
||||||
|
{404, "Arched Twin Grip (1H)"_s},
|
||||||
|
|
||||||
|
{1000, "Combat Knuckle (R/L)"_s},
|
||||||
|
{1001, "Battle Fist (R/L)"_s},
|
||||||
|
{1002, "Guard Knuckle (R/L)"_s},
|
||||||
|
|
||||||
|
{2000, "Combat Polearm (2H)"_s},
|
||||||
|
{2001, "Dual Guard Polearm (2H)"_s},
|
||||||
|
{2002, "Sepal Polearm (2H)"_s},
|
||||||
|
{2003, "Fin Polearm (2H)"_s},
|
||||||
|
{2004, "Arched Polearm (2H)"_s},
|
||||||
|
|
||||||
|
{2100, "Combat Side Polearm (2H)"_s},
|
||||||
|
{2101, "Plated Side Polearm (2H)"_s},
|
||||||
|
{2102, "Locked Side Polearm (2H)"_s},
|
||||||
|
{2103, "Fin Side Polearm (2H)"_s},
|
||||||
|
|
||||||
|
{2200, "Combat Dual Polearm (2H)"_s},
|
||||||
|
|
||||||
|
{2400, "Combat Twin Blade (2H)"_s},
|
||||||
|
{2401, "Guard Twin Blade (2H)"_s},
|
||||||
|
{2402, "Sepal Twin Blade (2H)"_s},
|
||||||
|
{2403, "Fin Twin Blade (2H)"_s},
|
||||||
|
{2404, "Arched Twin Blade (2H)"_s},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<Int, Containers::StringView> melee_assaulters {
|
||||||
|
{0, "Long Metal Blade"_s},
|
||||||
|
{1, "Long Assault Blade"_s},
|
||||||
|
{2, "Long Fin Blade"_s},
|
||||||
|
{3, "Long Double Blades"_s},
|
||||||
|
{4, "Long Straight Blade"_s},
|
||||||
|
{5, "Long Faceted Blade"_s},
|
||||||
|
{6, "Long Interlocked Blade"_s},
|
||||||
|
{7, "Long Frontbreak Blade"_s},
|
||||||
|
{8, "Long Encased Blade"_s},
|
||||||
|
{9, "Long Flat Gouger"_s},
|
||||||
|
{10, "Long Curved Blade"_s},
|
||||||
|
{11, "Long Broad Blade"_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},
|
||||||
|
|
||||||
|
{100, "Short Metal Blade"_s},
|
||||||
|
{101, "Short Assault Blade"_s},
|
||||||
|
{102, "Short Fin Blade"_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},
|
||||||
|
|
||||||
|
{200, "Bracer"_s},
|
||||||
|
{201, "Custom Bracer"_s},
|
||||||
|
|
||||||
|
{210, "Expanded Bracer"_s},
|
||||||
|
{211, "Expanded Custom Bracer"_s},
|
||||||
|
|
||||||
|
{300, "Heavy Smasher"_s},
|
||||||
|
{301, "Heavy Basher"_s},
|
||||||
|
{302, "Heavy Torch Mace"_s},
|
||||||
|
|
||||||
|
{400, "Light Smasher"_s},
|
||||||
|
{401, "Light Basher"_s},
|
||||||
|
{402, "Light Torch 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},
|
||||||
|
|
||||||
|
{500, "Combat Lance"_s},
|
||||||
|
{501, "Gouger Lance"_s},
|
||||||
|
|
||||||
|
{510, "Piercer"_s},
|
||||||
|
|
||||||
|
{600, "Short Combat Lance"_s},
|
||||||
|
|
||||||
|
{605, "Short Combat Drill (Motion)"_s},
|
||||||
|
|
||||||
|
{610, "Short Piercer"_s},
|
||||||
|
|
||||||
|
{700, "Combat Axe"_s},
|
||||||
|
{701, "Custom Combat Axe"_s},
|
||||||
|
{702, "Piercing Axe"_s},
|
||||||
|
{703, "Frontbreak Axe"_s},
|
||||||
|
{704, "Maiming Axe"_s},
|
||||||
|
{705, "Delta Axe"_s},
|
||||||
|
|
||||||
|
{800, "Combat Scythe"_s},
|
||||||
|
{801, "Reaper Blade"_s},
|
||||||
|
{802, "Clawtooth Scythe"_s},
|
||||||
|
{803, "Wingpoint Scythe"_s},
|
||||||
|
{804, "Snakebone 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},
|
||||||
|
};
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Shields
|
||||||
|
static const std::map<Int, 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},
|
||||||
|
|
||||||
|
{100, "Buckler Handle"_s},
|
||||||
|
{101, "Star Handle"_s},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<Int, 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},
|
||||||
|
|
||||||
|
{100, "V-Cross Shell"_s},
|
||||||
|
};
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Bullet Shooters
|
||||||
|
static const std::map<Int, Containers::StringView> bshooter_triggers {
|
||||||
|
{0, "BL-Combat Trigger (1H)"_s},
|
||||||
|
{1, "Light Machine Trigger (1H)"_s},
|
||||||
|
{2, "Tactical Trigger (1H)"_s},
|
||||||
|
{3, "Compact Trigger (1H)"_s},
|
||||||
|
{4, "Longhold Trigger (1H)"_s},
|
||||||
|
{5, "Downhold Trigger (1H)"_s},
|
||||||
|
{6, "Cellblock Trigger (1H)"_s},
|
||||||
|
{99, "Base Trigger (1H)"_s},
|
||||||
|
|
||||||
|
{100, "BL-Machine Trigger (2H)"_s},
|
||||||
|
{101, "BL-Short Trigger (2H)"_s},
|
||||||
|
{102, "Shielded Trigger (2H)"_s},
|
||||||
|
{103, "Platedframe Trigger (2H)"_s},
|
||||||
|
{104, "Sidebox Trigger (2H) (Motion)"_s},
|
||||||
|
{199, "2H Base Trigger (2H)"_s},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<Int, Containers::StringView> bshooter_barrels {
|
||||||
|
{0, "BL-Combat Barrel (1 shot)"_s},
|
||||||
|
{1, "Shock Absorb Barrel (1 shot) (Motion)"_s},
|
||||||
|
{2, "Muzzlemod Barrel (1 shot)"_s},
|
||||||
|
{3, "Triangular Barrel (1 shot)"_s},
|
||||||
|
{4, "Recoilblock Barrel (1 shot) (Motion)"_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},
|
||||||
|
|
||||||
|
{100, "Six-Barrel Gatling (Auto) (Motion)"_s},
|
||||||
|
{101, "Modded Six-Barrel Gatling (Auto) (Motion)"_s},
|
||||||
|
{102, "Four-Barrel Gatling (Auto) (Motion)"_s},
|
||||||
|
{103, "Retro Style Gatling (Auto) (Motion)"_s},
|
||||||
|
{197, "Short G Base Barrel (Auto)"_s},
|
||||||
|
{198, "Medium G Base Barrel (Auto)"_s},
|
||||||
|
{199, "Long G Base Barrel (Auto)"_s},
|
||||||
|
|
||||||
|
{200, "Blast Barrel (Spread)"_s},
|
||||||
|
{201, "Wideblast Barrel (Spread) (Motion)"_s},
|
||||||
|
{202, "Pelleter Barrel (Spread) (Motion)"_s},
|
||||||
|
{203, "Lockhold Barrel (Spread) (Motion)"_s},
|
||||||
|
{297, "Short B Base Barrel (Spread)"_s},
|
||||||
|
{298, "Medium B Base Barrel (Spread)"_s},
|
||||||
|
{299, "Long B Base Barrel (Spread)"_s},
|
||||||
|
|
||||||
|
{300, "Propulsive Barrel (Detonate)"_s},
|
||||||
|
{301, "Roundbox Barrel (Detonate)"_s},
|
||||||
|
{302, "ShieldDet Barrel (Detonate)"_s},
|
||||||
|
{303, "RecoilDet Barrel (Detonate) (Motion)"_s},
|
||||||
|
{397, "Short D Base Barrel (Detonate)"_s},
|
||||||
|
{398, "Medium D Base Barrel (Detonate)"_s},
|
||||||
|
{399, "Long D Base Barrel (Detonate)"_s},
|
||||||
|
};
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
//region Energy Shooters
|
||||||
|
static const std::map<Int, Containers::StringView> eshooter_triggers {
|
||||||
|
{0, "EN-Rifle Trigger (1H)"_s},
|
||||||
|
{1, "Underarm Trigger (1H)"_s},
|
||||||
|
{2, "EN-Inverted Trigger (1H)"_s},
|
||||||
|
{3, "EN-Submachine Trigger (1H) (Motion)"_s},
|
||||||
|
{4, "EN-Needler Trigger (1H)"_s},
|
||||||
|
{5, "Angular Trigger (1H)"_s},
|
||||||
|
{6, "Exposed Trigger (1H)"_s},
|
||||||
|
{99, "Base EnTrigger (1H)"_s},
|
||||||
|
|
||||||
|
{100, "EN-Combat Trigger (2H)"_s},
|
||||||
|
{101, "EN-Alternate Trigger (2H)"_s},
|
||||||
|
{102, "Framed Trigger (2H) (Motion)"_s},
|
||||||
|
{103, "Stabilised Trigger (2H)"_s},
|
||||||
|
{104, "EN-Heavy Trigger (2H)"_s},
|
||||||
|
{199, "2H Base EnTrigger (2H)"_s},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<Int, Containers::StringView> eshooter_busters {
|
||||||
|
{0, "EN-Combat Buster (1 shot)"_s},
|
||||||
|
{1, "Delta Cycler (1 shot) (Motion)"_s},
|
||||||
|
{2, "EN-Longbarrel Buster (1 shot)"_s},
|
||||||
|
{3, "Kinetic Buster (1 shot) (Motion)"_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},
|
||||||
|
|
||||||
|
{100, "EN-Rifle Buster (Auto)"_s},
|
||||||
|
{101, "EN-Focus Buster (Auto)"_s},
|
||||||
|
{102, "Machinist Buster (Auto)"_s},
|
||||||
|
{103, "EN-Precision Buster (Auto) (Motion)"_s},
|
||||||
|
{197, "Short A Base Buster (Auto)"_s},
|
||||||
|
{198, "Medium A Base Buster (Auto)"_s},
|
||||||
|
{199, "Long A Base Buster (Auto)"_s},
|
||||||
|
|
||||||
|
{200, "Railcharge Buster (Ray) (Motion)"_s},
|
||||||
|
{201, "Clawcharge Buster (Ray)"_s},
|
||||||
|
{202, "Twizelcharge Buster (Ray)"_s},
|
||||||
|
{203, "Deltacharge Buster (Ray)"_s},
|
||||||
|
{297, "Short R Base Buster (Ray)"_s},
|
||||||
|
{298, "Medium R Base Buster (Ray)"_s},
|
||||||
|
{299, "Long R Base Buster (Ray)"_s},
|
||||||
|
|
||||||
|
{300, "Subsonic Buster (Wave)"_s},
|
||||||
|
{301, "Amplifier Buster (Wave) (Motion)"_s},
|
||||||
|
{302, "Cyclonwave Buster (Wave)"_s},
|
||||||
|
{303, "Warhorn Buster (Wave) (Motion)"_s},
|
||||||
|
{397, "Short W Base Buster (Wave)"_s},
|
||||||
|
{398, "Medium W Base Buster (Wave)"_s},
|
||||||
|
{399, "Long W Base Buster (Wave)"_s},
|
||||||
|
};
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Bullet Launchers
|
||||||
|
static const std::map<Int, Containers::StringView> blauncher_pods {
|
||||||
|
{0, "BL-Delta Pack Launcher (Missile x12)"_s},
|
||||||
|
{1, "BL-Twin Pack Launcher (Missile x12)"_s},
|
||||||
|
{2, "Detector Launcher (Missile x12)"_s},
|
||||||
|
{3, "BL-Triplet Pack Launcher (Missile x12)"_s},
|
||||||
|
{4, "Shielded Launcher (Missile x12)"_s},
|
||||||
|
{99, "H Base Pod (Missile x12)"_s},
|
||||||
|
|
||||||
|
{100, "Warhead Pod (Nuke x2)"_s},
|
||||||
|
{101, "Warhead Launcher (Nuke x2)"_s},
|
||||||
|
{102, "Triangular Warhead Pod (Nuke x2)"_s},
|
||||||
|
{103, "Expanded Warhead Pod (Nuke x2)"_s},
|
||||||
|
{104, "Shielded Warhead Pod (Nuke x2)"_s},
|
||||||
|
{199, "N Base Pod (Nuke x2)"_s},
|
||||||
|
|
||||||
|
{200, "Widepack Launcher (Salvo x24)"_s},
|
||||||
|
{201, "Covered Launcher (Salvo x24)"_s},
|
||||||
|
{202, "Double Delta Launcher (Salvo x24)"_s},
|
||||||
|
{203, "Hexagonal Launcher (Salvo x24)"_s},
|
||||||
|
{204, "Shielded Six Launcher (Salvo x24)"_s},
|
||||||
|
{299, "S Base Pod (Salvo x24)"_s},
|
||||||
|
|
||||||
|
{300, "Sentinel Cluster Pod (Cluster x40)"_s},
|
||||||
|
{301, "Pincer Cluster Pod (Cluster x40)"_s},
|
||||||
|
{302, "Elliptical Cluster Pod (Cluster x40)"_s},
|
||||||
|
{303, "Sawed Cluster Pod (Cluster x40)"_s},
|
||||||
|
{304, "Pentagonal Cluster Pod (Cluster x40)"_s},
|
||||||
|
{399, "C Base Pod (Cluster x40)"_s},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<Int, Containers::StringView> blauncher_projectiles {
|
||||||
|
{0, "Flathead Missile"_s},
|
||||||
|
{1, "Warhead Missile"_s},
|
||||||
|
{2, "Pointhead Missile"_s},
|
||||||
|
{3, "Marker Missile"_s},
|
||||||
|
{4, "ArB Missile"_s},
|
||||||
|
};
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Energy Launchers
|
||||||
|
static const std::map<Int, Containers::StringView> elauncher_generators {
|
||||||
|
{0, "Fly Unit"_s},
|
||||||
|
{1, "Assault Unit (Motion)"_s},
|
||||||
|
{2, "Falcon Unit"_s},
|
||||||
|
{3, "Drake Unit (Motion)"_s},
|
||||||
|
{4, "Kingfisher Unit"_s},
|
||||||
|
{5, "Tri-Edge Unit"_s},
|
||||||
|
{6, "Flatline Unit"_s},
|
||||||
|
{7, "Boost Unit"_s},
|
||||||
|
{8, "Sparrow Unit"_s},
|
||||||
|
{9, "Guarded Unit"_s},
|
||||||
|
{10, "Sailtail Unit"_s},
|
||||||
|
{11, "Tri-Covered Unit"_s},
|
||||||
|
{12, "Pointy Unit"_s},
|
||||||
|
{13, "Scope-Like Unit"_s},
|
||||||
|
{14, "Rotating Unit (Motion)"_s},
|
||||||
|
{15, "Clamper Unit"_s},
|
||||||
|
{16, "Quadsat Unit"_s},
|
||||||
|
{17, "Squ-Rotating Unit (Motion)"_s},
|
||||||
|
{18, "Bloom Unit"_s},
|
||||||
|
{19, "Edge-Rotating Unit (Motion)"_s},
|
||||||
|
{20, "Shipend Unit"_s},
|
||||||
|
{21, "Revwing Unit"_s},
|
||||||
|
{22, "Viper Unit"_s},
|
||||||
|
{23, "EX Unit"_s},
|
||||||
|
{24, "Aery Unit"_s},
|
||||||
|
{25, "Carrier Unit"_s},
|
||||||
|
{26, "Compartment Unit"_s},
|
||||||
|
{27, "Flatedge Unit"_s},
|
||||||
|
{99, "Base Generator"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<Int, Containers::StringView> elauncher_pods {
|
||||||
|
{0, "EN-Dual Claw Launcher (Echo) (Motion)"_s},
|
||||||
|
{1, "EN-Assault Launcher (Echo)"_s},
|
||||||
|
{2, "EN-Tactical Launcher (Echo)"_s},
|
||||||
|
{3, "EN-Force Focus Launcher (Echo) (Motion)"_s},
|
||||||
|
{4, "EN-Needler Launcher (Echo)"_s},
|
||||||
|
{5, "Spark Launcher (Echo)"_s},
|
||||||
|
{6, "Pinpoint Launcher (Echo)"_s},
|
||||||
|
{99, "E Base EPod (Echo)"_s},
|
||||||
|
|
||||||
|
{100, "Raystream Launcher (Beam)"_s},
|
||||||
|
{101, "Perpetum Launcher (Beam)"_s},
|
||||||
|
{102, "Scorcher Launcher (Beam)"_s},
|
||||||
|
{103, "Concentrator Launcher (Beam)"_s},
|
||||||
|
{104, "Crosshair Launcher (Beam)"_s},
|
||||||
|
{105, "Powerlined Launcher (Beam)"_s},
|
||||||
|
{106, "Attached Launcher (Beam)"_s},
|
||||||
|
{199, "B Base EPod (Beam)"_s},
|
||||||
|
|
||||||
|
{200, "Hilt Launcher (Slash) (Motion)"_s},
|
||||||
|
{201, "Underangle Launcher (Slash)"_s},
|
||||||
|
{202, "Crossblade Launcher (Slash)"_s},
|
||||||
|
{203, "Deltablade Launcher (Slash) (Motion)"_s},
|
||||||
|
{204, "Spike Launcher (Slash)"_s},
|
||||||
|
{205, "Tri-Pronged Launcher (Slash) (Motion)"_s},
|
||||||
|
{206, "Heavyblade Launcher (Slash)"_s},
|
||||||
|
{299, "S Base EPod (Slash)"_s},
|
||||||
|
|
||||||
|
{300, "Covering Launcher (Photon)"_s},
|
||||||
|
{301, "Boxhead Launcher (Photon)"_s},
|
||||||
|
{302, "Stabilised Launcher (Photon)"_s},
|
||||||
|
{303, "Flatline Launcher (Photon)"_s},
|
||||||
|
{304, "Shelled Launcher (Photon)"_s},
|
||||||
|
{305, "Widearm Launcher (Photon)"_s},
|
||||||
|
{306, "Wingspan Launcher (Photon)"_s},
|
||||||
|
{399, "P Base EPod (Photon)"_s},
|
||||||
|
};
|
||||||
|
// endregion
|
|
@ -18,19 +18,17 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/Array.h>
|
#include <Corrade/Containers/Array.h>
|
||||||
#include <Corrade/Containers/Pair.h>
|
#include <Corrade/Containers/Pair.h>
|
||||||
|
#include <Corrade/Containers/ScopeGuard.h>
|
||||||
#include <Corrade/Utility/Path.h>
|
#include <Corrade/Utility/Path.h>
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||||
#include "../UESaveFile/Types/BoolProperty.h"
|
#include "../UESaveFile/Types/BoolProperty.h"
|
||||||
#include "../UESaveFile/Types/ByteProperty.h"
|
|
||||||
#include "../UESaveFile/Types/ColourStructProperty.h"
|
#include "../UESaveFile/Types/ColourStructProperty.h"
|
||||||
#include "../UESaveFile/Types/FloatProperty.h"
|
|
||||||
#include "../UESaveFile/Types/GenericStructProperty.h"
|
#include "../UESaveFile/Types/GenericStructProperty.h"
|
||||||
#include "../UESaveFile/Types/IntProperty.h"
|
#include "../UESaveFile/Types/IntProperty.h"
|
||||||
#include "../UESaveFile/Types/RotatorStructProperty.h"
|
|
||||||
#include "../UESaveFile/Types/StringProperty.h"
|
#include "../UESaveFile/Types/StringProperty.h"
|
||||||
#include "../UESaveFile/Types/VectorStructProperty.h"
|
|
||||||
#include "../UESaveFile/Types/Vector2DStructProperty.h"
|
|
||||||
|
|
||||||
#include "Mass.h"
|
#include "Mass.h"
|
||||||
|
|
||||||
|
@ -50,28 +48,28 @@ auto Mass::lastError() -> Containers::StringView {
|
||||||
|
|
||||||
auto Mass::getNameFromFile(Containers::StringView path) -> Containers::Optional<Containers::String> {
|
auto Mass::getNameFromFile(Containers::StringView path) -> Containers::Optional<Containers::String> {
|
||||||
if(!Utility::Path::exists(path)) {
|
if(!Utility::Path::exists(path)) {
|
||||||
Utility::Error{} << path << "couldn't be found."_s;
|
LOG_ERROR_FORMAT("{} couldn't be found.", path);
|
||||||
return Containers::NullOpt;
|
return Containers::NullOpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
UESaveFile mass{path};
|
UESaveFile mass{path};
|
||||||
|
|
||||||
if(!mass.valid()) {
|
if(!mass.valid()) {
|
||||||
Utility::Error{} << "The unit file seems to be corrupt."_s;
|
LOG_ERROR_FORMAT("{} is invalid: {}", path, mass.lastError());
|
||||||
return Containers::NullOpt;
|
return Containers::NullOpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unit_data = mass.at<GenericStructProperty>("UnitData"_s);
|
auto unit_data = mass.at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
Utility::Error{} << "Couldn't find unit data in the file."_s;
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, path);
|
||||||
return Containers::NullOpt;
|
return Containers::NullOpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto name_prop = unit_data->at<StringProperty>("Name_45_A037C5D54E53456407BDF091344529BB"_s);
|
auto name_prop = unit_data->at<StringProperty>(MASS_NAME);
|
||||||
|
|
||||||
if(!name_prop) {
|
if(!name_prop) {
|
||||||
Utility::Error{} << "Couldn't find the name in the file."_s;
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_NAME, path);
|
||||||
return Containers::NullOpt;
|
return Containers::NullOpt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,34 +77,63 @@ auto Mass::getNameFromFile(Containers::StringView path) -> Containers::Optional<
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::refreshValues() {
|
void Mass::refreshValues() {
|
||||||
|
LOG_INFO_FORMAT("Refreshing values for {}.", _filename);
|
||||||
|
|
||||||
|
logger().lockMutex();
|
||||||
|
logger().indent();
|
||||||
|
logger().unlockMutex();
|
||||||
|
|
||||||
|
Containers::ScopeGuard indent_guard{[]{
|
||||||
|
logger().lockMutex();
|
||||||
|
logger().unindent();
|
||||||
|
logger().unlockMutex();
|
||||||
|
}};
|
||||||
|
|
||||||
|
LOG_INFO("Checking if file exists.");
|
||||||
if(!Utility::Path::exists(Utility::Path::join(_folder, _filename))) {
|
if(!Utility::Path::exists(Utility::Path::join(_folder, _filename))) {
|
||||||
|
LOG_WARNING_FORMAT("{} doesn't exist in {}.", _filename, _folder);
|
||||||
_state = State::Empty;
|
_state = State::Empty;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_mass) {
|
if(!_mass) {
|
||||||
|
LOG_INFO("Reading the GVAS save.");
|
||||||
_mass.emplace(Utility::Path::join(_folder, _filename));
|
_mass.emplace(Utility::Path::join(_folder, _filename));
|
||||||
if(!_mass->valid()) {
|
if(!_mass->valid()) {
|
||||||
|
LOG_ERROR(_mass->lastError());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
LOG_INFO("Reloading the GVAS data.");
|
||||||
if(!_mass->reloadData()) {
|
if(!_mass->reloadData()) {
|
||||||
|
LOG_ERROR(_mass->lastError());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Checking the save file type.");
|
||||||
if(!unit_data) {
|
if(_mass->saveType() != "/Game/Core/Save/bpSaveGameUnit.bpSaveGameUnit_C"_s) {
|
||||||
|
LOG_ERROR_FORMAT("{} is not a valid unit save.", _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto name_prop = unit_data->at<StringProperty>("Name_45_A037C5D54E53456407BDF091344529BB"_s);
|
LOG_INFO("Getting the unit data.");
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Reading the M.A.S.S. name.");
|
||||||
|
auto name_prop = unit_data->at<StringProperty>(MASS_NAME);
|
||||||
|
|
||||||
if(!name_prop) {
|
if(!name_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_NAME, _filename);
|
||||||
_name = Containers::NullOpt;
|
_name = Containers::NullOpt;
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
|
@ -189,8 +216,10 @@ void Mass::refreshValues() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Getting the associated account.");
|
||||||
auto account_prop = _mass->at<StringProperty>("Account"_s);
|
auto account_prop = _mass->at<StringProperty>("Account"_s);
|
||||||
if(!account_prop) {
|
if(!account_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_ACCOUNT, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -205,6 +234,7 @@ auto Mass::filename() -> Containers::StringView {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::name() -> Containers::StringView {
|
auto Mass::name() -> Containers::StringView {
|
||||||
|
CORRADE_INTERNAL_ASSERT(_name);
|
||||||
return *_name;
|
return *_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,6 +244,7 @@ auto Mass::setName(Containers::StringView new_name) -> bool {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
||||||
|
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -221,6 +252,7 @@ auto Mass::setName(Containers::StringView new_name) -> bool {
|
||||||
auto name_prop = unit_data->at<StringProperty>("Name_45_A037C5D54E53456407BDF091344529BB"_s);
|
auto name_prop = unit_data->at<StringProperty>("Name_45_A037C5D54E53456407BDF091344529BB"_s);
|
||||||
|
|
||||||
if(!name_prop) {
|
if(!name_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_NAME, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -248,17 +280,20 @@ void Mass::setDirty(bool dirty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getTuning() {
|
void Mass::getTuning() {
|
||||||
getTuningCategory("Engine"_s, _tuning.engineId, "Gears"_s, _tuning.gearIds);
|
getTuningCategory(MASS_ENGINE, _tuning.engineId,
|
||||||
|
MASS_GEARS, _tuning.gearIds);
|
||||||
if(_state == State::Invalid) {
|
if(_state == State::Invalid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTuningCategory("OS"_s, _tuning.osId, "Modules"_s, _tuning.moduleIds);
|
getTuningCategory(MASS_OS, _tuning.osId,
|
||||||
|
MASS_MODULES, _tuning.moduleIds);
|
||||||
if(_state == State::Invalid) {
|
if(_state == State::Invalid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTuningCategory("Architect"_s, _tuning.archId, "Techs"_s, _tuning.techIds);
|
getTuningCategory(MASS_ARCHITECT, _tuning.archId,
|
||||||
|
MASS_TECHS, _tuning.techIds);
|
||||||
if(_state == State::Invalid) {
|
if(_state == State::Invalid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -295,10 +330,10 @@ auto Mass::account() -> Containers::StringView {
|
||||||
auto Mass::updateAccount(Containers::StringView new_account) -> bool {
|
auto Mass::updateAccount(Containers::StringView new_account) -> bool {
|
||||||
_account = new_account;
|
_account = new_account;
|
||||||
|
|
||||||
auto account = _mass->at<StringProperty>("Account"_s);
|
auto account = _mass->at<StringProperty>(MASS_ACCOUNT);
|
||||||
if(!account) {
|
if(!account) {
|
||||||
|
_lastError = "Couldn't find the " MASS_ACCOUNT " property."_s;
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
_lastError = "Couldn't find the account property."_s;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,8 +350,11 @@ auto Mass::updateAccount(Containers::StringView new_account) -> bool {
|
||||||
void Mass::getTuningCategory(Containers::StringView big_node_prop_name, Int& big_node_id,
|
void Mass::getTuningCategory(Containers::StringView big_node_prop_name, Int& big_node_id,
|
||||||
Containers::StringView small_nodes_prop_name, Containers::ArrayView<Int> small_nodes_ids)
|
Containers::StringView small_nodes_prop_name, Containers::ArrayView<Int> small_nodes_ids)
|
||||||
{
|
{
|
||||||
|
LOG_INFO_FORMAT("Getting tuning data ({}, {}).", big_node_prop_name, small_nodes_prop_name);
|
||||||
|
|
||||||
auto node_id = _mass->at<IntProperty>(big_node_prop_name);
|
auto node_id = _mass->at<IntProperty>(big_node_prop_name);
|
||||||
if(!node_id) {
|
if(!node_id) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", big_node_prop_name, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -324,11 +362,14 @@ void Mass::getTuningCategory(Containers::StringView big_node_prop_name, Int& big
|
||||||
|
|
||||||
auto node_ids = _mass->at<ArrayProperty>(small_nodes_prop_name);
|
auto node_ids = _mass->at<ArrayProperty>(small_nodes_prop_name);
|
||||||
if(!node_ids) {
|
if(!node_ids) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", small_nodes_prop_name, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node_ids->items.size() != small_nodes_ids.size()) {
|
if(node_ids->items.size() != small_nodes_ids.size()) {
|
||||||
|
LOG_ERROR_FORMAT("Node ID arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
small_nodes_ids.size(), node_ids->items.size());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||||
#include "../UESaveFile/Types/ByteProperty.h"
|
#include "../UESaveFile/Types/ByteProperty.h"
|
||||||
#include "../UESaveFile/Types/GenericStructProperty.h"
|
#include "../UESaveFile/Types/GenericStructProperty.h"
|
||||||
|
@ -32,19 +34,25 @@ auto Mass::armourParts() -> Containers::ArrayView<ArmourPart> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getArmourParts() {
|
void Mass::getArmourParts() {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Getting armour parts.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto armour_array = unit_data->at<ArrayProperty>("Armor_10_12E266C44116DDAF57E99ABB575A4B3C"_s);
|
auto armour_array = unit_data->at<ArrayProperty>(MASS_ARMOUR_PARTS);
|
||||||
if(!armour_array) {
|
if(!armour_array) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_ARMOUR_PARTS, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(armour_array->items.size() != _armour.parts.size()) {
|
if(armour_array->items.size() != _armour.parts.size()) {
|
||||||
|
LOG_ERROR_FORMAT("Armour part arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
_armour.parts.size(), armour_array->items.size());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -53,24 +61,28 @@ void Mass::getArmourParts() {
|
||||||
auto part_prop = armour_array->at<GenericStructProperty>(i);
|
auto part_prop = armour_array->at<GenericStructProperty>(i);
|
||||||
auto& part = _armour.parts[i];
|
auto& part = _armour.parts[i];
|
||||||
|
|
||||||
auto& armour_slot = part_prop->at<ByteProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C"_s)->enumValue;
|
auto& armour_slot = part_prop->at<ByteProperty>(MASS_ARMOUR_SLOT)->enumValue;
|
||||||
#define c(enumerator, strenum, name) if(armour_slot == (strenum)) { part.slot = ArmourSlot::enumerator; } else
|
#define c(enumerator, strenum, name) if(armour_slot == (strenum)) { part.slot = ArmourSlot::enumerator; } else
|
||||||
#include "../Maps/ArmourSlots.hpp"
|
#include "../Maps/ArmourSlots.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
{
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid armour slot enumerator {}.", armour_slot);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
Utility::Warning{} << "Invalid armour slot enum value in getArmourParts()."_s;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
part.id = part_prop->at<IntProperty>("ID_5_ACD101864D3481DE96EDACACC09BDD25"_s)->value;
|
part.id = part_prop->at<IntProperty>(MASS_ARMOUR_ID)->value;
|
||||||
|
|
||||||
auto part_styles = part_prop->at<ArrayProperty>("Styles_47_3E31870441DFD7DB8BEE5C85C26B365B"_s);
|
auto part_styles = part_prop->at<ArrayProperty>(MASS_ARMOUR_STYLES);
|
||||||
if(!part_styles) {
|
if(!part_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Part styles not found for part number {}.", i);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(part_styles->items.size() != part.styles.size()) {
|
if(part_styles->items.size() != part.styles.size()) {
|
||||||
|
LOG_ERROR_FORMAT("Armour part style arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
part.styles.size(), part_styles->items.size());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -79,8 +91,9 @@ void Mass::getArmourParts() {
|
||||||
part.styles[j] = part_styles->at<IntProperty>(j)->value;
|
part.styles[j] = part_styles->at<IntProperty>(j)->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto decals_array = part_prop->at<ArrayProperty>("Decals_42_F358794A4F18497970F56BA9627D3603"_s);
|
auto decals_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_DECALS);
|
||||||
if(!decals_array) {
|
if(!decals_array) {
|
||||||
|
LOG_ERROR_FORMAT("Part decals not found for part number {}.", i);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -89,8 +102,9 @@ void Mass::getArmourParts() {
|
||||||
|
|
||||||
getDecals(part.decals, decals_array);
|
getDecals(part.decals, decals_array);
|
||||||
|
|
||||||
auto accs_array = part_prop->at<ArrayProperty>("Accessories_52_D902DD4241FA0050C2529596255153F3"_s);
|
auto accs_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_ACCESSORIES);
|
||||||
if(!accs_array) {
|
if(!accs_array) {
|
||||||
|
LOG_WARNING_FORMAT("Part accessories not found for part number {}.", i);
|
||||||
part.accessories = Containers::Array<Accessory>{};
|
part.accessories = Containers::Array<Accessory>{};
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -104,11 +118,25 @@ void Mass::getArmourParts() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
||||||
|
LOG_INFO_FORMAT("Writing armour part in slot {}.", static_cast<int>(slot));
|
||||||
|
|
||||||
auto& part = *std::find_if(_armour.parts.begin(), _armour.parts.end(), [&slot](const ArmourPart& part){ return slot == part.slot; });
|
auto& part = *std::find_if(_armour.parts.begin(), _armour.parts.end(), [&slot](const ArmourPart& part){ return slot == part.slot; });
|
||||||
|
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
_lastError = "Couldn't find the unit data in " + _filename + ".";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto armour_array = unit_data->at<ArrayProperty>("Armor_10_12E266C44116DDAF57E99ABB575A4B3C"_s);
|
auto armour_array = unit_data->at<ArrayProperty>(MASS_ARMOUR_PARTS);
|
||||||
|
if(!armour_array) {
|
||||||
|
_lastError = "Couldn't find the armour part array in " + _filename + ".";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Containers::StringView slot_str = nullptr;
|
Containers::StringView slot_str = nullptr;
|
||||||
switch(slot) {
|
switch(slot) {
|
||||||
|
@ -123,7 +151,10 @@ auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < armour_array->items.size(); i++) {
|
for(UnsignedInt i = 0; i < armour_array->items.size(); i++) {
|
||||||
part_prop = armour_array->at<GenericStructProperty>(i);
|
part_prop = armour_array->at<GenericStructProperty>(i);
|
||||||
if(slot_str != part_prop->at<StringProperty>("Slot_3_408BA56F4C9605C7E805CF91B642249C"_s)->value) {
|
if(slot_str == part_prop->at<ByteProperty>(MASS_ARMOUR_SLOT)->enumValue) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
part_prop = nullptr;
|
part_prop = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,21 +168,22 @@ auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
||||||
#include "../Maps/ArmourSlots.hpp"
|
#include "../Maps/ArmourSlots.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
}
|
}
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
part_prop->at<IntProperty>("ID_5_ACD101864D3481DE96EDACACC09BDD25"_s)->value = part.id;
|
part_prop->at<IntProperty>(MASS_ARMOUR_ID)->value = part.id;
|
||||||
|
|
||||||
auto part_styles = part_prop->at<ArrayProperty>("Styles_47_3E31870441DFD7DB8BEE5C85C26B365B"_s);
|
auto part_styles = part_prop->at<ArrayProperty>(MASS_ARMOUR_STYLES);
|
||||||
for(UnsignedInt i = 0; i < part.styles.size(); i++) {
|
for(UnsignedInt i = 0; i < part.styles.size(); i++) {
|
||||||
part_styles->at<IntProperty>(i)->value = part.styles[i];
|
part_styles->at<IntProperty>(i)->value = part.styles[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto decals_array = part_prop->at<ArrayProperty>("Decals_42_F358794A4F18497970F56BA9627D3603"_s);
|
auto decals_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_DECALS);
|
||||||
writeDecals(part.decals, decals_array);
|
writeDecals(part.decals, decals_array);
|
||||||
|
|
||||||
if(part.accessories.size() != 0) {
|
if(part.accessories.size() != 0) {
|
||||||
auto accs_array = part_prop->at<ArrayProperty>("Accessories_52_D902DD4241FA0050C2529596255153F3"_s);
|
auto accs_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_ACCESSORIES);
|
||||||
writeAccessories(part.accessories, accs_array);
|
writeAccessories(part.accessories, accs_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,21 +204,26 @@ auto Mass::bulletLauncherAttachments() -> Containers::ArrayView<BulletLauncherAt
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getBulletLauncherAttachments() {
|
void Mass::getBulletLauncherAttachments() {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Getting the bullet launcher attachment data.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attach_style_prop = unit_data->at<ByteProperty>("WeaponBLAttachmentStyle_65_5943FCE8406F18D2C3F69285EB23A699"_s);
|
auto attach_style_prop = unit_data->at<ByteProperty>(MASS_BL_ATTACHMENT_STYLE);
|
||||||
auto attach_array = unit_data->at<ArrayProperty>("WeaponBLAttachment_61_442D08F547510A4CEE1501BBAF297BA0"_s);
|
auto attach_array = unit_data->at<ArrayProperty>(MASS_BL_ATTACHMENTS);
|
||||||
|
|
||||||
if(!attach_style_prop && !attach_array) {
|
if(!attach_style_prop && !attach_array) {
|
||||||
|
LOG_WARNING_FORMAT("No bullet launcher attachment data found in {}.", _filename);
|
||||||
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attach_style_prop && !attach_array) {
|
if(attach_style_prop && !attach_array) {
|
||||||
|
LOG_WARNING_FORMAT("No bullet launcher attachments found in {}.", _filename);
|
||||||
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
|
@ -199,25 +236,25 @@ void Mass::getBulletLauncherAttachments() {
|
||||||
auto attachment_prop = attach_array->at<GenericStructProperty>(i);
|
auto attachment_prop = attach_array->at<GenericStructProperty>(i);
|
||||||
auto& attachment = _armour.blAttachment[i];
|
auto& attachment = _armour.blAttachment[i];
|
||||||
|
|
||||||
Containers::StringView socket = attachment_prop->at<StringProperty>("Socket_9_B9DBF30D4A1F0032A2BE2F8B342B35A9"_s)->value;
|
Containers::StringView socket = attachment_prop->at<StringProperty>(MASS_BL_ATTACHMENT_SOCKET)->value;
|
||||||
#define c(enumerator, strenum, name) if(socket == (strenum)) { attachment.socket = BulletLauncherSocket::enumerator; } else
|
#define c(enumerator, strenum, name) if(socket == (strenum)) { attachment.socket = BulletLauncherSocket::enumerator; } else
|
||||||
#include "../Maps/BulletLauncherSockets.hpp"
|
#include "../Maps/BulletLauncherSockets.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
{
|
{
|
||||||
Utility::Error{} << "Invalid BL attachment socket.";
|
LOG_ERROR_FORMAT("Invalid attachment socket {}.", socket);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rel_loc_prop = attachment_prop->at<VectorStructProperty>("RelativeLocation_10_2F6E75DF4C40622658340E9A22D38B02"_s);
|
auto rel_loc_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELLOC);
|
||||||
attachment.relativeLocation = Vector3{rel_loc_prop->x, rel_loc_prop->y, rel_loc_prop->z};
|
attachment.relativeLocation = Vector3{rel_loc_prop->x, rel_loc_prop->y, rel_loc_prop->z};
|
||||||
auto off_loc_prop = attachment_prop->at<VectorStructProperty>("OffsetLocation_11_F42B3DA3436948FF85752DB33722382F"_s);
|
auto off_loc_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_OFFLOC);
|
||||||
attachment.offsetLocation = Vector3{off_loc_prop->x, off_loc_prop->y, off_loc_prop->z};
|
attachment.offsetLocation = Vector3{off_loc_prop->x, off_loc_prop->y, off_loc_prop->z};
|
||||||
auto rel_rot_prop = attachment_prop->at<VectorStructProperty>("RelativeRotation_12_578140464621245132CFF2A2AD85E735"_s);
|
auto rel_rot_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELROT);
|
||||||
attachment.relativeRotation = Vector3{rel_rot_prop->x, rel_rot_prop->y, rel_rot_prop->z};
|
attachment.relativeRotation = Vector3{rel_rot_prop->x, rel_rot_prop->y, rel_rot_prop->z};
|
||||||
auto off_rot_prop = attachment_prop->at<VectorStructProperty>("OffsetRotation_13_B5980BCD47905D842D1490A1A520B064"_s);
|
auto off_rot_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_OFFROT);
|
||||||
attachment.offsetRotation = Vector3{off_rot_prop->x, off_rot_prop->y, off_rot_prop->z};
|
attachment.offsetRotation = Vector3{off_rot_prop->x, off_rot_prop->y, off_rot_prop->z};
|
||||||
auto rel_scale_prop = attachment_prop->at<VectorStructProperty>("RelativeScale_16_37BC80EF42699F79533F7AA7B3094E38"_s);
|
auto rel_scale_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELSCALE);
|
||||||
attachment.relativeScale = Vector3{rel_scale_prop->x, rel_scale_prop->y, rel_scale_prop->z};
|
attachment.relativeScale = Vector3{rel_scale_prop->x, rel_scale_prop->y, rel_scale_prop->z};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,7 +265,8 @@ void Mass::getBulletLauncherAttachments() {
|
||||||
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
|
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
{
|
{
|
||||||
Utility::Error{} << "Unknown BL attachment style enumerator.";
|
LOG_ERROR_FORMAT("Invalid attachment style {}.", attach_style);
|
||||||
|
_state = State::Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -237,26 +275,31 @@ void Mass::getBulletLauncherAttachments() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeBulletLauncherAttachments() -> bool {
|
auto Mass::writeBulletLauncherAttachments() -> bool {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Writing bullet launcher attachments.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No unit data in " + _filename;
|
_lastError = "No unit data in " + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto attach_style_prop = unit_data->at<ByteProperty>("WeaponBLAttachmentStyle_65_5943FCE8406F18D2C3F69285EB23A699"_s);
|
auto attach_style_prop = unit_data->at<ByteProperty>(MASS_BL_ATTACHMENT_STYLE);
|
||||||
auto attach_array = unit_data->at<ArrayProperty>("WeaponBLAttachment_61_442D08F547510A4CEE1501BBAF297BA0"_s);
|
auto attach_array = unit_data->at<ArrayProperty>(MASS_BL_ATTACHMENTS);
|
||||||
|
|
||||||
if(!attach_style_prop && !attach_array) {
|
if(!attach_style_prop && !attach_array) {
|
||||||
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
|
||||||
_lastError = "No attachment properties to write to in " + _filename;
|
_lastError = "No attachment properties to write to in " + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(attach_style_prop && !attach_array) {
|
if(attach_style_prop && !attach_array) {
|
||||||
|
_lastError = "Couldn't find the attachments in " + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
_lastError = "Couldn't find the attachments in " + _filename;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,33 +310,34 @@ auto Mass::writeBulletLauncherAttachments() -> bool {
|
||||||
auto attachment_prop = attach_array->at<GenericStructProperty>(i);
|
auto attachment_prop = attach_array->at<GenericStructProperty>(i);
|
||||||
auto& attachment = _armour.blAttachment[i];
|
auto& attachment = _armour.blAttachment[i];
|
||||||
|
|
||||||
auto& socket = attachment_prop->at<StringProperty>("Socket_9_B9DBF30D4A1F0032A2BE2F8B342B35A9"_s)->value;
|
auto& socket = attachment_prop->at<StringProperty>(MASS_BL_ATTACHMENT_SOCKET)->value;
|
||||||
switch(attachment.socket) {
|
switch(attachment.socket) {
|
||||||
#define c(enumerator, strenum, name) case BulletLauncherSocket::enumerator: socket = strenum; break;
|
#define c(enumerator, strenum, name) case BulletLauncherSocket::enumerator: socket = strenum; break;
|
||||||
#include "../Maps/BulletLauncherSockets.hpp"
|
#include "../Maps/BulletLauncherSockets.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
default:
|
default:
|
||||||
_lastError = "Invalid socket type."_s;
|
_lastError = "Invalid socket type."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto rel_loc_prop = attachment_prop->at<VectorStructProperty>("RelativeLocation_10_2F6E75DF4C40622658340E9A22D38B02"_s);
|
auto rel_loc_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELLOC);
|
||||||
rel_loc_prop->x = attachment.relativeLocation.x();
|
rel_loc_prop->x = attachment.relativeLocation.x();
|
||||||
rel_loc_prop->y = attachment.relativeLocation.y();
|
rel_loc_prop->y = attachment.relativeLocation.y();
|
||||||
rel_loc_prop->z = attachment.relativeLocation.z();
|
rel_loc_prop->z = attachment.relativeLocation.z();
|
||||||
auto off_loc_prop = attachment_prop->at<VectorStructProperty>("OffsetLocation_11_F42B3DA3436948FF85752DB33722382F"_s);
|
auto off_loc_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_OFFLOC);
|
||||||
off_loc_prop->x = attachment.offsetLocation.x();
|
off_loc_prop->x = attachment.offsetLocation.x();
|
||||||
off_loc_prop->y = attachment.offsetLocation.y();
|
off_loc_prop->y = attachment.offsetLocation.y();
|
||||||
off_loc_prop->z = attachment.offsetLocation.z();
|
off_loc_prop->z = attachment.offsetLocation.z();
|
||||||
auto rel_rot_prop = attachment_prop->at<VectorStructProperty>("RelativeRotation_12_578140464621245132CFF2A2AD85E735"_s);
|
auto rel_rot_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELROT);
|
||||||
rel_rot_prop->x = attachment.relativeRotation.x();
|
rel_rot_prop->x = attachment.relativeRotation.x();
|
||||||
rel_rot_prop->y = attachment.relativeRotation.y();
|
rel_rot_prop->y = attachment.relativeRotation.y();
|
||||||
rel_rot_prop->z = attachment.relativeRotation.z();
|
rel_rot_prop->z = attachment.relativeRotation.z();
|
||||||
auto off_rot_prop = attachment_prop->at<VectorStructProperty>("OffsetRotation_13_B5980BCD47905D842D1490A1A520B064"_s);
|
auto off_rot_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_OFFROT);
|
||||||
off_rot_prop->x = attachment.offsetRotation.x();
|
off_rot_prop->x = attachment.offsetRotation.x();
|
||||||
off_rot_prop->y = attachment.offsetRotation.y();
|
off_rot_prop->y = attachment.offsetRotation.y();
|
||||||
off_rot_prop->z = attachment.offsetRotation.z();
|
off_rot_prop->z = attachment.offsetRotation.z();
|
||||||
auto rel_scale_prop = attachment_prop->at<VectorStructProperty>("RelativeScale_16_37BC80EF42699F79533F7AA7B3094E38"_s);
|
auto rel_scale_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELSCALE);
|
||||||
rel_scale_prop->x = attachment.relativeScale.x();
|
rel_scale_prop->x = attachment.relativeScale.x();
|
||||||
rel_scale_prop->y = attachment.relativeScale.y();
|
rel_scale_prop->y = attachment.relativeScale.y();
|
||||||
rel_scale_prop->z = attachment.relativeScale.z();
|
rel_scale_prop->z = attachment.relativeScale.z();
|
||||||
|
@ -302,7 +346,7 @@ auto Mass::writeBulletLauncherAttachments() -> bool {
|
||||||
|
|
||||||
if(!attach_style_prop) {
|
if(!attach_style_prop) {
|
||||||
attach_style_prop = new ByteProperty;
|
attach_style_prop = new ByteProperty;
|
||||||
attach_style_prop->name.emplace("WeaponBLAttachmentStyle_65_5943FCE8406F18D2C3F69285EB23A699"_s);
|
attach_style_prop->name.emplace(MASS_BL_ATTACHMENT_STYLE);
|
||||||
attach_style_prop->enumType = "enuBLAttachmentStyle"_s;
|
attach_style_prop->enumType = "enuBLAttachmentStyle"_s;
|
||||||
ByteProperty::ptr prop{attach_style_prop};
|
ByteProperty::ptr prop{attach_style_prop};
|
||||||
arrayAppend(unit_data->properties, std::move(prop));
|
arrayAppend(unit_data->properties, std::move(prop));
|
||||||
|
@ -317,6 +361,7 @@ auto Mass::writeBulletLauncherAttachments() -> bool {
|
||||||
#undef c
|
#undef c
|
||||||
default:
|
default:
|
||||||
_lastError = "Unknown BL attachment style.";
|
_lastError = "Unknown BL attachment style.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,19 +378,25 @@ auto Mass::armourCustomStyles() -> Containers::ArrayView<CustomStyle> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getArmourCustomStyles() {
|
void Mass::getArmourCustomStyles() {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Getting the custom armour styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto armour_styles = unit_data->at<ArrayProperty>("ArmorStyle_42_E2F6AC3647788CB366BD469B3B7E899E"_s);
|
auto armour_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_ARMOUR_STYLES);
|
||||||
if(!armour_styles) {
|
if(!armour_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_CUSTOM_ARMOUR_STYLES, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(armour_styles->items.size() != _armour.customStyles.size()) {
|
if(armour_styles->items.size() != _armour.customStyles.size()) {
|
||||||
|
LOG_ERROR_FORMAT("Custom armour style arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
_armour.customStyles.size(), armour_styles->items.size());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -354,21 +405,26 @@ void Mass::getArmourCustomStyles() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeArmourCustomStyle(UnsignedLong index) -> bool {
|
auto Mass::writeArmourCustomStyle(UnsignedLong index) -> bool {
|
||||||
|
LOG_INFO_FORMAT("Writing custom armour style {}.", index);
|
||||||
|
|
||||||
if(index > _armour.customStyles.size()) {
|
if(index > _armour.customStyles.size()) {
|
||||||
_lastError = "Style index out of range."_s;
|
_lastError = "Style index out of range."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "Couldn't find unit data in "_s + _filename;
|
_lastError = "Couldn't find unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto armour_styles = unit_data->at<ArrayProperty>("ArmorStyle_42_E2F6AC3647788CB366BD469B3B7E899E"_s);
|
auto armour_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_ARMOUR_STYLES);
|
||||||
if(!armour_styles) {
|
if(!armour_styles) {
|
||||||
_lastError = "Couldn't find armour custom styles in "_s + _filename;
|
_lastError = "Couldn't find armour custom styles in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||||
#include "../UESaveFile/Types/BoolProperty.h"
|
#include "../UESaveFile/Types/BoolProperty.h"
|
||||||
#include "../UESaveFile/Types/ColourStructProperty.h"
|
#include "../UESaveFile/Types/ColourStructProperty.h"
|
||||||
|
@ -31,79 +32,82 @@ using namespace Containers::Literals;
|
||||||
void Mass::getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array) {
|
void Mass::getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array) {
|
||||||
for(UnsignedInt i = 0; i < decal_array->items.size(); i++) {
|
for(UnsignedInt i = 0; i < decal_array->items.size(); i++) {
|
||||||
auto decal_prop = decal_array->at<GenericStructProperty>(i);
|
auto decal_prop = decal_array->at<GenericStructProperty>(i);
|
||||||
|
CORRADE_INTERNAL_ASSERT(decal_prop);
|
||||||
auto& decal = decals[i];
|
auto& decal = decals[i];
|
||||||
|
|
||||||
decal.id = decal_prop->at<IntProperty>("ID_3_694C0B35404D8A3168AEC89026BC8CF9"_s)->value;
|
decal.id = decal_prop->at<IntProperty>(MASS_DECAL_ID)->value;
|
||||||
auto colour_prop = decal_prop->at<ColourStructProperty>("Color_8_1B0B9D2B43DA6AAB9FA549B374D3E606"_s);
|
auto colour_prop = decal_prop->at<ColourStructProperty>(MASS_DECAL_COLOUR);
|
||||||
decal.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a};
|
decal.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a};
|
||||||
auto pos_prop = decal_prop->at<VectorStructProperty>("Position_41_022C8FE84E1AAFE587261E88F2C72250"_s);
|
auto pos_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_POSITION);
|
||||||
decal.position = Vector3{pos_prop->x, pos_prop->y, pos_prop->z};
|
decal.position = Vector3{pos_prop->x, pos_prop->y, pos_prop->z};
|
||||||
auto u_prop = decal_prop->at<VectorStructProperty>("UAxis_37_EBEB715F45491AECACCC07A1AE4646D1"_s);
|
auto u_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_UAXIS);
|
||||||
decal.uAxis = Vector3{u_prop->x, u_prop->y, u_prop->z};
|
decal.uAxis = Vector3{u_prop->x, u_prop->y, u_prop->z};
|
||||||
auto v_prop = decal_prop->at<VectorStructProperty>("VAxis_39_C31EB2664EE202CAECFBBB84100B5E35"_s);
|
auto v_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_VAXIS);
|
||||||
decal.vAxis = Vector3{v_prop->x, v_prop->y, v_prop->z};
|
decal.vAxis = Vector3{v_prop->x, v_prop->y, v_prop->z};
|
||||||
auto offset_prop = decal_prop->at<Vector2DStructProperty>("Offset_29_B02BBBB74FC60F5EDBEBAB8020738020"_s);
|
auto offset_prop = decal_prop->at<Vector2DStructProperty>(MASS_DECAL_OFFSET);
|
||||||
decal.offset = Vector2{offset_prop->x, offset_prop->y};
|
decal.offset = Vector2{offset_prop->x, offset_prop->y};
|
||||||
decal.scale = decal_prop->at<FloatProperty>("Scale_32_959D1C2747AFD8D62808468235CBBA40"_s)->value;
|
decal.scale = decal_prop->at<FloatProperty>(MASS_DECAL_SCALE)->value;
|
||||||
decal.rotation = decal_prop->at<FloatProperty>("Rotation_27_12D7C314493D203D5C2326A03C5F910F"_s)->value;
|
decal.rotation = decal_prop->at<FloatProperty>(MASS_DECAL_ROTATION)->value;
|
||||||
decal.flip = decal_prop->at<BoolProperty>("Flip_35_CECCFB184CCD9412BD93FE9A8B656BE1"_s)->value;
|
decal.flip = decal_prop->at<BoolProperty>(MASS_DECAL_FLIP)->value;
|
||||||
decal.wrap = decal_prop->at<BoolProperty>("Wrap_43_A7C68CDF4A92AF2ECDA53F953EE7CA62"_s)->value;
|
decal.wrap = decal_prop->at<BoolProperty>(MASS_DECAL_WRAP)->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::writeDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array) {
|
void Mass::writeDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array) {
|
||||||
for(UnsignedInt i = 0; i < decal_array->items.size(); i++) {
|
for(UnsignedInt i = 0; i < decal_array->items.size(); i++) {
|
||||||
auto decal_prop = decal_array->at<GenericStructProperty>(i);
|
auto decal_prop = decal_array->at<GenericStructProperty>(i);
|
||||||
|
CORRADE_INTERNAL_ASSERT(decal_prop);
|
||||||
auto& decal = decals[i];
|
auto& decal = decals[i];
|
||||||
|
|
||||||
decal_prop->at<IntProperty>("ID_3_694C0B35404D8A3168AEC89026BC8CF9"_s)->value = decal.id;
|
decal_prop->at<IntProperty>(MASS_DECAL_ID)->value = decal.id;
|
||||||
auto colour_prop = decal_prop->at<ColourStructProperty>("Color_8_1B0B9D2B43DA6AAB9FA549B374D3E606"_s);
|
auto colour_prop = decal_prop->at<ColourStructProperty>(MASS_DECAL_COLOUR);
|
||||||
colour_prop->r = decal.colour.r();
|
colour_prop->r = decal.colour.r();
|
||||||
colour_prop->g = decal.colour.g();
|
colour_prop->g = decal.colour.g();
|
||||||
colour_prop->b = decal.colour.b();
|
colour_prop->b = decal.colour.b();
|
||||||
colour_prop->a = decal.colour.a();
|
colour_prop->a = decal.colour.a();
|
||||||
auto pos_prop = decal_prop->at<VectorStructProperty>("Position_41_022C8FE84E1AAFE587261E88F2C72250"_s);
|
auto pos_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_POSITION);
|
||||||
pos_prop->x = decal.position.x();
|
pos_prop->x = decal.position.x();
|
||||||
pos_prop->y = decal.position.y();
|
pos_prop->y = decal.position.y();
|
||||||
pos_prop->z = decal.position.z();
|
pos_prop->z = decal.position.z();
|
||||||
auto u_prop = decal_prop->at<VectorStructProperty>("UAxis_37_EBEB715F45491AECACCC07A1AE4646D1"_s);
|
auto u_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_UAXIS);
|
||||||
u_prop->x = decal.uAxis.x();
|
u_prop->x = decal.uAxis.x();
|
||||||
u_prop->y = decal.uAxis.y();
|
u_prop->y = decal.uAxis.y();
|
||||||
u_prop->z = decal.uAxis.z();
|
u_prop->z = decal.uAxis.z();
|
||||||
auto v_prop = decal_prop->at<VectorStructProperty>("VAxis_39_C31EB2664EE202CAECFBBB84100B5E35"_s);
|
auto v_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_VAXIS);
|
||||||
v_prop->x = decal.vAxis.x();
|
v_prop->x = decal.vAxis.x();
|
||||||
v_prop->y = decal.vAxis.y();
|
v_prop->y = decal.vAxis.y();
|
||||||
v_prop->z = decal.vAxis.z();
|
v_prop->z = decal.vAxis.z();
|
||||||
auto offset_prop = decal_prop->at<Vector2DStructProperty>("Offset_29_B02BBBB74FC60F5EDBEBAB8020738020"_s);
|
auto offset_prop = decal_prop->at<Vector2DStructProperty>(MASS_DECAL_OFFSET);
|
||||||
offset_prop->x = decal.offset.x();
|
offset_prop->x = decal.offset.x();
|
||||||
offset_prop->y = decal.offset.y();
|
offset_prop->y = decal.offset.y();
|
||||||
decal_prop->at<FloatProperty>("Scale_32_959D1C2747AFD8D62808468235CBBA40"_s)->value = decal.scale;
|
decal_prop->at<FloatProperty>(MASS_DECAL_SCALE)->value = decal.scale;
|
||||||
decal_prop->at<FloatProperty>("Rotation_27_12D7C314493D203D5C2326A03C5F910F"_s)->value = decal.rotation;
|
decal_prop->at<FloatProperty>(MASS_DECAL_ROTATION)->value = decal.rotation;
|
||||||
decal_prop->at<BoolProperty>("Flip_35_CECCFB184CCD9412BD93FE9A8B656BE1"_s)->value = decal.flip;
|
decal_prop->at<BoolProperty>(MASS_DECAL_FLIP)->value = decal.flip;
|
||||||
decal_prop->at<BoolProperty>("Wrap_43_A7C68CDF4A92AF2ECDA53F953EE7CA62"_s)->value = decal.wrap;
|
decal_prop->at<BoolProperty>(MASS_DECAL_WRAP)->value = decal.wrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array) {
|
void Mass::getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array) {
|
||||||
for(UnsignedInt i = 0; i < accessory_array->items.size(); i++) {
|
for(UnsignedInt i = 0; i < accessory_array->items.size(); i++) {
|
||||||
auto acc_prop = accessory_array->at<GenericStructProperty>(i);
|
auto acc_prop = accessory_array->at<GenericStructProperty>(i);
|
||||||
|
CORRADE_INTERNAL_ASSERT(acc_prop);
|
||||||
auto& accessory = accessories[i];
|
auto& accessory = accessories[i];
|
||||||
|
|
||||||
accessory.attachIndex = acc_prop->at<IntProperty>("AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20"_s)->value;
|
accessory.attachIndex = acc_prop->at<IntProperty>(MASS_ACCESSORY_ATTACH_INDEX)->value;
|
||||||
accessory.id = acc_prop->at<IntProperty>("ID_4_5757B32647BAE263266259B8A7DFFFC1"_s)->value;
|
accessory.id = acc_prop->at<IntProperty>(MASS_ACCESSORY_ID)->value;
|
||||||
auto acc_styles = acc_prop->at<ArrayProperty>("Styles_7_91DEB0F24E24D13FC9472882C11D0DFD"_s);
|
auto acc_styles = acc_prop->at<ArrayProperty>(MASS_ACCESSORY_STYLES);
|
||||||
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
|
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
|
||||||
accessory.styles[j] = acc_styles->at<IntProperty>(j)->value;
|
accessory.styles[j] = acc_styles->at<IntProperty>(j)->value;
|
||||||
}
|
}
|
||||||
auto rel_pos_prop = acc_prop->at<VectorStructProperty>("RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1"_s);
|
auto rel_pos_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_RELPOS);
|
||||||
accessory.relativePosition = Vector3{rel_pos_prop->x, rel_pos_prop->y, rel_pos_prop->z};
|
accessory.relativePosition = Vector3{rel_pos_prop->x, rel_pos_prop->y, rel_pos_prop->z};
|
||||||
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>("RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6"_s);
|
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_OFFPOS);
|
||||||
accessory.relativePositionOffset = Vector3{rel_pos_offset_prop->x, rel_pos_offset_prop->y, rel_pos_offset_prop->z};
|
accessory.relativePositionOffset = Vector3{rel_pos_offset_prop->x, rel_pos_offset_prop->y, rel_pos_offset_prop->z};
|
||||||
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>("RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0"_s);
|
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>(MASS_ACCESSORY_RELROT);
|
||||||
accessory.relativeRotation = Vector3{rel_rot_prop->x, rel_rot_prop->y, rel_rot_prop->z};
|
accessory.relativeRotation = Vector3{rel_rot_prop->x, rel_rot_prop->y, rel_rot_prop->z};
|
||||||
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>("RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA"_s);
|
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>(MASS_ACCESSORY_OFFROT);
|
||||||
accessory.relativeRotationOffset = Vector3{rel_rot_offset_prop->x, rel_rot_offset_prop->y, rel_rot_offset_prop->z};
|
accessory.relativeRotationOffset = Vector3{rel_rot_offset_prop->x, rel_rot_offset_prop->y, rel_rot_offset_prop->z};
|
||||||
auto local_scale_prop = acc_prop->at<VectorStructProperty>("LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53"_s);
|
auto local_scale_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_SCALE);
|
||||||
accessory.localScale = Vector3{local_scale_prop->x, local_scale_prop->y, local_scale_prop->z};
|
accessory.localScale = Vector3{local_scale_prop->x, local_scale_prop->y, local_scale_prop->z};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,31 +115,32 @@ void Mass::getAccessories(Containers::ArrayView<Accessory> accessories, ArrayPro
|
||||||
void Mass::writeAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accs_array) {
|
void Mass::writeAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accs_array) {
|
||||||
for(UnsignedInt i = 0; i < accs_array->items.size(); i++) {
|
for(UnsignedInt i = 0; i < accs_array->items.size(); i++) {
|
||||||
auto acc_prop = accs_array->at<GenericStructProperty>(i);
|
auto acc_prop = accs_array->at<GenericStructProperty>(i);
|
||||||
|
CORRADE_INTERNAL_ASSERT(acc_prop);
|
||||||
auto& accessory = accessories[i];
|
auto& accessory = accessories[i];
|
||||||
|
|
||||||
acc_prop->at<IntProperty>("AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20"_s)->value = accessory.attachIndex;
|
acc_prop->at<IntProperty>(MASS_ACCESSORY_ATTACH_INDEX)->value = accessory.attachIndex;
|
||||||
acc_prop->at<IntProperty>("ID_4_5757B32647BAE263266259B8A7DFFFC1"_s)->value = accessory.id;
|
acc_prop->at<IntProperty>(MASS_ACCESSORY_ID)->value = accessory.id;
|
||||||
auto acc_styles = acc_prop->at<ArrayProperty>("Styles_7_91DEB0F24E24D13FC9472882C11D0DFD"_s);
|
auto acc_styles = acc_prop->at<ArrayProperty>(MASS_ACCESSORY_STYLES);
|
||||||
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
|
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
|
||||||
acc_styles->at<IntProperty>(j)->value = accessory.styles[j];
|
acc_styles->at<IntProperty>(j)->value = accessory.styles[j];
|
||||||
}
|
}
|
||||||
auto rel_pos_prop = acc_prop->at<VectorStructProperty>("RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1"_s);
|
auto rel_pos_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_RELPOS);
|
||||||
rel_pos_prop->x = accessory.relativePosition.x();
|
rel_pos_prop->x = accessory.relativePosition.x();
|
||||||
rel_pos_prop->y = accessory.relativePosition.y();
|
rel_pos_prop->y = accessory.relativePosition.y();
|
||||||
rel_pos_prop->z = accessory.relativePosition.z();
|
rel_pos_prop->z = accessory.relativePosition.z();
|
||||||
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>("RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6"_s);
|
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_OFFPOS);
|
||||||
rel_pos_offset_prop->x = accessory.relativePositionOffset.x();
|
rel_pos_offset_prop->x = accessory.relativePositionOffset.x();
|
||||||
rel_pos_offset_prop->y = accessory.relativePositionOffset.y();
|
rel_pos_offset_prop->y = accessory.relativePositionOffset.y();
|
||||||
rel_pos_offset_prop->z = accessory.relativePositionOffset.z();
|
rel_pos_offset_prop->z = accessory.relativePositionOffset.z();
|
||||||
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>("RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0"_s);
|
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>(MASS_ACCESSORY_RELROT);
|
||||||
rel_rot_prop->x = accessory.relativeRotation.x();
|
rel_rot_prop->x = accessory.relativeRotation.x();
|
||||||
rel_rot_prop->y = accessory.relativeRotation.y();
|
rel_rot_prop->y = accessory.relativeRotation.y();
|
||||||
rel_rot_prop->z = accessory.relativeRotation.z();
|
rel_rot_prop->z = accessory.relativeRotation.z();
|
||||||
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>("RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA"_s);
|
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>(MASS_ACCESSORY_OFFROT);
|
||||||
rel_rot_offset_prop->x = accessory.relativeRotationOffset.x();
|
rel_rot_offset_prop->x = accessory.relativeRotationOffset.x();
|
||||||
rel_rot_offset_prop->y = accessory.relativeRotationOffset.y();
|
rel_rot_offset_prop->y = accessory.relativeRotationOffset.y();
|
||||||
rel_rot_offset_prop->z = accessory.relativeRotationOffset.z();
|
rel_rot_offset_prop->z = accessory.relativeRotationOffset.z();
|
||||||
auto local_scale_prop = acc_prop->at<VectorStructProperty>("LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53"_s);
|
auto local_scale_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_SCALE);
|
||||||
local_scale_prop->x = accessory.localScale.x();
|
local_scale_prop->x = accessory.localScale.x();
|
||||||
local_scale_prop->y = accessory.localScale.y();
|
local_scale_prop->y = accessory.localScale.y();
|
||||||
local_scale_prop->z = accessory.localScale.z();
|
local_scale_prop->z = accessory.localScale.z();
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||||
#include "../UESaveFile/Types/ColourStructProperty.h"
|
#include "../UESaveFile/Types/ColourStructProperty.h"
|
||||||
#include "../UESaveFile/Types/FloatProperty.h"
|
#include "../UESaveFile/Types/FloatProperty.h"
|
||||||
|
@ -29,130 +31,137 @@ auto Mass::jointSliders() -> Joints& {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getJointSliders() {
|
void Mass::getJointSliders() {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Getting joint sliders.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame_prop = unit_data->at<GenericStructProperty>("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"_s);
|
auto frame_prop = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||||
if(!frame_prop) {
|
if(!frame_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_FRAME, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto length = frame_prop->at<FloatProperty>("NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"_s);
|
auto length = frame_prop->at<FloatProperty>(MASS_JOINT_NECK);
|
||||||
_frame.joints.neck = (length ? length->value : 0.0f);
|
_frame.joints.neck = (length ? length->value : 0.0f);
|
||||||
length = frame_prop->at<FloatProperty>("BodyLength_7_C16287754CBA96C93BAE36A5C154996A"_s);
|
length = frame_prop->at<FloatProperty>(MASS_JOINT_BODY);
|
||||||
_frame.joints.body = (length ? length->value : 0.0f);
|
_frame.joints.body = (length ? length->value : 0.0f);
|
||||||
length = frame_prop->at<FloatProperty>("ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"_s);
|
length = frame_prop->at<FloatProperty>(MASS_JOINT_SHOULDER);
|
||||||
_frame.joints.shoulders = (length ? length->value : 0.0f);
|
_frame.joints.shoulders = (length ? length->value : 0.0f);
|
||||||
length = frame_prop->at<FloatProperty>("HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"_s);
|
length = frame_prop->at<FloatProperty>(MASS_JOINT_HIP);
|
||||||
_frame.joints.hips = (length ? length->value : 0.0f);
|
_frame.joints.hips = (length ? length->value : 0.0f);
|
||||||
length = frame_prop->at<FloatProperty>("ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"_s);
|
length = frame_prop->at<FloatProperty>(MASS_JOINT_ARM_UPPER);
|
||||||
_frame.joints.upperArms = (length ? length->value : 0.0f);
|
_frame.joints.upperArms = (length ? length->value : 0.0f);
|
||||||
length = frame_prop->at<FloatProperty>("ArmLowerLength_12_ACD0F02745C28882619376926292FB36"_s);
|
length = frame_prop->at<FloatProperty>(MASS_JOINT_ARM_LOWER);
|
||||||
_frame.joints.lowerArms = (length ? length->value : 0.0f);
|
_frame.joints.lowerArms = (length ? length->value : 0.0f);
|
||||||
length = frame_prop->at<FloatProperty>("LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"_s);
|
length = frame_prop->at<FloatProperty>(MASS_JOINT_LEG_UPPER);
|
||||||
_frame.joints.upperLegs = (length ? length->value : 0.0f);
|
_frame.joints.upperLegs = (length ? length->value : 0.0f);
|
||||||
length = frame_prop->at<FloatProperty>("LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"_s);
|
length = frame_prop->at<FloatProperty>(MASS_JOINT_LEG_LOWER);
|
||||||
_frame.joints.lowerLegs = (length ? length->value : 0.0f);
|
_frame.joints.lowerLegs = (length ? length->value : 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeJointSliders() -> bool {
|
auto Mass::writeJointSliders() -> bool {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Writing joint sliders");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No unit data in "_s + _filename;
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame_prop = unit_data->at<GenericStructProperty>("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"_s);
|
auto frame_prop = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||||
|
|
||||||
if(!frame_prop) {
|
if(!frame_prop) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No frame data in "_s + _filename;
|
_lastError = "No frame data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Containers::Array<UnrealPropertyBase::ptr> temp;
|
Containers::Array<UnrealPropertyBase::ptr> temp;
|
||||||
|
|
||||||
auto length = frame_prop->atMove<FloatProperty>("NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"_s);
|
auto length = frame_prop->atMove<FloatProperty>(MASS_JOINT_NECK);
|
||||||
if(_frame.joints.neck != 0.0f) {
|
if(_frame.joints.neck != 0.0f) {
|
||||||
if(!length) {
|
if(!length) {
|
||||||
length.emplace();
|
length.emplace();
|
||||||
length->name.emplace("NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"_s);
|
length->name.emplace(MASS_JOINT_NECK);
|
||||||
}
|
}
|
||||||
length->value = _frame.joints.neck;
|
length->value = _frame.joints.neck;
|
||||||
arrayAppend(temp, std::move(length));
|
arrayAppend(temp, std::move(length));
|
||||||
}
|
}
|
||||||
|
|
||||||
length = frame_prop->atMove<FloatProperty>("BodyLength_7_C16287754CBA96C93BAE36A5C154996A"_s);
|
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_BODY);
|
||||||
if(_frame.joints.body != 0.0f) {
|
if(_frame.joints.body != 0.0f) {
|
||||||
if(!length) {
|
if(!length) {
|
||||||
length.emplace();
|
length.emplace();
|
||||||
length->name.emplace("BodyLength_7_C16287754CBA96C93BAE36A5C154996A"_s);
|
length->name.emplace(MASS_JOINT_BODY);
|
||||||
}
|
}
|
||||||
length->value = _frame.joints.body;
|
length->value = _frame.joints.body;
|
||||||
arrayAppend(temp, std::move(length));
|
arrayAppend(temp, std::move(length));
|
||||||
}
|
}
|
||||||
|
|
||||||
length = frame_prop->atMove<FloatProperty>("ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"_s);
|
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_SHOULDER);
|
||||||
if(_frame.joints.shoulders != 0.0f) {
|
if(_frame.joints.shoulders != 0.0f) {
|
||||||
if(!length) {
|
if(!length) {
|
||||||
length.emplace();
|
length.emplace();
|
||||||
length->name.emplace("ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"_s);
|
length->name.emplace(MASS_JOINT_SHOULDER);
|
||||||
}
|
}
|
||||||
length->value = _frame.joints.shoulders;
|
length->value = _frame.joints.shoulders;
|
||||||
arrayAppend(temp, std::move(length));
|
arrayAppend(temp, std::move(length));
|
||||||
}
|
}
|
||||||
|
|
||||||
length = frame_prop->atMove<FloatProperty>("ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"_s);
|
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_ARM_UPPER);
|
||||||
if(_frame.joints.upperArms != 0.0f) {
|
if(_frame.joints.upperArms != 0.0f) {
|
||||||
if(!length) {
|
if(!length) {
|
||||||
length.emplace();
|
length.emplace();
|
||||||
length->name.emplace("ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"_s);
|
length->name.emplace(MASS_JOINT_ARM_UPPER);
|
||||||
}
|
}
|
||||||
length->value = _frame.joints.upperArms;
|
length->value = _frame.joints.upperArms;
|
||||||
arrayAppend(temp, std::move(length));
|
arrayAppend(temp, std::move(length));
|
||||||
}
|
}
|
||||||
|
|
||||||
length = frame_prop->atMove<FloatProperty>("ArmLowerLength_12_ACD0F02745C28882619376926292FB36"_s);
|
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_ARM_LOWER);
|
||||||
if(_frame.joints.lowerArms != 0.0f) {
|
if(_frame.joints.lowerArms != 0.0f) {
|
||||||
if(!length) {
|
if(!length) {
|
||||||
length.emplace();
|
length.emplace();
|
||||||
length->name.emplace("ArmLowerLength_12_ACD0F02745C28882619376926292FB36"_s);
|
length->name.emplace(MASS_JOINT_ARM_LOWER);
|
||||||
}
|
}
|
||||||
length->value = _frame.joints.lowerArms;
|
length->value = _frame.joints.lowerArms;
|
||||||
arrayAppend(temp, std::move(length));
|
arrayAppend(temp, std::move(length));
|
||||||
}
|
}
|
||||||
|
|
||||||
length = frame_prop->atMove<FloatProperty>("HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"_s);
|
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_HIP);
|
||||||
if(_frame.joints.hips != 0.0f) {
|
if(_frame.joints.hips != 0.0f) {
|
||||||
if(!length) {
|
if(!length) {
|
||||||
length.emplace();
|
length.emplace();
|
||||||
length->name.emplace("HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"_s);
|
length->name.emplace(MASS_JOINT_HIP);
|
||||||
}
|
}
|
||||||
length->value = _frame.joints.hips;
|
length->value = _frame.joints.hips;
|
||||||
arrayAppend(temp, std::move(length));
|
arrayAppend(temp, std::move(length));
|
||||||
}
|
}
|
||||||
|
|
||||||
length = frame_prop->atMove<FloatProperty>("LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"_s);
|
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_LEG_UPPER);
|
||||||
if(_frame.joints.upperLegs != 0.0f) {
|
if(_frame.joints.upperLegs != 0.0f) {
|
||||||
if(!length) {
|
if(!length) {
|
||||||
length.emplace();
|
length.emplace();
|
||||||
length->name.emplace("LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"_s);
|
length->name.emplace(MASS_JOINT_LEG_UPPER);
|
||||||
}
|
}
|
||||||
length->value = _frame.joints.upperLegs;
|
length->value = _frame.joints.upperLegs;
|
||||||
arrayAppend(temp, std::move(length));
|
arrayAppend(temp, std::move(length));
|
||||||
}
|
}
|
||||||
|
|
||||||
length = frame_prop->atMove<FloatProperty>("LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"_s);
|
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_LEG_LOWER);
|
||||||
if(_frame.joints.lowerLegs != 0.0f) {
|
if(_frame.joints.lowerLegs != 0.0f) {
|
||||||
if(!length) {
|
if(!length) {
|
||||||
length.emplace();
|
length.emplace();
|
||||||
length->name.emplace("LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"_s);
|
length->name.emplace(MASS_JOINT_LEG_LOWER);
|
||||||
}
|
}
|
||||||
length->value = _frame.joints.lowerLegs;
|
length->value = _frame.joints.lowerLegs;
|
||||||
arrayAppend(temp, std::move(length));
|
arrayAppend(temp, std::move(length));
|
||||||
|
@ -177,25 +186,32 @@ auto Mass::frameStyles() -> Containers::ArrayView<Int> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getFrameStyles() {
|
void Mass::getFrameStyles() {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Getting frame styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame_prop = unit_data->at<GenericStructProperty>("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"_s);
|
auto frame_prop = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||||
if(!frame_prop) {
|
if(!frame_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_FRAME, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame_styles = frame_prop->at<ArrayProperty>("Styles_32_00A3B3284B37F1E7819458844A20EB48"_s);
|
auto frame_styles = frame_prop->at<ArrayProperty>(MASS_FRAME_STYLES);
|
||||||
if(!frame_styles) {
|
if(!frame_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_FRAME_STYLES, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(frame_styles->items.size() != _frame.styles.size()) {
|
if(frame_styles->items.size() != _frame.styles.size()) {
|
||||||
|
LOG_ERROR_FORMAT("Frame style arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
_frame.styles.size(), frame_styles->items.size());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -206,24 +222,29 @@ void Mass::getFrameStyles() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeFrameStyles() -> bool {
|
auto Mass::writeFrameStyles() -> bool {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Writing frame styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No unit data in "_s + _filename;
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame = unit_data->at<GenericStructProperty>("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"_s);
|
auto frame = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||||
if(!frame) {
|
if(!frame) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No frame data in "_s + _filename;
|
_lastError = "No frame data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame_styles = frame->at<ArrayProperty>("Styles_32_00A3B3284B37F1E7819458844A20EB48"_s);
|
auto frame_styles = frame->at<ArrayProperty>(MASS_FRAME_STYLES);
|
||||||
if(!frame_styles) {
|
if(!frame_styles) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No frame styles in "_s + _filename;
|
_lastError = "No frame styles in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,20 +265,25 @@ auto Mass::eyeFlareColour() -> Color4& {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getEyeFlareColour() {
|
void Mass::getEyeFlareColour() {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Getting the eye flare colour.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame_prop = unit_data->at<GenericStructProperty>("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"_s);
|
auto frame_prop = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||||
if(!frame_prop) {
|
if(!frame_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_FRAME, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eye_flare_prop = frame_prop->at<ColourStructProperty>("EyeFlareColor_36_AF79999C40FCA0E88A2F9A84488A38CA"_s);
|
auto eye_flare_prop = frame_prop->at<ColourStructProperty>(MASS_EYE_FLARE);
|
||||||
if(!eye_flare_prop) {
|
if(!eye_flare_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_EYE_FLARE, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -266,24 +292,29 @@ void Mass::getEyeFlareColour() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeEyeFlareColour() -> bool {
|
auto Mass::writeEyeFlareColour() -> bool {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Writing the eye flare colour.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No unit data in "_s + _filename;
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame = unit_data->at<GenericStructProperty>("Frame_3_F92B0F6A44A15088AF7F41B9FF290653"_s);
|
auto frame = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||||
if(!frame) {
|
if(!frame) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No frame data in "_s + _filename;
|
_lastError = "No frame data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto eye_flare_prop = frame->at<ColourStructProperty>("EyeFlareColor_36_AF79999C40FCA0E88A2F9A84488A38CA"_s);
|
auto eye_flare_prop = frame->at<ColourStructProperty>(MASS_EYE_FLARE);
|
||||||
if(!eye_flare_prop) {
|
if(!eye_flare_prop) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No eye flare property in "_s + _filename;
|
_lastError = "No eye flare property in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,19 +336,25 @@ auto Mass::frameCustomStyles() -> Containers::ArrayView<CustomStyle> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getFrameCustomStyles() {
|
void Mass::getFrameCustomStyles() {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Getting the frame's custom styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame_styles = unit_data->at<ArrayProperty>("FrameStyle_44_04A44C9440363CCEC5443D98BFAF22AA"_s);
|
auto frame_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_FRAME_STYLES);
|
||||||
if(!frame_styles) {
|
if(!frame_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_CUSTOM_FRAME_STYLES, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(frame_styles->items.size() != _frame.customStyles.size()) {
|
if(frame_styles->items.size() != _frame.customStyles.size()) {
|
||||||
|
LOG_ERROR_FORMAT("Frame custom style arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
_frame.customStyles.size(), frame_styles->items.size());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -326,22 +363,27 @@ void Mass::getFrameCustomStyles() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeFrameCustomStyle(UnsignedLong index) -> bool {
|
auto Mass::writeFrameCustomStyle(UnsignedLong index) -> bool {
|
||||||
|
LOG_INFO_FORMAT("Writing frame custom style number {}.", index);
|
||||||
|
|
||||||
if(index > _frame.customStyles.size()) {
|
if(index > _frame.customStyles.size()) {
|
||||||
_lastError = "Style index out of range."_s;
|
_lastError = "Style index out of range."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No unit data in "_s + _filename;
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frame_styles = unit_data->at<ArrayProperty>("FrameStyle_44_04A44C9440363CCEC5443D98BFAF22AA"_s);
|
auto frame_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_FRAME_STYLES);
|
||||||
if(!frame_styles) {
|
if(!frame_styles) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No frame styles in "_s + _filename;
|
_lastError = "No frame styles in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||||
#include "../UESaveFile/Types/ColourStructProperty.h"
|
#include "../UESaveFile/Types/ColourStructProperty.h"
|
||||||
#include "../UESaveFile/Types/FloatProperty.h"
|
#include "../UESaveFile/Types/FloatProperty.h"
|
||||||
|
@ -30,14 +32,18 @@ auto Mass::globalStyles() -> Containers::ArrayView<CustomStyle> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getGlobalStyles() {
|
void Mass::getGlobalStyles() {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
LOG_INFO("Getting global styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto global_styles = unit_data->at<ArrayProperty>("GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B"_s);
|
auto global_styles = unit_data->at<ArrayProperty>(MASS_GLOBAL_STYLES);
|
||||||
if(!global_styles) {
|
if(!global_styles) {
|
||||||
|
LOG_WARNING_FORMAT("Couldn't find global styles in {}.", _filename);
|
||||||
_globalStyles = Containers::Array<CustomStyle>{0};
|
_globalStyles = Containers::Array<CustomStyle>{0};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -50,22 +56,27 @@ void Mass::getGlobalStyles() {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeGlobalStyle(UnsignedLong index) -> bool {
|
auto Mass::writeGlobalStyle(UnsignedLong index) -> bool {
|
||||||
|
LOG_INFO_FORMAT("Writing global style number {}.", index);
|
||||||
|
|
||||||
if(index > _globalStyles.size()) {
|
if(index > _globalStyles.size()) {
|
||||||
_lastError = "Global style index out of range"_s;
|
_lastError = "Global style index out of range"_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No unit data found in "_s + _filename;
|
_lastError = "No unit data found in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto global_styles = unit_data->at<ArrayProperty>("GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B"_s);
|
auto global_styles = unit_data->at<ArrayProperty>(MASS_GLOBAL_STYLES);
|
||||||
if(!global_styles) {
|
if(!global_styles) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No global styles found in "_s + _filename;
|
_lastError = "No global styles found in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,52 +88,53 @@ void Mass::getCustomStyles(Containers::ArrayView<CustomStyle> styles, ArrayPrope
|
||||||
auto style_prop = style_array->at<GenericStructProperty>(i);
|
auto style_prop = style_array->at<GenericStructProperty>(i);
|
||||||
auto& style = styles[i];
|
auto& style = styles[i];
|
||||||
|
|
||||||
style.name = style_prop->at<StringProperty>("Name_27_1532115A46EF2B2FA283908DF561A86B"_s)->value;
|
style.name = style_prop->at<StringProperty>(MASS_STYLE_NAME)->value;
|
||||||
auto colour_prop = style_prop->at<ColourStructProperty>("Color_5_F0D383DF40474C9464AE48A0984A212E"_s);
|
auto colour_prop = style_prop->at<ColourStructProperty>(MASS_STYLE_COLOUR);
|
||||||
style.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a};
|
style.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a};
|
||||||
style.metallic = style_prop->at<FloatProperty>("Metallic_10_0A4CD1E4482CBF41CA61D0A856DE90B9"_s)->value;
|
style.metallic = style_prop->at<FloatProperty>(MASS_STYLE_METALLIC)->value;
|
||||||
style.gloss = style_prop->at<FloatProperty>("Gloss_11_9769599842CC275A401C4282A236E240"_s)->value;
|
style.gloss = style_prop->at<FloatProperty>(MASS_STYLE_GLOSS)->value;
|
||||||
style.glow = colour_prop->a == 0.0f ? false : true;
|
style.glow = colour_prop->a != 0.0f;
|
||||||
|
|
||||||
style.patternId = style_prop->at<IntProperty>("PatternID_14_516DB85641DAF8ECFD2920BE2BDF1311"_s)->value;
|
style.patternId = style_prop->at<IntProperty>(MASS_STYLE_PATTERN_ID)->value;
|
||||||
style.opacity = style_prop->at<FloatProperty>("Opacity_30_53BD060B4DFCA1C92302D6A0F7831131"_s)->value;
|
style.opacity = style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OPACITY)->value;
|
||||||
style.offset = Vector2{
|
style.offset = Vector2{
|
||||||
style_prop->at<FloatProperty>("OffsetX_23_70FC2E814C64BBB82452748D2AF9CD48"_s)->value,
|
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OFFSETX)->value,
|
||||||
style_prop->at<FloatProperty>("OffsetY_24_5E1F866C4C054D9B2EE337ADC180C17F"_s)->value
|
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OFFSETY)->value
|
||||||
};
|
};
|
||||||
style.rotation = style_prop->at<FloatProperty>("Rotation_25_EC2DFAD84AD0A6BD3FA841ACD52EDD6D"_s)->value;
|
style.rotation = style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_ROTATION)->value;
|
||||||
style.scale = style_prop->at<FloatProperty>("Scale_26_19DF0708409262183E1247B317137671"_s)->value;
|
style.scale = style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_SCALE)->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool {
|
auto Mass::writeCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool {
|
||||||
if(!style_array) {
|
if(!style_array) {
|
||||||
_lastError = "Mass::setCustomStyle(): style_array is null."_s;
|
_lastError = "style_array is null."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto style_prop = style_array->at<GenericStructProperty>(index);
|
auto style_prop = style_array->at<GenericStructProperty>(index);
|
||||||
|
|
||||||
if(!style_prop) {
|
if(!style_prop) {
|
||||||
_lastError = "Style index is out of range in "_s + _filename;
|
_lastError = "Style index is out of range in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
style_prop->at<StringProperty>("Name_27_1532115A46EF2B2FA283908DF561A86B"_s)->value = style.name;
|
style_prop->at<StringProperty>(MASS_STYLE_NAME)->value = style.name;
|
||||||
auto colour_prop = style_prop->at<ColourStructProperty>("Color_5_F0D383DF40474C9464AE48A0984A212E"_s);
|
auto colour_prop = style_prop->at<ColourStructProperty>(MASS_STYLE_COLOUR);
|
||||||
colour_prop->r = style.colour.r();
|
colour_prop->r = style.colour.r();
|
||||||
colour_prop->g = style.colour.g();
|
colour_prop->g = style.colour.g();
|
||||||
colour_prop->b = style.colour.b();
|
colour_prop->b = style.colour.b();
|
||||||
colour_prop->a = style.glow ? 1.0f : 0.0f;
|
colour_prop->a = style.glow ? 1.0f : 0.0f;
|
||||||
style_prop->at<FloatProperty>("Metallic_10_0A4CD1E4482CBF41CA61D0A856DE90B9"_s)->value = style.metallic;
|
style_prop->at<FloatProperty>(MASS_STYLE_METALLIC)->value = style.metallic;
|
||||||
style_prop->at<FloatProperty>("Gloss_11_9769599842CC275A401C4282A236E240"_s)->value = style.gloss;
|
style_prop->at<FloatProperty>(MASS_STYLE_GLOSS)->value = style.gloss;
|
||||||
|
|
||||||
style_prop->at<IntProperty>("PatternID_14_516DB85641DAF8ECFD2920BE2BDF1311"_s)->value = style.patternId;
|
style_prop->at<IntProperty>(MASS_STYLE_PATTERN_ID)->value = style.patternId;
|
||||||
style_prop->at<FloatProperty>("Opacity_30_53BD060B4DFCA1C92302D6A0F7831131"_s)->value = style.opacity;
|
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OPACITY)->value = style.opacity;
|
||||||
style_prop->at<FloatProperty>("OffsetX_23_70FC2E814C64BBB82452748D2AF9CD48"_s)->value = style.offset.x();
|
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OFFSETX)->value = style.offset.x();
|
||||||
style_prop->at<FloatProperty>("OffsetY_24_5E1F866C4C054D9B2EE337ADC180C17F"_s)->value = style.offset.y();
|
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OFFSETY)->value = style.offset.y();
|
||||||
style_prop->at<FloatProperty>("Rotation_25_EC2DFAD84AD0A6BD3FA841ACD52EDD6D"_s)->value = style.rotation;
|
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_ROTATION)->value = style.rotation;
|
||||||
style_prop->at<FloatProperty>("Scale_26_19DF0708409262183E1247B317137671"_s)->value = style.scale;
|
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_SCALE)->value = style.scale;
|
||||||
|
|
||||||
if(!_mass->saveToFile()) {
|
if(!_mass->saveToFile()) {
|
||||||
_lastError = _mass->lastError();
|
_lastError = _mass->lastError();
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||||
#include "../UESaveFile/Types/BoolProperty.h"
|
#include "../UESaveFile/Types/BoolProperty.h"
|
||||||
#include "../UESaveFile/Types/ByteProperty.h"
|
#include "../UESaveFile/Types/ByteProperty.h"
|
||||||
|
@ -31,11 +33,13 @@ auto Mass::meleeWeapons() -> Containers::ArrayView<Weapon> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getMeleeWeapons() {
|
void Mass::getMeleeWeapons() {
|
||||||
getWeaponType("WeaponCC_22_0BBEC58C4A0EA1DB9E037B9339EE26A7"_s, _weapons.melee);
|
LOG_INFO("Getting melee weapons.");
|
||||||
|
getWeaponType(MASS_WEAPONS_MELEE, _weapons.melee);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeMeleeWeapons() -> bool {
|
auto Mass::writeMeleeWeapons() -> bool {
|
||||||
return writeWeaponType("WeaponCC_22_0BBEC58C4A0EA1DB9E037B9339EE26A7"_s, _weapons.melee);
|
LOG_INFO("Writing melee weapons.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_MELEE, _weapons.melee);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::shields() -> Containers::ArrayView<Weapon> {
|
auto Mass::shields() -> Containers::ArrayView<Weapon> {
|
||||||
|
@ -43,11 +47,13 @@ auto Mass::shields() -> Containers::ArrayView<Weapon> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getShields() {
|
void Mass::getShields() {
|
||||||
getWeaponType("Shield_53_839BFD7945481BAEA3E43A9C5CA8E92E"_s, _weapons.shields);
|
LOG_INFO("Getting shields.");
|
||||||
|
getWeaponType(MASS_WEAPONS_SHIELD, _weapons.shields);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeShields() -> bool {
|
auto Mass::writeShields() -> bool {
|
||||||
return writeWeaponType("Shield_53_839BFD7945481BAEA3E43A9C5CA8E92E"_s, _weapons.shields);
|
LOG_INFO("Writing shields.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_SHIELD, _weapons.shields);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::bulletShooters() -> Containers::ArrayView<Weapon> {
|
auto Mass::bulletShooters() -> Containers::ArrayView<Weapon> {
|
||||||
|
@ -55,11 +61,13 @@ auto Mass::bulletShooters() -> Containers::ArrayView<Weapon> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getBulletShooters() {
|
void Mass::getBulletShooters() {
|
||||||
getWeaponType("WeaponBS_35_6EF6E0104FD7A138DF47F88CB57A83ED"_s, _weapons.bulletShooters);
|
LOG_INFO("Getting bullet shooters.");
|
||||||
|
getWeaponType(MASS_WEAPONS_BSHOOTER, _weapons.bulletShooters);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeBulletShooters() -> bool {
|
auto Mass::writeBulletShooters() -> bool {
|
||||||
return writeWeaponType("WeaponBS_35_6EF6E0104FD7A138DF47F88CB57A83ED"_s, _weapons.bulletShooters);
|
LOG_INFO("Writing bullet shooters.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_BSHOOTER, _weapons.bulletShooters);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::energyShooters() -> Containers::ArrayView<Weapon> {
|
auto Mass::energyShooters() -> Containers::ArrayView<Weapon> {
|
||||||
|
@ -67,11 +75,13 @@ auto Mass::energyShooters() -> Containers::ArrayView<Weapon> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getEnergyShooters() {
|
void Mass::getEnergyShooters() {
|
||||||
getWeaponType("WeaponES_37_1A295D544528623880A0B1AC2C7DEE99"_s, _weapons.energyShooters);
|
LOG_INFO("Getting energy shooters.");
|
||||||
|
getWeaponType(MASS_WEAPONS_ESHOOTER, _weapons.energyShooters);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeEnergyShooters() -> bool {
|
auto Mass::writeEnergyShooters() -> bool {
|
||||||
return writeWeaponType("WeaponES_37_1A295D544528623880A0B1AC2C7DEE99"_s, _weapons.energyShooters);
|
LOG_INFO("Writing energy shooters.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_ESHOOTER, _weapons.energyShooters);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::bulletLaunchers() -> Containers::ArrayView<Weapon> {
|
auto Mass::bulletLaunchers() -> Containers::ArrayView<Weapon> {
|
||||||
|
@ -79,11 +89,13 @@ auto Mass::bulletLaunchers() -> Containers::ArrayView<Weapon> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getBulletLaunchers() {
|
void Mass::getBulletLaunchers() {
|
||||||
getWeaponType("WeaponBL_36_5FD7C41E4613A75B44AB0E90B362846E"_s, _weapons.bulletLaunchers);
|
LOG_INFO("Getting bullet launchers.");
|
||||||
|
getWeaponType(MASS_WEAPONS_BLAUNCHER, _weapons.bulletLaunchers);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeBulletLaunchers() -> bool {
|
auto Mass::writeBulletLaunchers() -> bool {
|
||||||
return writeWeaponType("WeaponBL_36_5FD7C41E4613A75B44AB0E90B362846E"_s, _weapons.bulletLaunchers);
|
LOG_INFO("Writing bullet launchers.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_BLAUNCHER, _weapons.bulletLaunchers);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::energyLaunchers() -> Containers::ArrayView<Weapon> {
|
auto Mass::energyLaunchers() -> Containers::ArrayView<Weapon> {
|
||||||
|
@ -91,27 +103,33 @@ auto Mass::energyLaunchers() -> Containers::ArrayView<Weapon> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getEnergyLaunchers() {
|
void Mass::getEnergyLaunchers() {
|
||||||
getWeaponType("WeaponEL_38_9D23F3884ACA15902C9E6CA6E4995995"_s, _weapons.energyLaunchers);
|
LOG_INFO("Getting energy launchers.");
|
||||||
|
getWeaponType(MASS_WEAPONS_ELAUNCHER, _weapons.energyLaunchers);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeEnergyLaunchers() -> bool {
|
auto Mass::writeEnergyLaunchers() -> bool {
|
||||||
return writeWeaponType("WeaponEL_38_9D23F3884ACA15902C9E6CA6E4995995"_s, _weapons.energyLaunchers);
|
LOG_INFO("Writing energy launchers.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_ELAUNCHER, _weapons.energyLaunchers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) {
|
void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
||||||
if(!prop) {
|
if(!prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", prop_name, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(prop->items.size() != weapon_array.size()) {
|
if(prop->items.size() != weapon_array.size()) {
|
||||||
|
LOG_ERROR_FORMAT("Weapon arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
weapon_array.size(), prop->items.size());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -120,38 +138,39 @@ void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView
|
||||||
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
||||||
auto& weapon = weapon_array[i];
|
auto& weapon = weapon_array[i];
|
||||||
|
|
||||||
weapon.name = weapon_prop->at<StringProperty>("Name_13_7BF0D31F4E50C50C47231BB36A485D92"_s)->value;
|
weapon.name = weapon_prop->at<StringProperty>(MASS_WEAPON_NAME)->value;
|
||||||
auto& weapon_type = weapon_prop->at<ByteProperty>("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976"_s)->enumValue;
|
auto& weapon_type = weapon_prop->at<ByteProperty>(MASS_WEAPON_TYPE)->enumValue;
|
||||||
#define c(enumerator, strenum, name) if(weapon_type == (strenum)) { weapon.type = WeaponType::enumerator; } else
|
#define c(enumerator, strenum, name) if(weapon_type == (strenum)) { weapon.type = WeaponType::enumerator; } else
|
||||||
#include "../Maps/WeaponTypes.hpp"
|
#include "../Maps/WeaponTypes.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
{
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid weapon type {} in {}.", weapon_type, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
Utility::Warning{} << "Invalid weapon type enum value in getWeaponType()."_s;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parts_prop = weapon_prop->at<ArrayProperty>("Element_6_8E4617CC4B2C1F1490435599784EC6E0"_s);
|
auto parts_prop = weapon_prop->at<ArrayProperty>(MASS_WEAPON_ELEMENT);
|
||||||
weapon.parts = Containers::Array<WeaponPart>{ValueInit, parts_prop->items.size()};
|
weapon.parts = Containers::Array<WeaponPart>{ValueInit, parts_prop->items.size()};
|
||||||
|
|
||||||
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
||||||
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
||||||
auto& part = weapon.parts[j];
|
auto& part = weapon.parts[j];
|
||||||
|
|
||||||
part.id = part_prop->at<IntProperty>("ID_2_A74D75434308158E5926178822DD28EE"_s)->value;
|
part.id = part_prop->at<IntProperty>(MASS_WEAPON_PART_ID)->value;
|
||||||
|
|
||||||
auto part_styles = part_prop->at<ArrayProperty>("Styles_17_994C97C34A90667BE5B716BFD0B97588"_s);
|
auto part_styles = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_STYLES);
|
||||||
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
||||||
part.styles[k] = part_styles->at<IntProperty>(k)->value;
|
part.styles[k] = part_styles->at<IntProperty>(k)->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto part_decals = part_prop->at<ArrayProperty>("Decals_13_8B81112B453D7230C0CDE982185E14F1"_s);
|
auto part_decals = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_DECALS);
|
||||||
if(part_decals->items.size() != part.decals.size()) {
|
if(part_decals->items.size() != part.decals.size()) {
|
||||||
part.decals = Containers::Array<Decal>{part_decals->items.size()};
|
part.decals = Containers::Array<Decal>{part_decals->items.size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
getDecals(part.decals, part_decals);
|
getDecals(part.decals, part_decals);
|
||||||
|
|
||||||
auto part_accs = part_prop->at<ArrayProperty>("Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C"_s);
|
auto part_accs = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_ACCESSORIES);
|
||||||
if(!part_accs) {
|
if(!part_accs) {
|
||||||
part.accessories = Containers::Array<Accessory>{0};
|
part.accessories = Containers::Array<Accessory>{0};
|
||||||
continue;
|
continue;
|
||||||
|
@ -163,60 +182,69 @@ void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView
|
||||||
getAccessories(part.accessories, part_accs);
|
getAccessories(part.accessories, part_accs);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto custom_styles = weapon_prop->at<ArrayProperty>("Styles_10_8C3C82444B986AD7A99595AD4985912D"_s);
|
auto custom_styles = weapon_prop->at<ArrayProperty>(MASS_CUSTOM_WEAPON_STYLES);
|
||||||
if(!custom_styles) {
|
if(!custom_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Can't find weapon custom styles in {}", _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(custom_styles->items.size() != weapon.customStyles.size()) {
|
if(custom_styles->items.size() != weapon.customStyles.size()) {
|
||||||
|
LOG_ERROR_FORMAT("Custom weapon style arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
weapon.customStyles.size(), custom_styles->items.size());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCustomStyles(weapon.customStyles, custom_styles);
|
getCustomStyles(weapon.customStyles, custom_styles);
|
||||||
|
|
||||||
weapon.attached = weapon_prop->at<BoolProperty>("Attach_15_D00AABBD4AD6A04778D56D81E51927B3"_s)->value;
|
weapon.attached = weapon_prop->at<BoolProperty>(MASS_WEAPON_ATTACH)->value;
|
||||||
auto& damage_type = weapon_prop->at<ByteProperty>("DamageType_18_E1FFA53540591A9087EC698117A65C83"_s)->enumValue;
|
auto& damage_type = weapon_prop->at<ByteProperty>(MASS_WEAPON_DAMAGE_TYPE)->enumValue;
|
||||||
#define c(enumerator, strenum) if(damage_type == (strenum)) { weapon.damageType = DamageType::enumerator; } else
|
#define c(enumerator, strenum) if(damage_type == (strenum)) { weapon.damageType = DamageType::enumerator; } else
|
||||||
#include "../Maps/DamageTypes.hpp"
|
#include "../Maps/DamageTypes.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
{
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid damage type {} in {}.", damage_type, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
Utility::Warning{} << "Invalid damage type enum value in getWeaponType()."_s;
|
return;
|
||||||
}
|
}
|
||||||
weapon.dualWield = weapon_prop->at<BoolProperty>("DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222"_s)->value;
|
weapon.dualWield = weapon_prop->at<BoolProperty>(MASS_WEAPON_DUAL_WIELD)->value;
|
||||||
auto& effect_colour_mode = weapon_prop->at<ByteProperty>("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014"_s)->enumValue;
|
auto& effect_colour_mode = weapon_prop->at<ByteProperty>(MASS_WEAPON_COLOUR_EFX_MODE)->enumValue;
|
||||||
#define c(enumerator, strenum) if(effect_colour_mode == (strenum)) { weapon.effectColourMode = EffectColourMode::enumerator; } else
|
#define c(enumerator, strenum) if(effect_colour_mode == (strenum)) { weapon.effectColourMode = EffectColourMode::enumerator; } else
|
||||||
#include "../Maps/EffectColourModes.hpp"
|
#include "../Maps/EffectColourModes.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
{
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid effect colour mode {} in {}.", effect_colour_mode, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
Utility::Warning{} << "Invalid effect colour mode in getWeaponType()."_s;
|
return;
|
||||||
}
|
}
|
||||||
auto effect_colour = weapon_prop->at<ColourStructProperty>("ColorEfx_26_D921B62946C493E487455A831F4520AC"_s);
|
auto effect_colour = weapon_prop->at<ColourStructProperty>(MASS_WEAPON_COLOUR_EFX);
|
||||||
weapon.effectColour = Color4{effect_colour->r, effect_colour->g, effect_colour->b, effect_colour->a};
|
weapon.effectColour = Color4{effect_colour->r, effect_colour->g, effect_colour->b, effect_colour->a};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool {
|
auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool {
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
if(!unit_data) {
|
if(!unit_data) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No unit data in "_s + _filename;
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
||||||
if(!prop) {
|
if(!prop) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = prop_name + " not found in "_s + _filename;
|
_lastError = prop_name + " not found in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(prop->items.size() != weapon_array.size()) {
|
if(prop->items.size() != weapon_array.size()) {
|
||||||
|
_lastError = Utility::format("Weapon arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
weapon_array.size(), prop->items.size());
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
_lastError = "Weapon type array size mismatch."_s;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,19 +252,23 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
||||||
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
||||||
auto& weapon = weapon_array[i];
|
auto& weapon = weapon_array[i];
|
||||||
|
|
||||||
weapon_prop->at<StringProperty>("Name_13_7BF0D31F4E50C50C47231BB36A485D92"_s)->value = weapon.name;
|
weapon_prop->at<StringProperty>(MASS_WEAPON_NAME)->value = weapon.name;
|
||||||
switch(weapon.type) {
|
switch(weapon.type) {
|
||||||
#define c(enumerator, strenum, name) case WeaponType::enumerator: weapon_prop->at<ByteProperty>("Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976"_s)->enumValue = strenum; break;
|
#define c(enumerator, strenum, name) case WeaponType::enumerator: weapon_prop->at<ByteProperty>(MASS_WEAPON_TYPE)->enumValue = strenum; break;
|
||||||
#include "../Maps/WeaponTypes.hpp"
|
#include "../Maps/WeaponTypes.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
default:
|
default:
|
||||||
Utility::Warning{} << "Invalid weapon type enum value in writeWeaponType()."_s;
|
_lastError = Utility::format("Invalid weapon type at index {}.", i);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto parts_prop = weapon_prop->at<ArrayProperty>("Element_6_8E4617CC4B2C1F1490435599784EC6E0"_s);
|
auto parts_prop = weapon_prop->at<ArrayProperty>(MASS_WEAPON_ELEMENT);
|
||||||
if(parts_prop->items.size() != weapon.parts.size()) {
|
if(parts_prop->items.size() != weapon.parts.size()) {
|
||||||
|
_lastError = Utility::format("Weapon part arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
weapon.parts.size(), parts_prop->items.size());
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
_lastError = "Weapon parts array size mismatch."_s;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,40 +276,45 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
||||||
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
||||||
auto& part = weapon.parts[j];
|
auto& part = weapon.parts[j];
|
||||||
|
|
||||||
part_prop->at<IntProperty>("ID_2_A74D75434308158E5926178822DD28EE"_s)->value = part.id;
|
part_prop->at<IntProperty>(MASS_WEAPON_PART_ID)->value = part.id;
|
||||||
|
|
||||||
auto part_styles = part_prop->at<ArrayProperty>("Styles_17_994C97C34A90667BE5B716BFD0B97588"_s);
|
auto part_styles = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_STYLES);
|
||||||
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
||||||
part_styles->at<IntProperty>(k)->value = part.styles[k];
|
part_styles->at<IntProperty>(k)->value = part.styles[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto part_decals = part_prop->at<ArrayProperty>("Decals_13_8B81112B453D7230C0CDE982185E14F1"_s);
|
auto part_decals = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_DECALS);
|
||||||
writeDecals(part.decals, part_decals);
|
writeDecals(part.decals, part_decals);
|
||||||
|
|
||||||
auto part_accs = part_prop->at<ArrayProperty>("Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C"_s);
|
auto part_accs = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_ACCESSORIES);
|
||||||
if(!part_accs) {
|
if(!part_accs) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(part_accs->items.size() != part.accessories.size()) {
|
if(part_accs->items.size() != part.accessories.size()) {
|
||||||
|
_lastError = Utility::format("Part accessory arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
part.accessories.size(), part_accs->items.size());
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
_lastError = "Accessories array size mismatch."_s;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
writeAccessories(part.accessories, part_accs);
|
writeAccessories(part.accessories, part_accs);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto custom_styles = weapon_prop->at<ArrayProperty>("Styles_10_8C3C82444B986AD7A99595AD4985912D"_s);
|
auto custom_styles = weapon_prop->at<ArrayProperty>(MASS_CUSTOM_WEAPON_STYLES);
|
||||||
if(!custom_styles) {
|
if(!custom_styles) {
|
||||||
_state = State::Invalid;
|
|
||||||
_lastError = "No custom styles found for weapon."_s;
|
_lastError = "No custom styles found for weapon."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(custom_styles->items.size() != weapon.customStyles.size()) {
|
if(custom_styles->items.size() != weapon.customStyles.size()) {
|
||||||
|
_lastError = Utility::format("Custom style arrays are not of the same size. Expected {}, got {} instead.",
|
||||||
|
weapon.customStyles.size(), custom_styles->items.size());
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
_lastError = "Custom styles array size mismatch."_s;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,25 +322,29 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
||||||
writeCustomStyle(weapon.customStyles[j], j, custom_styles);
|
writeCustomStyle(weapon.customStyles[j], j, custom_styles);
|
||||||
}
|
}
|
||||||
|
|
||||||
weapon_prop->at<BoolProperty>("Attach_15_D00AABBD4AD6A04778D56D81E51927B3"_s)->value = weapon.attached;
|
weapon_prop->at<BoolProperty>(MASS_WEAPON_ATTACH)->value = weapon.attached;
|
||||||
switch(weapon.damageType) {
|
switch(weapon.damageType) {
|
||||||
#define c(enumerator, strenum) case DamageType::enumerator: weapon_prop->at<ByteProperty>("DamageType_18_E1FFA53540591A9087EC698117A65C83"_s)->enumValue = strenum; break;
|
#define c(enumerator, strenum) case DamageType::enumerator: weapon_prop->at<ByteProperty>(MASS_WEAPON_DAMAGE_TYPE)->enumValue = strenum; break;
|
||||||
#include "../Maps/DamageTypes.hpp"
|
#include "../Maps/DamageTypes.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
default:
|
default:
|
||||||
Utility::Warning{} << "Unknown damage type enum value in writeWeaponType()."_s;
|
_lastError = Utility::format("Invalid damage type at index {}.", i);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
weapon_prop->at<BoolProperty>("DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222"_s)->value = weapon.dualWield;
|
weapon_prop->at<BoolProperty>(MASS_WEAPON_DUAL_WIELD)->value = weapon.dualWield;
|
||||||
switch(weapon.effectColourMode) {
|
switch(weapon.effectColourMode) {
|
||||||
#define c(enumerator, enumstr) case EffectColourMode::enumerator: \
|
#define c(enumerator, enumstr) case EffectColourMode::enumerator: \
|
||||||
weapon_prop->at<ByteProperty>("ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014"_s)->enumValue = enumstr; \
|
weapon_prop->at<ByteProperty>(MASS_WEAPON_COLOUR_EFX_MODE)->enumValue = enumstr; \
|
||||||
break;
|
break;
|
||||||
#include "../Maps/EffectColourModes.hpp"
|
#include "../Maps/EffectColourModes.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
default:
|
default:
|
||||||
Utility::Warning{} << "Unknown effect colour mode in writeWeaponType()."_s;
|
_lastError = Utility::format("Invalid damage type at index {}.", i);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
auto effect_colour = weapon_prop->at<ColourStructProperty>("ColorEfx_26_D921B62946C493E487455A831F4520AC"_s);
|
auto effect_colour = weapon_prop->at<ColourStructProperty>(MASS_WEAPON_COLOUR_EFX);
|
||||||
effect_colour->r = weapon.effectColour.r();
|
effect_colour->r = weapon.effectColour.r();
|
||||||
effect_colour->g = weapon.effectColour.g();
|
effect_colour->g = weapon.effectColour.g();
|
||||||
effect_colour->b = weapon.effectColour.b();
|
effect_colour->b = weapon.effectColour.b();
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define MASS_UNIT_DATA "UnitData"
|
||||||
|
#define MASS_NAME "Name_45_A037C5D54E53456407BDF091344529BB"
|
||||||
|
#define MASS_ACCOUNT "Account"
|
||||||
|
#define MASS_GLOBAL_STYLES "GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B"
|
||||||
|
|
||||||
|
// Frame stuff
|
||||||
|
#define MASS_FRAME "Frame_3_F92B0F6A44A15088AF7F41B9FF290653"
|
||||||
|
#define MASS_JOINT_NECK "NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"
|
||||||
|
#define MASS_JOINT_BODY "BodyLength_7_C16287754CBA96C93BAE36A5C154996A"
|
||||||
|
#define MASS_JOINT_SHOULDER "ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"
|
||||||
|
#define MASS_JOINT_ARM_UPPER "ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"
|
||||||
|
#define MASS_JOINT_ARM_LOWER "ArmLowerLength_12_ACD0F02745C28882619376926292FB36"
|
||||||
|
#define MASS_JOINT_HIP "HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"
|
||||||
|
#define MASS_JOINT_LEG_UPPER "LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"
|
||||||
|
#define MASS_JOINT_LEG_LOWER "LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"
|
||||||
|
#define MASS_FRAME_STYLES "Styles_32_00A3B3284B37F1E7819458844A20EB48"
|
||||||
|
#define MASS_EYE_FLARE "EyeFlareColor_36_AF79999C40FCA0E88A2F9A84488A38CA"
|
||||||
|
#define MASS_CUSTOM_FRAME_STYLES "FrameStyle_44_04A44C9440363CCEC5443D98BFAF22AA"
|
||||||
|
|
||||||
|
// Armour stuff
|
||||||
|
#define MASS_ARMOUR_PARTS "Armor_10_12E266C44116DDAF57E99ABB575A4B3C"
|
||||||
|
#define MASS_ARMOUR_SLOT "Slot_3_408BA56F4C9605C7E805CF91B642249C"
|
||||||
|
#define MASS_ARMOUR_ID "ID_5_ACD101864D3481DE96EDACACC09BDD25"
|
||||||
|
#define MASS_ARMOUR_STYLES "Styles_47_3E31870441DFD7DB8BEE5C85C26B365B"
|
||||||
|
#define MASS_ARMOUR_DECALS "Decals_42_F358794A4F18497970F56BA9627D3603"
|
||||||
|
#define MASS_ARMOUR_ACCESSORIES "Accessories_52_D902DD4241FA0050C2529596255153F3"
|
||||||
|
#define MASS_CUSTOM_ARMOUR_STYLES "ArmorStyle_42_E2F6AC3647788CB366BD469B3B7E899E"
|
||||||
|
|
||||||
|
// Weapon stuff
|
||||||
|
#define MASS_WEAPONS_MELEE "WeaponCC_22_0BBEC58C4A0EA1DB9E037B9339EE26A7"
|
||||||
|
#define MASS_WEAPONS_SHIELD "Shield_53_839BFD7945481BAEA3E43A9C5CA8E92E"
|
||||||
|
#define MASS_WEAPONS_BSHOOTER "WeaponBS_35_6EF6E0104FD7A138DF47F88CB57A83ED"
|
||||||
|
#define MASS_WEAPONS_ESHOOTER "WeaponES_37_1A295D544528623880A0B1AC2C7DEE99"
|
||||||
|
#define MASS_WEAPONS_BLAUNCHER "WeaponBL_36_5FD7C41E4613A75B44AB0E90B362846E"
|
||||||
|
#define MASS_WEAPONS_ELAUNCHER "WeaponEL_38_9D23F3884ACA15902C9E6CA6E4995995"
|
||||||
|
#define MASS_WEAPON_NAME "Name_13_7BF0D31F4E50C50C47231BB36A485D92"
|
||||||
|
#define MASS_WEAPON_TYPE "Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976"
|
||||||
|
#define MASS_WEAPON_ELEMENT "Element_6_8E4617CC4B2C1F1490435599784EC6E0"
|
||||||
|
#define MASS_CUSTOM_WEAPON_STYLES "Styles_10_8C3C82444B986AD7A99595AD4985912D"
|
||||||
|
#define MASS_WEAPON_ATTACH "Attach_15_D00AABBD4AD6A04778D56D81E51927B3"
|
||||||
|
#define MASS_WEAPON_DAMAGE_TYPE "DamageType_18_E1FFA53540591A9087EC698117A65C83"
|
||||||
|
#define MASS_WEAPON_DUAL_WIELD "DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222"
|
||||||
|
#define MASS_WEAPON_COLOUR_EFX_MODE "ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014"
|
||||||
|
#define MASS_WEAPON_COLOUR_EFX "ColorEfx_26_D921B62946C493E487455A831F4520AC"
|
||||||
|
|
||||||
|
// Weapon part stuff
|
||||||
|
#define MASS_WEAPON_PART_ID "ID_2_A74D75434308158E5926178822DD28EE"
|
||||||
|
#define MASS_WEAPON_PART_STYLES "Styles_17_994C97C34A90667BE5B716BFD0B97588"
|
||||||
|
#define MASS_WEAPON_PART_DECALS "Decals_13_8B81112B453D7230C0CDE982185E14F1"
|
||||||
|
#define MASS_WEAPON_PART_ACCESSORIES "Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C"
|
||||||
|
|
||||||
|
// BL attachment stuff
|
||||||
|
#define MASS_BL_ATTACHMENT_STYLE "WeaponBLAttachmentStyle_65_5943FCE8406F18D2C3F69285EB23A699"
|
||||||
|
#define MASS_BL_ATTACHMENTS "WeaponBLAttachment_61_442D08F547510A4CEE1501BBAF297BA0"
|
||||||
|
#define MASS_BL_ATTACHMENT_SOCKET "Socket_9_B9DBF30D4A1F0032A2BE2F8B342B35A9"
|
||||||
|
#define MASS_BL_ATTACHMENT_RELLOC "RelativeLocation_10_2F6E75DF4C40622658340E9A22D38B02"
|
||||||
|
#define MASS_BL_ATTACHMENT_OFFLOC "OffsetLocation_11_F42B3DA3436948FF85752DB33722382F"
|
||||||
|
#define MASS_BL_ATTACHMENT_RELROT "RelativeRotation_12_578140464621245132CFF2A2AD85E735"
|
||||||
|
#define MASS_BL_ATTACHMENT_OFFROT "OffsetRotation_13_B5980BCD47905D842D1490A1A520B064"
|
||||||
|
#define MASS_BL_ATTACHMENT_RELSCALE "RelativeScale_16_37BC80EF42699F79533F7AA7B3094E38"
|
||||||
|
|
||||||
|
// Style stuff
|
||||||
|
#define MASS_STYLE_NAME "Name_27_1532115A46EF2B2FA283908DF561A86B"
|
||||||
|
#define MASS_STYLE_COLOUR "Color_5_F0D383DF40474C9464AE48A0984A212E"
|
||||||
|
#define MASS_STYLE_METALLIC "Metallic_10_0A4CD1E4482CBF41CA61D0A856DE90B9"
|
||||||
|
#define MASS_STYLE_GLOSS "Gloss_11_9769599842CC275A401C4282A236E240"
|
||||||
|
#define MASS_STYLE_PATTERN_ID "PatternID_14_516DB85641DAF8ECFD2920BE2BDF1311"
|
||||||
|
#define MASS_STYLE_PATTERN_OPACITY "Opacity_30_53BD060B4DFCA1C92302D6A0F7831131"
|
||||||
|
#define MASS_STYLE_PATTERN_OFFSETX "OffsetX_23_70FC2E814C64BBB82452748D2AF9CD48"
|
||||||
|
#define MASS_STYLE_PATTERN_OFFSETY "OffsetY_24_5E1F866C4C054D9B2EE337ADC180C17F"
|
||||||
|
#define MASS_STYLE_PATTERN_ROTATION "Rotation_25_EC2DFAD84AD0A6BD3FA841ACD52EDD6D"
|
||||||
|
#define MASS_STYLE_PATTERN_SCALE "Scale_26_19DF0708409262183E1247B317137671"
|
||||||
|
|
||||||
|
// Decal stuff
|
||||||
|
#define MASS_DECAL_ID "ID_3_694C0B35404D8A3168AEC89026BC8CF9"
|
||||||
|
#define MASS_DECAL_COLOUR "Color_8_1B0B9D2B43DA6AAB9FA549B374D3E606"
|
||||||
|
#define MASS_DECAL_POSITION "Position_41_022C8FE84E1AAFE587261E88F2C72250"
|
||||||
|
#define MASS_DECAL_UAXIS "UAxis_37_EBEB715F45491AECACCC07A1AE4646D1"
|
||||||
|
#define MASS_DECAL_VAXIS "VAxis_39_C31EB2664EE202CAECFBBB84100B5E35"
|
||||||
|
#define MASS_DECAL_OFFSET "Offset_29_B02BBBB74FC60F5EDBEBAB8020738020"
|
||||||
|
#define MASS_DECAL_SCALE "Scale_32_959D1C2747AFD8D62808468235CBBA40"
|
||||||
|
#define MASS_DECAL_ROTATION "Rotation_27_12D7C314493D203D5C2326A03C5F910F"
|
||||||
|
#define MASS_DECAL_FLIP "Flip_35_CECCFB184CCD9412BD93FE9A8B656BE1"
|
||||||
|
#define MASS_DECAL_WRAP "Wrap_43_A7C68CDF4A92AF2ECDA53F953EE7CA62"
|
||||||
|
|
||||||
|
// Accessory stuff
|
||||||
|
#define MASS_ACCESSORY_ATTACH_INDEX "AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20"
|
||||||
|
#define MASS_ACCESSORY_ID "ID_4_5757B32647BAE263266259B8A7DFFFC1"
|
||||||
|
#define MASS_ACCESSORY_STYLES "Styles_7_91DEB0F24E24D13FC9472882C11D0DFD"
|
||||||
|
#define MASS_ACCESSORY_RELPOS "RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1"
|
||||||
|
#define MASS_ACCESSORY_OFFPOS "RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6"
|
||||||
|
#define MASS_ACCESSORY_RELROT "RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0"
|
||||||
|
#define MASS_ACCESSORY_OFFROT "RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA"
|
||||||
|
#define MASS_ACCESSORY_SCALE "LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53"
|
||||||
|
|
||||||
|
// Tuning stuff
|
||||||
|
#define MASS_ENGINE "Engine"
|
||||||
|
#define MASS_GEARS "Gears"
|
||||||
|
#define MASS_OS "OS"
|
||||||
|
#define MASS_MODULES "Modules"
|
||||||
|
#define MASS_ARCHITECT "Architect"
|
||||||
|
#define MASS_TECHS "Techs"
|
|
@ -19,26 +19,21 @@
|
||||||
#include <Corrade/Utility/Format.h>
|
#include <Corrade/Utility/Format.h>
|
||||||
#include <Corrade/Utility/Path.h>
|
#include <Corrade/Utility/Path.h>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
#include "MassManager.h"
|
#include "MassManager.h"
|
||||||
|
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
MassManager::MassManager(Containers::StringView save_path, Containers::StringView account, bool demo, Containers::StringView staging_dir):
|
MassManager::MassManager(Containers::StringView save_path, Containers::StringView account, bool demo,
|
||||||
_saveDirectory{save_path},
|
Containers::StringView staging_dir):
|
||||||
_account{account},
|
_saveDirectory{save_path}, _account{account}, _demo{demo}, _stagingAreaDirectory{staging_dir}
|
||||||
_demo{demo},
|
|
||||||
_stagingAreaDirectory{staging_dir}
|
|
||||||
{
|
{
|
||||||
Containers::arrayReserve(_hangars, 32);
|
|
||||||
|
|
||||||
Containers::String mass_filename = "";
|
Containers::String mass_filename = "";
|
||||||
for(int i = 0; i < 32; i++) {
|
for(UnsignedInt i = 0; i < _hangars.size(); i++) {
|
||||||
mass_filename = Utility::Path::join(_saveDirectory, Utility::format("{}Unit{:.2d}{}.sav", demo ? "Demo"_s : ""_s, i, _account));
|
mass_filename = Utility::Path::join(_saveDirectory,
|
||||||
Containers::arrayAppend(_hangars, Mass{mass_filename});
|
Utility::format("{}Unit{:.2d}{}.sav", demo ? "Demo"_s : ""_s, i, _account));
|
||||||
}
|
new(&_hangars[i]) Mass{mass_filename};
|
||||||
|
|
||||||
if(!Utility::Path::exists(_stagingAreaDirectory)) {
|
|
||||||
Utility::Path::make(_stagingAreaDirectory);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshStagedMasses();
|
refreshStagedMasses();
|
||||||
|
@ -54,6 +49,8 @@ auto MassManager::hangar(Int hangar) -> Mass& {
|
||||||
|
|
||||||
void MassManager::refreshHangar(Int hangar) {
|
void MassManager::refreshHangar(Int hangar) {
|
||||||
if(hangar < 0 || hangar >= 32) {
|
if(hangar < 0 || hangar >= 32) {
|
||||||
|
_lastError = "Hangar index out of range.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +62,8 @@ void MassManager::refreshHangar(Int hangar) {
|
||||||
|
|
||||||
auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bool {
|
auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bool {
|
||||||
if(hangar < 0 || hangar >= 32) {
|
if(hangar < 0 || hangar >= 32) {
|
||||||
_lastError = "Hangar out of range in MassManager::importMass()"_s;
|
_lastError = "Hangar index out of range.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +71,7 @@ auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bo
|
||||||
|
|
||||||
if(it == _stagedMasses.end()) {
|
if(it == _stagedMasses.end()) {
|
||||||
_lastError = "Couldn't find "_s + staged_fn + " in the staged M.A.S.S.es."_s;
|
_lastError = "Couldn't find "_s + staged_fn + " in the staged M.A.S.S.es."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +95,7 @@ auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bo
|
||||||
|
|
||||||
if(!Utility::Path::move(source + ".tmp"_s, dest)) {
|
if(!Utility::Path::move(source + ".tmp"_s, dest)) {
|
||||||
_lastError = Utility::format("Couldn't move {} to hangar {:.2d}", staged_fn, hangar + 1);
|
_lastError = Utility::format("Couldn't move {} to hangar {:.2d}", staged_fn, hangar + 1);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,21 +104,24 @@ auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bo
|
||||||
|
|
||||||
auto MassManager::exportMass(Int hangar) -> bool {
|
auto MassManager::exportMass(Int hangar) -> bool {
|
||||||
if(hangar < 0 || hangar >= 32) {
|
if(hangar < 0 || hangar >= 32) {
|
||||||
_lastError = "Hangar out of range in MassManager::exportMass()"_s;
|
_lastError = "Hangar index out of range."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_hangars[hangar].state() != Mass::State::Valid) {
|
if(_hangars[hangar].state() != Mass::State::Valid) {
|
||||||
_lastError = Utility::format("There is no valid data to export in hangar {:.2d}", hangar + 1);
|
_lastError = Utility::format("There is no valid data to export in hangar {:.2d}", hangar + 1);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Containers::String source = Utility::Path::join(_saveDirectory, _hangars[hangar].filename());
|
Containers::String source = Utility::Path::join(_saveDirectory, _hangars[hangar].filename());
|
||||||
Containers::String dest = Utility::Path::join(_stagingAreaDirectory,
|
Containers::String dest = Utility::Path::join(_stagingAreaDirectory,
|
||||||
Utility::format("{}_{}.sav", _hangars[hangar].name(), _account));
|
Utility::format("{}_{}.sav", _hangars[hangar].name(), _account));
|
||||||
|
|
||||||
if(!Utility::Path::copy(source, dest)) {
|
if(!Utility::Path::copy(source, dest)) {
|
||||||
_lastError = Utility::format("Couldn't export data from hangar {:.2d} to {}", hangar, dest);
|
_lastError = Utility::format("Couldn't export data from hangar {:.2d} to {}", hangar, dest);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,12 +130,14 @@ auto MassManager::exportMass(Int hangar) -> bool {
|
||||||
|
|
||||||
auto MassManager::moveMass(Int source, Int destination) -> bool {
|
auto MassManager::moveMass(Int source, Int destination) -> bool {
|
||||||
if(source < 0 || source >= 32) {
|
if(source < 0 || source >= 32) {
|
||||||
_lastError = "Source hangar out of range."_s;
|
_lastError = "Source hangar index out of range."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(destination < 0 || destination >= 32) {
|
if(destination < 0 || destination >= 32) {
|
||||||
_lastError = "Destination hangar out of range."_s;
|
_lastError = "Destination hangar index out of range."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,12 +167,14 @@ auto MassManager::moveMass(Int source, Int destination) -> bool {
|
||||||
|
|
||||||
auto MassManager::deleteMass(Int hangar) -> bool {
|
auto MassManager::deleteMass(Int hangar) -> bool {
|
||||||
if(hangar < 0 || hangar >= 32) {
|
if(hangar < 0 || hangar >= 32) {
|
||||||
_lastError = "Hangar out of range."_s;
|
_lastError = "Hangar index out of range."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Utility::Path::remove(Utility::Path::join(_saveDirectory, _hangars[hangar].filename()))) {
|
if(!Utility::Path::remove(Utility::Path::join(_saveDirectory, _hangars[hangar].filename()))) {
|
||||||
_lastError = Utility::format("Deletion failed: {}", std::strerror(errno));
|
_lastError = Utility::format("Deletion failed: {}", std::strerror(errno));
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,10 +189,11 @@ void MassManager::refreshStagedMasses() {
|
||||||
_stagedMasses.clear();
|
_stagedMasses.clear();
|
||||||
|
|
||||||
using Utility::Path::ListFlag;
|
using Utility::Path::ListFlag;
|
||||||
auto file_list = Utility::Path::list(_stagingAreaDirectory, ListFlag::SkipSpecial|ListFlag::SkipDirectories|ListFlag::SkipDotAndDotDot);
|
auto file_list = Utility::Path::list(_stagingAreaDirectory,
|
||||||
|
ListFlag::SkipSpecial|ListFlag::SkipDirectories|ListFlag::SkipDotAndDotDot);
|
||||||
|
|
||||||
if(!file_list) {
|
if(!file_list) {
|
||||||
Utility::Error{} << _stagingAreaDirectory << "couldn't be opened";
|
LOG_ERROR_FORMAT("{} couldn't be opened.", _stagingAreaDirectory);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,30 +201,52 @@ void MassManager::refreshStagedMasses() {
|
||||||
return !file.hasSuffix(".sav"_s);
|
return !file.hasSuffix(".sav"_s);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto list_view = file_list->except(file_list->end() - iter);
|
auto list_view = file_list->exceptSuffix(file_list->end() - iter);
|
||||||
|
|
||||||
Utility::Debug{} << "Scanning for staged M.A.S.S.es...";
|
LOG_INFO("Scanning for staged M.A.S.S.es...");
|
||||||
for(Containers::StringView file : list_view) {
|
for(Containers::StringView file : list_view) {
|
||||||
auto name = Mass::getNameFromFile(Utility::Path::join(_stagingAreaDirectory, file));
|
auto name = Mass::getNameFromFile(Utility::Path::join(_stagingAreaDirectory, file));
|
||||||
|
|
||||||
if(name) {
|
if(name) {
|
||||||
Utility::Debug{} << "Found staged M.A.S.S.:" << *name;
|
LOG_INFO_FORMAT("Found staged M.A.S.S.: {}", *name);
|
||||||
_stagedMasses[file] = *name;
|
_stagedMasses[file] = *name;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Utility::Warning{} << "Skipped:" << file;
|
LOG_WARNING_FORMAT("Skipped {}.", file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MassManager::refreshStagedMass(Containers::StringView filename) {
|
||||||
|
LOG_INFO_FORMAT("Refreshing staged unit with filename {}.", filename);
|
||||||
|
|
||||||
|
bool file_exists = Utility::Path::exists(Utility::Path::join(_stagingAreaDirectory, filename));
|
||||||
|
auto it = _stagedMasses.find(filename);
|
||||||
|
|
||||||
|
if(file_exists) {
|
||||||
|
auto name = Mass::getNameFromFile(Utility::Path::join(_stagingAreaDirectory, filename));
|
||||||
|
if(name) {
|
||||||
|
_stagedMasses[filename] = *name;
|
||||||
|
}
|
||||||
|
else if(it != _stagedMasses.cend()) {
|
||||||
|
_stagedMasses.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(it != _stagedMasses.cend()) {
|
||||||
|
_stagedMasses.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto MassManager::deleteStagedMass(Containers::StringView filename) -> bool {
|
auto MassManager::deleteStagedMass(Containers::StringView filename) -> bool {
|
||||||
if(_stagedMasses.find(filename) == _stagedMasses.cend()) {
|
if(_stagedMasses.find(filename) == _stagedMasses.cend()) {
|
||||||
_lastError = "The file "_s + filename + " couldn't be found in the list of staged M.A.S.S.es."_s;
|
_lastError = "The file "_s + filename + " couldn't be found in the list of staged M.A.S.S.es."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Utility::Path::remove(Utility::Path::join(_stagingAreaDirectory, filename))) {
|
if(!Utility::Path::remove(Utility::Path::join(_stagingAreaDirectory, filename))) {
|
||||||
_lastError = filename + " couldn't be deleted: " + std::strerror(errno);
|
_lastError = filename + " couldn't be deleted: " + std::strerror(errno);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <Corrade/Containers/GrowableArray.h>
|
#include <Corrade/Containers/StaticArray.h>
|
||||||
#include <Corrade/Containers/String.h>
|
#include <Corrade/Containers/String.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ class MassManager {
|
||||||
|
|
||||||
auto stagedMasses() -> std::map<Containers::String, Containers::String> const&;
|
auto stagedMasses() -> std::map<Containers::String, Containers::String> const&;
|
||||||
void refreshStagedMasses();
|
void refreshStagedMasses();
|
||||||
|
void refreshStagedMass(Containers::StringView filename);
|
||||||
auto deleteStagedMass(Containers::StringView filename) -> bool;
|
auto deleteStagedMass(Containers::StringView filename) -> bool;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -53,7 +54,7 @@ class MassManager {
|
||||||
|
|
||||||
Containers::String _lastError;
|
Containers::String _lastError;
|
||||||
|
|
||||||
Containers::Array<Mass> _hangars;
|
Containers::StaticArray<32, Mass> _hangars{NoInit};
|
||||||
|
|
||||||
Containers::StringView _stagingAreaDirectory;
|
Containers::StringView _stagingAreaDirectory;
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,11 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <Corrade/Containers/Array.h>
|
|
||||||
#include <Corrade/Containers/Pair.h>
|
#include <Corrade/Containers/Pair.h>
|
||||||
#include <Corrade/Containers/StaticArray.h>
|
|
||||||
#include <Corrade/Utility/Path.h>
|
#include <Corrade/Utility/Path.h>
|
||||||
#include <Corrade/Utility/Format.h>
|
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||||
#include "../UESaveFile/Types/ResourceItemValue.h"
|
#include "../UESaveFile/Types/ResourceItemValue.h"
|
||||||
#include "../UESaveFile/Types/IntProperty.h"
|
#include "../UESaveFile/Types/IntProperty.h"
|
||||||
|
@ -35,8 +34,11 @@ using namespace Containers::Literals;
|
||||||
Profile::Profile(Containers::StringView path):
|
Profile::Profile(Containers::StringView path):
|
||||||
_profile(path)
|
_profile(path)
|
||||||
{
|
{
|
||||||
|
LOG_INFO_FORMAT("Reading profile at {}.", path);
|
||||||
|
|
||||||
if(!_profile.valid()) {
|
if(!_profile.valid()) {
|
||||||
_lastError = _profile.lastError();
|
_lastError = _profile.lastError();
|
||||||
|
_valid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +51,7 @@ Profile::Profile(Containers::StringView path):
|
||||||
_type = ProfileType::FullGame;
|
_type = ProfileType::FullGame;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto account_prop = _profile.at<StringProperty>("Account"_s);
|
auto account_prop = _profile.at<StringProperty>(PROFILE_ACCOUNT);
|
||||||
if(!account_prop) {
|
if(!account_prop) {
|
||||||
_lastError = "Couldn't find an account ID in "_s + _filename;
|
_lastError = "Couldn't find an account ID in "_s + _filename;
|
||||||
_valid = false;
|
_valid = false;
|
||||||
|
@ -57,13 +59,6 @@ Profile::Profile(Containers::StringView path):
|
||||||
}
|
}
|
||||||
_account = account_prop->value;
|
_account = account_prop->value;
|
||||||
|
|
||||||
if(_account.hasPrefix("PMCSlot"_s)) {
|
|
||||||
_version = ProfileVersion::Normal;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_version = ProfileVersion::Legacy;
|
|
||||||
}
|
|
||||||
|
|
||||||
refreshValues();
|
refreshValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,68 +82,77 @@ auto Profile::isDemo() const -> bool {
|
||||||
return _type == ProfileType::Demo;
|
return _type == ProfileType::Demo;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::version() const -> ProfileVersion {
|
|
||||||
return _version;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Profile::isLegacy() const -> bool {
|
|
||||||
return _version == ProfileVersion::Legacy;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Profile::account() const -> Containers::StringView {
|
auto Profile::account() const -> Containers::StringView {
|
||||||
return _account;
|
return _account;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Profile::refreshValues() {
|
void Profile::refreshValues() {
|
||||||
if(!_profile.reloadData()) {
|
if(!_profile.reloadData()) {
|
||||||
_lastError = _profile.lastError();
|
LOG_ERROR(_profile.lastError());
|
||||||
_valid = false;
|
_valid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto name_prop = _profile.at<StringProperty>("CompanyName"_s);
|
if(_profile.saveType() != "/Game/Core/Save/bpSaveGameProfile.bpSaveGameProfile_C"_s) {
|
||||||
|
LOG_ERROR_FORMAT("{} is not a valid profile save.", _filename);
|
||||||
|
_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Getting the company name.");
|
||||||
|
auto name_prop = _profile.at<StringProperty>(PROFILE_NAME);
|
||||||
if(!name_prop) {
|
if(!name_prop) {
|
||||||
_lastError = "No company name in "_s + _filename;
|
_lastError = "No company name in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
_valid = false;
|
_valid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_name = name_prop->value;
|
_name = name_prop->value;
|
||||||
|
|
||||||
auto prop = _profile.at<IntProperty>("ActiveFrameSlot"_s);
|
LOG_INFO("Getting the active frame slot.");
|
||||||
|
auto prop = _profile.at<IntProperty>(PROFILE_ACTIVE_FRAME_SLOT);
|
||||||
_activeFrameSlot = prop ? prop->value : 0;
|
_activeFrameSlot = prop ? prop->value : 0;
|
||||||
|
|
||||||
prop = _profile.at<IntProperty>("Credit"_s);
|
LOG_INFO("Getting the credits.");
|
||||||
|
prop = _profile.at<IntProperty>(PROFILE_CREDITS);
|
||||||
_credits = prop ? prop->value : 0;
|
_credits = prop ? prop->value : 0;
|
||||||
|
|
||||||
prop = _profile.at<IntProperty>("StoryProgress"_s);
|
LOG_INFO("Getting the story progress.");
|
||||||
|
prop = _profile.at<IntProperty>(PROFILE_STORY_PROGRESS);
|
||||||
_storyProgress = prop ? prop->value : 0;
|
_storyProgress = prop ? prop->value : 0;
|
||||||
|
|
||||||
prop = _profile.at<IntProperty>("LastMissionID"_s);
|
LOG_INFO("Getting the last mission ID.");
|
||||||
|
prop = _profile.at<IntProperty>(PROFILE_LAST_MISSION_ID);
|
||||||
_lastMissionId = prop ? prop->value : 0;
|
_lastMissionId = prop ? prop->value : 0;
|
||||||
|
|
||||||
_verseSteel = getResource("ResourceMaterial"_s, VerseSteel);
|
LOG_INFO("Getting the materials.");
|
||||||
_undinium = getResource("ResourceMaterial"_s, Undinium);
|
_verseSteel = getResource(PROFILE_MATERIAL, VerseSteel);
|
||||||
_necriumAlloy = getResource("ResourceMaterial"_s, NecriumAlloy);
|
_undinium = getResource(PROFILE_MATERIAL, Undinium);
|
||||||
_lunarite = getResource("ResourceMaterial"_s, Lunarite);
|
_necriumAlloy = getResource(PROFILE_MATERIAL, NecriumAlloy);
|
||||||
_asterite = getResource("ResourceMaterial"_s, Asterite);
|
_lunarite = getResource(PROFILE_MATERIAL, Lunarite);
|
||||||
|
_asterite = getResource(PROFILE_MATERIAL, Asterite);
|
||||||
|
_halliteFragma = getResource(PROFILE_MATERIAL, HalliteFragma);
|
||||||
|
|
||||||
_ednil = getResource("ResourceMaterial"_s, Ednil);
|
_ednil = getResource(PROFILE_MATERIAL, Ednil);
|
||||||
_nuflalt = getResource("ResourceMaterial"_s, Nuflalt);
|
_nuflalt = getResource(PROFILE_MATERIAL, Nuflalt);
|
||||||
_aurelene = getResource("ResourceMaterial"_s, Aurelene);
|
_aurelene = getResource(PROFILE_MATERIAL, Aurelene);
|
||||||
_soldus = getResource("ResourceMaterial"_s, Soldus);
|
_soldus = getResource(PROFILE_MATERIAL, Soldus);
|
||||||
_synthesisedN = getResource("ResourceMaterial"_s, SynthesisedN);
|
_synthesisedN = getResource(PROFILE_MATERIAL, SynthesisedN);
|
||||||
|
_nanoc = getResource(PROFILE_MATERIAL, Nanoc);
|
||||||
|
|
||||||
_alcarbonite = getResource("ResourceMaterial"_s, Alcarbonite);
|
_alcarbonite = getResource(PROFILE_MATERIAL, Alcarbonite);
|
||||||
_keriphene = getResource("ResourceMaterial"_s, Keriphene);
|
_keriphene = getResource(PROFILE_MATERIAL, Keriphene);
|
||||||
_nitinolCM = getResource("ResourceMaterial"_s, NitinolCM);
|
_nitinolCM = getResource(PROFILE_MATERIAL, NitinolCM);
|
||||||
_quarkium = getResource("ResourceMaterial"_s, Quarkium);
|
_quarkium = getResource(PROFILE_MATERIAL, Quarkium);
|
||||||
_alterene = getResource("ResourceMaterial"_s, Alterene);
|
_alterene = getResource(PROFILE_MATERIAL, Alterene);
|
||||||
|
_cosmium = getResource(PROFILE_MATERIAL, Cosmium);
|
||||||
|
|
||||||
_mixedComposition = getResource("ResourceQuarkData"_s, MixedComposition);
|
_mixedComposition = getResource(PROFILE_QUARK_DATA, MixedComposition);
|
||||||
_voidResidue = getResource("ResourceQuarkData"_s, VoidResidue);
|
_voidResidue = getResource(PROFILE_QUARK_DATA, VoidResidue);
|
||||||
_muscularConstruction = getResource("ResourceQuarkData"_s, MuscularConstruction);
|
_muscularConstruction = getResource(PROFILE_QUARK_DATA, MuscularConstruction);
|
||||||
_mineralExoskeletology = getResource("ResourceQuarkData"_s, MineralExoskeletology);
|
_mineralExoskeletology = getResource(PROFILE_QUARK_DATA, MineralExoskeletology);
|
||||||
_carbonisedSkin = getResource("ResourceQuarkData"_s, CarbonisedSkin);
|
_carbonisedSkin = getResource(PROFILE_QUARK_DATA, CarbonisedSkin);
|
||||||
|
_isolatedVoidParticle = getResource(PROFILE_QUARK_DATA, IsolatedVoidParticle);
|
||||||
|
|
||||||
_valid = true;
|
_valid = true;
|
||||||
}
|
}
|
||||||
|
@ -158,9 +162,10 @@ auto Profile::companyName() const -> Containers::StringView {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::renameCompany(Containers::StringView new_name) -> bool {
|
auto Profile::renameCompany(Containers::StringView new_name) -> bool {
|
||||||
auto name_prop = _profile.at<StringProperty>("CompanyName"_s);
|
auto name_prop = _profile.at<StringProperty>(PROFILE_NAME);
|
||||||
if(!name_prop) {
|
if(!name_prop) {
|
||||||
_lastError = "No company name in "_s + _filename;
|
_lastError = "No company name in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
_valid = false;
|
_valid = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -184,11 +189,12 @@ auto Profile::credits() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setCredits(Int amount) -> bool {
|
auto Profile::setCredits(Int amount) -> bool {
|
||||||
auto credits_prop = _profile.at<IntProperty>("Credit"_s);
|
auto credits_prop = _profile.at<IntProperty>(PROFILE_CREDITS);
|
||||||
|
|
||||||
if(!credits_prop) {
|
if(!credits_prop) {
|
||||||
credits_prop = new IntProperty;
|
credits_prop = new IntProperty;
|
||||||
credits_prop->name.emplace("Credit"_s);
|
credits_prop->name.emplace("Credit"_s);
|
||||||
|
credits_prop->valueLength = sizeof(Int);
|
||||||
_profile.appendProperty(IntProperty::ptr{credits_prop});
|
_profile.appendProperty(IntProperty::ptr{credits_prop});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,6 +218,7 @@ auto Profile::setStoryProgress(Int progress) -> bool {
|
||||||
if(!story_progress_prop) {
|
if(!story_progress_prop) {
|
||||||
story_progress_prop = new IntProperty;
|
story_progress_prop = new IntProperty;
|
||||||
story_progress_prop->name.emplace("StoryProgress"_s);
|
story_progress_prop->name.emplace("StoryProgress"_s);
|
||||||
|
story_progress_prop->valueLength = sizeof(Int);
|
||||||
_profile.appendProperty(IntProperty::ptr{story_progress_prop});
|
_profile.appendProperty(IntProperty::ptr{story_progress_prop});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,7 +241,7 @@ auto Profile::verseSteel() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setVerseSteel(Int amount) -> bool {
|
auto Profile::setVerseSteel(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, VerseSteel, amount);
|
return setResource(PROFILE_MATERIAL, VerseSteel, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::undinium() const -> Int {
|
auto Profile::undinium() const -> Int {
|
||||||
|
@ -242,7 +249,7 @@ auto Profile::undinium() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setUndinium(Int amount) -> bool {
|
auto Profile::setUndinium(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Undinium, amount);
|
return setResource(PROFILE_MATERIAL, Undinium, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::necriumAlloy() const -> Int {
|
auto Profile::necriumAlloy() const -> Int {
|
||||||
|
@ -250,7 +257,7 @@ auto Profile::necriumAlloy() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setNecriumAlloy(Int amount) -> bool {
|
auto Profile::setNecriumAlloy(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, NecriumAlloy, amount);
|
return setResource(PROFILE_MATERIAL, NecriumAlloy, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::lunarite() const -> Int {
|
auto Profile::lunarite() const -> Int {
|
||||||
|
@ -258,7 +265,7 @@ auto Profile::lunarite() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setLunarite(Int amount) -> bool {
|
auto Profile::setLunarite(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Lunarite, amount);
|
return setResource(PROFILE_MATERIAL, Lunarite, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::asterite() const -> Int {
|
auto Profile::asterite() const -> Int {
|
||||||
|
@ -266,7 +273,17 @@ auto Profile::asterite() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setAsterite(Int amount) -> bool {
|
auto Profile::setAsterite(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Asterite, amount);
|
return setResource(PROFILE_MATERIAL, Asterite, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int
|
||||||
|
Profile::halliteFragma() const {
|
||||||
|
return _halliteFragma;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::setHalliteFragma(Int amount) {
|
||||||
|
return setResource(PROFILE_MATERIAL, HalliteFragma, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::ednil() const -> Int {
|
auto Profile::ednil() const -> Int {
|
||||||
|
@ -274,7 +291,7 @@ auto Profile::ednil() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setEdnil(Int amount) -> bool {
|
auto Profile::setEdnil(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Ednil, amount);
|
return setResource(PROFILE_MATERIAL, Ednil, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::nuflalt() const -> Int {
|
auto Profile::nuflalt() const -> Int {
|
||||||
|
@ -282,7 +299,7 @@ auto Profile::nuflalt() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setNuflalt(Int amount) -> bool {
|
auto Profile::setNuflalt(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Nuflalt, amount);
|
return setResource(PROFILE_MATERIAL, Nuflalt, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::aurelene() const -> Int {
|
auto Profile::aurelene() const -> Int {
|
||||||
|
@ -290,7 +307,7 @@ auto Profile::aurelene() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setAurelene(Int amount) -> bool {
|
auto Profile::setAurelene(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Aurelene, amount);
|
return setResource(PROFILE_MATERIAL, Aurelene, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::soldus() const -> Int {
|
auto Profile::soldus() const -> Int {
|
||||||
|
@ -298,7 +315,7 @@ auto Profile::soldus() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setSoldus(Int amount) -> bool {
|
auto Profile::setSoldus(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Soldus, amount);
|
return setResource(PROFILE_MATERIAL, Soldus, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::synthesisedN() const -> Int {
|
auto Profile::synthesisedN() const -> Int {
|
||||||
|
@ -306,7 +323,17 @@ auto Profile::synthesisedN() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setSynthesisedN(Int amount) -> bool {
|
auto Profile::setSynthesisedN(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, SynthesisedN, amount);
|
return setResource(PROFILE_MATERIAL, SynthesisedN, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int
|
||||||
|
Profile::nanoc() const {
|
||||||
|
return _nanoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::setNanoc(Int amount) {
|
||||||
|
return setResource(PROFILE_MATERIAL, Nanoc, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::alcarbonite() const -> Int {
|
auto Profile::alcarbonite() const -> Int {
|
||||||
|
@ -314,7 +341,7 @@ auto Profile::alcarbonite() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setAlcarbonite(Int amount) -> bool {
|
auto Profile::setAlcarbonite(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Alcarbonite, amount);
|
return setResource(PROFILE_MATERIAL, Alcarbonite, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::keriphene() const -> Int {
|
auto Profile::keriphene() const -> Int {
|
||||||
|
@ -322,7 +349,7 @@ auto Profile::keriphene() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setKeriphene(Int amount) -> bool {
|
auto Profile::setKeriphene(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Keriphene, amount);
|
return setResource(PROFILE_MATERIAL, Keriphene, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::nitinolCM() const -> Int {
|
auto Profile::nitinolCM() const -> Int {
|
||||||
|
@ -330,7 +357,7 @@ auto Profile::nitinolCM() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setNitinolCM(Int amount) -> bool {
|
auto Profile::setNitinolCM(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, NitinolCM, amount);
|
return setResource(PROFILE_MATERIAL, NitinolCM, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::quarkium() const -> Int {
|
auto Profile::quarkium() const -> Int {
|
||||||
|
@ -338,7 +365,7 @@ auto Profile::quarkium() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setQuarkium(Int amount) -> bool {
|
auto Profile::setQuarkium(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Quarkium, amount);
|
return setResource(PROFILE_MATERIAL, Quarkium, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::alterene() const -> Int {
|
auto Profile::alterene() const -> Int {
|
||||||
|
@ -346,7 +373,17 @@ auto Profile::alterene() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setAlterene(Int amount) -> bool {
|
auto Profile::setAlterene(Int amount) -> bool {
|
||||||
return setResource("ResourceMaterial"_s, Alterene, amount);
|
return setResource(PROFILE_MATERIAL, Alterene, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int
|
||||||
|
Profile::cosmium() const {
|
||||||
|
return _cosmium;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::setCosmium(Int amount) {
|
||||||
|
return setResource(PROFILE_MATERIAL, Cosmium, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::mixedComposition() const -> Int {
|
auto Profile::mixedComposition() const -> Int {
|
||||||
|
@ -354,7 +391,7 @@ auto Profile::mixedComposition() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setMixedComposition(Int amount) -> bool {
|
auto Profile::setMixedComposition(Int amount) -> bool {
|
||||||
return setResource("ResourceQuarkData"_s, MixedComposition, amount);
|
return setResource(PROFILE_QUARK_DATA, MixedComposition, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::voidResidue() const -> Int {
|
auto Profile::voidResidue() const -> Int {
|
||||||
|
@ -362,7 +399,7 @@ auto Profile::voidResidue() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setVoidResidue(Int amount) -> bool {
|
auto Profile::setVoidResidue(Int amount) -> bool {
|
||||||
return setResource("ResourceQuarkData"_s, VoidResidue, amount);
|
return setResource(PROFILE_QUARK_DATA, VoidResidue, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::muscularConstruction() const -> Int {
|
auto Profile::muscularConstruction() const -> Int {
|
||||||
|
@ -370,7 +407,7 @@ auto Profile::muscularConstruction() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setMuscularConstruction(Int amount) -> bool {
|
auto Profile::setMuscularConstruction(Int amount) -> bool {
|
||||||
return setResource("ResourceQuarkData"_s, MuscularConstruction, amount);
|
return setResource(PROFILE_QUARK_DATA, MuscularConstruction, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::mineralExoskeletology() const -> Int {
|
auto Profile::mineralExoskeletology() const -> Int {
|
||||||
|
@ -378,7 +415,7 @@ auto Profile::mineralExoskeletology() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setMineralExoskeletology(Int amount) -> bool {
|
auto Profile::setMineralExoskeletology(Int amount) -> bool {
|
||||||
return setResource("ResourceQuarkData"_s, MineralExoskeletology, amount);
|
return setResource(PROFILE_QUARK_DATA, MineralExoskeletology, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::carbonisedSkin() const -> Int {
|
auto Profile::carbonisedSkin() const -> Int {
|
||||||
|
@ -386,7 +423,17 @@ auto Profile::carbonisedSkin() const -> Int {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::setCarbonisedSkin(Int amount) -> bool {
|
auto Profile::setCarbonisedSkin(Int amount) -> bool {
|
||||||
return setResource("ResourceQuarkData"_s, CarbonisedSkin, amount);
|
return setResource(PROFILE_QUARK_DATA, CarbonisedSkin, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int
|
||||||
|
Profile::isolatedVoidParticle() const {
|
||||||
|
return _isolatedVoidParticle;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::setIsolatedVoidParticle(Int amount) {
|
||||||
|
return setResource(PROFILE_QUARK_DATA, IsolatedVoidParticle, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Profile::getResource(Containers::StringView container, MaterialID id) -> Int {
|
auto Profile::getResource(Containers::StringView container, MaterialID id) -> Int {
|
||||||
|
@ -409,9 +456,10 @@ auto Profile::setResource(Containers::StringView container, MaterialID id, Int a
|
||||||
auto mats_prop = _profile.at<ArrayProperty>(container);
|
auto mats_prop = _profile.at<ArrayProperty>(container);
|
||||||
|
|
||||||
if(!mats_prop) {
|
if(!mats_prop) {
|
||||||
_lastError = "Couldn't find "_s + container + " in "_s + _filename;
|
mats_prop = new ArrayProperty;
|
||||||
_valid = false;
|
mats_prop->name.emplace(container);
|
||||||
return false;
|
mats_prop->itemType = "StructProperty";
|
||||||
|
_profile.appendProperty(ArrayProperty::ptr{mats_prop});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto predicate = [&id](UnrealPropertyBase::ptr& prop){
|
auto predicate = [&id](UnrealPropertyBase::ptr& prop){
|
||||||
|
@ -424,6 +472,9 @@ auto Profile::setResource(Containers::StringView container, MaterialID id, Int a
|
||||||
ResourceItemValue* res_prop;
|
ResourceItemValue* res_prop;
|
||||||
if(it == mats_prop->items.end()) {
|
if(it == mats_prop->items.end()) {
|
||||||
res_prop = new ResourceItemValue;
|
res_prop = new ResourceItemValue;
|
||||||
|
if(mats_prop->items.isEmpty()) {
|
||||||
|
res_prop->name.emplace(container);
|
||||||
|
}
|
||||||
res_prop->id = id;
|
res_prop->id = id;
|
||||||
ResourceItemValue::ptr prop{res_prop};
|
ResourceItemValue::ptr prop{res_prop};
|
||||||
arrayAppend(mats_prop->items, std::move(prop));
|
arrayAppend(mats_prop->items, std::move(prop));
|
||||||
|
|
|
@ -33,11 +33,6 @@ enum class ProfileType : UnsignedByte {
|
||||||
FullGame
|
FullGame
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ProfileVersion : UnsignedByte {
|
|
||||||
Legacy, // pre-0.8
|
|
||||||
Normal // 0.8 and later
|
|
||||||
};
|
|
||||||
|
|
||||||
class Profile {
|
class Profile {
|
||||||
public:
|
public:
|
||||||
explicit Profile(Containers::StringView path);
|
explicit Profile(Containers::StringView path);
|
||||||
|
@ -51,9 +46,6 @@ class Profile {
|
||||||
auto type() const -> ProfileType;
|
auto type() const -> ProfileType;
|
||||||
auto isDemo() const -> bool;
|
auto isDemo() const -> bool;
|
||||||
|
|
||||||
auto version() const -> ProfileVersion;
|
|
||||||
auto isLegacy() const -> bool;
|
|
||||||
|
|
||||||
auto account() const -> Containers::StringView;
|
auto account() const -> Containers::StringView;
|
||||||
|
|
||||||
void refreshValues();
|
void refreshValues();
|
||||||
|
@ -86,6 +78,9 @@ class Profile {
|
||||||
auto asterite() const -> Int;
|
auto asterite() const -> Int;
|
||||||
auto setAsterite(Int amount) -> bool;
|
auto setAsterite(Int amount) -> bool;
|
||||||
|
|
||||||
|
Int halliteFragma() const;
|
||||||
|
bool setHalliteFragma(Int amount);
|
||||||
|
|
||||||
auto ednil() const -> Int;
|
auto ednil() const -> Int;
|
||||||
auto setEdnil(Int amount) -> bool;
|
auto setEdnil(Int amount) -> bool;
|
||||||
|
|
||||||
|
@ -101,6 +96,9 @@ class Profile {
|
||||||
auto synthesisedN() const -> Int;
|
auto synthesisedN() const -> Int;
|
||||||
auto setSynthesisedN(Int amount) -> bool;
|
auto setSynthesisedN(Int amount) -> bool;
|
||||||
|
|
||||||
|
Int nanoc() const;
|
||||||
|
bool setNanoc(Int amount);
|
||||||
|
|
||||||
auto alcarbonite() const -> Int;
|
auto alcarbonite() const -> Int;
|
||||||
auto setAlcarbonite(Int amount) -> bool;
|
auto setAlcarbonite(Int amount) -> bool;
|
||||||
|
|
||||||
|
@ -116,6 +114,9 @@ class Profile {
|
||||||
auto alterene() const -> Int;
|
auto alterene() const -> Int;
|
||||||
auto setAlterene(Int amount) -> bool;
|
auto setAlterene(Int amount) -> bool;
|
||||||
|
|
||||||
|
Int cosmium() const;
|
||||||
|
bool setCosmium(Int amount);
|
||||||
|
|
||||||
auto mixedComposition() const -> Int;
|
auto mixedComposition() const -> Int;
|
||||||
auto setMixedComposition(Int amount) -> bool;
|
auto setMixedComposition(Int amount) -> bool;
|
||||||
|
|
||||||
|
@ -131,6 +132,9 @@ class Profile {
|
||||||
auto carbonisedSkin() const -> Int;
|
auto carbonisedSkin() const -> Int;
|
||||||
auto setCarbonisedSkin(Int amount) -> bool;
|
auto setCarbonisedSkin(Int amount) -> bool;
|
||||||
|
|
||||||
|
Int isolatedVoidParticle() const;
|
||||||
|
bool setIsolatedVoidParticle(Int amount);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto getResource(Containers::StringView container, MaterialID id) -> Int;
|
auto getResource(Containers::StringView container, MaterialID id) -> Int;
|
||||||
auto setResource(Containers::StringView container, MaterialID id, Int amount) -> bool;
|
auto setResource(Containers::StringView container, MaterialID id, Int amount) -> bool;
|
||||||
|
@ -138,7 +142,6 @@ class Profile {
|
||||||
Containers::String _filename;
|
Containers::String _filename;
|
||||||
|
|
||||||
ProfileType _type;
|
ProfileType _type;
|
||||||
ProfileVersion _version;
|
|
||||||
|
|
||||||
UESaveFile _profile;
|
UESaveFile _profile;
|
||||||
|
|
||||||
|
@ -148,29 +151,33 @@ class Profile {
|
||||||
Int _storyProgress = 0;
|
Int _storyProgress = 0;
|
||||||
Int _lastMissionId = 0;
|
Int _lastMissionId = 0;
|
||||||
|
|
||||||
Int _verseSteel = 0;
|
Int _verseSteel = 0;
|
||||||
Int _undinium = 0;
|
Int _undinium = 0;
|
||||||
Int _necriumAlloy = 0;
|
Int _necriumAlloy = 0;
|
||||||
Int _lunarite = 0;
|
Int _lunarite = 0;
|
||||||
Int _asterite = 0;
|
Int _asterite = 0;
|
||||||
|
Int _halliteFragma = 0;
|
||||||
|
|
||||||
Int _ednil = 0;
|
Int _ednil = 0;
|
||||||
Int _nuflalt = 0;
|
Int _nuflalt = 0;
|
||||||
Int _aurelene = 0;
|
Int _aurelene = 0;
|
||||||
Int _soldus = 0;
|
Int _soldus = 0;
|
||||||
Int _synthesisedN = 0;
|
Int _synthesisedN = 0;
|
||||||
|
Int _nanoc = 0;
|
||||||
|
|
||||||
Int _alcarbonite = 0;
|
Int _alcarbonite = 0;
|
||||||
Int _keriphene = 0;
|
Int _keriphene = 0;
|
||||||
Int _nitinolCM = 0;
|
Int _nitinolCM = 0;
|
||||||
Int _quarkium = 0;
|
Int _quarkium = 0;
|
||||||
Int _alterene = 0;
|
Int _alterene = 0;
|
||||||
|
Int _cosmium = 0;
|
||||||
|
|
||||||
Int _mixedComposition = 0;
|
Int _mixedComposition = 0;
|
||||||
Int _voidResidue = 0;
|
Int _voidResidue = 0;
|
||||||
Int _muscularConstruction = 0;
|
Int _muscularConstruction = 0;
|
||||||
Int _mineralExoskeletology = 0;
|
Int _mineralExoskeletology = 0;
|
||||||
Int _carbonisedSkin = 0;
|
Int _carbonisedSkin = 0;
|
||||||
|
Int _isolatedVoidParticle = 0;
|
||||||
|
|
||||||
Containers::String _account;
|
Containers::String _account;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define PROFILE_NAME "CompanyName"
|
||||||
|
#define PROFILE_ACTIVE_FRAME_SLOT "ActiveFrameSlot"
|
||||||
|
#define PROFILE_CREDITS "Credit"
|
||||||
|
#define PROFILE_STORY_PROGRESS "StoryProgress"
|
||||||
|
#define PROFILE_LAST_MISSION_ID "LastMissionID"
|
||||||
|
#define PROFILE_MATERIAL "ResourceMaterial"
|
||||||
|
#define PROFILE_QUARK_DATA "ResourceQuarkData"
|
||||||
|
#define PROFILE_ACCOUNT "Account"
|
|
@ -21,27 +21,31 @@
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
|
||||||
enum MaterialID : Int {
|
enum MaterialID : Int {
|
||||||
VerseSteel = 0xC3500,
|
VerseSteel = 0xC3500,
|
||||||
Undinium = 0xC3501,
|
Undinium = 0xC3501,
|
||||||
NecriumAlloy = 0xC3502,
|
NecriumAlloy = 0xC3502,
|
||||||
Lunarite = 0xC3503,
|
Lunarite = 0xC3503,
|
||||||
Asterite = 0xC3504,
|
Asterite = 0xC3504,
|
||||||
|
HalliteFragma = 0xC3505,
|
||||||
|
|
||||||
Ednil = 0xC350A,
|
Ednil = 0xC350A,
|
||||||
Nuflalt = 0xC350B,
|
Nuflalt = 0xC350B,
|
||||||
Aurelene = 0xC350C,
|
Aurelene = 0xC350C,
|
||||||
Soldus = 0xC350D,
|
Soldus = 0xC350D,
|
||||||
SynthesisedN = 0xC350E,
|
SynthesisedN = 0xC350E,
|
||||||
|
Nanoc = 0xC350F,
|
||||||
|
|
||||||
Alcarbonite = 0xC3514,
|
Alcarbonite = 0xC3514,
|
||||||
Keriphene = 0xC3515,
|
Keriphene = 0xC3515,
|
||||||
NitinolCM = 0xC3516,
|
NitinolCM = 0xC3516,
|
||||||
Quarkium = 0xC3517,
|
Quarkium = 0xC3517,
|
||||||
Alterene = 0xC3518,
|
Alterene = 0xC3518,
|
||||||
|
Cosmium = 0xC3519,
|
||||||
|
|
||||||
MixedComposition = 0xDBBA0,
|
MixedComposition = 0xDBBA0,
|
||||||
VoidResidue = 0xDBBA1,
|
VoidResidue = 0xDBBA1,
|
||||||
MuscularConstruction = 0xDBBA2,
|
MuscularConstruction = 0xDBBA2,
|
||||||
MineralExoskeletology = 0xDBBA3,
|
MineralExoskeletology = 0xDBBA3,
|
||||||
CarbonisedSkin = 0xDBBA4
|
CarbonisedSkin = 0xDBBA4,
|
||||||
|
IsolatedVoidParticle = 0xDBBA5,
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iomanip>
|
|
||||||
#include <regex>
|
|
||||||
|
|
||||||
#include <Corrade/Containers/ScopeGuard.h>
|
#include <Corrade/Containers/ScopeGuard.h>
|
||||||
#include <Corrade/Containers/StaticArray.h>
|
#include <Corrade/Containers/StaticArray.h>
|
||||||
|
@ -29,6 +27,8 @@
|
||||||
|
|
||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
#include "ProfileManager.h"
|
#include "ProfileManager.h"
|
||||||
|
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
|
@ -53,6 +53,8 @@ auto ProfileManager::profiles() -> Containers::ArrayView<Profile> {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ProfileManager::refreshProfiles() -> bool {
|
auto ProfileManager::refreshProfiles() -> bool {
|
||||||
|
LOG_INFO("Refreshing profiles.");
|
||||||
|
|
||||||
_profiles = Containers::Array<Profile>{};
|
_profiles = Containers::Array<Profile>{};
|
||||||
|
|
||||||
using Utility::Path::ListFlag;
|
using Utility::Path::ListFlag;
|
||||||
|
@ -61,31 +63,30 @@ auto ProfileManager::refreshProfiles() -> bool {
|
||||||
|
|
||||||
if(!files) {
|
if(!files) {
|
||||||
_lastError = _saveDirectory + " can't be opened.";
|
_lastError = _saveDirectory + " can't be opened.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto predicate = [](Containers::StringView file)->bool{
|
auto predicate = [](Containers::StringView file)->bool{
|
||||||
std::regex legacy_regex("(Demo)?Profile[0-9]{17}\\.sav", std::regex::nosubs);
|
return !((file.hasPrefix("DemoProfile") || file.hasPrefix("Profile")) && file.hasSuffix(".sav"));
|
||||||
std::regex new_regex("(Demo)?ProfilePMCSlot[0-9]{3}\\.sav", std::regex::nosubs);
|
|
||||||
std::cmatch m;
|
|
||||||
return !std::regex_match(file.data(), m, legacy_regex) && !std::regex_match(file.data(), m, new_regex);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
auto files_view = files->except(files->end() - std::remove_if(files->begin(), files->end(), predicate));
|
auto files_view = files->exceptSuffix(files->end() - std::remove_if(files->begin(), files->end(), predicate));
|
||||||
|
|
||||||
for(const auto& file : files_view) {
|
for(const auto& file : files_view) {
|
||||||
Profile profile{Utility::Path::join(_saveDirectory, file)};
|
Profile profile{Utility::Path::join(_saveDirectory, file)};
|
||||||
|
|
||||||
if(!profile.valid()) {
|
if(!profile.valid()) {
|
||||||
Utility::Warning{} << "Profile"_s << file << "is invalid:"_s << profile.lastError();
|
LOG_WARNING_FORMAT("Profile {} is invalid: {}", file, profile.lastError());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayAppend(_profiles, std::move(profile));
|
arrayAppend(_profiles, std::move(profile));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_profiles.empty()) {
|
if(_profiles.isEmpty()) {
|
||||||
_lastError = "No valid profiles were found."_s;
|
_lastError = "No valid profiles were found."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +102,7 @@ auto ProfileManager::deleteProfile(std::size_t index, bool delete_builds) -> boo
|
||||||
_lastError = Utility::format("Couldn't delete {} (filename: {}).",
|
_lastError = Utility::format("Couldn't delete {} (filename: {}).",
|
||||||
_profiles[index].companyName(),
|
_profiles[index].companyName(),
|
||||||
_profiles[index].filename());
|
_profiles[index].filename());
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
refreshProfiles();
|
refreshProfiles();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +131,7 @@ auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> boo
|
||||||
std::tm* time = std::localtime(×tamp);
|
std::tm* time = std::localtime(×tamp);
|
||||||
auto& profile = _profiles[index];
|
auto& profile = _profiles[index];
|
||||||
|
|
||||||
auto filename = Utility::format("{}_{}{:.2d}{:.2d}_{:.2d}{:.2d}{:.2d}.mbprofbackup",
|
auto filename = Utility::format("{}_{}{:.2d}{:.2d}_{:.2d}{:.2d}{:.2d}.backup.mbst",
|
||||||
Utility::String::replaceAll(profile.companyName().data(), " ", "_").c_str(),
|
Utility::String::replaceAll(profile.companyName().data(), " ", "_").c_str(),
|
||||||
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||||
time->tm_hour, time->tm_min, time->tm_sec);
|
time->tm_hour, time->tm_min, time->tm_sec);
|
||||||
|
@ -140,26 +142,28 @@ auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> boo
|
||||||
if(zip == nullptr) {
|
if(zip == nullptr) {
|
||||||
zip_error_init_with_code(&error, error_code);
|
zip_error_init_with_code(&error, error_code);
|
||||||
_lastError = zip_error_strerror(&error);
|
_lastError = zip_error_strerror(&error);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
zip_source_t* profile_source = zip_source_file(zip, Utility::Path::toNativeSeparators(Utility::Path::join(_saveDirectory, profile.filename())).data(), 0, 0);
|
zip_source_t* profile_source = zip_source_file(zip, Utility::Path::toNativeSeparators(Utility::Path::join(_saveDirectory, profile.filename())).data(), 0, 0);
|
||||||
if(profile_source == nullptr) {
|
if(profile_source == nullptr) {
|
||||||
_lastError = zip_strerror(zip);
|
_lastError = zip_strerror(zip);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
zip_source_free(profile_source);
|
zip_source_free(profile_source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(zip_file_add(zip, profile.filename().data(), profile_source, ZIP_FL_ENC_UTF_8) == -1) {
|
if(zip_file_add(zip, profile.filename().data(), profile_source, ZIP_FL_ENC_UTF_8) == -1) {
|
||||||
_lastError = zip_strerror(zip);
|
_lastError = zip_strerror(zip);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
zip_source_free(profile_source);
|
zip_source_free(profile_source);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto comment = Utility::format("{}|{}{}|{}-{:.2d}-{:.2d}-{:.2d}-{:.2d}-{:.2d}",
|
auto comment = Utility::format("{}|{}|{}-{:.2d}-{:.2d}-{:.2d}-{:.2d}-{:.2d}",
|
||||||
profile.companyName(),
|
profile.companyName(),
|
||||||
profile.isDemo() ? "demo"_s : "full"_s,
|
profile.isDemo() ? "demo"_s : "full"_s,
|
||||||
profile.isLegacy() ? ""_s : "_new"_s,
|
|
||||||
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||||
time->tm_hour, time->tm_min, time->tm_sec);
|
time->tm_hour, time->tm_min, time->tm_sec);
|
||||||
zip_set_archive_comment(zip, comment.data(), comment.size());
|
zip_set_archive_comment(zip, comment.data(), comment.size());
|
||||||
|
@ -189,6 +193,7 @@ auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> boo
|
||||||
|
|
||||||
if(zip_close(zip) == -1) {
|
if(zip_close(zip) == -1) {
|
||||||
_lastError = zip_strerror(zip);
|
_lastError = zip_strerror(zip);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,14 +215,15 @@ void ProfileManager::refreshBackups() {
|
||||||
|
|
||||||
if(!files) {
|
if(!files) {
|
||||||
_lastError = _backupsDirectory + " can't be opened.";
|
_lastError = _backupsDirectory + " can't be opened.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto predicate = [](Containers::StringView file)->bool{
|
auto predicate = [](Containers::StringView file)->bool{
|
||||||
return !file.hasSuffix(".mbprofbackup"_s);
|
return !(file.hasSuffix(".mbprofbackup"_s) || file.hasSuffix(".backup.mbst"));
|
||||||
};
|
};
|
||||||
|
|
||||||
auto files_view = files->except(files->end() - std::remove_if(files->begin(), files->end(), predicate));
|
auto files_view = files->exceptSuffix(files->end() - std::remove_if(files->begin(), files->end(), predicate));
|
||||||
|
|
||||||
int error_code = 0;
|
int error_code = 0;
|
||||||
zip_t* zip = nullptr;
|
zip_t* zip = nullptr;
|
||||||
|
@ -252,21 +258,11 @@ void ProfileManager::refreshBackups() {
|
||||||
|
|
||||||
backup.company = info[0];
|
backup.company = info[0];
|
||||||
|
|
||||||
if(info[1] == "full") {
|
if(info[1].hasPrefix("full")) {
|
||||||
backup.type = ProfileType::FullGame;
|
backup.type = ProfileType::FullGame;
|
||||||
backup.version = ProfileVersion::Legacy;
|
|
||||||
}
|
}
|
||||||
else if(info[1] == "demo") {
|
else if(info[1].hasPrefix("demo")) {
|
||||||
backup.type = ProfileType::Demo;
|
backup.type = ProfileType::Demo;
|
||||||
backup.version = ProfileVersion::Legacy;
|
|
||||||
}
|
|
||||||
else if(info[1] == "full_new") {
|
|
||||||
backup.type = ProfileType::FullGame;
|
|
||||||
backup.version = ProfileVersion::Normal;
|
|
||||||
}
|
|
||||||
else if(info[1] == "demo_new") {
|
|
||||||
backup.type = ProfileType::Demo;
|
|
||||||
backup.version = ProfileVersion::Normal;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -297,6 +293,7 @@ void ProfileManager::refreshBackups() {
|
||||||
auto ProfileManager::deleteBackup(std::size_t index) -> bool {
|
auto ProfileManager::deleteBackup(std::size_t index) -> bool {
|
||||||
if(!Utility::Path::remove(Utility::Path::join(_backupsDirectory, _backups[index].filename))) {
|
if(!Utility::Path::remove(Utility::Path::join(_backupsDirectory, _backups[index].filename))) {
|
||||||
_lastError = "Couldn't delete " + _backups[index].filename;
|
_lastError = "Couldn't delete " + _backups[index].filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,6 +320,7 @@ auto ProfileManager::restoreBackup(std::size_t index) -> bool {
|
||||||
zip_error_t error;
|
zip_error_t error;
|
||||||
zip_error_init_with_code(&error, error_code);
|
zip_error_init_with_code(&error, error_code);
|
||||||
_lastError = zip_error_strerror(&error);
|
_lastError = zip_error_strerror(&error);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,6 +330,7 @@ auto ProfileManager::restoreBackup(std::size_t index) -> bool {
|
||||||
FILE* out = std::fopen(Utility::Path::join(_saveDirectory, file).data(), "wb");
|
FILE* out = std::fopen(Utility::Path::join(_saveDirectory, file).data(), "wb");
|
||||||
if(out == nullptr) {
|
if(out == nullptr) {
|
||||||
_lastError = Utility::format(error_format.data(), file, std::strerror(errno));
|
_lastError = Utility::format(error_format.data(), file, std::strerror(errno));
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,6 +339,7 @@ auto ProfileManager::restoreBackup(std::size_t index) -> bool {
|
||||||
zip_file_t* zf = zip_fopen(zip, file.data(), ZIP_FL_ENC_GUESS);
|
zip_file_t* zf = zip_fopen(zip, file.data(), ZIP_FL_ENC_GUESS);
|
||||||
if(zf == nullptr) {
|
if(zf == nullptr) {
|
||||||
_lastError = Utility::format(error_format.data(), file, zip_strerror(zip));
|
_lastError = Utility::format(error_format.data(), file, zip_strerror(zip));
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,12 +351,14 @@ auto ProfileManager::restoreBackup(std::size_t index) -> bool {
|
||||||
while((bytes_read = zip_fread(zf, buf.data(), buf.size())) > 0) {
|
while((bytes_read = zip_fread(zf, buf.data(), buf.size())) > 0) {
|
||||||
if(std::fwrite(buf.data(), sizeof(char), bytes_read, out) < static_cast<std::size_t>(bytes_read)) {
|
if(std::fwrite(buf.data(), sizeof(char), bytes_read, out) < static_cast<std::size_t>(bytes_read)) {
|
||||||
_lastError = Utility::format(error_format.data(), file, "not enough bytes written.");
|
_lastError = Utility::format(error_format.data(), file, "not enough bytes written.");
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(bytes_read == -1) {
|
if(bytes_read == -1) {
|
||||||
_lastError = Utility::format(error_format.data(), file, "couldn't read bytes from archive.");
|
_lastError = Utility::format(error_format.data(), file, "couldn't read bytes from archive.");
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ struct Backup {
|
||||||
Containers::String filename;
|
Containers::String filename;
|
||||||
Containers::String company;
|
Containers::String company;
|
||||||
ProfileType type;
|
ProfileType type;
|
||||||
ProfileVersion version;
|
|
||||||
struct {
|
struct {
|
||||||
int year;
|
int year;
|
||||||
int month;
|
int month;
|
||||||
|
|
|
@ -16,14 +16,7 @@
|
||||||
|
|
||||||
#include "SaveTool.h"
|
#include "SaveTool.h"
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include <Corrade/Containers/Pair.h>
|
|
||||||
#include <Corrade/Containers/ScopeGuard.h>
|
#include <Corrade/Containers/ScopeGuard.h>
|
||||||
#include <Corrade/Containers/StringStl.h>
|
|
||||||
#include <Corrade/Utility/Format.h>
|
|
||||||
#include <Corrade/Utility/Path.h>
|
|
||||||
#include <Corrade/Utility/String.h>
|
|
||||||
#include <Corrade/Utility/Unicode.h>
|
#include <Corrade/Utility/Unicode.h>
|
||||||
|
|
||||||
#include <Magnum/GL/DebugOutput.h>
|
#include <Magnum/GL/DebugOutput.h>
|
||||||
|
@ -34,19 +27,15 @@
|
||||||
#include <Magnum/ImGuiIntegration/Integration.h>
|
#include <Magnum/ImGuiIntegration/Integration.h>
|
||||||
#include <Magnum/ImGuiIntegration/Context.hpp>
|
#include <Magnum/ImGuiIntegration/Context.hpp>
|
||||||
|
|
||||||
#include <cpr/cpr.h>
|
#include <SDL.h>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
#include <windef.h>
|
|
||||||
#include <winuser.h>
|
|
||||||
#include <processthreadsapi.h>
|
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
#include <shlobj.h>
|
|
||||||
#include <wtsapi32.h>
|
#include <wtsapi32.h>
|
||||||
|
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
@ -61,22 +50,11 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
Configuration{}.setTitle("M.A.S.S. Builder Save Tool " SAVETOOL_VERSION " (\"" SAVETOOL_CODENAME "\")")
|
Configuration{}.setTitle("M.A.S.S. Builder Save Tool " SAVETOOL_VERSION " (\"" SAVETOOL_CODENAME "\")")
|
||||||
.setSize({960, 720})}
|
.setSize({960, 720})}
|
||||||
{
|
{
|
||||||
#ifdef SAVETOOL_DEBUG_BUILD
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
tweak.enable(""_s, "../../"_s);
|
tweak.enable("", "../../");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(SDL_VERSION_ATLEAST(2, 0, 5)) {
|
|
||||||
if(SDL_SetHintWithPriority(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1", SDL_HINT_OVERRIDE) == SDL_TRUE) {
|
|
||||||
Utility::Debug{} << "Clickthrough is available."_s;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Utility::Warning{} << "Clickthrough is not available (hint couldn't be set)."_s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Utility::Warning{} << "Clickthrough is not available (SDL2 is too old)."_s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
LOG_INFO("Configuring OpenGL renderer.");
|
||||||
GL::Renderer::enable(GL::Renderer::Feature::Blending);
|
GL::Renderer::enable(GL::Renderer::Feature::Blending);
|
||||||
GL::Renderer::enable(GL::Renderer::Feature::ScissorTest);
|
GL::Renderer::enable(GL::Renderer::Feature::ScissorTest);
|
||||||
GL::Renderer::disable(GL::Renderer::Feature::FaceCulling);
|
GL::Renderer::disable(GL::Renderer::Feature::FaceCulling);
|
||||||
|
@ -86,8 +64,20 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add,
|
GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add,
|
||||||
GL::Renderer::BlendEquation::Add);
|
GL::Renderer::BlendEquation::Add);
|
||||||
|
|
||||||
initialiseGui();
|
LOG_INFO("Configuring SDL2.");
|
||||||
|
#if SDL_VERSION_ATLEAST(2,0,5)
|
||||||
|
if(SDL_SetHintWithPriority(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1", SDL_HINT_OVERRIDE) == SDL_TRUE) {
|
||||||
|
LOG_INFO("Clickthrough is enabled.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG_WARNING("Clickthrough is disabled.");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
LOG_WARNING_FORMAT("Clickthrough is disabled: SDL2 version is too old ({}.{}.{})",
|
||||||
|
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LOG_INFO("Registering custom events.");
|
||||||
if((_initEventId = SDL_RegisterEvents(3)) == UnsignedInt(-1)) {
|
if((_initEventId = SDL_RegisterEvents(3)) == UnsignedInt(-1)) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
"SDL_RegisterEvents() failed in SaveTool::SaveTool(). Exiting...", window());
|
"SDL_RegisterEvents() failed in SaveTool::SaveTool(). Exiting...", window());
|
||||||
|
@ -98,20 +88,27 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
_updateEventId = _initEventId + 1;
|
_updateEventId = _initEventId + 1;
|
||||||
_fileEventId = _initEventId + 2;
|
_fileEventId = _initEventId + 2;
|
||||||
|
|
||||||
initialiseToolDirectories();
|
LOG_INFO("Initialising the timer subsystem.");
|
||||||
|
if(SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
|
||||||
if(!findGameDataDirectory()) {
|
LOG_ERROR(SDL_GetError());
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", _lastError.data(), window());
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app",
|
||||||
|
SDL_GetError(), window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_configDir = Utility::Path::join(_gameDataDir, "Saved/Config/WindowsNoEditor");
|
initialiseGui();
|
||||||
_saveDir = Utility::Path::join(_gameDataDir, "Saved/SaveGames");
|
|
||||||
_screenshotsDir = Utility::Path::join(_gameDataDir, "Saved/Screenshots/WindowsNoEditor");
|
|
||||||
|
|
||||||
if(SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
|
if(!initialiseToolDirectories()) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", SDL_GetError(), window());
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app",
|
||||||
|
_lastError.data(), window());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!findGameDataDirectory()) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app",
|
||||||
|
_lastError.data(), window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -123,6 +120,7 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
return interval;
|
return interval;
|
||||||
}, this);
|
}, this);
|
||||||
if(_gameCheckTimerId == 0) {
|
if(_gameCheckTimerId == 0) {
|
||||||
|
LOG_ERROR(SDL_GetError());
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), window());
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
return;
|
return;
|
||||||
|
@ -130,22 +128,11 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
|
|
||||||
initialiseConfiguration();
|
initialiseConfiguration();
|
||||||
|
|
||||||
switch(_framelimit) {
|
LOG_INFO("Initialising update checker.");
|
||||||
case Framelimit::Vsync:
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
setSwapInterval(1);
|
|
||||||
break;
|
|
||||||
case Framelimit::HalfVsync:
|
|
||||||
setSwapInterval(2);
|
|
||||||
break;
|
|
||||||
case Framelimit::FpsCap:
|
|
||||||
setSwapInterval(0);
|
|
||||||
setMinimalLoopPeriod(1000/_fpsCap);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_checkUpdatesOnStartup) {
|
if(_checkUpdatesOnStartup) {
|
||||||
_updateThread = std::thread{[this]{ checkForUpdates(); }};
|
|
||||||
_queue.addToast(Toast::Type::Default, "Checking for updates..."_s);
|
_queue.addToast(Toast::Type::Default, "Checking for updates..."_s);
|
||||||
|
_updateThread = std::thread{[this]{ checkForUpdates(); }};
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GL::Context::current().isExtensionSupported<GL::Extensions::KHR::debug>() &&
|
if(GL::Context::current().isExtensionSupported<GL::Extensions::KHR::debug>() &&
|
||||||
|
@ -158,81 +145,57 @@ SaveTool::SaveTool(const Arguments& arguments):
|
||||||
_uiState = UiState::Initialising;
|
_uiState = UiState::Initialising;
|
||||||
_initThread = std::thread{[this]{ initialiseManager(); }};
|
_initThread = std::thread{[this]{ initialiseManager(); }};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_timeline.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveTool::~SaveTool() {
|
SaveTool::~SaveTool() {
|
||||||
|
LOG_INFO("Cleaning up.");
|
||||||
|
|
||||||
|
LOG_INFO("Shutting libcurl down.");
|
||||||
|
curl_global_cleanup();
|
||||||
|
|
||||||
SDL_RemoveTimer(_gameCheckTimerId);
|
SDL_RemoveTimer(_gameCheckTimerId);
|
||||||
|
|
||||||
|
LOG_INFO("Saving the configuration.");
|
||||||
|
|
||||||
_conf.setValue("cheat_mode"_s, _cheatMode);
|
_conf.setValue("cheat_mode"_s, _cheatMode);
|
||||||
_conf.setValue("unsafe_mode"_s, _unsafeMode);
|
_conf.setValue("advanced_mode"_s, _advancedMode);
|
||||||
_conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup);
|
_conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup);
|
||||||
_conf.setValue("skip_disclaimer"_s, _skipDisclaimer);
|
_conf.setValue("skip_disclaimer"_s, _skipDisclaimer);
|
||||||
|
_conf.setValue("swap_interval"_s, _swapInterval);
|
||||||
switch(_framelimit) {
|
_conf.setValue("fps_cap"_s, _fpsCap);
|
||||||
case Framelimit::Vsync:
|
|
||||||
_conf.setValue("frame_limit"_s, "vsync"_s);
|
|
||||||
break;
|
|
||||||
case Framelimit::HalfVsync:
|
|
||||||
_conf.setValue("frame_limit"_s, "half_vsync"_s);
|
|
||||||
break;
|
|
||||||
case Framelimit::FpsCap:
|
|
||||||
_conf.setValue<UnsignedInt>("frame_limit"_s, _fpsCap);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
_conf.save();
|
_conf.save();
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
LOG_INFO("Exiting.");
|
||||||
const std::string&,
|
|
||||||
const std::string& filename,
|
|
||||||
efsw::Action action,
|
|
||||||
std::string old_filename)
|
|
||||||
{
|
|
||||||
SDL_Event event;
|
|
||||||
SDL_zero(event);
|
|
||||||
event.type = _fileEventId;
|
|
||||||
|
|
||||||
if(watch_id == _watchIDs[StagingDir] && Utility::String::endsWith(filename, ".sav")) {
|
|
||||||
event.user.code = StagedUpdate;
|
|
||||||
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, _currentProfile->account() + ".sav")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.user.code = action;
|
|
||||||
event.user.data1 = Containers::String{Containers::AllocatedInit, filename.c_str()}.release();
|
|
||||||
if(action == efsw::Actions::Moved) {
|
|
||||||
event.user.data2 = Containers::String{old_filename}.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawEvent() {
|
void SaveTool::drawEvent() {
|
||||||
#ifdef SAVETOOL_DEBUG_BUILD
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
tweak.update();
|
tweak.update();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);
|
GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);
|
||||||
|
|
||||||
drawImGui();
|
drawImGui();
|
||||||
|
|
||||||
swapBuffers();
|
swapBuffers();
|
||||||
|
|
||||||
|
if(_swapInterval == 0 && _fpsCap < 301.0f) {
|
||||||
|
while(_timeline.currentFrameDuration() < (1.0f / _fpsCap));
|
||||||
|
}
|
||||||
|
|
||||||
redraw();
|
redraw();
|
||||||
|
|
||||||
|
_timeline.nextFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::viewportEvent(ViewportEvent& event) {
|
void SaveTool::viewportEvent(ViewportEvent& event) {
|
||||||
GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()});
|
GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()});
|
||||||
|
|
||||||
_imgui.relayout(event.windowSize());
|
const Vector2 size = Vector2{windowSize()}/dpiScaling();
|
||||||
|
_imgui.relayout(size, windowSize(), framebufferSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::keyPressEvent(KeyEvent& event) {
|
void SaveTool::keyPressEvent(KeyEvent& event) {
|
||||||
|
@ -278,354 +241,6 @@ void SaveTool::anyEvent(SDL_Event& event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::initEvent(SDL_Event& event) {
|
|
||||||
_initThread.join();
|
|
||||||
|
|
||||||
switch(event.user.code) {
|
|
||||||
case InitSuccess:
|
|
||||||
_uiState = UiState::ProfileManager;
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
break;
|
|
||||||
case ProfileManagerFailure:
|
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising ProfileManager", _profileManager->lastError().data(), window());
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::updateCheckEvent(SDL_Event& event) {
|
|
||||||
_updateThread.join();
|
|
||||||
|
|
||||||
cpr::Response r{std::move(*static_cast<cpr::Response*>(event.user.data1))};
|
|
||||||
delete static_cast<cpr::Response*>(event.user.data1);
|
|
||||||
|
|
||||||
if(r.elapsed > 10.0) {
|
|
||||||
_queue.addToast(Toast::Type::Error, "The request timed out."_s);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(r.status_code != 200) {
|
|
||||||
_queue.addToast(Toast::Type::Error, Utility::format("The request failed with error code {}: {}", r.status_code, r.reason.c_str()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
using json = nlohmann::json;
|
|
||||||
|
|
||||||
json response = json::parse(r.text);
|
|
||||||
|
|
||||||
struct Version {
|
|
||||||
explicit Version(Containers::StringView str) {
|
|
||||||
std::size_t start_point = 0;
|
|
||||||
|
|
||||||
if(str[0] == 'v') {
|
|
||||||
start_point++;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto components = Containers::StringView{str.data() + start_point}.split('.');
|
|
||||||
|
|
||||||
major = std::strtol(components[0].data(), nullptr, 10);
|
|
||||||
minor = std::strtol(components[1].data(), nullptr, 10);
|
|
||||||
patch = std::strtol(components[2].data(), nullptr, 10);
|
|
||||||
}
|
|
||||||
Int major;
|
|
||||||
Int minor;
|
|
||||||
Int patch;
|
|
||||||
|
|
||||||
bool operator==(const Version& other) const {
|
|
||||||
return (major == other.major) && (minor == other.minor) && (patch == other.patch);
|
|
||||||
}
|
|
||||||
bool operator>(const Version& other) const {
|
|
||||||
return ( major * 10000 + minor * 100 + patch) >
|
|
||||||
(other.major * 10000 + other.minor * 100 + other.patch);
|
|
||||||
}
|
|
||||||
operator Containers::String() const {
|
|
||||||
return Utility::format("{}.{}.{}", major, minor, patch);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Version current_ver{SAVETOOL_VERSION};
|
|
||||||
|
|
||||||
for(auto& release : response) {
|
|
||||||
if(release["prerelease"] == true) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Version latest_ver{release["tag_name"].get<std::string>().c_str()};
|
|
||||||
|
|
||||||
if(latest_ver > current_ver || (latest_ver == current_ver && Utility::String::endsWith(SAVETOOL_VERSION, "-pre"))) {
|
|
||||||
_queue.addToast(Toast::Type::Warning, "Your version is out of date.\nCheck the settings for more information."_s,
|
|
||||||
std::chrono::milliseconds{5000});
|
|
||||||
_updateAvailable = true;
|
|
||||||
_latestVersion = latest_ver;
|
|
||||||
_releaseLink = to_string(release["html_url"]);
|
|
||||||
_downloadLink = to_string(release["assets"][0]["browser_download_url"]);
|
|
||||||
}
|
|
||||||
else if(latest_ver == current_ver || (current_ver > latest_ver && Utility::String::endsWith(SAVETOOL_VERSION, "-pre"))) {
|
|
||||||
_queue.addToast(Toast::Type::Success, "The application is already up to date."_s);
|
|
||||||
}
|
|
||||||
else if(current_ver > latest_ver) {
|
|
||||||
_queue.addToast(Toast::Type::Warning, "Your version is more recent than the latest one in the repo. How???"_s);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
|
||||||
if(event.user.code == StagedUpdate) {
|
|
||||||
_massManager->refreshStagedMasses();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Containers::String filename{static_cast<char*>(event.user.data1), std::strlen(static_cast<char*>(event.user.data1)), nullptr};
|
|
||||||
Containers::String old_filename;
|
|
||||||
|
|
||||||
Int index = 0;
|
|
||||||
Int 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);
|
|
||||||
}
|
|
||||||
static bool is_moved_after_save = false;
|
|
||||||
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;
|
|
||||||
_profileManager->refreshProfiles();
|
|
||||||
}
|
|
||||||
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(!is_moved_after_save) {
|
|
||||||
is_moved_after_save = false;
|
|
||||||
_currentMass->setDirty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case FileMoved:
|
|
||||||
if(is_unit) {
|
|
||||||
if(old_filename.hasSuffix(".tmp"_s)) {
|
|
||||||
is_moved_after_save = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::initialiseConfiguration() {
|
|
||||||
if(_conf.hasValue("cheat_mode"_s)) {
|
|
||||||
_cheatMode = _conf.value<bool>("cheat_mode"_s);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_conf.setValue("cheat_mode"_s, _cheatMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_conf.hasValue("unsafe_mode"_s)) {
|
|
||||||
_unsafeMode = _conf.value<bool>("unsafe_mode"_s);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_conf.setValue("unsafe_mode"_s, _unsafeMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_conf.hasValue("startup_update_check"_s)) {
|
|
||||||
_checkUpdatesOnStartup = _conf.value<bool>("startup_update_check"_s);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_conf.hasValue("skip_disclaimer"_s)) {
|
|
||||||
_skipDisclaimer = _conf.value<bool>("skip_disclaimer"_s);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_conf.setValue("skip_disclaimer"_s, _skipDisclaimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(_conf.hasValue("frame_limit"_s)) {
|
|
||||||
std::string frame_limit = _conf.value("frame_limit"_s);
|
|
||||||
if(frame_limit == "vsync"_s) {
|
|
||||||
_framelimit = Framelimit::Vsync;
|
|
||||||
}
|
|
||||||
else if(frame_limit == "half_vsync"_s) {
|
|
||||||
_framelimit = Framelimit::HalfVsync;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_framelimit = Framelimit::FpsCap;
|
|
||||||
_fpsCap = std::stoul(frame_limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
_conf.setValue("frame_limit"_s, "vsync"_s);
|
|
||||||
}
|
|
||||||
|
|
||||||
_conf.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::initialiseGui() {
|
|
||||||
ImGui::CreateContext();
|
|
||||||
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
auto reg_font = _rs.getRaw("SourceSansPro-Regular.ttf"_s);
|
|
||||||
ImFontConfig font_config;
|
|
||||||
font_config.FontDataOwnedByAtlas = false;
|
|
||||||
std::strcpy(font_config.Name, "Source Sans Pro");
|
|
||||||
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(reg_font.data()), reg_font.size(), 20.0f, &font_config);
|
|
||||||
|
|
||||||
auto icon_font = _rs.getRaw(FONT_ICON_FILE_NAME_FAS);
|
|
||||||
static const ImWchar icon_range[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
|
|
||||||
ImFontConfig icon_config;
|
|
||||||
icon_config.FontDataOwnedByAtlas = false;
|
|
||||||
icon_config.MergeMode = true;
|
|
||||||
icon_config.PixelSnapH = true;
|
|
||||||
icon_config.OversampleH = icon_config.OversampleV = 1;
|
|
||||||
icon_config.GlyphMinAdvanceX = 18.0f;
|
|
||||||
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(icon_font.data()), icon_font.size(), 16.0f, &icon_config, icon_range);
|
|
||||||
|
|
||||||
auto brand_font = _rs.getRaw(FONT_ICON_FILE_NAME_FAB);
|
|
||||||
static const ImWchar brand_range[] = { ICON_MIN_FAB, ICON_MAX_FAB, 0 };
|
|
||||||
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(brand_font.data()), brand_font.size(), 16.0f, &icon_config, brand_range);
|
|
||||||
|
|
||||||
auto mono_font = _rs.getRaw("SourceCodePro-Regular.ttf"_s);
|
|
||||||
ImVector<ImWchar> range;
|
|
||||||
ImFontGlyphRangesBuilder builder;
|
|
||||||
builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
|
|
||||||
builder.AddChar(u'š'); // This allows displaying Vladimír Vondruš' name in Corrade's and Magnum's licences.
|
|
||||||
builder.BuildRanges(&range);
|
|
||||||
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(mono_font.data()), mono_font.size(), 18.0f, &font_config, range.Data);
|
|
||||||
|
|
||||||
_imgui = ImGuiIntegration::Context(*ImGui::GetCurrentContext(), windowSize());
|
|
||||||
|
|
||||||
io.IniFilename = nullptr;
|
|
||||||
|
|
||||||
ImGuiStyle& style = ImGui::GetStyle();
|
|
||||||
|
|
||||||
style.WindowTitleAlign = {0.5f, 0.5f};
|
|
||||||
style.FrameRounding = 3.2f;
|
|
||||||
style.Colors[ImGuiCol_WindowBg] = ImColor(0xff1f1f1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::initialiseManager() {
|
|
||||||
SDL_Event event;
|
|
||||||
SDL_zero(event);
|
|
||||||
event.type = _initEventId;
|
|
||||||
|
|
||||||
_profileManager.emplace(_saveDir, _backupsDir);
|
|
||||||
if(!_profileManager->ready()) {
|
|
||||||
event.user.code = ProfileManagerFailure;
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.user.code = InitSuccess;
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::initialiseToolDirectories() {
|
|
||||||
_backupsDir = Utility::Path::join(Utility::Path::split(*Utility::Path::executableLocation()).first(), "backups");
|
|
||||||
_stagingDir = Utility::Path::join(Utility::Path::split(*Utility::Path::executableLocation()).first(), "staging");
|
|
||||||
//_armouryDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "armoury");
|
|
||||||
//_armoursDir = Utility::Directory::join(_armouryDir, "armours");
|
|
||||||
//_weaponsDir = Utility::Directory::join(_armouryDir, "weapons");
|
|
||||||
//_stylesDir = Utility::Directory::join(_armouryDir, "styles");
|
|
||||||
|
|
||||||
if(!Utility::Path::exists(_backupsDir)) {
|
|
||||||
Utility::Path::make(_backupsDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!Utility::Path::exists(_stagingDir)) {
|
|
||||||
Utility::Path::make(_stagingDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if(!Utility::Directory::exists(_armouryDir)) {
|
|
||||||
// Utility::Directory::mkpath(_armouryDir);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if(!Utility::Directory::exists(_armoursDir)) {
|
|
||||||
// Utility::Directory::mkpath(_armoursDir);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if(!Utility::Directory::exists(_weaponsDir)) {
|
|
||||||
// Utility::Directory::mkpath(_weaponsDir);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//if(!Utility::Directory::exists(_stylesDir)) {
|
|
||||||
// Utility::Directory::mkpath(_stylesDir);
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SaveTool::findGameDataDirectory() -> bool {
|
|
||||||
wchar_t* localappdata_path = nullptr;
|
|
||||||
Containers::ScopeGuard guard{localappdata_path, CoTaskMemFree};
|
|
||||||
if(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_NO_APPCONTAINER_REDIRECTION, nullptr, &localappdata_path) != S_OK)
|
|
||||||
{
|
|
||||||
_lastError = "SHGetKnownFolderPath() failed in SaveTool::findGameDataDirectory()"_s;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
_gameDataDir = Utility::Path::join(Utility::Path::fromNativeSeparators(Utility::Unicode::narrow(localappdata_path)), "MASS_Builder"_s);
|
|
||||||
|
|
||||||
if(!Utility::Path::exists(_gameDataDir)) {
|
|
||||||
_lastError = _gameDataDir + " wasn't found. Make sure to play the game at least once."_s;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::initialiseMassManager() {
|
|
||||||
_massManager.emplace(_saveDir, _currentProfile->account(), _currentProfile->isDemo(), _stagingDir);
|
|
||||||
initialiseFileWatcher();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::initialiseFileWatcher() {
|
|
||||||
_fileWatcher.emplace();
|
|
||||||
_watchIDs[SaveDir] = _fileWatcher->addWatch(_saveDir, this, false);
|
|
||||||
_watchIDs[StagingDir] = _fileWatcher->addWatch(_stagingDir, this, false);
|
|
||||||
_fileWatcher->watch();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::drawImGui() {
|
void SaveTool::drawImGui() {
|
||||||
_imgui.newFrame();
|
_imgui.newFrame();
|
||||||
|
|
||||||
|
@ -668,7 +283,7 @@ void SaveTool::drawGui() {
|
||||||
drawAbout();
|
drawAbout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SAVETOOL_DEBUG_BUILD
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
if(_demoWindow) {
|
if(_demoWindow) {
|
||||||
ImGui::ShowDemoWindow(&_demoWindow);
|
ImGui::ShowDemoWindow(&_demoWindow);
|
||||||
}
|
}
|
||||||
|
@ -680,7 +295,7 @@ void SaveTool::drawGui() {
|
||||||
if(_metricsWindow) {
|
if(_metricsWindow) {
|
||||||
ImGui::ShowMetricsWindow(&_metricsWindow);
|
ImGui::ShowMetricsWindow(&_metricsWindow);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_queue.draw(windowSize());
|
_queue.draw(windowSize());
|
||||||
}
|
}
|
||||||
|
@ -699,11 +314,11 @@ void SaveTool::drawDisclaimer() {
|
||||||
|
|
||||||
ImGui::TextUnformatted("Before you start using the app, there are a few things you should know:");
|
ImGui::TextUnformatted("Before you start using the app, there are a few things you should know:");
|
||||||
|
|
||||||
ImGui::PushTextWrapPos(windowSize().x() * 0.67f);
|
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.67f);
|
||||||
|
|
||||||
ImGui::Bullet();
|
ImGui::Bullet();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::TextUnformatted("For this application to work properly, it is recommended to disable Steam Cloud syncing for the game. To disable it, right-click the game in your Steam library, click \"Properties\", go to the \"General\" tab, and uncheck \"Keep game saves in the Steam Cloud for M.A.S.S. Builder\".");
|
ImGui::TextUnformatted(R"(For this application to work properly, it is recommended to disable Steam Cloud syncing for the game. To disable it, right-click the game in your Steam library, click "Properties", go to the "General" tab, and uncheck "Keep game saves in the Steam Cloud for M.A.S.S. Builder".)");
|
||||||
|
|
||||||
ImGui::Bullet();
|
ImGui::Bullet();
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -822,14 +437,3 @@ void SaveTool::checkGameState() {
|
||||||
_gameState = GameState::Unknown;
|
_gameState = GameState::Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::checkForUpdates() {
|
|
||||||
cpr::Response r = cpr::Get(cpr::Url{"https://williamjcm.ovh/git/api/v1/repos/williamjcm/MassBuilderSaveTool/releases"}, cpr::Timeout{10000});
|
|
||||||
|
|
||||||
SDL_Event event;
|
|
||||||
SDL_zero(event);
|
|
||||||
event.type = _updateEventId;
|
|
||||||
event.user.code = r.status_code;
|
|
||||||
event.user.data1 = new cpr::Response{std::move(r)};
|
|
||||||
SDL_PushEvent(&event);
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,11 +23,15 @@
|
||||||
#include <Corrade/Containers/String.h>
|
#include <Corrade/Containers/String.h>
|
||||||
#include <Corrade/Utility/Configuration.h>
|
#include <Corrade/Utility/Configuration.h>
|
||||||
#include <Corrade/Utility/Resource.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/Platform/Sdl2Application.h>
|
||||||
#include <Magnum/ImGuiIntegration/Context.h>
|
#include <Magnum/ImGuiIntegration/Context.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL_timer.h>
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
||||||
|
@ -39,8 +43,6 @@
|
||||||
#include "../ToastQueue/ToastQueue.h"
|
#include "../ToastQueue/ToastQueue.h"
|
||||||
|
|
||||||
#ifdef SAVETOOL_DEBUG_BUILD
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
#include <Corrade/Utility/Tweakable.h>
|
|
||||||
|
|
||||||
#define tw CORRADE_TWEAKABLE
|
#define tw CORRADE_TWEAKABLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -81,6 +83,12 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
ProfileManagerFailure
|
ProfileManagerFailure
|
||||||
};
|
};
|
||||||
void initEvent(SDL_Event& event);
|
void initEvent(SDL_Event& event);
|
||||||
|
|
||||||
|
enum UpdateCheckStatus : Int {
|
||||||
|
CurlInitFailed = 0,
|
||||||
|
CurlError = 1,
|
||||||
|
CurlTimeout = 2,
|
||||||
|
};
|
||||||
void updateCheckEvent(SDL_Event& event);
|
void updateCheckEvent(SDL_Event& event);
|
||||||
|
|
||||||
enum FileEventType: Int {
|
enum FileEventType: Int {
|
||||||
|
@ -88,7 +96,7 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
FileDeleted = efsw::Action::Delete,
|
FileDeleted = efsw::Action::Delete,
|
||||||
FileModified = efsw::Action::Modified,
|
FileModified = efsw::Action::Modified,
|
||||||
FileMoved = efsw::Action::Moved,
|
FileMoved = efsw::Action::Moved,
|
||||||
StagedUpdate
|
StagedUpdate = 1 << 3
|
||||||
};
|
};
|
||||||
void fileUpdateEvent(SDL_Event& event);
|
void fileUpdateEvent(SDL_Event& event);
|
||||||
|
|
||||||
|
@ -96,7 +104,7 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
void initialiseConfiguration();
|
void initialiseConfiguration();
|
||||||
void initialiseGui();
|
void initialiseGui();
|
||||||
void initialiseManager();
|
void initialiseManager();
|
||||||
void initialiseToolDirectories();
|
auto initialiseToolDirectories() -> bool;
|
||||||
auto findGameDataDirectory() -> bool;
|
auto findGameDataDirectory() -> bool;
|
||||||
void initialiseMassManager();
|
void initialiseMassManager();
|
||||||
void initialiseFileWatcher();
|
void initialiseFileWatcher();
|
||||||
|
@ -160,23 +168,16 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
template<typename Functor, typename... Args>
|
template<typename Functor, typename... Args>
|
||||||
auto drawUnsafeWidget(Functor func, Args... args) -> bool {
|
auto drawUnsafeWidget(Functor func, Args... args) -> bool {
|
||||||
GameState game_state = _gameState; // Copying the value to reduce the risk of a data race.
|
GameState game_state = _gameState; // Copying the value to reduce the risk of a data race.
|
||||||
if(!_unsafeMode && game_state != GameState::NotRunning) {
|
ImGui::BeginDisabled(game_state != GameState::NotRunning);
|
||||||
ImGui::BeginDisabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool result = func(std::forward<Args>(args)...);
|
bool result = func(std::forward<Args>(args)...);
|
||||||
|
ImGui::EndDisabled();
|
||||||
if(!_unsafeMode && game_state != GameState::NotRunning) {
|
|
||||||
ImGui::EndDisabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} // Obviously, should only be used with ImGui widgets that return a bool.
|
} // 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...
|
// Also, func should be a lambda if there are any default arguments, like ImGui::Button(), etc...
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void drawUnsafeText(Containers::StringView text, Args... args) { // Alternative to the above, for ImGui::Text*() variants.
|
void drawUnsafeText(const char* text, Args... args) { // Alternative to the above, for ImGui::Text*() variants.
|
||||||
if(!_unsafeMode && _gameState != GameState::NotRunning) {
|
if(_gameState != GameState::NotRunning) {
|
||||||
ImGui::TextDisabled(text, std::forward<Args>(args)...);
|
ImGui::TextDisabled(text, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -211,11 +212,11 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
} _uiState{UiState::Disclaimer};
|
} _uiState{UiState::Disclaimer};
|
||||||
|
|
||||||
bool _aboutPopup{false};
|
bool _aboutPopup{false};
|
||||||
#ifdef SAVETOOL_DEBUG_BUILD
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
bool _demoWindow{false};
|
bool _demoWindow{false};
|
||||||
bool _styleEditor{false};
|
bool _styleEditor{false};
|
||||||
bool _metricsWindow{false};
|
bool _metricsWindow{false};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ToastQueue _queue;
|
ToastQueue _queue;
|
||||||
|
|
||||||
|
@ -261,22 +262,18 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
};
|
};
|
||||||
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
||||||
|
|
||||||
enum class Framelimit: UnsignedByte {
|
int _swapInterval = 1;
|
||||||
Vsync,
|
float _fpsCap = 60.0f;
|
||||||
HalfVsync,
|
|
||||||
FpsCap
|
|
||||||
} _framelimit{Framelimit::Vsync};
|
|
||||||
UnsignedInt _fpsCap{60};
|
|
||||||
|
|
||||||
bool _skipDisclaimer{false};
|
bool _skipDisclaimer{false};
|
||||||
bool _checkUpdatesOnStartup{true};
|
bool _checkUpdatesOnStartup{true};
|
||||||
bool _unsafeMode{false};
|
|
||||||
|
|
||||||
bool _updateAvailable{false};
|
bool _updateAvailable{false};
|
||||||
Containers::String _latestVersion;
|
Containers::String _latestVersion;
|
||||||
Containers::String _releaseLink;
|
Containers::String _releaseLink;
|
||||||
Containers::String _downloadLink;
|
Containers::String _downloadLink;
|
||||||
|
|
||||||
|
bool _modifiedBySaveTool{false};
|
||||||
bool _jointsDirty{false};
|
bool _jointsDirty{false};
|
||||||
bool _stylesDirty{false};
|
bool _stylesDirty{false};
|
||||||
bool _eyeFlareDirty{false};
|
bool _eyeFlareDirty{false};
|
||||||
|
@ -294,4 +291,7 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
||||||
bool _eLaunchersDirty{false};
|
bool _eLaunchersDirty{false};
|
||||||
|
|
||||||
bool _cheatMode{false};
|
bool _cheatMode{false};
|
||||||
|
bool _advancedMode{false};
|
||||||
|
|
||||||
|
Timeline _timeline;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
// 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 <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 "SaveTool.h"
|
||||||
|
|
||||||
|
void SaveTool::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())) {
|
||||||
|
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 SaveTool::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) {
|
||||||
|
_massManager->refreshStagedMass(filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::String old_filename;
|
||||||
|
|
||||||
|
Int index = 0;
|
||||||
|
Int 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,280 @@
|
||||||
|
// 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 <Corrade/Containers/Pair.h>
|
||||||
|
#include <Corrade/Containers/ScopeGuard.h>
|
||||||
|
#include <Corrade/Utility/Path.h>
|
||||||
|
#include <Corrade/Utility/Unicode.h>
|
||||||
|
|
||||||
|
#include <SDL_events.h>
|
||||||
|
#include <SDL_messagebox.h>
|
||||||
|
|
||||||
|
#include <shlobj.h>
|
||||||
|
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "SaveTool.h"
|
||||||
|
|
||||||
|
void SaveTool::initEvent(SDL_Event& event) {
|
||||||
|
_initThread.join();
|
||||||
|
|
||||||
|
switch(event.user.code) {
|
||||||
|
case InitSuccess:
|
||||||
|
_uiState = UiState::ProfileManager;
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
break;
|
||||||
|
case ProfileManagerFailure:
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error ",
|
||||||
|
_profileManager->lastError().data(), window());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveTool::initialiseConfiguration() {
|
||||||
|
LOG_INFO("Reading configuration file.");
|
||||||
|
|
||||||
|
if(_conf.hasValue("cheat_mode"_s)) {
|
||||||
|
_cheatMode = _conf.value<bool>("cheat_mode"_s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("cheat_mode"_s, _cheatMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("advanced_mode"_s)) {
|
||||||
|
_advancedMode = _conf.value<bool>("advanced_mode"_s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("advanced_mode"_s, _advancedMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("startup_update_check"_s)) {
|
||||||
|
_checkUpdatesOnStartup = _conf.value<bool>("startup_update_check"_s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("skip_disclaimer"_s)) {
|
||||||
|
_skipDisclaimer = _conf.value<bool>("skip_disclaimer"_s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("skip_disclaimer"_s, _skipDisclaimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("swap_interval"_s)) {
|
||||||
|
_swapInterval = _conf.value<int>("swap_interval"_s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("swap_interval"_s, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("fps_cap"_s)) {
|
||||||
|
_fpsCap = _conf.value<float>("fps_cap");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("fps_cap", 60.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("frame_limit"_s)) {
|
||||||
|
std::string frame_limit = _conf.value("frame_limit"_s);
|
||||||
|
if(frame_limit == "half_vsync"_s) {
|
||||||
|
_swapInterval = 2;
|
||||||
|
}
|
||||||
|
_conf.removeValue("frame_limit"_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSwapInterval(_swapInterval);
|
||||||
|
if(_swapInterval == 0) {
|
||||||
|
setMinimalLoopPeriod(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
_conf.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveTool::initialiseGui() {
|
||||||
|
LOG_INFO("Initialising Dear ImGui.");
|
||||||
|
|
||||||
|
ImGui::CreateContext();
|
||||||
|
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
const auto size = Vector2{windowSize()}/dpiScaling();
|
||||||
|
|
||||||
|
auto reg_font = _rs.getRaw("SourceSansPro-Regular.ttf"_s);
|
||||||
|
ImFontConfig font_config;
|
||||||
|
font_config.FontDataOwnedByAtlas = false;
|
||||||
|
std::strcpy(font_config.Name, "Source Sans Pro");
|
||||||
|
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(reg_font.data()), int(reg_font.size()),
|
||||||
|
20.0f * Float(framebufferSize().x()) / size.x(), &font_config);
|
||||||
|
|
||||||
|
auto icon_font = _rs.getRaw(FONT_ICON_FILE_NAME_FAS);
|
||||||
|
static const ImWchar icon_range[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
|
||||||
|
ImFontConfig icon_config;
|
||||||
|
icon_config.FontDataOwnedByAtlas = false;
|
||||||
|
icon_config.MergeMode = true;
|
||||||
|
icon_config.PixelSnapH = true;
|
||||||
|
icon_config.OversampleH = icon_config.OversampleV = 1;
|
||||||
|
icon_config.GlyphMinAdvanceX = 18.0f;
|
||||||
|
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(icon_font.data()), int(icon_font.size()),
|
||||||
|
16.0f * Float(framebufferSize().x()) / size.x(), &icon_config, icon_range);
|
||||||
|
|
||||||
|
auto brand_font = _rs.getRaw(FONT_ICON_FILE_NAME_FAB);
|
||||||
|
static const ImWchar brand_range[] = { ICON_MIN_FAB, ICON_MAX_FAB, 0 };
|
||||||
|
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(brand_font.data()), int(brand_font.size()),
|
||||||
|
16.0f * Float(framebufferSize().x()) / size.x(), &icon_config, brand_range);
|
||||||
|
|
||||||
|
auto mono_font = _rs.getRaw("SourceCodePro-Regular.ttf"_s);
|
||||||
|
ImVector<ImWchar> range;
|
||||||
|
ImFontGlyphRangesBuilder builder;
|
||||||
|
builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
|
||||||
|
builder.AddChar(u'š'); // This allows displaying Vladimír Vondruš' name in Corrade's and Magnum's licences.
|
||||||
|
builder.BuildRanges(&range);
|
||||||
|
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(mono_font.data()), int(mono_font.size()),
|
||||||
|
18.0f * Float(framebufferSize().x()) / size.x(), &font_config, range.Data);
|
||||||
|
|
||||||
|
_imgui = ImGuiIntegration::Context(*ImGui::GetCurrentContext(), windowSize());
|
||||||
|
|
||||||
|
io.IniFilename = nullptr;
|
||||||
|
|
||||||
|
ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
|
||||||
|
style.WindowTitleAlign = {0.5f, 0.5f};
|
||||||
|
style.FrameRounding = 3.2f;
|
||||||
|
style.Colors[ImGuiCol_WindowBg] = ImColor(0xff1f1f1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveTool::initialiseManager() {
|
||||||
|
LOG_INFO("Initialising the profile manager.");
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
SDL_zero(event);
|
||||||
|
event.type = _initEventId;
|
||||||
|
|
||||||
|
_profileManager.emplace(_saveDir, _backupsDir);
|
||||||
|
if(!_profileManager->ready()) {
|
||||||
|
event.user.code = ProfileManagerFailure;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.user.code = InitSuccess;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SaveTool::initialiseToolDirectories() -> bool {
|
||||||
|
LOG_INFO("Initialising Save Tool directories.");
|
||||||
|
|
||||||
|
_backupsDir = Utility::Path::join(Utility::Path::split(*Utility::Path::executableLocation()).first(), "backups");
|
||||||
|
_stagingDir = Utility::Path::join(Utility::Path::split(*Utility::Path::executableLocation()).first(), "staging");
|
||||||
|
//_armouryDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "armoury");
|
||||||
|
//_armoursDir = Utility::Directory::join(_armouryDir, "armours");
|
||||||
|
//_weaponsDir = Utility::Directory::join(_armouryDir, "weapons");
|
||||||
|
//_stylesDir = Utility::Directory::join(_armouryDir, "styles");
|
||||||
|
|
||||||
|
if(!Utility::Path::exists(_backupsDir)) {
|
||||||
|
LOG_WARNING("Backups directory not found, creating...");
|
||||||
|
if(!Utility::Path::make(_backupsDir)) {
|
||||||
|
LOG_ERROR(_lastError = "Couldn't create the backups directory.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Utility::Path::exists(_stagingDir)) {
|
||||||
|
LOG_WARNING("Staging directory not found, creating...");
|
||||||
|
if(!Utility::Path::make(_stagingDir)) {
|
||||||
|
LOG_ERROR(_lastError = "Couldn't create the staging directory.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if(!Utility::Directory::exists(_armouryDir)) {
|
||||||
|
// Utility::Debug{} << "Armoury directory not found, creating...";
|
||||||
|
// if(!Utility::Path::make(_armouryDir)) {
|
||||||
|
// Utility::Error{} << (_lastError = "Couldn't create the armoury directory.");
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if(!Utility::Directory::exists(_armoursDir)) {
|
||||||
|
// Utility::Debug{} << "Armours directory not found, creating...";
|
||||||
|
// if(!Utility::Path::make(_armoursDir)) {
|
||||||
|
// Utility::Error{} << (_lastError = "Couldn't create the armours directory.");
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if(!Utility::Directory::exists(_weaponsDir)) {
|
||||||
|
// Utility::Debug{} << "Weapons directory not found, creating...";
|
||||||
|
// if(!Utility::Path::make(_weaponsDir)) {
|
||||||
|
// Utility::Error{} << (_lastError = "Couldn't create the weapons directory.");
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if(!Utility::Directory::exists(_stylesDir)) {
|
||||||
|
// Utility::Debug{} << "Styles directory not found, creating...";
|
||||||
|
// if(!Utility::Path::make(_stylesDir)) {
|
||||||
|
// Utility::Error{} << (_lastError = "Couldn't create the styles directory.");
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SaveTool::findGameDataDirectory() -> bool {
|
||||||
|
LOG_INFO("Searching for the game's save directory.");
|
||||||
|
|
||||||
|
wchar_t* localappdata_path = nullptr;
|
||||||
|
Containers::ScopeGuard guard{localappdata_path, CoTaskMemFree};
|
||||||
|
if(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_NO_APPCONTAINER_REDIRECTION, nullptr, &localappdata_path) != S_OK)
|
||||||
|
{
|
||||||
|
_lastError = Utility::format("SHGetKnownFolderPath() failed with error code {}.", GetLastError());
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_gameDataDir = Utility::Path::join(Utility::Path::fromNativeSeparators(Utility::Unicode::narrow(localappdata_path)), "MASS_Builder"_s);
|
||||||
|
|
||||||
|
if(!Utility::Path::exists(_gameDataDir)) {
|
||||||
|
LOG_ERROR(_lastError = _gameDataDir + " wasn't found. Make sure to play the game at least once."_s);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_configDir = Utility::Path::join(_gameDataDir, "Saved/Config/WindowsNoEditor"_s);
|
||||||
|
_saveDir = Utility::Path::join(_gameDataDir, "Saved/SaveGames"_s);
|
||||||
|
_screenshotsDir = Utility::Path::join(_gameDataDir, "Saved/Screenshots/WindowsNoEditor"_s);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveTool::initialiseMassManager() {
|
||||||
|
LOG_INFO("Initialising the M.A.S.S. manager.");
|
||||||
|
_massManager.emplace(_saveDir, _currentProfile->account(), _currentProfile->isDemo(), _stagingDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveTool::initialiseFileWatcher() {
|
||||||
|
LOG_INFO("Initialising the file watcher.");
|
||||||
|
_fileWatcher.emplace();
|
||||||
|
_watchIDs[SaveDir] = _fileWatcher->addWatch(_saveDir, this, false);
|
||||||
|
_watchIDs[StagingDir] = _fileWatcher->addWatch(_stagingDir, this, false);
|
||||||
|
_fileWatcher->watch();
|
||||||
|
}
|
|
@ -14,20 +14,19 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "SaveTool.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <Corrade/Containers/Reference.h>
|
|
||||||
#include <Corrade/Utility/Format.h>
|
#include <Corrade/Utility/Format.h>
|
||||||
#include <Corrade/Utility/Path.h>
|
#include <Corrade/Utility/Path.h>
|
||||||
#include <Corrade/Utility/String.h>
|
|
||||||
|
#include <SDL_messagebox.h>
|
||||||
|
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
|
||||||
#include "../Maps/LastMissionId.h"
|
#include "../Maps/LastMissionId.h"
|
||||||
#include "../Maps/StoryProgress.h"
|
#include "../Maps/StoryProgress.h"
|
||||||
|
|
||||||
|
#include "SaveTool.h"
|
||||||
|
|
||||||
void SaveTool::drawManager() {
|
void SaveTool::drawManager() {
|
||||||
ImGui::SetNextWindowPos({0.0f, ImGui::GetItemRectSize().y}, ImGuiCond_Always);
|
ImGui::SetNextWindowPos({0.0f, ImGui::GetItemRectSize().y}, ImGuiCond_Always);
|
||||||
ImGui::SetNextWindowSize({Float(windowSize().x()), Float(windowSize().y()) - ImGui::GetItemRectSize().y},
|
ImGui::SetNextWindowSize({Float(windowSize().x()), Float(windowSize().y()) - ImGui::GetItemRectSize().y},
|
||||||
|
@ -52,7 +51,7 @@ void SaveTool::drawManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::BeginChild("##ProfileInfo",
|
if(ImGui::BeginChild("##ProfileInfo",
|
||||||
{ImGui::GetContentRegionAvailWidth() * 0.60f, 0.0f},
|
{ImGui::GetContentRegionAvail().x * 0.60f, 0.0f},
|
||||||
true, ImGuiWindowFlags_MenuBar))
|
true, ImGuiWindowFlags_MenuBar))
|
||||||
{
|
{
|
||||||
if(ImGui::BeginMenuBar()) {
|
if(ImGui::BeginMenuBar()) {
|
||||||
|
@ -146,8 +145,8 @@ auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
|
||||||
callback, nullptr);
|
callback, nullptr);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
GameState game_state = _gameState;
|
GameState game_state = _gameState;
|
||||||
if((!_unsafeMode && game_state != GameState::NotRunning) ||
|
if(game_state != GameState::NotRunning ||
|
||||||
!(len >= 6 && len <= 32) ||
|
!(len >= 6 && len <= 32) ||
|
||||||
!(name_view[0] != ' ' && name_view[len - 1] != ' '))
|
!(name_view[0] != ' ' && name_view[len - 1] != ' '))
|
||||||
{
|
{
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
|
@ -158,8 +157,8 @@ auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if((!_unsafeMode && game_state != GameState::NotRunning) ||
|
if(game_state != GameState::NotRunning ||
|
||||||
!(len >= 6 && len <= 32) ||
|
!(len >= 6 && len <= 32) ||
|
||||||
!(name_view[0] != ' ' && name_view[len - 1] != ' '))
|
!(name_view[0] != ' ' && name_view[len - 1] != ' '))
|
||||||
{
|
{
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
@ -204,7 +203,7 @@ void SaveTool::drawGeneralInfo() {
|
||||||
ImGui::Text("Last mission: 0x%x", _currentProfile->lastMissionId());
|
ImGui::Text("Last mission: 0x%x", _currentProfile->lastMissionId());
|
||||||
}
|
}
|
||||||
drawTooltip("This is the last mission selected in the mission selection screen, not the last mission played.",
|
drawTooltip("This is the last mission selected in the mission selection screen, not the last mission played.",
|
||||||
windowSize().x() * 0.35f);
|
float(windowSize().x()) * 0.35f);
|
||||||
|
|
||||||
const Float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
|
const Float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
|
||||||
ImGui::Dummy({ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - footer_height_to_reserve});
|
ImGui::Dummy({ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - footer_height_to_reserve});
|
||||||
|
@ -249,7 +248,7 @@ void SaveTool::drawGeneralInfo() {
|
||||||
}
|
}
|
||||||
drawTooltip("Story progress directly affects unlocked levels.");
|
drawTooltip("Story progress directly affects unlocked levels.");
|
||||||
if(ImGui::BeginPopup("StoryProgressMenu")) {
|
if(ImGui::BeginPopup("StoryProgressMenu")) {
|
||||||
if(!_unsafeMode && _gameState != GameState::NotRunning) {
|
if(_gameState != GameState::NotRunning) {
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
for(const auto& sp : story_progress) {
|
for(const auto& sp : story_progress) {
|
||||||
|
@ -310,7 +309,9 @@ void SaveTool::drawResearchInventory() {
|
||||||
drawMaterialRow("Asterite", 5,
|
drawMaterialRow("Asterite", 5,
|
||||||
[this]{ return _currentProfile->asterite(); },
|
[this]{ return _currentProfile->asterite(); },
|
||||||
[this](Int amount){ return _currentProfile->setAsterite(amount); });
|
[this](Int amount){ return _currentProfile->setAsterite(amount); });
|
||||||
drawUnavailableMaterialRow("Hallite fragma", 6);
|
drawMaterialRow("Hallite fragma", 6,
|
||||||
|
[this]{ return _currentProfile->halliteFragma(); },
|
||||||
|
[this](Int amount){ return _currentProfile->setHalliteFragma(amount); });
|
||||||
drawUnavailableMaterialRow("Unnoctinium", 7);
|
drawUnavailableMaterialRow("Unnoctinium", 7);
|
||||||
|
|
||||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
|
@ -332,7 +333,9 @@ void SaveTool::drawResearchInventory() {
|
||||||
drawMaterialRow("Synthesized N", 5,
|
drawMaterialRow("Synthesized N", 5,
|
||||||
[this]{ return _currentProfile->synthesisedN(); },
|
[this]{ return _currentProfile->synthesisedN(); },
|
||||||
[this](Int amount){ return _currentProfile->setSynthesisedN(amount); });
|
[this](Int amount){ return _currentProfile->setSynthesisedN(amount); });
|
||||||
drawUnavailableMaterialRow("Nanoc", 6);
|
drawMaterialRow("Nanoc", 6,
|
||||||
|
[this]{ return _currentProfile->nanoc(); },
|
||||||
|
[this](Int amount){ return _currentProfile->setNanoc(amount); });
|
||||||
drawUnavailableMaterialRow("Abyssillite", 7);
|
drawUnavailableMaterialRow("Abyssillite", 7);
|
||||||
|
|
||||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
|
@ -354,7 +357,9 @@ void SaveTool::drawResearchInventory() {
|
||||||
drawMaterialRow("Alterene", 5,
|
drawMaterialRow("Alterene", 5,
|
||||||
[this]{ return _currentProfile->alterene(); },
|
[this]{ return _currentProfile->alterene(); },
|
||||||
[this](Int amount){ return _currentProfile->setAlterene(amount); });
|
[this](Int amount){ return _currentProfile->setAlterene(amount); });
|
||||||
drawUnavailableMaterialRow("Cosmium", 6);
|
drawMaterialRow("Cosmium", 6,
|
||||||
|
[this]{ return _currentProfile->cosmium(); },
|
||||||
|
[this](Int amount){ return _currentProfile->setCosmium(amount); });
|
||||||
drawUnavailableMaterialRow("Purified quarkium", 7);
|
drawUnavailableMaterialRow("Purified quarkium", 7);
|
||||||
|
|
||||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
|
@ -376,7 +381,9 @@ void SaveTool::drawResearchInventory() {
|
||||||
drawMaterialRow("Carbonized skin", 5,
|
drawMaterialRow("Carbonized skin", 5,
|
||||||
[this]{ return _currentProfile->carbonisedSkin(); },
|
[this]{ return _currentProfile->carbonisedSkin(); },
|
||||||
[this](Int amount){ return _currentProfile->setCarbonisedSkin(amount); });
|
[this](Int amount){ return _currentProfile->setCarbonisedSkin(amount); });
|
||||||
drawUnavailableMaterialRow("Isolated void particle", 6);
|
drawMaterialRow("Isolated void particle", 6,
|
||||||
|
[this]{ return _currentProfile->isolatedVoidParticle(); },
|
||||||
|
[this](Int amount){ return _currentProfile->setIsolatedVoidParticle(amount); });
|
||||||
drawUnavailableMaterialRow("Weaponised physiology", 7);
|
drawUnavailableMaterialRow("Weaponised physiology", 7);
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
|
@ -473,7 +480,7 @@ void SaveTool::drawMassManager() {
|
||||||
|
|
||||||
ImGui::EndDragDropSource();
|
ImGui::EndDragDropSource();
|
||||||
}
|
}
|
||||||
if((_unsafeMode || _gameState == GameState::NotRunning) && ImGui::BeginDragDropTarget()) {
|
if(_gameState == GameState::NotRunning && ImGui::BeginDragDropTarget()) {
|
||||||
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("StagedMass")) {
|
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("StagedMass")) {
|
||||||
if(payload->DataSize != sizeof(Containers::String)) {
|
if(payload->DataSize != sizeof(Containers::String)) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
||||||
|
@ -580,7 +587,7 @@ void SaveTool::drawMassManager() {
|
||||||
ImGui::TableSetColumnIndex(0);
|
ImGui::TableSetColumnIndex(0);
|
||||||
Containers::String staged_formatted = Utility::format("{} ({})", pair.second, pair.first);
|
Containers::String staged_formatted = Utility::format("{} ({})", pair.second, pair.first);
|
||||||
ImGui::Selectable(staged_formatted.data());
|
ImGui::Selectable(staged_formatted.data());
|
||||||
if((ImGui::CalcTextSize(staged_formatted.data()).x + ImGui::GetStyle().FramePadding.x) > ImGui::GetContentRegionAvailWidth()) {
|
if((ImGui::CalcTextSize(staged_formatted.data()).x + ImGui::GetStyle().FramePadding.x) > ImGui::GetContentRegionAvail().x) {
|
||||||
drawTooltip(staged_formatted.data());
|
drawTooltip(staged_formatted.data());
|
||||||
}
|
}
|
||||||
if(ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) {
|
if(ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) {
|
||||||
|
@ -644,7 +651,7 @@ auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
|
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f);
|
||||||
if(_massManager->hangar(mass_index).state() == Mass::State::Invalid) {
|
if(_massManager->hangar(mass_index).state() == Mass::State::Invalid) {
|
||||||
ImGui::Text("Are you sure you want to delete the invalid M.A.S.S. data in hangar %.2i ? This operation is irreversible.",
|
ImGui::Text("Are you sure you want to delete the invalid M.A.S.S. data in hangar %.2i ? This operation is irreversible.",
|
||||||
mass_index + 1);
|
mass_index + 1);
|
||||||
|
@ -688,7 +695,7 @@ auto SaveTool::drawDeleteStagedMassPopup(Containers::StringView filename) -> ImG
|
||||||
return ImGui::GetID("Confirmation##DeleteStagedMassConfirmation");
|
return ImGui::GetID("Confirmation##DeleteStagedMassConfirmation");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
|
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f);
|
||||||
ImGui::Text("Are you sure you want to delete the staged M.A.S.S. named %s ? This operation is irreversible.",
|
ImGui::Text("Are you sure you want to delete the staged M.A.S.S. named %s ? This operation is irreversible.",
|
||||||
_massManager->stagedMasses().at(filename).data());
|
_massManager->stagedMasses().at(filename).data());
|
||||||
ImGui::PopTextWrapPos();
|
ImGui::PopTextWrapPos();
|
||||||
|
|
|
@ -15,16 +15,15 @@
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <Corrade/Containers/ScopeGuard.h>
|
#include <Corrade/Containers/ScopeGuard.h>
|
||||||
|
#include <Corrade/Utility/Format.h>
|
||||||
|
|
||||||
#include <Magnum/ImGuiIntegration/Integration.h>
|
#include <Magnum/ImGuiIntegration/Integration.h>
|
||||||
|
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
#include "../Maps/Accessories.h"
|
#include "../Maps/Accessories.h"
|
||||||
|
|
||||||
#define STYLENAMES_DEFINITION
|
#define STYLENAMES_DEFINITION
|
||||||
#include "../Maps/StyleNames.h"
|
#include "../Maps/StyleNames.h"
|
||||||
|
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
|
||||||
|
|
||||||
#include "SaveTool.h"
|
#include "SaveTool.h"
|
||||||
|
|
||||||
void SaveTool::drawMassViewer() {
|
void SaveTool::drawMassViewer() {
|
||||||
|
@ -91,7 +90,7 @@ void SaveTool::drawMassViewer() {
|
||||||
_selectedWeaponPart = 0;
|
_selectedWeaponPart = 0;
|
||||||
_selectedWeaponDecal = 0;
|
_selectedWeaponDecal = 0;
|
||||||
_selectedWeaponAccessory = 0;
|
_selectedWeaponAccessory = 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
@ -167,7 +166,7 @@ void SaveTool::drawGlobalStyles() {
|
||||||
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
|
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < _currentMass->globalStyles().size(); i++) {
|
for(UnsignedInt i = 0; i < _currentMass->globalStyles().size(); i++) {
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(int(i));
|
||||||
DCSResult result;
|
DCSResult result;
|
||||||
result = drawCustomStyle(_currentMass->globalStyles()[i]);
|
result = drawCustomStyle(_currentMass->globalStyles()[i]);
|
||||||
switch(result) {
|
switch(result) {
|
||||||
|
@ -175,7 +174,9 @@ void SaveTool::drawGlobalStyles() {
|
||||||
_currentMass->getGlobalStyles();
|
_currentMass->getGlobalStyles();
|
||||||
break;
|
break;
|
||||||
case DCS_Save:
|
case DCS_Save:
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeGlobalStyle(i)) {
|
if(!_currentMass->writeGlobalStyle(i)) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -392,9 +393,12 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
|
||||||
void SaveTool::drawDecalEditor(Decal& decal) {
|
void SaveTool::drawDecalEditor(Decal& decal) {
|
||||||
ImGui::Text("ID: %i", decal.id);
|
ImGui::Text("ID: %i", decal.id);
|
||||||
|
|
||||||
if(ImGui::BeginTable("##DecalTable", 2, ImGuiTableFlags_BordersInnerV)) {
|
if(ImGui::BeginTable("##DecalTable", _advancedMode ? 2 : 1, ImGuiTableFlags_BordersInnerV)) {
|
||||||
ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch);
|
||||||
ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch);
|
|
||||||
|
if(_advancedMode) {
|
||||||
|
ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
@ -438,52 +442,53 @@ void SaveTool::drawDecalEditor(Decal& decal) {
|
||||||
ImGui::Checkbox("##Wrap", &decal.wrap);
|
ImGui::Checkbox("##Wrap", &decal.wrap);
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
if(_advancedMode) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::TextUnformatted("Advanced settings. Touch these at your own risk.");
|
||||||
|
|
||||||
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
|
ImGui::BeginGroup();
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
drawAlignedText("Position:");
|
||||||
ImGui::TextUnformatted("Advanced settings. Touch these at your own risk.");
|
drawAlignedText("U axis:");
|
||||||
|
drawAlignedText("V axis:");
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
ImGui::BeginGroup();
|
ImGui::SameLine();
|
||||||
drawAlignedText("Position:");
|
|
||||||
drawAlignedText("U axis:");
|
|
||||||
drawAlignedText("V axis:");
|
|
||||||
ImGui::EndGroup();
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::BeginGroup();
|
||||||
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
|
ImGui::DragFloat("##PosX", &decal.position.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::DragFloat("##PosY", &decal.position.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::DragFloat("##PosZ", &decal.position.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
ImGui::BeginGroup();
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
ImGui::DragFloat("##UX", &decal.uAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
||||||
ImGui::DragFloat("##PosX", &decal.position.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
ImGui::PopItemWidth();
|
||||||
ImGui::PopItemWidth();
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::DragFloat("##UY", &decal.uAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
||||||
ImGui::DragFloat("##PosY", &decal.position.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
ImGui::PopItemWidth();
|
||||||
ImGui::PopItemWidth();
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::DragFloat("##UZ", &decal.uAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
||||||
ImGui::DragFloat("##PosZ", &decal.position.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
ImGui::PopItemWidth();
|
||||||
ImGui::PopItemWidth();
|
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
ImGui::DragFloat("##UX", &decal.uAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
ImGui::DragFloat("##VX", &decal.vAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
ImGui::DragFloat("##UY", &decal.uAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
ImGui::DragFloat("##VY", &decal.vAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
ImGui::DragFloat("##UZ", &decal.uAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
ImGui::DragFloat("##VZ", &decal.vAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::EndGroup();
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
}
|
||||||
ImGui::DragFloat("##VX", &decal.vAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
|
||||||
ImGui::PopItemWidth();
|
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
||||||
ImGui::DragFloat("##VY", &decal.vAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
|
||||||
ImGui::PopItemWidth();
|
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
|
||||||
ImGui::DragFloat("##VZ", &decal.vAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
|
||||||
ImGui::PopItemWidth();
|
|
||||||
ImGui::EndGroup();
|
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
@ -494,23 +499,149 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
ImGui::TextUnformatted("Accessory: <none>");
|
ImGui::TextUnformatted("Accessory: <none>");
|
||||||
}
|
}
|
||||||
else if(accessories.find(accessory.id) != accessories.cend()) {
|
else if(accessories.find(accessory.id) != accessories.cend()) {
|
||||||
ImGui::Text("Accessory #%i - %s", accessory.id, accessories.at(accessory.id).data());
|
ImGui::Text("Accessory #%.4i - %s", accessory.id, accessories.at(accessory.id).name.data());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImGui::Text("Accessory #%i", accessory.id);
|
ImGui::Text("Accessory #%i", accessory.id);
|
||||||
drawTooltip("WARNING: accessory mapping is a WIP.");
|
drawTooltip("WARNING: accessory mapping is a WIP.");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SAVETOOL_DEBUG_BUILD
|
ImGui::SameLine();
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().FramePadding.x * 5.0f);
|
|
||||||
ImGui::Text("Attach index: %i", accessory.attachIndex);
|
static Int tab = 0;
|
||||||
#endif
|
static Containers::Optional<AccessorySize> size = Containers::NullOpt;
|
||||||
|
if(ImGui::SmallButton("Change")) {
|
||||||
|
ImGui::OpenPopup("##AccessoryPopup");
|
||||||
|
if(accessory.id >= 3000) {
|
||||||
|
tab = 3;
|
||||||
|
}
|
||||||
|
else if(accessory.id >= 2000) {
|
||||||
|
tab = 2;
|
||||||
|
}
|
||||||
|
else if(accessory.id >= 1000) {
|
||||||
|
tab = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tab = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(ImGui::BeginPopup("##AccessoryPopup")) {
|
||||||
|
static const char* size_labels[] = {
|
||||||
|
"S",
|
||||||
|
"M",
|
||||||
|
"L",
|
||||||
|
"XL"
|
||||||
|
};
|
||||||
|
static const Float selectable_width = 90.0f;
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
||||||
|
if(ImGui::Selectable("Primitives", tab == 0, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
||||||
|
tab = 0;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("Armours", tab == 1, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
||||||
|
tab = 1;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("Components", tab == 2, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
||||||
|
tab = 2;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("Connectors", tab == 3, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
||||||
|
tab = 3;
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
||||||
|
if(ImGui::Selectable("All", !size, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||||
|
size = Containers::NullOpt;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("S", size && *size == AccessorySize::S, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||||
|
if(!size) {
|
||||||
|
size.emplace();
|
||||||
|
}
|
||||||
|
*size = AccessorySize::S;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("M", size && *size == AccessorySize::M, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||||
|
if(!size) {
|
||||||
|
size.emplace();
|
||||||
|
}
|
||||||
|
*size = AccessorySize::M;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("L", size && *size == AccessorySize::L, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||||
|
if(!size) {
|
||||||
|
size.emplace();
|
||||||
|
}
|
||||||
|
*size = AccessorySize::L;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("XL", size && *size == AccessorySize::XL, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||||
|
if(!size) {
|
||||||
|
size.emplace();
|
||||||
|
}
|
||||||
|
*size = AccessorySize::XL;
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if(ImGui::BeginListBox("##AccessoryListbox", {-1.0f, 0.0f})) {
|
||||||
|
for(const auto& acc : accessories) {
|
||||||
|
if(acc.first >= tab * 1000 && acc.first < ((tab + 1) * 1000) && (!size || *size == acc.second.size)) {
|
||||||
|
if(ImGui::Selectable(Utility::format("#{:.4d} - {} ({})", acc.first, acc.second.name, size_labels[acc.second.size]).data(),
|
||||||
|
acc.first == accessory.id))
|
||||||
|
{
|
||||||
|
accessory.id = acc.first;
|
||||||
|
accessory.attachIndex = 0;
|
||||||
|
}
|
||||||
|
if(acc.first == accessory.id) {
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndListBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(accessory.id > 0) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::SmallButton("Unequip")) {
|
||||||
|
accessory.id = 0;
|
||||||
|
accessory.attachIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
drawAlignedText("Styles:");
|
drawAlignedText("Styles:");
|
||||||
drawAlignedText("Base position:");
|
if(_advancedMode) {
|
||||||
|
drawAlignedText("Base position:");
|
||||||
|
}
|
||||||
drawAlignedText("Position offset:");
|
drawAlignedText("Position offset:");
|
||||||
drawAlignedText("Base rotation:");
|
if(_advancedMode) {
|
||||||
|
drawAlignedText("Base rotation:");
|
||||||
|
}
|
||||||
drawAlignedText("Rotation offset:");
|
drawAlignedText("Rotation offset:");
|
||||||
drawAlignedText("Scale:");
|
drawAlignedText("Scale:");
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
|
@ -541,15 +672,17 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
}
|
}
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
if(_advancedMode) {
|
||||||
ImGui::DragFloat("##PosX", &accessory.relativePosition.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
ImGui::PopItemWidth();
|
ImGui::DragFloat("##PosX", &accessory.relativePosition.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::PopItemWidth();
|
||||||
ImGui::DragFloat("##PosY", &accessory.relativePosition.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
ImGui::PopItemWidth();
|
ImGui::DragFloat("##PosY", &accessory.relativePosition.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::PopItemWidth();
|
||||||
ImGui::DragFloat("##PosZ", &accessory.relativePosition.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
ImGui::PopItemWidth();
|
ImGui::DragFloat("##PosZ", &accessory.relativePosition.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
ImGui::SliderFloat("##PosOffsetX", &accessory.relativePositionOffset.x(), -500.0f, +500.0f, "X: %.3f");
|
ImGui::SliderFloat("##PosOffsetX", &accessory.relativePositionOffset.x(), -500.0f, +500.0f, "X: %.3f");
|
||||||
|
@ -563,15 +696,17 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
drawHelpMarker("+/-500.0 = +/-250 in-game");
|
drawHelpMarker("+/-500.0 = +/-250 in-game");
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
if(_advancedMode) {
|
||||||
ImGui::DragFloat("##RotX", &accessory.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f");
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
ImGui::PopItemWidth();
|
ImGui::DragFloat("##RotX", &accessory.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f");
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::PopItemWidth();
|
||||||
ImGui::DragFloat("##RotY", &accessory.relativeRotation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Yaw: %.3f");
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
ImGui::PopItemWidth();
|
ImGui::DragFloat("##RotY", &accessory.relativeRotation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Yaw: %.3f");
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::PopItemWidth();
|
||||||
ImGui::DragFloat("##RotZ", &accessory.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f");
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
ImGui::PopItemWidth();
|
ImGui::DragFloat("##RotZ", &accessory.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f");
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
ImGui::SliderFloat("##RotOffsetX", &accessory.relativeRotationOffset.x(), -180.0f, +180.0f, "Roll: %.3f");
|
ImGui::SliderFloat("##RotOffsetX", &accessory.relativeRotationOffset.x(), -180.0f, +180.0f, "Roll: %.3f");
|
||||||
|
|
|
@ -43,7 +43,7 @@ void SaveTool::drawArmour() {
|
||||||
};
|
};
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < _currentMass->armourParts().size(); i++) {
|
for(UnsignedInt i = 0; i < _currentMass->armourParts().size(); i++) {
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(int(i));
|
||||||
|
|
||||||
auto& part = _currentMass->armourParts()[i];
|
auto& part = _currentMass->armourParts()[i];
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ void SaveTool::drawArmour() {
|
||||||
if(ImGui::CollapsingHeader(header)) {
|
if(ImGui::CollapsingHeader(header)) {
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() * 0.491f);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.491f);
|
||||||
if(ImGui::BeginListBox("##ChangePart")) {
|
if(ImGui::BeginListBox("##ChangePart")) {
|
||||||
if(std::strncmp("Neck", slot_labels[UnsignedInt(part.slot)].data(), 4) != 0) {
|
if(std::strncmp("Neck", slot_labels[UnsignedInt(part.slot)].data(), 4) != 0) {
|
||||||
for(auto& set : armour_sets) {
|
for(auto& set : armour_sets) {
|
||||||
|
@ -103,7 +103,7 @@ void SaveTool::drawArmour() {
|
||||||
|
|
||||||
ImGui::PushID(j);
|
ImGui::PushID(j);
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() - 2.0f);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 2.0f);
|
||||||
if(ImGui::BeginCombo("##Style", getStyleName(part.styles[j], _currentMass->armourCustomStyles()).data())) {
|
if(ImGui::BeginCombo("##Style", getStyleName(part.styles[j], _currentMass->armourCustomStyles()).data())) {
|
||||||
for(const auto& style : style_names) {
|
for(const auto& style : style_names) {
|
||||||
if(ImGui::Selectable(getStyleName(style.first, _currentMass->armourCustomStyles()).data(), part.styles[j] == style.first)) {
|
if(ImGui::Selectable(getStyleName(style.first, _currentMass->armourCustomStyles()).data(), part.styles[j] == style.first)) {
|
||||||
|
@ -126,7 +126,7 @@ void SaveTool::drawArmour() {
|
||||||
drawAlignedText("Showing/editing decal");
|
drawAlignedText("Showing/editing decal");
|
||||||
for(UnsignedInt j = 0; j < part.decals.size(); j++) {
|
for(UnsignedInt j = 0; j < part.decals.size(); j++) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::RadioButton(std::to_string(j + 1).c_str(), &_selectedArmourDecals[i], j);
|
ImGui::RadioButton(std::to_string(j + 1).c_str(), &_selectedArmourDecals[i], int(j));
|
||||||
}
|
}
|
||||||
|
|
||||||
drawDecalEditor(part.decals[_selectedArmourDecals[i]]);
|
drawDecalEditor(part.decals[_selectedArmourDecals[i]]);
|
||||||
|
@ -141,7 +141,7 @@ void SaveTool::drawArmour() {
|
||||||
drawAlignedText("Showing/editing accessory");
|
drawAlignedText("Showing/editing accessory");
|
||||||
for(UnsignedInt j = 0; j < part.accessories.size(); j++) {
|
for(UnsignedInt j = 0; j < part.accessories.size(); j++) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::RadioButton(std::string{char(65 + j)}.c_str(), &_selectedArmourAccessories[i], j);
|
ImGui::RadioButton(std::string{char(65 + j)}.c_str(), &_selectedArmourAccessories[i], int(j));
|
||||||
}
|
}
|
||||||
|
|
||||||
drawAccessoryEditor(part.accessories[_selectedArmourAccessories[i]], _currentMass->armourCustomStyles());
|
drawAccessoryEditor(part.accessories[_selectedArmourAccessories[i]], _currentMass->armourCustomStyles());
|
||||||
|
@ -152,7 +152,9 @@ void SaveTool::drawArmour() {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeArmourPart(part.slot)) {
|
if(!_currentMass->writeArmourPart(part.slot)) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,9 +276,11 @@ void SaveTool::drawArmour() {
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); }) &&
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); }) &&
|
||||||
!_currentMass->writeBulletLauncherAttachments())
|
!_currentMass->writeBulletLauncherAttachments())
|
||||||
{
|
{
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,7 +301,7 @@ void SaveTool::drawCustomArmourStyles() {
|
||||||
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
|
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < _currentMass->armourCustomStyles().size(); i++) {
|
for(UnsignedInt i = 0; i < _currentMass->armourCustomStyles().size(); i++) {
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(int(i));
|
||||||
DCSResult result;
|
DCSResult result;
|
||||||
result = drawCustomStyle(_currentMass->armourCustomStyles()[i]);
|
result = drawCustomStyle(_currentMass->armourCustomStyles()[i]);
|
||||||
switch(result) {
|
switch(result) {
|
||||||
|
@ -305,7 +309,9 @@ void SaveTool::drawCustomArmourStyles() {
|
||||||
_currentMass->getArmourCustomStyles();
|
_currentMass->getArmourCustomStyles();
|
||||||
break;
|
break;
|
||||||
case DCS_Save:
|
case DCS_Save:
|
||||||
if(_currentMass->writeArmourCustomStyle(i)) {
|
_modifiedBySaveTool = true;
|
||||||
|
if(!_currentMass->writeArmourCustomStyle(i)) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -32,7 +32,7 @@ void SaveTool::drawFrameInfo() {
|
||||||
|
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
if(ImGui::BeginChild("##JointSliders", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 300.0f}, true, ImGuiWindowFlags_MenuBar)) {
|
if(ImGui::BeginChild("##JointSliders", {(ImGui::GetContentRegionAvail().x / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 300.0f}, true, ImGuiWindowFlags_MenuBar)) {
|
||||||
if(ImGui::BeginMenuBar()) {
|
if(ImGui::BeginMenuBar()) {
|
||||||
ImGui::TextUnformatted("Joint sliders");
|
ImGui::TextUnformatted("Joint sliders");
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ void SaveTool::drawFrameInfo() {
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
if(ImGui::BeginChild("##FrameStyles", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 0.0f}, true, ImGuiWindowFlags_MenuBar)) {
|
if(ImGui::BeginChild("##FrameStyles", {(ImGui::GetContentRegionAvail().x / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 0.0f}, true, ImGuiWindowFlags_MenuBar)) {
|
||||||
if(ImGui::BeginMenuBar()) {
|
if(ImGui::BeginMenuBar()) {
|
||||||
ImGui::TextUnformatted("Frame styles");
|
ImGui::TextUnformatted("Frame styles");
|
||||||
|
|
||||||
|
@ -180,7 +180,9 @@ void SaveTool::drawJointSliders() {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeJointSliders()) {
|
if(!_currentMass->writeJointSliders()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
_jointsDirty = false;
|
_jointsDirty = false;
|
||||||
|
@ -228,7 +230,9 @@ void SaveTool::drawFrameStyles() {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeFrameStyles()) {
|
if(!_currentMass->writeFrameStyles()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
_stylesDirty = false;
|
_stylesDirty = false;
|
||||||
|
@ -259,7 +263,9 @@ void SaveTool::drawEyeColourPicker() {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeEyeFlareColour()) {
|
if(!_currentMass->writeEyeFlareColour()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
_eyeFlareDirty = false;
|
_eyeFlareDirty = false;
|
||||||
|
@ -285,7 +291,7 @@ void SaveTool::drawCustomFrameStyles() {
|
||||||
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
|
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < _currentMass->frameCustomStyles().size(); i++) {
|
for(UnsignedInt i = 0; i < _currentMass->frameCustomStyles().size(); i++) {
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(int(i));
|
||||||
DCSResult result;
|
DCSResult result;
|
||||||
result = drawCustomStyle(_currentMass->frameCustomStyles()[i]);
|
result = drawCustomStyle(_currentMass->frameCustomStyles()[i]);
|
||||||
switch(result) {
|
switch(result) {
|
||||||
|
@ -293,7 +299,9 @@ void SaveTool::drawCustomFrameStyles() {
|
||||||
_currentMass->getFrameCustomStyles();
|
_currentMass->getFrameCustomStyles();
|
||||||
break;
|
break;
|
||||||
case DCS_Save:
|
case DCS_Save:
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeFrameCustomStyle(i)) {
|
if(!_currentMass->writeFrameCustomStyle(i)) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
|
||||||
#include "../Maps/StyleNames.h"
|
#include "../Maps/StyleNames.h"
|
||||||
|
#include "../Maps/WeaponParts.h"
|
||||||
|
|
||||||
#include "SaveTool.h"
|
#include "SaveTool.h"
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ void SaveTool::drawWeapons() {
|
||||||
|
|
||||||
if(!ImGui::BeginTable("##WeaponsList", 1,
|
if(!ImGui::BeginTable("##WeaponsList", 1,
|
||||||
ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_BordersInnerH,
|
ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_BordersInnerH,
|
||||||
{ImGui::GetContentRegionAvailWidth() * 0.2f, -footer_height_to_reserve}))
|
{ImGui::GetContentRegionAvail().x * 0.2f, -footer_height_to_reserve}))
|
||||||
{
|
{
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
return;
|
return;
|
||||||
|
@ -57,7 +58,9 @@ void SaveTool::drawWeapons() {
|
||||||
|
|
||||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
if(_meleeDirty) {
|
if(_meleeDirty) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeMeleeWeapons()) {
|
if(!_currentMass->writeMeleeWeapons()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -66,7 +69,9 @@ void SaveTool::drawWeapons() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_shieldsDirty) {
|
if(_shieldsDirty) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeShields()) {
|
if(!_currentMass->writeShields()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -75,7 +80,9 @@ void SaveTool::drawWeapons() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_bShootersDirty) {
|
if(_bShootersDirty) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeBulletShooters()) {
|
if(!_currentMass->writeBulletShooters()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -84,7 +91,9 @@ void SaveTool::drawWeapons() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_eShootersDirty) {
|
if(_eShootersDirty) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(_currentMass->writeEnergyShooters()) {
|
if(_currentMass->writeEnergyShooters()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -93,7 +102,9 @@ void SaveTool::drawWeapons() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_bLaunchersDirty) {
|
if(_bLaunchersDirty) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(_currentMass->writeBulletLaunchers()) {
|
if(_currentMass->writeBulletLaunchers()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -102,7 +113,9 @@ void SaveTool::drawWeapons() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_eLaunchersDirty) {
|
if(_eLaunchersDirty) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
if(_currentMass->writeEnergyLaunchers()) {
|
if(_currentMass->writeEnergyLaunchers()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -167,40 +180,47 @@ void SaveTool::drawWeapons() {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if(drawUnsafeWidget([](){ return ImGui::Button(ICON_FA_SAVE " Save changes to weapon category"); })) {
|
if(drawUnsafeWidget([](){ return ImGui::Button(ICON_FA_SAVE " Save changes to weapon category"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
switch(_currentWeapon->type) {
|
switch(_currentWeapon->type) {
|
||||||
case WeaponType::Melee:
|
case WeaponType::Melee:
|
||||||
if(!_currentMass->writeMeleeWeapons()) {
|
if(!_currentMass->writeMeleeWeapons()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::Shield:
|
case WeaponType::Shield:
|
||||||
if(!_currentMass->writeShields()) {
|
if(!_currentMass->writeShields()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::BulletShooter:
|
case WeaponType::BulletShooter:
|
||||||
if(!_currentMass->writeBulletShooters()) {
|
if(!_currentMass->writeBulletShooters()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::EnergyShooter:
|
case WeaponType::EnergyShooter:
|
||||||
if(!_currentMass->writeEnergyShooters()) {
|
if(!_currentMass->writeEnergyShooters()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::BulletLauncher:
|
case WeaponType::BulletLauncher:
|
||||||
if(!_currentMass->writeBulletLaunchers()) {
|
if(!_currentMass->writeBulletLaunchers()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::EnergyLauncher:
|
case WeaponType::EnergyLauncher:
|
||||||
if(!_currentMass->writeEnergyLaunchers()) {
|
if(!_currentMass->writeEnergyLaunchers()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, "Unknown weapon type");
|
_queue.addToast(Toast::Type::Error, "Unknown weapon type");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +269,7 @@ void SaveTool::drawWeaponCategory(Containers::StringView name, Containers::Array
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(int(i));
|
||||||
|
|
||||||
if(ImGui::Selectable(weapon.name.data(), _currentWeapon == &weapon)) {
|
if(ImGui::Selectable(weapon.name.data(), _currentWeapon == &weapon)) {
|
||||||
_currentWeapon = &weapon;
|
_currentWeapon = &weapon;
|
||||||
|
@ -289,7 +309,7 @@ void SaveTool::drawWeaponCategory(Containers::StringView name, Containers::Array
|
||||||
|
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
if(weapon.attached == true) {
|
if(weapon.attached) {
|
||||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, 0x1F008CFFu);
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, 0x1F008CFFu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,8 +390,8 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
weapon.damageType = DamageType::Freeze;
|
weapon.damageType = DamageType::Freeze;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::RadioButton("Shock##Shock", weapon.damageType == DamageType::Freeze)) {
|
if(ImGui::RadioButton("Shock##Shock", weapon.damageType == DamageType::Shock)) {
|
||||||
weapon.damageType = DamageType::Freeze;
|
weapon.damageType = DamageType::Shock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,6 +412,8 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::ColorEdit3("##CustomEffectColourPicker", &weapon.effectColour.x(), ImGuiColorEditFlags_HDR|ImGuiColorEditFlags_Float);
|
ImGui::ColorEdit3("##CustomEffectColourPicker", &weapon.effectColour.x(), ImGuiColorEditFlags_HDR|ImGuiColorEditFlags_Float);
|
||||||
|
ImGui::SameLine();
|
||||||
|
drawHelpMarker("Click the coloured square for the full picker.");
|
||||||
|
|
||||||
if(!custom_effect) {
|
if(!custom_effect) {
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
@ -408,12 +430,80 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
_selectedWeaponPart = 0;
|
_selectedWeaponPart = 0;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponPart, i);
|
ImGui::RadioButton(std::to_string(i).c_str(), &_selectedWeaponPart, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& part = weapon.parts[_selectedWeaponPart];
|
auto& part = weapon.parts[_selectedWeaponPart];
|
||||||
|
|
||||||
ImGui::Text("ID: %i", part.id);
|
const auto* map = [this, &weapon]()-> const std::map<Int, Containers::StringView>* {
|
||||||
|
switch(weapon.type) {
|
||||||
|
case WeaponType::Melee:
|
||||||
|
return _selectedWeaponPart == 0 ? &melee_grips : &melee_assaulters;
|
||||||
|
case WeaponType::Shield:
|
||||||
|
return _selectedWeaponPart == 0 ? &shield_handles : &shield_shells;
|
||||||
|
case WeaponType::BulletShooter:
|
||||||
|
return _selectedWeaponPart == 0 ? &bshooter_triggers : &bshooter_barrels;
|
||||||
|
case WeaponType::EnergyShooter:
|
||||||
|
return _selectedWeaponPart == 0 ? &eshooter_triggers : &eshooter_busters;
|
||||||
|
case WeaponType::BulletLauncher:
|
||||||
|
return _selectedWeaponPart == 0 ? &blauncher_pods : &blauncher_projectiles;
|
||||||
|
case WeaponType::EnergyLauncher:
|
||||||
|
return _selectedWeaponPart == 0 ? &elauncher_generators : &elauncher_pods;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}();
|
||||||
|
|
||||||
|
if(!map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(map->find(part.id) != map->cend()) {
|
||||||
|
ImGui::TextUnformatted(map->at(part.id).data());
|
||||||
|
}
|
||||||
|
else if(part.id == -1) {
|
||||||
|
ImGui::TextUnformatted("<none>");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ImGui::Text("ID: %i", part.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!map->empty()) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::SmallButton("Change")) {
|
||||||
|
ImGui::OpenPopup("##WeaponPartPopup");
|
||||||
|
}
|
||||||
|
if(ImGui::BeginPopup("##WeaponPartPopup")) {
|
||||||
|
if(ImGui::BeginListBox("##WeaponParts")) {
|
||||||
|
for(const auto& mapped_part : *map) {
|
||||||
|
if(ImGui::Selectable(mapped_part.second.data(), mapped_part.first == part.id)) {
|
||||||
|
part.id = mapped_part.first;
|
||||||
|
}
|
||||||
|
if(mapped_part.first == part.id) {
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndListBox();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(weapon.type == WeaponType::Shield ||
|
||||||
|
(weapon.type == WeaponType::BulletLauncher && _selectedWeaponPart != 0))
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::SmallButton("Unequip")) {
|
||||||
|
part.id = -1;
|
||||||
|
}
|
||||||
|
if(weapon.type == WeaponType::Shield && _selectedWeaponPart == 0) {
|
||||||
|
drawTooltip("This will make the whole shield and its accessories invisible.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
drawTooltip("This will make accessories invisible as well.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(ImGui::BeginChild("##PartDetails", {0.0f, 0.0f}, true)) {
|
if(ImGui::BeginChild("##PartDetails", {0.0f, 0.0f}, true)) {
|
||||||
ImGui::TextUnformatted("Styles:");
|
ImGui::TextUnformatted("Styles:");
|
||||||
|
@ -446,7 +536,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
drawAlignedText("Showing/editing decal");
|
drawAlignedText("Showing/editing decal");
|
||||||
for(UnsignedLong i = 0; i < part.decals.size(); i++) {
|
for(UnsignedLong i = 0; i < part.decals.size(); i++) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponDecal, i);
|
ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponDecal, int(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
drawDecalEditor(part.decals[_selectedWeaponDecal]);
|
drawDecalEditor(part.decals[_selectedWeaponDecal]);
|
||||||
|
@ -461,7 +551,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
drawAlignedText("Showing/editing accessory");
|
drawAlignedText("Showing/editing accessory");
|
||||||
for(UnsignedLong i = 0; i < part.accessories.size(); i++) {
|
for(UnsignedLong i = 0; i < part.accessories.size(); i++) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::RadioButton(std::string{char(65 + i)}.c_str(), &_selectedWeaponAccessory, i);
|
ImGui::RadioButton(std::string{char(65 + i)}.c_str(), &_selectedWeaponAccessory, int(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
drawAccessoryEditor(part.accessories[_selectedWeaponAccessory], weapon.customStyles);
|
drawAccessoryEditor(part.accessories[_selectedWeaponAccessory], weapon.customStyles);
|
||||||
|
|
|
@ -14,12 +14,14 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "SaveTool.h"
|
|
||||||
|
|
||||||
#include <Magnum/ImGuiIntegration/Integration.h>
|
#include <Magnum/ImGuiIntegration/Integration.h>
|
||||||
|
|
||||||
|
#include <SDL_messagebox.h>
|
||||||
|
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
|
||||||
|
#include "SaveTool.h"
|
||||||
|
|
||||||
extern const ImVec2 center_pivot;
|
extern const ImVec2 center_pivot;
|
||||||
|
|
||||||
void SaveTool::drawProfileManager() {
|
void SaveTool::drawProfileManager() {
|
||||||
|
@ -50,7 +52,8 @@ void SaveTool::drawProfileManager() {
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
if(ImGui::SmallButton("Refresh")) {
|
if(ImGui::SmallButton("Refresh")) {
|
||||||
if(!_profileManager->refreshProfiles()) {
|
if(!_profileManager->refreshProfiles()) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error in ProfileManager", _profileManager->lastError().data(), window());
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
|
_profileManager->lastError().data(), window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,19 +85,18 @@ void SaveTool::drawProfileManager() {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(0);
|
ImGui::TableSetColumnIndex(0);
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(int(i));
|
||||||
if(ImGui::Selectable(profile.companyName().data(), false,
|
if(ImGui::Selectable(profile.companyName().data(), false,
|
||||||
ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_AllowItemOverlap))
|
ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_AllowItemOverlap))
|
||||||
{
|
{
|
||||||
_currentProfile = _profileManager->getProfile(i);
|
_currentProfile = _profileManager->getProfile(i);
|
||||||
initialiseMassManager();
|
initialiseMassManager();
|
||||||
|
initialiseFileWatcher();
|
||||||
_uiState = UiState::MainManager;
|
_uiState = UiState::MainManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
ImGui::Text("%s%s",
|
ImGui::TextUnformatted(profile.isDemo() ? "Demo" : "Full");
|
||||||
profile.isDemo() ? "Demo" : "Full",
|
|
||||||
profile.isLegacy() ? " (legacy)" : "");
|
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(2);
|
ImGui::TableSetColumnIndex(2);
|
||||||
if(ImGui::SmallButton(ICON_FA_FILE_ARCHIVE)) {
|
if(ImGui::SmallButton(ICON_FA_FILE_ARCHIVE)) {
|
||||||
|
@ -136,7 +138,7 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||||
if(ImGui::BeginPopupModal("Restore backup", nullptr,
|
if(ImGui::BeginPopupModal("Restore backup", nullptr,
|
||||||
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
|
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
{
|
{
|
||||||
ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
|
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f);
|
||||||
ImGui::Text("Are you sure you want to restore the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? Any existing data will be overwritten.",
|
ImGui::Text("Are you sure you want to restore the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? Any existing data will be overwritten.",
|
||||||
_profileManager->backups()[backup_index].company.data(),
|
_profileManager->backups()[backup_index].company.data(),
|
||||||
_profileManager->backups()[backup_index].timestamp.year,
|
_profileManager->backups()[backup_index].timestamp.year,
|
||||||
|
@ -158,7 +160,11 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||||
if(!_profileManager->restoreBackup(backup_index)) {
|
if(!_profileManager->restoreBackup(backup_index)) {
|
||||||
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
||||||
}
|
}
|
||||||
_profileManager->refreshProfiles();
|
if(!_profileManager->refreshProfiles()) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
|
_profileManager->lastError().data(), window());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -175,7 +181,7 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||||
if(ImGui::BeginPopupModal("Delete backup", nullptr,
|
if(ImGui::BeginPopupModal("Delete backup", nullptr,
|
||||||
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
|
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
{
|
{
|
||||||
ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
|
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f);
|
||||||
ImGui::Text("Are you sure you want to delete the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? This operation is irreversible.",
|
ImGui::Text("Are you sure you want to delete the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? This operation is irreversible.",
|
||||||
_profileManager->backups()[backup_index].company.data(),
|
_profileManager->backups()[backup_index].company.data(),
|
||||||
_profileManager->backups()[backup_index].timestamp.year,
|
_profileManager->backups()[backup_index].timestamp.year,
|
||||||
|
@ -229,7 +235,7 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_profileManager->backups().empty()) {
|
if(_profileManager->backups().isEmpty()) {
|
||||||
ImGui::TextDisabled("No backups were found.");
|
ImGui::TextDisabled("No backups were found.");
|
||||||
}
|
}
|
||||||
else if(ImGui::BeginTable("##Backups", 4,
|
else if(ImGui::BeginTable("##Backups", 4,
|
||||||
|
@ -275,12 +281,10 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||||
backup.timestamp.second);
|
backup.timestamp.second);
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(2);
|
ImGui::TableSetColumnIndex(2);
|
||||||
ImGui::Text("%s%s",
|
ImGui::TextUnformatted(backup.type == ProfileType::Demo ? "Demo" : "Full");
|
||||||
backup.type == ProfileType::Demo ? "Demo" : "Full",
|
|
||||||
backup.version == ProfileVersion::Legacy ? " (legacy)" : "");
|
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(3);
|
ImGui::TableSetColumnIndex(3);
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(int(i));
|
||||||
if(ImGui::SmallButton(ICON_FA_UNDO)) {
|
if(ImGui::SmallButton(ICON_FA_UNDO)) {
|
||||||
backup_index = i;
|
backup_index = i;
|
||||||
ImGui::OpenPopup(restore_backup_popup_id);
|
ImGui::OpenPopup(restore_backup_popup_id);
|
||||||
|
@ -337,12 +341,18 @@ auto SaveTool::drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID {
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
if(ImGui::Button("Yes")) {
|
if(ImGui::Button("Yes")) {
|
||||||
_profileManager->backupProfile(profile_index, true);
|
if(!_profileManager->backupProfile(profile_index, true)) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
|
_profileManager->lastError().data(), window());
|
||||||
|
}
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::Button("No", ImGui::GetItemRectSize())) {
|
if(ImGui::Button("No", ImGui::GetItemRectSize())) {
|
||||||
_profileManager->backupProfile(profile_index, false);
|
if(!_profileManager->backupProfile(profile_index, false)) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
|
_profileManager->lastError().data(), window());
|
||||||
|
}
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -370,7 +380,7 @@ auto SaveTool::drawDeleteProfilePopup(std::size_t profile_index) -> ImGuiID {
|
||||||
delete_builds = false;
|
delete_builds = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
|
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f);
|
||||||
ImGui::Text("Are you sure you want to delete the %s profile named %s ? This operation is irreversible.",
|
ImGui::Text("Are you sure you want to delete the %s profile named %s ? This operation is irreversible.",
|
||||||
_profileManager->profiles()[profile_index].isDemo() ? "demo" : "full game",
|
_profileManager->profiles()[profile_index].isDemo() ? "demo" : "full game",
|
||||||
_profileManager->profiles()[profile_index].companyName().data());
|
_profileManager->profiles()[profile_index].companyName().data());
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
// 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 <Corrade/Utility/Format.h>
|
||||||
|
|
||||||
|
#include <SDL_events.h>
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "SaveTool.h"
|
||||||
|
|
||||||
|
void SaveTool::updateCheckEvent(SDL_Event& event) {
|
||||||
|
_updateThread.join();
|
||||||
|
|
||||||
|
if(event.user.code == CurlInitFailed) {
|
||||||
|
_queue.addToast(Toast::Type::Error, "Couldn't initialise libcurl. Update check aborted."_s);
|
||||||
|
LOG_ERROR("Couldn't initialise libcurl. Update check aborted.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(event.user.code == CurlError) {
|
||||||
|
Containers::String error{static_cast<char*>(event.user.data2), CURL_ERROR_SIZE, nullptr};
|
||||||
|
_queue.addToast(Toast::Type::Error, error, std::chrono::milliseconds{5000});
|
||||||
|
_queue.addToast(Toast::Type::Error, static_cast<char*>(event.user.data1),
|
||||||
|
std::chrono::milliseconds{5000});
|
||||||
|
LOG_ERROR_FORMAT("{}: {}", static_cast<char*>(event.user.data1), static_cast<char*>(event.user.data2));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(event.user.code == CurlTimeout) {
|
||||||
|
_queue.addToast(Toast::Type::Error, "The request timed out."_s);
|
||||||
|
LOG_ERROR("The request timed out.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if(event.user.code != 200) {
|
||||||
|
_queue.addToast(Toast::Type::Error,
|
||||||
|
Utility::format("The request failed with error code {}.", event.user.code));
|
||||||
|
LOG_ERROR_FORMAT("The request failed with error code {}.", event.user.code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Version {
|
||||||
|
explicit Version(Containers::StringView str) {
|
||||||
|
std::size_t start_point = 0;
|
||||||
|
|
||||||
|
if(str[0] == 'v') {
|
||||||
|
start_point++;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto components = Containers::StringView{str.data() + start_point}.split('.');
|
||||||
|
|
||||||
|
major = std::strtol(components[0].data(), nullptr, 10);
|
||||||
|
minor = std::strtol(components[1].data(), nullptr, 10);
|
||||||
|
patch = std::strtol(components[2].data(), nullptr, 10);
|
||||||
|
|
||||||
|
fullVersion = major * 10000 + minor * 100 + patch;
|
||||||
|
|
||||||
|
if(str.hasSuffix("-pre")) {
|
||||||
|
prerelease = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Int fullVersion;
|
||||||
|
Int major = 0;
|
||||||
|
Int minor = 0;
|
||||||
|
Int patch = 0;
|
||||||
|
bool prerelease = false;
|
||||||
|
|
||||||
|
bool operator==(const Version& other) const {
|
||||||
|
return fullVersion == other.fullVersion && prerelease == other.prerelease;
|
||||||
|
}
|
||||||
|
bool operator>(const Version& other) const {
|
||||||
|
if((fullVersion > other.fullVersion) ||
|
||||||
|
(fullVersion == other.fullVersion && !prerelease && other.prerelease))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
explicit operator Containers::String() const {
|
||||||
|
return Utility::format("{}.{}.{}{}", major, minor, patch, prerelease ? "-pre" : "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Version current_ver{SAVETOOL_VERSION};
|
||||||
|
|
||||||
|
auto str = static_cast<char*>(event.user.data1);
|
||||||
|
Containers::String response{str, strlen(str), nullptr};
|
||||||
|
auto components = response.splitOnAnyWithoutEmptyParts("\r\n");
|
||||||
|
|
||||||
|
Version latest_ver{components.front()};
|
||||||
|
|
||||||
|
if(latest_ver > current_ver) {
|
||||||
|
_queue.addToast(Toast::Type::Warning,
|
||||||
|
"Your version is out of date.\nCheck the settings for more information."_s,
|
||||||
|
std::chrono::milliseconds{5000});
|
||||||
|
_updateAvailable = true;
|
||||||
|
_latestVersion = Containers::String{latest_ver};
|
||||||
|
_releaseLink = Utility::format("https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool/releases/tag/v{}",
|
||||||
|
components.front());
|
||||||
|
_downloadLink = components.back();
|
||||||
|
}
|
||||||
|
else if(latest_ver == current_ver || (current_ver > latest_ver && current_ver.prerelease)) {
|
||||||
|
_queue.addToast(Toast::Type::Success, "The application is already up to date."_s);
|
||||||
|
}
|
||||||
|
else if(current_ver > latest_ver && !current_ver.prerelease) {
|
||||||
|
_queue.addToast(Toast::Type::Warning,
|
||||||
|
"Your version is more recent than the latest one in the repo. How???"_s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto writeData(char* ptr, std::size_t size, std::size_t nmemb, Containers::String* buf)-> std::size_t {
|
||||||
|
if(!ptr || !buf) return 0;
|
||||||
|
(*buf) = Utility::format("{}{}", *buf, Containers::StringView{ptr, size * nmemb});
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveTool::checkForUpdates() {
|
||||||
|
SDL_Event event;
|
||||||
|
SDL_zero(event);
|
||||||
|
event.type = _updateEventId;
|
||||||
|
|
||||||
|
auto curl = curl_easy_init();
|
||||||
|
if(!curl) {
|
||||||
|
event.user.code = CurlInitFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(curl) {
|
||||||
|
Containers::String response_body{Containers::AllocatedInit, ""};
|
||||||
|
Containers::String error_buffer{ValueInit, CURL_ERROR_SIZE * 2};
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "https://williamjcm.ovh/mbst/version");
|
||||||
|
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer.data());
|
||||||
|
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 10000L);
|
||||||
|
|
||||||
|
auto code = curl_easy_perform(curl);
|
||||||
|
|
||||||
|
if(code == CURLE_OK) {
|
||||||
|
long status = 0;
|
||||||
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
|
||||||
|
event.user.code = Int(status);
|
||||||
|
event.user.data1 = response_body.release();
|
||||||
|
}
|
||||||
|
else if(code == CURLE_OPERATION_TIMEDOUT) {
|
||||||
|
event.user.code = CurlTimeout;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
event.user.code = CurlError;
|
||||||
|
event.user.data1 = const_cast<char*>(curl_easy_strerror(code));
|
||||||
|
event.user.data2 = Containers::String{error_buffer}.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
|
@ -17,7 +17,6 @@
|
||||||
#include "SaveTool.h"
|
#include "SaveTool.h"
|
||||||
|
|
||||||
#include <Corrade/version.h>
|
#include <Corrade/version.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
|
||||||
|
|
||||||
#include <Magnum/version.h>
|
#include <Magnum/version.h>
|
||||||
#include <Magnum/versionIntegration.h>
|
#include <Magnum/versionIntegration.h>
|
||||||
|
@ -25,6 +24,8 @@
|
||||||
|
|
||||||
#include <zipconf.h>
|
#include <zipconf.h>
|
||||||
|
|
||||||
|
#include <curl/curlver.h>
|
||||||
|
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ extern const ImVec2 center_pivot;
|
||||||
|
|
||||||
void SaveTool::drawAbout() {
|
void SaveTool::drawAbout() {
|
||||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
||||||
ImGui::SetNextWindowSize({windowSize().x() * 0.8f, windowSize().y() * 0.75f}, ImGuiCond_Always);
|
ImGui::SetNextWindowSize({float(windowSize().x()) * 0.8f, float(windowSize().y()) * 0.75f}, ImGuiCond_Always);
|
||||||
|
|
||||||
ImGui::OpenPopup("About##AboutPopup");
|
ImGui::OpenPopup("About##AboutPopup");
|
||||||
if(!ImGui::BeginPopupModal("About##AboutPopup", &_aboutPopup,
|
if(!ImGui::BeginPopupModal("About##AboutPopup", &_aboutPopup,
|
||||||
|
@ -58,6 +59,16 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::TextWrapped("This application, made for the M.A.S.S. Builder community by Guillaume Jacquemin (aka William JCM), "
|
ImGui::TextWrapped("This application, made for the M.A.S.S. Builder community by Guillaume Jacquemin (aka William JCM), "
|
||||||
"is a rewrite of the wxWidgets-powered M.A.S.S. Builder Save Tool (formerly known as wxMASSManager).");
|
"is a rewrite of the wxWidgets-powered M.A.S.S. Builder Save Tool (formerly known as wxMASSManager).");
|
||||||
|
|
||||||
|
auto website = "https://williamjcm.ovh/coding/mbst";
|
||||||
|
drawAlignedText(ICON_FA_GLOBE " %s", website);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Button("Copy to clipboard")) {
|
||||||
|
ImGui::SetClipboardText(website);
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Button("Open in browser")) {
|
||||||
|
openUri(website);
|
||||||
|
}
|
||||||
auto repo = "https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool";
|
auto repo = "https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool";
|
||||||
drawAlignedText(ICON_FA_GIT_ALT " %s", repo);
|
drawAlignedText(ICON_FA_GIT_ALT " %s", repo);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -74,10 +85,10 @@ void SaveTool::drawAbout() {
|
||||||
if(ImGui::CollapsingHeader("Licence")) {
|
if(ImGui::CollapsingHeader("Licence")) {
|
||||||
ImGui::TextWrapped("This application is made available under the terms of the GNU General Public License, version 3, the full text of which is available below:");
|
ImGui::TextWrapped("This application is made available under the terms of the GNU General Public License, version 3, the full text of which is available below:");
|
||||||
|
|
||||||
if(ImGui::BeginChild("##GPL", {0.0f, windowSize().y() * 0.3f}, true)) {
|
if(ImGui::BeginChild("##GPL", {0.0f, float(windowSize().y()) * 0.3f}, true)) {
|
||||||
static auto licence = _rs.getRaw("COPYING");
|
static auto licence = _rs.getRaw("COPYING");
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
||||||
ImGui::TextUnformatted(licence);
|
ImGui::TextEx(licence.data(), licence.data() + licence.size(), ImGuiTextFlags_None);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
@ -104,9 +115,9 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
ImGui::TextUnformatted("Licence: MIT");
|
||||||
|
|
||||||
static auto corrade_licence = _rs.getRaw("COPYING.Corrade");
|
static auto corrade_licence = _rs.getRaw("COPYING.Corrade");
|
||||||
if(ImGui::BeginChild("##CorradeLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
if(ImGui::BeginChild("##CorradeLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) {
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
||||||
ImGui::TextUnformatted(corrade_licence);
|
ImGui::TextEx(corrade_licence.data(), corrade_licence.data() + corrade_licence.size(), ImGuiTextFlags_None);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
@ -132,9 +143,9 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
ImGui::TextUnformatted("Licence: MIT");
|
||||||
|
|
||||||
static auto magnum_licence = _rs.getRaw("COPYING.Magnum");
|
static auto magnum_licence = _rs.getRaw("COPYING.Magnum");
|
||||||
if(ImGui::BeginChild("##MagnumLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
if(ImGui::BeginChild("##MagnumLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) {
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
||||||
ImGui::TextUnformatted(magnum_licence);
|
ImGui::TextEx(magnum_licence.data(), magnum_licence.data() + magnum_licence.size(), ImGuiTextFlags_None);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
@ -158,9 +169,9 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
ImGui::TextUnformatted("Licence: MIT");
|
||||||
|
|
||||||
static auto imgui_licence = _rs.getRaw("LICENSE.ImGui");
|
static auto imgui_licence = _rs.getRaw("LICENSE.ImGui");
|
||||||
if(ImGui::BeginChild("##ImGuiLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
if(ImGui::BeginChild("##ImGuiLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) {
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
||||||
ImGui::TextUnformatted(imgui_licence);
|
ImGui::TextEx(imgui_licence.data(), imgui_licence.data() + imgui_licence.size(), ImGuiTextFlags_None);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
@ -184,9 +195,9 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::TextUnformatted("Licence: zlib");
|
ImGui::TextUnformatted("Licence: zlib");
|
||||||
|
|
||||||
static auto sdl_licence = _rs.getRaw("LICENSE.SDL");
|
static auto sdl_licence = _rs.getRaw("LICENSE.SDL");
|
||||||
if(ImGui::BeginChild("##SDLLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
if(ImGui::BeginChild("##SDLLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) {
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
||||||
ImGui::TextUnformatted(sdl_licence);
|
ImGui::TextEx(sdl_licence.data(), sdl_licence.data() + sdl_licence.size(), ImGuiTextFlags_None);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
@ -210,9 +221,9 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::TextUnformatted("Licence: 3-clause BSD");
|
ImGui::TextUnformatted("Licence: 3-clause BSD");
|
||||||
|
|
||||||
static auto libzip_licence = _rs.getRaw("LICENSE.libzip");
|
static auto libzip_licence = _rs.getRaw("LICENSE.libzip");
|
||||||
if(ImGui::BeginChild("##libzipLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
if(ImGui::BeginChild("##libzipLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) {
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
||||||
ImGui::TextUnformatted(libzip_licence);
|
ImGui::TextEx(libzip_licence.data(), libzip_licence.data() + libzip_licence.size(), ImGuiTextFlags_None);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
@ -235,9 +246,9 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
ImGui::TextUnformatted("Licence: MIT");
|
||||||
|
|
||||||
static auto efsw_licence = _rs.getRaw("LICENSE.efsw");
|
static auto efsw_licence = _rs.getRaw("LICENSE.efsw");
|
||||||
if(ImGui::BeginChild("##efswLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
if(ImGui::BeginChild("##efswLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) {
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
||||||
ImGui::TextUnformatted(efsw_licence);
|
ImGui::TextEx(efsw_licence.data(), efsw_licence.data() + efsw_licence.size(), ImGuiTextFlags_None);
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
@ -245,49 +256,25 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::TreeNodeEx("C++ Requests (cpr)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
if(ImGui::TreeNodeEx("libcurl", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||||
auto cpr_website = "https://whoshuu.github.io/cpr/";
|
ImGui::Text("Version used: %s", LIBCURL_VERSION);
|
||||||
drawAlignedText(ICON_FA_GLOBE " %s", cpr_website);
|
auto curl_website = "https://curl.se/libcurl";
|
||||||
|
drawAlignedText(ICON_FA_GLOBE " %s", curl_website);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::Button("Copy to clipboard")) {
|
if(ImGui::Button("Copy to clipboard")) {
|
||||||
ImGui::SetClipboardText(cpr_website);
|
ImGui::SetClipboardText(curl_website);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::Button("Open in browser")) {
|
if(ImGui::Button("Open in browser")) {
|
||||||
openUri(cpr_website);
|
openUri(curl_website);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
ImGui::TextUnformatted("Licence: MIT/X derivative");
|
||||||
|
|
||||||
static auto cpr_licence = _rs.getRaw("LICENSE.cpr");
|
static auto curl_licence = _rs.getRaw("LICENSE.curl");
|
||||||
if(ImGui::BeginChild("##cprLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
if(ImGui::BeginChild("##libcurlLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) {
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
||||||
ImGui::TextUnformatted(cpr_licence);
|
ImGui::TextEx(curl_licence.data(), curl_licence.data() + curl_licence.size(), ImGuiTextFlags_None);
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui::TreeNodeEx("JSON for Modern C++ (aka json.hpp)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
|
||||||
auto json_website = "https://json.nlohmann.me/";
|
|
||||||
drawAlignedText(ICON_FA_GLOBE " %s", json_website);
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button("Copy to clipboard")) {
|
|
||||||
ImGui::SetClipboardText(json_website);
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button("Open in browser")) {
|
|
||||||
openUri(json_website);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
|
||||||
|
|
||||||
static auto json_licence = _rs.getRaw("LICENSE.json");
|
|
||||||
if(ImGui::BeginChild("##jsonLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextUnformatted(json_licence);
|
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
|
@ -14,13 +14,13 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "SaveTool.h"
|
|
||||||
|
|
||||||
#include <Corrade/Utility/Path.h>
|
#include <Corrade/Utility/Path.h>
|
||||||
|
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
||||||
|
|
||||||
|
#include "SaveTool.h"
|
||||||
|
|
||||||
void SaveTool::drawMainMenu() {
|
void SaveTool::drawMainMenu() {
|
||||||
if(ImGui::BeginMainMenuBar()) {
|
if(ImGui::BeginMainMenuBar()) {
|
||||||
if(ImGui::BeginMenu("Save Tool##SaveToolMenu")) {
|
if(ImGui::BeginMenu("Save Tool##SaveToolMenu")) {
|
||||||
|
@ -55,58 +55,59 @@ void SaveTool::drawMainMenu() {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if(ImGui::BeginMenu(ICON_FA_COG " Settings")) {
|
if(ImGui::BeginMenu(ICON_FA_COG " Settings")) {
|
||||||
drawAlignedText("Frame limiter:");
|
ImGui::BeginGroup();
|
||||||
|
drawAlignedText("Vertical sync:");
|
||||||
|
if(_swapInterval == 0) {
|
||||||
|
drawAlignedText("FPS cap:");
|
||||||
|
}
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
static UnsignedByte selection = static_cast<UnsignedByte>(_framelimit);
|
ImGui::BeginGroup();
|
||||||
static const char* framelimit_labels[3] = {
|
|
||||||
"V-sync",
|
static const char* framelimit_labels[] = {
|
||||||
"Half V-sync",
|
"Off",
|
||||||
"FPS cap, no V-sync"
|
"Every VBLANK",
|
||||||
|
"Every second VBLANK",
|
||||||
|
"Every third VBLANK",
|
||||||
};
|
};
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth());
|
ImGui::PushItemWidth(300.0f);
|
||||||
if(ImGui::BeginCombo("##FrameLimit", framelimit_labels[selection])) {
|
|
||||||
if(ImGui::Selectable(framelimit_labels[0], _framelimit == Framelimit::Vsync)) {
|
if(ImGui::BeginCombo("##FrameLimit", framelimit_labels[_swapInterval])) {
|
||||||
selection = 0;
|
for(int i = 0; i <= 3; i++) {
|
||||||
_framelimit = Framelimit::Vsync;
|
if(ImGui::Selectable(framelimit_labels[i], _swapInterval == i)) {
|
||||||
setSwapInterval(1);
|
_swapInterval = i;
|
||||||
}
|
setSwapInterval(i);
|
||||||
if(ImGui::Selectable(framelimit_labels[1], _framelimit == Framelimit::HalfVsync)) {
|
if(i == 0) {
|
||||||
selection = 1;
|
setMinimalLoopPeriod(0);
|
||||||
_framelimit = Framelimit::HalfVsync;
|
}
|
||||||
setSwapInterval(2);
|
}
|
||||||
}
|
|
||||||
if(ImGui::Selectable(framelimit_labels[2], _framelimit == Framelimit::FpsCap)) {
|
|
||||||
selection = 2;
|
|
||||||
_framelimit = Framelimit::FpsCap;
|
|
||||||
setSwapInterval(0);
|
|
||||||
setMinimalLoopPeriod(1000 / _fpsCap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndCombo();
|
ImGui::EndCombo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_framelimit == Framelimit::FpsCap) {
|
if(_swapInterval == 0) {
|
||||||
static constexpr UnsignedInt min_fps = 15;
|
ImGui::SliderFloat("##FpsCapSlider", &_fpsCap, 15.0f, 301.0f,
|
||||||
static constexpr UnsignedInt max_fps = 150;
|
_fpsCap != 301.0f ? "%.0f" : "Uncapped", ImGuiSliderFlags_AlwaysClamp);
|
||||||
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth());
|
|
||||||
if(ImGui::SliderScalar("##FpsSlider", ImGuiDataType_U32, &_fpsCap, &min_fps, &max_fps, "%u FPS", ImGuiSliderFlags_AlwaysClamp)) {
|
|
||||||
setMinimalLoopPeriod(1000 / _fpsCap);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
ImGui::Checkbox("Cheat mode", &_cheatMode);
|
ImGui::Checkbox("Cheat mode", &_cheatMode);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
drawHelpMarker("This gives access to save edition features that can be considered cheats.",
|
drawHelpMarker("This gives access to save edition features that can be considered cheats.",
|
||||||
Float(windowSize().x()) * 0.4f);
|
Float(windowSize().x()) * 0.4f);
|
||||||
|
|
||||||
ImGui::Checkbox("Unsafe mode", &_unsafeMode);
|
ImGui::Checkbox("Advanced mode", &_advancedMode);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
drawHelpMarker("This allows changing the state of save files in the game's save folder even when the game is running.",
|
drawHelpMarker("This gives access to editing values that have unknown purposes or are undocumented.",
|
||||||
Float(windowSize().x()) * 0.4f);
|
Float(windowSize().x()) * 0.4f);
|
||||||
|
|
||||||
ImGui::Checkbox("Check for updates on startup", &_checkUpdatesOnStartup);
|
ImGui::Checkbox("Check for updates on startup", &_checkUpdatesOnStartup);
|
||||||
|
@ -155,11 +156,11 @@ void SaveTool::drawMainMenu() {
|
||||||
|
|
||||||
if(ImGui::BeginMenu(ICON_FA_DISCORD " Discord communities")) {
|
if(ImGui::BeginMenu(ICON_FA_DISCORD " Discord communities")) {
|
||||||
if(ImGui::MenuItem("Official server")) {
|
if(ImGui::MenuItem("Official server")) {
|
||||||
openUri("https://discord.gg/quS7E46");
|
openUri("https://discord.gg/sekai-project");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::MenuItem("Community server")) {
|
if(ImGui::MenuItem("Community server")) {
|
||||||
openUri("https://discord.gg/YSSRTRB");
|
openUri("https://discord.gg/massbuildercommunity");
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
|
@ -168,7 +169,7 @@ void SaveTool::drawMainMenu() {
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SAVETOOL_DEBUG_BUILD
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
if(ImGui::BeginMenu("Debug tools")) {
|
if(ImGui::BeginMenu("Debug tools")) {
|
||||||
ImGui::MenuItem("ImGui demo window", nullptr, &_demoWindow);
|
ImGui::MenuItem("ImGui demo window", nullptr, &_demoWindow);
|
||||||
ImGui::MenuItem("ImGui style editor", nullptr, &_styleEditor);
|
ImGui::MenuItem("ImGui style editor", nullptr, &_styleEditor);
|
||||||
|
@ -176,7 +177,7 @@ void SaveTool::drawMainMenu() {
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(ImGui::BeginMenu("Help")) {
|
if(ImGui::BeginMenu("Help")) {
|
||||||
if(ImGui::BeginMenu(ICON_FA_KEYBOARD " Keyboard shortcuts")) {
|
if(ImGui::BeginMenu(ICON_FA_KEYBOARD " Keyboard shortcuts")) {
|
||||||
|
|
|
@ -142,12 +142,9 @@ void ToastQueue::draw(Vector2i viewport_size) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(current->message().size() > 127) {
|
ImGui::PushTextWrapPos(500.0f);
|
||||||
ImGui::TextColored(colour, "%.*s...", 127, current->message().data());
|
ImGui::TextColored(colour, current->message().data());
|
||||||
}
|
ImGui::PopTextWrapPos();
|
||||||
else {
|
|
||||||
ImGui::TextColored(colour, current->message().data());
|
|
||||||
}
|
|
||||||
|
|
||||||
height += ImGui::GetWindowHeight() + toast_spacing;
|
height += ImGui::GetWindowHeight() + toast_spacing;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ class Toast {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Type _type{Type::Default};
|
Type _type{Type::Default};
|
||||||
Containers::StringView _message;
|
Containers::String _message;
|
||||||
std::chrono::milliseconds _timeout;
|
std::chrono::milliseconds _timeout;
|
||||||
std::chrono::steady_clock::time_point _creationTime;
|
std::chrono::steady_clock::time_point _creationTime;
|
||||||
Animation::Track<UnsignedInt, Phase> _phaseTrack;
|
Animation::Track<UnsignedInt, Phase> _phaseTrack;
|
||||||
|
|
|
@ -19,14 +19,15 @@
|
||||||
#include <Corrade/Containers/Array.h>
|
#include <Corrade/Containers/Array.h>
|
||||||
#include <Corrade/Containers/String.h>
|
#include <Corrade/Containers/String.h>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
#include "BinaryReader.h"
|
#include "BinaryReader.h"
|
||||||
|
|
||||||
BinaryReader::BinaryReader(Containers::StringView filename) {
|
BinaryReader::BinaryReader(Containers::StringView filename) {
|
||||||
_file = std::fopen(filename.data(), "rb");
|
_file = std::fopen(filename.data(), "rb");
|
||||||
|
|
||||||
if(!_file) {
|
if(!_file) {
|
||||||
Utility::Error{} << "Couldn't open" << filename << "for reading:\n"
|
LOG_ERROR_FORMAT("Couldn't open {} for reading: {}", filename, std::strerror(errno));
|
||||||
<< std::strerror(errno);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
#include "BinaryWriter.h"
|
#include "BinaryWriter.h"
|
||||||
|
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
|
@ -23,8 +25,7 @@ using namespace Containers::Literals;
|
||||||
BinaryWriter::BinaryWriter(Containers::StringView filename) {
|
BinaryWriter::BinaryWriter(Containers::StringView filename) {
|
||||||
_file = std::fopen(filename.data(), "wb");
|
_file = std::fopen(filename.data(), "wb");
|
||||||
if(!_file) {
|
if(!_file) {
|
||||||
Utility::Error{} << "Couldn't open"_s << filename << "for reading:\n"_s
|
LOG_ERROR_FORMAT("Couldn't open {} for reading: {}", filename, std::strerror(errno));
|
||||||
<< std::strerror(errno);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +117,7 @@ auto BinaryWriter::writeArray(Containers::ArrayView<const char> array) -> bool {
|
||||||
|
|
||||||
auto BinaryWriter::writeUEString(Containers::StringView str) -> bool {
|
auto BinaryWriter::writeUEString(Containers::StringView str) -> bool {
|
||||||
if(str.size() > UINT32_MAX) {
|
if(str.size() > UINT32_MAX) {
|
||||||
Utility::Error{} << "BinaryWriter::writeUEString(): string is too big."_s;
|
LOG_ERROR_FORMAT("String is too big. Expected size() < UINT32_MAX, got {} instead.", str.size());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
#include "BinaryReader.h"
|
#include "BinaryReader.h"
|
||||||
#include "BinaryWriter.h"
|
#include "BinaryWriter.h"
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
#include "PropertySerialiser.h"
|
#include "PropertySerialiser.h"
|
||||||
|
|
||||||
PropertySerialiser::PropertySerialiser() {
|
PropertySerialiser::PropertySerialiser() {
|
||||||
|
@ -164,7 +166,7 @@ auto PropertySerialiser::deserialise(Containers::String name, Containers::String
|
||||||
prop = serialiser->deserialise(name, type, value_length, reader, *this);
|
prop = serialiser->deserialise(name, type, value_length, reader, *this);
|
||||||
|
|
||||||
if(!prop) {
|
if(!prop) {
|
||||||
!Utility::Error{} << "No prop in" << __func__;
|
LOG_ERROR("No property.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
#include "../PropertySerialiser.h"
|
#include "../PropertySerialiser.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "ArrayPropertySerialiser.h"
|
#include "ArrayPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -28,16 +29,19 @@ auto ArrayPropertySerialiser::deserialiseProperty(Containers::StringView name, C
|
||||||
{
|
{
|
||||||
Containers::String item_type;
|
Containers::String item_type;
|
||||||
if(!reader.readUEString(item_type)) {
|
if(!reader.readUEString(item_type)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read the item type of array property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in array property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedInt item_count;
|
UnsignedInt item_count;
|
||||||
if(!reader.readUnsignedInt(item_count)) {
|
if(!reader.readUnsignedInt(item_count)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read array property {}'s item count.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,6 +57,7 @@ auto ArrayPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, U
|
||||||
{
|
{
|
||||||
auto array_prop = dynamic_cast<ArrayProperty*>(prop.get());
|
auto array_prop = dynamic_cast<ArrayProperty*>(prop.get());
|
||||||
if(!array_prop) {
|
if(!array_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid array property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "BoolPropertySerialiser.h"
|
#include "BoolPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -30,15 +31,18 @@ auto BoolPropertySerialiser::deserialise(Containers::StringView name, Containers
|
||||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||||
{
|
{
|
||||||
if(value_length != 0) {
|
if(value_length != 0) {
|
||||||
|
LOG_ERROR_FORMAT("Invalid value length for bool property {}. Expected 0, got {} instead.", name, value_length);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Short value;
|
Short value;
|
||||||
if(!reader.readShort(value)) {
|
if(!reader.readShort(value)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read bool property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(value > 1 || value < 0) {
|
if(value > 1 || value < 0) {
|
||||||
|
LOG_ERROR_FORMAT("Bool property {}'s value is invalid. Expected 1 or 0, got {} instead.", name, value);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +56,8 @@ auto BoolPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto bool_prop = dynamic_cast<BoolProperty*>(prop.get());
|
auto bool_prop = dynamic_cast<BoolProperty*>(prop.get());
|
||||||
|
|
||||||
if(!bool_prop) {
|
if(!bool_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid bool property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "BytePropertySerialiser.h"
|
#include "BytePropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -33,16 +34,19 @@ auto BytePropertySerialiser::deserialise(Containers::StringView name, Containers
|
||||||
|
|
||||||
if(value_length != UnsignedLong(-1)) {
|
if(value_length != UnsignedLong(-1)) {
|
||||||
if(!reader.readUEString(prop->enumType)) {
|
if(!reader.readUEString(prop->enumType)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read byte property {}'s enum type.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in byte property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readUEString(prop->enumValue)) {
|
if(!reader.readUEString(prop->enumValue)) {
|
||||||
|
LOG_ERROR("Couldn't read byte property's enum value.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,8 +68,8 @@ auto BytePropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto byte_prop = dynamic_cast<ByteProperty*>(prop.get());
|
auto byte_prop = dynamic_cast<ByteProperty*>(prop.get());
|
||||||
|
|
||||||
if(!byte_prop) {
|
if(!byte_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid byte property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "ColourPropertySerialiser.h"
|
#include "ColourPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ auto ColourPropertySerialiser::deserialiseProperty(Containers::StringView name,
|
||||||
if(!reader.readFloat(prop->r) || !reader.readFloat(prop->g) ||
|
if(!reader.readFloat(prop->r) || !reader.readFloat(prop->g) ||
|
||||||
!reader.readFloat(prop->b) || !reader.readFloat(prop->a))
|
!reader.readFloat(prop->b) || !reader.readFloat(prop->a))
|
||||||
{
|
{
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read colour property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +40,8 @@ auto ColourPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop,
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto colour_prop = dynamic_cast<ColourStructProperty*>(prop.get());
|
auto colour_prop = dynamic_cast<ColourStructProperty*>(prop.get());
|
||||||
|
|
||||||
if(!colour_prop) {
|
if(!colour_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid colour property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "DateTimePropertySerialiser.h"
|
#include "DateTimePropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ auto DateTimePropertySerialiser::deserialiseProperty(Containers::StringView name
|
||||||
auto prop = Containers::pointer<DateTimeStructProperty>();
|
auto prop = Containers::pointer<DateTimeStructProperty>();
|
||||||
|
|
||||||
if(!reader.readUnsignedLong(prop->timestamp)) {
|
if(!reader.readUnsignedLong(prop->timestamp)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read date/time property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +38,8 @@ auto DateTimePropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto dt_prop = dynamic_cast<DateTimeStructProperty*>(prop.get());
|
auto dt_prop = dynamic_cast<DateTimeStructProperty*>(prop.get());
|
||||||
|
|
||||||
if(!dt_prop) {
|
if(!dt_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid date/time property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "EnumPropertySerialiser.h"
|
#include "EnumPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -32,15 +33,18 @@ auto EnumPropertySerialiser::deserialise(Containers::StringView name, Containers
|
||||||
auto prop = Containers::pointer<EnumProperty>();
|
auto prop = Containers::pointer<EnumProperty>();
|
||||||
|
|
||||||
if(!reader.readUEString(prop->enumType)) {
|
if(!reader.readUEString(prop->enumType)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read enum property {}'s enum type.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in enum property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readUEString(prop->value)) {
|
if(!reader.readUEString(prop->value)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read enum property {}'s enum value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,8 +55,8 @@ auto EnumPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto enum_prop = dynamic_cast<EnumProperty*>(prop.get());
|
auto enum_prop = dynamic_cast<EnumProperty*>(prop.get());
|
||||||
|
|
||||||
if(!enum_prop) {
|
if(!enum_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid enum property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "FloatPropertySerialiser.h"
|
#include "FloatPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -33,10 +34,12 @@ auto FloatPropertySerialiser::deserialise(Containers::StringView name, Container
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in float property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readFloat(prop->value)) {
|
if(!reader.readFloat(prop->value)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read float property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +50,8 @@ auto FloatPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedL
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto float_prop = dynamic_cast<FloatProperty*>(prop.get());
|
auto float_prop = dynamic_cast<FloatProperty*>(prop.get());
|
||||||
|
|
||||||
if(!float_prop) {
|
if(!float_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid float property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "GuidPropertySerialiser.h"
|
#include "GuidPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ auto GuidPropertySerialiser::deserialiseProperty(Containers::StringView name, Co
|
||||||
auto prop = Containers::pointer<GuidStructProperty>();
|
auto prop = Containers::pointer<GuidStructProperty>();
|
||||||
|
|
||||||
if(!reader.readStaticArray(prop->guid)) {
|
if(!reader.readStaticArray(prop->guid)) {
|
||||||
Utility::Error{} << "Couldn't read GUID in"_s << __func__;
|
LOG_ERROR_FORMAT("Couldn't read GUID property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,8 +40,8 @@ auto GuidPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Un
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto guid_prop = dynamic_cast<GuidStructProperty*>(prop.get());
|
auto guid_prop = dynamic_cast<GuidStructProperty*>(prop.get());
|
||||||
|
|
||||||
if(!guid_prop) {
|
if(!guid_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid byte property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "IntPropertySerialiser.h"
|
#include "IntPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ auto IntPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
||||||
|
|
||||||
if(value_length == UnsignedLong(-1)) {
|
if(value_length == UnsignedLong(-1)) {
|
||||||
if(!reader.readInt(prop->value)) {
|
if(!reader.readInt(prop->value)) {
|
||||||
|
LOG_ERROR("Couldn't read int property's value.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +38,12 @@ auto IntPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in int property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readInt(prop->value)) {
|
if(!reader.readInt(prop->value)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read int property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +56,8 @@ auto IntPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto int_prop = dynamic_cast<IntProperty*>(prop.get());
|
auto int_prop = dynamic_cast<IntProperty*>(prop.get());
|
||||||
|
|
||||||
if(!int_prop) {
|
if(!int_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid int property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
#include "../PropertySerialiser.h"
|
#include "../PropertySerialiser.h"
|
||||||
|
|
||||||
#include "../Types/NoneProperty.h"
|
#include "../Types/NoneProperty.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "MapPropertySerialiser.h"
|
#include "MapPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -31,25 +31,30 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
||||||
auto prop = Containers::pointer<MapProperty>();
|
auto prop = Containers::pointer<MapProperty>();
|
||||||
|
|
||||||
if(!reader.readUEString(prop->keyType)) {
|
if(!reader.readUEString(prop->keyType)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read map property {}'s key type.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readUEString(prop->valueType)) {
|
if(!reader.readUEString(prop->valueType)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read map property {}'s value type.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in map property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedInt null;
|
UnsignedInt null;
|
||||||
if(!reader.readUnsignedInt(null) || null != 0u) {
|
if(!reader.readUnsignedInt(null) || null != 0u) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null int in map property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedInt count;
|
UnsignedInt count;
|
||||||
if(!reader.readUnsignedInt(count)) {
|
if(!reader.readUnsignedInt(count)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read map property {}'s item count.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,10 +69,12 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
||||||
if(prop->keyType == "IntProperty"_s || prop->keyType == "StrProperty"_s) {
|
if(prop->keyType == "IntProperty"_s || prop->keyType == "StrProperty"_s) {
|
||||||
pair.key = serialiser.readItem(reader, prop->keyType, -1, name);
|
pair.key = serialiser.readItem(reader, prop->keyType, -1, name);
|
||||||
if(pair.key == nullptr) {
|
if(pair.key == nullptr) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a valid key in map property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // Add other branches depending on key type, should more maps appear in the future.
|
else { // Add other branches depending on key type, should more maps appear in the future.
|
||||||
|
LOG_ERROR_FORMAT("Key type {} not implemented.", prop->keyType);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,6 +112,7 @@ auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
|
||||||
{
|
{
|
||||||
auto map_prop = dynamic_cast<MapProperty*>(prop.get());
|
auto map_prop = dynamic_cast<MapProperty*>(prop.get());
|
||||||
if(!map_prop) {
|
if(!map_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid map property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,17 +128,20 @@ auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
|
||||||
UnsignedLong dummy_bytes_written = 0;
|
UnsignedLong dummy_bytes_written = 0;
|
||||||
for(auto& pair : map_prop->map) {
|
for(auto& pair : map_prop->map) {
|
||||||
if(!serialiser.writeItem(pair.key, map_prop->keyType, dummy_bytes_written, writer)) {
|
if(!serialiser.writeItem(pair.key, map_prop->keyType, dummy_bytes_written, writer)) {
|
||||||
|
LOG_ERROR("Couldn't write a key.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& value : pair.values) {
|
for(auto& value : pair.values) {
|
||||||
if(map_prop->valueType == "StructProperty"_s) {
|
if(map_prop->valueType == "StructProperty"_s) {
|
||||||
if(!serialiser.write(value, dummy_bytes_written, writer)) {
|
if(!serialiser.write(value, dummy_bytes_written, writer)) {
|
||||||
|
LOG_ERROR("Couldn't write a value.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(!serialiser.writeItem(value, map_prop->valueType, dummy_bytes_written, writer)) {
|
if(!serialiser.writeItem(value, map_prop->valueType, dummy_bytes_written, writer)) {
|
||||||
|
LOG_ERROR("Couldn't write a value.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
#include "../PropertySerialiser.h"
|
#include "../PropertySerialiser.h"
|
||||||
|
|
||||||
#include "../Types/IntProperty.h"
|
#include "../Types/IntProperty.h"
|
||||||
#include "../Types/NoneProperty.h"
|
#include "../Types/NoneProperty.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "ResourcePropertySerialiser.h"
|
#include "ResourcePropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -31,49 +31,46 @@ auto ResourcePropertySerialiser::deserialiseProperty(Containers::StringView name
|
||||||
{
|
{
|
||||||
auto prop = Containers::pointer<ResourceItemValue>();
|
auto prop = Containers::pointer<ResourceItemValue>();
|
||||||
|
|
||||||
Containers::String str;
|
auto id_prop = serialiser.read(reader);
|
||||||
if(!reader.readUEString(str) || str != "ID_4_AAE08F17428E229EC7A2209F51081A21"_s) {
|
if(!id_prop) {
|
||||||
|
LOG_ERROR("Couldn't read the ID property."_s);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readUEString(str) || str != "IntProperty"_s) {
|
if((*id_prop->name) != "ID_4_AAE08F17428E229EC7A2209F51081A21"_s ||
|
||||||
|
id_prop->propertyType != "IntProperty"_s ||
|
||||||
|
dynamic_cast<IntProperty*>(id_prop.get()) == nullptr)
|
||||||
|
{
|
||||||
|
LOG_ERROR("The ID property is invalid."_s);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readUnsignedLong(value_length) || value_length != 4ull) {
|
prop->id = dynamic_cast<IntProperty*>(id_prop.get())->value;
|
||||||
|
|
||||||
|
auto value_prop = serialiser.read(reader);
|
||||||
|
if(!value_prop) {
|
||||||
|
LOG_ERROR("Couldn't read the value property."_s);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char terminator;
|
if((*value_prop->name) != "Quantity_3_560F09B5485C365D3041888910019CE3"_s ||
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
value_prop->propertyType != "IntProperty"_s ||
|
||||||
|
dynamic_cast<IntProperty*>(value_prop.get()) == nullptr)
|
||||||
|
{
|
||||||
|
LOG_ERROR("The value property is invalid."_s);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readInt(prop->id)) {
|
prop->quantity = dynamic_cast<IntProperty*>(value_prop.get())->value;
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!reader.readUEString(str) || str != "Quantity_3_560F09B5485C365D3041888910019CE3"_s) {
|
auto none_prop = serialiser.read(reader);
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!reader.readUEString(str) || str != "IntProperty"_s) {
|
if(!none_prop ||
|
||||||
return nullptr;
|
(*none_prop->name) != "None"_s ||
|
||||||
}
|
none_prop->propertyType != "NoneProperty"_s ||
|
||||||
|
!dynamic_cast<NoneProperty*>(none_prop.get()))
|
||||||
if(!reader.readUnsignedLong(value_length) || value_length != 4ull) {
|
{
|
||||||
return nullptr;
|
LOG_ERROR("Couldn't find a terminating NoneProperty."_s);
|
||||||
}
|
|
||||||
|
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!reader.readInt(prop->quantity)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!reader.readUEString(str) || str != "None"_s) {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +82,7 @@ auto ResourcePropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop
|
||||||
{
|
{
|
||||||
auto res_prop = dynamic_cast<ResourceItemValue*>(prop.get());
|
auto res_prop = dynamic_cast<ResourceItemValue*>(prop.get());
|
||||||
if(!res_prop) {
|
if(!res_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid ResourceItemValue property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "RotatorPropertySerialiser.h"
|
#include "RotatorPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ auto RotatorPropertySerialiser::deserialiseProperty(Containers::StringView name,
|
||||||
auto prop = Containers::pointer<RotatorStructProperty>();
|
auto prop = Containers::pointer<RotatorStructProperty>();
|
||||||
|
|
||||||
if(!reader.readFloat(prop->x) || !reader.readFloat(prop->y) || !reader.readFloat(prop->z)) {
|
if(!reader.readFloat(prop->x) || !reader.readFloat(prop->y) || !reader.readFloat(prop->z)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read rotator property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +38,8 @@ auto RotatorPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop,
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto rotator = dynamic_cast<RotatorStructProperty*>(prop.get());
|
auto rotator = dynamic_cast<RotatorStructProperty*>(prop.get());
|
||||||
|
|
||||||
if(!rotator) {
|
if(!rotator) {
|
||||||
|
LOG_ERROR("The property is not a valid rotator property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
#include "../PropertySerialiser.h"
|
#include "../PropertySerialiser.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "SetPropertySerialiser.h"
|
#include "SetPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -26,21 +27,25 @@ auto SetPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
||||||
{
|
{
|
||||||
Containers::String item_type;
|
Containers::String item_type;
|
||||||
if(!reader.readUEString(item_type)) {
|
if(!reader.readUEString(item_type)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read set property {}'s item type.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in set property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedInt four_bytes;
|
UnsignedInt four_bytes;
|
||||||
if(!reader.readUnsignedInt(four_bytes) || four_bytes != 0u) {
|
if(!reader.readUnsignedInt(four_bytes) || four_bytes != 0u) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read four null bytes in set property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedInt item_count;
|
UnsignedInt item_count;
|
||||||
if(!reader.readUnsignedInt(item_count)) {
|
if(!reader.readUnsignedInt(item_count)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read set property {}'s item count.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +61,7 @@ auto SetPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
|
||||||
{
|
{
|
||||||
auto set_prop = dynamic_cast<SetProperty*>(prop.get());
|
auto set_prop = dynamic_cast<SetProperty*>(prop.get());
|
||||||
if(!set_prop) {
|
if(!set_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid set property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "StringPropertySerialiser.h"
|
#include "StringPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -36,11 +37,13 @@ auto StringPropertySerialiser::deserialise(Containers::StringView name, Containe
|
||||||
if(value_length != UnsignedLong(-1)) {
|
if(value_length != UnsignedLong(-1)) {
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in string property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readUEString(prop->value)) {
|
if(!reader.readUEString(prop->value)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read string property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,8 +56,8 @@ auto StringPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, Unsigned
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto str_prop = dynamic_cast<StringProperty*>(prop.get());
|
auto str_prop = dynamic_cast<StringProperty*>(prop.get());
|
||||||
|
|
||||||
if(!str_prop) {
|
if(!str_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid string property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
#include "../PropertySerialiser.h"
|
#include "../PropertySerialiser.h"
|
||||||
|
|
||||||
#include "../Types/GenericStructProperty.h"
|
#include "../Types/GenericStructProperty.h"
|
||||||
#include "../Types/NoneProperty.h"
|
#include "../Types/NoneProperty.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "StructSerialiser.h"
|
#include "StructSerialiser.h"
|
||||||
|
|
||||||
|
@ -36,16 +36,19 @@ auto StructSerialiser::deserialise(Containers::StringView name, Containers::Stri
|
||||||
{
|
{
|
||||||
Containers::String item_type;
|
Containers::String item_type;
|
||||||
if(!reader.readUEString(item_type)) {
|
if(!reader.readUEString(item_type)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s item type.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Containers::StaticArray<16, char> guid{ValueInit};
|
Containers::StaticArray<16, char> guid{ValueInit};
|
||||||
if(!reader.readStaticArray(guid)) {
|
if(!reader.readStaticArray(guid)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s GUID.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in struct property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,10 +70,11 @@ auto StructSerialiser::deserialise(Containers::StringView name, Containers::Stri
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!prop) {
|
if(!prop) {
|
||||||
|
LOG_ERROR("Invalid property");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static_cast<StructProperty*>(prop.get())->structGuid = guid;
|
dynamic_cast<StructProperty*>(prop.get())->structGuid = guid;
|
||||||
|
|
||||||
arrayAppend(array, std::move(prop));
|
arrayAppend(array, std::move(prop));
|
||||||
}
|
}
|
||||||
|
@ -84,20 +88,23 @@ auto StructSerialiser::deserialise(Containers::StringView name, Containers::Stri
|
||||||
{
|
{
|
||||||
Containers::String item_type;
|
Containers::String item_type;
|
||||||
if(!reader.readUEString(item_type)) {
|
if(!reader.readUEString(item_type)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s item type.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item_type == "None") {
|
if(item_type == "None") {
|
||||||
return Containers::pointer<NoneProperty>();
|
return NoneProperty::ptr{};
|
||||||
}
|
}
|
||||||
|
|
||||||
Containers::StaticArray<16, char> guid{ValueInit};
|
Containers::StaticArray<16, char> guid{ValueInit};
|
||||||
if(!reader.readStaticArray(guid)) {
|
if(!reader.readStaticArray(guid)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s GUID.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in byte property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +130,7 @@ auto StructSerialiser::serialise(Containers::ArrayView<UnrealPropertyBase::ptr>
|
||||||
|
|
||||||
auto struct_prop = dynamic_cast<StructProperty*>(props.front().get());
|
auto struct_prop = dynamic_cast<StructProperty*>(props.front().get());
|
||||||
if(!struct_prop) {
|
if(!struct_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid struct property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,13 +143,14 @@ auto StructSerialiser::serialise(Containers::ArrayView<UnrealPropertyBase::ptr>
|
||||||
UnsignedLong bytes_written_here = 0;
|
UnsignedLong bytes_written_here = 0;
|
||||||
for(auto& prop : props) {
|
for(auto& prop : props) {
|
||||||
struct_prop = dynamic_cast<StructProperty*>(prop.get());
|
struct_prop = dynamic_cast<StructProperty*>(prop.get());
|
||||||
|
|
||||||
if(!struct_prop) {
|
if(!struct_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid struct property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!serialiser.writeItem(prop, struct_prop->structType, bytes_written_here, writer)) {
|
if(!serialiser.writeItem(prop, struct_prop->structType, bytes_written_here, writer)) {
|
||||||
if(!writeStructValue(struct_prop, bytes_written_here, writer, serialiser)) {
|
if(!writeStructValue(struct_prop, bytes_written_here, writer, serialiser)) {
|
||||||
|
LOG_ERROR("Couldn't write the struct value.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,8 +167,8 @@ auto StructSerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& by
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto struct_prop = dynamic_cast<StructProperty*>(prop.get());
|
auto struct_prop = dynamic_cast<StructProperty*>(prop.get());
|
||||||
|
|
||||||
if(!struct_prop) {
|
if(!struct_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid struct property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +180,7 @@ auto StructSerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& by
|
||||||
UnsignedLong dummy_bytes_written = 0;
|
UnsignedLong dummy_bytes_written = 0;
|
||||||
UnsignedLong vl_start = writer.arrayPosition();
|
UnsignedLong vl_start = writer.arrayPosition();
|
||||||
if(!writeStructValue(struct_prop, dummy_bytes_written, writer, serialiser)) {
|
if(!writeStructValue(struct_prop, dummy_bytes_written, writer, serialiser)) {
|
||||||
|
LOG_ERROR("Couldn't write the struct value.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bytes_written += writer.arrayPosition() - vl_start;
|
bytes_written += writer.arrayPosition() - vl_start;
|
||||||
|
@ -206,13 +216,14 @@ auto StructSerialiser::writeStructValue(StructProperty* prop, UnsignedLong& byte
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto struct_prop = dynamic_cast<GenericStructProperty*>(prop);
|
auto struct_prop = dynamic_cast<GenericStructProperty*>(prop);
|
||||||
|
|
||||||
if(!struct_prop) {
|
if(!struct_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid struct property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto& item : struct_prop->properties) {
|
for(auto& item : struct_prop->properties) {
|
||||||
if(!serialiser.write(item, bytes_written, writer)) {
|
if(!serialiser.write(item, bytes_written, writer)) {
|
||||||
|
LOG_ERROR("Couldn't write the struct's data.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "Vector2DPropertySerialiser.h"
|
#include "Vector2DPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ auto Vector2DPropertySerialiser::deserialiseProperty(Containers::StringView name
|
||||||
auto prop = Containers::pointer<Vector2DStructProperty>();
|
auto prop = Containers::pointer<Vector2DStructProperty>();
|
||||||
|
|
||||||
if(!reader.readFloat(prop->x) || !reader.readFloat(prop->y)) {
|
if(!reader.readFloat(prop->x) || !reader.readFloat(prop->y)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read 2D vector property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +38,8 @@ auto Vector2DPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto vector = dynamic_cast<Vector2DStructProperty*>(prop.get());
|
auto vector = dynamic_cast<Vector2DStructProperty*>(prop.get());
|
||||||
|
|
||||||
if(!vector) {
|
if(!vector) {
|
||||||
|
LOG_ERROR("The property is not a valid 2D vector property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../BinaryReader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../BinaryWriter.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "VectorPropertySerialiser.h"
|
#include "VectorPropertySerialiser.h"
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ auto VectorPropertySerialiser::deserialiseProperty(Containers::StringView name,
|
||||||
auto prop = Containers::pointer<VectorStructProperty>();
|
auto prop = Containers::pointer<VectorStructProperty>();
|
||||||
|
|
||||||
if(!reader.readFloat(prop->x) || !reader.readFloat(prop->y) || !reader.readFloat(prop->z)) {
|
if(!reader.readFloat(prop->x) || !reader.readFloat(prop->y) || !reader.readFloat(prop->z)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read vector property {}'s value.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +38,8 @@ auto VectorPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop,
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||||
{
|
{
|
||||||
auto vector = dynamic_cast<VectorStructProperty*>(prop.get());
|
auto vector = dynamic_cast<VectorStructProperty*>(prop.get());
|
||||||
|
|
||||||
if(!vector) {
|
if(!vector) {
|
||||||
|
LOG_ERROR("The property is not a valid vector property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,12 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <Corrade/Containers/ArrayView.h>
|
|
||||||
#include <Corrade/Containers/Optional.h>
|
#include <Corrade/Containers/Optional.h>
|
||||||
#include <Corrade/Utility/Path.h>
|
#include <Corrade/Utility/Path.h>
|
||||||
|
|
||||||
#include "BinaryReader.h"
|
#include "BinaryReader.h"
|
||||||
#include "BinaryWriter.h"
|
#include "BinaryWriter.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
#include "UESaveFile.h"
|
#include "UESaveFile.h"
|
||||||
|
|
||||||
|
@ -52,6 +52,10 @@ auto UESaveFile::reloadData() -> bool {
|
||||||
return valid();
|
return valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto UESaveFile::saveType() -> Containers::StringView {
|
||||||
|
return _saveType;
|
||||||
|
}
|
||||||
|
|
||||||
void UESaveFile::appendProperty(UnrealPropertyBase::ptr prop) {
|
void UESaveFile::appendProperty(UnrealPropertyBase::ptr prop) {
|
||||||
auto none_prop = std::move(_properties.back());
|
auto none_prop = std::move(_properties.back());
|
||||||
_properties.back() = std::move(prop);
|
_properties.back() = std::move(prop);
|
||||||
|
@ -62,14 +66,22 @@ auto UESaveFile::props() -> Containers::ArrayView<UnrealPropertyBase::ptr> {
|
||||||
return _properties;
|
return _properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <Corrade/Containers/StringStl.h>
|
|
||||||
|
|
||||||
auto UESaveFile::saveToFile() -> bool {
|
auto UESaveFile::saveToFile() -> bool {
|
||||||
|
LOG_INFO_FORMAT("Writing to {}.", _filepath);
|
||||||
|
|
||||||
|
bool temp_file = _filepath.hasSuffix(".tmp");
|
||||||
|
|
||||||
|
if(!temp_file && !Utility::Path::copy(_filepath, _filepath + ".bak"_s)) {
|
||||||
|
_lastError = "Couldn't create a backup for " + _filepath;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
BinaryWriter writer{_filepath + ".tmp"_s};
|
BinaryWriter writer{_filepath + ".tmp"_s};
|
||||||
|
|
||||||
if(!writer.open()) {
|
if(!writer.open()) {
|
||||||
_lastError = "Couldn't open the file for saving."_s;
|
_lastError = "Couldn't open the file for saving."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,13 +95,15 @@ auto UESaveFile::saveToFile() -> bool {
|
||||||
!writer.writeUEString(_engineVersion.buildId))
|
!writer.writeUEString(_engineVersion.buildId))
|
||||||
{
|
{
|
||||||
_lastError = "Couldn't write the header."_s;
|
_lastError = "Couldn't write the header."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!writer.writeUnsignedInt(_customFormatVersion) ||
|
if(!writer.writeUnsignedInt(_customFormatVersion) ||
|
||||||
!writer.writeUnsignedInt(_customFormatData.size()))
|
!writer.writeUnsignedInt(_customFormatData.size()))
|
||||||
{
|
{
|
||||||
_lastError = "Couldn't write the header."_s;
|
_lastError = "Couldn't write the custom format data."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,13 +111,15 @@ auto UESaveFile::saveToFile() -> bool {
|
||||||
if(!writer.writeStaticArray(Containers::StaticArrayView<16, const char>{_customFormatData[i].id}) ||
|
if(!writer.writeStaticArray(Containers::StaticArrayView<16, const char>{_customFormatData[i].id}) ||
|
||||||
!writer.writeUnsignedInt(_customFormatData[i].value))
|
!writer.writeUnsignedInt(_customFormatData[i].value))
|
||||||
{
|
{
|
||||||
_lastError = "Couldn't write the header."_s;
|
_lastError = "Couldn't write the custom format data."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!writer.writeUEString(_saveType)) {
|
if(!writer.writeUEString(_saveType)) {
|
||||||
_lastError = "Couldn't write the header."_s;
|
_lastError = "Couldn't write the save type."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,11 +127,13 @@ auto UESaveFile::saveToFile() -> bool {
|
||||||
UnsignedLong bytes_written = 0;
|
UnsignedLong bytes_written = 0;
|
||||||
if(!_propSerialiser->write(prop, bytes_written, writer)) {
|
if(!_propSerialiser->write(prop, bytes_written, writer)) {
|
||||||
_lastError = "Couldn't write the property "_s + *prop->name + " to the array."_s;
|
_lastError = "Couldn't write the property "_s + *prop->name + " to the array."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!writer.flushToFile()) {
|
if(!writer.flushToFile()) {
|
||||||
_lastError = "Couldn't write the property "_s + *prop->name + " to the file."_s;
|
_lastError = "Couldn't write the property "_s + *prop->name + " to the file."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,17 +142,13 @@ auto UESaveFile::saveToFile() -> bool {
|
||||||
|
|
||||||
writer.closeFile();
|
writer.closeFile();
|
||||||
|
|
||||||
if(!Utility::Path::copy(_filepath, _filepath + ".bak"_s)) {
|
if(!Utility::Path::copy(_filepath + ".tmp"_s, _filepath)) {
|
||||||
|
_lastError = "Couldn't save the file properly.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Utility::Path::copy(_filepath + ".tmp"_s, _filepath)) {
|
Utility::Path::remove(_filepath + ".tmp"_s);
|
||||||
Utility::Path::copy(_filepath + ".bak"_s, _filepath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Utility::Path::remove(_filepath + ".tmp"_s);
|
|
||||||
}
|
|
||||||
|
|
||||||
_noReloadAfterSave = true;
|
_noReloadAfterSave = true;
|
||||||
|
|
||||||
|
@ -142,9 +156,13 @@ auto UESaveFile::saveToFile() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
void UESaveFile::loadData() {
|
void UESaveFile::loadData() {
|
||||||
|
LOG_INFO_FORMAT("Reading data from {}.", _filepath);
|
||||||
|
|
||||||
_valid = false;
|
_valid = false;
|
||||||
|
|
||||||
if(!Utility::Path::exists(_filepath)) {
|
if(!Utility::Path::exists(_filepath)) {
|
||||||
|
_lastError = "The file couldn't be found.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,19 +170,22 @@ void UESaveFile::loadData() {
|
||||||
|
|
||||||
if(!reader.open()) {
|
if(!reader.open()) {
|
||||||
_lastError = _filepath + " couldn't be opened."_s;
|
_lastError = _filepath + " couldn't be opened."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Containers::Array<char> magic;
|
Containers::Array<char> magic;
|
||||||
if(!reader.readArray(magic, 4)) {
|
if(!reader.readArray(magic, 4)) {
|
||||||
_lastError = "Couldn't read magic bytes in "_s + _filepath;
|
_lastError = "Couldn't read magic bytes in "_s + _filepath;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Containers::String invalid = _filepath + " isn't a valid UE4 save."_s;
|
|
||||||
|
|
||||||
if(std::strncmp(magic.data(), _magicBytes.data(), 4) != 0) {
|
if(std::strncmp(magic.data(), _magicBytes.data(), 4) != 0) {
|
||||||
_lastError = std::move(invalid);
|
_lastError = Utility::format("Magic bytes don't match. Expected {{{}, {}, {}, {}}}, got {{{}, {}, {}, {}}} instead",
|
||||||
|
_magicBytes[0], _magicBytes[1], _magicBytes[2], _magicBytes[3],
|
||||||
|
magic[0], magic[1], magic[2], magic[3]);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,23 +197,26 @@ void UESaveFile::loadData() {
|
||||||
!reader.readUnsignedInt(_engineVersion.build) ||
|
!reader.readUnsignedInt(_engineVersion.build) ||
|
||||||
!reader.readUEString(_engineVersion.buildId))
|
!reader.readUEString(_engineVersion.buildId))
|
||||||
{
|
{
|
||||||
_lastError = std::move(invalid);
|
_lastError = "Couldn't read version data.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readUnsignedInt(_customFormatVersion)) {
|
if(!reader.readUnsignedInt(_customFormatVersion)) {
|
||||||
_lastError = std::move(invalid);
|
_lastError = "Couldn't read the custom format version.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedInt custom_format_data_size = 0;
|
UnsignedInt custom_format_data_size = 0;
|
||||||
|
|
||||||
if(!reader.readUnsignedInt(custom_format_data_size)) {
|
if(!reader.readUnsignedInt(custom_format_data_size)) {
|
||||||
_lastError = std::move(invalid);
|
_lastError = "Couldn't read the custom format data size.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayReserve(_customFormatData, custom_format_data_size);
|
_customFormatData = Containers::Array<CustomFormatDataEntry>{custom_format_data_size};
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < custom_format_data_size; i++) {
|
for(UnsignedInt i = 0; i < custom_format_data_size; i++) {
|
||||||
CustomFormatDataEntry entry;
|
CustomFormatDataEntry entry;
|
||||||
|
@ -200,15 +224,17 @@ void UESaveFile::loadData() {
|
||||||
if(!reader.readStaticArray(entry.id) ||
|
if(!reader.readStaticArray(entry.id) ||
|
||||||
!reader.readInt(entry.value))
|
!reader.readInt(entry.value))
|
||||||
{
|
{
|
||||||
_lastError = std::move(invalid);
|
_lastError = "Couldn't read the custom format data";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayAppend(_customFormatData, entry);
|
_customFormatData[i] = std::move(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!reader.readUEString(_saveType)) {
|
if(!reader.readUEString(_saveType)) {
|
||||||
_lastError = std::move(invalid);
|
_lastError = "Couldn't read the save type.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,8 +243,15 @@ void UESaveFile::loadData() {
|
||||||
arrayAppend(_properties, std::move(prop));
|
arrayAppend(_properties, std::move(prop));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_properties.isEmpty()) {
|
||||||
|
_lastError = "No properties were found."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(_properties.back()->name != "None"_s && _properties.back()->propertyType != "NoneProperty"_s) {
|
if(_properties.back()->name != "None"_s && _properties.back()->propertyType != "NoneProperty"_s) {
|
||||||
_lastError = "Couldn't find a final NoneProperty."_s;
|
_lastError = "Couldn't find a final NoneProperty."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include <Corrade/Containers/Array.h>
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
#include <Corrade/Containers/GrowableArray.h>
|
#include <Corrade/Containers/GrowableArray.h>
|
||||||
#include <Corrade/Containers/Reference.h>
|
#include <Corrade/Containers/Reference.h>
|
||||||
#include <Corrade/Containers/StaticArray.h>
|
#include <Corrade/Containers/StaticArray.h>
|
||||||
|
@ -41,6 +41,8 @@ class UESaveFile {
|
||||||
|
|
||||||
auto reloadData() -> bool;
|
auto reloadData() -> bool;
|
||||||
|
|
||||||
|
auto saveType() -> Containers::StringView;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
std::enable_if_t<std::is_base_of<UnrealPropertyBase, T>::value, T*>
|
std::enable_if_t<std::is_base_of<UnrealPropertyBase, T>::value, T*>
|
||||||
at(Containers::StringView name) {
|
at(Containers::StringView name) {
|
||||||
|
|
|
@ -45,9 +45,5 @@ filename=../third-party/efsw/LICENSE
|
||||||
alias=LICENSE.efsw
|
alias=LICENSE.efsw
|
||||||
|
|
||||||
[file]
|
[file]
|
||||||
filename=../third-party/cpr/LICENSE
|
filename=../third-party/curl/COPYING
|
||||||
alias=LICENSE.cpr
|
alias=LICENSE.curl
|
||||||
|
|
||||||
[file]
|
|
||||||
filename=../third-party/json/LICENSE.MIT
|
|
||||||
alias=LICENSE.json
|
|
||||||
|
|
59
src/main.cpp
59
src/main.cpp
|
@ -14,36 +14,71 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "SaveTool/SaveTool.h"
|
#include <SDL_messagebox.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <cpuid.h>
|
||||||
|
|
||||||
#include <errhandlingapi.h>
|
#include <errhandlingapi.h>
|
||||||
#include <synchapi.h>
|
#include <synchapi.h>
|
||||||
#include <winerror.h>
|
#include <winerror.h>
|
||||||
|
|
||||||
|
#include "Logger/MagnumLogBuffer.h"
|
||||||
|
#include "SaveTool/SaveTool.h"
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
void* mutex_handle = CreateMutexW(nullptr, 0, L"MassBuilderSaveTool");
|
MagnumLogBuffer debug_intercept_buffer{EntryType::Info};
|
||||||
|
MagnumLogBuffer warning_intercept_buffer{EntryType::Warning};
|
||||||
|
MagnumLogBuffer error_intercept_buffer{EntryType::Error};
|
||||||
|
std::ostream debug_intercept_stream{&debug_intercept_buffer};
|
||||||
|
std::ostream warning_intercept_stream{&warning_intercept_buffer};
|
||||||
|
std::ostream error_intercept_stream{&error_intercept_buffer};
|
||||||
|
Debug debug_intercept{&debug_intercept_stream};
|
||||||
|
Warning warning_intercept{&warning_intercept_stream};
|
||||||
|
Error error_intercept{&error_intercept_stream};
|
||||||
|
|
||||||
|
logger().initialise();
|
||||||
|
|
||||||
|
LOG_INFO("Initialising M.A.S.S. Builder Save Tool version " SAVETOOL_VERSION ".");
|
||||||
|
|
||||||
|
auto str = setlocale(LC_ALL, ".utf-8");
|
||||||
|
if(str) {
|
||||||
|
Containers::StringView locale{str};
|
||||||
|
LOG_INFO_FORMAT("Current locale: {}", locale);
|
||||||
|
|
||||||
|
if(!locale.hasSuffix(".utf8")) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
|
"Your system doesn't support UTF-8.", nullptr);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mutex_handle = CreateMutexW(nullptr, 0, L"MassBuilderSaveTool");
|
||||||
|
|
||||||
if(!mutex_handle) {
|
if(!mutex_handle) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app",
|
LOG_ERROR_FORMAT("Error initialising the instance checker. GetLastError() returned {}.", GetLastError());
|
||||||
"There was an error initialising the mutex.",nullptr);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
|
"There was an error initialising the single-instance checker.",nullptr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetLastError() == ERROR_ALREADY_EXISTS) {
|
if(GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app",
|
LOG_ERROR("Another instance of the application was detected.");
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
"There can be only one running instance of the application.",nullptr);
|
"There can be only one running instance of the application.",nullptr);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SAVETOOL_DEBUG_BUILD
|
std::uint32_t brand[12];
|
||||||
std::ofstream output{"SaveToolLog.txt", std::ios::trunc|std::ios::out};
|
|
||||||
|
|
||||||
Utility::Debug d{&output};
|
if (!__get_cpuid_max(0x80000004, nullptr)) {
|
||||||
Utility::Warning w{&output};
|
LOG_WARNING("CPUID features not supported. Can't get the current processor's model.");
|
||||||
Utility::Error e{&output};
|
}
|
||||||
#endif
|
else {
|
||||||
|
__get_cpuid(0x80000002, brand+0x0, brand+0x1, brand+0x2, brand+0x3);
|
||||||
|
__get_cpuid(0x80000003, brand+0x4, brand+0x5, brand+0x6, brand+0x7);
|
||||||
|
__get_cpuid(0x80000004, brand+0x8, brand+0x9, brand+0xa, brand+0xb);
|
||||||
|
LOG_INFO_FORMAT("Processor: {}", Containers::arrayCast<const char>(brand).data());
|
||||||
|
}
|
||||||
|
|
||||||
SaveTool app({argc, argv});
|
SaveTool app({argc, argv});
|
||||||
Int result = app.exec();
|
Int result = app.exec();
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 857cc7c0c93f003dbfc5fed7a87de907fffb2a1b
|
Subproject commit 0bfeed061b10ea7dd37c88d9bae1824bad760f3a
|
|
@ -1 +1 @@
|
||||||
Subproject commit dc4f2eac6814b37b5257d295c2838bcde95272aa
|
Subproject commit 41b2e250b7e1e09c2ed057f079617e3d77393c47
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit eccea39e4b112a088ae665eda5854cc366f86128
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 280cbeee2789749fa9b2267ce7a07813645897de
|
|
@ -1 +1 @@
|
||||||
Subproject commit f5f42f4b9a1c34512b779b2c5544ae42fdf97afa
|
Subproject commit f3914e475cc8cec461ac05060470c6510ee81246
|
|
@ -1 +1 @@
|
||||||
Subproject commit ddddabdccfdafffd8664fb4e29230dc4f848137e
|
Subproject commit a8df192df022ed6ac447e7b7ada718c4c4824b41
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 626e7d61e44dee32887126c8f437dd077dec09cf
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit e7c81b67ab91d5dc54c2238d9f7d9abab1a0a8c3
|
Subproject commit bdc03ab23b703fcc516436d6ebcbfb6ac4484033
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3fc9028b5451aa95973f104d1ef2a1c0df589e64
|
Subproject commit a49602987499379e4a2d155472961d99ddfc75ba
|
|
@ -1 +1 @@
|
||||||
Subproject commit 323c23f4e8e7cda9a7848c03401a3ba0a1de0bd4
|
Subproject commit 883bd0cb6e00172b6fca34ff8cc4bc70bc302637
|
Loading…
Reference in New Issue