Compare commits
203 commits
1point3-ex
...
master
Author | SHA1 | Date | |
---|---|---|---|
608fc9c4c3 | |||
1aa301c316 | |||
30e6ee4018 | |||
72d3745c08 | |||
4b4f52c89c | |||
1a21afcfab | |||
4bcd9521b3 | |||
205c502c54 | |||
40f2d88433 | |||
57f6364b7f | |||
db4632182a | |||
4787415432 | |||
fdb8704f00 | |||
07832e6a89 | |||
380f77cc80 | |||
ce2a8df6a1 | |||
f2927acd50 | |||
d975dd9723 | |||
c303345437 | |||
8b8fbee6ba | |||
53c58ba979 | |||
bbf457beb6 | |||
a290542f6e | |||
3e0c0bb7a4 | |||
e1e82c0c43 | |||
165ca39e84 | |||
c1ad757f80 | |||
c0bf16144f | |||
90a67f30d9 | |||
e9a356fa21 | |||
03cbb7f8ae | |||
b8584f26bb | |||
e10a2df906 | |||
e11fa34c09 | |||
79e2ff38c5 | |||
9f570a004b | |||
ccbafe5e30 | |||
902e31e160 | |||
f2a021cd78 | |||
b9fe38782d | |||
028d991b74 | |||
fd367619e2 | |||
555cfcaadd | |||
2f70aa7672 | |||
e10e457ad8 | |||
661f6acd12 | |||
fbfcce1d86 | |||
e06a65ec71 | |||
bd360b9268 | |||
35c96af509 | |||
3ffac15c26 | |||
c48165614a | |||
1db00ba892 | |||
8ecd1922f1 | |||
12995367eb | |||
bf5a9872e1 | |||
9f0386d5b3 | |||
8a809b7752 | |||
04d2ab9dc7 | |||
9d1d0af70a | |||
29b6e57956 | |||
0b2796e94b | |||
72e71b575a | |||
fd9f9e5e36 | |||
90a2a9edd9 | |||
04e99d4953 | |||
c9ac1ad4c8 | |||
d242431d78 | |||
20f116d832 | |||
5cb04e7c20 | |||
e9fad7600b | |||
387647669f | |||
cd5213a3f9 | |||
0b46403ede | |||
efc3fe0dc7 | |||
43420d2277 | |||
ba3769404d | |||
f68dee939e | |||
3c79f39046 | |||
3bc750436f | |||
e156196b98 | |||
3a3b5bfdff | |||
ca050b0e48 | |||
22f5fc947c | |||
7ce726f933 | |||
570134ced0 | |||
ca7b71fb36 | |||
132c46da89 | |||
d9755a31fe | |||
bf7f6d24f3 | |||
df9e6bcd17 | |||
90fd22225f | |||
5af4ad0e66 | |||
819e144410 | |||
9e7547a1cd | |||
066ce6ac70 | |||
57b4af4637 | |||
e4ef5d4423 | |||
a7b0c894d0 | |||
088f357a6b | |||
938bf7b8b5 | |||
389dabfc77 | |||
07cbaefeac | |||
f9aa4bc817 | |||
e634ef037d | |||
bb85c3d6b0 | |||
b19c3e0025 | |||
1851867b7e | |||
d612b0afe6 | |||
f7a8962194 | |||
a1a155d0ac | |||
ecdf7d736f | |||
3fc9243c81 | |||
81430de345 | |||
39d71a7a09 | |||
4b3912f6ef | |||
4e98a89b9d | |||
9f8c8191ca | |||
e9ce919fd0 | |||
1af948fe03 | |||
abac0570a4 | |||
245b741590 | |||
eef4c72d3d | |||
c3453ebfc7 | |||
c4f061aa65 | |||
dc8fd24cb7 | |||
5f43e143dc | |||
03472e56dc | |||
8e0f0e5beb | |||
9c074c24bd | |||
3c2cb001ff | |||
c1701c19f4 | |||
e336b37d81 | |||
5ce73712cc | |||
7b64d78b5b | |||
59aa006611 | |||
81b35476a0 | |||
b909f0ac13 | |||
aff84ccc96 | |||
8177d61755 | |||
c0943bd084 | |||
6fa21128ab | |||
a8ab212931 | |||
9a7aaaeaca | |||
b3bf75918e | |||
9de6766750 | |||
90ff680aff | |||
07fca7b0d0 | |||
4ea694ea6e | |||
722cc511d6 | |||
924838ecb4 | |||
dfd0d56ab0 | |||
89a10ff98d | |||
71fde374a9 | |||
c7cc3ba76c | |||
0aa933e766 | |||
5ea6f1e3a7 | |||
32046d9bf8 | |||
3c4dfbda9a | |||
d1712bf8cb | |||
567546489f | |||
c054169124 | |||
b58ff5a763 | |||
28eb40f6b4 | |||
d0a3375d7a | |||
393ec4a372 | |||
83e9169dae | |||
8625f8835c | |||
c3a9c8dd31 | |||
51b25ea9c5 | |||
1421257c4f | |||
df5fa7a39e | |||
c5b4747685 | |||
7ddc8e0748 | |||
7392d961c7 | |||
fa81d2428e | |||
79c97733db | |||
060daebe17 | |||
8cf5351f0b | |||
e795e276da | |||
bf820f65ec | |||
fb6246cff7 | |||
7257b9865c | |||
45bc2b97d9 | |||
9de62db449 | |||
44656b32d5 | |||
9ec88fa521 | |||
ee540b601e | |||
fe10bbb3f3 | |||
bb066d3134 | |||
e21e7a1aba | |||
714d8cc6bb | |||
a33cbdfad6 | |||
b7cd78ca21 | |||
453c5391a4 | |||
05611d59b1 | |||
a5a8db289a | |||
6130734764 | |||
16b8807eb7 | |||
f1ea2bda25 | |||
42cec59c71 | |||
5c6a83c03b | |||
e6c597ffbc |
213 changed files with 12741 additions and 9114 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,4 @@
|
||||||
build*/
|
*build*/
|
||||||
.idea/
|
.idea/
|
||||||
*.kdev4
|
*.kdev4
|
||||||
*~
|
*~
|
||||||
|
|
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -17,11 +17,11 @@
|
||||||
[submodule "SDL2"]
|
[submodule "SDL2"]
|
||||||
path = third-party/SDL
|
path = third-party/SDL
|
||||||
url = https://github.com/libsdl-org/SDL
|
url = https://github.com/libsdl-org/SDL
|
||||||
branch = main
|
branch = SDL2
|
||||||
[submodule "libzip"]
|
[submodule "libzip"]
|
||||||
path = third-party/libzip
|
path = third-party/libzip
|
||||||
url = https://github.com/nih-at/libzip
|
url = https://github.com/nih-at/libzip
|
||||||
branch = master
|
branch = main
|
||||||
[submodule "efsw"]
|
[submodule "efsw"]
|
||||||
path = third-party/efsw
|
path = third-party/efsw
|
||||||
url = https://github.com/SpartanJ/efsw
|
url = https://github.com/SpartanJ/efsw
|
||||||
|
|
193
CMakeLists.txt
193
CMakeLists.txt
|
@ -1,5 +1,5 @@
|
||||||
# MassBuilderSaveTool
|
# MassBuilderSaveTool
|
||||||
# Copyright (C) 2021-2022 Guillaume Jacquemin
|
# Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,98 +14,127 @@
|
||||||
# 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/>.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5)
|
cmake_minimum_required(VERSION 3.24)
|
||||||
project(MassBuilderSaveTool)
|
project(MassBuilderSaveTool)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/modules/" ${CMAKE_MODULE_PATH})
|
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/modules/" ${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
|
set(ZLIB_USE_STATIC_LIBS ON CACHE BOOL "" FORCE) # Required on setups where zlib is available as both dynamic and static libs. Which is pretty much everywhere, actually.
|
||||||
|
|
||||||
set(CORRADE_BUILD_DEPRECATED OFF CACHE BOOL "" FORCE)
|
option(SAVETOOL_USE_SYSTEM_LIBS "Use system-wide versions of the dependencies instead of the versions provided by submodules." OFF)
|
||||||
set(CORRADE_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
|
||||||
set(CORRADE_BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
|
|
||||||
set(CORRADE_BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
|
|
||||||
set(CORRADE_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
|
||||||
set(CORRADE_WITH_INTERCONNECT ON CACHE BOOL "" FORCE)
|
|
||||||
set(CORRADE_WITH_PLUGINMANAGER OFF 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)
|
|
||||||
|
|
||||||
set(DIRECTX OFF CACHE BOOL "" FORCE) # We use OpenGL.
|
include(CMakeDependentOption)
|
||||||
set(SDL_ATOMIC OFF CACHE BOOL "" FORCE)
|
cmake_dependent_option(SAVETOOL_USE_SYSTEM_CORRADE_MAGNUM "Use system-wide versions of Corrade and Magnum." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||||
set(SDL_CPUINFO OFF CACHE BOOL "" FORCE)
|
cmake_dependent_option(SAVETOOL_USE_SYSTEM_SDL2 "Use a system-wide version of SDL2." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||||
set(SDL_EVENTS ON CACHE BOOL "" FORCE)
|
cmake_dependent_option(SAVETOOL_USE_SYSTEM_LIBZIP "Use a system-wide version of libzip." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||||
set(SDL_FILE OFF CACHE BOOL "" FORCE)
|
cmake_dependent_option(SAVETOOL_USE_SYSTEM_EFSW "Use a system-wide version of EFSW." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||||
set(SDL_FILESYSTEM OFF CACHE BOOL "" FORCE)
|
cmake_dependent_option(SAVETOOL_USE_SYSTEM_LIBCURL "Use a system-wide version of libcurl." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||||
set(SDL_HAPTIC OFF CACHE BOOL "" FORCE)
|
|
||||||
set(SDL_LOCALE OFF CACHE BOOL "" FORCE)
|
|
||||||
set(SDL_POWER OFF CACHE BOOL "" FORCE)
|
|
||||||
set(SDL_RENDER OFF CACHE BOOL "" FORCE)
|
|
||||||
set(SDL_SENSOR OFF CACHE BOOL "" FORCE)
|
|
||||||
set(SDL_THREADS ON CACHE BOOL "" FORCE)
|
|
||||||
set(SDL_TIMERS ON CACHE BOOL "" FORCE)
|
|
||||||
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
|
|
||||||
add_subdirectory(third-party/SDL EXCLUDE_FROM_ALL)
|
|
||||||
|
|
||||||
set(MAGNUM_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
if(NOT SAVETOOL_USE_SYSTEM_LIBS OR NOT (SAVETOOL_USE_SYSTEM_CORRADE_MAGNUM AND SAVETOOL_USE_SYSTEM_SDL2 AND SAVETOOL_USE_SYSTEM_LIBZIP AND SAVETOOL_USE_SYSTEM_EFSW AND SAVETOOL_USE_SYSTEM_LIBCURL))
|
||||||
set(MAGNUM_BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
|
# Generic variables shared by multiple libs that don't provide their own.
|
||||||
set(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_BUILD_DEPRECATED OFF CACHE BOOL "" FORCE)
|
set(BUILD_STATIC_LIBS ON CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(MAGNUM_TARGET_GL ON CACHE BOOL "" FORCE)
|
if(NOT SAVETOOL_USE_SYSTEM_SDL2)
|
||||||
set(MAGNUM_TARGET_GLES OFF CACHE BOOL "" FORCE)
|
set(DIRECTX OFF CACHE BOOL "" FORCE) # We use OpenGL.
|
||||||
set(MAGNUM_TARGET_VK OFF CACHE BOOL "" FORCE)
|
set(SDL_ATOMIC OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_AUDIO OFF CACHE BOOL "" FORCE)
|
set(SDL_CPUINFO OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_DEBUGTOOLS OFF CACHE BOOL "" FORCE)
|
set(SDL_EVENTS ON CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_GL ON CACHE BOOL "" FORCE)
|
set(SDL_FILE OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_MESHTOOLS OFF CACHE BOOL "" FORCE)
|
set(SDL_FILESYSTEM OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_PRIMITIVES OFF CACHE BOOL "" FORCE)
|
set(SDL_HAPTIC OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_SCENEGRAPH OFF CACHE BOOL "" FORCE)
|
set(SDL_LOCALE OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_SCENETOOLS OFF CACHE BOOL "" FORCE)
|
set(SDL_POWER OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_SHADERS ON CACHE BOOL "" FORCE)
|
set(SDL_RENDER OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_SHADERTOOLS OFF CACHE BOOL "" FORCE)
|
set(SDL_SENSOR OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_TEXT OFF CACHE BOOL "" FORCE)
|
set(SDL_THREADS ON CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_TEXTURETOOLS OFF CACHE BOOL "" FORCE)
|
set(SDL_TIMERS ON CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_TRADE OFF CACHE BOOL "" FORCE)
|
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
|
||||||
set(MAGNUM_WITH_VK OFF CACHE BOOL "" FORCE)
|
add_subdirectory(third-party/SDL EXCLUDE_FROM_ALL)
|
||||||
set(MAGNUM_WITH_SDL2APPLICATION ON CACHE BOOL "" FORCE)
|
endif(NOT SAVETOOL_USE_SYSTEM_SDL2)
|
||||||
add_subdirectory(third-party/magnum EXCLUDE_FROM_ALL)
|
|
||||||
|
|
||||||
set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third-party/imgui)
|
if(NOT SAVETOOL_USE_SYSTEM_CORRADE_MAGNUM)
|
||||||
set(MAGNUM_WITH_IMGUI ON CACHE BOOL "" FORCE)
|
set(CORRADE_BUILD_DEPRECATED OFF CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/magnum-integration EXCLUDE_FROM_ALL)
|
set(CORRADE_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_WITH_INTERCONNECT OFF CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_WITH_PLUGINMANAGER OFF CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_WITH_TESTSUITE OFF CACHE BOOL "" FORCE)
|
||||||
|
set(CORRADE_WITH_MAIN ON CACHE BOOL "" FORCE)
|
||||||
|
add_subdirectory(third-party/corrade EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
||||||
set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
|
||||||
set(ENABLE_MBEDTLS OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
|
||||||
set(ENABLE_OPENSSL OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_DEPRECATED OFF CACHE BOOL "" FORCE)
|
||||||
set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
set(ENABLE_BZIP2 OFF CACHE BOOL "" FORCE)
|
|
||||||
set(ENABLE_LZMA OFF CACHE BOOL "" FORCE)
|
|
||||||
set(ENABLE_ZSTD OFF CACHE BOOL "" FORCE)
|
|
||||||
set(BUILD_TOOLS OFF CACHE BOOL "" FORCE)
|
|
||||||
set(BUILD_REGRESS OFF CACHE BOOL "" FORCE)
|
|
||||||
set(BUILD_EXAMPLES 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)
|
|
||||||
|
|
||||||
set(VERBOSE OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_TARGET_GL ON CACHE BOOL "" FORCE)
|
||||||
set(BUILD_TEST_APP OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_TARGET_GLES OFF CACHE BOOL "" FORCE)
|
||||||
set(EFSW_INSTALL OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_TARGET_VK OFF CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/efsw EXCLUDE_FROM_ALL)
|
set(MAGNUM_WITH_AUDIO OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_DEBUGTOOLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_GL ON CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_MATERIALTOOLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_MESHTOOLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(MAGNUM_WITH_PRIMITIVES OFF 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)
|
||||||
|
|
||||||
set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE)
|
set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third-party/imgui)
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
set(MAGNUM_WITH_IMGUI ON CACHE BOOL "" FORCE)
|
||||||
set(ENABLE_UNICODE ON CACHE BOOL "" FORCE)
|
add_subdirectory(third-party/magnum-integration EXCLUDE_FROM_ALL)
|
||||||
set(ENABLE_DEBUG ON CACHE BOOL "" FORCE)
|
endif(NOT SAVETOOL_USE_SYSTEM_CORRADE_MAGNUM)
|
||||||
set(ENABLE_THREADED_RESOLVER OFF CACHE BOOL "" FORCE)
|
|
||||||
set(HTTP_ONLY ON CACHE BOOL "" FORCE)
|
if(NOT SAVETOOL_USE_SYSTEM_LIBZIP)
|
||||||
set(CURL_USE_SCHANNEL ON CACHE BOOL "" FORCE)
|
set(ENABLE_COMMONCRYPTO OFF 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.
|
set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE)
|
||||||
add_subdirectory(third-party/curl EXCLUDE_FROM_ALL)
|
set(ENABLE_MBEDTLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_OPENSSL OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_BZIP2 OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_LZMA OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_ZSTD OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_TOOLS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_REGRESS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_DOC OFF CACHE BOOL "" FORCE)
|
||||||
|
add_subdirectory(third-party/libzip EXCLUDE_FROM_ALL)
|
||||||
|
endif(NOT SAVETOOL_USE_SYSTEM_LIBZIP)
|
||||||
|
|
||||||
|
if(NOT SAVETOOL_USE_SYSTEM_EFSW)
|
||||||
|
set(VERBOSE OFF CACHE BOOL "" FORCE)
|
||||||
|
set(BUILD_TEST_APP OFF CACHE BOOL "" FORCE)
|
||||||
|
set(EFSW_INSTALL OFF CACHE BOOL "" FORCE)
|
||||||
|
add_subdirectory(third-party/efsw EXCLUDE_FROM_ALL)
|
||||||
|
endif(NOT SAVETOOL_USE_SYSTEM_EFSW)
|
||||||
|
|
||||||
|
if(NOT SAVETOOL_USE_SYSTEM_LIBCURL)
|
||||||
|
set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_UNICODE ON CACHE BOOL "" FORCE)
|
||||||
|
set(ENABLE_INET_PTON OFF CACHE BOOL "" FORCE)
|
||||||
|
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)
|
||||||
|
endif(NOT SAVETOOL_USE_SYSTEM_LIBCURL)
|
||||||
|
|
||||||
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 mingw-w64-ucrt-x86_64-zlib`.
|
||||||
|
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`
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
# components, which are:
|
# components, which are:
|
||||||
#
|
#
|
||||||
# Containers - Containers library
|
# Containers - Containers library
|
||||||
|
# Interconnect - Interconnect library
|
||||||
|
# Main - Main library
|
||||||
# PluginManager - PluginManager library
|
# PluginManager - PluginManager library
|
||||||
# TestSuite - TestSuite library
|
# TestSuite - TestSuite library
|
||||||
# Utility - Utility library
|
# Utility - Utility library
|
||||||
|
@ -68,7 +70,7 @@
|
||||||
# mode for MSVC 2017
|
# mode for MSVC 2017
|
||||||
# CORRADE_MSVC2015_COMPATIBILITY - Defined if compiled with compatibility
|
# CORRADE_MSVC2015_COMPATIBILITY - Defined if compiled with compatibility
|
||||||
# mode for MSVC 2015
|
# mode for MSVC 2015
|
||||||
# CORRADE_BUILD_DEPRECATED - Defined if compiled with deprecated APIs
|
# CORRADE_BUILD_DEPRECATED - Defined if compiled with deprecated features
|
||||||
# included
|
# included
|
||||||
# CORRADE_BUILD_STATIC - Defined if compiled as static libraries.
|
# CORRADE_BUILD_STATIC - Defined if compiled as static libraries.
|
||||||
# Default are shared libraries.
|
# Default are shared libraries.
|
||||||
|
@ -78,6 +80,9 @@
|
||||||
# CORRADE_BUILD_MULTITHREADED - Defined if compiled in a way that makes it
|
# CORRADE_BUILD_MULTITHREADED - Defined if compiled in a way that makes it
|
||||||
# possible to safely use certain Corrade features simultaneously in multiple
|
# possible to safely use certain Corrade features simultaneously in multiple
|
||||||
# threads
|
# threads
|
||||||
|
# CORRADE_BUILD_CPU_RUNTIME_DISPATCH - Defined if built with code paths
|
||||||
|
# optimized for multiple architectres with the best matching variant selected
|
||||||
|
# at runtime based on detected CPU features
|
||||||
# CORRADE_TARGET_UNIX - Defined if compiled for some Unix flavor
|
# CORRADE_TARGET_UNIX - Defined if compiled for some Unix flavor
|
||||||
# (Linux, BSD, macOS)
|
# (Linux, BSD, macOS)
|
||||||
# CORRADE_TARGET_APPLE - Defined if compiled for Apple platforms
|
# CORRADE_TARGET_APPLE - Defined if compiled for Apple platforms
|
||||||
|
@ -98,6 +103,8 @@
|
||||||
# CORRADE_TARGET_MSVC - Defined if compiling with MSVC or Clang with
|
# CORRADE_TARGET_MSVC - Defined if compiling with MSVC or Clang with
|
||||||
# a MSVC frontend
|
# a MSVC frontend
|
||||||
# CORRADE_TARGET_MINGW - Defined if compiling under MinGW
|
# CORRADE_TARGET_MINGW - Defined if compiling under MinGW
|
||||||
|
# CORRADE_CPU_USE_IFUNC - Defined if GNU IFUNC is allowed to be used
|
||||||
|
# for runtime dispatch in the Cpu library
|
||||||
# CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT - Defined if PluginManager
|
# CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT - Defined if PluginManager
|
||||||
# doesn't support dynamic plugin loading due to platform limitations
|
# doesn't support dynamic plugin loading due to platform limitations
|
||||||
# CORRADE_TESTSUITE_TARGET_XCTEST - Defined if TestSuite is targeting Xcode
|
# CORRADE_TESTSUITE_TARGET_XCTEST - Defined if TestSuite is targeting Xcode
|
||||||
|
@ -115,6 +122,7 @@
|
||||||
# automatically)
|
# automatically)
|
||||||
# CORRADE_TESTSUITE_XCTEST_RUNNER - Path to XCTestRunner.mm.in file
|
# CORRADE_TESTSUITE_XCTEST_RUNNER - Path to XCTestRunner.mm.in file
|
||||||
# CORRADE_TESTSUITE_ADB_RUNNER - Path to AdbRunner.sh file
|
# CORRADE_TESTSUITE_ADB_RUNNER - Path to AdbRunner.sh file
|
||||||
|
# CORRADE_UTILITY_JS - Path to CorradeUtility.js file
|
||||||
# CORRADE_PEDANTIC_COMPILER_OPTIONS - List of pedantic compiler options used
|
# CORRADE_PEDANTIC_COMPILER_OPTIONS - List of pedantic compiler options used
|
||||||
# for targets with :prop_tgt:`CORRADE_USE_PEDANTIC_FLAGS` enabled
|
# for targets with :prop_tgt:`CORRADE_USE_PEDANTIC_FLAGS` enabled
|
||||||
# CORRADE_PEDANTIC_COMPILER_DEFINITIONS - List of pedantic compiler
|
# CORRADE_PEDANTIC_COMPILER_DEFINITIONS - List of pedantic compiler
|
||||||
|
@ -208,7 +216,7 @@
|
||||||
# <metadata file>
|
# <metadata file>
|
||||||
# <sources>...)
|
# <sources>...)
|
||||||
#
|
#
|
||||||
# Unline the above version this puts everything into ``<debug install dir>`` on
|
# Unlike the above version this puts everything into ``<debug install dir>`` on
|
||||||
# both DLL and non-DLL platforms. If ``<debug install dir>`` is set to
|
# both DLL and non-DLL platforms. If ``<debug install dir>`` is set to
|
||||||
# :variable:`CMAKE_CURRENT_BINARY_DIR` (e.g. for testing purposes), the files
|
# :variable:`CMAKE_CURRENT_BINARY_DIR` (e.g. for testing purposes), the files
|
||||||
# are copied directly, without the need to perform install step. Note that the
|
# are copied directly, without the need to perform install step. Note that the
|
||||||
|
@ -264,7 +272,7 @@
|
||||||
# This file is part of Corrade.
|
# This file is part of Corrade.
|
||||||
#
|
#
|
||||||
# Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
|
# Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
|
||||||
# 2017, 2018, 2019, 2020, 2021, 2022
|
# 2017, 2018, 2019, 2020, 2021, 2022, 2023
|
||||||
# Vladimír Vondruš <mosra@centrum.cz>
|
# Vladimír Vondruš <mosra@centrum.cz>
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
@ -317,6 +325,7 @@ set(_corradeFlags
|
||||||
BUILD_STATIC
|
BUILD_STATIC
|
||||||
BUILD_STATIC_UNIQUE_GLOBALS
|
BUILD_STATIC_UNIQUE_GLOBALS
|
||||||
BUILD_MULTITHREADED
|
BUILD_MULTITHREADED
|
||||||
|
BUILD_CPU_RUNTIME_DISPATCH
|
||||||
TARGET_UNIX
|
TARGET_UNIX
|
||||||
TARGET_APPLE
|
TARGET_APPLE
|
||||||
TARGET_IOS
|
TARGET_IOS
|
||||||
|
@ -325,10 +334,12 @@ set(_corradeFlags
|
||||||
TARGET_WINDOWS_RT
|
TARGET_WINDOWS_RT
|
||||||
TARGET_EMSCRIPTEN
|
TARGET_EMSCRIPTEN
|
||||||
TARGET_ANDROID
|
TARGET_ANDROID
|
||||||
# TARGET_X86 etc and TARGET_LIBCXX are not exposed to CMake as the meaning
|
# TARGET_X86 etc, TARGET_32BIT, TARGET_BIG_ENDIAN and TARGET_LIBCXX etc.
|
||||||
# is unclear on platforms with multi-arch binaries or when mixing different
|
# are not exposed to CMake as the meaning is unclear on platforms with
|
||||||
# STL implementations. TARGET_GCC etc are figured out via UseCorrade.cmake,
|
# multi-arch binaries or when mixing different STL implementations.
|
||||||
# as the compiler can be different when compiling the lib & when using it.
|
# TARGET_GCC etc are figured out via UseCorrade.cmake, as the compiler can
|
||||||
|
# be different when compiling the lib & when using it.
|
||||||
|
CPU_USE_IFUNC
|
||||||
PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
|
PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
|
||||||
TESTSUITE_TARGET_XCTEST
|
TESTSUITE_TARGET_XCTEST
|
||||||
UTILITY_USE_ANSI_COLORS)
|
UTILITY_USE_ANSI_COLORS)
|
||||||
|
@ -406,6 +417,8 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
|
||||||
if(TARGET Corrade::${_component})
|
if(TARGET Corrade::${_component})
|
||||||
set(Corrade_${_component}_FOUND TRUE)
|
set(Corrade_${_component}_FOUND TRUE)
|
||||||
else()
|
else()
|
||||||
|
unset(Corrade_${_component}_FOUND)
|
||||||
|
|
||||||
# Library (and not header-only) components
|
# Library (and not header-only) components
|
||||||
if(_component IN_LIST _CORRADE_LIBRARY_COMPONENTS AND NOT _component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS)
|
if(_component IN_LIST _CORRADE_LIBRARY_COMPONENTS AND NOT _component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS)
|
||||||
add_library(Corrade::${_component} UNKNOWN IMPORTED)
|
add_library(Corrade::${_component} UNKNOWN IMPORTED)
|
||||||
|
@ -461,8 +474,9 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
|
||||||
# Interconnect library
|
# Interconnect library
|
||||||
if(_component STREQUAL Interconnect)
|
if(_component STREQUAL Interconnect)
|
||||||
# Disable /OPT:ICF on MSVC, which merges functions with identical
|
# Disable /OPT:ICF on MSVC, which merges functions with identical
|
||||||
# contents and thus breaks signal comparison
|
# contents and thus breaks signal comparison. Same case is for
|
||||||
if(CORRADE_TARGET_WINDOWS AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
# clang-cl which uses the MSVC linker by default.
|
||||||
|
if(CORRADE_TARGET_WINDOWS AND (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" OR CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC"))
|
||||||
if(CMAKE_VERSION VERSION_LESS 3.13)
|
if(CMAKE_VERSION VERSION_LESS 3.13)
|
||||||
set_property(TARGET Corrade::${_component} PROPERTY
|
set_property(TARGET Corrade::${_component} PROPERTY
|
||||||
INTERFACE_LINK_LIBRARIES "-OPT:NOICF,REF")
|
INTERFACE_LINK_LIBRARIES "-OPT:NOICF,REF")
|
||||||
|
@ -496,25 +510,33 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
|
||||||
elseif(_component STREQUAL PluginManager)
|
elseif(_component STREQUAL PluginManager)
|
||||||
# -ldl is handled by Utility now
|
# -ldl is handled by Utility now
|
||||||
|
|
||||||
# TestSuite library has some additional files
|
# TestSuite library has some additional files. If those are not found,
|
||||||
|
# set the component _FOUND variable to false so it works properly both
|
||||||
|
# when the component is required and when it's optional.
|
||||||
elseif(_component STREQUAL TestSuite)
|
elseif(_component STREQUAL TestSuite)
|
||||||
# XCTest runner file
|
# XCTest runner file
|
||||||
if(CORRADE_TESTSUITE_TARGET_XCTEST)
|
if(CORRADE_TESTSUITE_TARGET_XCTEST)
|
||||||
find_file(CORRADE_TESTSUITE_XCTEST_RUNNER XCTestRunner.mm.in
|
find_file(CORRADE_TESTSUITE_XCTEST_RUNNER XCTestRunner.mm.in
|
||||||
PATH_SUFFIXES share/corrade/TestSuite)
|
PATH_SUFFIXES share/corrade/TestSuite)
|
||||||
set(CORRADE_TESTSUITE_XCTEST_RUNNER_NEEDED CORRADE_TESTSUITE_XCTEST_RUNNER)
|
if(NOT CORRADE_TESTSUITE_XCTEST_RUNNER)
|
||||||
|
set(Corrade_${_component}_FOUND FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
# ADB runner file
|
# ADB runner file
|
||||||
elseif(CORRADE_TARGET_ANDROID)
|
elseif(CORRADE_TARGET_ANDROID)
|
||||||
find_file(CORRADE_TESTSUITE_ADB_RUNNER AdbRunner.sh
|
find_file(CORRADE_TESTSUITE_ADB_RUNNER AdbRunner.sh
|
||||||
PATH_SUFFIXES share/corrade/TestSuite)
|
PATH_SUFFIXES share/corrade/TestSuite)
|
||||||
set(CORRADE_TESTSUITE_ADB_RUNNER_NEEDED CORRADE_TESTSUITE_ADB_RUNNER)
|
if(NOT CORRADE_TESTSUITE_ADB_RUNNER)
|
||||||
|
set(Corrade_${_component}_FOUND FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Emscripten runner file
|
# Emscripten runner file
|
||||||
elseif(CORRADE_TARGET_EMSCRIPTEN)
|
elseif(CORRADE_TARGET_EMSCRIPTEN)
|
||||||
find_file(CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER EmscriptenRunner.html.in
|
find_file(CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER EmscriptenRunner.html.in
|
||||||
PATH_SUFFIXES share/corrade/TestSuite)
|
PATH_SUFFIXES share/corrade/TestSuite)
|
||||||
set(CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER_NEEDED CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER)
|
if(NOT CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER)
|
||||||
|
set(Corrade_${_component}_FOUND FALSE)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Utility library (contains all setup that is used by others)
|
# Utility library (contains all setup that is used by others)
|
||||||
|
@ -539,6 +561,15 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
|
||||||
set_property(TARGET Corrade::${_component} APPEND PROPERTY
|
set_property(TARGET Corrade::${_component} APPEND PROPERTY
|
||||||
INTERFACE_LINK_LIBRARIES "log")
|
INTERFACE_LINK_LIBRARIES "log")
|
||||||
endif()
|
endif()
|
||||||
|
# Emscripten has various stuff implemented in JS
|
||||||
|
if(CORRADE_TARGET_EMSCRIPTEN)
|
||||||
|
find_file(CORRADE_UTILITY_JS CorradeUtility.js
|
||||||
|
PATH_SUFFIXES lib)
|
||||||
|
set_property(TARGET Corrade::${_component} APPEND PROPERTY
|
||||||
|
# TODO switch to INTERFACE_LINK_OPTIONS and SHELL: once we
|
||||||
|
# require CMake 3.13 unconditionally
|
||||||
|
INTERFACE_LINK_LIBRARIES "--js-library ${CORRADE_UTILITY_JS}")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Find library includes
|
# Find library includes
|
||||||
|
@ -559,13 +590,16 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Decide if the component was found
|
# Decide if the component was found, unless the _FOUND is already set
|
||||||
|
# by something above.
|
||||||
|
if(NOT DEFINED Corrade_${_component}_FOUND)
|
||||||
if((_component IN_LIST _CORRADE_LIBRARY_COMPONENTS AND _CORRADE_${_COMPONENT}_INCLUDE_DIR AND (_component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS OR CORRADE_${_COMPONENT}_LIBRARY_RELEASE OR CORRADE_${_COMPONENT}_LIBRARY_DEBUG)) OR (_component IN_LIST _CORRADE_EXECUTABLE_COMPONENTS AND CORRADE_${_COMPONENT}_EXECUTABLE))
|
if((_component IN_LIST _CORRADE_LIBRARY_COMPONENTS AND _CORRADE_${_COMPONENT}_INCLUDE_DIR AND (_component IN_LIST _CORRADE_HEADER_ONLY_COMPONENTS OR CORRADE_${_COMPONENT}_LIBRARY_RELEASE OR CORRADE_${_COMPONENT}_LIBRARY_DEBUG)) OR (_component IN_LIST _CORRADE_EXECUTABLE_COMPONENTS AND CORRADE_${_COMPONENT}_EXECUTABLE))
|
||||||
set(Corrade_${_component}_FOUND TRUE)
|
set(Corrade_${_component}_FOUND TRUE)
|
||||||
else()
|
else()
|
||||||
set(Corrade_${_component}_FOUND FALSE)
|
set(Corrade_${_component}_FOUND FALSE)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# For CMake 3.16+ with REASON_FAILURE_MESSAGE, provide additional potentially
|
# For CMake 3.16+ with REASON_FAILURE_MESSAGE, provide additional potentially
|
||||||
|
@ -590,7 +624,7 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.16)
|
||||||
# misleading messages.
|
# misleading messages.
|
||||||
elseif(NOT _component IN_LIST _CORRADE_IMPLICITLY_ENABLED_COMPONENTS)
|
elseif(NOT _component IN_LIST _CORRADE_IMPLICITLY_ENABLED_COMPONENTS)
|
||||||
string(TOUPPER ${_component} _COMPONENT)
|
string(TOUPPER ${_component} _COMPONENT)
|
||||||
list(APPEND _CORRADE_REASON_FAILURE_MESSAGE "${_component} is not built by default. Make sure you enabled WITH_${_COMPONENT} when building Corrade.")
|
list(APPEND _CORRADE_REASON_FAILURE_MESSAGE "${_component} is not built by default. Make sure you enabled CORRADE_WITH_${_COMPONENT} when building Corrade.")
|
||||||
# Otherwise we have no idea. Better be silent than to print something
|
# Otherwise we have no idea. Better be silent than to print something
|
||||||
# misleading.
|
# misleading.
|
||||||
else()
|
else()
|
||||||
|
@ -606,9 +640,6 @@ find_package_handle_standard_args(Corrade REQUIRED_VARS
|
||||||
CORRADE_INCLUDE_DIR
|
CORRADE_INCLUDE_DIR
|
||||||
_CORRADE_MODULE_DIR
|
_CORRADE_MODULE_DIR
|
||||||
_CORRADE_CONFIGURE_FILE
|
_CORRADE_CONFIGURE_FILE
|
||||||
${CORRADE_TESTSUITE_XCTEST_RUNNER_NEEDED}
|
|
||||||
${CORRADE_TESTSUITE_ADB_RUNNER_NEEDED}
|
|
||||||
${CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER_NEEDED}
|
|
||||||
HANDLE_COMPONENTS
|
HANDLE_COMPONENTS
|
||||||
${_CORRADE_REASON_FAILURE_MESSAGE})
|
${_CORRADE_REASON_FAILURE_MESSAGE})
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
# This file is part of Magnum.
|
# This file is part of Magnum.
|
||||||
#
|
#
|
||||||
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
||||||
# 2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
|
# 2020, 2021, 2022, 2023 Vladimír Vondruš <mosra@centrum.cz>
|
||||||
# Copyright © 2018 Jonathan Hale <squareys@googlemail.com>
|
# Copyright © 2018 Jonathan Hale <squareys@googlemail.com>
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
# Audio - Audio library
|
# Audio - Audio library
|
||||||
# DebugTools - DebugTools library
|
# DebugTools - DebugTools library
|
||||||
# GL - GL library
|
# GL - GL library
|
||||||
|
# MaterialTools - MaterialTools library
|
||||||
# MeshTools - MeshTools library
|
# MeshTools - MeshTools library
|
||||||
# Primitives - Primitives library
|
# Primitives - Primitives library
|
||||||
# SceneGraph - SceneGraph library
|
# SceneGraph - SceneGraph library
|
||||||
|
@ -78,7 +79,6 @@
|
||||||
# WindowlessGlxApplication - Windowless GLX application
|
# WindowlessGlxApplication - Windowless GLX application
|
||||||
# WindowlessIosApplication - Windowless iOS application
|
# WindowlessIosApplication - Windowless iOS application
|
||||||
# WindowlessWglApplication - Windowless WGL application
|
# WindowlessWglApplication - Windowless WGL application
|
||||||
# WindowlessWindowsEglApplication - Windowless Windows/EGL application
|
|
||||||
# CglContext - CGL context
|
# CglContext - CGL context
|
||||||
# EglContext - EGL context
|
# EglContext - EGL context
|
||||||
# GlxContext - GLX context
|
# GlxContext - GLX context
|
||||||
|
@ -128,19 +128,18 @@
|
||||||
#
|
#
|
||||||
# Features of found Magnum library are exposed in these variables:
|
# Features of found Magnum library are exposed in these variables:
|
||||||
#
|
#
|
||||||
# MAGNUM_BUILD_DEPRECATED - Defined if compiled with deprecated APIs
|
# MAGNUM_BUILD_DEPRECATED - Defined if compiled with deprecated features
|
||||||
# included
|
# included
|
||||||
# MAGNUM_BUILD_STATIC - Defined if compiled as static libraries
|
# MAGNUM_BUILD_STATIC - Defined if compiled as static libraries
|
||||||
# MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS - Defined if static libraries keep the
|
# MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS - Defined if static libraries keep the
|
||||||
# globals unique even across different shared libraries
|
# globals unique even across different shared libraries
|
||||||
# MAGNUM_TARGET_GL - Defined if compiled with OpenGL interop
|
# MAGNUM_TARGET_GL - Defined if compiled with OpenGL interop
|
||||||
# MAGNUM_TARGET_GLES - Defined if compiled for OpenGL ES
|
# MAGNUM_TARGET_GLES - Defined if compiled for OpenGL ES
|
||||||
# MAGNUM_TARGET_GLES2 - Defined if compiled for OpenGL ES 2.0
|
|
||||||
# MAGNUM_TARGET_GLES3 - Defined if compiled for OpenGL ES 3.0
|
|
||||||
# MAGNUM_TARGET_DESKTOP_GLES - Defined if compiled with OpenGL ES
|
|
||||||
# emulation on desktop OpenGL
|
|
||||||
# MAGNUM_TARGET_WEBGL - Defined if compiled for WebGL
|
# MAGNUM_TARGET_WEBGL - Defined if compiled for WebGL
|
||||||
# MAGNUM_TARGET_HEADLESS - Defined if compiled for headless machines
|
# MAGNUM_TARGET_GLES2 - Defined if compiled for OpenGL ES 2.0 / WebGL
|
||||||
|
# 1 instead of OpenGL ES 3.0+ / WebGL 2
|
||||||
|
# MAGNUM_TARGET_EGL - Defined if compiled for EGL instead of a
|
||||||
|
# platform-specific OpenGL support library like CGL, EAGL, GLX or WGL
|
||||||
# MAGNUM_TARGET_VK - Defined if compiled with Vulkan interop
|
# MAGNUM_TARGET_VK - Defined if compiled with Vulkan interop
|
||||||
#
|
#
|
||||||
# The following variables are provided for backwards compatibility purposes
|
# The following variables are provided for backwards compatibility purposes
|
||||||
|
@ -149,6 +148,12 @@
|
||||||
#
|
#
|
||||||
# MAGNUM_BUILD_MULTITHREADED - Alias to CORRADE_BUILD_MULTITHREADED. Use
|
# MAGNUM_BUILD_MULTITHREADED - Alias to CORRADE_BUILD_MULTITHREADED. Use
|
||||||
# CORRADE_BUILD_MULTITHREADED instead.
|
# CORRADE_BUILD_MULTITHREADED instead.
|
||||||
|
# MAGNUM_TARGET_HEADLESS - Alias to MAGNUM_TARGET_EGL, unless on iOS,
|
||||||
|
# Android, Emscripten or Windows RT. Use MAGNUM_TARGET_EGL instead.
|
||||||
|
# MAGNUM_TARGET_DESKTOP_GLES` - Defined if compiled for OpenGL ES but
|
||||||
|
# GLX / WGL is used instead of EGL. Use MAGNUM_TARGET_EGL instead.
|
||||||
|
# MAGNUM_TARGET_GLES3 - Defined if compiled for OpenGL ES 3.0+ /
|
||||||
|
# WebGL 2. Use an inverse of the MAGNUM_TARGET_GLES2 variable instead.
|
||||||
#
|
#
|
||||||
# Additionally these variables are defined for internal usage:
|
# Additionally these variables are defined for internal usage:
|
||||||
#
|
#
|
||||||
|
@ -159,6 +164,7 @@
|
||||||
# MAGNUM_*_LIBRARY - Component libraries (w/o dependencies)
|
# MAGNUM_*_LIBRARY - Component libraries (w/o dependencies)
|
||||||
# MAGNUM_*_LIBRARY_DEBUG - Debug version of given library, if found
|
# MAGNUM_*_LIBRARY_DEBUG - Debug version of given library, if found
|
||||||
# MAGNUM_*_LIBRARY_RELEASE - Release version of given library, if found
|
# MAGNUM_*_LIBRARY_RELEASE - Release version of given library, if found
|
||||||
|
# MAGNUM_PLATFORM_JS - Path to MagnumPlatform.js file
|
||||||
# MAGNUM_BINARY_INSTALL_DIR - Binary installation directory
|
# MAGNUM_BINARY_INSTALL_DIR - Binary installation directory
|
||||||
# MAGNUM_LIBRARY_INSTALL_DIR - Library installation directory
|
# MAGNUM_LIBRARY_INSTALL_DIR - Library installation directory
|
||||||
# MAGNUM_DATA_INSTALL_DIR - Data installation directory
|
# MAGNUM_DATA_INSTALL_DIR - Data installation directory
|
||||||
|
@ -202,7 +208,7 @@
|
||||||
# This file is part of Magnum.
|
# This file is part of Magnum.
|
||||||
#
|
#
|
||||||
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
||||||
# 2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
|
# 2020, 2021, 2022, 2023 Vladimír Vondruš <mosra@centrum.cz>
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
# copy of this software and associated documentation files (the "Software"),
|
# copy of this software and associated documentation files (the "Software"),
|
||||||
|
@ -223,18 +229,37 @@
|
||||||
# DEALINGS IN THE SOFTWARE.
|
# DEALINGS IN THE SOFTWARE.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
# CMake policies used by FindMagnum are popped again at the end.
|
||||||
|
cmake_policy(PUSH)
|
||||||
|
# Prefer GLVND when finding OpenGL. If this causes problems (known to fail with
|
||||||
|
# NVidia drivers in Debian Buster, reported on 2019-04-09), users can override
|
||||||
|
# this by setting OpenGL_GL_PREFERENCE to LEGACY.
|
||||||
|
if(POLICY CMP0072)
|
||||||
|
cmake_policy(SET CMP0072 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Corrade library dependencies
|
# Corrade library dependencies
|
||||||
set(_MAGNUM_CORRADE_DEPENDENCIES )
|
set(_MAGNUM_CORRADE_DEPENDENCIES )
|
||||||
foreach(_component ${Magnum_FIND_COMPONENTS})
|
foreach(_magnum_component ${Magnum_FIND_COMPONENTS})
|
||||||
string(TOUPPER ${_component} _COMPONENT)
|
set(_MAGNUM_${_magnum_component}_CORRADE_DEPENDENCIES )
|
||||||
|
|
||||||
# Unrolling the transitive dependencies here so this doesn't need to be
|
# Unrolling the transitive dependencies here so this doesn't need to be
|
||||||
# after resolving inter-component dependencies. Listing also all plugins.
|
# after resolving inter-component dependencies. Listing also all plugins.
|
||||||
if(_component MATCHES "^(Audio|DebugTools|MeshTools|Primitives|SceneTools|ShaderTools|Text|TextureTools|Trade|.+Importer|.+ImageConverter|.+Font|.+ShaderConverter)$")
|
if(_magnum_component MATCHES "^(Audio|DebugTools|MeshTools|Primitives|SceneTools|ShaderTools|Text|TextureTools|Trade|.+Importer|.+ImageConverter|.+Font|.+ShaderConverter)$")
|
||||||
set(_MAGNUM_${_COMPONENT}_CORRADE_DEPENDENCIES PluginManager)
|
list(APPEND _MAGNUM_${_magnum_component}_CORRADE_DEPENDENCIES PluginManager)
|
||||||
|
endif()
|
||||||
|
if(_magnum_component STREQUAL DebugTools)
|
||||||
|
# DebugTools depends on TestSuite optionally, so if it's not there
|
||||||
|
# assume it wasn't compiled against it. Also, all variables from the
|
||||||
|
# FindCorrade module overwrite the local variables here (in particular
|
||||||
|
# _component, _COMPONENT and such), so we need to prefix extensively.
|
||||||
|
find_package(Corrade QUIET COMPONENTS TestSuite)
|
||||||
|
if(Corrade_TestSuite_FOUND)
|
||||||
|
list(APPEND _MAGNUM_${_magnum_component}_CORRADE_DEPENDENCIES TestSuite)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list(APPEND _MAGNUM_CORRADE_DEPENDENCIES ${_MAGNUM_${_COMPONENT}_CORRADE_DEPENDENCIES})
|
list(APPEND _MAGNUM_CORRADE_DEPENDENCIES ${_MAGNUM_${_magnum_component}_CORRADE_DEPENDENCIES})
|
||||||
endforeach()
|
endforeach()
|
||||||
find_package(Corrade REQUIRED Utility ${_MAGNUM_CORRADE_DEPENDENCIES})
|
find_package(Corrade REQUIRED Utility ${_MAGNUM_CORRADE_DEPENDENCIES})
|
||||||
|
|
||||||
|
@ -268,10 +293,8 @@ set(_magnumFlags
|
||||||
TARGET_GL
|
TARGET_GL
|
||||||
TARGET_GLES
|
TARGET_GLES
|
||||||
TARGET_GLES2
|
TARGET_GLES2
|
||||||
TARGET_GLES3
|
|
||||||
TARGET_DESKTOP_GLES
|
|
||||||
TARGET_WEBGL
|
TARGET_WEBGL
|
||||||
TARGET_HEADLESS
|
TARGET_EGL
|
||||||
TARGET_VK)
|
TARGET_VK)
|
||||||
foreach(_magnumFlag ${_magnumFlags})
|
foreach(_magnumFlag ${_magnumFlags})
|
||||||
list(FIND _magnumConfigure "#define MAGNUM_${_magnumFlag}" _magnum_${_magnumFlag})
|
list(FIND _magnumConfigure "#define MAGNUM_${_magnumFlag}" _magnum_${_magnumFlag})
|
||||||
|
@ -280,17 +303,23 @@ foreach(_magnumFlag ${_magnumFlags})
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# For compatibility only, to be removed at some point
|
# For compatibility only, to be removed at some point. Refer to
|
||||||
if(MAGNUM_BUILD_DEPRECATED AND CORRADE_BUILD_MULTITHREADED)
|
# src/Magnum/configure.h.cmake for the decision logic here.
|
||||||
|
if(MAGNUM_BUILD_DEPRECATED)
|
||||||
|
if(CORRADE_BUILD_MULTITHREADED)
|
||||||
set(MAGNUM_BUILD_MULTITHREADED 1)
|
set(MAGNUM_BUILD_MULTITHREADED 1)
|
||||||
endif()
|
endif()
|
||||||
|
if(NOT CORRADE_TARGET_IOS AND NOT CORRADE_TARGET_ANDROID AND NOT CORRADE_TARGET_EMSCRIPTEN AND NOT CORRADE_TARGET_WINDOWS_RT)
|
||||||
# OpenGL library preference. Prefer to use GLVND, since that's the better
|
if(NOT MAGNUM_TARGET_GLES AND MAGNUM_TARGET_EGL)
|
||||||
# approach nowadays, but allow the users to override it from outside in case
|
set(MAGNUM_TARGET_HEADLESS 1)
|
||||||
# it is broken for some reason (Nvidia drivers in Debian's testing (Buster) --
|
endif()
|
||||||
# reported on 2019-04-09).
|
if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_EGL)
|
||||||
if(NOT CMAKE_VERSION VERSION_LESS 3.10 AND NOT OpenGL_GL_PREFERENCE)
|
set(MAGNUM_TARGET_DESKTOP_GLES 1)
|
||||||
set(OpenGL_GL_PREFERENCE GLVND)
|
endif()
|
||||||
|
endif()
|
||||||
|
if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_GLES2)
|
||||||
|
set(MAGNUM_TARGET_GLES3 1)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Base Magnum library
|
# Base Magnum library
|
||||||
|
@ -355,8 +384,8 @@ endif()
|
||||||
# Component distinction (listing them explicitly to avoid mistakes with finding
|
# Component distinction (listing them explicitly to avoid mistakes with finding
|
||||||
# components from other repositories)
|
# components from other repositories)
|
||||||
set(_MAGNUM_LIBRARY_COMPONENTS
|
set(_MAGNUM_LIBRARY_COMPONENTS
|
||||||
Audio DebugTools GL MeshTools Primitives SceneGraph SceneTools Shaders
|
Audio DebugTools GL MaterialTools MeshTools Primitives SceneGraph
|
||||||
ShaderTools Text TextureTools Trade
|
SceneTools Shaders ShaderTools Text TextureTools Trade
|
||||||
WindowlessEglApplication EglContext OpenGLTester)
|
WindowlessEglApplication EglContext OpenGLTester)
|
||||||
set(_MAGNUM_PLUGIN_COMPONENTS
|
set(_MAGNUM_PLUGIN_COMPONENTS
|
||||||
AnyAudioImporter AnyImageConverter AnyImageImporter AnySceneConverter
|
AnyAudioImporter AnyImageConverter AnyImageImporter AnySceneConverter
|
||||||
|
@ -395,7 +424,7 @@ if(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE)
|
||||||
list(APPEND _MAGNUM_LIBRARY_COMPONENTS GlxApplication XEglApplication WindowlessGlxApplication GlxContext)
|
list(APPEND _MAGNUM_LIBRARY_COMPONENTS GlxApplication XEglApplication WindowlessGlxApplication GlxContext)
|
||||||
endif()
|
endif()
|
||||||
if(CORRADE_TARGET_WINDOWS)
|
if(CORRADE_TARGET_WINDOWS)
|
||||||
list(APPEND _MAGNUM_LIBRARY_COMPONENTS WindowlessWglApplication WglContext WindowlessWindowsEglApplication)
|
list(APPEND _MAGNUM_LIBRARY_COMPONENTS WindowlessWglApplication WglContext)
|
||||||
endif()
|
endif()
|
||||||
if(CORRADE_TARGET_UNIX OR CORRADE_TARGET_WINDOWS)
|
if(CORRADE_TARGET_UNIX OR CORRADE_TARGET_WINDOWS)
|
||||||
list(APPEND _MAGNUM_EXECUTABLE_COMPONENTS fontconverter distancefieldconverter)
|
list(APPEND _MAGNUM_EXECUTABLE_COMPONENTS fontconverter distancefieldconverter)
|
||||||
|
@ -420,30 +449,24 @@ if(MAGNUM_TARGET_GL)
|
||||||
set(_MAGNUM_DebugTools_GL_DEPENDENCY_IS_OPTIONAL ON)
|
set(_MAGNUM_DebugTools_GL_DEPENDENCY_IS_OPTIONAL ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(_MAGNUM_MaterialTools_DEPENDENCIES Trade)
|
||||||
|
|
||||||
set(_MAGNUM_MeshTools_DEPENDENCIES Trade)
|
set(_MAGNUM_MeshTools_DEPENDENCIES Trade)
|
||||||
if(MAGNUM_TARGET_GL)
|
if(MAGNUM_TARGET_GL)
|
||||||
list(APPEND _MAGNUM_MeshTools_DEPENDENCIES GL)
|
list(APPEND _MAGNUM_MeshTools_DEPENDENCIES GL)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(_MAGNUM_OpenGLTester_DEPENDENCIES GL)
|
set(_MAGNUM_OpenGLTester_DEPENDENCIES GL)
|
||||||
if(MAGNUM_TARGET_HEADLESS OR CORRADE_TARGET_EMSCRIPTEN OR CORRADE_TARGET_ANDROID)
|
if(MAGNUM_TARGET_EGL)
|
||||||
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessEglApplication)
|
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessEglApplication)
|
||||||
elseif(CORRADE_TARGET_IOS)
|
elseif(CORRADE_TARGET_IOS)
|
||||||
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessIosApplication)
|
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessIosApplication)
|
||||||
elseif(CORRADE_TARGET_APPLE AND NOT MAGNUM_TARGET_GLES)
|
elseif(CORRADE_TARGET_APPLE)
|
||||||
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessCglApplication)
|
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessCglApplication)
|
||||||
elseif(CORRADE_TARGET_UNIX)
|
elseif(CORRADE_TARGET_UNIX)
|
||||||
if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_DESKTOP_GLES)
|
|
||||||
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessEglApplication)
|
|
||||||
else()
|
|
||||||
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessGlxApplication)
|
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessGlxApplication)
|
||||||
endif()
|
|
||||||
elseif(CORRADE_TARGET_WINDOWS)
|
elseif(CORRADE_TARGET_WINDOWS)
|
||||||
if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES)
|
|
||||||
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessWglApplication)
|
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessWglApplication)
|
||||||
else()
|
|
||||||
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessWindowsEglApplication)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(_MAGNUM_Primitives_DEPENDENCIES MeshTools Trade)
|
set(_MAGNUM_Primitives_DEPENDENCIES MeshTools Trade)
|
||||||
|
@ -492,7 +515,6 @@ set(_MAGNUM_WindowlessEglApplication_DEPENDENCIES GL)
|
||||||
set(_MAGNUM_WindowlessGlxApplication_DEPENDENCIES GL)
|
set(_MAGNUM_WindowlessGlxApplication_DEPENDENCIES GL)
|
||||||
set(_MAGNUM_WindowlessIosApplication_DEPENDENCIES GL)
|
set(_MAGNUM_WindowlessIosApplication_DEPENDENCIES GL)
|
||||||
set(_MAGNUM_WindowlessWglApplication_DEPENDENCIES GL)
|
set(_MAGNUM_WindowlessWglApplication_DEPENDENCIES GL)
|
||||||
set(_MAGNUM_WindowlessWindowsEglApplication_DEPENDENCIES GL)
|
|
||||||
set(_MAGNUM_XEglApplication_DEPENDENCIES GL)
|
set(_MAGNUM_XEglApplication_DEPENDENCIES GL)
|
||||||
set(_MAGNUM_CglContext_DEPENDENCIES GL)
|
set(_MAGNUM_CglContext_DEPENDENCIES GL)
|
||||||
set(_MAGNUM_EglContext_DEPENDENCIES GL)
|
set(_MAGNUM_EglContext_DEPENDENCIES GL)
|
||||||
|
@ -680,7 +702,17 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
INTERFACE_LINK_LIBRARIES android EGL::EGL)
|
INTERFACE_LINK_LIBRARIES android EGL::EGL)
|
||||||
|
|
||||||
# EmscriptenApplication has no additional dependencies
|
# Emscripten application dependencies
|
||||||
|
elseif(_component STREQUAL EmscriptenApplication)
|
||||||
|
# Emscripten has various stuff implemented in JS
|
||||||
|
if(CORRADE_TARGET_EMSCRIPTEN)
|
||||||
|
find_file(MAGNUM_PLATFORM_JS MagnumPlatform.js
|
||||||
|
PATH_SUFFIXES lib)
|
||||||
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
|
# TODO switch to INTERFACE_LINK_OPTIONS and SHELL: once
|
||||||
|
# we require CMake 3.13 unconditionally
|
||||||
|
INTERFACE_LINK_LIBRARIES "--js-library ${MAGNUM_PLATFORM_JS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
# GLFW application dependencies
|
# GLFW application dependencies
|
||||||
elseif(_component STREQUAL GlfwApplication)
|
elseif(_component STREQUAL GlfwApplication)
|
||||||
|
@ -699,7 +731,7 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})
|
INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# With GLVND (since CMake 3.11) we need to explicitly link to
|
# With GLVND (since CMake 3.10) we need to explicitly link to
|
||||||
# GLX/EGL because libOpenGL doesn't provide it. For EGL we have
|
# GLX/EGL because libOpenGL doesn't provide it. For EGL we have
|
||||||
# our own EGL find module, which makes things simpler. The
|
# our own EGL find module, which makes things simpler. The
|
||||||
# upstream FindOpenGL is anything but simple. Also can't use
|
# upstream FindOpenGL is anything but simple. Also can't use
|
||||||
|
@ -708,16 +740,16 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
# OPENGL_opengl_LIBRARY because that's set even if
|
# OPENGL_opengl_LIBRARY because that's set even if
|
||||||
# OpenGL_GL_PREFERENCE is explicitly set to LEGACY.
|
# OpenGL_GL_PREFERENCE is explicitly set to LEGACY.
|
||||||
if(MAGNUM_TARGET_GL)
|
if(MAGNUM_TARGET_GL)
|
||||||
if(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE AND (NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES))
|
if(MAGNUM_TARGET_EGL)
|
||||||
|
find_package(EGL)
|
||||||
|
set_property(TARGET Magnum::${_component} APPEND
|
||||||
|
PROPERTY INTERFACE_LINK_LIBRARIES EGL::EGL)
|
||||||
|
elseif(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE)
|
||||||
find_package(OpenGL)
|
find_package(OpenGL)
|
||||||
if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)
|
if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)
|
||||||
set_property(TARGET Magnum::${_component} APPEND
|
set_property(TARGET Magnum::${_component} APPEND
|
||||||
PROPERTY INTERFACE_LINK_LIBRARIES OpenGL::GLX)
|
PROPERTY INTERFACE_LINK_LIBRARIES OpenGL::GLX)
|
||||||
endif()
|
endif()
|
||||||
elseif(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_DESKTOP_GLES AND NOT CORRADE_TARGET_EMSCRIPTEN)
|
|
||||||
find_package(EGL)
|
|
||||||
set_property(TARGET Magnum::${_component} APPEND
|
|
||||||
PROPERTY INTERFACE_LINK_LIBRARIES EGL::EGL)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -736,9 +768,17 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
elseif(CORRADE_TARGET_UNIX)
|
elseif(CORRADE_TARGET_UNIX)
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})
|
INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})
|
||||||
|
# Emscripten has various stuff implemented in JS
|
||||||
|
elseif(CORRADE_TARGET_EMSCRIPTEN)
|
||||||
|
find_file(MAGNUM_PLATFORM_JS MagnumPlatform.js
|
||||||
|
PATH_SUFFIXES lib)
|
||||||
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
|
# TODO switch to INTERFACE_LINK_OPTIONS and SHELL: once
|
||||||
|
# we require CMake 3.13 unconditionally
|
||||||
|
INTERFACE_LINK_LIBRARIES "--js-library ${MAGNUM_PLATFORM_JS}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# With GLVND (since CMake 3.11) we need to explicitly link to
|
# With GLVND (since CMake 3.10) we need to explicitly link to
|
||||||
# GLX/EGL because libOpenGL doesn't provide it. For EGL we have
|
# GLX/EGL because libOpenGL doesn't provide it. For EGL we have
|
||||||
# our own EGL find module, which makes things simpler. The
|
# our own EGL find module, which makes things simpler. The
|
||||||
# upstream FindOpenGL is anything but simple. Also can't use
|
# upstream FindOpenGL is anything but simple. Also can't use
|
||||||
|
@ -747,16 +787,16 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
# OPENGL_opengl_LIBRARY because that's set even if
|
# OPENGL_opengl_LIBRARY because that's set even if
|
||||||
# OpenGL_GL_PREFERENCE is explicitly set to LEGACY.
|
# OpenGL_GL_PREFERENCE is explicitly set to LEGACY.
|
||||||
if(MAGNUM_TARGET_GL)
|
if(MAGNUM_TARGET_GL)
|
||||||
if(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE AND (NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES))
|
if(MAGNUM_TARGET_EGL)
|
||||||
|
find_package(EGL)
|
||||||
|
set_property(TARGET Magnum::${_component} APPEND
|
||||||
|
PROPERTY INTERFACE_LINK_LIBRARIES EGL::EGL)
|
||||||
|
elseif(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE)
|
||||||
find_package(OpenGL)
|
find_package(OpenGL)
|
||||||
if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)
|
if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)
|
||||||
set_property(TARGET Magnum::${_component} APPEND
|
set_property(TARGET Magnum::${_component} APPEND
|
||||||
PROPERTY INTERFACE_LINK_LIBRARIES OpenGL::GLX)
|
PROPERTY INTERFACE_LINK_LIBRARIES OpenGL::GLX)
|
||||||
endif()
|
endif()
|
||||||
elseif(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_DESKTOP_GLES AND NOT CORRADE_TARGET_EMSCRIPTEN)
|
|
||||||
find_package(EGL)
|
|
||||||
set_property(TARGET Magnum::${_component} APPEND
|
|
||||||
PROPERTY INTERFACE_LINK_LIBRARIES EGL::EGL)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -768,12 +808,19 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
INTERFACE_LINK_LIBRARIES ${X11_LIBRARIES})
|
INTERFACE_LINK_LIBRARIES ${X11_LIBRARIES})
|
||||||
|
|
||||||
# With GLVND (since CMake 3.11) we need to explicitly link to
|
# With GLVND (since CMake 3.10) we need to explicitly link to
|
||||||
# GLX because libOpenGL doesn't provide it. Also can't use
|
# GLX because libOpenGL doesn't provide it. Also can't use
|
||||||
# OpenGL_OpenGL_FOUND, because that one is set also if GLVND is
|
# OpenGL_OpenGL_FOUND, because that one is set also if GLVND is
|
||||||
# *not* found. WTF. Also can't just check for
|
# *not* found. WTF. Also can't just check for
|
||||||
# OPENGL_opengl_LIBRARY because that's set even if
|
# OPENGL_opengl_LIBRARY because that's set even if
|
||||||
# OpenGL_GL_PREFERENCE is explicitly set to LEGACY.
|
# OpenGL_GL_PREFERENCE is explicitly set to LEGACY.
|
||||||
|
#
|
||||||
|
# If MAGNUM_TARGET_GLES and MAGNUM_TARGET_EGL is set, these
|
||||||
|
# applications can be built only if GLVND is available as
|
||||||
|
# otherwise there would be a conflict between libGL and
|
||||||
|
# libGLES. Thus, if GLVND is not available, it won't link
|
||||||
|
# libGLX here, but that shouldn't be a problem since the
|
||||||
|
# application library won't exist either.
|
||||||
find_package(OpenGL)
|
find_package(OpenGL)
|
||||||
if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)
|
if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
|
@ -799,12 +846,6 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
|
|
||||||
# Windowless WGL application has no additional dependencies
|
# Windowless WGL application has no additional dependencies
|
||||||
|
|
||||||
# Windowless Windows/EGL application dependencies
|
|
||||||
elseif(_component STREQUAL WindowlessWindowsEglApplication)
|
|
||||||
find_package(EGL)
|
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
|
||||||
INTERFACE_LINK_LIBRARIES EGL::EGL)
|
|
||||||
|
|
||||||
# X/EGL application dependencies
|
# X/EGL application dependencies
|
||||||
elseif(_component STREQUAL XEglApplication)
|
elseif(_component STREQUAL XEglApplication)
|
||||||
find_package(EGL)
|
find_package(EGL)
|
||||||
|
@ -822,7 +863,7 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
|
|
||||||
# GLX context dependencies
|
# GLX context dependencies
|
||||||
if(_component STREQUAL GlxContext)
|
if(_component STREQUAL GlxContext)
|
||||||
# With GLVND (since CMake 3.11) we need to explicitly link to
|
# With GLVND (since CMake 3.10) we need to explicitly link to
|
||||||
# GLX because libOpenGL doesn't provide it. Also can't use
|
# GLX because libOpenGL doesn't provide it. Also can't use
|
||||||
# OpenGL_OpenGL_FOUND, because that one is set also if GLVND is
|
# OpenGL_OpenGL_FOUND, because that one is set also if GLVND is
|
||||||
# *not* found. If GLVND is not used, link to X11 instead. Also
|
# *not* found. If GLVND is not used, link to X11 instead. Also
|
||||||
|
@ -854,14 +895,14 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
elseif(_component STREQUAL Audio)
|
elseif(_component STREQUAL Audio)
|
||||||
find_package(OpenAL)
|
find_package(OpenAL)
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
INTERFACE_LINK_LIBRARIES Corrade::PluginManager OpenAL::OpenAL)
|
INTERFACE_LINK_LIBRARIES OpenAL::OpenAL)
|
||||||
|
|
||||||
# No special setup for DebugTools library
|
# No special setup for DebugTools library
|
||||||
|
|
||||||
# GL library
|
# GL library
|
||||||
elseif(_component STREQUAL GL)
|
elseif(_component STREQUAL GL)
|
||||||
if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES)
|
if(NOT MAGNUM_TARGET_GLES OR (MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_EGL AND NOT CORRADE_TARGET_IOS))
|
||||||
# If the GLVND library (CMake 3.11+) was found, link to the
|
# If the GLVND library (CMake 3.10+) was found, link to the
|
||||||
# imported target. Otherwise (and also on all systems except
|
# imported target. Otherwise (and also on all systems except
|
||||||
# Linux) link to the classic libGL. Can't use
|
# Linux) link to the classic libGL. Can't use
|
||||||
# OpenGL_OpenGL_FOUND, because that one is set also if GLVND is
|
# OpenGL_OpenGL_FOUND, because that one is set also if GLVND is
|
||||||
|
@ -880,12 +921,16 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
find_package(OpenGLES2 REQUIRED)
|
find_package(OpenGLES2 REQUIRED)
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
INTERFACE_LINK_LIBRARIES OpenGLES2::OpenGLES2)
|
INTERFACE_LINK_LIBRARIES OpenGLES2::OpenGLES2)
|
||||||
elseif(MAGNUM_TARGET_GLES3)
|
else()
|
||||||
find_package(OpenGLES3 REQUIRED)
|
find_package(OpenGLES3 REQUIRED)
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
INTERFACE_LINK_LIBRARIES OpenGLES3::OpenGLES3)
|
INTERFACE_LINK_LIBRARIES OpenGLES3::OpenGLES3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# MaterialTools library
|
||||||
|
elseif(_component STREQUAL MaterialTools)
|
||||||
|
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES PhongToPbrMetallicRoughness.h)
|
||||||
|
|
||||||
# MeshTools library
|
# MeshTools library
|
||||||
elseif(_component STREQUAL MeshTools)
|
elseif(_component STREQUAL MeshTools)
|
||||||
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES CompressIndices.h)
|
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES CompressIndices.h)
|
||||||
|
@ -904,26 +949,19 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
|
|
||||||
# No special setup for SceneGraph library
|
# No special setup for SceneGraph library
|
||||||
|
|
||||||
# ShaderTools library
|
# SceneTools library
|
||||||
elseif(_component STREQUAL ShaderTools)
|
elseif(_component STREQUAL SceneTools)
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Hierarchy.h)
|
||||||
INTERFACE_LINK_LIBRARIES Corrade::PluginManager)
|
|
||||||
|
|
||||||
|
# No special setup for ShaderTools library
|
||||||
# No special setup for Shaders library
|
# No special setup for Shaders library
|
||||||
|
# No special setup for Text library
|
||||||
# Text library
|
|
||||||
elseif(_component STREQUAL Text)
|
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
|
||||||
INTERFACE_LINK_LIBRARIES Corrade::PluginManager)
|
|
||||||
|
|
||||||
# TextureTools library
|
# TextureTools library
|
||||||
elseif(_component STREQUAL TextureTools)
|
elseif(_component STREQUAL TextureTools)
|
||||||
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Atlas.h)
|
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Atlas.h)
|
||||||
|
|
||||||
# Trade library
|
# No special setup for Trade library
|
||||||
elseif(_component STREQUAL Trade)
|
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
|
||||||
INTERFACE_LINK_LIBRARIES Corrade::PluginManager)
|
|
||||||
|
|
||||||
# Vk library
|
# Vk library
|
||||||
elseif(_component STREQUAL Vk)
|
elseif(_component STREQUAL Vk)
|
||||||
|
@ -952,8 +990,13 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Automatic import of static plugins. Skip in case the include dir was
|
# Automatic import of static plugins. Skip in case the include dir was
|
||||||
# not found -- that'll fail later with a proper message.
|
# not found -- that'll fail later with a proper message. Skip it also
|
||||||
if(_component IN_LIST _MAGNUM_PLUGIN_COMPONENTS AND _MAGNUM_${_COMPONENT}_INCLUDE_DIR)
|
# if the include dir doesn't contain the generated configure.h, which
|
||||||
|
# is the case with Magnum as a subproject and given plugin not enabled
|
||||||
|
# -- there it finds just the sources, where's just configure.h.cmake,
|
||||||
|
# and that's not useful for anything. The assumption here is that it
|
||||||
|
# will fail later anyway on the binary not being found.
|
||||||
|
if(_component IN_LIST _MAGNUM_PLUGIN_COMPONENTS AND _MAGNUM_${_COMPONENT}_INCLUDE_DIR AND EXISTS ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}/configure.h)
|
||||||
# Automatic import of static plugins
|
# Automatic import of static plugins
|
||||||
file(READ ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}/configure.h _magnum${_component}Configure)
|
file(READ ${_MAGNUM_${_COMPONENT}_INCLUDE_DIR}/configure.h _magnum${_component}Configure)
|
||||||
string(FIND "${_magnum${_component}Configure}" "#define MAGNUM_${_COMPONENT}_BUILD_STATIC" _magnum${_component}_BUILD_STATIC)
|
string(FIND "${_magnum${_component}Configure}" "#define MAGNUM_${_COMPONENT}_BUILD_STATIC" _magnum${_component}_BUILD_STATIC)
|
||||||
|
@ -967,9 +1010,13 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||||
# are optional dependencies, defer adding them to later once we know if
|
# are optional dependencies, defer adding them to later once we know if
|
||||||
# they were found or not.
|
# they were found or not.
|
||||||
if(_component IN_LIST _MAGNUM_LIBRARY_COMPONENTS OR _component IN_LIST _MAGNUM_PLUGIN_COMPONENTS)
|
if(_component IN_LIST _MAGNUM_LIBRARY_COMPONENTS OR _component IN_LIST _MAGNUM_PLUGIN_COMPONENTS)
|
||||||
|
foreach(_dependency ${_MAGNUM_${_component}_CORRADE_DEPENDENCIES})
|
||||||
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
|
INTERFACE_LINK_LIBRARIES Corrade::${_dependency})
|
||||||
|
endforeach()
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
INTERFACE_LINK_LIBRARIES Magnum::Magnum)
|
INTERFACE_LINK_LIBRARIES Magnum::Magnum)
|
||||||
set(_MAGNUM_${component}_OPTIONAL_DEPENDENCIES_TO_ADD )
|
set(_MAGNUM_${_component}_OPTIONAL_DEPENDENCIES_TO_ADD )
|
||||||
foreach(_dependency ${_MAGNUM_${_component}_DEPENDENCIES})
|
foreach(_dependency ${_MAGNUM_${_component}_DEPENDENCIES})
|
||||||
if(NOT _MAGNUM_${_component}_${_dependency}_DEPENDENCY_IS_OPTIONAL)
|
if(NOT _MAGNUM_${_component}_${_dependency}_DEPENDENCY_IS_OPTIONAL)
|
||||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||||
|
@ -1031,20 +1078,6 @@ if(CORRADE_TARGET_EMSCRIPTEN)
|
||||||
MAGNUM_EMSCRIPTENAPPLICATION_JS
|
MAGNUM_EMSCRIPTENAPPLICATION_JS
|
||||||
MAGNUM_WINDOWLESSEMSCRIPTENAPPLICATION_JS
|
MAGNUM_WINDOWLESSEMSCRIPTENAPPLICATION_JS
|
||||||
MAGNUM_WEBAPPLICATION_CSS)
|
MAGNUM_WEBAPPLICATION_CSS)
|
||||||
|
|
||||||
# If we are on CMake 3.13 and up, `-s USE_WEBGL2=1` linker option is
|
|
||||||
# propagated from FindOpenGLES3.cmake already. If not (and the GL library
|
|
||||||
# is used), we need to modify the global CMAKE_EXE_LINKER_FLAGS. Do it here
|
|
||||||
# instead of in FindOpenGLES3.cmake so it works also for CMake subprojects
|
|
||||||
# (in which case find_package(OpenGLES3) is called in (and so
|
|
||||||
# CMAKE_EXE_LINKER_FLAGS would be modified in) Magnum's root CMakeLists.txt
|
|
||||||
# and thus can't affect the variable in the outer project). CMake supports
|
|
||||||
# IN_LIST as an operator since 3.1 (Emscripten needs at least 3.7), but
|
|
||||||
# it's behind a policy, so enable that one as well.
|
|
||||||
cmake_policy(SET CMP0057 NEW)
|
|
||||||
if(CMAKE_VERSION VERSION_LESS 3.13 AND GL IN_LIST Magnum_FIND_COMPONENTS AND NOT MAGNUM_TARGET_GLES2 AND NOT CMAKE_EXE_LINKER_FLAGS MATCHES "-s USE_WEBGL2=1")
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_WEBGL2=1")
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# For CMake 3.16+ with REASON_FAILURE_MESSAGE, provide additional potentially
|
# For CMake 3.16+ with REASON_FAILURE_MESSAGE, provide additional potentially
|
||||||
|
@ -1069,7 +1102,7 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.16)
|
||||||
# misleading messages.
|
# misleading messages.
|
||||||
elseif(NOT _component IN_LIST _MAGNUM_IMPLICITLY_ENABLED_COMPONENTS)
|
elseif(NOT _component IN_LIST _MAGNUM_IMPLICITLY_ENABLED_COMPONENTS)
|
||||||
string(TOUPPER ${_component} _COMPONENT)
|
string(TOUPPER ${_component} _COMPONENT)
|
||||||
list(APPEND _MAGNUM_REASON_FAILURE_MESSAGE "${_component} is not built by default. Make sure you enabled WITH_${_COMPONENT} when building Magnum.")
|
list(APPEND _MAGNUM_REASON_FAILURE_MESSAGE "${_component} is not built by default. Make sure you enabled MAGNUM_WITH_${_COMPONENT} when building Magnum.")
|
||||||
# Otherwise we have no idea. Better be silent than to print something
|
# Otherwise we have no idea. Better be silent than to print something
|
||||||
# misleading.
|
# misleading.
|
||||||
else()
|
else()
|
||||||
|
@ -1271,3 +1304,6 @@ if(MAGNUM_PLUGINS_RELEASE_DIR)
|
||||||
set(MAGNUM_PLUGINS_SCENECONVERTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/sceneconverters)
|
set(MAGNUM_PLUGINS_SCENECONVERTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/sceneconverters)
|
||||||
set(MAGNUM_PLUGINS_AUDIOIMPORTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/audioimporters)
|
set(MAGNUM_PLUGINS_AUDIOIMPORTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/audioimporters)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Resets CMake policies set at the top of the file to not affect other code.
|
||||||
|
cmake_policy(POP)
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
# This file is part of Magnum.
|
# This file is part of Magnum.
|
||||||
#
|
#
|
||||||
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
||||||
# 2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
|
# 2020, 2021, 2022, 2023 Vladimír Vondruš <mosra@centrum.cz>
|
||||||
# Copyright © 2018 Konstantinos Chatzilygeroudis <costashatz@gmail.com>
|
# Copyright © 2018 Konstantinos Chatzilygeroudis <costashatz@gmail.com>
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
@ -89,8 +89,14 @@ if(_MAGNUMINTEGRATION_OPTIONAL_DEPENDENCIES)
|
||||||
find_package(Magnum OPTIONAL_COMPONENTS ${_MAGNUMINTEGRATION_OPTIONAL_DEPENDENCIES})
|
find_package(Magnum OPTIONAL_COMPONENTS ${_MAGNUMINTEGRATION_OPTIONAL_DEPENDENCIES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Global integration include dir
|
# Global include dir that's unique to Magnum Integration. Often it will be
|
||||||
find_path(MAGNUMINTEGRATION_INCLUDE_DIR Magnum
|
# installed alongside Magnum, which is why the hint, but if not, it shouldn't
|
||||||
|
# just pick MAGNUM_INCLUDE_DIR because then _MAGNUMINTEGRATION_*_INCLUDE_DIR
|
||||||
|
# will fail to be found. In case of CMake subprojects the versionIntegration.h
|
||||||
|
# is generated inside the build dir so this won't find it, instead
|
||||||
|
# src/CMakeLists.txt forcibly sets MAGNUMINTEGRATION_INCLUDE_DIR as an internal
|
||||||
|
# cache value to make that work.
|
||||||
|
find_path(MAGNUMINTEGRATION_INCLUDE_DIR Magnum/versionIntegration.h
|
||||||
HINTS ${MAGNUM_INCLUDE_DIR})
|
HINTS ${MAGNUM_INCLUDE_DIR})
|
||||||
mark_as_advanced(MAGNUMINTEGRATION_INCLUDE_DIR)
|
mark_as_advanced(MAGNUMINTEGRATION_INCLUDE_DIR)
|
||||||
|
|
||||||
|
@ -314,7 +320,7 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.16)
|
||||||
# misleading messages.
|
# misleading messages.
|
||||||
elseif(NOT _component IN_LIST _MAGNUMINTEGRATION_IMPLICITLY_ENABLED_COMPONENTS)
|
elseif(NOT _component IN_LIST _MAGNUMINTEGRATION_IMPLICITLY_ENABLED_COMPONENTS)
|
||||||
string(TOUPPER ${_component} _COMPONENT)
|
string(TOUPPER ${_component} _COMPONENT)
|
||||||
list(APPEND _MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE "${_component} is not built by default. Make sure you enabled WITH_${_COMPONENT} when building Magnum Integration.")
|
list(APPEND _MAGNUMINTEGRATION_REASON_FAILURE_MESSAGE "${_component} is not built by default. Make sure you enabled MAGNUM_WITH_${_COMPONENT} when building Magnum Integration.")
|
||||||
# Otherwise we have no idea. Better be silent than to print something
|
# Otherwise we have no idea. Better be silent than to print something
|
||||||
# misleading.
|
# misleading.
|
||||||
else()
|
else()
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
# This file is part of Magnum.
|
# This file is part of Magnum.
|
||||||
#
|
#
|
||||||
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
|
||||||
# 2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
|
# 2020, 2021, 2022, 2023 Vladimír Vondruš <mosra@centrum.cz>
|
||||||
# Copyright © 2018 Jonathan Hale <squareys@googlemail.com>
|
# Copyright © 2018 Jonathan Hale <squareys@googlemail.com>
|
||||||
#
|
#
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
@ -138,10 +138,10 @@ else()
|
||||||
# which CMake somehow prefers before the SDL2-2.0.dylib file. Making
|
# which CMake somehow prefers before the SDL2-2.0.dylib file. Making
|
||||||
# the dylib first so it is preferred. Not sure how this maps to debug
|
# the dylib first so it is preferred. Not sure how this maps to debug
|
||||||
# config though :/
|
# config though :/
|
||||||
NAMES SDL2-2.0 SDL2
|
NAMES SDL2-2.0 SDL2 SDL2-static
|
||||||
PATH_SUFFIXES ${_SDL2_LIBRARY_PATH_SUFFIX})
|
PATH_SUFFIXES ${_SDL2_LIBRARY_PATH_SUFFIX})
|
||||||
find_library(SDL2_LIBRARY_DEBUG
|
find_library(SDL2_LIBRARY_DEBUG
|
||||||
NAMES SDL2d
|
NAMES SDL2d SDL2-staticd
|
||||||
PATH_SUFFIXES ${_SDL2_LIBRARY_PATH_SUFFIX})
|
PATH_SUFFIXES ${_SDL2_LIBRARY_PATH_SUFFIX})
|
||||||
# FPHSA needs one of the _DEBUG/_RELEASE variables to check that the
|
# FPHSA needs one of the _DEBUG/_RELEASE variables to check that the
|
||||||
# library was found -- using SDL_LIBRARY, which will get populated by
|
# library was found -- using SDL_LIBRARY, which will get populated by
|
||||||
|
|
|
@ -11,4 +11,16 @@
|
||||||
/>
|
/>
|
||||||
</dependentAssembly>
|
</dependentAssembly>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<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>
|
</assembly>
|
555
src/Application/Application.cpp
Normal file
555
src/Application/Application.cpp
Normal file
|
@ -0,0 +1,555 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Containers/ScopeGuard.h>
|
||||||
|
#include <Corrade/Utility/Unicode.h>
|
||||||
|
|
||||||
|
#include <Magnum/GL/DebugOutput.h>
|
||||||
|
#include <Magnum/GL/DefaultFramebuffer.h>
|
||||||
|
#include <Magnum/GL/Extensions.h>
|
||||||
|
#include <Magnum/GL/Renderer.h>
|
||||||
|
|
||||||
|
#include <Magnum/ImGuiIntegration/Integration.h>
|
||||||
|
#include <Magnum/ImGuiIntegration/Context.hpp>
|
||||||
|
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
|
||||||
|
#include <wtypesbase.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <wtsapi32.h>
|
||||||
|
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
#include "../Configuration/Configuration.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
extern const ImVec2 center_pivot = {0.5f, 0.5f};
|
||||||
|
|
||||||
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
|
Utility::Tweakable tweak;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace mbst {
|
||||||
|
|
||||||
|
Application::Application(const Arguments& arguments):
|
||||||
|
Platform::Sdl2Application{arguments,
|
||||||
|
Configuration{}.setTitle("M.A.S.S. Builder Save Tool " SAVETOOL_VERSION_STRING " (\"" SAVETOOL_CODENAME "\")")
|
||||||
|
.setSize({960, 720})}
|
||||||
|
{
|
||||||
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
|
tweak.enable("", "../../");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LOG_INFO_FORMAT("Framebuffer size: {}x{}", framebufferSize().x(), framebufferSize().y());
|
||||||
|
LOG_INFO_FORMAT("Window size: {}x{}", windowSize().x(), windowSize().y());
|
||||||
|
LOG_INFO_FORMAT("DPI scaling: {}x{}", dpiScaling().x(), dpiScaling().y());
|
||||||
|
|
||||||
|
LOG_INFO("Configuring OpenGL renderer.");
|
||||||
|
GL::Renderer::enable(GL::Renderer::Feature::Blending);
|
||||||
|
GL::Renderer::enable(GL::Renderer::Feature::ScissorTest);
|
||||||
|
GL::Renderer::setBlendFunction(GL::Renderer::BlendFunction::SourceAlpha,
|
||||||
|
GL::Renderer::BlendFunction::OneMinusSourceAlpha);
|
||||||
|
GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add,
|
||||||
|
GL::Renderer::BlendEquation::Add);
|
||||||
|
|
||||||
|
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)) == std::uint32_t(-1)) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
|
"SDL_RegisterEvents() failed in Application::SaveTool(). Exiting...", window());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateEventId = _initEventId + 1;
|
||||||
|
_fileEventId = _initEventId + 2;
|
||||||
|
|
||||||
|
LOG_INFO("Initialising the timer subsystem.");
|
||||||
|
if(SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
|
||||||
|
LOG_ERROR(SDL_GetError());
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app",
|
||||||
|
SDL_GetError(), window());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialiseGui();
|
||||||
|
|
||||||
|
checkGameState();
|
||||||
|
_gameCheckTimerId = SDL_AddTimer(2000,
|
||||||
|
[](std::uint32_t interval, void* param)->std::uint32_t{
|
||||||
|
static_cast<Application*>(param)->checkGameState();
|
||||||
|
return interval;
|
||||||
|
}, this);
|
||||||
|
if(_gameCheckTimerId == 0) {
|
||||||
|
LOG_ERROR(SDL_GetError());
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), window());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initialiseConfiguration();
|
||||||
|
|
||||||
|
if(conf().checkUpdatesOnStartup()) {
|
||||||
|
_queue.addToast(Toast::Type::Default, "Checking for updates..."_s);
|
||||||
|
_updateThread = std::thread{[this]{ checkForUpdates(); }};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(GL::Context::current().isExtensionSupported<GL::Extensions::KHR::debug>() &&
|
||||||
|
GL::Context::current().detectedDriver() == GL::Context::DetectedDriver::NVidia)
|
||||||
|
{
|
||||||
|
GL::DebugOutput::setEnabled(GL::DebugOutput::Source::Api, GL::DebugOutput::Type::Other, {131185}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(conf().skipDisclaimer()) {
|
||||||
|
_uiState = UiState::Initialising;
|
||||||
|
_initThread = std::thread{[this]{ initialiseManager(); }};
|
||||||
|
}
|
||||||
|
|
||||||
|
_timeline.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::~Application() {
|
||||||
|
LOG_INFO("Cleaning up.");
|
||||||
|
|
||||||
|
SDL_RemoveTimer(_gameCheckTimerId);
|
||||||
|
|
||||||
|
LOG_INFO("Saving the configuration.");
|
||||||
|
|
||||||
|
conf().save();
|
||||||
|
|
||||||
|
LOG_INFO("Exiting.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawEvent() {
|
||||||
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
|
tweak.update();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);
|
||||||
|
|
||||||
|
drawImGui();
|
||||||
|
|
||||||
|
swapBuffers();
|
||||||
|
|
||||||
|
if(conf().swapInterval() == 0 && conf().fpsCap() < 301.0f) {
|
||||||
|
while(_timeline.currentFrameDuration() < (1.0f / conf().fpsCap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
redraw();
|
||||||
|
|
||||||
|
_timeline.nextFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::viewportEvent(ViewportEvent& event) {
|
||||||
|
GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()});
|
||||||
|
|
||||||
|
const auto size = Vector2{windowSize()}/dpiScaling();
|
||||||
|
_imgui.relayout(size, windowSize(), framebufferSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::keyPressEvent(KeyEvent& event) {
|
||||||
|
if(_imgui.handleKeyPressEvent(event)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::keyReleaseEvent(KeyEvent& event) {
|
||||||
|
if(_imgui.handleKeyReleaseEvent(event)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::mousePressEvent(MouseEvent& event) {
|
||||||
|
if(_imgui.handleMousePressEvent(event)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::mouseReleaseEvent(MouseEvent& event) {
|
||||||
|
if(_imgui.handleMouseReleaseEvent(event)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::mouseMoveEvent(MouseMoveEvent& event) {
|
||||||
|
if(_imgui.handleMouseMoveEvent(event)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::mouseScrollEvent(MouseScrollEvent& event) {
|
||||||
|
if(_imgui.handleMouseScrollEvent(event)) {
|
||||||
|
event.setAccepted();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::textInputEvent(TextInputEvent& event) {
|
||||||
|
if(_imgui.handleTextInputEvent(event)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::anyEvent(SDL_Event& event) {
|
||||||
|
if(event.type == _initEventId) {
|
||||||
|
initEvent(event);
|
||||||
|
}
|
||||||
|
else if(event.type == _updateEventId) {
|
||||||
|
updateCheckEvent(event);
|
||||||
|
}
|
||||||
|
else if(event.type == _fileEventId) {
|
||||||
|
fileUpdateEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawImGui() {
|
||||||
|
_imgui.newFrame();
|
||||||
|
|
||||||
|
if(ImGui::GetIO().WantTextInput && !isTextInputActive()) {
|
||||||
|
startTextInput();
|
||||||
|
}
|
||||||
|
else if(!ImGui::GetIO().WantTextInput && isTextInputActive()) {
|
||||||
|
stopTextInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawGui();
|
||||||
|
|
||||||
|
_imgui.updateApplicationCursor(*this);
|
||||||
|
|
||||||
|
_imgui.drawFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawGui() {
|
||||||
|
drawMainMenu();
|
||||||
|
|
||||||
|
switch(_uiState) {
|
||||||
|
case UiState::Disclaimer:
|
||||||
|
drawDisclaimer();
|
||||||
|
break;
|
||||||
|
case UiState::Initialising:
|
||||||
|
drawInitialisation();
|
||||||
|
break;
|
||||||
|
case UiState::ProfileManager:
|
||||||
|
drawProfileManager();
|
||||||
|
break;
|
||||||
|
case UiState::MainManager:
|
||||||
|
drawManager();
|
||||||
|
break;
|
||||||
|
case UiState::MassViewer:
|
||||||
|
drawMassViewer();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_aboutPopup) {
|
||||||
|
drawAbout();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
|
if(_demoWindow) {
|
||||||
|
ImGui::ShowDemoWindow(&_demoWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_styleEditor) {
|
||||||
|
ImGui::ShowStyleEditor(&ImGui::GetStyle());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_metricsWindow) {
|
||||||
|
ImGui::ShowMetricsWindow(&_metricsWindow);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_queue.draw(windowSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawDisclaimer() {
|
||||||
|
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f} / dpiScaling()}, ImGuiCond_Always, center_pivot);
|
||||||
|
|
||||||
|
if(ImGui::Begin("Disclaimer##DisclaimerWindow", nullptr,
|
||||||
|
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoBringToFrontOnFocus|
|
||||||
|
ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_MenuBar))
|
||||||
|
{
|
||||||
|
if(ImGui::BeginMenuBar()) {
|
||||||
|
ImGui::TextUnformatted("Disclaimer");
|
||||||
|
ImGui::EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("Before you start using the app, there are a few things you should know:");
|
||||||
|
|
||||||
|
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.67f);
|
||||||
|
|
||||||
|
ImGui::Bullet();
|
||||||
|
ImGui::SameLine();
|
||||||
|
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::SameLine();
|
||||||
|
ImGui::TextUnformatted("The developer of this application (Guillaume Jacquemin) isn't associated with Vermillion Digital, and both parties cannot be held responsible for data loss or corruption this app might cause. PLEASE USE AT YOUR OWN RISK!");
|
||||||
|
|
||||||
|
ImGui::Bullet();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted("This application is released under the terms of the GNU General Public Licence version 3. Please see the COPYING file for more details, or the About screen if you somehow didn't get that file with your download of the program.");
|
||||||
|
|
||||||
|
ImGui::Bullet();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted("This version of the application was tested on M.A.S.S. Builder early access version " SAVETOOL_SUPPORTED_GAME_VERSION ". It may or may not work with other versions of the game.");
|
||||||
|
|
||||||
|
if(conf().isRunningInWine()) {
|
||||||
|
ImGui::Bullet();
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted("You are currently running this application in Wine/Proton. It hasn't been fully tested, so some issues may arise. Furthermore, features may be unavailable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
|
||||||
|
if(ImGui::BeginTable("##DisclaimerLayoutTable", 3)) {
|
||||||
|
ImGui::TableSetupColumn("##Empty1", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
ImGui::TableSetupColumn("##Button", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
ImGui::TableSetupColumn("##Empty2", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(0);
|
||||||
|
ImGui::Dummy({0.0f, 5.0f});
|
||||||
|
ImGui::Dummy({4.0f, 0.0f});
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(drawCheckbox("Don't show next time", conf().skipDisclaimer())) {
|
||||||
|
conf().setSkipDisclaimer(!conf().skipDisclaimer());
|
||||||
|
}
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {24.0f, 12.0f});
|
||||||
|
if(ImGui::Button("I understand the risks")) {
|
||||||
|
_uiState = UiState::Initialising;
|
||||||
|
_initThread = std::thread{[this]{ initialiseManager(); }};
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawInitialisation() {
|
||||||
|
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f} / dpiScaling()}, ImGuiCond_Always, center_pivot);
|
||||||
|
|
||||||
|
if(ImGui::BeginPopupModal("##InitPopup", nullptr,
|
||||||
|
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar))
|
||||||
|
{
|
||||||
|
ImGui::TextUnformatted("Initialising the manager. Please wait...");
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::OpenPopup("##InitPopup");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawGameState() {
|
||||||
|
ImGui::TextUnformatted("Game state:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
{
|
||||||
|
switch(_gameState) {
|
||||||
|
case GameState::Unknown:
|
||||||
|
ImGui::TextColored(ImColor{0xff00a5ff}, ICON_FA_CIRCLE);
|
||||||
|
drawTooltip("unknown");
|
||||||
|
break;
|
||||||
|
case GameState::NotRunning:
|
||||||
|
ImGui::TextColored(ImColor{0xff32cd32}, ICON_FA_CIRCLE);
|
||||||
|
drawTooltip("not running");
|
||||||
|
break;
|
||||||
|
case GameState::Running:
|
||||||
|
ImGui::TextColored(ImColor{0xff0000ff}, ICON_FA_CIRCLE);
|
||||||
|
drawTooltip("running");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawHelpMarker(Containers::StringView text, float wrap_pos) {
|
||||||
|
ImGui::TextUnformatted(ICON_FA_QUESTION_CIRCLE);
|
||||||
|
drawTooltip(text, wrap_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawTooltip(Containers::StringView text, float wrap_pos) {
|
||||||
|
if(ImGui::IsItemHovered() && ImGui::BeginTooltip()) {
|
||||||
|
if(wrap_pos > 0.0f) {
|
||||||
|
ImGui::PushTextWrapPos(wrap_pos);
|
||||||
|
}
|
||||||
|
ImGui::TextUnformatted(text.cbegin(), text.cend());
|
||||||
|
if(wrap_pos > 0.0f) {
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
}
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Application::drawCheckbox(Containers::StringView label, bool value) {
|
||||||
|
return ImGui::Checkbox(label.data(), &value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawVector3Drag(Containers::StringView id, Vector3& vec, float speed, Vector3 min, Vector3 max,
|
||||||
|
const char* x_format, const char* y_format, const char* z_format, ImGuiSliderFlags_ flags)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id.cbegin());
|
||||||
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
|
ImGui::DragFloat("##X", &vec.x(), speed, min.x(), max.x(), x_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::DragFloat("##Y", &vec.y(), speed, min.y(), max.y(), y_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::DragFloat("##Z", &vec.z(), speed, min.z(), max.z(), z_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawVector3dDrag(Containers::StringView id, Vector3d& vec, float speed, Vector3d min, Vector3d max,
|
||||||
|
const char* x_format, const char* y_format, const char* z_format,
|
||||||
|
ImGuiSliderFlags_ flags)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id.cbegin());
|
||||||
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
|
ImGui::DragScalar("##X", ImGuiDataType_Double, &vec.x(), speed, &min.x(), &max.x(), x_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::DragScalar("##Y", ImGuiDataType_Double, &vec.y(), speed, &min.y(), &max.y(), y_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::DragScalar("##X", ImGuiDataType_Double, &vec.x(), speed, &min.z(), &max.z(), z_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawVector3Slider(Containers::StringView id, Vector3& vec, Vector3 min, Vector3 max, const char* x_format,
|
||||||
|
const char* y_format, const char* z_format, ImGuiSliderFlags_ flags)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id.cbegin());
|
||||||
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
|
ImGui::SliderFloat("##X", &vec.x(), min.x(), max.x(), x_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::SliderFloat("##Y", &vec.y(), min.y(), max.y(), y_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::SliderFloat("##Z", &vec.z(), min.z(), max.z(), z_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawVector3dSlider(Containers::StringView id, Vector3d& vec, Vector3d min, Vector3d max,
|
||||||
|
const char* x_format, const char* y_format, const char* z_format,
|
||||||
|
ImGuiSliderFlags_ flags)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id.cbegin());
|
||||||
|
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||||
|
ImGui::SliderScalar("##X", ImGuiDataType_Double, &vec.x(), &min.x(), &max.x(), x_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::SliderScalar("##Y", ImGuiDataType_Double, &vec.y(), &min.y(), &max.y(), y_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::SliderScalar("##X", ImGuiDataType_Double, &vec.x(), &min.z(), &max.z(), z_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawVector2Slider(Containers::StringView id, Vector2& vec, Vector2 min, Vector2 max, const char* x_format,
|
||||||
|
const char* y_format, ImGuiSliderFlags_ flags)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id.cbegin());
|
||||||
|
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
||||||
|
ImGui::SliderFloat("##X", &vec.x(), min.x(), max.x(), x_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::SliderFloat("##Y", &vec.y(), min.y(), max.y(), y_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawVector2dSlider(Containers::StringView id, Vector2d& vec, Vector2d min, Vector2d max,
|
||||||
|
const char* x_format, const char* y_format, ImGuiSliderFlags_ flags)
|
||||||
|
{
|
||||||
|
ImGui::PushID(id.cbegin());
|
||||||
|
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
||||||
|
ImGui::SliderScalar("##X", ImGuiDataType_Double, &vec.x(), &min.x(), &max.x(), x_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
ImGui::SliderScalar("##Y", ImGuiDataType_Double, &vec.y(), &min.y(), &max.y(), y_format, flags);
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::openUri(Containers::StringView uri) {
|
||||||
|
if(!conf().isRunningInWine()) {
|
||||||
|
ShellExecuteA(nullptr, nullptr, uri.data(), nullptr, nullptr, SW_SHOWDEFAULT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::system(Utility::format("winebrowser.exe {}", uri).cbegin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::checkGameState() {
|
||||||
|
WTS_PROCESS_INFOW* process_infos = nullptr;
|
||||||
|
unsigned long process_count = 0;
|
||||||
|
|
||||||
|
if(WTSEnumerateProcessesW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &process_infos, &process_count)) {
|
||||||
|
Containers::ScopeGuard guard{process_infos, WTSFreeMemory};
|
||||||
|
|
||||||
|
for(unsigned long i = 0; i < process_count; ++i) {
|
||||||
|
if(std::wcscmp(process_infos[i].pProcessName, L"MASS_Builder-Win64-Shipping.exe") == 0) {
|
||||||
|
_gameState = GameState::Running;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_gameState = GameState::NotRunning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_gameState = GameState::Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
300
src/Application/Application.h
Normal file
300
src/Application/Application.h
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/Pointer.h>
|
||||||
|
#include <Corrade/Containers/String.h>
|
||||||
|
#include <Corrade/Utility/Resource.h>
|
||||||
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
|
#include <Corrade/Utility/Tweakable.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Magnum/Timeline.h>
|
||||||
|
#include <Magnum/Platform/Sdl2Application.h>
|
||||||
|
#include <Magnum/ImGuiIntegration/Context.h>
|
||||||
|
|
||||||
|
#include <SDL_timer.h>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <efsw/efsw.hpp>
|
||||||
|
|
||||||
|
#include "../Managers/BackupManager.h"
|
||||||
|
#include "../Managers/MassManager.h"
|
||||||
|
#include "../Managers/ProfileManager.h"
|
||||||
|
#include "../Managers/StagedMassManager.h"
|
||||||
|
#include "../ToastQueue/ToastQueue.h"
|
||||||
|
#include "../UpdateChecker/UpdateChecker.h"
|
||||||
|
|
||||||
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
|
#define tw CORRADE_TWEAKABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
using namespace Magnum;
|
||||||
|
|
||||||
|
namespace mbst {
|
||||||
|
|
||||||
|
class Application: public Platform::Sdl2Application, public efsw::FileWatchListener {
|
||||||
|
public:
|
||||||
|
explicit Application(const Arguments& arguments);
|
||||||
|
|
||||||
|
~Application() override;
|
||||||
|
|
||||||
|
void handleFileAction(efsw::WatchID watch_id,
|
||||||
|
const std::string& dir,
|
||||||
|
const std::string& filename,
|
||||||
|
efsw::Action action,
|
||||||
|
std::string old_filename) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Events
|
||||||
|
void drawEvent() override;
|
||||||
|
void viewportEvent(ViewportEvent& event) override;
|
||||||
|
|
||||||
|
void keyPressEvent(KeyEvent& event) override;
|
||||||
|
void keyReleaseEvent(KeyEvent& event) override;
|
||||||
|
|
||||||
|
void mousePressEvent(MouseEvent& event) override;
|
||||||
|
void mouseReleaseEvent(MouseEvent& event) override;
|
||||||
|
void mouseMoveEvent(MouseMoveEvent& event) override;
|
||||||
|
void mouseScrollEvent(MouseScrollEvent& event) override;
|
||||||
|
void textInputEvent(TextInputEvent& event) override;
|
||||||
|
|
||||||
|
void anyEvent(SDL_Event& event) override;
|
||||||
|
|
||||||
|
enum InitStatus: std::int32_t {
|
||||||
|
InitSuccess,
|
||||||
|
ProfileManagerFailure
|
||||||
|
};
|
||||||
|
void initEvent(SDL_Event& event);
|
||||||
|
|
||||||
|
void updateCheckEvent(SDL_Event& event);
|
||||||
|
|
||||||
|
enum FileEventType: std::int32_t {
|
||||||
|
FileAdded = efsw::Action::Add,
|
||||||
|
FileDeleted = efsw::Action::Delete,
|
||||||
|
FileModified = efsw::Action::Modified,
|
||||||
|
FileMoved = efsw::Action::Moved,
|
||||||
|
StagedUpdate = 1 << 3
|
||||||
|
};
|
||||||
|
void fileUpdateEvent(SDL_Event& event);
|
||||||
|
|
||||||
|
// Initialisation methods
|
||||||
|
void initialiseConfiguration();
|
||||||
|
void initialiseGui();
|
||||||
|
void initialiseManager();
|
||||||
|
void initialiseMassManager();
|
||||||
|
void initialiseFileWatcher();
|
||||||
|
|
||||||
|
// GUI-related methods
|
||||||
|
void drawImGui();
|
||||||
|
void drawGui();
|
||||||
|
void drawMainMenu();
|
||||||
|
void drawDisclaimer();
|
||||||
|
void drawInitialisation();
|
||||||
|
|
||||||
|
void drawProfileManager();
|
||||||
|
void drawBackupListPopup();
|
||||||
|
void drawBackupFolder(const Managers::Vfs::Directory<Managers::Backup>& dir);
|
||||||
|
void drawBackupRestorePopup(std::size_t backup_index);
|
||||||
|
void drawBackupDeletePopup(std::size_t backup_index);
|
||||||
|
void drawDeleteProfilePopup(std::size_t profile_index);
|
||||||
|
|
||||||
|
void drawManager();
|
||||||
|
bool drawIntEditPopup(int* value_to_edit, int max);
|
||||||
|
bool drawRenamePopup(Containers::ArrayView<char> name_view);
|
||||||
|
void drawGeneralInfo();
|
||||||
|
void drawResearchInventory();
|
||||||
|
void drawMaterialRow(Containers::StringView name, std::int32_t tier, GameData::MaterialID id);
|
||||||
|
void drawMassManager();
|
||||||
|
void drawDeleteMassPopup(int mass_index);
|
||||||
|
void drawDeleteStagedMassPopup(Containers::StringView filename);
|
||||||
|
|
||||||
|
void drawMassViewer();
|
||||||
|
void drawFrameInfo();
|
||||||
|
void drawJointSliders();
|
||||||
|
void drawFrameStyles();
|
||||||
|
void drawEyeColourPicker();
|
||||||
|
void drawCustomFrameStyles();
|
||||||
|
void drawArmour();
|
||||||
|
void drawBLAttachment();
|
||||||
|
void drawCustomArmourStyles();
|
||||||
|
void drawWeapons();
|
||||||
|
void drawWeaponCategory(Containers::StringView name, Containers::ArrayView<GameObjects::Weapon> weapons_view,
|
||||||
|
bool& dirty, Containers::StringView payload_type,
|
||||||
|
Containers::StringView payload_tooltip);
|
||||||
|
void drawWeaponEditor(GameObjects::Weapon& weapon);
|
||||||
|
void drawGlobalStyles();
|
||||||
|
void drawTuning();
|
||||||
|
void drawDecalEditor(GameObjects::Decal& decal);
|
||||||
|
void drawAccessoryEditor(GameObjects::Accessory& accessory,
|
||||||
|
Containers::ArrayView<GameObjects::CustomStyle> style_view);
|
||||||
|
auto getStyleName(std::int32_t id, Containers::ArrayView<GameObjects::CustomStyle> view)
|
||||||
|
-> Containers::StringView;
|
||||||
|
|
||||||
|
enum DCSResult {
|
||||||
|
DCS_Fail,
|
||||||
|
DCS_ResetStyle,
|
||||||
|
DCS_Save
|
||||||
|
};
|
||||||
|
auto drawCustomStyle(GameObjects::CustomStyle& style) -> DCSResult;
|
||||||
|
|
||||||
|
void drawAbout();
|
||||||
|
void drawGameState();
|
||||||
|
|
||||||
|
// Convenience wrappers over ImGui stuff
|
||||||
|
void drawHelpMarker(Containers::StringView text, float wrap_pos = 0.0f);
|
||||||
|
void drawTooltip(Containers::StringView text, float wrap_pos = 0.0f);
|
||||||
|
bool drawCheckbox(Containers::StringView label, bool value);
|
||||||
|
void drawVector3Drag(Containers::StringView id, Vector3& vec, float speed, Vector3 min, Vector3 max,
|
||||||
|
const char* x_format, const char* y_format, const char* z_format,
|
||||||
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
||||||
|
void drawVector3dDrag(Containers::StringView id, Vector3d& vec, float speed, Vector3d min, Vector3d max,
|
||||||
|
const char* x_format, const char* y_format, const char* z_format,
|
||||||
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
||||||
|
void drawVector3Slider(Containers::StringView id, Vector3& vec, Vector3 min, Vector3 max, const char* x_format,
|
||||||
|
const char* y_format, const char* z_format,
|
||||||
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
||||||
|
void drawVector3dSlider(Containers::StringView id, Vector3d& vec, Vector3d min, Vector3d max,
|
||||||
|
const char* x_format, const char* y_format, const char* z_format,
|
||||||
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
||||||
|
void drawVector2Slider(Containers::StringView id, Vector2& vec, Vector2 min, Vector2 max, const char* x_format,
|
||||||
|
const char* y_format, ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
||||||
|
void drawVector2dSlider(Containers::StringView id, Vector2d& vec, Vector2d min, Vector2d max,
|
||||||
|
const char* x_format, const char* y_format,
|
||||||
|
ImGuiSliderFlags_ flags = ImGuiSliderFlags_None);
|
||||||
|
|
||||||
|
template<typename Functor, typename... Args>
|
||||||
|
bool drawUnsafeWidget(Functor func, Args... args) {
|
||||||
|
GameState game_state = _gameState; // Copying the value to reduce the risk of a data race.
|
||||||
|
ImGui::BeginDisabled(game_state != GameState::NotRunning);
|
||||||
|
bool result = func(std::forward<Args>(args)...);
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
return result;
|
||||||
|
} // Obviously, should only be used with ImGui widgets that return a bool.
|
||||||
|
// Also, func should be a lambda if there are any default arguments, like ImGui::Button(), etc...
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void drawUnsafeText(const char* text, Args... args) { // Alternative to the above, for ImGui::Text*() variants.
|
||||||
|
if(_gameState != GameState::NotRunning) {
|
||||||
|
ImGui::TextDisabled(text, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImGui::Text(text, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void drawAlignedText(Containers::StringView text, Args... args) {
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text(text.data(), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void openUri(Containers::StringView uri);
|
||||||
|
|
||||||
|
void checkGameState();
|
||||||
|
|
||||||
|
void checkForUpdates();
|
||||||
|
|
||||||
|
Utility::Resource _rs{"assets"_s};
|
||||||
|
|
||||||
|
// GUI-related members
|
||||||
|
ImGuiIntegration::Context _imgui{NoCreate};
|
||||||
|
|
||||||
|
enum class UiState: uint8_t {
|
||||||
|
Disclaimer,
|
||||||
|
Initialising,
|
||||||
|
ProfileManager,
|
||||||
|
MainManager,
|
||||||
|
MassViewer
|
||||||
|
} _uiState{UiState::Disclaimer};
|
||||||
|
|
||||||
|
bool _aboutPopup = false;
|
||||||
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
|
bool _demoWindow = false;
|
||||||
|
bool _styleEditor = false;
|
||||||
|
bool _metricsWindow = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ToastQueue _queue;
|
||||||
|
|
||||||
|
std::thread _initThread;
|
||||||
|
std::thread _updateThread;
|
||||||
|
|
||||||
|
std::uint32_t _initEventId;
|
||||||
|
std::uint32_t _updateEventId;
|
||||||
|
std::uint32_t _fileEventId;
|
||||||
|
|
||||||
|
Containers::String _lastError;
|
||||||
|
|
||||||
|
enum class GameState : std::uint8_t {
|
||||||
|
Unknown, NotRunning, Running
|
||||||
|
} _gameState{GameState::Unknown};
|
||||||
|
|
||||||
|
SDL_TimerID _gameCheckTimerId = 0;
|
||||||
|
|
||||||
|
Containers::Pointer<Managers::ProfileManager> _profileManager;
|
||||||
|
GameObjects::Profile* _currentProfile = nullptr;
|
||||||
|
|
||||||
|
Containers::Pointer<Managers::BackupManager> _backupManager;
|
||||||
|
|
||||||
|
Containers::Pointer<Managers::MassManager> _massManager;
|
||||||
|
GameObjects::Mass* _currentMass = nullptr;
|
||||||
|
|
||||||
|
Containers::Pointer<Managers::StagedMassManager> _stagedMassManager;
|
||||||
|
|
||||||
|
GameObjects::Weapon* _currentWeapon = nullptr;
|
||||||
|
|
||||||
|
Containers::Pointer<efsw::FileWatcher> _fileWatcher;
|
||||||
|
enum watchID {
|
||||||
|
SaveDir = 0,
|
||||||
|
StagingDir = 1
|
||||||
|
};
|
||||||
|
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
||||||
|
|
||||||
|
Containers::Optional<UpdateChecker> _checker{Containers::NullOpt};
|
||||||
|
std::mutex _checkerMutex;
|
||||||
|
|
||||||
|
bool _modifiedBySaveTool = false;
|
||||||
|
bool _jointsDirty = false;
|
||||||
|
bool _stylesDirty = false;
|
||||||
|
bool _eyeFlareDirty = false;
|
||||||
|
bool _meleeDirty = false;
|
||||||
|
bool _shieldsDirty = false;
|
||||||
|
bool _bShootersDirty = false;
|
||||||
|
bool _eShootersDirty = false;
|
||||||
|
bool _bLaunchersDirty = false;
|
||||||
|
bool _eLaunchersDirty = false;
|
||||||
|
|
||||||
|
Containers::Optional<std::size_t> _selectedArmourSlot{Containers::NullOpt};
|
||||||
|
Containers::StaticArray<38, std::int32_t> _selectedArmourDecals{ValueInit};
|
||||||
|
Containers::StaticArray<38, std::int32_t> _selectedArmourAccessories{ValueInit};
|
||||||
|
std::uint32_t _selectedBLPlacement = 0;
|
||||||
|
std::int32_t _selectedWeaponPart = 0;
|
||||||
|
std::int32_t _selectedWeaponDecal = 0;
|
||||||
|
std::int32_t _selectedWeaponAccessory = 0;
|
||||||
|
|
||||||
|
Timeline _timeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,19 +14,23 @@
|
||||||
// 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/Utility/Format.h>
|
||||||
#include <Corrade/Utility/String.h>
|
#include <Corrade/Utility/String.h>
|
||||||
#include <Corrade/Utility/Unicode.h>
|
#include <Corrade/Utility/Unicode.h>
|
||||||
|
|
||||||
|
#include <SDL_events.h>
|
||||||
|
#include <SDL_messagebox.h>
|
||||||
|
|
||||||
#include <fileapi.h>
|
#include <fileapi.h>
|
||||||
#include <handleapi.h>
|
#include <handleapi.h>
|
||||||
|
|
||||||
#include "SaveTool.h"
|
#include "Application.h"
|
||||||
|
|
||||||
void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
namespace mbst {
|
||||||
const std::string&,
|
|
||||||
const std::string& filename,
|
void
|
||||||
efsw::Action action,
|
Application::handleFileAction(efsw::WatchID watch_id, const std::string&, const std::string& filename,
|
||||||
std::string old_filename)
|
efsw::Action action, std::string old_filename)
|
||||||
{
|
{
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
SDL_zero(event);
|
SDL_zero(event);
|
||||||
|
@ -44,7 +48,9 @@ void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
||||||
return;
|
return;
|
||||||
} // TODO: actually do something when config files will finally be handled
|
} // TODO: actually do something when config files will finally be handled
|
||||||
|
|
||||||
if(!Utility::String::endsWith(filename, _currentProfile->account() + ".sav")) {
|
if(!Utility::String::endsWith(filename, Utility::format("Profile{}.sav", _currentProfile->account()).data()) &&
|
||||||
|
filename.find("Unit") == std::string::npos)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,18 +62,20 @@ void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
||||||
SDL_PushEvent(&event);
|
SDL_PushEvent(&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
void
|
||||||
Containers::String filename{static_cast<char*>(event.user.data1), std::strlen(static_cast<char*>(event.user.data1)), nullptr};
|
Application::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) {
|
if((event.user.code & StagedUpdate) == StagedUpdate) {
|
||||||
_massManager->refreshStagedMass(filename);
|
_stagedMassManager->refreshMass(filename);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Containers::String old_filename;
|
Containers::String old_filename;
|
||||||
|
|
||||||
Int index = 0;
|
std::int32_t index = 0;
|
||||||
Int old_index = 0;
|
std::int32_t old_index = 0;
|
||||||
bool is_current_profile = filename == _currentProfile->filename();
|
bool is_current_profile = filename == _currentProfile->filename();
|
||||||
bool is_unit = filename.hasPrefix(_currentProfile->isDemo() ? "DemoUnit"_s : "Unit"_s);
|
bool is_unit = filename.hasPrefix(_currentProfile->isDemo() ? "DemoUnit"_s : "Unit"_s);
|
||||||
if(is_unit) {
|
if(is_unit) {
|
||||||
|
@ -76,7 +84,8 @@ void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(event.user.code == FileMoved) {
|
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_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_index = ((old_filename[_currentProfile->isDemo() ? 8 : 4] - 0x30) * 10) +
|
||||||
(old_filename[_currentProfile->isDemo() ? 9 : 5] - 0x30);
|
(old_filename[_currentProfile->isDemo() ? 9 : 5] - 0x30);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +105,11 @@ void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
||||||
if(is_current_profile) {
|
if(is_current_profile) {
|
||||||
_currentProfile = nullptr;
|
_currentProfile = nullptr;
|
||||||
_uiState = UiState::ProfileManager;
|
_uiState = UiState::ProfileManager;
|
||||||
_profileManager->refreshProfiles();
|
if(!_profileManager->refreshProfiles()) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
|
_profileManager->lastError().data(), window());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if(is_unit) {
|
else if(is_unit) {
|
||||||
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
|
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
|
||||||
|
@ -114,8 +127,8 @@ void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(_modifiedBySaveTool && _currentMass->filename() == filename) {
|
if(_modifiedBySaveTool && _currentMass->filename() == filename) {
|
||||||
auto handle = CreateFileW(Utility::Unicode::widen(Containers::StringView{filename}), GENERIC_READ, 0,
|
auto handle = CreateFileW(Utility::Unicode::widen(Containers::StringView{filename}),
|
||||||
nullptr, OPEN_EXISTING, 0, nullptr);
|
GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||||
if(handle && handle != INVALID_HANDLE_VALUE) {
|
if(handle && handle != INVALID_HANDLE_VALUE) {
|
||||||
CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
_modifiedBySaveTool = false;
|
_modifiedBySaveTool = false;
|
||||||
|
@ -139,3 +152,5 @@ void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
||||||
_queue.addToast(Toast::Type::Warning, "Unknown file action type"_s);
|
_queue.addToast(Toast::Type::Warning, "Unknown file action type"_s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
141
src/Application/Application_Initialisation.cpp
Normal file
141
src/Application/Application_Initialisation.cpp
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <SDL_events.h>
|
||||||
|
#include <SDL_messagebox.h>
|
||||||
|
|
||||||
|
#include "../Configuration/Configuration.h"
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
namespace mbst {
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::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
|
||||||
|
Application::initialiseConfiguration() {
|
||||||
|
LOG_INFO("Reading configuration file.");
|
||||||
|
|
||||||
|
setSwapInterval(conf().swapInterval());
|
||||||
|
setMinimalLoopPeriod(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::initialiseGui() {
|
||||||
|
LOG_INFO("Initialising Dear ImGui.");
|
||||||
|
|
||||||
|
auto ctx = ImGui::CreateContext();
|
||||||
|
auto& 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);
|
||||||
|
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(mono_font.data()), int(mono_font.size()),
|
||||||
|
18.0f * float(framebufferSize().x()) / size.x(), &font_config);
|
||||||
|
|
||||||
|
_imgui = ImGuiIntegration::Context(*ctx, Vector2{windowSize()}/dpiScaling(), windowSize(), framebufferSize());
|
||||||
|
|
||||||
|
io.IniFilename = nullptr;
|
||||||
|
|
||||||
|
auto& style = ImGui::GetStyle();
|
||||||
|
|
||||||
|
style.WindowTitleAlign = {0.5f, 0.5f};
|
||||||
|
style.FrameRounding = 3.2f;
|
||||||
|
style.Colors[ImGuiCol_WindowBg] = ImColor(0xff1f1f1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::initialiseManager() {
|
||||||
|
LOG_INFO("Initialising the profile manager.");
|
||||||
|
|
||||||
|
SDL_Event event;
|
||||||
|
SDL_zero(event);
|
||||||
|
event.type = _initEventId;
|
||||||
|
|
||||||
|
_profileManager.emplace();
|
||||||
|
if(!_profileManager->ready()) {
|
||||||
|
event.user.code = ProfileManagerFailure;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_backupManager.emplace();
|
||||||
|
|
||||||
|
_stagedMassManager.emplace();
|
||||||
|
|
||||||
|
event.user.code = InitSuccess;
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::initialiseMassManager() {
|
||||||
|
LOG_INFO("Initialising the M.A.S.S. manager.");
|
||||||
|
_massManager.emplace(_currentProfile->account(), _currentProfile->isDemo());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::initialiseFileWatcher() {
|
||||||
|
LOG_INFO("Initialising the file watcher.");
|
||||||
|
_fileWatcher.emplace();
|
||||||
|
_watchIDs[SaveDir] = _fileWatcher->addWatch(conf().directories().gameSaves, this, false);
|
||||||
|
_watchIDs[StagingDir] = _fileWatcher->addWatch(conf().directories().staging, this, false);
|
||||||
|
_fileWatcher->watch();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,23 +14,29 @@
|
||||||
// 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/Containers/ScopeGuard.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 <Magnum/ImGuiIntegration/Integration.h>
|
||||||
|
|
||||||
|
#include <SDL_messagebox.h>
|
||||||
|
|
||||||
|
#include "../Configuration/Configuration.h"
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
#include "../GameData/LastMissionId.h"
|
||||||
|
#include "../GameData/StoryProgress.h"
|
||||||
|
|
||||||
#include "../Maps/LastMissionId.h"
|
#include "Application.h"
|
||||||
#include "../Maps/StoryProgress.h"
|
|
||||||
|
|
||||||
void SaveTool::drawManager() {
|
namespace mbst {
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::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(ImVec2{Vector2{float(windowSize().x()), float(windowSize().y()) - ImGui::GetItemRectSize().y} / dpiScaling()},
|
||||||
ImGuiCond_Always);
|
ImGuiCond_Always);
|
||||||
if(!ImGui::Begin("##MainWindow", nullptr,
|
if(!ImGui::Begin("##MainWindow", nullptr,
|
||||||
ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_NoMove|
|
ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_NoMove|
|
||||||
|
@ -52,8 +58,8 @@ 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))
|
ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar))
|
||||||
{
|
{
|
||||||
if(ImGui::BeginMenuBar()) {
|
if(ImGui::BeginMenuBar()) {
|
||||||
ImGui::TextUnformatted("Profile information");
|
ImGui::TextUnformatted("Profile information");
|
||||||
|
@ -80,7 +86,7 @@ void SaveTool::drawManager() {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
if(ImGui::BeginChild("##MASSManager", {0.0f, 0.0f},
|
if(ImGui::BeginChild("##MASSManager", {0.0f, 0.0f},
|
||||||
true, ImGuiWindowFlags_MenuBar))
|
ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar))
|
||||||
{
|
{
|
||||||
if(ImGui::BeginMenuBar()) {
|
if(ImGui::BeginMenuBar()) {
|
||||||
ImGui::TextUnformatted("M.A.S.S. management");
|
ImGui::TextUnformatted("M.A.S.S. management");
|
||||||
|
@ -95,7 +101,8 @@ void SaveTool::drawManager() {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SaveTool::drawIntEditPopup(int* value_to_edit, int max) -> bool {
|
bool
|
||||||
|
Application::drawIntEditPopup(int* value_to_edit, int max) {
|
||||||
bool apply = false;
|
bool apply = false;
|
||||||
if(ImGui::BeginPopup("int_edit")) {
|
if(ImGui::BeginPopup("int_edit")) {
|
||||||
ImGui::Text("Please enter a value between 0 and %i:", max);
|
ImGui::Text("Please enter a value between 0 and %i:", max);
|
||||||
|
@ -104,7 +111,7 @@ auto SaveTool::drawIntEditPopup(int* value_to_edit, int max) -> bool {
|
||||||
drawHelpMarker("You can either drag the widget left or right to change the value,\n"
|
drawHelpMarker("You can either drag the widget left or right to change the value,\n"
|
||||||
"or click on it while holding Ctrl to edit the value directly.");
|
"or click on it while holding Ctrl to edit the value directly.");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
drawUnsafeWidget([](auto... args){ return ImGui::SliderInt("", args...); },
|
drawUnsafeWidget([](auto... args){ return ImGui::SliderInt("##IntSlider", args...); },
|
||||||
value_to_edit, 0, max, "%d", ImGuiSliderFlags_AlwaysClamp);
|
value_to_edit, 0, max, "%d", ImGuiSliderFlags_AlwaysClamp);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(drawUnsafeWidget([]{ return ImGui::Button("Apply"); })) {
|
if(drawUnsafeWidget([]{ return ImGui::Button("Apply"); })) {
|
||||||
|
@ -118,7 +125,8 @@ auto SaveTool::drawIntEditPopup(int* value_to_edit, int max) -> bool {
|
||||||
return apply;
|
return apply;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
|
bool
|
||||||
|
Application::drawRenamePopup(Containers::ArrayView<char> name_view) {
|
||||||
bool apply = false;
|
bool apply = false;
|
||||||
if(ImGui::BeginPopup("name_edit")) {
|
if(ImGui::BeginPopup("name_edit")) {
|
||||||
ImGui::TextUnformatted("Please enter a new name. Conditions:");
|
ImGui::TextUnformatted("Please enter a new name. Conditions:");
|
||||||
|
@ -134,19 +142,21 @@ auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
|
||||||
(name_view[0] != ' ' && name_view[len - 1] != ' ') ? ICON_FA_CHECK : ICON_FA_TIMES);
|
(name_view[0] != ' ' && name_view[len - 1] != ' ') ? ICON_FA_CHECK : ICON_FA_TIMES);
|
||||||
|
|
||||||
static auto callback = [](ImGuiInputTextCallbackData* data)->int {
|
static auto callback = [](ImGuiInputTextCallbackData* data)->int {
|
||||||
if(data->EventChar < 256 && std::strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789- ", char(data->EventChar))) {
|
if(data->EventChar < 256 &&
|
||||||
|
std::strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789- ", char(data->EventChar)))
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
drawUnsafeWidget([](auto... args){ return ImGui::InputText("", args...); },
|
drawUnsafeWidget([](auto... args){ return ImGui::InputText("##NameField", args...); },
|
||||||
name_view.data(), name_view.size(),
|
name_view.data(), name_view.size(),
|
||||||
ImGuiInputTextFlags_CallbackCharFilter,
|
ImGuiInputTextFlags_CallbackCharFilter,
|
||||||
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] != ' '))
|
||||||
{
|
{
|
||||||
|
@ -158,7 +168,7 @@ 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] != ' '))
|
||||||
{
|
{
|
||||||
|
@ -170,16 +180,17 @@ auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
|
||||||
return apply;
|
return apply;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawGeneralInfo() {
|
void
|
||||||
|
Application::drawGeneralInfo() {
|
||||||
if(!_currentProfile) {
|
if(!_currentProfile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Text("Credits: %i", _currentProfile->credits());
|
ImGui::Text("Credits: %i", _currentProfile->credits());
|
||||||
|
|
||||||
auto it = std::find_if(story_progress.begin(), story_progress.end(),
|
auto it = std::find_if(GameData::story_progress.begin(), GameData::story_progress.end(),
|
||||||
[this](const StoryProgressPoint& p){ return p.id == _currentProfile->storyProgress(); });
|
[this](const GameData::StoryProgressPoint& p){ return p.id == _currentProfile->storyProgress(); });
|
||||||
if(it != story_progress.end())
|
if(it != GameData::story_progress.end())
|
||||||
{
|
{
|
||||||
ImGui::TextUnformatted("Story progress:");
|
ImGui::TextUnformatted("Story progress:");
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.x / 4.0f);
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.x / 4.0f);
|
||||||
|
@ -194,8 +205,8 @@ void SaveTool::drawGeneralInfo() {
|
||||||
ImGui::Text("Story progress: 0x%x", _currentProfile->storyProgress());
|
ImGui::Text("Story progress: 0x%x", _currentProfile->storyProgress());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mission_id_map.find(_currentProfile->lastMissionId()) != mission_id_map.cend()) {
|
if(GameData::mission_id_map.find(_currentProfile->lastMissionId()) != GameData::mission_id_map.cend()) {
|
||||||
ImGui::Text("Last mission: %s", mission_id_map.at(_currentProfile->lastMissionId()).data());
|
ImGui::Text("Last mission: %s", GameData::mission_id_map.at(_currentProfile->lastMissionId()).data());
|
||||||
}
|
}
|
||||||
else if(_currentProfile->lastMissionId() == -1) {
|
else if(_currentProfile->lastMissionId() == -1) {
|
||||||
ImGui::TextUnformatted("Last mission: none");
|
ImGui::TextUnformatted("Last mission: none");
|
||||||
|
@ -204,9 +215,9 @@ 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});
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
@ -225,13 +236,13 @@ void SaveTool::drawGeneralInfo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!_cheatMode) {
|
if(!conf().cheatMode()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
static Int credits;
|
static std::int32_t credits;
|
||||||
if(drawUnsafeWidget([]{ return ImGui::Button("Edit credits"); })) {
|
if(drawUnsafeWidget([]{ return ImGui::Button("Edit credits"); })) {
|
||||||
credits = _currentProfile->credits();
|
credits = _currentProfile->credits();
|
||||||
ImGui::OpenPopup("int_edit");
|
ImGui::OpenPopup("int_edit");
|
||||||
|
@ -249,10 +260,10 @@ 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 : GameData::story_progress) {
|
||||||
if(ImGui::BeginMenu(sp.chapter.data())) {
|
if(ImGui::BeginMenu(sp.chapter.data())) {
|
||||||
if(!sp.after) {
|
if(!sp.after) {
|
||||||
if(ImGui::MenuItem(sp.point.data())) {
|
if(ImGui::MenuItem(sp.point.data())) {
|
||||||
|
@ -278,7 +289,8 @@ void SaveTool::drawGeneralInfo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawResearchInventory() {
|
void
|
||||||
|
Application::drawResearchInventory() {
|
||||||
if(!_currentProfile) {
|
if(!_currentProfile) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -293,148 +305,90 @@ void SaveTool::drawResearchInventory() {
|
||||||
|
|
||||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
ImGui::Text("Engine materials");
|
ImGui::TextUnformatted("Engine materials");
|
||||||
|
|
||||||
drawMaterialRow("Verse steel", 1,
|
drawMaterialRow("Verse steel", 1, GameData::MaterialID::VerseSteel);
|
||||||
[this]{ return _currentProfile->verseSteel(); },
|
drawMaterialRow("Undinium", 2, GameData::MaterialID::Undinium);
|
||||||
[this](Int amount){ return _currentProfile->setVerseSteel(amount); });
|
drawMaterialRow("Necrium alloy", 3, GameData::MaterialID::NecriumAlloy);
|
||||||
drawMaterialRow("Undinium", 2,
|
drawMaterialRow("Lunarite", 4, GameData::MaterialID::Lunarite);
|
||||||
[this]{ return _currentProfile->undinium(); },
|
drawMaterialRow("Asterite", 5, GameData::MaterialID::Asterite);
|
||||||
[this](Int amount){ return _currentProfile->setUndinium(amount); });
|
drawMaterialRow("Hallite fragma", 6, GameData::MaterialID::HalliteFragma);
|
||||||
drawMaterialRow("Necrium alloy", 3,
|
drawMaterialRow("Unnoctinium", 7, GameData::MaterialID::Unnoctinium);
|
||||||
[this]{ return _currentProfile->necriumAlloy(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setNecriumAlloy(amount); });
|
|
||||||
drawMaterialRow("Lunarite", 4,
|
|
||||||
[this]{ return _currentProfile->lunarite(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setLunarite(amount); });
|
|
||||||
drawMaterialRow("Asterite", 5,
|
|
||||||
[this]{ return _currentProfile->asterite(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setAsterite(amount); });
|
|
||||||
drawUnavailableMaterialRow("Hallite fragma", 6);
|
|
||||||
drawUnavailableMaterialRow("Unnoctinium", 7);
|
|
||||||
|
|
||||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
ImGui::Text("OS materials");
|
ImGui::TextUnformatted("OS materials");
|
||||||
|
|
||||||
drawMaterialRow("Ednil", 1,
|
drawMaterialRow("Ednil", 1, GameData::MaterialID::Ednil);
|
||||||
[this]{ return _currentProfile->ednil(); },
|
drawMaterialRow("Nuflalt", 2, GameData::MaterialID::Nuflalt);
|
||||||
[this](Int amount){ return _currentProfile->setEdnil(amount); });
|
drawMaterialRow("Aurelene", 3, GameData::MaterialID::Aurelene);
|
||||||
drawMaterialRow("Nuflalt", 2,
|
drawMaterialRow("Soldus", 4, GameData::MaterialID::Soldus);
|
||||||
[this]{ return _currentProfile->nuflalt(); },
|
drawMaterialRow("Synthesized N", 5, GameData::MaterialID::SynthesisedN);
|
||||||
[this](Int amount){ return _currentProfile->setNuflalt(amount); });
|
drawMaterialRow("Nanoc", 6, GameData::MaterialID::Nanoc);
|
||||||
drawMaterialRow("Aurelene", 3,
|
drawMaterialRow("Abyssillite", 7, GameData::MaterialID::Abyssillite);
|
||||||
[this]{ return _currentProfile->aurelene(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setAurelene(amount); });
|
|
||||||
drawMaterialRow("Soldus", 4,
|
|
||||||
[this]{ return _currentProfile->soldus(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setSoldus(amount); });
|
|
||||||
drawMaterialRow("Synthesized N", 5,
|
|
||||||
[this]{ return _currentProfile->synthesisedN(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setSynthesisedN(amount); });
|
|
||||||
drawUnavailableMaterialRow("Nanoc", 6);
|
|
||||||
drawUnavailableMaterialRow("Abyssillite", 7);
|
|
||||||
|
|
||||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
ImGui::Text("Architect materials");
|
ImGui::TextUnformatted("Architect materials");
|
||||||
|
|
||||||
drawMaterialRow("Alcarbonite", 1,
|
drawMaterialRow("Alcarbonite", 1, GameData::MaterialID::Alcarbonite);
|
||||||
[this]{ return _currentProfile->alcarbonite(); },
|
drawMaterialRow("Keriphene", 2, GameData::MaterialID::Keriphene);
|
||||||
[this](Int amount){ return _currentProfile->setAlcarbonite(amount); });
|
drawMaterialRow("Nitinol-CM", 3, GameData::MaterialID::NitinolCM);
|
||||||
drawMaterialRow("Keripehene", 2,
|
drawMaterialRow("Quarkium", 4, GameData::MaterialID::Quarkium);
|
||||||
[this]{ return _currentProfile->keriphene(); },
|
drawMaterialRow("Alterene", 5, GameData::MaterialID::Alterene);
|
||||||
[this](Int amount){ return _currentProfile->setKeriphene(amount); });
|
drawMaterialRow("Cosmium", 6, GameData::MaterialID::Cosmium);
|
||||||
drawMaterialRow("Nitinol-CM", 3,
|
drawMaterialRow("Purified quarkium", 7, GameData::MaterialID::PurifiedQuarkium);
|
||||||
[this]{ return _currentProfile->nitinolCM(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setNitinolCM(amount); });
|
|
||||||
drawMaterialRow("Quarkium", 4,
|
|
||||||
[this]{ return _currentProfile->quarkium(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setQuarkium(amount); });
|
|
||||||
drawMaterialRow("Alterene", 5,
|
|
||||||
[this]{ return _currentProfile->alterene(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setAlterene(amount); });
|
|
||||||
drawUnavailableMaterialRow("Cosmium", 6);
|
|
||||||
drawUnavailableMaterialRow("Purified quarkium", 7);
|
|
||||||
|
|
||||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
ImGui::Text("Quark data");
|
ImGui::TextUnformatted("Quark data");
|
||||||
|
|
||||||
drawMaterialRow("Mixed composition", 1,
|
drawMaterialRow("Mixed composition", 1, GameData::MaterialID::MixedComposition);
|
||||||
[this]{ return _currentProfile->mixedComposition(); },
|
drawMaterialRow("Void residue", 2, GameData::MaterialID::VoidResidue);
|
||||||
[this](Int amount){ return _currentProfile->setMixedComposition(amount); });
|
drawMaterialRow("Muscular construction", 3, GameData::MaterialID::MuscularConstruction);
|
||||||
drawMaterialRow("Void residue", 2,
|
drawMaterialRow("Mineral exoskeletology", 4, GameData::MaterialID::MineralExoskeletology);
|
||||||
[this]{ return _currentProfile->voidResidue(); },
|
drawMaterialRow("Carbonized skin", 5, GameData::MaterialID::CarbonisedSkin);
|
||||||
[this](Int amount){ return _currentProfile->setVoidResidue(amount); });
|
drawMaterialRow("Isolated void particle", 6, GameData::MaterialID::IsolatedVoidParticle);
|
||||||
drawMaterialRow("Muscular construction", 3,
|
drawMaterialRow("Weaponised physiology", 7, GameData::MaterialID::WeaponisedPhysiology);
|
||||||
[this]{ return _currentProfile->muscularConstruction(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setMuscularConstruction(amount); });
|
|
||||||
drawMaterialRow("Mineral exoskeletology", 4,
|
|
||||||
[this]{ return _currentProfile->mineralExoskeletology(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setMineralExoskeletology(amount); });
|
|
||||||
drawMaterialRow("Carbonized skin", 5,
|
|
||||||
[this]{ return _currentProfile->carbonisedSkin(); },
|
|
||||||
[this](Int amount){ return _currentProfile->setCarbonisedSkin(amount); });
|
|
||||||
drawUnavailableMaterialRow("Isolated void particle", 6);
|
|
||||||
drawUnavailableMaterialRow("Weaponised physiology", 7);
|
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Getter, typename Setter>
|
void
|
||||||
void SaveTool::drawMaterialRow(Containers::StringView name, Int tier, Getter getter, Setter setter) {
|
Application::drawMaterialRow(Containers::StringView name, std::int32_t tier, GameData::MaterialID id) {
|
||||||
static_assert(std::is_same<decltype(getter()), Int>::value, "getter doesn't return an Int, and/or doesn't take zero arguments.");
|
|
||||||
static_assert(std::is_same<decltype(setter(0)), bool>::value, "setter doesn't return a bool, and/or doesn't take a single Int as an argument.");
|
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableSetColumnIndex(0);
|
ImGui::TableSetColumnIndex(0);
|
||||||
ImGui::Text("T%i", tier);
|
ImGui::Text("T%i", tier);
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
ImGui::TextUnformatted(name.data());
|
ImGui::TextUnformatted(name.cbegin(), name.cend());
|
||||||
ImGui::TableSetColumnIndex(2);
|
ImGui::TableSetColumnIndex(2);
|
||||||
if(getter() != -1) {
|
ImGui::Text("%i", _currentProfile->material(id));
|
||||||
ImGui::Text("%i", getter());
|
if(conf().cheatMode()) {
|
||||||
if(_cheatMode) {
|
|
||||||
ImGui::TableSetColumnIndex(3);
|
ImGui::TableSetColumnIndex(3);
|
||||||
ImGui::PushID(name.data());
|
ImGui::PushID(name.data());
|
||||||
static Int var = 0;
|
static std::int32_t var = 0;
|
||||||
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_EDIT)) {
|
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_EDIT)) {
|
||||||
(var) = getter();
|
var = _currentProfile->material(id);
|
||||||
ImGui::OpenPopup("int_edit");
|
ImGui::OpenPopup("int_edit");
|
||||||
}
|
}
|
||||||
drawTooltip("Edit");
|
drawTooltip("Edit");
|
||||||
if(drawIntEditPopup(&(var), 9999)) {
|
if(drawIntEditPopup(&var, 9999)) {
|
||||||
if(!setter(var)) {
|
if(!_currentProfile->setMaterial(id, var)) {
|
||||||
_queue.addToast(Toast::Type::Error, _currentProfile->lastError());
|
_queue.addToast(Toast::Type::Error, _currentProfile->lastError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImGui::TextDisabled("Not found in the save file");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawUnavailableMaterialRow(Containers::StringView name, Int tier) {
|
void
|
||||||
ImGui::TableNextRow();
|
Application::drawMassManager() {
|
||||||
ImGui::TableSetColumnIndex(0);
|
|
||||||
ImGui::Text("T%i", tier);
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
|
||||||
ImGui::TextUnformatted(name.data());
|
|
||||||
ImGui::TableSetColumnIndex(2);
|
|
||||||
ImGui::TextDisabled("Unavailable as of game version " SUPPORTED_GAME_VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveTool::drawMassManager() {
|
|
||||||
if(!_massManager) {
|
if(!_massManager) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mass_to_delete = 0;
|
static int mass_to_delete = 0;
|
||||||
static ImGuiID mass_deletion_popup_ID = drawDeleteMassPopup(mass_to_delete);
|
|
||||||
|
|
||||||
if(ImGui::BeginTable("##HangarsTable", 4,
|
if(ImGui::BeginTable("##HangarsTable", 4,
|
||||||
ImGuiTableFlags_BordersOuter|ImGuiTableFlags_RowBg|ImGuiTableFlags_ScrollY,
|
ImGuiTableFlags_BordersOuter|ImGuiTableFlags_RowBg|ImGuiTableFlags_ScrollY,
|
||||||
|
@ -463,7 +417,7 @@ void SaveTool::drawMassManager() {
|
||||||
ImGui::TableSetColumnIndex(0);
|
ImGui::TableSetColumnIndex(0);
|
||||||
ImGui::Selectable(Utility::format("{:.2d}", i + 1).data(),
|
ImGui::Selectable(Utility::format("{:.2d}", i + 1).data(),
|
||||||
false, ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_AllowItemOverlap);
|
false, ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_AllowItemOverlap);
|
||||||
if(_massManager->hangar(i).state() == Mass::State::Valid &&
|
if(_massManager->hangar(i).state() == GameObjects::Mass::State::Valid &&
|
||||||
ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoHoldToOpenOthers))
|
ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoHoldToOpenOthers))
|
||||||
{
|
{
|
||||||
drag_drop_index = i;
|
drag_drop_index = i;
|
||||||
|
@ -473,25 +427,25 @@ 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",
|
||||||
"payload->DataSize != sizeof(Containers::String) in SaveTool::drawMassManager()",
|
"payload->DataSize != sizeof(Containers::String) in Application::drawMassManager()",
|
||||||
window());
|
window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Containers::StringView file = *static_cast<Containers::String*>(payload->Data);
|
Containers::StringView file = *static_cast<Containers::String*>(payload->Data);
|
||||||
|
|
||||||
if(!_massManager->importMass(file, i)) {
|
if(!_stagedMassManager->import(file, i, _currentProfile->account(), _currentProfile->isDemo())) {
|
||||||
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if((payload = ImGui::AcceptDragDropPayload("Mass"))) {
|
else if((payload = ImGui::AcceptDragDropPayload("Mass"))) {
|
||||||
if(payload->DataSize != sizeof(int)) {
|
if(payload->DataSize != sizeof(int)) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
||||||
"payload->DataSize != sizeof(int) in SaveTool::drawMassManager()",
|
"payload->DataSize != sizeof(int) in Application::drawMassManager()",
|
||||||
window());
|
window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -508,14 +462,15 @@ void SaveTool::drawMassManager() {
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
switch(_massManager->hangar(i).state()) {
|
switch(_massManager->hangar(i).state()) {
|
||||||
case Mass::State::Empty:
|
case GameObjects::Mass::State::Empty:
|
||||||
ImGui::TextDisabled("<empty>");
|
ImGui::TextDisabled("<empty>");
|
||||||
break;
|
break;
|
||||||
case Mass::State::Invalid:
|
case GameObjects::Mass::State::Invalid:
|
||||||
ImGui::TextDisabled("<invalid>");
|
ImGui::TextDisabled("<invalid>");
|
||||||
break;
|
break;
|
||||||
case Mass::State::Valid:
|
case GameObjects::Mass::State::Valid:
|
||||||
ImGui::TextUnformatted(_massManager->hangar(i).name().data());
|
ImGui::TextUnformatted(_massManager->hangar(i).name().cbegin(),
|
||||||
|
_massManager->hangar(i).name().cend());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,10 +480,10 @@ void SaveTool::drawMassManager() {
|
||||||
drawTooltip("This is the currently active frame slot.");
|
drawTooltip("This is the currently active frame slot.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_massManager->hangar(i).state() != Mass::State::Empty) {
|
if(_massManager->hangar(i).state() != GameObjects::Mass::State::Empty) {
|
||||||
ImGui::TableSetColumnIndex(3);
|
ImGui::TableSetColumnIndex(3);
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(i);
|
||||||
if(_massManager->hangar(i).state() == Mass::State::Valid) {
|
if(_massManager->hangar(i).state() == GameObjects::Mass::State::Valid) {
|
||||||
if(ImGui::SmallButton(ICON_FA_SEARCH)) {
|
if(ImGui::SmallButton(ICON_FA_SEARCH)) {
|
||||||
_currentMass = &_massManager->hangar(i);
|
_currentMass = &_massManager->hangar(i);
|
||||||
_uiState = UiState::MassViewer;
|
_uiState = UiState::MassViewer;
|
||||||
|
@ -543,9 +498,10 @@ void SaveTool::drawMassManager() {
|
||||||
ImGui::SameLine(0.0f, 2.0f);
|
ImGui::SameLine(0.0f, 2.0f);
|
||||||
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) {
|
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) {
|
||||||
mass_to_delete = i;
|
mass_to_delete = i;
|
||||||
ImGui::OpenPopup(mass_deletion_popup_ID);
|
ImGui::OpenPopup("Confirmation##DeleteMassConfirmation");
|
||||||
}
|
}
|
||||||
drawTooltip("Delete");
|
drawTooltip("Delete");
|
||||||
|
drawDeleteMassPopup(mass_to_delete);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -555,7 +511,6 @@ void SaveTool::drawMassManager() {
|
||||||
|
|
||||||
drawDeleteMassPopup(mass_to_delete);
|
drawDeleteMassPopup(mass_to_delete);
|
||||||
|
|
||||||
static ImGuiID staged_mass_deletion_popup_ID = drawDeleteStagedMassPopup("");
|
|
||||||
static Containers::StringView staged_mass_to_delete;
|
static Containers::StringView staged_mass_to_delete;
|
||||||
|
|
||||||
if(ImGui::BeginTable("##StagingArea", 2,
|
if(ImGui::BeginTable("##StagingArea", 2,
|
||||||
|
@ -572,32 +527,33 @@ void SaveTool::drawMassManager() {
|
||||||
ImGui::TextUnformatted("Staging area");
|
ImGui::TextUnformatted("Staging area");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::SmallButton(ICON_FA_FOLDER_OPEN " Open staging folder")) {
|
if(ImGui::SmallButton(ICON_FA_FOLDER_OPEN " Open staging folder")) {
|
||||||
openUri(Utility::Path::toNativeSeparators(_stagingDir));
|
openUri(Utility::Path::toNativeSeparators(conf().directories().staging));
|
||||||
}
|
}
|
||||||
|
|
||||||
for(const auto& pair : _massManager->stagedMasses()) {
|
for(const auto& mass : _stagedMassManager->stagedMasses()) {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableSetColumnIndex(0);
|
ImGui::TableSetColumnIndex(0);
|
||||||
Containers::String staged_formatted = Utility::format("{} ({})", pair.second, pair.first);
|
Containers::String staged_formatted = Utility::format("{} ({})", mass.name, mass.filename);
|
||||||
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)) {
|
||||||
ImGui::SetDragDropPayload("StagedMass", &(pair.first), sizeof(Containers::String));
|
ImGui::SetDragDropPayload("StagedMass", &(mass.filename), sizeof(Containers::String));
|
||||||
|
|
||||||
ImGui::Text("%s - Staged", pair.second.data());
|
ImGui::Text("%s - Staged", mass.name.cbegin());
|
||||||
|
|
||||||
ImGui::EndDragDropSource();
|
ImGui::EndDragDropSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
ImGui::PushID(pair.first.data());
|
ImGui::PushID(mass.filename.data());
|
||||||
if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) {
|
if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) {
|
||||||
staged_mass_to_delete = pair.first;
|
staged_mass_to_delete = mass.filename;
|
||||||
ImGui::OpenPopup(staged_mass_deletion_popup_ID);
|
ImGui::OpenPopup("Confirmation##DeleteStagedMassConfirmation");
|
||||||
}
|
}
|
||||||
drawTooltip("Delete");
|
drawTooltip("Delete");
|
||||||
|
drawDeleteStagedMassPopup(staged_mass_to_delete);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,7 +563,7 @@ void SaveTool::drawMassManager() {
|
||||||
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("Mass")) {
|
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("Mass")) {
|
||||||
if(payload->DataSize != sizeof(int)) {
|
if(payload->DataSize != sizeof(int)) {
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
||||||
"payload->DataSize != sizeof(int) in SaveTool::drawMassManager()",
|
"payload->DataSize != sizeof(int) in Application::drawMassManager()",
|
||||||
window());
|
window());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -625,27 +581,28 @@ void SaveTool::drawMassManager() {
|
||||||
drawDeleteStagedMassPopup(staged_mass_to_delete);
|
drawDeleteStagedMassPopup(staged_mass_to_delete);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID {
|
void
|
||||||
|
Application::drawDeleteMassPopup(int mass_index) {
|
||||||
if(!ImGui::BeginPopupModal("Confirmation##DeleteMassConfirmation", nullptr,
|
if(!ImGui::BeginPopupModal("Confirmation##DeleteMassConfirmation", nullptr,
|
||||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
||||||
{
|
{
|
||||||
return ImGui::GetID("Confirmation##DeleteMassConfirmation");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_massManager->hangar(mass_index).state() == Mass::State::Empty) {
|
Containers::ScopeGuard guard{ImGui::EndPopup};
|
||||||
|
|
||||||
|
if(_massManager->hangar(mass_index).state() == GameObjects::Mass::State::Empty) {
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
ImGui::EndPopup();
|
return;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_gameState != GameState::NotRunning) {
|
if(_gameState != GameState::NotRunning) {
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
ImGui::EndPopup();
|
return;
|
||||||
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() == GameObjects::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);
|
||||||
}
|
}
|
||||||
|
@ -675,22 +632,19 @@ auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID {
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SaveTool::drawDeleteStagedMassPopup(Containers::StringView filename) -> ImGuiID {
|
void
|
||||||
|
Application::drawDeleteStagedMassPopup(Containers::StringView filename) {
|
||||||
if(!ImGui::BeginPopupModal("Confirmation##DeleteStagedMassConfirmation", nullptr,
|
if(!ImGui::BeginPopupModal("Confirmation##DeleteStagedMassConfirmation", nullptr,
|
||||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
||||||
{
|
{
|
||||||
return ImGui::GetID("Confirmation##DeleteStagedMassConfirmation");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
_stagedMassManager->at(filename).filename.cbegin());
|
||||||
ImGui::PopTextWrapPos();
|
ImGui::PopTextWrapPos();
|
||||||
|
|
||||||
if(ImGui::BeginTable("##DeleteStagedMassLayout", 2)) {
|
if(ImGui::BeginTable("##DeleteStagedMassLayout", 2)) {
|
||||||
|
@ -701,8 +655,9 @@ auto SaveTool::drawDeleteStagedMassPopup(Containers::StringView filename) -> ImG
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
if(ImGui::Button("Yes")) {
|
if(ImGui::Button("Yes")) {
|
||||||
if(!_massManager->deleteStagedMass(filename)) {
|
if(!_stagedMassManager->remove(filename)) {
|
||||||
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
_queue.addToast(Toast::Type::Error,
|
||||||
|
"Couldn't delete the staged M.A.S.S. at " + filename + ": " + _stagedMassManager->lastError());
|
||||||
}
|
}
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
@ -715,6 +670,6 @@ auto SaveTool::drawDeleteStagedMassPopup(Containers::StringView filename) -> ImG
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -15,19 +15,26 @@
|
||||||
// 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 "../Maps/Accessories.h"
|
#include <imgui_internal.h>
|
||||||
#define STYLENAMES_DEFINITION
|
|
||||||
#include "../Maps/StyleNames.h"
|
|
||||||
|
|
||||||
|
#include "../Configuration/Configuration.h"
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
#include "../GameData/Accessories.h"
|
||||||
|
#define STYLENAMES_DEFINITION
|
||||||
|
#include "../GameData/StyleNames.h"
|
||||||
|
#include "../ImportExport/Export.h"
|
||||||
|
|
||||||
#include "SaveTool.h"
|
#include "Application.h"
|
||||||
|
|
||||||
void SaveTool::drawMassViewer() {
|
namespace mbst {
|
||||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
|
||||||
|
void
|
||||||
|
Application::drawMassViewer() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
_currentMass = nullptr;
|
_currentMass = nullptr;
|
||||||
_currentWeapon = nullptr;
|
_currentWeapon = nullptr;
|
||||||
_uiState = UiState::MainManager;
|
_uiState = UiState::MainManager;
|
||||||
|
@ -36,7 +43,7 @@ void SaveTool::drawMassViewer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
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(ImVec2{Vector2{float(windowSize().x()), float(windowSize().y()) - ImGui::GetItemRectSize().y} / dpiScaling()},
|
||||||
ImGuiCond_Always);
|
ImGuiCond_Always);
|
||||||
if(!ImGui::Begin("##MassViewer", nullptr,
|
if(!ImGui::Begin("##MassViewer", nullptr,
|
||||||
ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_NoMove|
|
ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_NoMove|
|
||||||
|
@ -48,7 +55,7 @@ void SaveTool::drawMassViewer() {
|
||||||
|
|
||||||
if(ImGui::BeginChild("##MassInfo",
|
if(ImGui::BeginChild("##MassInfo",
|
||||||
{0.0f, 0.0f},
|
{0.0f, 0.0f},
|
||||||
true, ImGuiWindowFlags_MenuBar))
|
ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar))
|
||||||
{
|
{
|
||||||
if(ImGui::BeginMenuBar()) {
|
if(ImGui::BeginMenuBar()) {
|
||||||
if(ImGui::BeginTable("##MassViewerMenuTable", 4)) {
|
if(ImGui::BeginTable("##MassViewerMenuTable", 4)) {
|
||||||
|
@ -84,13 +91,14 @@ void SaveTool::drawMassViewer() {
|
||||||
_jointsDirty = false;
|
_jointsDirty = false;
|
||||||
_stylesDirty = false;
|
_stylesDirty = false;
|
||||||
_eyeFlareDirty = false;
|
_eyeFlareDirty = false;
|
||||||
_selectedArmourDecals = Containers::StaticArray<38, Int>{ValueInit};
|
_selectedArmourSlot = Containers::NullOpt;
|
||||||
_selectedArmourAccessories = Containers::StaticArray<38, Int>{ValueInit};
|
_selectedArmourDecals = Containers::StaticArray<38, std::int32_t>{ValueInit};
|
||||||
|
_selectedArmourAccessories = Containers::StaticArray<38, std::int32_t>{ValueInit};
|
||||||
_selectedBLPlacement = 0;
|
_selectedBLPlacement = 0;
|
||||||
_selectedWeaponPart = 0;
|
_selectedWeaponPart = 0;
|
||||||
_selectedWeaponDecal = 0;
|
_selectedWeaponDecal = 0;
|
||||||
_selectedWeaponAccessory = 0;
|
_selectedWeaponAccessory = 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
@ -122,6 +130,13 @@ void SaveTool::drawMassViewer() {
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_currentMass->bulletLauncherAttachmentStyle() != GameObjects::BulletLauncherAttachmentStyle::NotFound &&
|
||||||
|
ImGui::BeginTabItem("Bullet launcher attachment"))
|
||||||
|
{
|
||||||
|
drawBLAttachment();
|
||||||
|
ImGui::EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
if(ImGui::BeginTabItem("Custom armour styles")) {
|
if(ImGui::BeginTabItem("Custom armour styles")) {
|
||||||
drawCustomArmourStyles();
|
drawCustomArmourStyles();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
|
@ -132,7 +147,7 @@ void SaveTool::drawMassViewer() {
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_currentMass->globalStyles().size() != 0 && ImGui::BeginTabItem("Global styles")) {
|
if(!_currentMass->globalStyles().isEmpty() && ImGui::BeginTabItem("Global styles")) {
|
||||||
drawGlobalStyles();
|
drawGlobalStyles();
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
|
@ -153,8 +168,9 @@ void SaveTool::drawMassViewer() {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawGlobalStyles() {
|
void
|
||||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
Application::drawGlobalStyles() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,10 +181,9 @@ 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(std::uint32_t i = 0; i < _currentMass->globalStyles().size(); i++) {
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(int(i));
|
||||||
DCSResult result;
|
auto result = drawCustomStyle(_currentMass->globalStyles()[i]);
|
||||||
result = drawCustomStyle(_currentMass->globalStyles()[i]);
|
|
||||||
switch(result) {
|
switch(result) {
|
||||||
case DCS_ResetStyle:
|
case DCS_ResetStyle:
|
||||||
_currentMass->getGlobalStyles();
|
_currentMass->getGlobalStyles();
|
||||||
|
@ -189,8 +204,9 @@ void SaveTool::drawGlobalStyles() {
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawTuning() {
|
void
|
||||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
Application::drawTuning() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +237,7 @@ void SaveTool::drawTuning() {
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::TextUnformatted("Gears");
|
ImGui::TextUnformatted("Gears");
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < _currentMass->gears().size(); i++) {
|
for(std::uint32_t i = 0; i < _currentMass->gears().size(); i++) {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Text("%i", _currentMass->gears()[i]);
|
ImGui::Text("%i", _currentMass->gears()[i]);
|
||||||
|
@ -247,7 +263,7 @@ void SaveTool::drawTuning() {
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::TextUnformatted("Modules");
|
ImGui::TextUnformatted("Modules");
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < _currentMass->modules().size(); i++) {
|
for(std::uint32_t i = 0; i < _currentMass->modules().size(); i++) {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Text("%i", _currentMass->modules()[i]);
|
ImGui::Text("%i", _currentMass->modules()[i]);
|
||||||
|
@ -273,7 +289,7 @@ void SaveTool::drawTuning() {
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::TextUnformatted("Techs");
|
ImGui::TextUnformatted("Techs");
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < _currentMass->techs().size(); i++) {
|
for(std::uint32_t i = 0; i < _currentMass->techs().size(); i++) {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Text("%i", _currentMass->techs()[i]);
|
ImGui::Text("%i", _currentMass->techs()[i]);
|
||||||
|
@ -285,8 +301,9 @@ void SaveTool::drawTuning() {
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
|
Application::DCSResult
|
||||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
Application::drawCustomStyle(GameObjects::CustomStyle& style) {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
return DCS_Fail;
|
return DCS_Fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,13 +313,15 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
|
||||||
|
|
||||||
DCSResult return_value = DCS_Fail;
|
DCSResult return_value = DCS_Fail;
|
||||||
|
|
||||||
if(!ImGui::BeginChild("##CustomStyle", {0.0f, 244.0f}, true, ImGuiWindowFlags_MenuBar)) {
|
if(!ImGui::BeginChild("##CustomStyle", {}, ImGuiChildFlags_Border|ImGuiChildFlags_AutoResizeY,
|
||||||
|
ImGuiWindowFlags_MenuBar))
|
||||||
|
{
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
return DCS_Fail;
|
return DCS_Fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::BeginMenuBar()) {
|
if(ImGui::BeginMenuBar()) {
|
||||||
ImGui::TextUnformatted(style.name.data());
|
ImGui::TextUnformatted(style.name.cbegin(), style.name.cend());
|
||||||
|
|
||||||
static Containers::StaticArray<33, char> name_buf{ValueInit};
|
static Containers::StaticArray<33, char> name_buf{ValueInit};
|
||||||
if(ImGui::SmallButton(ICON_FA_EDIT " Rename")) {
|
if(ImGui::SmallButton(ICON_FA_EDIT " Rename")) {
|
||||||
|
@ -316,6 +335,18 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
|
||||||
style.name = name_buf.data();
|
style.name = name_buf.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//if(ImGui::SmallButton(ICON_FA_FILE_EXPORT " Export")) {
|
||||||
|
// if(!ImportExport::exportStyle(_currentMass->name(), style)) {
|
||||||
|
// _queue.addToast(Toast::Type::Error, ImportExport::lastExportError());
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// _queue.addToast(Toast::Type::Success, "Style exported successfully.");
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_FILE_IMPORT " Import")) {
|
||||||
|
// // TODO: implement once the style manager is ready.
|
||||||
|
//}
|
||||||
|
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,12 +421,16 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawDecalEditor(Decal& decal) {
|
void
|
||||||
|
Application::drawDecalEditor(GameObjects::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", conf().advancedMode() ? 2 : 1, ImGuiTableFlags_BordersInnerV)) {
|
||||||
ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
|
||||||
|
if(conf().advancedMode()) {
|
||||||
ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
@ -417,12 +452,17 @@ void SaveTool::drawDecalEditor(Decal& decal) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
drawHelpMarker("Right-click for more option, click the coloured square for the full picker.");
|
drawHelpMarker("Right-click for more option, click the coloured square for the full picker.");
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
std::visit(
|
||||||
ImGui::SliderFloat("##OffsetX", &decal.offset.x(), 0.0f, 1.0f, "X: %.3f");
|
[this](auto& arg){
|
||||||
ImGui::PopItemWidth();
|
using T = std::decay_t<decltype(arg)>;
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
if constexpr (std::is_same_v<T, Vector2>) {
|
||||||
ImGui::SliderFloat("##OffsetY", &decal.offset.y(), 0.0f, 1.0f, "Y: %.3f");
|
drawVector2Slider("##Offset", arg, Vector2{0.0f}, Vector2{1.0f}, "X: %.3f", "Y: %.3f");
|
||||||
ImGui::PopItemWidth();
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, Vector2d>) {
|
||||||
|
drawVector2dSlider("##Offset", arg, Vector2d{0.0}, Vector2d{1.0}, "X: %.3f", "Y: %.3f");
|
||||||
|
}
|
||||||
|
}, decal.offset
|
||||||
|
);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
drawHelpMarker("0.0 = -100 in-game\n1.0 = 100 in-game");
|
drawHelpMarker("0.0 = -100 in-game\n1.0 = 100 in-game");
|
||||||
|
|
||||||
|
@ -439,7 +479,7 @@ void SaveTool::drawDecalEditor(Decal& decal) {
|
||||||
ImGui::Checkbox("##Wrap", &decal.wrap);
|
ImGui::Checkbox("##Wrap", &decal.wrap);
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
if(conf().advancedMode()) {
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
|
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
|
||||||
|
@ -455,47 +495,64 @@ void SaveTool::drawDecalEditor(Decal& decal) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
ImGui::PushItemWidth(-1.0f);
|
||||||
ImGui::DragFloat("##PosX", &decal.position.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
std::visit(
|
||||||
ImGui::PopItemWidth();
|
[this](auto& arg){
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
using T = std::decay_t<decltype(arg)>;
|
||||||
ImGui::DragFloat("##PosY", &decal.position.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
ImGui::PopItemWidth();
|
drawVector3Drag("##Position", arg, 1.0f, Vector3{-FLT_MAX}, Vector3{FLT_MAX}, "X: %.3f",
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
"Y: %.3f", "Z: %.3f");
|
||||||
ImGui::DragFloat("##PosZ", &decal.position.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
}
|
||||||
ImGui::PopItemWidth();
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
drawVector3dDrag("##Position", arg, 1.0f, Vector3d{-DBL_MAX}, Vector3d{DBL_MAX}, "X: %.3f",
|
||||||
|
"Y: %.3f", "Z: %.3f");
|
||||||
|
}
|
||||||
|
}, decal.position
|
||||||
|
);
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
std::visit(
|
||||||
ImGui::DragFloat("##UX", &decal.uAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
[this](auto& arg){
|
||||||
ImGui::PopItemWidth();
|
using T = std::decay_t<decltype(arg)>;
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
ImGui::DragFloat("##UY", &decal.uAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
drawVector3Drag("##U", arg, 1.0f, Vector3{-FLT_MAX}, Vector3{FLT_MAX}, "X: %.3f", "Y: %.3f",
|
||||||
ImGui::PopItemWidth();
|
"Z: %.3f");
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
}
|
||||||
ImGui::DragFloat("##UZ", &decal.uAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
ImGui::PopItemWidth();
|
drawVector3dDrag("##U", arg, 1.0f, Vector3d{-DBL_MAX}, Vector3d{DBL_MAX}, "X: %.3f", "Y: %.3f",
|
||||||
|
"Z: %.3f");
|
||||||
|
}
|
||||||
|
}, decal.uAxis
|
||||||
|
);
|
||||||
|
|
||||||
|
std::visit(
|
||||||
|
[this](auto& arg){
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
|
drawVector3Drag("##V", arg, 1.0f, Vector3{-FLT_MAX}, Vector3{FLT_MAX}, "X: %.3f", "Y: %.3f",
|
||||||
|
"Z: %.3f");
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
drawVector3dDrag("##V", arg, 1.0f, Vector3d{-DBL_MAX}, Vector3d{DBL_MAX}, "X: %.3f", "Y: %.3f",
|
||||||
|
"Z: %.3f");
|
||||||
|
}
|
||||||
|
}, decal.vAxis
|
||||||
|
);
|
||||||
|
|
||||||
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::PopItemWidth();
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<CustomStyle> style_view) {
|
void
|
||||||
|
Application::drawAccessoryEditor(GameObjects::Accessory& accessory, Containers::ArrayView<GameObjects::CustomStyle> style_view) {
|
||||||
if(accessory.id < 1) {
|
if(accessory.id < 1) {
|
||||||
ImGui::TextUnformatted("Accessory: <none>");
|
ImGui::TextUnformatted("Accessory: <none>");
|
||||||
}
|
}
|
||||||
else if(accessories.find(accessory.id) != accessories.cend()) {
|
else if(GameData::accessories.find(accessory.id) != GameData::accessories.cend()) {
|
||||||
ImGui::Text("Accessory #%i - %s", accessory.id, accessories.at(accessory.id).data());
|
ImGui::Text("Accessory #%.4i - %s", accessory.id, GameData::accessories.at(accessory.id).name.data());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImGui::Text("Accessory #%i", accessory.id);
|
ImGui::Text("Accessory #%i", accessory.id);
|
||||||
|
@ -504,13 +561,11 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
static Int tab = 0;
|
static std::int32_t tab = 0;
|
||||||
|
static Containers::Optional<GameData::Accessory::Size> size = Containers::NullOpt;
|
||||||
if(ImGui::SmallButton("Change")) {
|
if(ImGui::SmallButton("Change")) {
|
||||||
ImGui::OpenPopup("##AccessoryPopup");
|
ImGui::OpenPopup("##AccessoryPopup");
|
||||||
if(accessory.id < 1000) {
|
if(accessory.id >= 3000) {
|
||||||
tab = 0;
|
|
||||||
}
|
|
||||||
else if(accessory.id >= 3000) {
|
|
||||||
tab = 3;
|
tab = 3;
|
||||||
}
|
}
|
||||||
else if(accessory.id >= 2000) {
|
else if(accessory.id >= 2000) {
|
||||||
|
@ -519,9 +574,18 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
else if(accessory.id >= 1000) {
|
else if(accessory.id >= 1000) {
|
||||||
tab = 1;
|
tab = 1;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
tab = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(ImGui::BeginPopup("##AccessoryPopup")) {
|
if(ImGui::BeginPopup("##AccessoryPopup")) {
|
||||||
Float selectable_width = 90.0f;
|
static const char* size_labels[] = {
|
||||||
|
"S",
|
||||||
|
"M",
|
||||||
|
"L",
|
||||||
|
"XL"
|
||||||
|
};
|
||||||
|
static const float selectable_width = 90.0f;
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
||||||
if(ImGui::Selectable("Primitives", tab == 0, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
if(ImGui::Selectable("Primitives", tab == 0, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
||||||
|
@ -549,14 +613,60 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
|
|
||||||
ImGui::Separator();
|
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 == GameData::Accessory::Size::S, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||||
|
if(!size) {
|
||||||
|
size.emplace();
|
||||||
|
}
|
||||||
|
*size = GameData::Accessory::Size::S;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("M", size && *size == GameData::Accessory::Size::M, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||||
|
if(!size) {
|
||||||
|
size.emplace();
|
||||||
|
}
|
||||||
|
*size = GameData::Accessory::Size::M;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("L", size && *size == GameData::Accessory::Size::L, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||||
|
if(!size) {
|
||||||
|
size.emplace();
|
||||||
|
}
|
||||||
|
*size = GameData::Accessory::Size::L;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable("XL", size && *size == GameData::Accessory::Size::XL, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||||
|
if(!size) {
|
||||||
|
size.emplace();
|
||||||
|
}
|
||||||
|
*size = GameData::Accessory::Size::XL;
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
if(ImGui::BeginListBox("##AccessoryListbox", {-1.0f, 0.0f})) {
|
if(ImGui::BeginListBox("##AccessoryListbox", {-1.0f, 0.0f})) {
|
||||||
for(const auto& acc : accessories) {
|
for(const auto& [id, acc] : GameData::accessories) {
|
||||||
if(acc.first >= tab * 1000 && acc.first < ((tab + 1) * 1000)) {
|
if(id >= tab * 1000 && id < ((tab + 1) * 1000) && (!size || *size == acc.size)) {
|
||||||
if(ImGui::Selectable(acc.second.data(), acc.first == accessory.id)) {
|
if(ImGui::Selectable(Utility::format("#{:.4d} - {} ({})", id, acc.name, size_labels[acc.size]).data(),
|
||||||
accessory.id = acc.first;
|
id == accessory.id))
|
||||||
|
{
|
||||||
|
accessory.id = id;
|
||||||
accessory.attachIndex = 0;
|
accessory.attachIndex = 0;
|
||||||
}
|
}
|
||||||
if(acc.first == accessory.id) {
|
if(id == accessory.id) {
|
||||||
ImGui::SetItemDefaultFocus();
|
ImGui::SetItemDefaultFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,9 +688,13 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
|
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
drawAlignedText("Styles:");
|
drawAlignedText("Styles:");
|
||||||
|
if(conf().advancedMode()) {
|
||||||
drawAlignedText("Base position:");
|
drawAlignedText("Base position:");
|
||||||
|
}
|
||||||
drawAlignedText("Position offset:");
|
drawAlignedText("Position offset:");
|
||||||
|
if(conf().advancedMode()) {
|
||||||
drawAlignedText("Base rotation:");
|
drawAlignedText("Base rotation:");
|
||||||
|
}
|
||||||
drawAlignedText("Rotation offset:");
|
drawAlignedText("Rotation offset:");
|
||||||
drawAlignedText("Scale:");
|
drawAlignedText("Scale:");
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
|
@ -590,7 +704,7 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
||||||
if(ImGui::BeginCombo("##Style1", getStyleName(accessory.styles[0], style_view).data())) {
|
if(ImGui::BeginCombo("##Style1", getStyleName(accessory.styles[0], style_view).data())) {
|
||||||
for(const auto& style : style_names) {
|
for(const auto& style : GameData::builtin_style_names) {
|
||||||
if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[0] == style.first)) {
|
if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[0] == style.first)) {
|
||||||
accessory.styles[0] = style.first;
|
accessory.styles[0] = style.first;
|
||||||
}
|
}
|
||||||
|
@ -601,7 +715,7 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
if(ImGui::BeginCombo("##Style2", getStyleName(accessory.styles[1], style_view).data())) {
|
if(ImGui::BeginCombo("##Style2", getStyleName(accessory.styles[1], style_view).data())) {
|
||||||
for(const auto& style : style_names) {
|
for(const auto& style : GameData::builtin_style_names) {
|
||||||
if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[1] == style.first)) {
|
if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[1] == style.first)) {
|
||||||
accessory.styles[1] = style.first;
|
accessory.styles[1] = style.first;
|
||||||
}
|
}
|
||||||
|
@ -611,63 +725,86 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
||||||
}
|
}
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
if(conf().advancedMode()) {
|
||||||
ImGui::DragFloat("##PosX", &accessory.relativePosition.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
std::visit(
|
||||||
ImGui::PopItemWidth();
|
[this](auto& arg){
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
using T = std::decay_t<decltype(arg)>;
|
||||||
ImGui::DragFloat("##PosY", &accessory.relativePosition.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
ImGui::PopItemWidth();
|
drawVector3Drag("##RelativePosition", arg, 1.0f, Vector3{-FLT_MAX}, Vector3{FLT_MAX}, "X: %.3f",
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
"Y: %.3f", "Z: %.3f");
|
||||||
ImGui::DragFloat("##PosZ", &accessory.relativePosition.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
}
|
||||||
ImGui::PopItemWidth();
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
drawVector3dDrag("##RelativePosition", arg, 1.0f, Vector3d{-DBL_MAX}, Vector3d{DBL_MAX}, "X: %.3f",
|
||||||
|
"Y: %.3f", "Z: %.3f");
|
||||||
|
}
|
||||||
|
}, accessory.relativePosition
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
std::visit(
|
||||||
ImGui::SliderFloat("##PosOffsetX", &accessory.relativePositionOffset.x(), -500.0f, +500.0f, "X: %.3f");
|
[this](auto& arg){
|
||||||
ImGui::PopItemWidth();
|
using T = std::decay_t<decltype(arg)>;
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
ImGui::SliderFloat("##PosOffsetY", &accessory.relativePositionOffset.y(), -500.0f, +500.0f, "Y: %.3f");
|
drawVector3Slider("##OffsetPosition", arg, Vector3{-500.0f}, Vector3{500.0f}, "X: %.3f", "Y: %.3f",
|
||||||
ImGui::PopItemWidth();
|
"Z: %.3f");
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
}
|
||||||
ImGui::SliderFloat("##PosOffsetZ", &accessory.relativePositionOffset.z(), -500.0f, +500.0f, "Z: %.3f");
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
ImGui::PopItemWidth();
|
drawVector3dSlider("##OffsetPosition", arg, Vector3d{-500.0}, Vector3d{500.0}, "X: %.3f", "Y: %.3f",
|
||||||
|
"Z: %.3f");
|
||||||
|
}
|
||||||
|
}, accessory.relativePositionOffset
|
||||||
|
);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
drawHelpMarker("+/-500.0 = +/-250 in-game");
|
drawHelpMarker("+/-500.0 = +/-250 in-game");
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
if(conf().advancedMode()) {
|
||||||
ImGui::DragFloat("##RotX", &accessory.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f");
|
std::visit(
|
||||||
ImGui::PopItemWidth();
|
[this](auto& arg){
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
using T = std::decay_t<decltype(arg)>;
|
||||||
ImGui::DragFloat("##RotY", &accessory.relativeRotation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Yaw: %.3f");
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
ImGui::PopItemWidth();
|
drawVector3Drag("##RelativeRotation", arg, 1.0f, Vector3{-FLT_MAX}, Vector3{FLT_MAX}, "Roll: %.3f",
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
"Yaw: %.3f", "Pitch: %.3f");
|
||||||
ImGui::DragFloat("##RotZ", &accessory.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f");
|
}
|
||||||
ImGui::PopItemWidth();
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
drawVector3dDrag("##RelativeRotation", arg, 1.0f, Vector3d{-DBL_MAX}, Vector3d{DBL_MAX},
|
||||||
|
"Roll: %.3f", "Yaw: %.3f", "Pitch: %.3f");
|
||||||
|
}
|
||||||
|
}, accessory.relativePosition
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
std::visit(
|
||||||
ImGui::SliderFloat("##RotOffsetX", &accessory.relativeRotationOffset.x(), -180.0f, +180.0f, "Roll: %.3f");
|
[this](auto& arg){
|
||||||
ImGui::PopItemWidth();
|
using T = std::decay_t<decltype(arg)>;
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
ImGui::SliderFloat("##RotOffsetY", &accessory.relativeRotationOffset.y(), -180.0f, +180.0f, "Yaw: %.3f");
|
drawVector3Slider("##OffsetRotation", arg, Vector3{-180.0f}, Vector3{180.0f}, "Roll: %.3f",
|
||||||
ImGui::PopItemWidth();
|
"Yaw: %.3f", "Pitch: %.3f");
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
}
|
||||||
ImGui::SliderFloat("##RotOffsetZ", &accessory.relativeRotationOffset.z(), -180.0f, +180.0f, "Pitch: %.3f");
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
ImGui::PopItemWidth();
|
drawVector3dSlider("##OffsetRotation", arg, Vector3d{-180.0}, Vector3d{180.0}, "Roll: %.3f",
|
||||||
|
"Yaw: %.3f", "Pitch: %.3f");
|
||||||
|
}
|
||||||
|
}, accessory.relativeRotationOffset
|
||||||
|
);
|
||||||
|
|
||||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
std::visit(
|
||||||
ImGui::SliderFloat("##ScaleX", &accessory.localScale.x(), -3.0f, +3.0f, "X: %.3f");
|
[this](auto& arg){
|
||||||
ImGui::PopItemWidth();
|
using T = std::decay_t<decltype(arg)>;
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
ImGui::SliderFloat("##ScaleY", &accessory.localScale.y(), -3.0f, +3.0f, "Y: %.3f");
|
drawVector3Slider("##Scale", arg, Vector3{-3.0f}, Vector3{3.0f}, "X: %.3f", "Y: %.3f", "Z: %.3f");
|
||||||
ImGui::PopItemWidth();
|
}
|
||||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
ImGui::SliderFloat("##ScaleZ", &accessory.localScale.z(), -3.0f, +3.0f, "Z: %.3f");
|
drawVector3dSlider("##Scale", arg, Vector3d{-3.0}, Vector3d{3.0}, "X: %.3f", "Y: %.3f", "Z: %.3f");
|
||||||
ImGui::PopItemWidth();
|
}
|
||||||
|
}, accessory.localScale
|
||||||
|
);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
drawHelpMarker("+/-3.0 = +/-150 in-game");
|
drawHelpMarker("+/-3.0 = +/-150 in-game");
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SaveTool::getStyleName(Int id, Containers::ArrayView<CustomStyle> view) -> Containers::StringView {
|
Containers::StringView
|
||||||
|
Application::getStyleName(std::int32_t id, Containers::ArrayView<GameObjects::CustomStyle> view) {
|
||||||
if(id >= 0 && id <= 15) {
|
if(id >= 0 && id <= 15) {
|
||||||
return view[id].name;
|
return view[id].name;
|
||||||
}
|
}
|
||||||
|
@ -675,6 +812,8 @@ auto SaveTool::getStyleName(Int id, Containers::ArrayView<CustomStyle> view) ->
|
||||||
return _currentMass->globalStyles()[id - 50].name;
|
return _currentMass->globalStyles()[id - 50].name;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return style_names.at(id);
|
return GameData::builtin_style_names.at(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
406
src/Application/Application_MassViewer_Armour.cpp
Normal file
406
src/Application/Application_MassViewer_Armour.cpp
Normal file
|
@ -0,0 +1,406 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
#include "../GameData/ArmourSets.h"
|
||||||
|
#include "../GameData/StyleNames.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
namespace mbst {
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawArmour() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static Containers::StringView slot_labels[] = {
|
||||||
|
#define c(enumerator, strenum, name) name,
|
||||||
|
#include "../Maps/ArmourSlots.hpp"
|
||||||
|
#undef c
|
||||||
|
};
|
||||||
|
|
||||||
|
auto labels_view = arrayView(slot_labels);
|
||||||
|
|
||||||
|
const static float footer_height_to_reserve = ImGui::GetFrameHeightWithSpacing();
|
||||||
|
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
if(ImGui::BeginTable("##SlotsTable", 1,
|
||||||
|
ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_BordersInnerH,
|
||||||
|
{ImGui::GetContentRegionAvail().x * 0.15f, -footer_height_to_reserve}))
|
||||||
|
{
|
||||||
|
ImGui::TableSetupColumn("##Slots", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
|
||||||
|
for(std::size_t i = 0; i < labels_view.size(); i++) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if(ImGui::Selectable(labels_view[i].data(), _selectedArmourSlot && (*_selectedArmourSlot) == i,
|
||||||
|
ImGuiSelectableFlags_SpanAvailWidth))
|
||||||
|
{
|
||||||
|
_selectedArmourSlot = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset all")) {
|
||||||
|
_currentMass->getArmourParts();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if(!_selectedArmourSlot) {
|
||||||
|
ImGui::TextUnformatted("No selected armour slot.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& part = _currentMass->armourParts()[*_selectedArmourSlot];
|
||||||
|
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
if(ImGui::BeginChild("##ArmourEditor", {0.0f, -footer_height_to_reserve})) {
|
||||||
|
|
||||||
|
ImGui::SeparatorText("Part");
|
||||||
|
|
||||||
|
if(GameData::armour_sets.find(part.id) != GameData::armour_sets.cend()) {
|
||||||
|
ImGui::Text("Set name: %s", GameData::armour_sets.at(part.id).name.data());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImGui::Text("Set ID: %d", part.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if(ImGui::SmallButton("Change")) {
|
||||||
|
ImGui::OpenPopup("##ArmourPartPopup");
|
||||||
|
}
|
||||||
|
if(ImGui::BeginPopup("##ArmourPartPopup")) {
|
||||||
|
if(ImGui::BeginListBox("##ChangePart")) {
|
||||||
|
for(const auto& [id, set] : GameData::armour_sets) {
|
||||||
|
if((part.slot == GameObjects::ArmourPart::Slot::Neck && !set.neck_compatible) ||
|
||||||
|
(id == -2 &&
|
||||||
|
!(part.slot == GameObjects::ArmourPart::Slot::LeftFrontSkirt ||
|
||||||
|
part.slot == GameObjects::ArmourPart::Slot::RightFrontSkirt ||
|
||||||
|
part.slot == GameObjects::ArmourPart::Slot::LeftSideSkirt ||
|
||||||
|
part.slot == GameObjects::ArmourPart::Slot::RightSideSkirt ||
|
||||||
|
part.slot == GameObjects::ArmourPart::Slot::LeftBackSkirt ||
|
||||||
|
part.slot == GameObjects::ArmourPart::Slot::RightBackSkirt ||
|
||||||
|
part.slot == GameObjects::ArmourPart::Slot::LeftAnkle ||
|
||||||
|
part.slot == GameObjects::ArmourPart::Slot::RightAnkle)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::Selectable(set.name.data(), id == part.id,
|
||||||
|
ImGuiSelectableFlags_SpanAvailWidth))
|
||||||
|
{
|
||||||
|
part.id = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndListBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SeparatorText("Styles");
|
||||||
|
|
||||||
|
for(std::int32_t i = 0; i < 4; i++) {
|
||||||
|
drawAlignedText("Slot %d:", i + 1);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::PushID(i);
|
||||||
|
if(ImGui::BeginCombo("##Style",
|
||||||
|
getStyleName(part.styles[i], _currentMass->armourCustomStyles()).data()))
|
||||||
|
{
|
||||||
|
for(const auto& style : GameData::builtin_style_names) {
|
||||||
|
if(ImGui::Selectable(getStyleName(style.first, _currentMass->armourCustomStyles()).data(),
|
||||||
|
part.styles[i] == style.first))
|
||||||
|
{
|
||||||
|
part.styles[i] = style.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SeparatorText("Decals");
|
||||||
|
|
||||||
|
constexpr static float selectable_width = 25.0f;
|
||||||
|
|
||||||
|
drawAlignedText("Showing/editing decal:");
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
||||||
|
for(std::uint32_t i = 0; i < part.decals.size(); i++) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable(std::to_string(i + 1).c_str(), _selectedArmourDecals[*_selectedArmourSlot] == int(i),
|
||||||
|
ImGuiSelectableFlags_None, {selectable_width, 0.0f}))
|
||||||
|
{
|
||||||
|
_selectedArmourDecals[*_selectedArmourSlot] = int(i);
|
||||||
|
}
|
||||||
|
if(i != part.decals.size() - 1) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
drawDecalEditor(part.decals[_selectedArmourDecals[*_selectedArmourSlot]]);
|
||||||
|
|
||||||
|
if(!part.accessories.isEmpty()) {
|
||||||
|
ImGui::SeparatorText("Accessories");
|
||||||
|
|
||||||
|
drawAlignedText("Showing/editing accessory:");
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
||||||
|
for(std::uint32_t i = 0; i < part.accessories.size(); i++) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable((std::string{} + char(i + 65)).c_str(),
|
||||||
|
_selectedArmourAccessories[*_selectedArmourSlot] == int(i),
|
||||||
|
ImGuiSelectableFlags_None, {selectable_width, 0.0f}))
|
||||||
|
{
|
||||||
|
_selectedArmourAccessories[*_selectedArmourSlot] = int(i);
|
||||||
|
}
|
||||||
|
if(i != part.accessories.size() - 1) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
drawAccessoryEditor(part.accessories[_selectedArmourAccessories[*_selectedArmourSlot]],
|
||||||
|
_currentMass->armourCustomStyles());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
|
if(!_currentMass->writeArmourPart(part.slot)) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawBLAttachment() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawAlignedText("Attachment style:"_s);
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::RadioButton("Active one",
|
||||||
|
_currentMass->bulletLauncherAttachmentStyle() == GameObjects::BulletLauncherAttachmentStyle::ActiveOne))
|
||||||
|
{
|
||||||
|
_currentMass->bulletLauncherAttachmentStyle() = GameObjects::BulletLauncherAttachmentStyle::ActiveOne;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::RadioButton("Active one per slot",
|
||||||
|
_currentMass->bulletLauncherAttachmentStyle() == GameObjects::BulletLauncherAttachmentStyle::ActiveOnePerSlot))
|
||||||
|
{
|
||||||
|
_currentMass->bulletLauncherAttachmentStyle() = GameObjects::BulletLauncherAttachmentStyle::ActiveOnePerSlot;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::RadioButton("All equipped",
|
||||||
|
_currentMass->bulletLauncherAttachmentStyle() == GameObjects::BulletLauncherAttachmentStyle::AllEquipped))
|
||||||
|
{
|
||||||
|
_currentMass->bulletLauncherAttachmentStyle() = GameObjects::BulletLauncherAttachmentStyle::ActiveOnePerSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
constexpr static float selectable_width = 25.0f;
|
||||||
|
drawAlignedText("Launcher slot:");
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
||||||
|
for(auto i = 0u; i < _currentMass->bulletLauncherAttachments().size(); i++) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Selectable(std::to_string(i).c_str(), _selectedBLPlacement == i, ImGuiSelectableFlags_None,
|
||||||
|
{selectable_width, 0.0f}))
|
||||||
|
{
|
||||||
|
_selectedBLPlacement = i;
|
||||||
|
}
|
||||||
|
if(i != _currentMass->bulletLauncherAttachments().size() - 1) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
auto& placement = _currentMass->bulletLauncherAttachments()[_selectedBLPlacement];
|
||||||
|
|
||||||
|
static const Containers::StringView socket_labels[] = {
|
||||||
|
#define c(enumerator, enumstr, name) name,
|
||||||
|
#include "../Maps/BulletLauncherSockets.hpp"
|
||||||
|
#undef c
|
||||||
|
};
|
||||||
|
|
||||||
|
drawAlignedText("Socket:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::BeginCombo("##Socket", socket_labels[std::uint32_t(placement.socket)].data())) {
|
||||||
|
for(std::uint32_t i = 0; i < (sizeof(socket_labels) / sizeof(socket_labels[0])); i++) {
|
||||||
|
if(ImGui::Selectable(socket_labels[i].data(), i == std::uint32_t(placement.socket), ImGuiSelectableFlags_SpanAvailWidth)) {
|
||||||
|
placement.socket = static_cast<GameObjects::BulletLauncherAttachment::Socket>(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(placement.socket != GameObjects::BulletLauncherAttachment::Socket::Auto) {
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
drawAlignedText("Relative position:");
|
||||||
|
drawAlignedText("Offset position:");
|
||||||
|
drawAlignedText("Relative rotation:");
|
||||||
|
drawAlignedText("Offset rotation:");
|
||||||
|
drawAlignedText("Scale:");
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
std::visit(
|
||||||
|
[this](auto& arg){
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
|
drawVector3Drag("##RelativePosition", arg, 1.0f, Vector3{-FLT_MAX}, Vector3{FLT_MAX}, "X: %.3f",
|
||||||
|
"Y: %.3f", "Z: %.3f");
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
drawVector3dDrag("##RelativePosition", arg, 1.0f, Vector3d{-DBL_MAX}, Vector3d{DBL_MAX},
|
||||||
|
"X: %.3f", "Y: %.3f", "Z: %.3f");
|
||||||
|
}
|
||||||
|
}, placement.relativeLocation
|
||||||
|
);
|
||||||
|
|
||||||
|
std::visit(
|
||||||
|
[this](auto& arg){
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
|
drawVector3Slider("##OffsetPosition", arg, Vector3{-500.0f}, Vector3{500.0f}, "X: %.3f", "Y: %.3f",
|
||||||
|
"Z: %.3f");
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
drawVector3dSlider("##OffsetPosition", arg, Vector3d{-500.0}, Vector3d{500.0}, "X: %.3f",
|
||||||
|
"Y: %.3f", "Z: %.3f");
|
||||||
|
}
|
||||||
|
}, placement.offsetLocation
|
||||||
|
);
|
||||||
|
ImGui::SameLine();
|
||||||
|
drawHelpMarker("+/-500.0 = +/-250 in-game");
|
||||||
|
|
||||||
|
std::visit(
|
||||||
|
[this](auto& arg){
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
|
drawVector3Drag("##RelativeRotation", arg, 1.0f, Vector3{-FLT_MAX}, Vector3{FLT_MAX},
|
||||||
|
"Pitch: %.3f", "Yaw: %.3f", "Roll: %.3f");
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
drawVector3dDrag("##RelativeRotation", arg, 1.0f, Vector3d{-DBL_MAX}, Vector3d{DBL_MAX},
|
||||||
|
"Pitch: %.3f", "Yaw: %.3f", "Roll: %.3f");
|
||||||
|
}
|
||||||
|
}, placement.relativeRotation
|
||||||
|
);
|
||||||
|
|
||||||
|
std::visit(
|
||||||
|
[this](auto& arg){
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
|
drawVector3Slider("##OffsetRotation", arg, Vector3{-30.0f, -30.0f, -180.0f},
|
||||||
|
Vector3{30.0f, 30.0f, 180.0f}, "Pitch: %.3f", "Yaw: %.3f", "Roll: %.3f");
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
drawVector3dSlider("##OffsetRotation", arg, Vector3d{-30.0, -30.0, -180.0},
|
||||||
|
Vector3d{30.0, 30.0, 180.0}, "Pitch: %.3f", "Yaw: %.3f", "Roll: %.3f");
|
||||||
|
}
|
||||||
|
}, placement.offsetRotation
|
||||||
|
);
|
||||||
|
|
||||||
|
std::visit(
|
||||||
|
[this](auto& arg){
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
|
drawVector3Slider("##Scale", arg, Vector3{0.5f}, Vector3{1.5f}, "X: %.3f", "Y: %.3f", "Z: %.3f");
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
drawVector3dSlider("##Scale", arg, Vector3d{0.5}, Vector3d{1.5}, "X: %.3f", "Y: %.3f", "Z: %.3f");
|
||||||
|
}
|
||||||
|
}, placement.relativeScale
|
||||||
|
);
|
||||||
|
ImGui::SameLine();
|
||||||
|
drawHelpMarker("0.5 = 50 in-game\n1.5 = 150 in-game");
|
||||||
|
ImGui::EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
|
if(!_currentMass->writeBulletLauncherAttachments()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawCustomArmourStyles() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ImGui::BeginChild("##ArmourStyles")) {
|
||||||
|
ImGui::EndChild();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
|
||||||
|
|
||||||
|
for(std::uint32_t i = 0; i < _currentMass->armourCustomStyles().size(); i++) {
|
||||||
|
ImGui::PushID(int(i));
|
||||||
|
auto result = drawCustomStyle(_currentMass->armourCustomStyles()[i]);
|
||||||
|
switch(result) {
|
||||||
|
case DCS_ResetStyle:
|
||||||
|
_currentMass->getArmourCustomStyles();
|
||||||
|
break;
|
||||||
|
case DCS_Save:
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
|
if(!_currentMass->writeArmourCustomStyle(i)) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
294
src/Application/Application_MassViewer_Frame.cpp
Normal file
294
src/Application/Application_MassViewer_Frame.cpp
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <imgui_internal.h>
|
||||||
|
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
#include "../GameData/StyleNames.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
namespace mbst {
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawFrameInfo() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ImGui::BeginChild("##FrameInfo")) {
|
||||||
|
ImGui::EndChild();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
if(ImGui::BeginChild("##JointSliders",
|
||||||
|
{(ImGui::GetContentRegionAvail().x / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f),
|
||||||
|
0.0f},
|
||||||
|
ImGuiChildFlags_Border|ImGuiChildFlags_AutoResizeY, ImGuiWindowFlags_MenuBar))
|
||||||
|
{
|
||||||
|
if(ImGui::BeginMenuBar()) {
|
||||||
|
ImGui::TextUnformatted("Joint sliders");
|
||||||
|
drawHelpMarker("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.",
|
||||||
|
static_cast<float>(windowSize().x()) / 4.0f);
|
||||||
|
|
||||||
|
ImGui::EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawJointSliders();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if(ImGui::BeginChild("##FrameStyles",
|
||||||
|
{(ImGui::GetContentRegionAvail().x / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 0.0f},
|
||||||
|
ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar))
|
||||||
|
{
|
||||||
|
if(ImGui::BeginMenuBar()) {
|
||||||
|
ImGui::TextUnformatted("Frame styles");
|
||||||
|
|
||||||
|
ImGui::EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawFrameStyles();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if(ImGui::BeginChild("##EyeFlare", {}, ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar)) {
|
||||||
|
if(ImGui::BeginMenuBar()) {
|
||||||
|
ImGui::TextUnformatted("Eye flare colour");
|
||||||
|
drawHelpMarker("Right-click the picker for more options.", 250.0f);
|
||||||
|
|
||||||
|
ImGui::EndMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawEyeColourPicker();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawJointSliders() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
drawAlignedText("Neck:");
|
||||||
|
drawAlignedText("Body:");
|
||||||
|
drawAlignedText("Shoulders:");
|
||||||
|
drawAlignedText("Hips:");
|
||||||
|
drawAlignedText("Arms:");
|
||||||
|
drawAlignedText("Legs:");
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
ImGui::PushItemWidth(-1.0f);
|
||||||
|
if(ImGui::SliderFloat("##NeckSlider", &_currentMass->jointSliders().neck, 0.0f, 1.0f)) {
|
||||||
|
_jointsDirty = true;
|
||||||
|
}
|
||||||
|
if(ImGui::SliderFloat("##BodySlider", &_currentMass->jointSliders().body, 0.0f, 1.0f)) {
|
||||||
|
_jointsDirty = true;
|
||||||
|
}
|
||||||
|
if(ImGui::SliderFloat("##ShouldersSlider", &_currentMass->jointSliders().shoulders, 0.0f, 1.0f)) {
|
||||||
|
_jointsDirty = true;
|
||||||
|
}
|
||||||
|
if(ImGui::SliderFloat("##HipsSlider", &_currentMass->jointSliders().hips, 0.0f, 1.0f)) {
|
||||||
|
_jointsDirty = true;
|
||||||
|
}
|
||||||
|
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
||||||
|
if(ImGui::SliderFloat("##UpperArmsSlider", &_currentMass->jointSliders().upperArms, 0.0f, 1.0f, "Upper: %.3f")) {
|
||||||
|
_jointsDirty = true;
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
if(ImGui::SliderFloat("##LowerArmsSlider", &_currentMass->jointSliders().lowerArms, 0.0f, 1.0f, "Lower: %.3f")) {
|
||||||
|
_jointsDirty = true;
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
||||||
|
if(ImGui::SliderFloat("##UpperLegsSlider", &_currentMass->jointSliders().upperLegs, 0.0f, 1.0f, "Upper: %.3f")) {
|
||||||
|
_jointsDirty = true;
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||||
|
if(ImGui::SliderFloat("##LowerLegsSlider", &_currentMass->jointSliders().lowerLegs, 0.0f, 1.0f, "Lower: %.3f")) {
|
||||||
|
_jointsDirty = true;
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
if(!_jointsDirty) {
|
||||||
|
ImGui::BeginDisabled();
|
||||||
|
ImGui::Button(ICON_FA_SAVE " Save");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Button(ICON_FA_UNDO " Reset");
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
|
if(!_currentMass->writeJointSliders()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
|
}
|
||||||
|
_jointsDirty = false;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Button(ICON_FA_UNDO " Reset")) {
|
||||||
|
_currentMass->getJointSliders();
|
||||||
|
_jointsDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawFrameStyles() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::int32_t i = 0; i < 4; i++) {
|
||||||
|
drawAlignedText("Slot %d:", i + 1);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::PushID(i);
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(-1.0f);
|
||||||
|
if(ImGui::BeginCombo("##Style",
|
||||||
|
getStyleName(_currentMass->frameStyles()[i], _currentMass->frameCustomStyles()).data()))
|
||||||
|
{
|
||||||
|
for(const auto& style : GameData::builtin_style_names) {
|
||||||
|
if(ImGui::Selectable(getStyleName(style.first, _currentMass->frameCustomStyles()).data(),
|
||||||
|
_currentMass->frameStyles()[i] == style.first))
|
||||||
|
{
|
||||||
|
_currentMass->frameStyles()[i] = style.first;
|
||||||
|
_stylesDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_stylesDirty) {
|
||||||
|
ImGui::BeginDisabled();
|
||||||
|
ImGui::Button(ICON_FA_SAVE " Save");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Button(ICON_FA_UNDO " Reset");
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
|
if(!_currentMass->writeFrameStyles()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
|
}
|
||||||
|
_stylesDirty = false;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Button(ICON_FA_UNDO " Reset")) {
|
||||||
|
_currentMass->getFrameStyles();
|
||||||
|
_stylesDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawEyeColourPicker() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::ColorPicker3("##EyeFlarePicker", &_currentMass->eyeFlareColour().x())) {
|
||||||
|
_eyeFlareDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_eyeFlareDirty) {
|
||||||
|
ImGui::BeginDisabled();
|
||||||
|
ImGui::Button(ICON_FA_SAVE " Save");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Button(ICON_FA_UNDO " Reset");
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
|
if(!_currentMass->writeEyeFlareColour()) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
|
}
|
||||||
|
_eyeFlareDirty = false;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Button(ICON_FA_UNDO " Reset")) {
|
||||||
|
_currentMass->getEyeFlareColour();
|
||||||
|
_eyeFlareDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawCustomFrameStyles() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ImGui::BeginChild("##FrameStyles")) {
|
||||||
|
ImGui::EndChild();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
|
||||||
|
|
||||||
|
for(std::uint32_t i = 0; i < _currentMass->frameCustomStyles().size(); i++) {
|
||||||
|
ImGui::PushID(int(i));
|
||||||
|
auto result = drawCustomStyle(_currentMass->frameCustomStyles()[i]);
|
||||||
|
switch(result) {
|
||||||
|
case DCS_ResetStyle:
|
||||||
|
_currentMass->getFrameCustomStyles();
|
||||||
|
break;
|
||||||
|
case DCS_Save:
|
||||||
|
_modifiedBySaveTool = true;
|
||||||
|
if(!_currentMass->writeFrameCustomStyle(i)) {
|
||||||
|
_modifiedBySaveTool = false;
|
||||||
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,24 +16,27 @@
|
||||||
|
|
||||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
|
||||||
#include "../Maps/StyleNames.h"
|
#include "../GameData/StyleNames.h"
|
||||||
#include "../Maps/WeaponParts.h"
|
#include "../GameData/WeaponParts.h"
|
||||||
|
|
||||||
#include "SaveTool.h"
|
#include "Application.h"
|
||||||
|
|
||||||
void SaveTool::drawWeapons() {
|
namespace mbst {
|
||||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
|
||||||
|
void
|
||||||
|
Application::drawWeapons() {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||||
_currentWeapon = nullptr;
|
_currentWeapon = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
|
const float footer_height_to_reserve = ImGui::GetFrameHeightWithSpacing();
|
||||||
|
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
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;
|
||||||
|
@ -52,11 +55,9 @@ void SaveTool::drawWeapons() {
|
||||||
|
|
||||||
bool dirty = _meleeDirty || _shieldsDirty || _bShootersDirty || _eShootersDirty || _bLaunchersDirty || _eLaunchersDirty;
|
bool dirty = _meleeDirty || _shieldsDirty || _bShootersDirty || _eShootersDirty || _bLaunchersDirty || _eLaunchersDirty;
|
||||||
|
|
||||||
if(!dirty) {
|
ImGui::BeginDisabled(!dirty);
|
||||||
ImGui::BeginDisabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save order"); })) {
|
||||||
if(_meleeDirty) {
|
if(_meleeDirty) {
|
||||||
_modifiedBySaveTool = true;
|
_modifiedBySaveTool = true;
|
||||||
if(!_currentMass->writeMeleeWeapons()) {
|
if(!_currentMass->writeMeleeWeapons()) {
|
||||||
|
@ -153,9 +154,7 @@ void SaveTool::drawWeapons() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!dirty) {
|
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
@ -177,42 +176,40 @@ void SaveTool::drawWeapons() {
|
||||||
|
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
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;
|
_modifiedBySaveTool = true;
|
||||||
switch(_currentWeapon->type) {
|
switch(_currentWeapon->type) {
|
||||||
case WeaponType::Melee:
|
case GameObjects::Weapon::Type::Melee:
|
||||||
if(!_currentMass->writeMeleeWeapons()) {
|
if(!_currentMass->writeMeleeWeapons()) {
|
||||||
_modifiedBySaveTool = false;
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::Shield:
|
case GameObjects::Weapon::Type::Shield:
|
||||||
if(!_currentMass->writeShields()) {
|
if(!_currentMass->writeShields()) {
|
||||||
_modifiedBySaveTool = false;
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::BulletShooter:
|
case GameObjects::Weapon::Type::BulletShooter:
|
||||||
if(!_currentMass->writeBulletShooters()) {
|
if(!_currentMass->writeBulletShooters()) {
|
||||||
_modifiedBySaveTool = false;
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::EnergyShooter:
|
case GameObjects::Weapon::Type::EnergyShooter:
|
||||||
if(!_currentMass->writeEnergyShooters()) {
|
if(!_currentMass->writeEnergyShooters()) {
|
||||||
_modifiedBySaveTool = false;
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::BulletLauncher:
|
case GameObjects::Weapon::Type::BulletLauncher:
|
||||||
if(!_currentMass->writeBulletLaunchers()) {
|
if(!_currentMass->writeBulletLaunchers()) {
|
||||||
_modifiedBySaveTool = false;
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WeaponType::EnergyLauncher:
|
case GameObjects::Weapon::Type::EnergyLauncher:
|
||||||
if(!_currentMass->writeEnergyLaunchers()) {
|
if(!_currentMass->writeEnergyLaunchers()) {
|
||||||
_modifiedBySaveTool = false;
|
_modifiedBySaveTool = false;
|
||||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||||
|
@ -228,22 +225,22 @@ void SaveTool::drawWeapons() {
|
||||||
|
|
||||||
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset weapon category")) {
|
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset weapon category")) {
|
||||||
switch(_currentWeapon->type) {
|
switch(_currentWeapon->type) {
|
||||||
case WeaponType::Melee:
|
case GameObjects::Weapon::Type::Melee:
|
||||||
_currentMass->getMeleeWeapons();
|
_currentMass->getMeleeWeapons();
|
||||||
break;
|
break;
|
||||||
case WeaponType::Shield:
|
case GameObjects::Weapon::Type::Shield:
|
||||||
_currentMass->getShields();
|
_currentMass->getShields();
|
||||||
break;
|
break;
|
||||||
case WeaponType::BulletShooter:
|
case GameObjects::Weapon::Type::BulletShooter:
|
||||||
_currentMass->getBulletShooters();
|
_currentMass->getBulletShooters();
|
||||||
break;
|
break;
|
||||||
case WeaponType::EnergyShooter:
|
case GameObjects::Weapon::Type::EnergyShooter:
|
||||||
_currentMass->getEnergyShooters();
|
_currentMass->getEnergyShooters();
|
||||||
break;
|
break;
|
||||||
case WeaponType::BulletLauncher:
|
case GameObjects::Weapon::Type::BulletLauncher:
|
||||||
_currentMass->getBulletLaunchers();
|
_currentMass->getBulletLaunchers();
|
||||||
break;
|
break;
|
||||||
case WeaponType::EnergyLauncher:
|
case GameObjects::Weapon::Type::EnergyLauncher:
|
||||||
_currentMass->getEnergyLaunchers();
|
_currentMass->getEnergyLaunchers();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -254,28 +251,29 @@ void SaveTool::drawWeapons() {
|
||||||
ImGui::EndGroup();
|
ImGui::EndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawWeaponCategory(Containers::StringView name, Containers::ArrayView<Weapon> weapons_view, bool& dirty,
|
void
|
||||||
|
Application::drawWeaponCategory(Containers::StringView name, Containers::ArrayView<GameObjects::Weapon> weapons_view, bool& dirty,
|
||||||
Containers::StringView payload_type, Containers::StringView payload_tooltip)
|
Containers::StringView payload_type, Containers::StringView payload_tooltip)
|
||||||
{
|
{
|
||||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::TextUnformatted(name.data());
|
ImGui::TextUnformatted(name.cbegin(), name.cend());
|
||||||
|
|
||||||
ImGui::PushID(payload_type.data());
|
ImGui::PushID(payload_type.data());
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < weapons_view.size(); i++) {
|
for(std::uint32_t i = 0; i < weapons_view.size(); i++) {
|
||||||
auto& weapon = weapons_view[i];
|
auto& weapon = weapons_view[i];
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
if(ImGui::BeginDragDropSource()) {
|
if(ImGui::BeginDragDropSource()) {
|
||||||
ImGui::SetDragDropPayload(payload_type.data(), &i, sizeof(UnsignedInt));
|
ImGui::SetDragDropPayload(payload_type.data(), &i, sizeof(std::uint32_t));
|
||||||
if(ImGui::GetIO().KeyCtrl) {
|
if(ImGui::GetIO().KeyCtrl) {
|
||||||
ImGui::Text("%s %i - %s (copy)", payload_tooltip.data(), i + 1, weapon.name.data());
|
ImGui::Text("%s %i - %s (copy)", payload_tooltip.data(), i + 1, weapon.name.data());
|
||||||
}
|
}
|
||||||
|
@ -309,7 +307,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,8 +315,9 @@ void SaveTool::drawWeaponCategory(Containers::StringView name, Containers::Array
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
void
|
||||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid || !_currentWeapon) {
|
Application::drawWeaponEditor(GameObjects::Weapon& weapon) {
|
||||||
|
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid || !_currentWeapon) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,7 +327,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
#undef c
|
#undef c
|
||||||
};
|
};
|
||||||
|
|
||||||
drawAlignedText("%s: %s", labels[UnsignedInt(weapon.type)].data(), weapon.name.data());
|
drawAlignedText("%s: %s", labels[std::uint32_t(weapon.type)].data(), weapon.name.data());
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
@ -347,11 +346,11 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
drawAlignedText("Equipped:");
|
drawAlignedText("Equipped:");
|
||||||
|
|
||||||
if(weapon.type != WeaponType::Shield) {
|
if(weapon.type != GameObjects::Weapon::Type::Shield) {
|
||||||
drawAlignedText("Damage type:");
|
drawAlignedText("Damage type:");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(weapon.type == WeaponType::Melee) {
|
if(weapon.type == GameObjects::Weapon::Type::Melee) {
|
||||||
drawAlignedText("Dual-wield:");
|
drawAlignedText("Dual-wield:");
|
||||||
|
|
||||||
drawAlignedText("Custom effect mode:");
|
drawAlignedText("Custom effect mode:");
|
||||||
|
@ -365,48 +364,48 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
ImGui::Checkbox("##EquippedCheckbox", &weapon.attached);
|
ImGui::Checkbox("##EquippedCheckbox", &weapon.attached);
|
||||||
|
|
||||||
if(weapon.type != WeaponType::Shield) {
|
if(weapon.type != GameObjects::Weapon::Type::Shield) {
|
||||||
if(weapon.type == WeaponType::Melee &&
|
if(weapon.type == GameObjects::Weapon::Type::Melee &&
|
||||||
ImGui::RadioButton("Physical##NoElement", weapon.damageType == DamageType::Physical))
|
ImGui::RadioButton("Physical##NoElement", weapon.damageType == GameObjects::Weapon::DamageType::Physical))
|
||||||
{
|
{
|
||||||
weapon.damageType = DamageType::Physical;
|
weapon.damageType = GameObjects::Weapon::DamageType::Physical;
|
||||||
}
|
}
|
||||||
else if((weapon.type == WeaponType::BulletShooter || weapon.type == WeaponType::BulletLauncher) &&
|
else if((weapon.type == GameObjects::Weapon::Type::BulletShooter || weapon.type == GameObjects::Weapon::Type::BulletLauncher) &&
|
||||||
ImGui::RadioButton("Piercing##NoElement", weapon.damageType == DamageType::Piercing))
|
ImGui::RadioButton("Piercing##NoElement", weapon.damageType == GameObjects::Weapon::DamageType::Piercing))
|
||||||
{
|
{
|
||||||
weapon.damageType = DamageType::Piercing;
|
weapon.damageType = GameObjects::Weapon::DamageType::Piercing;
|
||||||
}
|
}
|
||||||
else if((weapon.type == WeaponType::EnergyShooter || weapon.type == WeaponType::EnergyLauncher) &&
|
else if((weapon.type == GameObjects::Weapon::Type::EnergyShooter || weapon.type == GameObjects::Weapon::Type::EnergyLauncher) &&
|
||||||
ImGui::RadioButton("Plasma##NoElement", weapon.damageType == DamageType::Plasma))
|
ImGui::RadioButton("Plasma##NoElement", weapon.damageType == GameObjects::Weapon::DamageType::Plasma))
|
||||||
{
|
{
|
||||||
weapon.damageType = DamageType::Plasma;
|
weapon.damageType = GameObjects::Weapon::DamageType::Plasma;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::RadioButton("Heat##Heat", weapon.damageType == DamageType::Heat)) {
|
if(ImGui::RadioButton("Heat##Heat", weapon.damageType == GameObjects::Weapon::DamageType::Heat)) {
|
||||||
weapon.damageType = DamageType::Heat;
|
weapon.damageType = GameObjects::Weapon::DamageType::Heat;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::RadioButton("Freeze##Freeze", weapon.damageType == DamageType::Freeze)) {
|
if(ImGui::RadioButton("Freeze##Freeze", weapon.damageType == GameObjects::Weapon::DamageType::Freeze)) {
|
||||||
weapon.damageType = DamageType::Freeze;
|
weapon.damageType = GameObjects::Weapon::DamageType::Freeze;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::RadioButton("Shock##Shock", weapon.damageType == DamageType::Shock)) {
|
if(ImGui::RadioButton("Shock##Shock", weapon.damageType == GameObjects::Weapon::DamageType::Shock)) {
|
||||||
weapon.damageType = DamageType::Shock;
|
weapon.damageType = GameObjects::Weapon::DamageType::Shock;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(weapon.type == WeaponType::Melee) {
|
if(weapon.type == GameObjects::Weapon::Type::Melee) {
|
||||||
ImGui::Checkbox("##DualWield", &weapon.dualWield);
|
ImGui::Checkbox("##DualWield", &weapon.dualWield);
|
||||||
|
|
||||||
if(ImGui::RadioButton("Default##Default", weapon.effectColourMode == EffectColourMode::Default)) {
|
if(ImGui::RadioButton("Default##Default", weapon.effectColourMode == GameObjects::Weapon::EffectColourMode::Default)) {
|
||||||
weapon.effectColourMode = EffectColourMode::Default;
|
weapon.effectColourMode = GameObjects::Weapon::EffectColourMode::Default;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::RadioButton("Custom##Custom", weapon.effectColourMode == EffectColourMode::Custom)) {
|
if(ImGui::RadioButton("Custom##Custom", weapon.effectColourMode == GameObjects::Weapon::EffectColourMode::Custom)) {
|
||||||
weapon.effectColourMode = EffectColourMode::Custom;
|
weapon.effectColourMode = GameObjects::Weapon::EffectColourMode::Custom;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool custom_effect = (weapon.effectColourMode == EffectColourMode::Custom);
|
bool custom_effect = (weapon.effectColourMode == GameObjects::Weapon::EffectColourMode::Custom);
|
||||||
if(!custom_effect) {
|
if(!custom_effect) {
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
}
|
}
|
||||||
|
@ -425,8 +424,8 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
|
|
||||||
if(ImGui::CollapsingHeader("Weapon parts")) {
|
if(ImGui::CollapsingHeader("Weapon parts")) {
|
||||||
drawAlignedText("Viewing/editing part:");
|
drawAlignedText("Viewing/editing part:");
|
||||||
for(Int i = 0; UnsignedLong(i) < weapon.parts.size(); i++) {
|
for(std::int32_t i = 0; std::size_t(i) < weapon.parts.size(); i++) {
|
||||||
if(UnsignedLong(_selectedWeaponPart) >= weapon.parts.size()) {
|
if(std::size_t(_selectedWeaponPart) >= weapon.parts.size()) {
|
||||||
_selectedWeaponPart = 0;
|
_selectedWeaponPart = 0;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -435,29 +434,31 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
|
|
||||||
auto& part = weapon.parts[_selectedWeaponPart];
|
auto& part = weapon.parts[_selectedWeaponPart];
|
||||||
|
|
||||||
const auto* map = [this, &weapon]()-> const std::map<Int, Containers::StringView>* {
|
const auto* map = [this, &weapon]()-> const std::map<std::int32_t, Containers::StringView>* {
|
||||||
switch(weapon.type) {
|
switch(weapon.type) {
|
||||||
case WeaponType::Melee:
|
case GameObjects::Weapon::Type::Melee:
|
||||||
return _selectedWeaponPart == 0 ? &melee_grips : &melee_assaulters;
|
return _selectedWeaponPart == 0 ? &GameData::melee_grips : &GameData::melee_assaulters;
|
||||||
case WeaponType::Shield:
|
case GameObjects::Weapon::Type::Shield:
|
||||||
return _selectedWeaponPart == 0 ? &shield_handles : &shield_shells;
|
return _selectedWeaponPart == 0 ? &GameData::shield_handles : &GameData::shield_shells;
|
||||||
case WeaponType::BulletShooter:
|
case GameObjects::Weapon::Type::BulletShooter:
|
||||||
return _selectedWeaponPart == 0 ? &bshooter_triggers : &bshooter_barrels;
|
return _selectedWeaponPart == 0 ? &GameData::bshooter_triggers : &GameData::bshooter_barrels;
|
||||||
case WeaponType::EnergyShooter:
|
case GameObjects::Weapon::Type::EnergyShooter:
|
||||||
return _selectedWeaponPart == 0 ? &eshooter_triggers : &eshooter_busters;
|
return _selectedWeaponPart == 0 ? &GameData::eshooter_triggers : &GameData::eshooter_busters;
|
||||||
case WeaponType::BulletLauncher:
|
case GameObjects::Weapon::Type::BulletLauncher:
|
||||||
return _selectedWeaponPart == 0 ? &blauncher_pods : &blauncher_projectiles;
|
return _selectedWeaponPart == 0 ? &GameData::blauncher_pods : &GameData::blauncher_projectiles;
|
||||||
case WeaponType::EnergyLauncher:
|
case GameObjects::Weapon::Type::EnergyLauncher:
|
||||||
return _selectedWeaponPart == 0 ? &elauncher_generators : &elauncher_pods;
|
return _selectedWeaponPart == 0 ? &GameData::elauncher_generators : &GameData::elauncher_pods;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
CORRADE_INTERNAL_ASSERT(map);
|
if(!map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(map->find(part.id) != map->cend()) {
|
if(map->find(part.id) != map->cend()) {
|
||||||
ImGui::TextUnformatted(map->at(part.id).data());
|
ImGui::TextUnformatted(map->at(part.id).cbegin(), map->at(part.id).cend());
|
||||||
}
|
}
|
||||||
else if(part.id == -1) {
|
else if(part.id == -1) {
|
||||||
ImGui::TextUnformatted("<none>");
|
ImGui::TextUnformatted("<none>");
|
||||||
|
@ -477,6 +478,9 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
if(ImGui::Selectable(mapped_part.second.data(), mapped_part.first == part.id)) {
|
if(ImGui::Selectable(mapped_part.second.data(), mapped_part.first == part.id)) {
|
||||||
part.id = mapped_part.first;
|
part.id = mapped_part.first;
|
||||||
}
|
}
|
||||||
|
if(mapped_part.first == part.id) {
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndListBox();
|
ImGui::EndListBox();
|
||||||
|
@ -485,14 +489,14 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(weapon.type == WeaponType::Shield ||
|
if(weapon.type == GameObjects::Weapon::Type::Shield ||
|
||||||
(weapon.type == WeaponType::BulletLauncher && _selectedWeaponPart != 0))
|
(weapon.type == GameObjects::Weapon::Type::BulletLauncher && _selectedWeaponPart != 0))
|
||||||
{
|
{
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::SmallButton("Unequip")) {
|
if(ImGui::SmallButton("Unequip")) {
|
||||||
part.id = -1;
|
part.id = -1;
|
||||||
}
|
}
|
||||||
if(weapon.type == WeaponType::Shield && _selectedWeaponPart == 0) {
|
if(weapon.type == GameObjects::Weapon::Type::Shield && _selectedWeaponPart == 0) {
|
||||||
drawTooltip("This will make the whole shield and its accessories invisible.");
|
drawTooltip("This will make the whole shield and its accessories invisible.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -500,10 +504,10 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::BeginChild("##PartDetails", {0.0f, 0.0f}, true)) {
|
if(ImGui::BeginChild("##PartDetails", {}, ImGuiChildFlags_Border)) {
|
||||||
ImGui::TextUnformatted("Styles:");
|
ImGui::TextUnformatted("Styles:");
|
||||||
|
|
||||||
for(Int i = 0; i < 4; i++) {
|
for(std::int32_t i = 0; i < 4; i++) {
|
||||||
drawAlignedText("Slot %d:", i + 1);
|
drawAlignedText("Slot %d:", i + 1);
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -511,7 +515,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
ImGui::PushID(i);
|
ImGui::PushID(i);
|
||||||
|
|
||||||
if(ImGui::BeginCombo("##Style", getStyleName(part.styles[i], weapon.customStyles).data())) {
|
if(ImGui::BeginCombo("##Style", getStyleName(part.styles[i], weapon.customStyles).data())) {
|
||||||
for(const auto& style: style_names) {
|
for(const auto& style: GameData::builtin_style_names) {
|
||||||
if(ImGui::Selectable(getStyleName(style.first, weapon.customStyles).data(),
|
if(ImGui::Selectable(getStyleName(style.first, weapon.customStyles).data(),
|
||||||
part.styles[i] == style.first)) {
|
part.styles[i] == style.first)) {
|
||||||
part.styles[i] = style.first;
|
part.styles[i] = style.first;
|
||||||
|
@ -529,24 +533,24 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
ImGui::PushID("Decal");
|
ImGui::PushID("Decal");
|
||||||
|
|
||||||
drawAlignedText("Showing/editing decal");
|
drawAlignedText("Showing/editing decal");
|
||||||
for(UnsignedLong i = 0; i < part.decals.size(); i++) {
|
for(std::size_t 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]);
|
||||||
|
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
if(part.accessories.size() != 0) {
|
if(!part.accessories.isEmpty()) {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
ImGui::PushID("Accessory");
|
ImGui::PushID("Accessory");
|
||||||
|
|
||||||
drawAlignedText("Showing/editing accessory");
|
drawAlignedText("Showing/editing accessory");
|
||||||
for(UnsignedLong i = 0; i < part.accessories.size(); i++) {
|
for(std::size_t 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);
|
||||||
|
@ -558,3 +562,5 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,18 +14,23 @@
|
||||||
// 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 "Application.h"
|
||||||
|
|
||||||
extern const ImVec2 center_pivot;
|
extern const ImVec2 center_pivot;
|
||||||
|
|
||||||
void SaveTool::drawProfileManager() {
|
namespace mbst {
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawProfileManager() {
|
||||||
static std::size_t profile_index = 0;
|
static std::size_t profile_index = 0;
|
||||||
|
|
||||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f} / dpiScaling()}, ImGuiCond_Always, center_pivot);
|
||||||
if(ImGui::Begin("Profile management##ProfileManager", nullptr,
|
if(ImGui::Begin("Profile management##ProfileManager", nullptr,
|
||||||
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoBringToFrontOnFocus|
|
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoBringToFrontOnFocus|
|
||||||
ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_MenuBar))
|
ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_MenuBar))
|
||||||
|
@ -35,10 +40,6 @@ void SaveTool::drawProfileManager() {
|
||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ImGuiID backup_list_popup_id = drawBackupListPopup();
|
|
||||||
static ImGuiID backup_popup_id = drawBackupProfilePopup(profile_index);
|
|
||||||
static ImGuiID delete_popup_id = drawDeleteProfilePopup(profile_index);
|
|
||||||
|
|
||||||
if(ImGui::BeginTable("##ManagerLayout", 2)) {
|
if(ImGui::BeginTable("##ManagerLayout", 2)) {
|
||||||
ImGui::TableSetupColumn("##Label", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("##Label", ImGuiTableColumnFlags_WidthStretch);
|
||||||
ImGui::TableSetupColumn("##Refresh", ImGuiTableColumnFlags_WidthFixed);
|
ImGui::TableSetupColumn("##Refresh", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
@ -50,15 +51,17 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::SmallButton("Backups")) {
|
if(ImGui::SmallButton("Backups")) {
|
||||||
_profileManager->refreshBackups();
|
_backupManager->refresh();
|
||||||
ImGui::OpenPopup(backup_list_popup_id);
|
ImGui::OpenPopup("Backups##BackupsModal");
|
||||||
}
|
}
|
||||||
|
drawBackupListPopup();
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
@ -77,12 +80,12 @@ void SaveTool::drawProfileManager() {
|
||||||
ImGui::TextUnformatted("Actions");
|
ImGui::TextUnformatted("Actions");
|
||||||
|
|
||||||
for(std::size_t i = 0; i < _profileManager->profiles().size(); ++i) {
|
for(std::size_t i = 0; i < _profileManager->profiles().size(); ++i) {
|
||||||
Profile& profile = _profileManager->profiles()[i];
|
GameObjects::Profile& profile = _profileManager->profiles()[i];
|
||||||
|
|
||||||
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))
|
||||||
{
|
{
|
||||||
|
@ -93,22 +96,25 @@ void SaveTool::drawProfileManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
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)) {
|
||||||
profile_index = i;
|
if(!_backupManager->create(_profileManager->profiles()[i])) {
|
||||||
ImGui::OpenPopup(backup_popup_id);
|
_queue.addToast(Toast::Type::Error, _backupManager->lastError(), std::chrono::seconds{5});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_queue.addToast(Toast::Type::Success, "Backup created successfully!"_s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
drawTooltip("Backup");
|
drawTooltip("Backup");
|
||||||
ImGui::SameLine(0.0f, 2.0f);
|
ImGui::SameLine(0.0f, 2.0f);
|
||||||
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) {
|
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) {
|
||||||
profile_index = i;
|
profile_index = i;
|
||||||
ImGui::OpenPopup(delete_popup_id);
|
ImGui::OpenPopup("Confirmation##DeleteProfileConfirmation");
|
||||||
}
|
}
|
||||||
drawTooltip("Delete");
|
drawTooltip("Delete");
|
||||||
|
drawDeleteProfilePopup(profile_index);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
|
@ -117,103 +123,20 @@ void SaveTool::drawProfileManager() {
|
||||||
ImGui::TextUnformatted("Click a profile to manage it.");
|
ImGui::TextUnformatted("Click a profile to manage it.");
|
||||||
}
|
}
|
||||||
|
|
||||||
drawBackupListPopup();
|
|
||||||
drawBackupProfilePopup(profile_index);
|
|
||||||
drawDeleteProfilePopup(profile_index);
|
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
void
|
||||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
Application::drawBackupListPopup() {
|
||||||
|
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f} / dpiScaling()}, ImGuiCond_Always, center_pivot);
|
||||||
if(!ImGui::BeginPopupModal("Backups##BackupsModal", nullptr,
|
if(!ImGui::BeginPopupModal("Backups##BackupsModal", nullptr,
|
||||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
||||||
{
|
{
|
||||||
return ImGui::GetID("Backups##BackupsModal");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::size_t backup_index;
|
static std::size_t backup_index;
|
||||||
|
|
||||||
if(ImGui::BeginPopupModal("Restore backup", nullptr,
|
|
||||||
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
|
|
||||||
{
|
|
||||||
ImGui::PushTextWrapPos(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.",
|
|
||||||
_profileManager->backups()[backup_index].company.data(),
|
|
||||||
_profileManager->backups()[backup_index].timestamp.year,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.month,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.day,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.hour,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.minute,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.second);
|
|
||||||
ImGui::PopTextWrapPos();
|
|
||||||
|
|
||||||
if(ImGui::BeginTable("##RestoreBackupLayout", 2)) {
|
|
||||||
ImGui::TableSetupColumn("##Dummy", ImGuiTableColumnFlags_WidthStretch);
|
|
||||||
ImGui::TableSetupColumn("##YesNo", ImGuiTableColumnFlags_WidthFixed);
|
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
|
||||||
if(ImGui::Button("Yes")) {
|
|
||||||
if(!_profileManager->restoreBackup(backup_index)) {
|
|
||||||
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
|
||||||
}
|
|
||||||
_profileManager->refreshProfiles();
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button("No", ImGui::GetItemRectSize())) {
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui::BeginPopupModal("Delete backup", nullptr,
|
|
||||||
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
|
|
||||||
{
|
|
||||||
ImGui::PushTextWrapPos(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.",
|
|
||||||
_profileManager->backups()[backup_index].company.data(),
|
|
||||||
_profileManager->backups()[backup_index].timestamp.year,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.month,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.day,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.hour,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.minute,
|
|
||||||
_profileManager->backups()[backup_index].timestamp.second);
|
|
||||||
ImGui::PopTextWrapPos();
|
|
||||||
|
|
||||||
if(ImGui::BeginTable("##DeleteBackupLayout", 2)) {
|
|
||||||
ImGui::TableSetupColumn("##Dummy", ImGuiTableColumnFlags_WidthStretch);
|
|
||||||
ImGui::TableSetupColumn("##YesNo", ImGuiTableColumnFlags_WidthFixed);
|
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
|
||||||
if(ImGui::Button("Yes")) {
|
|
||||||
if(!_profileManager->deleteBackup(backup_index)) {
|
|
||||||
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
|
||||||
}
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button("No", ImGui::GetItemRectSize())) {
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
static ImGuiID restore_backup_popup_id = ImGui::GetID("Restore backup");
|
|
||||||
static ImGuiID delete_backup_popup_id = ImGui::GetID("Delete backup");
|
|
||||||
|
|
||||||
if(ImGui::BeginTable("##BackupsLabelLayout", 2)) {
|
if(ImGui::BeginTable("##BackupsLabelLayout", 2)) {
|
||||||
ImGui::TableSetupColumn("##Label", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("##Label", ImGuiTableColumnFlags_WidthStretch);
|
||||||
ImGui::TableSetupColumn("##Refresh", ImGuiTableColumnFlags_WidthFixed);
|
ImGui::TableSetupColumn("##Refresh", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
@ -224,13 +147,13 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(1);
|
ImGui::TableSetColumnIndex(1);
|
||||||
if(ImGui::SmallButton("Refresh")) {
|
if(ImGui::SmallButton("Refresh")) {
|
||||||
_profileManager->refreshBackups();
|
_backupManager->refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(_profileManager->backups().isEmpty()) {
|
if(_backupManager->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,
|
||||||
|
@ -252,16 +175,17 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||||
ImGui::TableSetColumnIndex(3);
|
ImGui::TableSetColumnIndex(3);
|
||||||
ImGui::TextUnformatted("Actions");
|
ImGui::TextUnformatted("Actions");
|
||||||
|
|
||||||
for(std::size_t i = 0; i < _profileManager->backups().size(); ++i) {
|
//drawBackupFolder(_backupManager->vfs());
|
||||||
auto& backup = _profileManager->backups()[i];
|
|
||||||
|
for(std::size_t i = 0; i < _backupManager->backups().size(); ++i) {
|
||||||
|
auto& backup = _backupManager->backups()[i];
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(0);
|
ImGui::TableSetColumnIndex(0);
|
||||||
ImGui::TextUnformatted(backup.company.data());
|
ImGui::TextUnformatted(backup.company.cbegin(), backup.company.cend());
|
||||||
if(ImGui::IsItemHovered()) {
|
if(ImGui::IsItemHovered() && ImGui::BeginTooltip()) {
|
||||||
ImGui::BeginTooltip();
|
|
||||||
for(const auto& file : backup.includedFiles) {
|
for(const auto& file : backup.includedFiles) {
|
||||||
ImGui::TextUnformatted(file.data());
|
ImGui::TextUnformatted(file.cbegin());
|
||||||
}
|
}
|
||||||
ImGui::EndTooltip();
|
ImGui::EndTooltip();
|
||||||
}
|
}
|
||||||
|
@ -276,29 +200,29 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||||
backup.timestamp.second);
|
backup.timestamp.second);
|
||||||
|
|
||||||
ImGui::TableSetColumnIndex(2);
|
ImGui::TableSetColumnIndex(2);
|
||||||
ImGui::Text("%s%s",
|
ImGui::TextUnformatted(backup.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##RestoreBackupModal");
|
||||||
}
|
}
|
||||||
drawTooltip("Restore");
|
drawTooltip("Restore");
|
||||||
|
drawBackupRestorePopup(backup_index);
|
||||||
ImGui::SameLine(0.0f, 2.0f);
|
ImGui::SameLine(0.0f, 2.0f);
|
||||||
if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) {
|
if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) {
|
||||||
backup_index = i;
|
backup_index = i;
|
||||||
ImGui::OpenPopup(delete_backup_popup_id);
|
ImGui::OpenPopup("Delete backup##DeleteBackupModal");
|
||||||
}
|
}
|
||||||
drawTooltip("Delete");
|
drawTooltip("Delete");
|
||||||
|
drawBackupDeletePopup(backup_index);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PushTextWrapPos(ImGui::GetWindowContentRegionWidth());
|
ImGui::PushTextWrapPos(ImGui::GetContentRegionAvail().x);
|
||||||
ImGui::TextUnformatted("Hover over a company name to see which files are included in the backup.");
|
ImGui::TextUnformatted("Hover over a company name to see which files are included in the backup.");
|
||||||
ImGui::PopTextWrapPos();
|
ImGui::PopTextWrapPos();
|
||||||
|
|
||||||
|
@ -317,20 +241,91 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SaveTool::drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID {
|
void
|
||||||
if(!ImGui::BeginPopupModal("Include builds ?##IncludeBuildsDialog", nullptr,
|
Application::drawBackupFolder(const Managers::Vfs::Directory<Managers::Backup>& dir) {
|
||||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
if(dir.files().isEmpty() && dir.subdirs().isEmpty()) {
|
||||||
{
|
return;
|
||||||
return ImGui::GetID("Include builds ?##IncludeBuildsDialog");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TextUnformatted("Should builds be added to the backup ?");
|
for(auto& subdir : dir.subdirs()) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
bool open = ImGui::TreeNodeEx(subdir.name().cbegin(), ImGuiTreeNodeFlags_SpanAllColumns);
|
||||||
|
|
||||||
if(ImGui::BeginTable("##NameBackupLayout", 2)) {
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextDisabled("--");
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextDisabled("--");
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextDisabled("--");
|
||||||
|
|
||||||
|
if(open) {
|
||||||
|
drawBackupFolder(subdir);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto file : dir.files()) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TreeNodeEx(file->company.cbegin(), ImGuiTreeNodeFlags_SpanAllColumns|ImGuiTreeNodeFlags_Leaf|
|
||||||
|
ImGuiTreeNodeFlags_NoTreePushOnOpen);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%.4i-%.2i-%.2i %.2i:%.2i:%.2i",
|
||||||
|
file->timestamp.year,
|
||||||
|
file->timestamp.month,
|
||||||
|
file->timestamp.day,
|
||||||
|
file->timestamp.hour,
|
||||||
|
file->timestamp.minute,
|
||||||
|
file->timestamp.second);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted(file->demo ? "Demo" : "Full");
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::PushID(file);
|
||||||
|
if(ImGui::SmallButton(ICON_FA_UNDO)) {
|
||||||
|
//ImGui::OpenPopup("Restore backup##RestoreBackupModal");
|
||||||
|
}
|
||||||
|
drawTooltip("Restore");
|
||||||
|
//drawBackupRestorePopup(backup_index);
|
||||||
|
ImGui::SameLine(0.0f, 2.0f);
|
||||||
|
if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) {
|
||||||
|
//ImGui::OpenPopup("Delete backup##DeleteBackupModal");
|
||||||
|
}
|
||||||
|
drawTooltip("Delete");
|
||||||
|
//drawBackupDeletePopup(backup_index);
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawBackupRestorePopup(std::size_t backup_index) {
|
||||||
|
if(!ImGui::BeginPopupModal("Restore backup##RestoreBackupModal", nullptr,
|
||||||
|
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.50f);
|
||||||
|
ImGui::Text("Are you sure you want to restore the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ?\n\n"
|
||||||
|
"Any existing data will be overwritten.",
|
||||||
|
_backupManager->backups()[backup_index].company.data(),
|
||||||
|
_backupManager->backups()[backup_index].timestamp.year,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.month,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.day,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.hour,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.minute,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.second);
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
|
||||||
|
if(ImGui::BeginTable("##RestoreBackupLayout", 2)) {
|
||||||
ImGui::TableSetupColumn("##Dummy", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("##Dummy", ImGuiTableColumnFlags_WidthStretch);
|
||||||
ImGui::TableSetupColumn("##YesNo", ImGuiTableColumnFlags_WidthFixed);
|
ImGui::TableSetupColumn("##YesNo", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
|
||||||
|
@ -338,16 +333,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(!_backupManager->restore(backup_index)) {
|
||||||
|
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
||||||
|
}
|
||||||
|
if(!_profileManager->refreshProfiles()) {
|
||||||
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||||
|
_profileManager->lastError().data(), window());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
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);
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if(ImGui::Button("Cancel")) {
|
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,15 +352,58 @@ auto SaveTool::drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SaveTool::drawDeleteProfilePopup(std::size_t profile_index) -> ImGuiID {
|
void
|
||||||
|
Application::drawBackupDeletePopup(std::size_t backup_index) {
|
||||||
|
if(!ImGui::BeginPopupModal("Delete backup##DeleteBackupModal", nullptr,
|
||||||
|
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.50f);
|
||||||
|
ImGui::Text("Are you sure you want to delete the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ?\n\n"
|
||||||
|
"This operation is irreversible.",
|
||||||
|
_backupManager->backups()[backup_index].company.data(),
|
||||||
|
_backupManager->backups()[backup_index].timestamp.year,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.month,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.day,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.hour,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.minute,
|
||||||
|
_backupManager->backups()[backup_index].timestamp.second);
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
|
||||||
|
if(ImGui::BeginTable("##DeleteBackupLayout", 2)) {
|
||||||
|
ImGui::TableSetupColumn("##Dummy", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
ImGui::TableSetupColumn("##YesNo", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
if(ImGui::Button("Yes")) {
|
||||||
|
if(!_backupManager->remove(backup_index)) {
|
||||||
|
_queue.addToast(Toast::Type::Error, _profileManager->lastError());
|
||||||
|
}
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Button("No", ImGui::GetItemRectSize())) {
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawDeleteProfilePopup(std::size_t profile_index) {
|
||||||
if(!ImGui::BeginPopupModal("Confirmation##DeleteProfileConfirmation", nullptr,
|
if(!ImGui::BeginPopupModal("Confirmation##DeleteProfileConfirmation", nullptr,
|
||||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
||||||
{
|
{
|
||||||
return ImGui::GetID("Confirmation##DeleteProfileConfirmation");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool delete_builds = false;
|
static bool delete_builds = false;
|
||||||
|
@ -371,7 +411,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());
|
||||||
|
@ -401,6 +441,6 @@ auto SaveTool::drawDeleteProfilePopup(std::size_t profile_index) -> ImGuiID {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
95
src/Application/Application_UpdateChecker.cpp
Normal file
95
src/Application/Application_UpdateChecker.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Utility/Format.h>
|
||||||
|
|
||||||
|
#include <SDL_events.h>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
namespace mbst {
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::updateCheckEvent(SDL_Event& event) {
|
||||||
|
_updateThread.join();
|
||||||
|
|
||||||
|
switch(static_cast<UpdateChecker::Result>(event.user.code)) {
|
||||||
|
case UpdateChecker::Success:
|
||||||
|
_checkerMutex.lock();
|
||||||
|
if(_checker->updateAvailable()) {
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
_queue.addToast(Toast::Type::Warning,
|
||||||
|
"Your version is out of date and thus unsupported.\nCheck the settings for more information."_s, 5s);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(_checker->version() == current_version || (current_version > _checker->version() && current_version.prerelease)) {
|
||||||
|
_queue.addToast(Toast::Type::Success, "The application is already up to date."_s);
|
||||||
|
}
|
||||||
|
else if(_checker->version() > current_version && !current_version.prerelease) {
|
||||||
|
_queue.addToast(Toast::Type::Warning,
|
||||||
|
"Your version is more recent than the latest one in the repo. How???"_s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_checkerMutex.unlock();
|
||||||
|
break;
|
||||||
|
case UpdateChecker::HttpError:
|
||||||
|
_checkerMutex.lock();
|
||||||
|
_queue.addToast(Toast::Type::Error, _checker->error());
|
||||||
|
LOG_ERROR(_checker->error());
|
||||||
|
_checkerMutex.unlock();
|
||||||
|
break;
|
||||||
|
case UpdateChecker::CurlInitFailed:
|
||||||
|
_queue.addToast(Toast::Type::Error, "Couldn't initialise libcurl. Update check aborted."_s);
|
||||||
|
LOG_ERROR("Couldn't initialise libcurl. Update check aborted.");
|
||||||
|
break;
|
||||||
|
case UpdateChecker::CurlError:
|
||||||
|
{
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
_checkerMutex.lock();
|
||||||
|
_queue.addToast(Toast::Type::Error, _checker->error(), 10s);
|
||||||
|
LOG_ERROR(_checker->error());
|
||||||
|
_checkerMutex.unlock();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UpdateChecker::CurlTimeout:
|
||||||
|
_queue.addToast(Toast::Type::Error, "The request timed out."_s);
|
||||||
|
LOG_ERROR("The request timed out.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::checkForUpdates() {
|
||||||
|
SDL_Event event;
|
||||||
|
SDL_zero(event);
|
||||||
|
event.type = _updateEventId;
|
||||||
|
|
||||||
|
_checkerMutex.lock();
|
||||||
|
|
||||||
|
if(!_checker) {
|
||||||
|
_checker.emplace();
|
||||||
|
}
|
||||||
|
|
||||||
|
event.user.code = _checker->check();
|
||||||
|
|
||||||
|
_checkerMutex.unlock();
|
||||||
|
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,10 +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 "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,14 +22,21 @@
|
||||||
|
|
||||||
#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"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
extern const ImVec2 center_pivot;
|
extern const ImVec2 center_pivot;
|
||||||
|
|
||||||
void SaveTool::drawAbout() {
|
namespace mbst {
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::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,7 +62,7 @@ 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";
|
auto website = "https://williamjcm.ovh/mbst";
|
||||||
drawAlignedText(ICON_FA_GLOBE " %s", website);
|
drawAlignedText(ICON_FA_GLOBE " %s", website);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::Button("Copy to clipboard")) {
|
if(ImGui::Button("Copy to clipboard")) {
|
||||||
|
@ -68,7 +72,7 @@ void SaveTool::drawAbout() {
|
||||||
if(ImGui::Button("Open in browser")) {
|
if(ImGui::Button("Open in browser")) {
|
||||||
openUri(website);
|
openUri(website);
|
||||||
}
|
}
|
||||||
auto repo = "https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool";
|
auto repo = "https://git.williamjcm.ovh/williamjcm/MassBuilderSaveTool";
|
||||||
drawAlignedText(ICON_FA_GIT_ALT " %s", repo);
|
drawAlignedText(ICON_FA_GIT_ALT " %s", repo);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if(ImGui::Button("Copy to clipboard")) {
|
if(ImGui::Button("Copy to clipboard")) {
|
||||||
|
@ -82,12 +86,13 @@ void SaveTool::drawAbout() {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
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}, ImGuiChildFlags_Border)) {
|
||||||
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::TextEx(licence.data(), licence.data() + licence.size(), ImGuiTextFlags_None);
|
ImGui::TextUnformatted(licence.cbegin(), licence.cend());
|
||||||
ImGui::PopFont();
|
ImGui::PopFont();
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
@ -113,14 +118,6 @@ void SaveTool::drawAbout() {
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
ImGui::TextUnformatted("Licence: MIT");
|
||||||
|
|
||||||
static auto corrade_licence = _rs.getRaw("COPYING.Corrade");
|
|
||||||
if(ImGui::BeginChild("##CorradeLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextEx(corrade_licence.data(), corrade_licence.data() + corrade_licence.size(), ImGuiTextFlags_None);
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,14 +138,6 @@ void SaveTool::drawAbout() {
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
ImGui::TextUnformatted("Licence: MIT");
|
||||||
|
|
||||||
static auto magnum_licence = _rs.getRaw("COPYING.Magnum");
|
|
||||||
if(ImGui::BeginChild("##MagnumLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextEx(magnum_licence.data(), magnum_licence.data() + magnum_licence.size(), ImGuiTextFlags_None);
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,14 +156,6 @@ void SaveTool::drawAbout() {
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
ImGui::TextUnformatted("Licence: MIT");
|
||||||
|
|
||||||
static auto imgui_licence = _rs.getRaw("LICENSE.ImGui");
|
|
||||||
if(ImGui::BeginChild("##ImGuiLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextEx(imgui_licence.data(), imgui_licence.data() + imgui_licence.size(), ImGuiTextFlags_None);
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,14 +174,6 @@ void SaveTool::drawAbout() {
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: zlib");
|
ImGui::TextUnformatted("Licence: zlib");
|
||||||
|
|
||||||
static auto sdl_licence = _rs.getRaw("LICENSE.SDL");
|
|
||||||
if(ImGui::BeginChild("##SDLLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextEx(sdl_licence.data(), sdl_licence.data() + sdl_licence.size(), ImGuiTextFlags_None);
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,14 +192,6 @@ void SaveTool::drawAbout() {
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: 3-clause BSD");
|
ImGui::TextUnformatted("Licence: 3-clause BSD");
|
||||||
|
|
||||||
static auto libzip_licence = _rs.getRaw("LICENSE.libzip");
|
|
||||||
if(ImGui::BeginChild("##libzipLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextEx(libzip_licence.data(), libzip_licence.data() + libzip_licence.size(), ImGuiTextFlags_None);
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,18 +209,11 @@ void SaveTool::drawAbout() {
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: MIT");
|
ImGui::TextUnformatted("Licence: MIT");
|
||||||
|
|
||||||
static auto efsw_licence = _rs.getRaw("LICENSE.efsw");
|
|
||||||
if(ImGui::BeginChild("##efswLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextEx(efsw_licence.data(), efsw_licence.data() + efsw_licence.size(), ImGuiTextFlags_None);
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ImGui::TreeNodeEx("libcurl", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
if(ImGui::TreeNodeEx("libcurl", ImGuiTreeNodeFlags_SpanAvailWidth)) {
|
||||||
|
ImGui::Text("Version used: %s", LIBCURL_VERSION);
|
||||||
auto curl_website = "https://curl.se/libcurl";
|
auto curl_website = "https://curl.se/libcurl";
|
||||||
drawAlignedText(ICON_FA_GLOBE " %s", curl_website);
|
drawAlignedText(ICON_FA_GLOBE " %s", curl_website);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
@ -269,14 +227,6 @@ void SaveTool::drawAbout() {
|
||||||
|
|
||||||
ImGui::TextUnformatted("Licence: MIT/X derivative");
|
ImGui::TextUnformatted("Licence: MIT/X derivative");
|
||||||
|
|
||||||
static auto curl_licence = _rs.getRaw("LICENSE.curl");
|
|
||||||
if(ImGui::BeginChild("##libcurlLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
|
|
||||||
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
|
|
||||||
ImGui::TextEx(curl_licence.data(), curl_licence.data() + curl_licence.size(), ImGuiTextFlags_None);
|
|
||||||
ImGui::PopFont();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,3 +270,5 @@ void SaveTool::drawAbout() {
|
||||||
|
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
277
src/Application/Application_drawMainMenu.cpp
Normal file
277
src/Application/Application_drawMainMenu.cpp
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Utility/Path.h>
|
||||||
|
|
||||||
|
#include "../Configuration/Configuration.h"
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||||
|
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
namespace mbst {
|
||||||
|
|
||||||
|
void
|
||||||
|
Application::drawMainMenu() {
|
||||||
|
if(!ImGui::BeginMainMenuBar()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginMenu("Save Tool##SaveToolMenu")) {
|
||||||
|
if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open game data directory")) {
|
||||||
|
if(ImGui::MenuItem(ICON_FA_COG " Configuration", nullptr, false,
|
||||||
|
Utility::Path::exists(conf().directories().gameConfig)))
|
||||||
|
{
|
||||||
|
openUri(Utility::Path::toNativeSeparators(conf().directories().gameConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::MenuItem(ICON_FA_SAVE " Saves", nullptr, false,
|
||||||
|
Utility::Path::exists(conf().directories().gameSaves)))
|
||||||
|
{
|
||||||
|
openUri(Utility::Path::toNativeSeparators(conf().directories().gameSaves));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::MenuItem(ICON_FA_IMAGE " Screenshots", nullptr, false,
|
||||||
|
Utility::Path::exists(conf().directories().gameScreenshots)))
|
||||||
|
{
|
||||||
|
openUri(Utility::Path::toNativeSeparators(conf().directories().gameScreenshots));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open manager directory")) {
|
||||||
|
if(ImGui::MenuItem(ICON_FA_FILE_ARCHIVE " Profile backups", nullptr, false,
|
||||||
|
Utility::Path::exists(conf().directories().backups)))
|
||||||
|
{
|
||||||
|
openUri(Utility::Path::toNativeSeparators(conf().directories().backups));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::MenuItem(ICON_FA_EXCHANGE_ALT " Staging area", nullptr, false,
|
||||||
|
Utility::Path::exists(conf().directories().staging)))
|
||||||
|
{
|
||||||
|
openUri(Utility::Path::toNativeSeparators(conf().directories().staging));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if(ImGui::BeginMenu(ICON_FA_BOXES " Armoury")) {
|
||||||
|
if(ImGui::MenuItem(ICON_FA_SHIELD_ALT " Armour parts", nullptr, false,
|
||||||
|
Utility::Path::exists(conf().directories().armours)))
|
||||||
|
{
|
||||||
|
openUri(Utility::Path::toNativeSeparators(conf().directories().armours));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::MenuItem(ICON_FA_HAMMER " Weapons", nullptr, false,
|
||||||
|
Utility::Path::exists(conf().directories().weapons)))
|
||||||
|
{
|
||||||
|
openUri(Utility::Path::toNativeSeparators(conf().directories().weapons));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::MenuItem(ICON_FA_PALETTE " Custom styles", nullptr, false,
|
||||||
|
Utility::Path::exists(conf().directories().styles)))
|
||||||
|
{
|
||||||
|
openUri(Utility::Path::toNativeSeparators(conf().directories().styles));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if(ImGui::BeginMenu(ICON_FA_COG " Settings")) {
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
drawAlignedText("Vertical sync:");
|
||||||
|
if(conf().swapInterval() == 0) {
|
||||||
|
drawAlignedText("FPS cap:");
|
||||||
|
}
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
static const char* framelimit_labels[] = {
|
||||||
|
"Off",
|
||||||
|
"Every VBLANK",
|
||||||
|
"Every second VBLANK",
|
||||||
|
"Every third VBLANK",
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGui::PushItemWidth(300.0f);
|
||||||
|
|
||||||
|
if(ImGui::BeginCombo("##FrameLimit", framelimit_labels[conf().swapInterval()])) {
|
||||||
|
for(int i = 0; i <= 3; i++) {
|
||||||
|
if(ImGui::Selectable(framelimit_labels[i], conf().swapInterval() == i)) {
|
||||||
|
conf().setSwapInterval(i);
|
||||||
|
setSwapInterval(i);
|
||||||
|
if(i == 0) {
|
||||||
|
setMinimalLoopPeriod(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(conf().swapInterval() == 0) {
|
||||||
|
static float fps_cap = conf().fpsCap();
|
||||||
|
if(ImGui::SliderFloat("##FpsCapSlider", &fps_cap, 15.0f, 301.0f,
|
||||||
|
conf().fpsCap() != 301.0f ? "%.0f" : "Uncapped", ImGuiSliderFlags_AlwaysClamp))
|
||||||
|
{
|
||||||
|
conf().setFpsCap(fps_cap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
|
||||||
|
if(drawCheckbox("Cheat mode", conf().cheatMode())) {
|
||||||
|
conf().setCheatMode(!conf().cheatMode());
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
drawHelpMarker("This gives access to save edition features that can be considered cheats.",
|
||||||
|
float(windowSize().x()) * 0.4f);
|
||||||
|
|
||||||
|
if(drawCheckbox("Advanced mode", conf().advancedMode())) {
|
||||||
|
conf().setAdvancedMode(!conf().advancedMode());
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
drawHelpMarker("This gives access to editing values that have unknown purposes or are undocumented.",
|
||||||
|
float(windowSize().x()) * 0.4f);
|
||||||
|
|
||||||
|
if(drawCheckbox("Check for updates on startup", conf().checkUpdatesOnStartup())) {
|
||||||
|
conf().setCheckUpdatesOnStartup(!conf().checkUpdatesOnStartup());
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Button(ICON_FA_SYNC_ALT " Check now")) {
|
||||||
|
_queue.addToast(Toast::Type::Default, "Checking for updates...");
|
||||||
|
_updateThread = std::thread{[this]{ checkForUpdates(); }};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_checker && _checkerMutex.try_lock()) {
|
||||||
|
if(_checker->updateAvailable()) {
|
||||||
|
drawAlignedText("Version %s is available.", Containers::String{_checker->version()}.data());
|
||||||
|
if(ImGui::Button(ICON_FA_FILE_SIGNATURE " Release notes")) {
|
||||||
|
openUri("https://williamjcm.ovh/mbst");
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if(ImGui::Button(ICON_FA_DOWNLOAD " Download now")) {
|
||||||
|
openUri(_checker->downloadLink());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_checkerMutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(drawCheckbox("Skip disclaimer", conf().skipDisclaimer())) {
|
||||||
|
conf().setSkipDisclaimer(!conf().skipDisclaimer());
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if(ImGui::MenuItem(ICON_FA_SIGN_OUT_ALT " Quit##QuitMenuItem")) {
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::BeginDisabled(conf().isRunningInWine());
|
||||||
|
if(ImGui::BeginMenu("Game##GameMenu")) {
|
||||||
|
if(ImGui::MenuItem(ICON_FA_PLAY " Run demo##RunDemoMenuItem")) {
|
||||||
|
openUri("steam://run/1048390");
|
||||||
|
}
|
||||||
|
drawTooltip("Will not work if you have the full game.");
|
||||||
|
|
||||||
|
if(ImGui::MenuItem(ICON_FA_PLAY " Run full game##RunFullGameMenuItem")) {
|
||||||
|
openUri("steam://run/956680");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if(ImGui::BeginMenu(ICON_FA_DISCORD " Discord communities")) {
|
||||||
|
if(ImGui::MenuItem("Official server")) {
|
||||||
|
openUri("https://discord.gg/sekai-project");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ImGui::MenuItem("Community server")) {
|
||||||
|
openUri("https://discord.gg/massbuildercommunity");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
if(conf().isRunningInWine() && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
|
||||||
|
ImGui::SetTooltip("Not available when running in Wine.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SAVETOOL_DEBUG_BUILD
|
||||||
|
if(ImGui::BeginMenu("Debug tools")) {
|
||||||
|
ImGui::MenuItem("ImGui demo window", nullptr, &_demoWindow);
|
||||||
|
ImGui::MenuItem("ImGui style editor", nullptr, &_styleEditor);
|
||||||
|
ImGui::MenuItem("ImGui metrics window", nullptr, &_metricsWindow);
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(ImGui::BeginMenu("Help")) {
|
||||||
|
if(ImGui::BeginMenu(ICON_FA_KEYBOARD " Keyboard shortcuts")) {
|
||||||
|
ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
|
||||||
|
ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
|
||||||
|
ImGui::BulletText("While inputing text:\n");
|
||||||
|
ImGui::Indent();
|
||||||
|
ImGui::BulletText("CTRL+Left/Right to word jump.");
|
||||||
|
ImGui::BulletText("CTRL+A or double-click to select all.");
|
||||||
|
ImGui::BulletText("CTRL+X/C/V to use clipboard cut/copy/paste.");
|
||||||
|
ImGui::BulletText("CTRL+Z,CTRL+Y to undo/redo.");
|
||||||
|
ImGui::BulletText("ESCAPE to revert.");
|
||||||
|
ImGui::BulletText("You can apply arithmetic operators +,*,/ on numerical values.\nUse +- to subtract.");
|
||||||
|
ImGui::Unindent();
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
ImGui::MenuItem(ICON_FA_INFO_CIRCLE " About", nullptr, &_aboutPopup);
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_gameCheckTimerId != 0) {
|
||||||
|
if(ImGui::BeginTable("##MainMenuLayout", 2)) {
|
||||||
|
ImGui::TableSetupColumn("##Dummy", ImGuiTableColumnFlags_WidthStretch);
|
||||||
|
ImGui::TableSetupColumn("##GameState", ImGuiTableColumnFlags_WidthFixed);
|
||||||
|
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableSetColumnIndex(1);
|
||||||
|
drawGameState();
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/BinaryIo/BinaryIo.h
Normal file
24
src/BinaryIo/BinaryIo.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace BinaryIo {
|
||||||
|
|
||||||
|
class Reader;
|
||||||
|
class Writer;
|
||||||
|
|
||||||
|
}
|
150
src/BinaryIo/Reader.cpp
Normal file
150
src/BinaryIo/Reader.cpp
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/Array.h>
|
||||||
|
#include <Corrade/Containers/String.h>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "Reader.h"
|
||||||
|
|
||||||
|
namespace BinaryIo {
|
||||||
|
|
||||||
|
Reader::Reader(Containers::StringView filename) {
|
||||||
|
_file = std::fopen(filename.data(), "rb");
|
||||||
|
|
||||||
|
if(!_file) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't open {} for reading: {}", filename, std::strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Reader::~Reader() {
|
||||||
|
closeFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::open() {
|
||||||
|
return _file;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::eof() {
|
||||||
|
return std::feof(_file) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
Reader::position() {
|
||||||
|
return _ftelli64(_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::seek(std::int64_t position) {
|
||||||
|
return _fseeki64(_file, position, SEEK_SET) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::closeFile() {
|
||||||
|
std::fclose(_file);
|
||||||
|
_file = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readChar(char& value) {
|
||||||
|
return std::fread(&value, sizeof(char), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readInt8(std::int8_t& value) {
|
||||||
|
return std::fread(&value, sizeof(std::int8_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readUint8(std::uint8_t& value) {
|
||||||
|
return std::fread(&value, sizeof(std::uint8_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readInt16(std::int16_t& value) {
|
||||||
|
return std::fread(&value, sizeof(std::int16_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readUint16(std::uint16_t& value) {
|
||||||
|
return std::fread(&value, sizeof(std::uint16_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readInt32(std::int32_t& value) {
|
||||||
|
return std::fread(&value, sizeof(std::int32_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readUint32(std::uint32_t& value) {
|
||||||
|
return std::fread(&value, sizeof(std::uint32_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readInt64(std::int64_t& value) {
|
||||||
|
return std::fread(&value, sizeof(std::int64_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readUint64(std::uint64_t& value) {
|
||||||
|
return std::fread(&value, sizeof(std::uint64_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readFloat(float& value) {
|
||||||
|
return std::fread(&value, sizeof(float), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readDouble(double& value) {
|
||||||
|
return std::fread(&value, sizeof(double), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readArray(Containers::Array<char>& array, std::size_t count) {
|
||||||
|
if(array.size() < count) {
|
||||||
|
array = Containers::Array<char>{ValueInit, count};
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::fread(array.data(), sizeof(char), count, _file) == count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readUEString(Containers::String& str) {
|
||||||
|
std::uint32_t length = 0;
|
||||||
|
if(!readUint32(length) || length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = Containers::String{ValueInit, length - 1};
|
||||||
|
|
||||||
|
return std::fread(str.data(), sizeof(char), length, _file) == length;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
Reader::peekChar() {
|
||||||
|
std::int32_t c;
|
||||||
|
c = std::fgetc(_file);
|
||||||
|
std::ungetc(c, _file);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
80
src/BinaryIo/Reader.h
Normal file
80
src/BinaryIo/Reader.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/Containers.h>
|
||||||
|
#include <Corrade/Containers/StaticArray.h>
|
||||||
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
|
||||||
|
namespace BinaryIo {
|
||||||
|
|
||||||
|
class Reader {
|
||||||
|
public:
|
||||||
|
explicit Reader(Containers::StringView filename);
|
||||||
|
~Reader();
|
||||||
|
|
||||||
|
Reader(const Reader& other) = delete;
|
||||||
|
Reader& operator=(const Reader& other) = delete;
|
||||||
|
|
||||||
|
Reader(Reader&& other) = default;
|
||||||
|
Reader& operator=(Reader&& other) = default;
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
bool eof();
|
||||||
|
auto position() -> std::int64_t;
|
||||||
|
|
||||||
|
bool seek(std::int64_t position);
|
||||||
|
|
||||||
|
void closeFile();
|
||||||
|
|
||||||
|
bool readChar(char& value);
|
||||||
|
bool readInt8(std::int8_t& value);
|
||||||
|
bool readUint8(std::uint8_t& value);
|
||||||
|
bool readInt16(std::int16_t& value);
|
||||||
|
bool readUint16(std::uint16_t& value);
|
||||||
|
bool readInt32(std::int32_t& value);
|
||||||
|
bool readUint32(std::uint32_t& value);
|
||||||
|
bool readInt64(std::int64_t& value);
|
||||||
|
bool readUint64(std::uint64_t& value);
|
||||||
|
bool readFloat(float& value);
|
||||||
|
bool readDouble(double& value);
|
||||||
|
bool readArray(Containers::Array<char>& array, std::size_t count);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool readValue(T& value) {
|
||||||
|
return fread(&value, sizeof(T), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t S>
|
||||||
|
bool readStaticArray(Containers::StaticArray<S, char>& array) {
|
||||||
|
return std::fread(array.data(), sizeof(char), S, _file) == S;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readUEString(Containers::String& str);
|
||||||
|
|
||||||
|
auto peekChar() -> std::int32_t;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::FILE* _file = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
163
src/BinaryIo/Writer.cpp
Normal file
163
src/BinaryIo/Writer.cpp
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "Writer.h"
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace BinaryIo {
|
||||||
|
|
||||||
|
Writer::Writer(Containers::StringView filename) {
|
||||||
|
_file = std::fopen(filename.data(), "wb");
|
||||||
|
if(!_file) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't open {} for reading: {}", filename, std::strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer::~Writer() {
|
||||||
|
closeFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::open() {
|
||||||
|
return _file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Writer::closeFile() {
|
||||||
|
std::fflush(_file);
|
||||||
|
std::fclose(_file);
|
||||||
|
_file = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int64_t
|
||||||
|
Writer::position() {
|
||||||
|
return _ftelli64(_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<const char>
|
||||||
|
Writer::array() const {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
Writer::arrayPosition() const {
|
||||||
|
return _index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::flushToFile() {
|
||||||
|
bool ret = writeArray(_data);
|
||||||
|
std::fflush(_file);
|
||||||
|
_data = Containers::Array<char>{};
|
||||||
|
_index = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeChar(char value) {
|
||||||
|
return std::fwrite(&value, sizeof(char), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeInt8(std::int8_t value) {
|
||||||
|
return std::fwrite(&value, sizeof(std::int8_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeUint8(std::uint8_t value) {
|
||||||
|
return std::fwrite(&value, sizeof(std::uint8_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeInt16(std::int16_t value) {
|
||||||
|
return std::fwrite(&value, sizeof(std::int16_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeUint16(std::uint16_t value) {
|
||||||
|
return std::fwrite(&value, sizeof(std::uint16_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeInt32(std::int32_t value) {
|
||||||
|
return std::fwrite(&value, sizeof(std::int32_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeUint32(std::uint32_t value) {
|
||||||
|
return std::fwrite(&value, sizeof(std::uint32_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeInt64(std::int64_t value) {
|
||||||
|
return std::fwrite(&value, sizeof(std::int64_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeUint64(std::uint64_t value) {
|
||||||
|
return std::fwrite(&value, sizeof(std::uint64_t), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeFloat(float value) {
|
||||||
|
return std::fwrite(&value, sizeof(float), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeDouble(double value) {
|
||||||
|
return std::fwrite(&value, sizeof(double), 1, _file) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeArray(Containers::ArrayView<const char> array) {
|
||||||
|
if(array.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::fwrite(array.data(), sizeof(char), array.size(), _file) == array.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Writer::writeUEString(Containers::StringView str) {
|
||||||
|
if(str.size() > UINT32_MAX) {
|
||||||
|
LOG_ERROR_FORMAT("String is too big. Expected size() < UINT32_MAX, got {} instead.", str.size());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeUint32(static_cast<std::uint32_t>(str.size()) + 1);
|
||||||
|
|
||||||
|
if(str.size() > 0) {
|
||||||
|
std::size_t count = std::fwrite(str.data(), sizeof(char), str.size(), _file);
|
||||||
|
if(count != str.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return writeChar('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
Writer::writeUEStringToArray(Containers::StringView value) {
|
||||||
|
return writeValueToArray<std::uint32_t>(std::uint32_t(value.size()) + 1u) +
|
||||||
|
writeDataToArray(Containers::ArrayView<const char>{value}) +
|
||||||
|
writeValueToArray<char>('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,6 +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 <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include <Corrade/Containers/ArrayView.h>
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
|
@ -23,81 +24,80 @@
|
||||||
#include <Corrade/Containers/StaticArray.h>
|
#include <Corrade/Containers/StaticArray.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
class BinaryWriter {
|
namespace BinaryIo {
|
||||||
|
|
||||||
|
class Writer {
|
||||||
public:
|
public:
|
||||||
explicit BinaryWriter(Containers::StringView filename);
|
explicit Writer(Containers::StringView filename);
|
||||||
~BinaryWriter();
|
~Writer();
|
||||||
|
|
||||||
BinaryWriter(const BinaryWriter& other) = delete;
|
Writer(const Writer& other) = delete;
|
||||||
BinaryWriter& operator=(const BinaryWriter& other) = delete;
|
Writer& operator=(const Writer& other) = delete;
|
||||||
|
|
||||||
BinaryWriter(BinaryWriter&& other) = default;
|
Writer(Writer&& other) = default;
|
||||||
BinaryWriter& operator=(BinaryWriter&& other) = default;
|
Writer& operator=(Writer&& other) = default;
|
||||||
|
|
||||||
auto open() -> bool;
|
bool open();
|
||||||
|
|
||||||
void closeFile();
|
void closeFile();
|
||||||
|
|
||||||
auto position() -> Long;
|
auto position() -> std::int64_t;
|
||||||
|
|
||||||
auto array() const -> Containers::ArrayView<const char>;
|
auto array() const -> Containers::ArrayView<const char>;
|
||||||
auto arrayPosition() const -> UnsignedLong;
|
auto arrayPosition() const -> std::size_t;
|
||||||
auto flushToFile() -> bool;
|
bool flushToFile();
|
||||||
|
|
||||||
auto writeByte(Byte value) -> bool;
|
bool writeChar(char value);
|
||||||
auto writeChar(char value) -> bool;
|
bool writeInt8(std::int8_t value);
|
||||||
auto writeUnsignedByte(UnsignedByte value) -> bool;
|
bool writeUint8(std::uint8_t value);
|
||||||
auto writeShort(Short value) -> bool;
|
bool writeInt16(std::int16_t value);
|
||||||
auto writeUnsignedShort(UnsignedShort value) -> bool;
|
bool writeUint16(std::uint16_t value);
|
||||||
auto writeInt(Int value) -> bool;
|
bool writeInt32(std::int32_t value);
|
||||||
auto writeUnsignedInt(UnsignedInt value) -> bool;
|
bool writeUint32(std::uint32_t value);
|
||||||
auto writeLong(Long value) -> bool;
|
bool writeInt64(std::int64_t value);
|
||||||
auto writeUnsignedLong(UnsignedLong value) -> bool;
|
bool writeUint64(std::uint64_t value);
|
||||||
auto writeFloat(Float value) -> bool;
|
bool writeFloat(float value);
|
||||||
auto writeDouble(Double value) -> bool;
|
bool writeDouble(double value);
|
||||||
auto writeArray(Containers::ArrayView<const char> array) -> bool;
|
bool writeArray(Containers::ArrayView<const char> array);
|
||||||
template<std::size_t size>
|
template<std::size_t size>
|
||||||
auto writeString(const char(&str)[size]) -> bool {
|
bool writeString(const char(&str)[size]) {
|
||||||
return writeArray({str, size - 1});
|
return writeArray({str, size - 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t S>
|
template<std::size_t S>
|
||||||
auto writeStaticArray(Containers::StaticArrayView<S, const char> array) -> bool {
|
bool writeStaticArray(Containers::StaticArrayView<S, const char> array) {
|
||||||
return std::fwrite(array.data(), sizeof(char), S, _file) == S;
|
return std::fwrite(array.data(), sizeof(char), S, _file) == S;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writeUEString(Containers::StringView str) -> bool;
|
bool writeUEString(Containers::StringView str);
|
||||||
|
|
||||||
template<typename T, typename U = std::conditional_t<std::is_trivially_copyable<T>::value, T, T&>>
|
template<typename T, typename U = std::conditional_t<std::is_trivially_copyable<T>::value, T, T&>>
|
||||||
auto writeValueToArray(U value) -> UnsignedLong {
|
auto writeValueToArray(U value) -> std::size_t {
|
||||||
Containers::ArrayView<T> view{&value, 1};
|
Containers::ArrayView<T> view{&value, 1};
|
||||||
return writeDataToArray(view);
|
return writeDataToArray(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto writeUEStringToArray(Containers::StringView value) -> UnsignedLong;
|
auto writeUEStringToArray(Containers::StringView value) -> std::size_t;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void writeValueToArrayAt(T& value, UnsignedLong position) {
|
void writeValueToArrayAt(T& value, std::size_t position) {
|
||||||
Containers::ArrayView<T> view{&value, 1};
|
Containers::ArrayView<T> view{&value, 1};
|
||||||
writeDataToArrayAt(view, position);
|
writeDataToArrayAt(view, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
auto writeDataToArray(Containers::ArrayView<T> view) -> UnsignedLong {
|
auto writeDataToArray(Containers::ArrayView<T> view) -> std::size_t {
|
||||||
arrayAppend(_data, Containers::arrayCast<const char>(view));
|
arrayAppend(_data, Containers::arrayCast<const char>(view));
|
||||||
_index += sizeof(T) * view.size();
|
_index += sizeof(T) * view.size();
|
||||||
return sizeof(T) * view.size();
|
return sizeof(T) * view.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void writeDataToArrayAt(Containers::ArrayView<T> view, UnsignedLong position) {
|
void writeDataToArrayAt(Containers::ArrayView<T> view, std::size_t position) {
|
||||||
auto casted_view = Containers::arrayCast<const char>(view);
|
auto casted_view = Containers::arrayCast<const char>(view);
|
||||||
for(UnsignedLong i = 0; i < casted_view.size(); i++) {
|
for(std::size_t i = 0; i < casted_view.size(); i++) {
|
||||||
_data[position + i] = casted_view[i];
|
_data[position + i] = casted_view[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,5 +106,7 @@ class BinaryWriter {
|
||||||
FILE* _file = nullptr;
|
FILE* _file = nullptr;
|
||||||
|
|
||||||
Containers::Array<char> _data;
|
Containers::Array<char> _data;
|
||||||
UnsignedLong _index = 0;
|
std::size_t _index = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
# MassBuilderSaveTool
|
# MassBuilderSaveTool
|
||||||
# Copyright (C) 2021-2022 Guillaume Jacquemin
|
# Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
#
|
#
|
||||||
# This program is free software: you can redistribute it and/or modify
|
# 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
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,164 +14,236 @@
|
||||||
# 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/>.
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
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.5)
|
set(SAVETOOL_PROJECT_VERSION 1.5.2)
|
||||||
|
|
||||||
find_package(Corrade REQUIRED Main Containers Utility Interconnect)
|
find_package(Corrade REQUIRED Containers Utility)
|
||||||
|
if(CORRADE_TARGET_WINDOWS)
|
||||||
|
find_package(Corrade REQUIRED Main)
|
||||||
|
endif()
|
||||||
find_package(Magnum REQUIRED GL Sdl2Application)
|
find_package(Magnum REQUIRED GL Sdl2Application)
|
||||||
find_package(MagnumIntegration REQUIRED ImGui)
|
find_package(MagnumIntegration REQUIRED ImGui)
|
||||||
|
|
||||||
|
if(SAVETOOL_USE_SYSTEM_LIBZIP)
|
||||||
|
find_package(libzip REQUIRED)
|
||||||
|
endif(SAVETOOL_USE_SYSTEM_LIBZIP)
|
||||||
|
|
||||||
|
if(SAVETOOL_USE_SYSTEM_EFSW)
|
||||||
|
find_package(efsw REQUIRED)
|
||||||
|
endif(SAVETOOL_USE_SYSTEM_EFSW)
|
||||||
|
|
||||||
|
if(SAVETOOL_USE_SYSTEM_LIBCURL)
|
||||||
|
find_package(CURL REQUIRED HTTPS)
|
||||||
|
endif(SAVETOOL_USE_SYSTEM_LIBCURL)
|
||||||
|
|
||||||
set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON)
|
set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON)
|
||||||
|
|
||||||
corrade_add_resource(Assets assets.conf)
|
corrade_add_resource(Assets assets.conf)
|
||||||
|
|
||||||
add_library(UESaveFile STATIC EXCLUDE_FROM_ALL
|
set(Logger_SOURCES
|
||||||
UESaveFile/Serialisers/AbstractUnrealCollectionPropertySerialiser.h
|
Logger/Logger.h
|
||||||
UESaveFile/Serialisers/AbstractUnrealPropertySerialiser.h
|
Logger/Logger.cpp
|
||||||
UESaveFile/Serialisers/AbstractUnrealStructSerialiser.h
|
Logger/EntryType.h
|
||||||
UESaveFile/Serialisers/ArrayPropertySerialiser.h
|
Logger/MagnumLogBuffer.h
|
||||||
UESaveFile/Serialisers/ArrayPropertySerialiser.cpp
|
Logger/MagnumLogBuffer.cpp
|
||||||
UESaveFile/Serialisers/BoolPropertySerialiser.h
|
)
|
||||||
UESaveFile/Serialisers/BoolPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/BytePropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/BytePropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/ColourPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/ColourPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/DateTimePropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/DateTimePropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/EnumPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/EnumPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/FloatPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/FloatPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/GuidPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/GuidPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/IntPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/IntPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/MapPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/MapPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/ResourcePropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/ResourcePropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/RotatorPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/RotatorPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/StringPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/StringPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/SetPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/SetPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/StructSerialiser.h
|
|
||||||
UESaveFile/Serialisers/StructSerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/TextPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/TextPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/UnrealPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/VectorPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/VectorPropertySerialiser.cpp
|
|
||||||
UESaveFile/Serialisers/Vector2DPropertySerialiser.h
|
|
||||||
UESaveFile/Serialisers/Vector2DPropertySerialiser.cpp
|
|
||||||
|
|
||||||
UESaveFile/Types/ArrayProperty.h
|
set(BinaryIo_SOURCES
|
||||||
UESaveFile/Types/BoolProperty.h
|
BinaryIo/BinaryIo.h
|
||||||
UESaveFile/Types/ByteProperty.h
|
BinaryIo/Reader.h
|
||||||
UESaveFile/Types/ColourStructProperty.h
|
BinaryIo/Reader.cpp
|
||||||
UESaveFile/Types/DateTimeStructProperty.h
|
BinaryIo/Writer.h
|
||||||
UESaveFile/Types/EnumProperty.h
|
BinaryIo/Writer.cpp
|
||||||
UESaveFile/Types/FloatProperty.h
|
)
|
||||||
UESaveFile/Types/GenericStructProperty.h
|
|
||||||
UESaveFile/Types/GuidStructProperty.h
|
|
||||||
UESaveFile/Types/IntProperty.h
|
|
||||||
UESaveFile/Types/MapProperty.h
|
|
||||||
UESaveFile/Types/NoneProperty.h
|
|
||||||
UESaveFile/Types/RotatorStructProperty.h
|
|
||||||
UESaveFile/Types/SetProperty.h
|
|
||||||
UESaveFile/Types/StringProperty.h
|
|
||||||
UESaveFile/Types/StructProperty.h
|
|
||||||
UESaveFile/Types/ResourceItemValue.h
|
|
||||||
UESaveFile/Types/TextProperty.h
|
|
||||||
UESaveFile/Types/UnrealProperty.h
|
|
||||||
UESaveFile/Types/UnrealPropertyBase.h
|
|
||||||
UESaveFile/Types/VectorStructProperty.h
|
|
||||||
|
|
||||||
UESaveFile/Debug.h
|
set(Gvas_SOURCES
|
||||||
UESaveFile/Debug.cpp
|
Gvas/Serialisers/Serialisers.h
|
||||||
UESaveFile/UESaveFile.h
|
Gvas/Serialisers/AbstractUnrealCollectionProperty.h
|
||||||
UESaveFile/UESaveFile.cpp
|
Gvas/Serialisers/AbstractUnrealProperty.h
|
||||||
UESaveFile/BinaryReader.h
|
Gvas/Serialisers/AbstractUnrealStruct.h
|
||||||
UESaveFile/BinaryReader.cpp
|
Gvas/Serialisers/ArrayProperty.h
|
||||||
UESaveFile/BinaryWriter.h
|
Gvas/Serialisers/ArrayProperty.cpp
|
||||||
UESaveFile/BinaryWriter.cpp
|
Gvas/Serialisers/BoolProperty.h
|
||||||
UESaveFile/PropertySerialiser.h
|
Gvas/Serialisers/BoolProperty.cpp
|
||||||
UESaveFile/PropertySerialiser.cpp)
|
Gvas/Serialisers/ByteProperty.h
|
||||||
|
Gvas/Serialisers/ByteProperty.cpp
|
||||||
|
Gvas/Serialisers/ColourProperty.h
|
||||||
|
Gvas/Serialisers/ColourProperty.cpp
|
||||||
|
Gvas/Serialisers/DateTimeProperty.h
|
||||||
|
Gvas/Serialisers/DateTimeProperty.cpp
|
||||||
|
Gvas/Serialisers/EnumProperty.h
|
||||||
|
Gvas/Serialisers/EnumProperty.cpp
|
||||||
|
Gvas/Serialisers/FloatProperty.h
|
||||||
|
Gvas/Serialisers/FloatProperty.cpp
|
||||||
|
Gvas/Serialisers/GuidProperty.h
|
||||||
|
Gvas/Serialisers/GuidProperty.cpp
|
||||||
|
Gvas/Serialisers/IntProperty.h
|
||||||
|
Gvas/Serialisers/IntProperty.cpp
|
||||||
|
Gvas/Serialisers/MapProperty.h
|
||||||
|
Gvas/Serialisers/MapProperty.cpp
|
||||||
|
Gvas/Serialisers/ResourceProperty.h
|
||||||
|
Gvas/Serialisers/ResourceProperty.cpp
|
||||||
|
Gvas/Serialisers/RotatorProperty.h
|
||||||
|
Gvas/Serialisers/RotatorProperty.cpp
|
||||||
|
Gvas/Serialisers/StringProperty.h
|
||||||
|
Gvas/Serialisers/StringProperty.cpp
|
||||||
|
Gvas/Serialisers/SetProperty.h
|
||||||
|
Gvas/Serialisers/SetProperty.cpp
|
||||||
|
Gvas/Serialisers/Struct.h
|
||||||
|
Gvas/Serialisers/Struct.cpp
|
||||||
|
Gvas/Serialisers/TextProperty.h
|
||||||
|
Gvas/Serialisers/TextProperty.cpp
|
||||||
|
Gvas/Serialisers/UnrealProperty.h
|
||||||
|
Gvas/Serialisers/VectorProperty.h
|
||||||
|
Gvas/Serialisers/VectorProperty.cpp
|
||||||
|
Gvas/Serialisers/Vector2DProperty.h
|
||||||
|
Gvas/Serialisers/Vector2DProperty.cpp
|
||||||
|
|
||||||
target_link_libraries(UESaveFile PRIVATE
|
Gvas/Types/Types.h
|
||||||
Corrade::Containers
|
Gvas/Types/ArrayProperty.h
|
||||||
Corrade::Utility
|
Gvas/Types/BoolProperty.h
|
||||||
Magnum::Magnum)
|
Gvas/Types/ByteProperty.h
|
||||||
|
Gvas/Types/ColourStructProperty.h
|
||||||
|
Gvas/Types/DateTimeStructProperty.h
|
||||||
|
Gvas/Types/EnumProperty.h
|
||||||
|
Gvas/Types/FloatProperty.h
|
||||||
|
Gvas/Types/GenericStructProperty.h
|
||||||
|
Gvas/Types/GuidStructProperty.h
|
||||||
|
Gvas/Types/IntProperty.h
|
||||||
|
Gvas/Types/MapProperty.h
|
||||||
|
Gvas/Types/NoneProperty.h
|
||||||
|
Gvas/Types/RotatorStructProperty.h
|
||||||
|
Gvas/Types/SetProperty.h
|
||||||
|
Gvas/Types/StringProperty.h
|
||||||
|
Gvas/Types/StructProperty.h
|
||||||
|
Gvas/Types/ResourceItemValue.h
|
||||||
|
Gvas/Types/TextProperty.h
|
||||||
|
Gvas/Types/UnrealProperty.h
|
||||||
|
Gvas/Types/UnrealPropertyBase.h
|
||||||
|
Gvas/Types/Vector2DStructProperty.h
|
||||||
|
Gvas/Types/VectorStructProperty.h
|
||||||
|
|
||||||
add_executable(MassBuilderSaveTool WIN32
|
Gvas/Gvas.h
|
||||||
|
Gvas/Debug.h
|
||||||
|
Gvas/Debug.cpp
|
||||||
|
Gvas/File.h
|
||||||
|
Gvas/File.cpp
|
||||||
|
Gvas/PropertySerialiser.h
|
||||||
|
Gvas/PropertySerialiser.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(ImportExport_SOURCES
|
||||||
|
ImportExport/Import.h
|
||||||
|
ImportExport/Import.cpp
|
||||||
|
ImportExport/Export.h
|
||||||
|
ImportExport/Export.cpp
|
||||||
|
ImportExport/Keys.h
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CORRADE_TARGET_WINDOWS)
|
||||||
|
set(SAVETOOL_RC_FILE resource.rc)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_executable(MassBuilderSaveTool
|
||||||
main.cpp
|
main.cpp
|
||||||
SaveTool/SaveTool.h
|
Application/Application.h
|
||||||
SaveTool/SaveTool.cpp
|
Application/Application.cpp
|
||||||
SaveTool/SaveTool_drawAbout.cpp
|
Application/Application_drawAbout.cpp
|
||||||
SaveTool/SaveTool_drawMainMenu.cpp
|
Application/Application_drawMainMenu.cpp
|
||||||
SaveTool/SaveTool_FileWatcher.cpp
|
Application/Application_FileWatcher.cpp
|
||||||
SaveTool/SaveTool_Initialisation.cpp
|
Application/Application_Initialisation.cpp
|
||||||
SaveTool/SaveTool_MainManager.cpp
|
Application/Application_MainManager.cpp
|
||||||
SaveTool/SaveTool_MassViewer.cpp
|
Application/Application_MassViewer.cpp
|
||||||
SaveTool/SaveTool_MassViewer_Frame.cpp
|
Application/Application_MassViewer_Frame.cpp
|
||||||
SaveTool/SaveTool_MassViewer_Armour.cpp
|
Application/Application_MassViewer_Armour.cpp
|
||||||
SaveTool/SaveTool_MassViewer_Weapons.cpp
|
Application/Application_MassViewer_Weapons.cpp
|
||||||
SaveTool/SaveTool_ProfileManager.cpp
|
Application/Application_ProfileManager.cpp
|
||||||
SaveTool/SaveTool_UpdateChecker.cpp
|
Application/Application_UpdateChecker.cpp
|
||||||
ProfileManager/ProfileManager.h
|
Configuration/Configuration.h
|
||||||
ProfileManager/ProfileManager.cpp
|
Configuration/Configuration.cpp
|
||||||
Profile/Profile.h
|
FontAwesome/IconsFontAwesome5.h
|
||||||
Profile/Profile.cpp
|
FontAwesome/IconsFontAwesome5Brands.h
|
||||||
Profile/ResourceIDs.h
|
GameData/Accessories.h
|
||||||
MassManager/MassManager.h
|
GameData/ArmourSets.h
|
||||||
MassManager/MassManager.cpp
|
GameData/LastMissionId.h
|
||||||
Mass/Accessory.h
|
GameData/ResourceIDs.h
|
||||||
Mass/ArmourPart.h
|
GameData/StoryProgress.h
|
||||||
Mass/BulletLauncherAttachment.h
|
GameData/StyleNames.h
|
||||||
Mass/CustomStyle.h
|
GameData/WeaponParts.h
|
||||||
Mass/Decal.h
|
GameObjects/Accessory.h
|
||||||
Mass/Joints.h
|
GameObjects/ArmourPart.h
|
||||||
Mass/Mass.h
|
GameObjects/BulletLauncherAttachment.h
|
||||||
Mass/Mass.cpp
|
GameObjects/CustomStyle.h
|
||||||
Mass/Mass_Frame.cpp
|
GameObjects/Decal.h
|
||||||
Mass/Mass_Armour.cpp
|
GameObjects/Joints.h
|
||||||
Mass/Mass_Weapons.cpp
|
GameObjects/Mass.h
|
||||||
Mass/Mass_Styles.cpp
|
GameObjects/Mass.cpp
|
||||||
Mass/Mass_DecalsAccessories.cpp
|
GameObjects/Mass_Frame.cpp
|
||||||
Mass/Weapon.h
|
GameObjects/Mass_Armour.cpp
|
||||||
Mass/Weapon.cpp
|
GameObjects/Mass_Weapons.cpp
|
||||||
Mass/WeaponPart.h
|
GameObjects/Mass_Styles.cpp
|
||||||
Maps/Accessories.h
|
GameObjects/Mass_DecalsAccessories.cpp
|
||||||
Maps/ArmourSets.h
|
GameObjects/Profile.h
|
||||||
|
GameObjects/Profile.cpp
|
||||||
|
GameObjects/PropertyNames.h
|
||||||
|
GameObjects/Weapon.h
|
||||||
|
GameObjects/Weapon.cpp
|
||||||
|
GameObjects/WeaponPart.h
|
||||||
|
Managers/Backup.h
|
||||||
|
Managers/BackupManager.h
|
||||||
|
Managers/BackupManager.cpp
|
||||||
|
Managers/MassManager.h
|
||||||
|
Managers/MassManager.cpp
|
||||||
|
Managers/ProfileManager.h
|
||||||
|
Managers/ProfileManager.cpp
|
||||||
|
Managers/StagedMass.h
|
||||||
|
Managers/StagedMassManager.h
|
||||||
|
Managers/StagedMassManager.cpp
|
||||||
|
Managers/Vfs/Directory.h
|
||||||
Maps/ArmourSlots.hpp
|
Maps/ArmourSlots.hpp
|
||||||
Maps/BulletLauncherAttachmentStyles.hpp
|
Maps/BulletLauncherAttachmentStyles.hpp
|
||||||
Maps/BulletLauncherSockets.hpp
|
Maps/BulletLauncherSockets.hpp
|
||||||
Maps/DamageTypes.hpp
|
Maps/DamageTypes.hpp
|
||||||
Maps/EffectColourModes.hpp
|
Maps/EffectColourModes.hpp
|
||||||
Maps/LastMissionId.h
|
|
||||||
Maps/StoryProgress.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
|
||||||
|
UpdateChecker/UpdateChecker.h
|
||||||
|
UpdateChecker/UpdateChecker.cpp
|
||||||
Utilities/Crc32.h
|
Utilities/Crc32.h
|
||||||
FontAwesome/IconsFontAwesome5.h
|
Utilities/Crc32.cpp
|
||||||
FontAwesome/IconsFontAwesome5Brands.h
|
Utilities/Temp.h
|
||||||
resource.rc
|
Utilities/Temp.cpp
|
||||||
${Assets})
|
Version/Version.h
|
||||||
|
Version/Version.cpp
|
||||||
|
${Logger_SOURCES}
|
||||||
|
${BinaryIo_SOURCES}
|
||||||
|
${Gvas_SOURCES}
|
||||||
|
${ImportExport_SOURCES}
|
||||||
|
${SAVETOOL_RC_FILE}
|
||||||
|
${Assets}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(CORRADE_TARGET_WINDOWS)
|
||||||
|
set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE $<CONFIG:Release>)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(MassBuilderSaveTool PRIVATE
|
||||||
|
SAVETOOL_VERSION_STRING="${SAVETOOL_PROJECT_VERSION}"
|
||||||
|
SAVETOOL_VERSION_MAJOR=1
|
||||||
|
SAVETOOL_VERSION_MINOR=5
|
||||||
|
SAVETOOL_VERSION_PATCH=2
|
||||||
|
SAVETOOL_VERSION_PRERELEASE=false
|
||||||
|
SAVETOOL_CODENAME="Friendly Valkyrie"
|
||||||
|
SAVETOOL_SUPPORTED_GAME_VERSION="0.11.x"
|
||||||
|
)
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||||
add_compile_definitions(SAVETOOL_DEBUG_BUILD)
|
target_compile_definitions(MassBuilderSaveTool PRIVATE SAVETOOL_DEBUG_BUILD)
|
||||||
endif()
|
endif()
|
||||||
add_compile_definitions(SAVETOOL_VERSION="${SAVETOOL_PROJECT_VERSION}"
|
|
||||||
SAVETOOL_CODENAME="Dickish Cyclops"
|
|
||||||
SUPPORTED_GAME_VERSION="0.8.6")
|
|
||||||
|
|
||||||
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})
|
||||||
|
@ -186,15 +258,29 @@ endif()
|
||||||
target_link_libraries(MassBuilderSaveTool PRIVATE
|
target_link_libraries(MassBuilderSaveTool PRIVATE
|
||||||
Corrade::Containers
|
Corrade::Containers
|
||||||
Corrade::Utility
|
Corrade::Utility
|
||||||
Corrade::Interconnect
|
|
||||||
Corrade::Main
|
|
||||||
Magnum::Magnum
|
Magnum::Magnum
|
||||||
Magnum::GL
|
Magnum::GL
|
||||||
Magnum::Sdl2Application
|
Magnum::Sdl2Application
|
||||||
MagnumIntegration::ImGui
|
MagnumIntegration::ImGui
|
||||||
UESaveFile
|
CURL::libcurl_static
|
||||||
efsw
|
)
|
||||||
zip
|
|
||||||
libcurl
|
if(SAVETOOL_USE_SYSTEM_LIBZIP)
|
||||||
|
target_link_libraries(MassBuilderSaveTool PRIVATE libzip::zip)
|
||||||
|
else()
|
||||||
|
target_link_libraries(MassBuilderSaveTool PRIVATE zip)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(SAVETOOL_USE_SYSTEM_EFSW)
|
||||||
|
target_link_libraries(MassBuilderSaveTool PRIVATE efsw::efsw)
|
||||||
|
else()
|
||||||
|
target_link_libraries(MassBuilderSaveTool PRIVATE efsw)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(CORRADE_TARGET_WINDOWS)
|
||||||
|
target_link_libraries(MassBuilderSaveTool PRIVATE
|
||||||
|
Corrade::Main
|
||||||
imm32
|
imm32
|
||||||
wtsapi32)
|
wtsapi32
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
292
src/Configuration/Configuration.cpp
Normal file
292
src/Configuration/Configuration.cpp
Normal file
|
@ -0,0 +1,292 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Containers/Optional.h>
|
||||||
|
#include <Corrade/Containers/Pair.h>
|
||||||
|
#include <Corrade/Containers/ScopeGuard.h>
|
||||||
|
#include <Corrade/Utility/Path.h>
|
||||||
|
#include <Corrade/Utility/Unicode.h>
|
||||||
|
|
||||||
|
#include <combaseapi.h>
|
||||||
|
#include <knownfolders.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "Configuration.h"
|
||||||
|
|
||||||
|
namespace mbst {
|
||||||
|
|
||||||
|
Configuration::Configuration() {
|
||||||
|
Containers::String exe_path = Utility::Path::split(*Utility::Path::executableLocation()).first();
|
||||||
|
_conf = Utility::Configuration{Utility::Path::join(exe_path, "MassBuilderSaveTool.ini")};
|
||||||
|
|
||||||
|
if(_conf.hasValue("swap_interval")) {
|
||||||
|
_swapInterval = _conf.value<int>("swap_interval");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("swap_interval", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("frame_limit")) {
|
||||||
|
std::string frame_limit = _conf.value("frame_limit");
|
||||||
|
if(frame_limit == "half_vsync") {
|
||||||
|
_swapInterval = 2;
|
||||||
|
}
|
||||||
|
_conf.removeValue("frame_limit");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("fps_cap")) {
|
||||||
|
_fpsCap = _conf.value<float>("fps_cap");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("fps_cap", 60.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("cheat_mode")) {
|
||||||
|
_cheatMode = _conf.value<bool>("cheat_mode");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("cheat_mode", _cheatMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("advanced_mode")) {
|
||||||
|
_advancedMode = _conf.value<bool>("advanced_mode");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("advanced_mode", _advancedMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("startup_update_check")) {
|
||||||
|
_checkUpdatesOnStartup = _conf.value<bool>("startup_update_check");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("startup_update_check", _checkUpdatesOnStartup);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_conf.hasValue("skip_disclaimer")) {
|
||||||
|
_skipDisclaimer = _conf.value<bool>("skip_disclaimer");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_conf.setValue("skip_disclaimer", _skipDisclaimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Searching for the game's save directory.");
|
||||||
|
wchar_t* localappdata_path = nullptr;
|
||||||
|
Containers::ScopeGuard guard{localappdata_path, CoTaskMemFree};
|
||||||
|
auto result = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_DEFAULT, nullptr, &localappdata_path);
|
||||||
|
if(result != S_OK)
|
||||||
|
{
|
||||||
|
char* message_buffer = nullptr;
|
||||||
|
auto size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
nullptr, result, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
|
||||||
|
reinterpret_cast<char*>(&message_buffer), 0, nullptr);
|
||||||
|
String message{message_buffer, size};
|
||||||
|
LocalFree(message_buffer);
|
||||||
|
|
||||||
|
_lastError = Utility::format("SHGetKnownFolderPath() failed with error code {}: {}", result, message);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto game_data_dir = Utility::Path::join(
|
||||||
|
Utility::Path::fromNativeSeparators(Utility::Unicode::narrow(localappdata_path)),
|
||||||
|
"MASS_Builder/Saved"_s
|
||||||
|
);
|
||||||
|
if(!Utility::Path::exists(game_data_dir)) {
|
||||||
|
LOG_ERROR(_lastError = game_data_dir + " wasn't found. Make sure to play the game at least once."_s);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_directories.gameConfig = Utility::Path::join(game_data_dir, "Config/WindowsNoEditor"_s);
|
||||||
|
_directories.gameSaves = Utility::Path::join(game_data_dir, "SaveGames"_s);
|
||||||
|
_directories.gameScreenshots = Utility::Path::join(game_data_dir, "Screenshots/WindowsNoEditor"_s);
|
||||||
|
|
||||||
|
LOG_INFO("Initialising Save Tool directories.");
|
||||||
|
Containers::String executable_location = Utility::Path::split(*Utility::Path::executableLocation()).first();
|
||||||
|
_directories.backups = Utility::Path::join(executable_location, "backups");
|
||||||
|
_directories.staging = Utility::Path::join(executable_location, "staging");
|
||||||
|
//auto armoury_dir = Utility::Path::join(executable_location, "armoury");
|
||||||
|
//_directories.armours = Utility::Path::join(armoury_dir, "armours");
|
||||||
|
//_directories.weapons = Utility::Path::join(armoury_dir, "weapons");
|
||||||
|
//_directories.styles = Utility::Path::join(armoury_dir, "styles");
|
||||||
|
_directories.temp = Utility::Path::join(executable_location, "temp");
|
||||||
|
|
||||||
|
if(!Utility::Path::exists(_directories.backups)) {
|
||||||
|
LOG_WARNING("Backups directory not found, creating...");
|
||||||
|
if(!Utility::Path::make(_directories.backups)) {
|
||||||
|
LOG_ERROR(_lastError = "Couldn't create the backups directory.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!Utility::Path::exists(_directories.staging)) {
|
||||||
|
LOG_WARNING("Staging directory not found, creating...");
|
||||||
|
if(!Utility::Path::make(_directories.staging)) {
|
||||||
|
LOG_ERROR(_lastError = "Couldn't create the staging directory.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if(!Utility::Path::exists(_directories.armours)) {
|
||||||
|
// LOG_WARNING("Armours directory not found, creating...");
|
||||||
|
// if(!Utility::Path::make(_directories.armours)) {
|
||||||
|
// LOG_ERROR(_lastError = "Couldn't create the armours directory.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//if(!Utility::Path::exists(_directories.weapons)) {
|
||||||
|
// LOG_WARNING("Weapons directory not found, creating...");
|
||||||
|
// if(!Utility::Path::make(_directories.weapons)) {
|
||||||
|
// LOG_ERROR(_lastError = "Couldn't create the weapons directory.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//if(!Utility::Path::exists(_directories.styles)) {
|
||||||
|
// LOG_WARNING("Styles directory not found, creating...");
|
||||||
|
// if(!Utility::Path::make(_directories.styles)) {
|
||||||
|
// LOG_ERROR(_lastError = "Couldn't create the styles directory.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
if(!Utility::Path::exists(_directories.temp)) {
|
||||||
|
LOG_WARNING("Temporary directory not found, creating...");
|
||||||
|
if(!Utility::Path::make(_directories.temp)) {
|
||||||
|
LOG_ERROR(_lastError = "Couldn't create the temporary directory.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration::~Configuration() {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Configuration::valid() const {
|
||||||
|
return _valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::StringView
|
||||||
|
Configuration::lastError() const {
|
||||||
|
return _lastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Configuration::save() {
|
||||||
|
_conf.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Configuration::swapInterval() const {
|
||||||
|
return _swapInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Configuration::setSwapInterval(int interval) {
|
||||||
|
_swapInterval = interval;
|
||||||
|
_conf.setValue("swap_interval", _swapInterval);
|
||||||
|
_conf.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
Configuration::fpsCap() const {
|
||||||
|
return _fpsCap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Configuration::setFpsCap(float cap) {
|
||||||
|
_fpsCap = cap;
|
||||||
|
_conf.setValue("fps_cap", _fpsCap);
|
||||||
|
_conf.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Configuration::cheatMode() const {
|
||||||
|
return _cheatMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Configuration::setCheatMode(bool enabled) {
|
||||||
|
_cheatMode = enabled;
|
||||||
|
_conf.setValue("cheat_mode", _cheatMode);
|
||||||
|
_conf.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Configuration::advancedMode() const {
|
||||||
|
return _advancedMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Configuration::setAdvancedMode(bool enabled) {
|
||||||
|
_advancedMode = enabled;
|
||||||
|
_conf.setValue("advanced_mode", _advancedMode);
|
||||||
|
_conf.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Configuration::checkUpdatesOnStartup() const {
|
||||||
|
return _checkUpdatesOnStartup;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Configuration::setCheckUpdatesOnStartup(bool mode) {
|
||||||
|
_checkUpdatesOnStartup = mode;
|
||||||
|
_conf.setValue("startup_update_check", _checkUpdatesOnStartup);
|
||||||
|
_conf.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Configuration::skipDisclaimer() const {
|
||||||
|
return _skipDisclaimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Configuration::setSkipDisclaimer(bool mode) {
|
||||||
|
_skipDisclaimer = mode;
|
||||||
|
_conf.setValue("skip_disclaimer", _skipDisclaimer);
|
||||||
|
_conf.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Configuration::isRunningInWine() const {
|
||||||
|
return _isRunningInWine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Configuration::setRunningInWine(bool wine) {
|
||||||
|
_isRunningInWine = wine;
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration::Directories const&
|
||||||
|
Configuration::directories() const {
|
||||||
|
return _directories;
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration&
|
||||||
|
Configuration::instance() {
|
||||||
|
static Configuration conf{};
|
||||||
|
return conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
Configuration&
|
||||||
|
conf() {
|
||||||
|
return Configuration::instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
94
src/Configuration/Configuration.h
Normal file
94
src/Configuration/Configuration.h
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Utility/Configuration.h>
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
|
||||||
|
namespace mbst {
|
||||||
|
|
||||||
|
class Configuration {
|
||||||
|
public:
|
||||||
|
static auto instance() -> Configuration&;
|
||||||
|
|
||||||
|
~Configuration();
|
||||||
|
|
||||||
|
bool valid() const;
|
||||||
|
|
||||||
|
auto lastError() const -> Containers::StringView;
|
||||||
|
|
||||||
|
void save();
|
||||||
|
|
||||||
|
auto swapInterval() const -> int;
|
||||||
|
void setSwapInterval(int interval);
|
||||||
|
|
||||||
|
auto fpsCap() const -> float;
|
||||||
|
void setFpsCap(float cap);
|
||||||
|
|
||||||
|
bool cheatMode() const;
|
||||||
|
void setCheatMode(bool enabled);
|
||||||
|
|
||||||
|
bool advancedMode() const;
|
||||||
|
void setAdvancedMode(bool enabled);
|
||||||
|
|
||||||
|
bool checkUpdatesOnStartup() const;
|
||||||
|
void setCheckUpdatesOnStartup(bool mode);
|
||||||
|
|
||||||
|
bool skipDisclaimer() const;
|
||||||
|
void setSkipDisclaimer(bool mode);
|
||||||
|
|
||||||
|
bool isRunningInWine() const;
|
||||||
|
void setRunningInWine(bool wine);
|
||||||
|
|
||||||
|
struct Directories {
|
||||||
|
Containers::String gameSaves;
|
||||||
|
Containers::String gameConfig;
|
||||||
|
Containers::String gameScreenshots;
|
||||||
|
Containers::String backups;
|
||||||
|
Containers::String staging;
|
||||||
|
Containers::String armours;
|
||||||
|
Containers::String weapons;
|
||||||
|
Containers::String styles;
|
||||||
|
Containers::String temp;
|
||||||
|
};
|
||||||
|
auto directories() const -> Directories const&;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit Configuration();
|
||||||
|
|
||||||
|
Utility::Configuration _conf;
|
||||||
|
|
||||||
|
Containers::String _lastError;
|
||||||
|
|
||||||
|
int _swapInterval = 1;
|
||||||
|
float _fpsCap = 60.0f;
|
||||||
|
bool _cheatMode = false;
|
||||||
|
bool _advancedMode = false;
|
||||||
|
bool _checkUpdatesOnStartup = true;
|
||||||
|
bool _skipDisclaimer = false;
|
||||||
|
|
||||||
|
bool _isRunningInWine = false;
|
||||||
|
|
||||||
|
bool _valid = false;
|
||||||
|
|
||||||
|
Directories _directories;
|
||||||
|
};
|
||||||
|
|
||||||
|
Configuration& conf();
|
||||||
|
|
||||||
|
}
|
783
src/GameData/Accessories.h
Normal file
783
src/GameData/Accessories.h
Normal file
|
@ -0,0 +1,783 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameData {
|
||||||
|
|
||||||
|
struct Accessory {
|
||||||
|
Containers::StringView name;
|
||||||
|
enum Size {
|
||||||
|
S,
|
||||||
|
M,
|
||||||
|
L,
|
||||||
|
XL
|
||||||
|
};
|
||||||
|
Size size{};
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::map<std::int32_t, Accessory> accessories{
|
||||||
|
// region Primitives
|
||||||
|
{1, {"Cube"_s, Accessory::Size::S}},
|
||||||
|
{2, {"Pentagon"_s, Accessory::Size::S}},
|
||||||
|
{3, {"Hexagon"_s, Accessory::Size::S}},
|
||||||
|
{4, {"Cylinder"_s, Accessory::Size::S}},
|
||||||
|
{5, {"Sphere"_s, Accessory::Size::S}},
|
||||||
|
{6, {"TriPyramid"_s, Accessory::Size::S}},
|
||||||
|
{7, {"SquPyramid"_s, Accessory::Size::S}},
|
||||||
|
{8, {"PenPyramid"_s, Accessory::Size::S}},
|
||||||
|
{9, {"HexPyramid"_s, Accessory::Size::S}},
|
||||||
|
{10, {"Cone"_s, Accessory::Size::S}},
|
||||||
|
{11, {"SquStick"_s, Accessory::Size::S}},
|
||||||
|
{12, {"PenStick"_s, Accessory::Size::S}},
|
||||||
|
{13, {"HexStick"_s, Accessory::Size::S}},
|
||||||
|
{14, {"CycStick"_s, Accessory::Size::S}},
|
||||||
|
{15, {"Capsule"_s, Accessory::Size::S}},
|
||||||
|
{16, {"Decal Pad 01"_s, Accessory::Size::S}},
|
||||||
|
{17, {"Decal Pad 02"_s, Accessory::Size::S}},
|
||||||
|
{18, {"Decal Pad 03"_s, Accessory::Size::S}},
|
||||||
|
{19, {"Decal Pad 04"_s, Accessory::Size::S}},
|
||||||
|
{20, {"Decal Pad 05"_s, Accessory::Size::S}},
|
||||||
|
{21, {"Triangle"_s, Accessory::Size::S}},
|
||||||
|
{22, {"ThinStar"_s, Accessory::Size::S}},
|
||||||
|
{23, {"Star"_s, Accessory::Size::S}},
|
||||||
|
{24, {"SixSideStar"_s, Accessory::Size::S}},
|
||||||
|
{25, {"Asterisk"_s, Accessory::Size::S}},
|
||||||
|
{26, {"Ring"_s, Accessory::Size::S}},
|
||||||
|
{27, {"SawedRing"_s, Accessory::Size::S}},
|
||||||
|
{28, {"HalfRing"_s, Accessory::Size::S}},
|
||||||
|
{29, {"Cresent"_s, Accessory::Size::S}},
|
||||||
|
{30, {"Donut"_s, Accessory::Size::S}},
|
||||||
|
{31, {"FiveCogWheel"_s, Accessory::Size::S}},
|
||||||
|
{32, {"SixCogWheel"_s, Accessory::Size::S}},
|
||||||
|
{33, {"SevenCogWheel"_s, Accessory::Size::S}},
|
||||||
|
{34, {"EightCogWheel"_s, Accessory::Size::S}},
|
||||||
|
{35, {"TwelveCogWheel"_s, Accessory::Size::S}},
|
||||||
|
|
||||||
|
{51, {"SquBevel"_s, Accessory::Size::S}},
|
||||||
|
{52, {"TriBevel"_s, Accessory::Size::S}},
|
||||||
|
{53, {"PenBevel"_s, Accessory::Size::S}},
|
||||||
|
{54, {"HexBevel"_s, Accessory::Size::S}},
|
||||||
|
{55, {"CycBevel"_s, Accessory::Size::S}},
|
||||||
|
{56, {"RecBevel"_s, Accessory::Size::S}},
|
||||||
|
{57, {"DaiBevel"_s, Accessory::Size::S}},
|
||||||
|
{58, {"MonBevel"_s, Accessory::Size::S}},
|
||||||
|
{59, {"CofBevel"_s, Accessory::Size::S}},
|
||||||
|
{60, {"JevBevel"_s, Accessory::Size::S}},
|
||||||
|
{61, {"SquEmboss"_s, Accessory::Size::S}},
|
||||||
|
{62, {"TriEmboss"_s, Accessory::Size::S}},
|
||||||
|
{63, {"PenEmboss"_s, Accessory::Size::S}},
|
||||||
|
{64, {"HexEmboss"_s, Accessory::Size::S}},
|
||||||
|
{65, {"CycEmboss"_s, Accessory::Size::S}},
|
||||||
|
{66, {"RecEmboss"_s, Accessory::Size::S}},
|
||||||
|
{67, {"DaiEmboss"_s, Accessory::Size::S}},
|
||||||
|
{68, {"MonEmboss"_s, Accessory::Size::S}},
|
||||||
|
{69, {"CofEmboss"_s, Accessory::Size::S}},
|
||||||
|
{70, {"JevEmboss"_s, Accessory::Size::S}},
|
||||||
|
|
||||||
|
{101, {"Flat Hex Pin"_s, Accessory::Size::S}},
|
||||||
|
{102, {"Cross Circle Pin"_s, Accessory::Size::S}},
|
||||||
|
{103, {"Flat Circle Pin"_s, Accessory::Size::S}},
|
||||||
|
{104, {"Hex Circle Pin"_s, Accessory::Size::S}},
|
||||||
|
{105, {"Circle Button Pin"_s, Accessory::Size::S}},
|
||||||
|
{106, {"Hexagon Pin"_s, Accessory::Size::S}},
|
||||||
|
{107, {"Cross Square Pin"_s, Accessory::Size::S}},
|
||||||
|
{108, {"Flat Square Pin"_s, Accessory::Size::S}},
|
||||||
|
{109, {"Quad Corner Pin"_s, Accessory::Size::S}},
|
||||||
|
{110, {"Bi Corner Pin"_s, Accessory::Size::S}},
|
||||||
|
{111, {"Circle Pin"_s, Accessory::Size::S}},
|
||||||
|
{112, {"Flat End Pin"_s, Accessory::Size::S}},
|
||||||
|
{113, {"Flat Cut Pin"_s, Accessory::Size::S}},
|
||||||
|
{114, {"Radial Pin"_s, Accessory::Size::S}},
|
||||||
|
{115, {"Diamiter Pin"_s, Accessory::Size::S}},
|
||||||
|
|
||||||
|
{151, {"TriPoint"_s, Accessory::Size::S}},
|
||||||
|
{152, {"SquPoint"_s, Accessory::Size::S}},
|
||||||
|
{153, {"PenPoint"_s, Accessory::Size::S}},
|
||||||
|
{154, {"HexPoint"_s, Accessory::Size::S}},
|
||||||
|
{155, {"CycPoint"_s, Accessory::Size::S}},
|
||||||
|
{156, {"Bevel SquCutPoint"_s, Accessory::Size::S}},
|
||||||
|
{157, {"Bevel HexCutPoint"_s, Accessory::Size::S}},
|
||||||
|
{158, {"Bevel HexPoint"_s, Accessory::Size::S}},
|
||||||
|
{159, {"Bevel CycCutPoint"_s, Accessory::Size::S}},
|
||||||
|
{160, {"Bevel CycPoint"_s, Accessory::Size::S}},
|
||||||
|
|
||||||
|
{201, {"Shaped Edge 01"_s, Accessory::Size::M}},
|
||||||
|
{202, {"Shaped Edge 02"_s, Accessory::Size::M}},
|
||||||
|
{203, {"Shaped Edge 03"_s, Accessory::Size::M}},
|
||||||
|
{204, {"Shaped Edge 04"_s, Accessory::Size::M}},
|
||||||
|
{205, {"Shaped Edge 05"_s, Accessory::Size::M}},
|
||||||
|
{206, {"Shaped Edge 06"_s, Accessory::Size::M}},
|
||||||
|
{207, {"Shaped Edge 07"_s, Accessory::Size::M}},
|
||||||
|
{208, {"Shaped Edge 08"_s, Accessory::Size::M}},
|
||||||
|
{209, {"Shaped Edge 09"_s, Accessory::Size::M}},
|
||||||
|
{210, {"Shaped Edge 10"_s, Accessory::Size::M}},
|
||||||
|
{211, {"Shaped Edge 11"_s, Accessory::Size::M}},
|
||||||
|
{212, {"Shaped Edge 12"_s, Accessory::Size::M}},
|
||||||
|
{213, {"Shaped Edge 13"_s, Accessory::Size::M}},
|
||||||
|
{214, {"Shaped Edge 14"_s, Accessory::Size::M}},
|
||||||
|
{215, {"Shaped Edge 15"_s, Accessory::Size::M}},
|
||||||
|
{216, {"Shaped Edge 16"_s, Accessory::Size::M}},
|
||||||
|
{217, {"Shaped Edge 17"_s, Accessory::Size::M}},
|
||||||
|
{218, {"Shaped Edge 18"_s, Accessory::Size::M}},
|
||||||
|
{219, {"Shaped Edge 19"_s, Accessory::Size::M}},
|
||||||
|
{220, {"Shaped Edge 20"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{251, {"Fish Tail 01"_s, Accessory::Size::M}},
|
||||||
|
{252, {"Fish Tail 02"_s, Accessory::Size::M}},
|
||||||
|
{253, {"Fish Tail 03"_s, Accessory::Size::M}},
|
||||||
|
{254, {"Fish Tail 04"_s, Accessory::Size::M}},
|
||||||
|
{255, {"Fish Tail 05"_s, Accessory::Size::M}},
|
||||||
|
{256, {"Based Separator 01"_s, Accessory::Size::M}},
|
||||||
|
{257, {"Based Separator 02"_s, Accessory::Size::M}},
|
||||||
|
{258, {"Based Separator 03"_s, Accessory::Size::M}},
|
||||||
|
{259, {"Based Separator 04"_s, Accessory::Size::M}},
|
||||||
|
{260, {"Based Separator 05"_s, Accessory::Size::M}},
|
||||||
|
{261, {"Based Separator 06"_s, Accessory::Size::M}},
|
||||||
|
{262, {"Based Separator 07"_s, Accessory::Size::M}},
|
||||||
|
{263, {"Based Separator 08"_s, Accessory::Size::M}},
|
||||||
|
{264, {"Based Separator 09"_s, Accessory::Size::M}},
|
||||||
|
{265, {"Based Separator 10"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{301, {"Rectangular Box 01"_s, Accessory::Size::M}},
|
||||||
|
{302, {"Rectangular Box 02"_s, Accessory::Size::M}},
|
||||||
|
{303, {"Rectangular Box 03"_s, Accessory::Size::M}},
|
||||||
|
{304, {"Rectangular Box 04"_s, Accessory::Size::M}},
|
||||||
|
{305, {"Rectangular Box 05"_s, Accessory::Size::M}},
|
||||||
|
{306, {"CofBox 01"_s, Accessory::Size::M}},
|
||||||
|
{307, {"CofBox 02"_s, Accessory::Size::M}},
|
||||||
|
{308, {"CofBox 03"_s, Accessory::Size::M}},
|
||||||
|
{309, {"CofBox 04"_s, Accessory::Size::M}},
|
||||||
|
{310, {"CofBox 05"_s, Accessory::Size::M}},
|
||||||
|
{311, {"Triangular Box 01"_s, Accessory::Size::M}},
|
||||||
|
{312, {"Triangular Box 02"_s, Accessory::Size::M}},
|
||||||
|
{313, {"Triangular Box 03"_s, Accessory::Size::M}},
|
||||||
|
{314, {"Triangular Box 04"_s, Accessory::Size::M}},
|
||||||
|
{315, {"Triangular Box 05"_s, Accessory::Size::M}},
|
||||||
|
{316, {"Diagonal Box A01"_s, Accessory::Size::M}},
|
||||||
|
{317, {"Diagonal Box A02"_s, Accessory::Size::M}},
|
||||||
|
{318, {"Diagonal Box A03"_s, Accessory::Size::M}},
|
||||||
|
{319, {"Diagonal Box A04"_s, Accessory::Size::M}},
|
||||||
|
{320, {"Diagonal Box A05"_s, Accessory::Size::M}},
|
||||||
|
{321, {"Diagonal Box B01"_s, Accessory::Size::M}},
|
||||||
|
{322, {"Diagonal Box B02"_s, Accessory::Size::M}},
|
||||||
|
{323, {"Diagonal Box B03"_s, Accessory::Size::M}},
|
||||||
|
{324, {"Diagonal Box B04"_s, Accessory::Size::M}},
|
||||||
|
{325, {"Diagonal Box B05"_s, Accessory::Size::M}},
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Armours
|
||||||
|
{1001, {"Short Layer 01"_s, Accessory::Size::M}},
|
||||||
|
{1002, {"Short Layer 02"_s, Accessory::Size::M}},
|
||||||
|
{1003, {"Short Layer 03"_s, Accessory::Size::M}},
|
||||||
|
{1004, {"Short Layer 04"_s, Accessory::Size::M}},
|
||||||
|
{1005, {"Short Layer 05"_s, Accessory::Size::M}},
|
||||||
|
{1006, {"Long Layer 01"_s, Accessory::Size::M}},
|
||||||
|
{1007, {"Long Layer 02"_s, Accessory::Size::M}},
|
||||||
|
{1008, {"Long Layer 03"_s, Accessory::Size::M}},
|
||||||
|
{1009, {"Long Layer 04"_s, Accessory::Size::M}},
|
||||||
|
{1010, {"Long Layer 05"_s, Accessory::Size::M}},
|
||||||
|
{1011, {"Diagonal Long Layer 01"_s, Accessory::Size::M}},
|
||||||
|
{1012, {"Diagonal Long Layer 02"_s, Accessory::Size::M}},
|
||||||
|
{1013, {"Diagonal Long Layer 03"_s, Accessory::Size::M}},
|
||||||
|
{1014, {"Diagonal Long Layer 04"_s, Accessory::Size::M}},
|
||||||
|
{1015, {"Diagonal Long Layer 05"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{1051, {"Sloped Layer 01"_s, Accessory::Size::M}},
|
||||||
|
{1052, {"Sloped Layer 02"_s, Accessory::Size::M}},
|
||||||
|
{1053, {"Sloped Layer 03"_s, Accessory::Size::M}},
|
||||||
|
{1054, {"Sloped Layer 04"_s, Accessory::Size::M}},
|
||||||
|
{1055, {"Sloped Layer 05"_s, Accessory::Size::M}},
|
||||||
|
{1056, {"Sloped Layer 06"_s, Accessory::Size::M}},
|
||||||
|
{1057, {"Sloped Layer 07"_s, Accessory::Size::M}},
|
||||||
|
{1058, {"Sloped Layer 08"_s, Accessory::Size::M}},
|
||||||
|
{1059, {"Sloped Layer 09"_s, Accessory::Size::M}},
|
||||||
|
{1060, {"Sloped Layer 10"_s, Accessory::Size::M}},
|
||||||
|
{1061, {"Sloped Layer 11"_s, Accessory::Size::M}},
|
||||||
|
{1062, {"Sloped Layer 12"_s, Accessory::Size::M}},
|
||||||
|
{1063, {"Sloped Layer 13"_s, Accessory::Size::M}},
|
||||||
|
{1064, {"Sloped Layer 14"_s, Accessory::Size::M}},
|
||||||
|
{1065, {"Sloped Layer 15"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{1101, {"Raised Center 01"_s, Accessory::Size::M}},
|
||||||
|
{1102, {"Raised Center 02"_s, Accessory::Size::M}},
|
||||||
|
{1103, {"Raised Center 03"_s, Accessory::Size::M}},
|
||||||
|
{1104, {"Raised Center 04"_s, Accessory::Size::M}},
|
||||||
|
{1105, {"Raised Center 05"_s, Accessory::Size::M}},
|
||||||
|
{1106, {"Raised Block 01"_s, Accessory::Size::M}},
|
||||||
|
{1107, {"Raised Block 02"_s, Accessory::Size::M}},
|
||||||
|
{1108, {"Raised Block 03"_s, Accessory::Size::M}},
|
||||||
|
{1109, {"Raised Pointed"_s, Accessory::Size::M}},
|
||||||
|
{1110, {"Raised Cover"_s, Accessory::Size::M}},
|
||||||
|
{1111, {"Raised Slant 01"_s, Accessory::Size::M}},
|
||||||
|
{1112, {"Raised Slant 02"_s, Accessory::Size::M}},
|
||||||
|
{1113, {"Raised Slant 03"_s, Accessory::Size::M}},
|
||||||
|
{1114, {"Raised Slant 04"_s, Accessory::Size::M}},
|
||||||
|
{1115, {"Raised Slant 05"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{1151, {"Wide Patch 01"_s, Accessory::Size::L}},
|
||||||
|
{1152, {"Wide Patch 02"_s, Accessory::Size::L}},
|
||||||
|
{1153, {"Wide Patch 03"_s, Accessory::Size::L}},
|
||||||
|
{1154, {"Wide Patch 04"_s, Accessory::Size::L}},
|
||||||
|
{1155, {"Wide Patch 05"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{1201, {"Pointed Armour 01"_s, Accessory::Size::L}},
|
||||||
|
{1202, {"Pointed Armour 02"_s, Accessory::Size::L}},
|
||||||
|
{1203, {"Pointed Armour 03"_s, Accessory::Size::L}},
|
||||||
|
{1204, {"Pointed Armour 04"_s, Accessory::Size::L}},
|
||||||
|
{1205, {"Pointed Armour 05"_s, Accessory::Size::L}},
|
||||||
|
{1206, {"Pointed Armour 06"_s, Accessory::Size::L}},
|
||||||
|
{1207, {"Pointed Armour 07"_s, Accessory::Size::L}},
|
||||||
|
{1208, {"Pointed Armour 08"_s, Accessory::Size::L}},
|
||||||
|
{1209, {"Pointed Armour 09"_s, Accessory::Size::L}},
|
||||||
|
{1210, {"Pointed Armour 10"_s, Accessory::Size::L}},
|
||||||
|
{1211, {"Pointed Armour 11"_s, Accessory::Size::L}},
|
||||||
|
{1212, {"Pointed Armour 12"_s, Accessory::Size::L}},
|
||||||
|
{1213, {"Pointed Armour 13"_s, Accessory::Size::L}},
|
||||||
|
{1214, {"Pointed Armour 14"_s, Accessory::Size::L}},
|
||||||
|
{1215, {"Pointed Armour 15"_s, Accessory::Size::L}},
|
||||||
|
{1216, {"Pointed Armour 16"_s, Accessory::Size::L}},
|
||||||
|
{1217, {"Pointed Armour 17"_s, Accessory::Size::L}},
|
||||||
|
{1218, {"Pointed Armour 18"_s, Accessory::Size::L}},
|
||||||
|
{1219, {"Pointed Armour 19"_s, Accessory::Size::L}},
|
||||||
|
{1220, {"Pointed Armour 20"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{1251, {"E Limb Cover 01"_s, Accessory::Size::L}},
|
||||||
|
{1252, {"E Limb Cover 02"_s, Accessory::Size::L}},
|
||||||
|
{1253, {"E Limb Cover 03"_s, Accessory::Size::L}},
|
||||||
|
{1254, {"E Limb Cover 04"_s, Accessory::Size::L}},
|
||||||
|
{1255, {"E Limb Cover 05"_s, Accessory::Size::L}},
|
||||||
|
{1256, {"E Limb Cover 06"_s, Accessory::Size::L}},
|
||||||
|
{1257, {"E Limb Cover 07"_s, Accessory::Size::L}},
|
||||||
|
{1258, {"E Limb Cover 08"_s, Accessory::Size::L}},
|
||||||
|
{1259, {"E Limb Cover 09"_s, Accessory::Size::L}},
|
||||||
|
{1260, {"E Limb Cover 10"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{1301, {"C Limb Cover 01"_s, Accessory::Size::L}},
|
||||||
|
{1302, {"C Limb Cover 02"_s, Accessory::Size::L}},
|
||||||
|
{1303, {"C Limb Cover 03"_s, Accessory::Size::L}},
|
||||||
|
{1304, {"C Limb Cover 04"_s, Accessory::Size::L}},
|
||||||
|
{1305, {"C Limb Cover 05"_s, Accessory::Size::L}},
|
||||||
|
{1306, {"C Limb Cover 06"_s, Accessory::Size::L}},
|
||||||
|
{1307, {"C Limb Cover 07"_s, Accessory::Size::L}},
|
||||||
|
{1308, {"C Limb Cover 08"_s, Accessory::Size::L}},
|
||||||
|
{1309, {"C Limb Cover 09"_s, Accessory::Size::L}},
|
||||||
|
{1310, {"C Limb Cover 10"_s, Accessory::Size::L}},
|
||||||
|
{1311, {"C Limb Cover 11"_s, Accessory::Size::L}},
|
||||||
|
{1312, {"C Limb Cover 12"_s, Accessory::Size::L}},
|
||||||
|
{1313, {"C Limb Cover 13"_s, Accessory::Size::L}},
|
||||||
|
{1314, {"C Limb Cover 14"_s, Accessory::Size::L}},
|
||||||
|
{1315, {"C Limb Cover 15"_s, Accessory::Size::L}},
|
||||||
|
{1316, {"C Limb Cover 16"_s, Accessory::Size::L}},
|
||||||
|
{1317, {"C Limb Cover 17"_s, Accessory::Size::L}},
|
||||||
|
{1318, {"C Limb Cover 18"_s, Accessory::Size::L}},
|
||||||
|
{1319, {"C Limb Cover 19"_s, Accessory::Size::L}},
|
||||||
|
{1320, {"C Limb Cover 20"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{1351, {"P Limb Cover 01"_s, Accessory::Size::XL}},
|
||||||
|
{1352, {"P Limb Cover 02"_s, Accessory::Size::XL}},
|
||||||
|
{1353, {"P Limb Cover 03"_s, Accessory::Size::XL}},
|
||||||
|
{1354, {"P Limb Cover 04"_s, Accessory::Size::XL}},
|
||||||
|
{1355, {"P Limb Cover 05"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{1401, {"Flat Cover 01"_s, Accessory::Size::XL}},
|
||||||
|
{1402, {"Flat Cover 02"_s, Accessory::Size::XL}},
|
||||||
|
{1403, {"Flat Cover 03"_s, Accessory::Size::XL}},
|
||||||
|
{1404, {"Flat Cover 04"_s, Accessory::Size::XL}},
|
||||||
|
{1405, {"Flat Cover 05"_s, Accessory::Size::XL}},
|
||||||
|
{1406, {"Flat Cover 06"_s, Accessory::Size::XL}},
|
||||||
|
{1407, {"Flat Cover 07"_s, Accessory::Size::XL}},
|
||||||
|
{1408, {"Flat Cover 08"_s, Accessory::Size::XL}},
|
||||||
|
{1409, {"Flat Cover 09"_s, Accessory::Size::XL}},
|
||||||
|
{1410, {"Flat Cover 10"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{1451, {"L Side Opening 01"_s, Accessory::Size::XL}},
|
||||||
|
{1452, {"L Side Opening 02"_s, Accessory::Size::XL}},
|
||||||
|
{1453, {"L Side Opening 03"_s, Accessory::Size::XL}},
|
||||||
|
{1454, {"L Side Opening 04"_s, Accessory::Size::XL}},
|
||||||
|
{1455, {"L Side Opening 05"_s, Accessory::Size::XL}},
|
||||||
|
{1456, {"L Side Opening 06"_s, Accessory::Size::XL}},
|
||||||
|
{1457, {"L Side Opening 07"_s, Accessory::Size::XL}},
|
||||||
|
{1458, {"L Side Opening 08"_s, Accessory::Size::XL}},
|
||||||
|
{1459, {"L Side Opening 09"_s, Accessory::Size::XL}},
|
||||||
|
{1460, {"L Side Opening 10"_s, Accessory::Size::XL}},
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Components
|
||||||
|
{2001, {"Disc Padding 01"_s, Accessory::Size::M}},
|
||||||
|
{2002, {"Disc Padding 02"_s, Accessory::Size::M}},
|
||||||
|
{2003, {"Disc Padding 03"_s, Accessory::Size::M}},
|
||||||
|
{2004, {"Disc Padding 04"_s, Accessory::Size::M}},
|
||||||
|
{2005, {"Disc Padding 05"_s, Accessory::Size::M}},
|
||||||
|
{2006, {"Thin Padding 01"_s, Accessory::Size::M}},
|
||||||
|
{2007, {"Thin Padding 02"_s, Accessory::Size::M}},
|
||||||
|
{2008, {"Thin Padding 03"_s, Accessory::Size::M}},
|
||||||
|
{2009, {"Thin Padding 04"_s, Accessory::Size::M}},
|
||||||
|
{2010, {"Thin Padding 05"_s, Accessory::Size::M}},
|
||||||
|
{2011, {"Thick Padding 01"_s, Accessory::Size::M}},
|
||||||
|
{2012, {"Thick Padding 02"_s, Accessory::Size::M}},
|
||||||
|
{2013, {"Thick Padding 03"_s, Accessory::Size::M}},
|
||||||
|
{2014, {"Thick Padding 04"_s, Accessory::Size::M}},
|
||||||
|
{2015, {"Thick Padding 05"_s, Accessory::Size::M}},
|
||||||
|
{2016, {"Thick Padding 06"_s, Accessory::Size::M}},
|
||||||
|
{2017, {"Thick Padding 07"_s, Accessory::Size::M}},
|
||||||
|
{2018, {"Thick Padding 08"_s, Accessory::Size::M}},
|
||||||
|
{2019, {"Thick Padding 09"_s, Accessory::Size::M}},
|
||||||
|
{2020, {"Thick Padding 10"_s, Accessory::Size::M}},
|
||||||
|
{2021, {"CSide Padding 01"_s, Accessory::Size::M}},
|
||||||
|
{2022, {"CSide Padding 02"_s, Accessory::Size::M}},
|
||||||
|
{2023, {"CSide Padding 03"_s, Accessory::Size::M}},
|
||||||
|
{2024, {"CSide Padding 04"_s, Accessory::Size::M}},
|
||||||
|
{2025, {"CSide Padding 05"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{2051, {"Container 01"_s, Accessory::Size::L}},
|
||||||
|
{2052, {"Container 02"_s, Accessory::Size::L}},
|
||||||
|
{2053, {"Container 03"_s, Accessory::Size::L}},
|
||||||
|
{2054, {"Container 04"_s, Accessory::Size::L}},
|
||||||
|
{2055, {"Container 05"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2101, {"Plating 01"_s, Accessory::Size::L}},
|
||||||
|
{2102, {"Plating 02"_s, Accessory::Size::L}},
|
||||||
|
{2103, {"Plating 03"_s, Accessory::Size::L}},
|
||||||
|
{2104, {"Plating 04"_s, Accessory::Size::L}},
|
||||||
|
{2105, {"Plating 05"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2126, {"Curved Plating 01"_s, Accessory::Size::L}},
|
||||||
|
{2127, {"Curved Plating 02"_s, Accessory::Size::L}},
|
||||||
|
{2128, {"Curved Plating 03"_s, Accessory::Size::L}},
|
||||||
|
{2129, {"Curved Plating 04"_s, Accessory::Size::L}},
|
||||||
|
{2130, {"Curved Plating 05"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2151, {"Complex Base 01"_s, Accessory::Size::L}},
|
||||||
|
{2152, {"Complex Base 02"_s, Accessory::Size::L}},
|
||||||
|
{2153, {"Complex Base 03"_s, Accessory::Size::L}},
|
||||||
|
{2154, {"Complex Base 04"_s, Accessory::Size::L}},
|
||||||
|
{2155, {"Complex Base 05"_s, Accessory::Size::L}},
|
||||||
|
{2156, {"Complex Base 06"_s, Accessory::Size::L}},
|
||||||
|
{2157, {"Complex Base 07"_s, Accessory::Size::L}},
|
||||||
|
{2158, {"Complex Base 08"_s, Accessory::Size::L}},
|
||||||
|
{2159, {"Complex Base 09"_s, Accessory::Size::L}},
|
||||||
|
{2160, {"Complex Base 10"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2201, {"Long Base 01"_s, Accessory::Size::XL}},
|
||||||
|
{2202, {"Long Base 02"_s, Accessory::Size::XL}},
|
||||||
|
{2203, {"Long Base 03"_s, Accessory::Size::XL}},
|
||||||
|
{2204, {"Long Base 04"_s, Accessory::Size::XL}},
|
||||||
|
{2205, {"Long Base 05"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{2251, {"Straight Wing 01"_s, Accessory::Size::XL}},
|
||||||
|
{2252, {"Straight Wing 02"_s, Accessory::Size::XL}},
|
||||||
|
{2253, {"Straight Wing 03"_s, Accessory::Size::XL}},
|
||||||
|
{2254, {"Straight Wing 04"_s, Accessory::Size::XL}},
|
||||||
|
{2255, {"Straight Wing 05"_s, Accessory::Size::XL}},
|
||||||
|
{2256, {"Straight Wing 06"_s, Accessory::Size::XL}},
|
||||||
|
{2257, {"Straight Wing 07"_s, Accessory::Size::XL}},
|
||||||
|
{2258, {"Straight Wing 08"_s, Accessory::Size::XL}},
|
||||||
|
{2259, {"Straight Wing 09"_s, Accessory::Size::XL}},
|
||||||
|
{2260, {"Straight Wing 10"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{2301, {"Triangular Wing 01"_s, Accessory::Size::XL}},
|
||||||
|
{2302, {"Triangular Wing 02"_s, Accessory::Size::XL}},
|
||||||
|
{2303, {"Triangular Wing 03"_s, Accessory::Size::XL}},
|
||||||
|
{2304, {"Triangular Wing 04"_s, Accessory::Size::XL}},
|
||||||
|
{2305, {"Triangular Wing 05"_s, Accessory::Size::XL}},
|
||||||
|
{2306, {"Triangular Wing 06"_s, Accessory::Size::XL}},
|
||||||
|
{2307, {"Triangular Wing 07"_s, Accessory::Size::XL}},
|
||||||
|
{2308, {"Triangular Wing 08"_s, Accessory::Size::XL}},
|
||||||
|
{2309, {"Triangular Wing 09"_s, Accessory::Size::XL}},
|
||||||
|
{2310, {"Triangular Wing 10"_s, Accessory::Size::XL}},
|
||||||
|
{2311, {"Triangular Wing 11"_s, Accessory::Size::L}},
|
||||||
|
{2312, {"Triangular Wing 12"_s, Accessory::Size::L}},
|
||||||
|
{2313, {"Triangular Wing 13"_s, Accessory::Size::L}},
|
||||||
|
{2314, {"Triangular Wing 14"_s, Accessory::Size::L}},
|
||||||
|
{2315, {"Triangular Wing 15"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2351, {"Complex Wing 01"_s, Accessory::Size::XL}},
|
||||||
|
{2352, {"Complex Wing 02"_s, Accessory::Size::XL}},
|
||||||
|
{2353, {"Complex Wing 03"_s, Accessory::Size::XL}},
|
||||||
|
{2354, {"Complex Wing 04"_s, Accessory::Size::XL}},
|
||||||
|
{2355, {"Complex Wing 05"_s, Accessory::Size::XL}},
|
||||||
|
{2356, {"Complex Wing 06"_s, Accessory::Size::L}},
|
||||||
|
{2357, {"Complex Wing 07"_s, Accessory::Size::L}},
|
||||||
|
{2358, {"Complex Wing 08"_s, Accessory::Size::L}},
|
||||||
|
{2359, {"Complex Wing 09"_s, Accessory::Size::L}},
|
||||||
|
{2360, {"Complex Wing 10"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2401, {"Blade 01"_s, Accessory::Size::XL}},
|
||||||
|
{2402, {"Blade 02"_s, Accessory::Size::XL}},
|
||||||
|
{2403, {"Blade 03"_s, Accessory::Size::XL}},
|
||||||
|
{2404, {"Blade 04"_s, Accessory::Size::XL}},
|
||||||
|
{2405, {"Blade 05"_s, Accessory::Size::XL}},
|
||||||
|
{2406, {"Blade 06"_s, Accessory::Size::XL}},
|
||||||
|
{2407, {"Blade 07"_s, Accessory::Size::XL}},
|
||||||
|
{2408, {"Blade 08"_s, Accessory::Size::XL}},
|
||||||
|
{2409, {"Blade 09"_s, Accessory::Size::XL}},
|
||||||
|
{2410, {"Blade 10"_s, Accessory::Size::XL}},
|
||||||
|
{2411, {"Blade 11"_s, Accessory::Size::XL}},
|
||||||
|
{2412, {"Blade 12"_s, Accessory::Size::XL}},
|
||||||
|
{2413, {"Blade 13"_s, Accessory::Size::XL}},
|
||||||
|
{2414, {"Blade 14"_s, Accessory::Size::XL}},
|
||||||
|
{2415, {"Blade 15"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{2426, {"Curved Blade 01"_s, Accessory::Size::XL}},
|
||||||
|
{2427, {"Curved Blade 02"_s, Accessory::Size::XL}},
|
||||||
|
{2428, {"Curved Blade 03"_s, Accessory::Size::XL}},
|
||||||
|
{2429, {"Curved Blade 04"_s, Accessory::Size::XL}},
|
||||||
|
{2430, {"Curved Blade 05"_s, Accessory::Size::XL}},
|
||||||
|
{2431, {"Axe Head 01"_s, Accessory::Size::XL}},
|
||||||
|
{2432, {"Axe Head 02"_s, Accessory::Size::XL}},
|
||||||
|
{2433, {"Axe Head 03"_s, Accessory::Size::XL}},
|
||||||
|
{2434, {"Axe Head 04"_s, Accessory::Size::XL}},
|
||||||
|
{2435, {"Axe Head 05"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{2451, {"Horn 01"_s, Accessory::Size::M}},
|
||||||
|
{2452, {"Horn 02"_s, Accessory::Size::M}},
|
||||||
|
{2453, {"Horn 03"_s, Accessory::Size::M}},
|
||||||
|
{2454, {"Horn 04"_s, Accessory::Size::M}},
|
||||||
|
{2455, {"Horn 05"_s, Accessory::Size::M}},
|
||||||
|
{2456, {"Horn 06"_s, Accessory::Size::M}},
|
||||||
|
{2457, {"Horn 07"_s, Accessory::Size::M}},
|
||||||
|
{2458, {"Horn 08"_s, Accessory::Size::M}},
|
||||||
|
{2459, {"Horn 09"_s, Accessory::Size::M}},
|
||||||
|
{2460, {"Horn 10"_s, Accessory::Size::M}},
|
||||||
|
{2461, {"Horn 11"_s, Accessory::Size::M}},
|
||||||
|
{2462, {"Horn 12"_s, Accessory::Size::M}},
|
||||||
|
{2463, {"Horn 13"_s, Accessory::Size::M}},
|
||||||
|
{2464, {"Horn 14"_s, Accessory::Size::M}},
|
||||||
|
{2465, {"Horn 15"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{2471, {"Mask"_s, Accessory::Size::M}},
|
||||||
|
{2472, {"Droplet"_s, Accessory::Size::M}},
|
||||||
|
{2473, {"Thigh"_s, Accessory::Size::M}},
|
||||||
|
{2474, {"LegS"_s, Accessory::Size::M}},
|
||||||
|
{2475, {"LegTH"_s, Accessory::Size::M}},
|
||||||
|
{2476, {"Plume 01"_s, Accessory::Size::M}},
|
||||||
|
{2477, {"Plume 02"_s, Accessory::Size::M}},
|
||||||
|
{2478, {"Plume 03"_s, Accessory::Size::M}},
|
||||||
|
{2479, {"Plume 04"_s, Accessory::Size::M}},
|
||||||
|
{2480, {"Plume 05"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{2491, {"Tail 01"_s, Accessory::Size::XL}},
|
||||||
|
{2492, {"Tail 02"_s, Accessory::Size::XL}},
|
||||||
|
{2493, {"Tail 03"_s, Accessory::Size::XL}},
|
||||||
|
{2494, {"Tail 04"_s, Accessory::Size::XL}},
|
||||||
|
{2495, {"Tail 05"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{2501, {"Finger 01"_s, Accessory::Size::M}},
|
||||||
|
{2502, {"Finger 02"_s, Accessory::Size::M}},
|
||||||
|
{2503, {"Finger 03"_s, Accessory::Size::M}},
|
||||||
|
{2504, {"Finger 04"_s, Accessory::Size::M}},
|
||||||
|
{2505, {"Finger 05"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{2510, {"Clamp 01"_s, Accessory::Size::M}},
|
||||||
|
{2511, {"Clamp 02"_s, Accessory::Size::M}},
|
||||||
|
{2512, {"Clamp 03"_s, Accessory::Size::M}},
|
||||||
|
{2513, {"Clamp 04"_s, Accessory::Size::M}},
|
||||||
|
{2514, {"Clamp 05"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{2521, {"Fabric 01"_s, Accessory::Size::XL}},
|
||||||
|
{2522, {"Fabric 02"_s, Accessory::Size::XL}},
|
||||||
|
{2523, {"Fabric 03"_s, Accessory::Size::XL}},
|
||||||
|
{2524, {"Fabric 04"_s, Accessory::Size::XL}},
|
||||||
|
{2525, {"Fabric 05"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{2551, {"Energy Barrel 01"_s, Accessory::Size::XL}},
|
||||||
|
{2552, {"Energy Barrel 02"_s, Accessory::Size::XL}},
|
||||||
|
{2553, {"Energy Barrel 03"_s, Accessory::Size::XL}},
|
||||||
|
{2554, {"Energy Barrel 04"_s, Accessory::Size::XL}},
|
||||||
|
{2555, {"Energy Barrel 05"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{2560, {"Wire Head 01"_s, Accessory::Size::M}},
|
||||||
|
{2561, {"Wire Head 02"_s, Accessory::Size::M}},
|
||||||
|
{2562, {"Wire Head 03"_s, Accessory::Size::M}},
|
||||||
|
{2563, {"Wire Head 04"_s, Accessory::Size::M}},
|
||||||
|
{2564, {"Wire Head 05"_s, Accessory::Size::M}},
|
||||||
|
{2565, {"Wire Head 06"_s, Accessory::Size::M}},
|
||||||
|
{2566, {"Wire Head 07"_s, Accessory::Size::M}},
|
||||||
|
{2567, {"Wire Head 08"_s, Accessory::Size::M}},
|
||||||
|
{2568, {"Wire Head 09"_s, Accessory::Size::M}},
|
||||||
|
{2569, {"Wire Head 10"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{2601, {"L Bullet Barrel 01"_s, Accessory::Size::XL}},
|
||||||
|
{2602, {"L Bullet Barrel 02"_s, Accessory::Size::XL}},
|
||||||
|
{2603, {"L Bullet Barrel 03"_s, Accessory::Size::XL}},
|
||||||
|
{2604, {"L Bullet Barrel 04"_s, Accessory::Size::XL}},
|
||||||
|
{2605, {"L Bullet Barrel 05"_s, Accessory::Size::XL}},
|
||||||
|
{2606, {"S Bullet Barrel 01"_s, Accessory::Size::XL}},
|
||||||
|
{2607, {"S Bullet Barrel 02"_s, Accessory::Size::XL}},
|
||||||
|
{2608, {"S Bullet Barrel 03"_s, Accessory::Size::XL}},
|
||||||
|
{2609, {"S Bullet Barrel 04"_s, Accessory::Size::XL}},
|
||||||
|
{2610, {"S Bullet Barrel 05"_s, Accessory::Size::XL}},
|
||||||
|
{2611, {"B Bullet Barrel 01"_s, Accessory::Size::XL}},
|
||||||
|
{2612, {"B Bullet Barrel 02"_s, Accessory::Size::XL}},
|
||||||
|
{2613, {"B Bullet Barrel 03"_s, Accessory::Size::XL}},
|
||||||
|
{2614, {"B Bullet Barrel 04"_s, Accessory::Size::XL}},
|
||||||
|
{2615, {"B Bullet Barrel 05"_s, Accessory::Size::XL}},
|
||||||
|
{2616, {"B Bullet Barrel 06"_s, Accessory::Size::XL}},
|
||||||
|
{2617, {"B Bullet Barrel 07"_s, Accessory::Size::XL}},
|
||||||
|
{2618, {"B Bullet Barrel 08"_s, Accessory::Size::XL}},
|
||||||
|
{2619, {"B Bullet Barrel 09"_s, Accessory::Size::XL}},
|
||||||
|
{2620, {"B Bullet Barrel 10"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{2651, {"Cylinder Scope 01"_s, Accessory::Size::M}},
|
||||||
|
{2652, {"Cylinder Scope 02"_s, Accessory::Size::M}},
|
||||||
|
{2653, {"Cylinder Scope 03"_s, Accessory::Size::M}},
|
||||||
|
{2654, {"Cylinder Scope 04"_s, Accessory::Size::M}},
|
||||||
|
{2655, {"Cylinder Scope 05"_s, Accessory::Size::M}},
|
||||||
|
{2656, {"Elec Scope 01"_s, Accessory::Size::M}},
|
||||||
|
{2657, {"Elec Scope 02"_s, Accessory::Size::M}},
|
||||||
|
{2658, {"Elec Scope 03"_s, Accessory::Size::M}},
|
||||||
|
{2659, {"Elec Scope 04"_s, Accessory::Size::M}},
|
||||||
|
{2660, {"Elec Scope 05"_s, Accessory::Size::M}},
|
||||||
|
{2661, {"Mark Scope 01"_s, Accessory::Size::S}},
|
||||||
|
{2662, {"Mark Scope 02"_s, Accessory::Size::S}},
|
||||||
|
{2663, {"Mark Scope 03"_s, Accessory::Size::S}},
|
||||||
|
{2664, {"Mark Scope 04"_s, Accessory::Size::S}},
|
||||||
|
{2665, {"Mark Scope 05"_s, Accessory::Size::S}},
|
||||||
|
|
||||||
|
{2701, {"S Single Weaponry"_s, Accessory::Size::M}},
|
||||||
|
{2702, {"S Packed Weaponry 01"_s, Accessory::Size::M}},
|
||||||
|
{2703, {"S Packed Weaponry 02"_s, Accessory::Size::M}},
|
||||||
|
{2704, {"S Packed Weaponry 03"_s, Accessory::Size::M}},
|
||||||
|
{2705, {"S Packed Weaponry 04"_s, Accessory::Size::M}},
|
||||||
|
{2706, {"L Single Weaponry"_s, Accessory::Size::XL}},
|
||||||
|
{2707, {"L Packed Weaponry 01"_s, Accessory::Size::XL}},
|
||||||
|
{2708, {"L Packed Weaponry 02"_s, Accessory::Size::XL}},
|
||||||
|
{2709, {"L Packed Weaponry 03"_s, Accessory::Size::XL}},
|
||||||
|
{2710, {"L Packed Weaponry 04"_s, Accessory::Size::XL}},
|
||||||
|
{2711, {"Atk Single Weaponry"_s, Accessory::Size::XL}},
|
||||||
|
{2712, {"Atk Packed Weaponry 01"_s, Accessory::Size::XL}},
|
||||||
|
{2713, {"Atk Packed Weaponry 02"_s, Accessory::Size::XL}},
|
||||||
|
{2714, {"Atk Packed Weaponry 03"_s, Accessory::Size::XL}},
|
||||||
|
{2715, {"Atk Packed Weaponry 04"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{2721, {"Double Pod"_s, Accessory::Size::L}},
|
||||||
|
{2722, {"Triple Pod"_s, Accessory::Size::L}},
|
||||||
|
{2723, {"Vertical T Pod"_s, Accessory::Size::L}},
|
||||||
|
{2724, {"Quadruple Pod"_s, Accessory::Size::L}},
|
||||||
|
{2725, {"Vertical Q Pod"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2741, {"Grenade 01"_s, Accessory::Size::M}},
|
||||||
|
{2742, {"Grenade 02"_s, Accessory::Size::M}},
|
||||||
|
{2743, {"Grenade 03"_s, Accessory::Size::M}},
|
||||||
|
{2744, {"Grenade 04"_s, Accessory::Size::M}},
|
||||||
|
{2745, {"Grenade 05"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{2751, {"Vent 01"_s, Accessory::Size::M}},
|
||||||
|
{2752, {"Vent 02"_s, Accessory::Size::M}},
|
||||||
|
{2753, {"Vent 03"_s, Accessory::Size::M}},
|
||||||
|
{2754, {"Vent 04"_s, Accessory::Size::M}},
|
||||||
|
{2755, {"Vent 05"_s, Accessory::Size::M}},
|
||||||
|
{2756, {"Vent 06"_s, Accessory::Size::M}},
|
||||||
|
{2757, {"Vent 07"_s, Accessory::Size::M}},
|
||||||
|
{2758, {"Vent 08"_s, Accessory::Size::M}},
|
||||||
|
{2759, {"Vent 09"_s, Accessory::Size::M}},
|
||||||
|
{2760, {"Vent 10"_s, Accessory::Size::M}},
|
||||||
|
{2761, {"Cooling Tile 01"_s, Accessory::Size::L}},
|
||||||
|
{2762, {"Cooling Tile 02"_s, Accessory::Size::L}},
|
||||||
|
{2763, {"Cooling Tile 03"_s, Accessory::Size::L}},
|
||||||
|
{2764, {"Cooling Tile 04"_s, Accessory::Size::L}},
|
||||||
|
{2765, {"Cooling Tile 05"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2901, {"Complex Construct 01"_s, Accessory::Size::L}},
|
||||||
|
{2902, {"Complex Construct 02"_s, Accessory::Size::L}},
|
||||||
|
{2903, {"Complex Construct 03"_s, Accessory::Size::L}},
|
||||||
|
{2904, {"Complex Construct 04"_s, Accessory::Size::L}},
|
||||||
|
{2905, {"Complex Construct 05"_s, Accessory::Size::L}},
|
||||||
|
{2906, {"Grating 01"_s, Accessory::Size::M}},
|
||||||
|
{2907, {"Grating 02"_s, Accessory::Size::M}},
|
||||||
|
{2908, {"Grating 03"_s, Accessory::Size::M}},
|
||||||
|
{2909, {"Grating 04"_s, Accessory::Size::M}},
|
||||||
|
{2910, {"Grating 05"_s, Accessory::Size::M}},
|
||||||
|
{2911, {"Wireframe 01"_s, Accessory::Size::L}},
|
||||||
|
{2912, {"Wireframe 02"_s, Accessory::Size::L}},
|
||||||
|
{2913, {"Wireframe 03"_s, Accessory::Size::L}},
|
||||||
|
{2914, {"Wireframe 04"_s, Accessory::Size::L}},
|
||||||
|
{2915, {"Wireframe 05"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2926, {"Complex Armour 01"_s, Accessory::Size::L}},
|
||||||
|
{2927, {"Complex Armour 02"_s, Accessory::Size::L}},
|
||||||
|
{2928, {"Complex Armour 03"_s, Accessory::Size::L}},
|
||||||
|
{2929, {"Complex Armour 04"_s, Accessory::Size::L}},
|
||||||
|
{2930, {"Complex Armour 05"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{2950, {"Q Mask 01"_s, Accessory::Size::M}},
|
||||||
|
{2951, {"Q Mask 02"_s, Accessory::Size::M}},
|
||||||
|
{2952, {"Q Mask 03"_s, Accessory::Size::M}},
|
||||||
|
{2953, {"Q Mask 04"_s, Accessory::Size::M}},
|
||||||
|
{2954, {"Q Mask 05"_s, Accessory::Size::M}},
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Connectors
|
||||||
|
{3001, {"Circular Vent 01"_s, Accessory::Size::M}},
|
||||||
|
{3002, {"Circular Vent 02"_s, Accessory::Size::M}},
|
||||||
|
{3003, {"Circular Vent 03"_s, Accessory::Size::M}},
|
||||||
|
{3004, {"Circular Vent 04"_s, Accessory::Size::M}},
|
||||||
|
{3005, {"Circular Vent 05"_s, Accessory::Size::M}},
|
||||||
|
{3006, {"Circular Vent 06"_s, Accessory::Size::M}},
|
||||||
|
{3007, {"Circular Vent 07"_s, Accessory::Size::M}},
|
||||||
|
{3008, {"Circular Vent 08"_s, Accessory::Size::M}},
|
||||||
|
{3009, {"Circular Vent 09"_s, Accessory::Size::M}},
|
||||||
|
{3010, {"Circular Vent 10"_s, Accessory::Size::M}},
|
||||||
|
{3011, {"Circular Vent 11"_s, Accessory::Size::M}},
|
||||||
|
{3012, {"Circular Vent 12"_s, Accessory::Size::M}},
|
||||||
|
{3013, {"Circular Vent 13"_s, Accessory::Size::M}},
|
||||||
|
{3014, {"Circular Vent 14"_s, Accessory::Size::M}},
|
||||||
|
{3015, {"Circular Vent 15"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{3051, {"Reactor 01"_s, Accessory::Size::L}},
|
||||||
|
{3052, {"Reactor 02"_s, Accessory::Size::L}},
|
||||||
|
{3053, {"Reactor 03"_s, Accessory::Size::L}},
|
||||||
|
{3054, {"Reactor 04"_s, Accessory::Size::L}},
|
||||||
|
{3055, {"Reactor 05"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{3101, {"Connecting Tube 01"_s, Accessory::Size::XL}},
|
||||||
|
{3102, {"Connecting Tube 02"_s, Accessory::Size::XL}},
|
||||||
|
{3103, {"Connecting Tube 03"_s, Accessory::Size::XL}},
|
||||||
|
{3104, {"Connecting Tube 04"_s, Accessory::Size::XL}},
|
||||||
|
{3105, {"Connecting Tube 05"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{3151, {"Latch 01"_s, Accessory::Size::M}},
|
||||||
|
{3152, {"Latch 02"_s, Accessory::Size::M}},
|
||||||
|
{3153, {"Latch 03"_s, Accessory::Size::M}},
|
||||||
|
{3154, {"Latch 04"_s, Accessory::Size::M}},
|
||||||
|
{3155, {"Latch 05"_s, Accessory::Size::M}},
|
||||||
|
{3156, {"Latch 06"_s, Accessory::Size::M}},
|
||||||
|
{3157, {"Latch 07"_s, Accessory::Size::M}},
|
||||||
|
{3158, {"Latch 08"_s, Accessory::Size::M}},
|
||||||
|
{3159, {"Latch 09"_s, Accessory::Size::M}},
|
||||||
|
{3160, {"Latch 10"_s, Accessory::Size::M}},
|
||||||
|
{3161, {"Latch 11"_s, Accessory::Size::M}},
|
||||||
|
{3162, {"Latch 12"_s, Accessory::Size::M}},
|
||||||
|
{3163, {"Latch 13"_s, Accessory::Size::M}},
|
||||||
|
{3164, {"Latch 14"_s, Accessory::Size::M}},
|
||||||
|
{3165, {"Latch 15"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{3201, {"Short Connector 01"_s, Accessory::Size::M}},
|
||||||
|
{3202, {"Short Connector 02"_s, Accessory::Size::M}},
|
||||||
|
{3203, {"Short Connector 03"_s, Accessory::Size::M}},
|
||||||
|
{3204, {"Short Connector 04"_s, Accessory::Size::M}},
|
||||||
|
{3205, {"Short Connector 05"_s, Accessory::Size::M}},
|
||||||
|
{3206, {"Antenna 01"_s, Accessory::Size::S}},
|
||||||
|
{3207, {"Antenna 02"_s, Accessory::Size::S}},
|
||||||
|
{3208, {"Antenna 03"_s, Accessory::Size::S}},
|
||||||
|
{3209, {"Antenna 04"_s, Accessory::Size::S}},
|
||||||
|
{3210, {"Antenna 05"_s, Accessory::Size::S}},
|
||||||
|
|
||||||
|
{3226, {"Long Connector 01"_s, Accessory::Size::XL}},
|
||||||
|
{3227, {"Long Connector 02"_s, Accessory::Size::XL}},
|
||||||
|
{3228, {"Long Connector 03"_s, Accessory::Size::XL}},
|
||||||
|
{3229, {"Long Connector 04"_s, Accessory::Size::XL}},
|
||||||
|
{3230, {"Long Connector 05"_s, Accessory::Size::XL}},
|
||||||
|
{3231, {"Long Connector 06"_s, Accessory::Size::XL}},
|
||||||
|
{3232, {"Long Connector 07"_s, Accessory::Size::XL}},
|
||||||
|
{3233, {"Long Connector 08"_s, Accessory::Size::XL}},
|
||||||
|
{3234, {"Long Connector 09"_s, Accessory::Size::XL}},
|
||||||
|
{3235, {"Long Connector 10"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{3251, {"Complex Connector 01"_s, Accessory::Size::XL}},
|
||||||
|
{3252, {"Complex Connector 02"_s, Accessory::Size::XL}},
|
||||||
|
{3253, {"Complex Connector 03"_s, Accessory::Size::XL}},
|
||||||
|
{3254, {"Complex Connector 04"_s, Accessory::Size::XL}},
|
||||||
|
{3255, {"Complex Connector 05"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{3301, {"Tube Line 01"_s, Accessory::Size::L}},
|
||||||
|
{3302, {"Tube Line 02"_s, Accessory::Size::L}},
|
||||||
|
{3303, {"Tube Line 03"_s, Accessory::Size::L}},
|
||||||
|
{3304, {"Tube Line 04"_s, Accessory::Size::XL}},
|
||||||
|
{3305, {"Tube Line 05"_s, Accessory::Size::XL}},
|
||||||
|
{3306, {"Tube Line 06"_s, Accessory::Size::M}},
|
||||||
|
{3307, {"Tube Line 07"_s, Accessory::Size::M}},
|
||||||
|
{3308, {"Tube Line 08"_s, Accessory::Size::M}},
|
||||||
|
{3309, {"Tube Line 09"_s, Accessory::Size::L}},
|
||||||
|
{3310, {"Tube Line 10"_s, Accessory::Size::L}},
|
||||||
|
|
||||||
|
{3351, {"Radar Plate 01"_s, Accessory::Size::M}},
|
||||||
|
{3352, {"Radar Plate 02"_s, Accessory::Size::M}},
|
||||||
|
{3353, {"Radar Plate 03"_s, Accessory::Size::M}},
|
||||||
|
{3354, {"Radar Plate 04"_s, Accessory::Size::M}},
|
||||||
|
{3355, {"Radar Plate 05"_s, Accessory::Size::M}},
|
||||||
|
{3356, {"Radar Pod 01"_s, Accessory::Size::M}},
|
||||||
|
{3357, {"Radar Pod 02"_s, Accessory::Size::M}},
|
||||||
|
{3358, {"Radar Pod 03"_s, Accessory::Size::M}},
|
||||||
|
{3359, {"Radar Pod 04"_s, Accessory::Size::M}},
|
||||||
|
{3360, {"Radar Pod 05"_s, Accessory::Size::M}},
|
||||||
|
{3361, {"Radar Ring 01"_s, Accessory::Size::XL}},
|
||||||
|
{3362, {"Radar Ring 02"_s, Accessory::Size::XL}},
|
||||||
|
{3363, {"Radar Ring 03"_s, Accessory::Size::XL}},
|
||||||
|
{3364, {"Radar Ring 04"_s, Accessory::Size::XL}},
|
||||||
|
{3365, {"Radar Ring 05"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{3401, {"Tri Pod 01"_s, Accessory::Size::M}},
|
||||||
|
{3402, {"Tri Pod 02"_s, Accessory::Size::M}},
|
||||||
|
{3403, {"Tri Pod 03"_s, Accessory::Size::M}},
|
||||||
|
{3404, {"Tri Pod 04"_s, Accessory::Size::M}},
|
||||||
|
{3405, {"Tri Pod 05"_s, Accessory::Size::M}},
|
||||||
|
{3406, {"Signal Pod 01"_s, Accessory::Size::M}},
|
||||||
|
{3407, {"Signal Pod 02"_s, Accessory::Size::M}},
|
||||||
|
{3408, {"Signal Pod 03"_s, Accessory::Size::M}},
|
||||||
|
{3409, {"Signal Pod 04"_s, Accessory::Size::M}},
|
||||||
|
{3410, {"Signal Pod 05"_s, Accessory::Size::M}},
|
||||||
|
|
||||||
|
{3451, {"Track Wheel 01"_s, Accessory::Size::XL}},
|
||||||
|
{3452, {"Track Wheel 02"_s, Accessory::Size::XL}},
|
||||||
|
{3453, {"Track Wheel 03"_s, Accessory::Size::XL}},
|
||||||
|
{3454, {"Track Wheel 04"_s, Accessory::Size::XL}},
|
||||||
|
{3455, {"Track Wheel 05"_s, Accessory::Size::XL}},
|
||||||
|
{3456, {"Track Chain 01"_s, Accessory::Size::XL}},
|
||||||
|
{3457, {"Track Chain 02"_s, Accessory::Size::XL}},
|
||||||
|
{3458, {"Track Chain 03"_s, Accessory::Size::XL}},
|
||||||
|
{3459, {"Track Chain 04"_s, Accessory::Size::XL}},
|
||||||
|
{3460, {"Track Chain 05"_s, Accessory::Size::XL}},
|
||||||
|
{3461, {"Track Chain 06"_s, Accessory::Size::XL}},
|
||||||
|
{3462, {"Track Chain 07"_s, Accessory::Size::XL}},
|
||||||
|
{3463, {"Track Chain 08"_s, Accessory::Size::XL}},
|
||||||
|
{3464, {"Track Chain 09"_s, Accessory::Size::XL}},
|
||||||
|
{3465, {"Track Chain 10"_s, Accessory::Size::XL}},
|
||||||
|
{3466, {"Track Chain 11"_s, Accessory::Size::XL}},
|
||||||
|
{3467, {"Track Chain 12"_s, Accessory::Size::XL}},
|
||||||
|
{3468, {"Track Chain 13"_s, Accessory::Size::XL}},
|
||||||
|
{3469, {"Track Chain 14"_s, Accessory::Size::XL}},
|
||||||
|
{3470, {"Track Chain 15"_s, Accessory::Size::XL}},
|
||||||
|
|
||||||
|
{3500, {"Wire Module 05"_s, Accessory::Size::XL}},
|
||||||
|
{3501, {"Wire Module 06"_s, Accessory::Size::XL}},
|
||||||
|
{3502, {"Wire Module 07"_s, Accessory::Size::XL}},
|
||||||
|
{3503, {"Wire Module 08"_s, Accessory::Size::XL}},
|
||||||
|
{3504, {"Wire Module 09"_s, Accessory::Size::XL}},
|
||||||
|
{3505, {"Wire Module 10"_s, Accessory::Size::XL}},
|
||||||
|
{3506, {"Wire Module 11"_s, Accessory::Size::XL}},
|
||||||
|
{3507, {"Wire Module 12"_s, Accessory::Size::XL}},
|
||||||
|
{3508, {"Wire Module 13"_s, Accessory::Size::XL}},
|
||||||
|
{3509, {"Wire Module 14"_s, Accessory::Size::XL}},
|
||||||
|
{3510, {"Wire Module 15"_s, Accessory::Size::XL}},
|
||||||
|
{3511, {"Wire Module 06"_s, Accessory::Size::XL}},
|
||||||
|
{3512, {"Wire Module 07"_s, Accessory::Size::XL}},
|
||||||
|
{3513, {"Wire Module 08"_s, Accessory::Size::XL}},
|
||||||
|
{3514, {"Wire Module 09"_s, Accessory::Size::XL}},
|
||||||
|
// endregion
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,22 +16,24 @@
|
||||||
// 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 <cstdint>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
using namespace Magnum;
|
|
||||||
|
namespace mbst::GameData {
|
||||||
|
|
||||||
struct ArmourSet {
|
struct ArmourSet {
|
||||||
Containers::StringView name;
|
Containers::StringView name;
|
||||||
bool neck_compatible;
|
bool neck_compatible;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<Int, ArmourSet> armour_sets {
|
static const std::map<std::int32_t, ArmourSet> armour_sets {
|
||||||
|
{-2, {"<hidden>"_s, false}},
|
||||||
{-1, {"<unequipped>"_s, true}},
|
{-1, {"<unequipped>"_s, true}},
|
||||||
{0, {"Vanguard"_s, true}},
|
{0, {"Vanguard"_s, true}},
|
||||||
{1, {"Assault Mk.I"_s, true}},
|
{1, {"Assault Mk.I"_s, true}},
|
||||||
|
@ -55,4 +57,9 @@ static const std::map<Int, ArmourSet> armour_sets {
|
||||||
{25, {"Axial Core R-Type"_s, true}},
|
{25, {"Axial Core R-Type"_s, true}},
|
||||||
{26, {"Axial Core S-Type"_s, false}},
|
{26, {"Axial Core S-Type"_s, false}},
|
||||||
{27, {"Axial Core X-Type"_s, false}},
|
{27, {"Axial Core X-Type"_s, false}},
|
||||||
|
{28, {"Zenith-X"_s, true}},
|
||||||
|
{29, {"Zenith-Y"_s, false}},
|
||||||
|
{30, {"Zenith-Z"_s, false}},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
70
src/GameData/LastMissionId.h
Normal file
70
src/GameData/LastMissionId.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameData {
|
||||||
|
|
||||||
|
static const std::map<std::int32_t, Containers::StringView> mission_id_map {{
|
||||||
|
// Story missions
|
||||||
|
{100, "Mission 1 - Training"_s},
|
||||||
|
{101, "Mission 2 - Patrol Operation"_s},
|
||||||
|
{102, "Mission 3 - Fusion Cells in the Snow"_s},
|
||||||
|
{103, "Mission 4 - Earning Changes"_s},
|
||||||
|
{104, "Mission 5 - Unexpected Coordination"_s},
|
||||||
|
{105, "Mission 6 - Empowering Void"_s},
|
||||||
|
{106, "Mission 7 - Logisitics Obstacles"_s},
|
||||||
|
{107, "Mission 8 - Wrath of the Wastelands"_s},
|
||||||
|
{108, "Mission 9 - Suspicious Originator"_s},
|
||||||
|
{109, "Mission 10 - Researchers Data Recovery"_s},
|
||||||
|
{110, "Mission 11 - Tempestuous Sector"_s},
|
||||||
|
{111, "Mission 12 - Clashes of Metal"_s},
|
||||||
|
{112, "Mission 13 - The Sandstorm Glutton"_s},
|
||||||
|
{113, "Mission 14 - An Icy Investigation"_s},
|
||||||
|
{114, "Mission 15 - Outposts Line of Defense"_s},
|
||||||
|
{115, "Mission 16 - Hidden in the Pass"_s},
|
||||||
|
{116, "Mission 17 - Homebase Security"_s},
|
||||||
|
{117, "Mission 18 - Molewarp Protection Deal"_s},
|
||||||
|
{118, "Mission 19 - Behind the Walls of Ice"_s},
|
||||||
|
{119, "Mission 20 - Odin in the Sea of Flames"_s},
|
||||||
|
{120, "Mission 21 - Retracing Ruined Shelter"_s},
|
||||||
|
{121, "Mission 22 - The Traitor"_s},
|
||||||
|
{122, "Mission 23 - Duel of Aces"_s},
|
||||||
|
|
||||||
|
// Hunting grounds
|
||||||
|
{200, "Hunt 1 - Desert Pathway Safety"_s},
|
||||||
|
{201, "Hunt 2 - Snowfield Custodian"_s},
|
||||||
|
{202, "Hunt 3 - Abandoned Valley Raid"_s},
|
||||||
|
{203, "Hunt 4 - Depths of the Machineries"_s},
|
||||||
|
{204, "Hunt 5 - Crater Crashers"_s},
|
||||||
|
{205, "Hunt 6 - Prototype Performance Tests"_s},
|
||||||
|
{206, "Hunt 7 - A Mess in Manufacturing"_s},
|
||||||
|
{207, "Hunt 8 - Visitors in Volcanic Fissures"_s},
|
||||||
|
|
||||||
|
// Challenges
|
||||||
|
{300, "Challenge 1 - Redline Battlefront"_s},
|
||||||
|
{320, "Challenge 2 - Void Convergence"_s},
|
||||||
|
{400, "Challenge 3 - Gates of Ascension"_s}
|
||||||
|
}};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,32 +16,40 @@
|
||||||
// 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 <Magnum/Types.h>
|
namespace mbst::GameData {
|
||||||
|
|
||||||
using namespace Magnum;
|
enum MaterialID : std::int32_t {
|
||||||
|
|
||||||
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,
|
||||||
|
Unnoctinium = 0xC3506,
|
||||||
|
|
||||||
Ednil = 0xC350A,
|
Ednil = 0xC350A,
|
||||||
Nuflalt = 0xC350B,
|
Nuflalt = 0xC350B,
|
||||||
Aurelene = 0xC350C,
|
Aurelene = 0xC350C,
|
||||||
Soldus = 0xC350D,
|
Soldus = 0xC350D,
|
||||||
SynthesisedN = 0xC350E,
|
SynthesisedN = 0xC350E,
|
||||||
|
Nanoc = 0xC350F,
|
||||||
|
Abyssillite = 0xC3510,
|
||||||
|
|
||||||
Alcarbonite = 0xC3514,
|
Alcarbonite = 0xC3514,
|
||||||
Keriphene = 0xC3515,
|
Keriphene = 0xC3515,
|
||||||
NitinolCM = 0xC3516,
|
NitinolCM = 0xC3516,
|
||||||
Quarkium = 0xC3517,
|
Quarkium = 0xC3517,
|
||||||
Alterene = 0xC3518,
|
Alterene = 0xC3518,
|
||||||
|
Cosmium = 0xC3519,
|
||||||
|
PurifiedQuarkium = 0xC351A,
|
||||||
|
|
||||||
MixedComposition = 0xDBBA0,
|
MixedComposition = 0xDBBA0,
|
||||||
VoidResidue = 0xDBBA1,
|
VoidResidue = 0xDBBA1,
|
||||||
MuscularConstruction = 0xDBBA2,
|
MuscularConstruction = 0xDBBA2,
|
||||||
MineralExoskeletology = 0xDBBA3,
|
MineralExoskeletology = 0xDBBA3,
|
||||||
CarbonisedSkin = 0xDBBA4
|
CarbonisedSkin = 0xDBBA4,
|
||||||
|
IsolatedVoidParticle = 0xDBBA5,
|
||||||
|
WeaponisedPhysiology = 0xDBBA6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,16 +19,15 @@
|
||||||
#include <Corrade/Containers/Array.h>
|
#include <Corrade/Containers/Array.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
using namespace Magnum;
|
|
||||||
|
namespace mbst::GameData {
|
||||||
|
|
||||||
struct StoryProgressPoint {
|
struct StoryProgressPoint {
|
||||||
Int id;
|
std::int32_t id{};
|
||||||
Containers::StringView chapter;
|
Containers::StringView chapter = nullptr;
|
||||||
Containers::StringView point;
|
Containers::StringView point = nullptr;
|
||||||
Containers::StringView after = nullptr;
|
Containers::StringView after = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,5 +102,34 @@ static const Corrade::Containers::Array<StoryProgressPoint> story_progress
|
||||||
{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},
|
||||||
|
{0x0709, "Chapter 3"_s, "Returned to hangar"_s, "After mission 17"_s},
|
||||||
|
{0x070A, "Chapter 3"_s, "Got hunt 6 briefing"_s, "After mission 17"_s},
|
||||||
|
{0x070B, "Chapter 3"_s, "Returned to hangar"_s, "After mission 17"_s},
|
||||||
|
{0x070C, "Chapter 3"_s, "Got mission 18 briefing"_s, "After mission 17"_s},
|
||||||
|
{0x076C, "Chapter 3"_s, "Debriefing"_s, "After mission 18"_s},
|
||||||
|
{0x076D, "Chapter 3"_s, "Returned to hangar"_s, "After mission 18"_s},
|
||||||
|
{0x076E, "Chapter 3"_s, "Got hunt 7 and mission 19 briefing"_s, "After mission 18"_s},
|
||||||
|
|
||||||
|
{0x07D0, "Chapter 4"_s, "Debriefing"_s, "After mission 19"_s},
|
||||||
|
{0x07D1, "Chapter 4"_s, "Returned to hangar"_s, "After mission 19"_s},
|
||||||
|
{0x07D2, "Chapter 4"_s, "Got mission 20 briefing"_s, "After mission 19"_s},
|
||||||
|
{0x0834, "Chapter 4"_s, "Debriefing"_s, "After mission 20"_s},
|
||||||
|
{0x0835, "Chapter 4"_s, "Returned to hangar"_s, "After mission 20"_s},
|
||||||
|
{0x0836, "Chapter 4"_s, "Got hunt 8 and mission 21 briefing"_s, "After mission 20"_s},
|
||||||
|
{0x0898, "Chapter 4"_s, "Debriefing"_s, "After mission 21"_s},
|
||||||
|
{0x0899, "Chapter 4"_s, "Returned to hangar"_s, "After mission 21"_s},
|
||||||
|
{0x089A, "Chapter 4"_s, "Got mission 22 briefing"_s, "After mission 21"_s},
|
||||||
|
{0x08FC, "Chapter 4"_s, "Debriefing"_s, "After mission 22"_s},
|
||||||
|
{0x08FD, "Chapter 4"_s, "Returned to hangar"_s, "After mission 22"_s},
|
||||||
|
{0x08FE, "Chapter 4"_s, "Got mission 23 briefing"_s, "After mission 22"_s},
|
||||||
|
{0x0960, "Chapter 4"_s, "Returned to hangar"_s, "After mission 23"_s},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,53 +16,20 @@
|
||||||
// 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 <cstdint>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Magnum.h>
|
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
extern const std::map<Int, Containers::StringView> style_names
|
namespace mbst::GameData {
|
||||||
|
|
||||||
|
extern const std::map<std::int32_t, Containers::StringView> builtin_style_names
|
||||||
#ifdef STYLENAMES_DEFINITION
|
#ifdef STYLENAMES_DEFINITION
|
||||||
{
|
{
|
||||||
{0, "Custom Style 1"_s},
|
|
||||||
{1, "Custom Style 2"_s},
|
|
||||||
{2, "Custom Style 3"_s},
|
|
||||||
{3, "Custom Style 4"_s},
|
|
||||||
{4, "Custom Style 5"_s},
|
|
||||||
{5, "Custom Style 6"_s},
|
|
||||||
{6, "Custom Style 7"_s},
|
|
||||||
{7, "Custom Style 8"_s},
|
|
||||||
{8, "Custom Style 9"_s},
|
|
||||||
{9, "Custom Style 10"_s},
|
|
||||||
{10, "Custom Style 11"_s},
|
|
||||||
{11, "Custom Style 12"_s},
|
|
||||||
{12, "Custom Style 13"_s},
|
|
||||||
{13, "Custom Style 14"_s},
|
|
||||||
{14, "Custom Style 15"_s},
|
|
||||||
{15, "Custom Style 16"_s},
|
|
||||||
|
|
||||||
{50, "Global Style 1"_s},
|
|
||||||
{51, "Global Style 2"_s},
|
|
||||||
{52, "Global Style 3"_s},
|
|
||||||
{53, "Global Style 4"_s},
|
|
||||||
{54, "Global Style 5"_s},
|
|
||||||
{55, "Global Style 6"_s},
|
|
||||||
{56, "Global Style 7"_s},
|
|
||||||
{57, "Global Style 8"_s},
|
|
||||||
{58, "Global Style 9"_s},
|
|
||||||
{59, "Global Style 10"_s},
|
|
||||||
{60, "Global Style 11"_s},
|
|
||||||
{61, "Global Style 12"_s},
|
|
||||||
{62, "Global Style 13"_s},
|
|
||||||
{63, "Global Style 14"_s},
|
|
||||||
{64, "Global Style 15"_s},
|
|
||||||
{65, "Global Style 16"_s},
|
|
||||||
|
|
||||||
{100, "Iron"_s},
|
{100, "Iron"_s},
|
||||||
{101, "Silver"_s},
|
{101, "Silver"_s},
|
||||||
{102, "Gold"_s},
|
{102, "Gold"_s},
|
||||||
|
@ -194,3 +161,5 @@ extern const std::map<Int, Containers::StringView> style_names
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
;
|
;
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -15,19 +15,20 @@
|
||||||
// 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 <cstdint>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameData {
|
||||||
|
|
||||||
// region Melee
|
// region Melee
|
||||||
static const std::map<Int, Containers::StringView> melee_grips {
|
static const std::map<std::int32_t, Containers::StringView> melee_grips {
|
||||||
{0, "Combat Grip (1H)"_s},
|
{0, "Combat Grip (1H)"_s},
|
||||||
{1, "Knuckle Guard Grip (1H)"_s},
|
{1, "Knuckle Guard Grip (1H)"_s},
|
||||||
{2, "Dual Guard Grip (1H)"_s},
|
{2, "Dual Guard Grip (1H)"_s},
|
||||||
|
@ -36,6 +37,7 @@ static const std::map<Int, Containers::StringView> melee_grips {
|
||||||
{5, "Guardian Grip (1H)"_s},
|
{5, "Guardian Grip (1H)"_s},
|
||||||
{6, "Knight Guard Grip (1H)"_s},
|
{6, "Knight Guard Grip (1H)"_s},
|
||||||
{7, "Saber Guard Grip (1H)"_s},
|
{7, "Saber Guard Grip (1H)"_s},
|
||||||
|
{8, "Base Grip (1H)"_s},
|
||||||
|
|
||||||
{100, "Combat Side Grip (1H)"_s},
|
{100, "Combat Side Grip (1H)"_s},
|
||||||
{101, "Hollowed Side Grip (1H)"_s},
|
{101, "Hollowed Side Grip (1H)"_s},
|
||||||
|
@ -43,42 +45,63 @@ static const std::map<Int, Containers::StringView> melee_grips {
|
||||||
{103, "Plated Side Grip (1H)"_s},
|
{103, "Plated Side Grip (1H)"_s},
|
||||||
{104, "Locked Side Grip (1H)"_s},
|
{104, "Locked Side Grip (1H)"_s},
|
||||||
{105, "Longpoint Side Grip (1H)"_s},
|
{105, "Longpoint Side Grip (1H)"_s},
|
||||||
|
{106, "Concave Side Grip (1H)"_s},
|
||||||
|
{107, "Polehead Side Grip (1H)"_s},
|
||||||
|
{108, "Base Side Grip (1H)"_s},
|
||||||
|
|
||||||
{200, "Combat Dual Grip (1H)"_s},
|
{200, "Combat Dual Grip (1H)"_s},
|
||||||
{201, "Hollowed Dual Grip (1H)"_s},
|
{201, "Hollowed Dual Grip (1H)"_s},
|
||||||
{202, "Plated Dual Grip (1H)"_s},
|
{202, "Plated Dual Grip (1H)"_s},
|
||||||
|
{203, "Concave Dual Grip (1H)"_s},
|
||||||
|
{204, "Polehead Dual Grip (1H)"_s},
|
||||||
|
|
||||||
{400, "Combat Twin Grip (1H)"_s},
|
{400, "Combat Twin Grip (1H)"_s},
|
||||||
{401, "Sepal Twin Grip (1H)"_s},
|
{401, "Sepal Twin Grip (1H)"_s},
|
||||||
{402, "Hollowed Twin Grip (1H)"_s},
|
{402, "Hollowed Twin Grip (1H)"_s},
|
||||||
{403, "Knuckle Guard Twin Grip (1H)"_s},
|
{403, "Knuckle Guard Twin Grip (1H)"_s},
|
||||||
{404, "Arched Twin Grip (1H)"_s},
|
{404, "Arched Twin Grip (1H)"_s},
|
||||||
|
{405, "Handguard Twin Grip (1H)"_s},
|
||||||
|
{406, "Fullguard Twin Grip (1H)"_s},
|
||||||
|
{407, "Base Twin Grip (1H)"_s},
|
||||||
|
|
||||||
{1000, "Combat Knuckle (R/L)"_s},
|
{1000, "Combat Knuckle (R/L)"_s},
|
||||||
{1001, "Battle Fist (R/L)"_s},
|
{1001, "Battle Fist (R/L)"_s},
|
||||||
{1002, "Guard Knuckle (R/L)"_s},
|
{1002, "Guard Knuckle (R/L)"_s},
|
||||||
|
{1003, "Heavy Fist (R/L)"_s},
|
||||||
|
{1004, "Thick Fist (R/L)"_s},
|
||||||
|
{1005, "Base Fist (R/L)"_s},
|
||||||
|
|
||||||
{2000, "Combat Polearm (2H)"_s},
|
{2000, "Combat Polearm (2H)"_s},
|
||||||
{2001, "Dual Guard Polearm (2H)"_s},
|
{2001, "Dual Guard Polearm (2H)"_s},
|
||||||
{2002, "Sepal Polearm (2H)"_s},
|
{2002, "Sepal Polearm (2H)"_s},
|
||||||
{2003, "Fin Polearm (2H)"_s},
|
{2003, "Fin Polearm (2H)"_s},
|
||||||
{2004, "Arched Polearm (2H)"_s},
|
{2004, "Arched Polearm (2H)"_s},
|
||||||
|
{2005, "Sharp Polearm (2H)"_s},
|
||||||
|
{2006, "Ring Polearm (2H)"_s},
|
||||||
|
{2007, "Base Polearm (2H)"_s},
|
||||||
|
|
||||||
{2100, "Combat Side Polearm (2H)"_s},
|
{2100, "Combat Side Polearm (2H)"_s},
|
||||||
{2101, "Plated Side Polearm (2H)"_s},
|
{2101, "Plated Side Polearm (2H)"_s},
|
||||||
{2102, "Locked Side Polearm (2H)"_s},
|
{2102, "Locked Side Polearm (2H)"_s},
|
||||||
{2103, "Fin Side Polearm (2H)"_s},
|
{2103, "Fin Side Polearm (2H)"_s},
|
||||||
|
{2104, "Heavy Side Polearm (2H)"_s},
|
||||||
|
{2105, "Base Side Polearm (2H)"_s},
|
||||||
|
|
||||||
{2200, "Combat Dual Polearm (2H)"_s},
|
{2200, "Combat Dual Polearm (2H)"_s},
|
||||||
|
{2201, "Studded Dual Polearm (2H)"_s},
|
||||||
|
{2202, "Circular Dual Polearm (2H)"_s},
|
||||||
|
|
||||||
{2400, "Combat Twin Blade (2H)"_s},
|
{2400, "Combat Twin Blade (2H)"_s},
|
||||||
{2401, "Guard Twin Blade (2H)"_s},
|
{2401, "Guard Twin Blade (2H)"_s},
|
||||||
{2402, "Sepal Twin Blade (2H)"_s},
|
{2402, "Sepal Twin Blade (2H)"_s},
|
||||||
{2403, "Fin Twin Blade (2H)"_s},
|
{2403, "Fin Twin Blade (2H)"_s},
|
||||||
{2404, "Arched Twin Blade (2H)"_s},
|
{2404, "Arched Twin Blade (2H)"_s},
|
||||||
|
{2405, "Holder Twin Blade (2H)"_s},
|
||||||
|
{2406, "Ring Twin Blade (2H)"_s},
|
||||||
|
{2407, "Base Twin Blade (2H)"_s},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<Int, Containers::StringView> melee_assaulters {
|
static const std::map<std::int32_t, Containers::StringView> melee_assaulters {
|
||||||
{0, "Long Metal Blade"_s},
|
{0, "Long Metal Blade"_s},
|
||||||
{1, "Long Assault Blade"_s},
|
{1, "Long Assault Blade"_s},
|
||||||
{2, "Long Fin Blade"_s},
|
{2, "Long Fin Blade"_s},
|
||||||
|
@ -91,6 +114,7 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
||||||
{9, "Long Flat Gouger"_s},
|
{9, "Long Flat Gouger"_s},
|
||||||
{10, "Long Curved Blade"_s},
|
{10, "Long Curved Blade"_s},
|
||||||
{11, "Long Broad Blade"_s},
|
{11, "Long Broad Blade"_s},
|
||||||
|
{12, "Base L Sword"_s},
|
||||||
|
|
||||||
{20, "Long Combat Edge"_s},
|
{20, "Long Combat Edge"_s},
|
||||||
{21, "Long Attached Edge"_s},
|
{21, "Long Attached Edge"_s},
|
||||||
|
@ -104,6 +128,7 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
||||||
{100, "Short Metal Blade"_s},
|
{100, "Short Metal Blade"_s},
|
||||||
{101, "Short Assault Blade"_s},
|
{101, "Short Assault Blade"_s},
|
||||||
{102, "Short Fin Blade"_s},
|
{102, "Short Fin Blade"_s},
|
||||||
|
{103, "Base S Sword"_s},
|
||||||
|
|
||||||
{120, "Short Combat Edge"_s},
|
{120, "Short Combat Edge"_s},
|
||||||
|
|
||||||
|
@ -119,6 +144,7 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
||||||
|
|
||||||
{200, "Bracer"_s},
|
{200, "Bracer"_s},
|
||||||
{201, "Custom Bracer"_s},
|
{201, "Custom Bracer"_s},
|
||||||
|
{202, "Base Hammer"_s},
|
||||||
|
|
||||||
{210, "Expanded Bracer"_s},
|
{210, "Expanded Bracer"_s},
|
||||||
{211, "Expanded Custom Bracer"_s},
|
{211, "Expanded Custom Bracer"_s},
|
||||||
|
@ -126,10 +152,18 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
||||||
{300, "Heavy Smasher"_s},
|
{300, "Heavy Smasher"_s},
|
||||||
{301, "Heavy Basher"_s},
|
{301, "Heavy Basher"_s},
|
||||||
{302, "Heavy Torch Mace"_s},
|
{302, "Heavy Torch Mace"_s},
|
||||||
|
{303, "Heavy Spike Club"_s},
|
||||||
|
{304, "Heavy Diamond Smasher"_s},
|
||||||
|
{305, "Heavy Spinning Smasher (Motion)"_s},
|
||||||
|
{306, "Base L Mace"_s},
|
||||||
|
|
||||||
{400, "Light Smasher"_s},
|
{400, "Light Smasher"_s},
|
||||||
{401, "Light Basher"_s},
|
{401, "Light Basher"_s},
|
||||||
{402, "Light Torch Mace"_s},
|
{402, "Light Torch Mace"_s},
|
||||||
|
{403, "Light Spike Club"_s},
|
||||||
|
{404, "Light Diamond Smasher"_s},
|
||||||
|
{405, "Light Spinning Smasher"_s},
|
||||||
|
{406, "Base S Mace"_s},
|
||||||
|
|
||||||
{420, "War Hammer"_s},
|
{420, "War Hammer"_s},
|
||||||
{421, "Great Hammer"_s},
|
{421, "Great Hammer"_s},
|
||||||
|
@ -141,13 +175,16 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
||||||
|
|
||||||
{500, "Combat Lance"_s},
|
{500, "Combat Lance"_s},
|
||||||
{501, "Gouger Lance"_s},
|
{501, "Gouger Lance"_s},
|
||||||
|
{502, "Pointy Lance"_s},
|
||||||
|
{503, "Spinning Pointy Lance (Motion)"_s},
|
||||||
|
{504, "Crystal Lance"_s},
|
||||||
{510, "Piercer"_s},
|
{510, "Piercer"_s},
|
||||||
|
|
||||||
{600, "Short Combat Lance"_s},
|
{600, "Short Combat Lance"_s},
|
||||||
|
{601, "Short Pointy Lance"_s},
|
||||||
|
{602, "Short Spinning Pointy Lance (Motion)"_s},
|
||||||
|
{603, "Short Crystal Lance"_s},
|
||||||
{605, "Short Combat Drill (Motion)"_s},
|
{605, "Short Combat Drill (Motion)"_s},
|
||||||
|
|
||||||
{610, "Short Piercer"_s},
|
{610, "Short Piercer"_s},
|
||||||
|
|
||||||
{700, "Combat Axe"_s},
|
{700, "Combat Axe"_s},
|
||||||
|
@ -172,7 +209,7 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Shields
|
// region Shields
|
||||||
static const std::map<Int, Containers::StringView> shield_handles {
|
static const std::map<std::int32_t, Containers::StringView> shield_handles {
|
||||||
{0, "Balanced Handle"_s},
|
{0, "Balanced Handle"_s},
|
||||||
{1, "Expanded Handle"_s},
|
{1, "Expanded Handle"_s},
|
||||||
{2, "Lowguard Handle"_s},
|
{2, "Lowguard Handle"_s},
|
||||||
|
@ -191,7 +228,7 @@ static const std::map<Int, Containers::StringView> shield_handles {
|
||||||
{101, "Star Handle"_s},
|
{101, "Star Handle"_s},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<Int, Containers::StringView> shield_shells {
|
static const std::map<std::int32_t, Containers::StringView> shield_shells {
|
||||||
{0, "Balanced Shell"_s},
|
{0, "Balanced Shell"_s},
|
||||||
{1, "Compass Shell"_s},
|
{1, "Compass Shell"_s},
|
||||||
{2, "Uppoint Shell"_s},
|
{2, "Uppoint Shell"_s},
|
||||||
|
@ -212,7 +249,7 @@ static const std::map<Int, Containers::StringView> shield_shells {
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Bullet Shooters
|
// region Bullet Shooters
|
||||||
static const std::map<Int, Containers::StringView> bshooter_triggers {
|
static const std::map<std::int32_t, Containers::StringView> bshooter_triggers {
|
||||||
{0, "BL-Combat Trigger (1H)"_s},
|
{0, "BL-Combat Trigger (1H)"_s},
|
||||||
{1, "Light Machine Trigger (1H)"_s},
|
{1, "Light Machine Trigger (1H)"_s},
|
||||||
{2, "Tactical Trigger (1H)"_s},
|
{2, "Tactical Trigger (1H)"_s},
|
||||||
|
@ -220,40 +257,59 @@ static const std::map<Int, Containers::StringView> bshooter_triggers {
|
||||||
{4, "Longhold Trigger (1H)"_s},
|
{4, "Longhold Trigger (1H)"_s},
|
||||||
{5, "Downhold Trigger (1H)"_s},
|
{5, "Downhold Trigger (1H)"_s},
|
||||||
{6, "Cellblock Trigger (1H)"_s},
|
{6, "Cellblock Trigger (1H)"_s},
|
||||||
|
{99, "Base Trigger (1H)"_s},
|
||||||
|
|
||||||
{100, "BL-Machine Trigger (2H)"_s},
|
{100, "BL-Machine Trigger (2H)"_s},
|
||||||
{101, "BL-Short Trigger (2H)"_s},
|
{101, "BL-Short Trigger (2H)"_s},
|
||||||
{102, "Shielded Trigger (2H)"_s},
|
{102, "Shielded Trigger (2H)"_s},
|
||||||
{103, "Platedframe Trigger (2H)"_s},
|
{103, "Platedframe Trigger (2H)"_s},
|
||||||
{104, "Sidebox Trigger (2H) (Motion)"_s},
|
{104, "Sidebox Trigger (2H) (Motion)"_s},
|
||||||
|
{199, "2H Base Trigger (2H)"_s},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<Int, Containers::StringView> bshooter_barrels {
|
static const std::map<std::int32_t, Containers::StringView> bshooter_barrels {
|
||||||
{0, "BL-Combat Barrel (1 shot)"_s},
|
{0, "BL-Combat Barrel (1 shot)"_s},
|
||||||
{1, "Shock Absorb Barrel (1 shot) (Motion)"_s},
|
{1, "Shock Absorb Barrel (1 shot) (Motion)"_s},
|
||||||
{2, "Muzzlemod Barrel (1 shot)"_s},
|
{2, "Muzzlemod Barrel (1 shot)"_s},
|
||||||
{3, "Triangular Barrel (1 shot)"_s},
|
{3, "Triangular Barrel (1 shot)"_s},
|
||||||
{4, "Recoilblock Barrel (1 shot) (Motion)"_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},
|
{100, "Six-Barrel Gatling (Auto) (Motion)"_s},
|
||||||
{101, "Modded Six-Barrel Gatling (Auto) (Motion)"_s},
|
{101, "Modded Six-Barrel Gatling (Auto) (Motion)"_s},
|
||||||
{102, "Four-Barrel Gatling (Auto) (Motion)"_s},
|
{102, "Four-Barrel Gatling (Auto) (Motion)"_s},
|
||||||
{103, "Retro Style 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},
|
{200, "Blast Barrel (Spread)"_s},
|
||||||
{201, "Wideblast Barrel (Spread) (Motion)"_s},
|
{201, "Wideblast Barrel (Spread) (Motion)"_s},
|
||||||
{202, "Pelleter Barrel (Spread) (Motion)"_s},
|
{202, "Pelleter Barrel (Spread) (Motion)"_s},
|
||||||
{203, "Lockhold 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},
|
{300, "Propulsive Barrel (Detonate)"_s},
|
||||||
{301, "Roundbox Barrel (Detonate)"_s},
|
{301, "Roundbox Barrel (Detonate)"_s},
|
||||||
{302, "ShieldDet Barrel (Detonate)"_s},
|
{302, "ShieldDet Barrel (Detonate)"_s},
|
||||||
{303, "RecoilDet Barrel (Detonate) (Motion)"_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},
|
||||||
|
|
||||||
|
{400, "Heavy Burst Barrel (Pile Bunker) (Motion)"_s},
|
||||||
|
{401, "Under Guard Barrel (Pile Bunker) (Motion)"_s},
|
||||||
|
{402, "Facthold Barrel (Pile Bunker) (Motion)"_s},
|
||||||
|
{499, "Long P Base Barrel (Pile Bunker) (Motion)"_s},
|
||||||
};
|
};
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
//region Energy Shooters
|
//region Energy Shooters
|
||||||
static const std::map<Int, Containers::StringView> eshooter_triggers {
|
static const std::map<std::int32_t, Containers::StringView> eshooter_triggers {
|
||||||
{0, "EN-Rifle Trigger (1H)"_s},
|
{0, "EN-Rifle Trigger (1H)"_s},
|
||||||
{1, "Underarm Trigger (1H)"_s},
|
{1, "Underarm Trigger (1H)"_s},
|
||||||
{2, "EN-Inverted Trigger (1H)"_s},
|
{2, "EN-Inverted Trigger (1H)"_s},
|
||||||
|
@ -261,65 +317,88 @@ static const std::map<Int, Containers::StringView> eshooter_triggers {
|
||||||
{4, "EN-Needler Trigger (1H)"_s},
|
{4, "EN-Needler Trigger (1H)"_s},
|
||||||
{5, "Angular Trigger (1H)"_s},
|
{5, "Angular Trigger (1H)"_s},
|
||||||
{6, "Exposed Trigger (1H)"_s},
|
{6, "Exposed Trigger (1H)"_s},
|
||||||
|
{99, "Base EnTrigger (1H)"_s},
|
||||||
|
|
||||||
{100, "EN-Combat Trigger (2H)"_s},
|
{100, "EN-Combat Trigger (2H)"_s},
|
||||||
{101, "EN-Alternate Trigger (2H)"_s},
|
{101, "EN-Alternate Trigger (2H)"_s},
|
||||||
{102, "Framed Trigger (2H) (Motion)"_s},
|
{102, "Framed Trigger (2H) (Motion)"_s},
|
||||||
{103, "Stabilised Trigger (2H)"_s},
|
{103, "Stabilised Trigger (2H)"_s},
|
||||||
{104, "EN-Heavy Trigger (2H)"_s},
|
{104, "EN-Heavy Trigger (2H)"_s},
|
||||||
|
{199, "2H Base EnTrigger (2H)"_s},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<Int, Containers::StringView> eshooter_busters {
|
static const std::map<std::int32_t, Containers::StringView> eshooter_busters {
|
||||||
{0, "EN-Combat Buster (1 shot)"_s},
|
{0, "EN-Combat Buster (1 shot)"_s},
|
||||||
{1, "Delta Cycler (1 shot) (Motion)"_s},
|
{1, "Delta Cycler (1 shot) (Motion)"_s},
|
||||||
{2, "EN-Longbarrel Buster (1 shot)"_s},
|
{2, "EN-Longbarrel Buster (1 shot)"_s},
|
||||||
{3, "Kinetic Buster (1 shot) (Motion)"_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},
|
{100, "EN-Rifle Buster (Auto)"_s},
|
||||||
{101, "EN-Focus Buster (Auto)"_s},
|
{101, "EN-Focus Buster (Auto)"_s},
|
||||||
{102, "Machinist Buster (Auto)"_s},
|
{102, "Machinist Buster (Auto)"_s},
|
||||||
{103, "EN-Precision Buster (Auto) (Motion)"_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},
|
{200, "Railcharge Buster (Ray) (Motion)"_s},
|
||||||
{201, "Clawcharge Buster (Ray)"_s},
|
{201, "Clawcharge Buster (Ray)"_s},
|
||||||
{202, "Twizelcharge Buster (Ray)"_s},
|
{202, "Twizelcharge Buster (Ray)"_s},
|
||||||
{203, "Deltacharge 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},
|
{300, "Subsonic Buster (Wave)"_s},
|
||||||
{301, "Amplifier Buster (Wave) (Motion)"_s},
|
{301, "Amplifier Buster (Wave) (Motion)"_s},
|
||||||
{302, "Cyclonwave Buster (Wave)"_s},
|
{302, "Cyclonwave Buster (Wave)"_s},
|
||||||
{303, "Warhorn Buster (Wave) (Motion)"_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},
|
||||||
|
|
||||||
|
{400, "Wiredcharge Buster (Prism) (Motion)"_s},
|
||||||
|
{402, "Heavyclamp Buster (Prism) (Motion)"_s},
|
||||||
|
{402, "Curlescent Buster (Prism) (Motion)"_s},
|
||||||
|
{499, "Long P Base Buster (Prism) (Motion)"_s},
|
||||||
};
|
};
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Bullet Launchers
|
// region Bullet Launchers
|
||||||
static const std::map<Int, Containers::StringView> blauncher_pods {
|
static const std::map<std::int32_t, Containers::StringView> blauncher_pods {
|
||||||
{0, "BL-Delta Pack Launcher (Missile x12)"_s},
|
{0, "BL-Delta Pack Launcher (Missile x12)"_s},
|
||||||
{1, "BL-Twin Pack Launcher (Missile x12)"_s},
|
{1, "BL-Twin Pack Launcher (Missile x12)"_s},
|
||||||
{2, "Detector Launcher (Missile x12)"_s},
|
{2, "Detector Launcher (Missile x12)"_s},
|
||||||
{3, "BL-Triplet Pack Launcher (Missile x12)"_s},
|
{3, "BL-Triplet Pack Launcher (Missile x12)"_s},
|
||||||
{4, "Shielded Launcher (Missile x12)"_s},
|
{4, "Shielded Launcher (Missile x12)"_s},
|
||||||
|
{99, "H Base Pod (Missile x12)"_s},
|
||||||
|
|
||||||
{100, "Warhead Pod (Nuke x2)"_s},
|
{100, "Warhead Pod (Nuke x2)"_s},
|
||||||
{101, "Warhead Launcher (Nuke x2)"_s},
|
{101, "Warhead Launcher (Nuke x2)"_s},
|
||||||
{102, "Triangular Warhead Pod (Nuke x2)"_s},
|
{102, "Triangular Warhead Pod (Nuke x2)"_s},
|
||||||
{103, "Expanded Warhead Pod (Nuke x2)"_s},
|
{103, "Expanded Warhead Pod (Nuke x2)"_s},
|
||||||
{104, "Shielded 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},
|
{200, "Widepack Launcher (Salvo x24)"_s},
|
||||||
{201, "Covered Launcher (Salvo x24)"_s},
|
{201, "Covered Launcher (Salvo x24)"_s},
|
||||||
{202, "Double Delta Launcher (Salvo x24)"_s},
|
{202, "Double Delta Launcher (Salvo x24)"_s},
|
||||||
{203, "Hexagonal Launcher (Salvo x24)"_s},
|
{203, "Hexagonal Launcher (Salvo x24)"_s},
|
||||||
{204, "Shielded Six 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},
|
{300, "Sentinel Cluster Pod (Cluster x40)"_s},
|
||||||
{301, "Pincer Cluster Pod (Cluster x40)"_s},
|
{301, "Pincer Cluster Pod (Cluster x40)"_s},
|
||||||
{302, "Elliptical Cluster Pod (Cluster x40)"_s},
|
{302, "Elliptical Cluster Pod (Cluster x40)"_s},
|
||||||
{303, "Sawed Cluster Pod (Cluster x40)"_s},
|
{303, "Sawed Cluster Pod (Cluster x40)"_s},
|
||||||
{304, "Pentagonal 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 {
|
static const std::map<std::int32_t, Containers::StringView> blauncher_projectiles {
|
||||||
{0, "Flathead Missile"_s},
|
{0, "Flathead Missile"_s},
|
||||||
{1, "Warhead Missile"_s},
|
{1, "Warhead Missile"_s},
|
||||||
{2, "Pointhead Missile"_s},
|
{2, "Pointhead Missile"_s},
|
||||||
|
@ -329,7 +408,7 @@ static const std::map<Int, Containers::StringView> blauncher_projectiles {
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Energy Launchers
|
// region Energy Launchers
|
||||||
static const std::map<Int, Containers::StringView> elauncher_generators {
|
static const std::map<std::int32_t, Containers::StringView> elauncher_generators {
|
||||||
{0, "Fly Unit"_s},
|
{0, "Fly Unit"_s},
|
||||||
{1, "Assault Unit (Motion)"_s},
|
{1, "Assault Unit (Motion)"_s},
|
||||||
{2, "Falcon Unit"_s},
|
{2, "Falcon Unit"_s},
|
||||||
|
@ -358,9 +437,10 @@ static const std::map<Int, Containers::StringView> elauncher_generators {
|
||||||
{25, "Carrier Unit"_s},
|
{25, "Carrier Unit"_s},
|
||||||
{26, "Compartment Unit"_s},
|
{26, "Compartment Unit"_s},
|
||||||
{27, "Flatedge Unit"_s},
|
{27, "Flatedge Unit"_s},
|
||||||
|
{99, "Base Generator"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<Int, Containers::StringView> elauncher_pods {
|
static const std::map<std::int32_t, Containers::StringView> elauncher_pods {
|
||||||
{0, "EN-Dual Claw Launcher (Echo) (Motion)"_s},
|
{0, "EN-Dual Claw Launcher (Echo) (Motion)"_s},
|
||||||
{1, "EN-Assault Launcher (Echo)"_s},
|
{1, "EN-Assault Launcher (Echo)"_s},
|
||||||
{2, "EN-Tactical Launcher (Echo)"_s},
|
{2, "EN-Tactical Launcher (Echo)"_s},
|
||||||
|
@ -368,6 +448,7 @@ static const std::map<Int, Containers::StringView> elauncher_pods {
|
||||||
{4, "EN-Needler Launcher (Echo)"_s},
|
{4, "EN-Needler Launcher (Echo)"_s},
|
||||||
{5, "Spark Launcher (Echo)"_s},
|
{5, "Spark Launcher (Echo)"_s},
|
||||||
{6, "Pinpoint Launcher (Echo)"_s},
|
{6, "Pinpoint Launcher (Echo)"_s},
|
||||||
|
{99, "E Base EPod (Echo)"_s},
|
||||||
|
|
||||||
{100, "Raystream Launcher (Beam)"_s},
|
{100, "Raystream Launcher (Beam)"_s},
|
||||||
{101, "Perpetum Launcher (Beam)"_s},
|
{101, "Perpetum Launcher (Beam)"_s},
|
||||||
|
@ -376,6 +457,7 @@ static const std::map<Int, Containers::StringView> elauncher_pods {
|
||||||
{104, "Crosshair Launcher (Beam)"_s},
|
{104, "Crosshair Launcher (Beam)"_s},
|
||||||
{105, "Powerlined Launcher (Beam)"_s},
|
{105, "Powerlined Launcher (Beam)"_s},
|
||||||
{106, "Attached Launcher (Beam)"_s},
|
{106, "Attached Launcher (Beam)"_s},
|
||||||
|
{199, "B Base EPod (Beam)"_s},
|
||||||
|
|
||||||
{200, "Hilt Launcher (Slash) (Motion)"_s},
|
{200, "Hilt Launcher (Slash) (Motion)"_s},
|
||||||
{201, "Underangle Launcher (Slash)"_s},
|
{201, "Underangle Launcher (Slash)"_s},
|
||||||
|
@ -384,6 +466,7 @@ static const std::map<Int, Containers::StringView> elauncher_pods {
|
||||||
{204, "Spike Launcher (Slash)"_s},
|
{204, "Spike Launcher (Slash)"_s},
|
||||||
{205, "Tri-Pronged Launcher (Slash) (Motion)"_s},
|
{205, "Tri-Pronged Launcher (Slash) (Motion)"_s},
|
||||||
{206, "Heavyblade Launcher (Slash)"_s},
|
{206, "Heavyblade Launcher (Slash)"_s},
|
||||||
|
{299, "S Base EPod (Slash)"_s},
|
||||||
|
|
||||||
{300, "Covering Launcher (Photon)"_s},
|
{300, "Covering Launcher (Photon)"_s},
|
||||||
{301, "Boxhead Launcher (Photon)"_s},
|
{301, "Boxhead Launcher (Photon)"_s},
|
||||||
|
@ -392,5 +475,8 @@ static const std::map<Int, Containers::StringView> elauncher_pods {
|
||||||
{304, "Shelled Launcher (Photon)"_s},
|
{304, "Shelled Launcher (Photon)"_s},
|
||||||
{305, "Widearm Launcher (Photon)"_s},
|
{305, "Widearm Launcher (Photon)"_s},
|
||||||
{306, "Wingspan Launcher (Photon)"_s},
|
{306, "Wingspan Launcher (Photon)"_s},
|
||||||
|
{399, "P Base EPod (Photon)"_s},
|
||||||
};
|
};
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,6 +16,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 <variant>
|
||||||
|
|
||||||
#include <Corrade/Containers/StaticArray.h>
|
#include <Corrade/Containers/StaticArray.h>
|
||||||
|
|
||||||
#include <Magnum/Magnum.h>
|
#include <Magnum/Magnum.h>
|
||||||
|
@ -24,13 +26,19 @@
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
|
||||||
|
typedef std::variant<Vector3, Vector3d> Vector3Variant;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
struct Accessory {
|
struct Accessory {
|
||||||
Int attachIndex = -1;
|
std::int32_t attachIndex = -1;
|
||||||
Int id = -1;
|
std::int32_t id = -1;
|
||||||
Containers::StaticArray<2, Int> styles{ValueInit};
|
Containers::StaticArray<2, std::int32_t> styles{ValueInit};
|
||||||
Vector3 relativePosition{0.0f};
|
Vector3Variant relativePosition{Vector3{}};
|
||||||
Vector3 relativePositionOffset{0.0f};
|
Vector3Variant relativePositionOffset{Vector3{}};
|
||||||
Vector3 relativeRotation{0.0f};
|
Vector3Variant relativeRotation{Vector3{}};
|
||||||
Vector3 relativeRotationOffset{0.0f};
|
Vector3Variant relativeRotationOffset{Vector3{}};
|
||||||
Vector3 localScale{1.0f};
|
Vector3Variant localScale{Vector3{1.0f}};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,24 +19,24 @@
|
||||||
#include <Corrade/Containers/Array.h>
|
#include <Corrade/Containers/Array.h>
|
||||||
#include <Corrade/Containers/StaticArray.h>
|
#include <Corrade/Containers/StaticArray.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
|
||||||
|
|
||||||
#include "Decal.h"
|
#include "Decal.h"
|
||||||
#include "Accessory.h"
|
#include "Accessory.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
enum class ArmourSlot {
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
|
struct ArmourPart {
|
||||||
|
enum class Slot {
|
||||||
#define c(enumerator, enumstr, name) enumerator,
|
#define c(enumerator, enumstr, name) enumerator,
|
||||||
#include "../Maps/ArmourSlots.hpp"
|
#include "../Maps/ArmourSlots.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
};
|
};
|
||||||
|
Slot slot = Slot::Face;
|
||||||
struct ArmourPart {
|
std::int32_t id = 0;
|
||||||
ArmourSlot slot = ArmourSlot::Face;
|
Containers::StaticArray<4, std::int32_t> styles{ValueInit};
|
||||||
Int id = 0;
|
|
||||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
|
||||||
Containers::Array<Decal> decals;
|
Containers::Array<Decal> decals;
|
||||||
Containers::Array<Accessory> accessories;
|
Containers::Array<Accessory> accessories;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -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/String.h>
|
#include <variant>
|
||||||
|
|
||||||
#include <Magnum/Magnum.h>
|
#include <Magnum/Magnum.h>
|
||||||
#include <Magnum/Math/Vector3.h>
|
#include <Magnum/Math/Vector3.h>
|
||||||
|
@ -24,23 +24,28 @@
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
|
||||||
|
typedef std::variant<Vector3, Vector3d> Vector3Variant;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
enum class BulletLauncherAttachmentStyle {
|
enum class BulletLauncherAttachmentStyle {
|
||||||
#define c(enumerator, enumstr) enumerator,
|
#define c(enumerator, enumstr) enumerator,
|
||||||
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
|
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class BulletLauncherSocket {
|
struct BulletLauncherAttachment {
|
||||||
|
enum class Socket {
|
||||||
#define c(enumerator, enumstr, name) enumerator,
|
#define c(enumerator, enumstr, name) enumerator,
|
||||||
#include "../Maps/BulletLauncherSockets.hpp"
|
#include "../Maps/BulletLauncherSockets.hpp"
|
||||||
#undef c
|
#undef c
|
||||||
|
};
|
||||||
|
Socket socket = Socket::Auto;
|
||||||
|
Vector3Variant relativeLocation;
|
||||||
|
Vector3Variant offsetLocation;
|
||||||
|
Vector3Variant relativeRotation;
|
||||||
|
Vector3Variant offsetRotation;
|
||||||
|
Vector3Variant relativeScale;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BulletLauncherAttachment {
|
}
|
||||||
BulletLauncherSocket socket = BulletLauncherSocket::Auto;
|
|
||||||
Vector3 relativeLocation;
|
|
||||||
Vector3 offsetLocation;
|
|
||||||
Vector3 relativeRotation;
|
|
||||||
Vector3 offsetRotation;
|
|
||||||
Vector3 relativeScale;
|
|
||||||
};
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,16 +25,29 @@
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
struct CustomStyle {
|
struct CustomStyle {
|
||||||
Containers::String name;
|
Containers::String name;
|
||||||
Color4 colour{0.0f};
|
Color4 colour{0.0f};
|
||||||
Float metallic = 0.5f;
|
float metallic = 0.5f;
|
||||||
Float gloss = 0.5f;
|
float gloss = 0.5f;
|
||||||
bool glow = false;
|
bool glow = false;
|
||||||
|
|
||||||
Int patternId = 0;
|
std::int32_t patternId = 0;
|
||||||
Float opacity = 0.5f;
|
float opacity = 0.5f;
|
||||||
Vector2 offset{0.5f};
|
Vector2 offset{0.5f};
|
||||||
Float rotation = 0.0f;
|
float rotation = 0.0f;
|
||||||
Float scale = 0.5f;
|
float scale = 0.5f;
|
||||||
|
|
||||||
|
// This is only used to know which style array the current style is located in when exporting a standalone style.
|
||||||
|
enum class Type: std::uint8_t {
|
||||||
|
Unknown,
|
||||||
|
Frame,
|
||||||
|
Armour,
|
||||||
|
Weapon,
|
||||||
|
Global
|
||||||
|
} type = Type::Unknown;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,21 +16,31 @@
|
||||||
// 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 <variant>
|
||||||
|
|
||||||
#include <Magnum/Magnum.h>
|
#include <Magnum/Magnum.h>
|
||||||
#include <Magnum/Math/Color.h>
|
#include <Magnum/Math/Color.h>
|
||||||
#include <Magnum/Math/Vector2.h>
|
#include <Magnum/Math/Vector2.h>
|
||||||
|
#include <Magnum/Math/Vector3.h>
|
||||||
|
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
|
||||||
|
typedef std::variant<Vector2, Vector2d> Vector2Variant;
|
||||||
|
typedef std::variant<Vector3, Vector3d> Vector3Variant;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
struct Decal {
|
struct Decal {
|
||||||
Int id = -1;
|
std::int32_t id = -1;
|
||||||
Color4 colour{0.0f};
|
Color4 colour{0.0f};
|
||||||
Vector3 position{0.0f};
|
Vector3Variant position{Vector3{}};
|
||||||
Vector3 uAxis{0.0f};
|
Vector3Variant uAxis{Vector3{}};
|
||||||
Vector3 vAxis{0.0f};
|
Vector3Variant vAxis{Vector3{}};
|
||||||
Vector2 offset{0.5f};
|
Vector2Variant offset{Vector2{0.5f}};
|
||||||
Float scale = 0.5f;
|
float scale = 0.5f;
|
||||||
Float rotation = 0.0f;
|
float rotation = 0.0f;
|
||||||
bool flip = false;
|
bool flip = false;
|
||||||
bool wrap = false;
|
bool wrap = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,17 +16,17 @@
|
||||||
// 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 <Magnum/Types.h>
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
struct Joints {
|
struct Joints {
|
||||||
Float neck = 0.0f;
|
float neck = 0.0f;
|
||||||
Float body = 0.0f;
|
float body = 0.0f;
|
||||||
Float shoulders = 0.0f;
|
float shoulders = 0.0f;
|
||||||
Float hips = 0.0f;
|
float hips = 0.0f;
|
||||||
Float upperArms = 0.0f;
|
float upperArms = 0.0f;
|
||||||
Float lowerArms = 0.0f;
|
float lowerArms = 0.0f;
|
||||||
Float upperLegs = 0.0f;
|
float upperLegs = 0.0f;
|
||||||
Float lowerLegs = 0.0f;
|
float lowerLegs = 0.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,22 +21,21 @@
|
||||||
#include <Corrade/Containers/ScopeGuard.h>
|
#include <Corrade/Containers/ScopeGuard.h>
|
||||||
#include <Corrade/Utility/Path.h>
|
#include <Corrade/Utility/Path.h>
|
||||||
|
|
||||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
#include "PropertyNames.h"
|
||||||
#include "../UESaveFile/Types/BoolProperty.h"
|
#include "../Logger/Logger.h"
|
||||||
#include "../UESaveFile/Types/ByteProperty.h"
|
#include "../Gvas/Types/ArrayProperty.h"
|
||||||
#include "../UESaveFile/Types/ColourStructProperty.h"
|
#include "../Gvas/Types/BoolProperty.h"
|
||||||
#include "../UESaveFile/Types/FloatProperty.h"
|
#include "../Gvas/Types/ColourStructProperty.h"
|
||||||
#include "../UESaveFile/Types/GenericStructProperty.h"
|
#include "../Gvas/Types/GenericStructProperty.h"
|
||||||
#include "../UESaveFile/Types/IntProperty.h"
|
#include "../Gvas/Types/IntProperty.h"
|
||||||
#include "../UESaveFile/Types/RotatorStructProperty.h"
|
#include "../Gvas/Types/StringProperty.h"
|
||||||
#include "../UESaveFile/Types/StringProperty.h"
|
|
||||||
#include "../UESaveFile/Types/VectorStructProperty.h"
|
|
||||||
#include "../UESaveFile/Types/Vector2DStructProperty.h"
|
|
||||||
|
|
||||||
#include "Mass.h"
|
#include "Mass.h"
|
||||||
|
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
Mass::Mass(Containers::StringView path) {
|
Mass::Mass(Containers::StringView path) {
|
||||||
auto split = Utility::Path::split(path);
|
auto split = Utility::Path::split(path);
|
||||||
_folder = split.first();
|
_folder = split.first();
|
||||||
|
@ -45,82 +44,101 @@ Mass::Mass(Containers::StringView path) {
|
||||||
refreshValues();
|
refreshValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::lastError() -> Containers::StringView {
|
Containers::StringView
|
||||||
|
Mass::lastError() {
|
||||||
return _lastError;
|
return _lastError;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::getNameFromFile(Containers::StringView path) -> Containers::Optional<Containers::String> {
|
Containers::Optional<Containers::String>
|
||||||
|
Mass::getNameFromFile(Containers::StringView path) {
|
||||||
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};
|
Gvas::File 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<Gvas::Types::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<Gvas::Types::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {name_prop->value};
|
return {name_prop->value};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::refreshValues() {
|
void
|
||||||
Utility::Debug{} << "=Refreshing values for" << _filename << Utility::Debug::nospace << "=";
|
Mass::refreshValues() {
|
||||||
|
LOG_INFO_FORMAT("Refreshing values for {}.", _filename);
|
||||||
|
|
||||||
Containers::ScopeGuard guard{[]{ Utility::Error{} << "Refresh failed."; }};
|
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))) {
|
||||||
Utility::Warning{} << _filename << "does not exist in" << _folder;
|
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()) {
|
||||||
Utility::Error{} << _mass->lastError();
|
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()) {
|
||||||
Utility::Error{} << _mass->lastError();
|
LOG_ERROR(_mass->lastError());
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_INFO("Checking the save file type.");
|
||||||
if(_mass->saveType() != "/Game/Core/Save/bpSaveGameUnit.bpSaveGameUnit_C"_s) {
|
if(_mass->saveType() != "/Game/Core/Save/bpSaveGameUnit.bpSaveGameUnit_C"_s) {
|
||||||
Utility::Error{} << _filename << "is not a valid unit save.";
|
LOG_ERROR_FORMAT("{} is not a valid unit save.", _filename);
|
||||||
}
|
|
||||||
|
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
|
||||||
if(!unit_data) {
|
|
||||||
Utility::Error{} << "Couldn't find unit data in" << _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<Gvas::Types::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<Gvas::Types::StringProperty>(MASS_NAME);
|
||||||
|
|
||||||
if(!name_prop) {
|
if(!name_prop) {
|
||||||
Utility::Error{} << "Couldn't find a M.A.S.S. name in" << _filename;
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_NAME, _filename);
|
||||||
_name = Containers::NullOpt;
|
_name = Containers::NullOpt;
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
|
@ -203,42 +221,46 @@ void Mass::refreshValues() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto account_prop = _mass->at<StringProperty>("Account"_s);
|
LOG_INFO("Getting the associated account.");
|
||||||
|
auto account_prop = _mass->at<Gvas::Types::StringProperty>("Account"_s);
|
||||||
if(!account_prop) {
|
if(!account_prop) {
|
||||||
Utility::Error{} << "Couldn't find an account ID in" << _filename;
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_ACCOUNT, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_account = account_prop->value;
|
_account = account_prop->value;
|
||||||
|
|
||||||
guard.release();
|
|
||||||
guard = Containers::ScopeGuard{[]{Utility::Debug{} << "Refresh successful.";}};
|
|
||||||
|
|
||||||
_state = State::Valid;
|
_state = State::Valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::filename() -> Containers::StringView {
|
Containers::StringView
|
||||||
|
Mass::filename() {
|
||||||
return _filename;
|
return _filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::name() -> Containers::StringView {
|
Containers::StringView
|
||||||
|
Mass::name() {
|
||||||
|
CORRADE_INTERNAL_ASSERT(_name);
|
||||||
return *_name;
|
return *_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::setName(Containers::StringView new_name) -> bool {
|
bool
|
||||||
|
Mass::setName(Containers::StringView new_name) {
|
||||||
_name = {new_name};
|
_name = {new_name};
|
||||||
|
|
||||||
auto unit_data = _mass->at<GenericStructProperty>("UnitData"_s);
|
auto unit_data = _mass->at<Gvas::Types::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto name_prop = unit_data->at<StringProperty>("Name_45_A037C5D54E53456407BDF091344529BB"_s);
|
auto name_prop = unit_data->at<Gvas::Types::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;
|
||||||
}
|
}
|
||||||
|
@ -253,70 +275,84 @@ auto Mass::setName(Containers::StringView new_name) -> bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::state() -> State {
|
Mass::State
|
||||||
|
Mass::state() {
|
||||||
return _state;
|
return _state;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::dirty() const -> bool {
|
bool Mass::dirty() const {
|
||||||
return _dirty;
|
return _dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::setDirty(bool dirty) {
|
void
|
||||||
|
Mass::setDirty(bool dirty) {
|
||||||
_dirty = dirty;
|
_dirty = dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getTuning() {
|
void
|
||||||
getTuningCategory("Engine"_s, _tuning.engineId, "Gears"_s, _tuning.gearIds);
|
Mass::getTuning() {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::engine() -> Int& {
|
std::int32_t&
|
||||||
|
Mass::engine() {
|
||||||
return _tuning.engineId;
|
return _tuning.engineId;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::gears() -> Containers::ArrayView<Int> {
|
Containers::ArrayView<std::int32_t>
|
||||||
|
Mass::gears() {
|
||||||
return _tuning.gearIds;
|
return _tuning.gearIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::os() -> Int& {
|
std::int32_t&
|
||||||
|
Mass::os() {
|
||||||
return _tuning.osId;
|
return _tuning.osId;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::modules() -> Containers::ArrayView<Int> {
|
Containers::ArrayView<std::int32_t>
|
||||||
|
Mass::modules() {
|
||||||
return _tuning.moduleIds;
|
return _tuning.moduleIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::architecture() -> Int& {
|
std::int32_t&
|
||||||
|
Mass::architecture() {
|
||||||
return _tuning.archId;
|
return _tuning.archId;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::techs() -> Containers::ArrayView<Int> {
|
Containers::ArrayView<std::int32_t>
|
||||||
|
Mass::techs() {
|
||||||
return _tuning.techIds;
|
return _tuning.techIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::account() -> Containers::StringView {
|
Containers::StringView
|
||||||
|
Mass::account() {
|
||||||
return _account;
|
return _account;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mass::updateAccount(Containers::StringView new_account) -> bool {
|
bool
|
||||||
|
Mass::updateAccount(Containers::StringView new_account) {
|
||||||
_account = new_account;
|
_account = new_account;
|
||||||
|
|
||||||
auto account = _mass->at<StringProperty>("Account"_s);
|
auto account = _mass->at<Gvas::Types::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,33 +366,40 @@ auto Mass::updateAccount(Containers::StringView new_account) -> bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mass::getTuningCategory(Containers::StringView big_node_prop_name, Int& big_node_id,
|
void
|
||||||
Containers::StringView small_nodes_prop_name, Containers::ArrayView<Int> small_nodes_ids)
|
Mass::getTuningCategory(Containers::StringView big_node_prop_name, std::int32_t& big_node_id,
|
||||||
|
Containers::StringView small_nodes_prop_name,
|
||||||
|
Containers::ArrayView<std::int32_t> small_nodes_ids)
|
||||||
{
|
{
|
||||||
auto node_id = _mass->at<IntProperty>(big_node_prop_name);
|
LOG_INFO_FORMAT("Getting tuning data ({}, {}).", big_node_prop_name, small_nodes_prop_name);
|
||||||
|
|
||||||
|
auto node_id = _mass->at<Gvas::Types::IntProperty>(big_node_prop_name);
|
||||||
if(!node_id) {
|
if(!node_id) {
|
||||||
Utility::Error{} << "Couldn't find" << big_node_prop_name << "in" << _filename;
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", big_node_prop_name, _filename);
|
||||||
_state = State::Invalid;
|
_state = State::Invalid;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
big_node_id = node_id->value;
|
big_node_id = node_id->value;
|
||||||
|
|
||||||
auto node_ids = _mass->at<ArrayProperty>(small_nodes_prop_name);
|
auto node_ids = _mass->at<Gvas::Types::ArrayProperty>(small_nodes_prop_name);
|
||||||
if(!node_ids) {
|
if(!node_ids) {
|
||||||
Utility::Error{} << "Couldn't find" << small_nodes_prop_name << "in" << _filename;
|
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()) {
|
||||||
Utility::Error{} << "Node ID arrays are not of the same size. Expected" << small_nodes_ids.size() << Utility::Debug::nospace << ", got" << node_ids->items.size() << "instead.";
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < small_nodes_ids.size(); i++) {
|
for(std::uint32_t i = 0; i < small_nodes_ids.size(); i++) {
|
||||||
auto small_node_id = node_ids->at<IntProperty>(i);
|
auto small_node_id = node_ids->at<Gvas::Types::IntProperty>(i);
|
||||||
CORRADE_INTERNAL_ASSERT(small_node_id);
|
CORRADE_INTERNAL_ASSERT(small_node_id);
|
||||||
small_nodes_ids[i] = small_node_id->value;
|
small_nodes_ids[i] = small_node_id->value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -36,19 +36,16 @@
|
||||||
#include "WeaponPart.h"
|
#include "WeaponPart.h"
|
||||||
#include "Weapon.h"
|
#include "Weapon.h"
|
||||||
|
|
||||||
#include "../UESaveFile/UESaveFile.h"
|
#include "../Gvas/File.h"
|
||||||
|
#include "../Gvas/Types/Types.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
|
||||||
struct ArrayProperty;
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
class Mass {
|
class Mass {
|
||||||
public:
|
public:
|
||||||
enum class State : UnsignedByte {
|
|
||||||
Empty, Invalid, Valid
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit Mass(Containers::StringView path);
|
explicit Mass(Containers::StringView path);
|
||||||
|
|
||||||
Mass(const Mass&) = delete;
|
Mass(const Mass&) = delete;
|
||||||
|
@ -66,101 +63,106 @@ class Mass {
|
||||||
auto filename() -> Containers::StringView;
|
auto filename() -> Containers::StringView;
|
||||||
|
|
||||||
auto name() -> Containers::StringView;
|
auto name() -> Containers::StringView;
|
||||||
auto setName(Containers::StringView new_name) -> bool;
|
bool setName(Containers::StringView new_name);
|
||||||
|
|
||||||
|
enum class State: std::uint8_t {
|
||||||
|
Empty, Invalid, Valid
|
||||||
|
};
|
||||||
|
|
||||||
auto state() -> State;
|
auto state() -> State;
|
||||||
|
|
||||||
auto dirty() const -> bool;
|
bool dirty() const;
|
||||||
void setDirty(bool dirty = true);
|
void setDirty(bool dirty = true);
|
||||||
|
|
||||||
auto jointSliders() -> Joints&;
|
auto jointSliders() -> Joints&;
|
||||||
void getJointSliders();
|
void getJointSliders();
|
||||||
auto writeJointSliders() -> bool;
|
bool writeJointSliders();
|
||||||
|
|
||||||
auto frameStyles() -> Containers::ArrayView<Int>;
|
auto frameStyles() -> Containers::ArrayView<std::int32_t>;
|
||||||
void getFrameStyles();
|
void getFrameStyles();
|
||||||
auto writeFrameStyles() -> bool;
|
bool writeFrameStyles();
|
||||||
|
|
||||||
auto eyeFlareColour() -> Color4&;
|
auto eyeFlareColour() -> Color4&;
|
||||||
void getEyeFlareColour();
|
void getEyeFlareColour();
|
||||||
auto writeEyeFlareColour() -> bool;
|
bool writeEyeFlareColour();
|
||||||
|
|
||||||
auto frameCustomStyles() -> Containers::ArrayView<CustomStyle>;
|
auto frameCustomStyles() -> Containers::ArrayView<CustomStyle>;
|
||||||
void getFrameCustomStyles();
|
void getFrameCustomStyles();
|
||||||
auto writeFrameCustomStyle(UnsignedLong index) -> bool;
|
bool writeFrameCustomStyle(std::size_t index);
|
||||||
|
|
||||||
auto armourParts() -> Containers::ArrayView<ArmourPart>;
|
auto armourParts() -> Containers::ArrayView<ArmourPart>;
|
||||||
void getArmourParts();
|
void getArmourParts();
|
||||||
auto writeArmourPart(ArmourSlot slot) -> bool;
|
bool writeArmourPart(ArmourPart::Slot slot);
|
||||||
|
|
||||||
auto bulletLauncherAttachmentStyle() -> BulletLauncherAttachmentStyle&;
|
auto bulletLauncherAttachmentStyle() -> BulletLauncherAttachmentStyle&;
|
||||||
auto bulletLauncherAttachments() -> Containers::ArrayView<BulletLauncherAttachment>;
|
auto bulletLauncherAttachments() -> Containers::ArrayView<BulletLauncherAttachment>;
|
||||||
void getBulletLauncherAttachments();
|
void getBulletLauncherAttachments();
|
||||||
auto writeBulletLauncherAttachments() -> bool;
|
bool writeBulletLauncherAttachments();
|
||||||
|
|
||||||
auto armourCustomStyles() -> Containers::ArrayView<CustomStyle>;
|
auto armourCustomStyles() -> Containers::ArrayView<CustomStyle>;
|
||||||
void getArmourCustomStyles();
|
void getArmourCustomStyles();
|
||||||
auto writeArmourCustomStyle(UnsignedLong index) -> bool;
|
bool writeArmourCustomStyle(std::size_t index);
|
||||||
|
|
||||||
auto meleeWeapons() -> Containers::ArrayView<Weapon>;
|
auto meleeWeapons() -> Containers::ArrayView<Weapon>;
|
||||||
void getMeleeWeapons();
|
void getMeleeWeapons();
|
||||||
auto writeMeleeWeapons() -> bool;
|
bool writeMeleeWeapons();
|
||||||
|
|
||||||
auto shields() -> Containers::ArrayView<Weapon>;
|
auto shields() -> Containers::ArrayView<Weapon>;
|
||||||
void getShields();
|
void getShields();
|
||||||
auto writeShields() -> bool;
|
bool writeShields();
|
||||||
|
|
||||||
auto bulletShooters() -> Containers::ArrayView<Weapon>;
|
auto bulletShooters() -> Containers::ArrayView<Weapon>;
|
||||||
void getBulletShooters();
|
void getBulletShooters();
|
||||||
auto writeBulletShooters() -> bool;
|
bool writeBulletShooters();
|
||||||
|
|
||||||
auto energyShooters() -> Containers::ArrayView<Weapon>;
|
auto energyShooters() -> Containers::ArrayView<Weapon>;
|
||||||
void getEnergyShooters();
|
void getEnergyShooters();
|
||||||
auto writeEnergyShooters() -> bool;
|
bool writeEnergyShooters();
|
||||||
|
|
||||||
auto bulletLaunchers() -> Containers::ArrayView<Weapon>;
|
auto bulletLaunchers() -> Containers::ArrayView<Weapon>;
|
||||||
void getBulletLaunchers();
|
void getBulletLaunchers();
|
||||||
auto writeBulletLaunchers() -> bool;
|
bool writeBulletLaunchers();
|
||||||
|
|
||||||
auto energyLaunchers() -> Containers::ArrayView<Weapon>;
|
auto energyLaunchers() -> Containers::ArrayView<Weapon>;
|
||||||
void getEnergyLaunchers();
|
void getEnergyLaunchers();
|
||||||
auto writeEnergyLaunchers() -> bool;
|
bool writeEnergyLaunchers();
|
||||||
|
|
||||||
auto globalStyles() -> Containers::ArrayView<CustomStyle>;
|
auto globalStyles() -> Containers::ArrayView<CustomStyle>;
|
||||||
void getGlobalStyles();
|
void getGlobalStyles();
|
||||||
auto writeGlobalStyle(UnsignedLong index) -> bool;
|
bool writeGlobalStyle(std::size_t index);
|
||||||
|
|
||||||
void getTuning();
|
void getTuning();
|
||||||
|
|
||||||
auto engine() -> Int&;
|
auto engine() -> std::int32_t&;
|
||||||
auto gears() -> Containers::ArrayView<Int>;
|
auto gears() -> Containers::ArrayView<std::int32_t>;
|
||||||
|
|
||||||
auto os() -> Int&;
|
auto os() -> std::int32_t&;
|
||||||
auto modules() -> Containers::ArrayView<Int>;
|
auto modules() -> Containers::ArrayView<std::int32_t>;
|
||||||
|
|
||||||
auto architecture() -> Int&;
|
auto architecture() -> std::int32_t&;
|
||||||
auto techs() -> Containers::ArrayView<Int>;
|
auto techs() -> Containers::ArrayView<std::int32_t>;
|
||||||
|
|
||||||
auto account() -> Containers::StringView;
|
auto account() -> Containers::StringView;
|
||||||
auto updateAccount(Containers::StringView new_account) -> bool;
|
bool updateAccount(Containers::StringView new_account);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void getCustomStyles(Containers::ArrayView<CustomStyle> styles, ArrayProperty* style_array);
|
void getCustomStyles(Containers::ArrayView<CustomStyle> styles, Gvas::Types::ArrayProperty* style_array);
|
||||||
auto writeCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool;
|
bool writeCustomStyle(const CustomStyle& style, std::size_t index, Gvas::Types::ArrayProperty* style_array);
|
||||||
|
|
||||||
void getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array);
|
void getDecals(Containers::ArrayView<Decal> decals, Gvas::Types::ArrayProperty* decal_array);
|
||||||
void writeDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array);
|
void writeDecals(Containers::ArrayView<Decal> decals, Gvas::Types::ArrayProperty* decal_array);
|
||||||
|
|
||||||
void getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array);
|
void getAccessories(Containers::ArrayView<Accessory> accessories, Gvas::Types::ArrayProperty* accessory_array);
|
||||||
void writeAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accs_array);
|
void writeAccessories(Containers::ArrayView<Accessory> accessories, Gvas::Types::ArrayProperty* accs_array);
|
||||||
|
|
||||||
void getWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array);
|
void getWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array);
|
||||||
auto writeWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool;
|
bool writeWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array);
|
||||||
|
|
||||||
void getTuningCategory(Containers::StringView big_node_prop_name, Int& big_node_id,
|
void getTuningCategory(Containers::StringView big_node_prop_name, std::int32_t& big_node_id,
|
||||||
Containers::StringView small_nodes_prop_name, Containers::ArrayView<Int> small_nodes_ids);
|
Containers::StringView small_nodes_prop_name,
|
||||||
|
Containers::ArrayView<std::int32_t> small_nodes_ids);
|
||||||
|
|
||||||
Containers::Optional<UESaveFile> _mass;
|
Containers::Optional<Gvas::File> _mass;
|
||||||
|
|
||||||
Containers::String _lastError;
|
Containers::String _lastError;
|
||||||
|
|
||||||
|
@ -174,7 +176,7 @@ class Mass {
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Joints joints{};
|
Joints joints{};
|
||||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
Containers::StaticArray<4, std::int32_t> styles{ValueInit};
|
||||||
Color4 eyeFlare{0.0f};
|
Color4 eyeFlare{0.0f};
|
||||||
Containers::StaticArray<16, CustomStyle> customStyles;
|
Containers::StaticArray<16, CustomStyle> customStyles;
|
||||||
} _frame;
|
} _frame;
|
||||||
|
@ -198,15 +200,17 @@ class Mass {
|
||||||
Containers::Array<CustomStyle> _globalStyles;
|
Containers::Array<CustomStyle> _globalStyles;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Int engineId;
|
std::int32_t engineId;
|
||||||
Containers::StaticArray<7, Int> gearIds;
|
Containers::StaticArray<7, std::int32_t> gearIds;
|
||||||
|
|
||||||
Int osId;
|
std::int32_t osId;
|
||||||
Containers::StaticArray<7, Int> moduleIds;
|
Containers::StaticArray<7, std::int32_t> moduleIds;
|
||||||
|
|
||||||
Int archId;
|
std::int32_t archId;
|
||||||
Containers::StaticArray<7, Int> techIds;
|
Containers::StaticArray<7, std::int32_t> techIds;
|
||||||
} _tuning;
|
} _tuning;
|
||||||
|
|
||||||
Containers::String _account;
|
Containers::String _account;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
441
src/GameObjects/Mass_Armour.cpp
Normal file
441
src/GameObjects/Mass_Armour.cpp
Normal file
|
@ -0,0 +1,441 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
#include "../Gvas/Types/ArrayProperty.h"
|
||||||
|
#include "../Gvas/Types/ByteProperty.h"
|
||||||
|
#include "../Gvas/Types/GenericStructProperty.h"
|
||||||
|
#include "../Gvas/Types/IntProperty.h"
|
||||||
|
#include "../Gvas/Types/StringProperty.h"
|
||||||
|
#include "../Gvas/Types/VectorStructProperty.h"
|
||||||
|
|
||||||
|
#include "Mass.h"
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
|
Containers::ArrayView<ArmourPart>
|
||||||
|
Mass::armourParts() {
|
||||||
|
return _armour.parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getArmourParts() {
|
||||||
|
LOG_INFO("Getting armour parts.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto armour_array = unit_data->at<Gvas::Types::ArrayProperty>(MASS_ARMOUR_PARTS);
|
||||||
|
if(!armour_array) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_ARMOUR_PARTS, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::uint32_t i = 0; i < armour_array->items.size(); i++) {
|
||||||
|
auto part_prop = armour_array->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
auto& part = _armour.parts[i];
|
||||||
|
|
||||||
|
auto& armour_slot = part_prop->at<Gvas::Types::ByteProperty>(MASS_ARMOUR_SLOT)->enumValue;
|
||||||
|
#define c(enumerator, strenum, name) if(armour_slot == (strenum)) { part.slot = ArmourPart::Slot::enumerator; } else
|
||||||
|
#include "../Maps/ArmourSlots.hpp"
|
||||||
|
#undef c
|
||||||
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid armour slot enumerator {}.", armour_slot);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
part.id = part_prop->at<Gvas::Types::IntProperty>(MASS_ARMOUR_ID)->value;
|
||||||
|
|
||||||
|
auto part_styles = part_prop->at<Gvas::Types::ArrayProperty>(MASS_ARMOUR_STYLES);
|
||||||
|
if(!part_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Part styles not found for part number {}.", i);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::uint32_t j = 0; j < part_styles->items.size(); j++) {
|
||||||
|
part.styles[j] = part_styles->at<Gvas::Types::IntProperty>(j)->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto decals_array = part_prop->at<Gvas::Types::ArrayProperty>(MASS_ARMOUR_DECALS);
|
||||||
|
if(!decals_array) {
|
||||||
|
LOG_ERROR_FORMAT("Part decals not found for part number {}.", i);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
part.decals = Containers::Array<Decal>{decals_array->items.size()};
|
||||||
|
|
||||||
|
getDecals(part.decals, decals_array);
|
||||||
|
|
||||||
|
auto accs_array = part_prop->at<Gvas::Types::ArrayProperty>(MASS_ARMOUR_ACCESSORIES);
|
||||||
|
if(!accs_array) {
|
||||||
|
LOG_WARNING_FORMAT("Part accessories not found for part number {}.", i);
|
||||||
|
part.accessories = Containers::Array<Accessory>{};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(part.accessories.size() != accs_array->items.size()) {
|
||||||
|
part.accessories = Containers::Array<Accessory>{accs_array->items.size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
getAccessories(part.accessories, accs_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeArmourPart(ArmourPart::Slot slot) {
|
||||||
|
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 unit_data = _mass->at<Gvas::Types::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<Gvas::Types::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;
|
||||||
|
switch(slot) {
|
||||||
|
#define c(enumerator, strenum, name) case ArmourPart::Slot::enumerator: \
|
||||||
|
slot_str = strenum; \
|
||||||
|
break;
|
||||||
|
#include "../Maps/ArmourSlots.hpp"
|
||||||
|
#undef c
|
||||||
|
}
|
||||||
|
|
||||||
|
Gvas::Types::GenericStructProperty* part_prop = nullptr;
|
||||||
|
|
||||||
|
for(std::uint32_t i = 0; i < armour_array->items.size(); i++) {
|
||||||
|
part_prop = armour_array->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
if(slot_str == part_prop->at<Gvas::Types::ByteProperty>(MASS_ARMOUR_SLOT)->enumValue) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
part_prop = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!part_prop) {
|
||||||
|
auto prefix = "Couldn't find the armour part for slot "_s;
|
||||||
|
switch(slot) {
|
||||||
|
#define c(enumerator, strenum, name) case ArmourPart::Slot::enumerator: \
|
||||||
|
_lastError = prefix + "ArmourSlot::" #enumerator "."_s; \
|
||||||
|
break;
|
||||||
|
#include "../Maps/ArmourSlots.hpp"
|
||||||
|
#undef c
|
||||||
|
}
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
part_prop->at<Gvas::Types::IntProperty>(MASS_ARMOUR_ID)->value = part.id;
|
||||||
|
|
||||||
|
auto part_styles = part_prop->at<Gvas::Types::ArrayProperty>(MASS_ARMOUR_STYLES);
|
||||||
|
for(std::uint32_t i = 0; i < part.styles.size(); i++) {
|
||||||
|
part_styles->at<Gvas::Types::IntProperty>(i)->value = part.styles[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto decals_array = part_prop->at<Gvas::Types::ArrayProperty>(MASS_ARMOUR_DECALS);
|
||||||
|
writeDecals(part.decals, decals_array);
|
||||||
|
|
||||||
|
if(!part.accessories.isEmpty()) {
|
||||||
|
auto accs_array = part_prop->at<Gvas::Types::ArrayProperty>(MASS_ARMOUR_ACCESSORIES);
|
||||||
|
writeAccessories(part.accessories, accs_array);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_mass->saveToFile()) {
|
||||||
|
_lastError = _mass->lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BulletLauncherAttachmentStyle&
|
||||||
|
Mass::bulletLauncherAttachmentStyle() {
|
||||||
|
return _armour.blAttachmentStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<BulletLauncherAttachment>
|
||||||
|
Mass::bulletLauncherAttachments() {
|
||||||
|
return _armour.blAttachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getBulletLauncherAttachments() {
|
||||||
|
LOG_INFO("Getting the bullet launcher attachment data.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto attach_style_prop = unit_data->at<Gvas::Types::ByteProperty>(MASS_BL_ATTACHMENT_STYLE);
|
||||||
|
auto attach_array = unit_data->at<Gvas::Types::ArrayProperty>(MASS_BL_ATTACHMENTS);
|
||||||
|
|
||||||
|
if(!attach_style_prop && !attach_array) {
|
||||||
|
LOG_WARNING_FORMAT("No bullet launcher attachment data found in {}.", _filename);
|
||||||
|
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(attach_style_prop && !attach_array) {
|
||||||
|
LOG_WARNING_FORMAT("No bullet launcher attachments found in {}.", _filename);
|
||||||
|
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(attach_array->items.size() == _weapons.bulletLaunchers.size() &&
|
||||||
|
attach_array->items.size() == _armour.blAttachment.size())
|
||||||
|
{
|
||||||
|
for(std::uint32_t i = 0; i < attach_array->items.size(); i++) {
|
||||||
|
auto attachment_prop = attach_array->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
auto& attachment = _armour.blAttachment[i];
|
||||||
|
|
||||||
|
Containers::StringView socket = attachment_prop->at<Gvas::Types::StringProperty>(MASS_BL_ATTACHMENT_SOCKET)->value;
|
||||||
|
#define c(enumerator, strenum, name) if(socket == (strenum)) { attachment.socket = BulletLauncherAttachment::Socket::enumerator; } else
|
||||||
|
#include "../Maps/BulletLauncherSockets.hpp"
|
||||||
|
#undef c
|
||||||
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid attachment socket {}.", socket);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rel_loc_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_RELLOC);
|
||||||
|
attachment.relativeLocation = rel_loc_prop->vector;
|
||||||
|
auto off_loc_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_OFFLOC);
|
||||||
|
attachment.offsetLocation = off_loc_prop->vector;
|
||||||
|
auto rel_rot_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_RELROT);
|
||||||
|
attachment.relativeRotation = rel_rot_prop->vector;
|
||||||
|
auto off_rot_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_OFFROT);
|
||||||
|
attachment.offsetRotation = off_rot_prop->vector;
|
||||||
|
auto rel_scale_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_RELSCALE);
|
||||||
|
attachment.relativeScale = rel_scale_prop->vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(attach_style_prop) {
|
||||||
|
Containers::StringView attach_style = attach_style_prop->enumValue;
|
||||||
|
#define c(enumerator, strenum) if(attach_style == (strenum)) { _armour.blAttachmentStyle = BulletLauncherAttachmentStyle::enumerator; } else
|
||||||
|
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
|
||||||
|
#undef c
|
||||||
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid attachment style {}.", attach_style);
|
||||||
|
_state = State::Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::ActiveOne;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeBulletLauncherAttachments() {
|
||||||
|
LOG_INFO("Writing bullet launcher attachments.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
_lastError = "No unit data in " + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto attach_style_prop = unit_data->at<Gvas::Types::ByteProperty>(MASS_BL_ATTACHMENT_STYLE);
|
||||||
|
auto attach_array = unit_data->at<Gvas::Types::ArrayProperty>(MASS_BL_ATTACHMENTS);
|
||||||
|
|
||||||
|
if(!attach_style_prop && !attach_array) {
|
||||||
|
_lastError = "No attachment properties to write to in " + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(attach_style_prop && !attach_array) {
|
||||||
|
_lastError = "Couldn't find the attachments in " + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(attach_array->items.size() == _weapons.bulletLaunchers.size() &&
|
||||||
|
attach_array->items.size() == _armour.blAttachment.size())
|
||||||
|
{
|
||||||
|
for(std::uint32_t i = 0; i < attach_array->items.size(); i++) {
|
||||||
|
auto attachment_prop = attach_array->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
auto& attachment = _armour.blAttachment[i];
|
||||||
|
|
||||||
|
auto& socket = attachment_prop->at<Gvas::Types::StringProperty>(MASS_BL_ATTACHMENT_SOCKET)->value;
|
||||||
|
switch(attachment.socket) {
|
||||||
|
#define c(enumerator, strenum, name) case BulletLauncherAttachment::Socket::enumerator: socket = strenum; break;
|
||||||
|
#include "../Maps/BulletLauncherSockets.hpp"
|
||||||
|
#undef c
|
||||||
|
default:
|
||||||
|
_lastError = "Invalid socket type."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rel_loc_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_RELLOC);
|
||||||
|
rel_loc_prop->vector = attachment.relativeLocation;
|
||||||
|
auto off_loc_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_OFFLOC);
|
||||||
|
off_loc_prop->vector = attachment.offsetLocation;
|
||||||
|
auto rel_rot_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_RELROT);
|
||||||
|
rel_rot_prop->vector = attachment.relativeRotation;
|
||||||
|
auto off_rot_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_OFFROT);
|
||||||
|
off_rot_prop->vector = attachment.offsetRotation;
|
||||||
|
auto rel_scale_prop = attachment_prop->at<Gvas::Types::VectorStructProperty>(MASS_BL_ATTACHMENT_RELSCALE);
|
||||||
|
rel_scale_prop->vector = attachment.relativeScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!attach_style_prop) {
|
||||||
|
attach_style_prop = new Gvas::Types::ByteProperty;
|
||||||
|
attach_style_prop->name.emplace(MASS_BL_ATTACHMENT_STYLE);
|
||||||
|
attach_style_prop->enumType = "enuBLAttachmentStyle"_s;
|
||||||
|
Gvas::Types::ByteProperty::ptr prop{attach_style_prop};
|
||||||
|
arrayAppend(unit_data->properties, Utility::move(prop));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& attach_style = attach_style_prop->enumValue;
|
||||||
|
switch(_armour.blAttachmentStyle) {
|
||||||
|
#define c(enumerator, strenum) case BulletLauncherAttachmentStyle::enumerator: \
|
||||||
|
attach_style = strenum; \
|
||||||
|
break;
|
||||||
|
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
|
||||||
|
#undef c
|
||||||
|
default:
|
||||||
|
_lastError = "Unknown BL attachment style.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_mass->saveToFile()) {
|
||||||
|
_lastError = _mass->lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<CustomStyle>
|
||||||
|
Mass::armourCustomStyles() {
|
||||||
|
return _armour.customStyles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getArmourCustomStyles() {
|
||||||
|
LOG_INFO("Getting the custom armour styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto armour_styles = unit_data->at<Gvas::Types::ArrayProperty>(MASS_CUSTOM_ARMOUR_STYLES);
|
||||||
|
if(!armour_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_CUSTOM_ARMOUR_STYLES, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCustomStyles(_armour.customStyles, armour_styles);
|
||||||
|
|
||||||
|
for(auto& style : _armour.customStyles) {
|
||||||
|
style.type = CustomStyle::Type::Armour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeArmourCustomStyle(std::size_t index) {
|
||||||
|
LOG_INFO_FORMAT("Writing custom armour style {}.", index);
|
||||||
|
|
||||||
|
if(index > _armour.customStyles.size()) {
|
||||||
|
_lastError = "Style index out of range."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
_lastError = "Couldn't find unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto armour_styles = unit_data->at<Gvas::Types::ArrayProperty>(MASS_CUSTOM_ARMOUR_STYLES);
|
||||||
|
if(!armour_styles) {
|
||||||
|
_lastError = "Couldn't find armour custom styles in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return writeCustomStyle(_armour.customStyles[index], index, armour_styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
139
src/GameObjects/Mass_DecalsAccessories.cpp
Normal file
139
src/GameObjects/Mass_DecalsAccessories.cpp
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Gvas/Types/ArrayProperty.h"
|
||||||
|
#include "../Gvas/Types/BoolProperty.h"
|
||||||
|
#include "../Gvas/Types/ColourStructProperty.h"
|
||||||
|
#include "../Gvas/Types/FloatProperty.h"
|
||||||
|
#include "../Gvas/Types/GenericStructProperty.h"
|
||||||
|
#include "../Gvas/Types/RotatorStructProperty.h"
|
||||||
|
#include "../Gvas/Types/VectorStructProperty.h"
|
||||||
|
#include "../Gvas/Types/Vector2DStructProperty.h"
|
||||||
|
#include "../Gvas/Types/IntProperty.h"
|
||||||
|
|
||||||
|
#include "Mass.h"
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getDecals(Containers::ArrayView<Decal> decals, Gvas::Types::ArrayProperty* decal_array) {
|
||||||
|
for(std::uint32_t i = 0; i < decal_array->items.size(); i++) {
|
||||||
|
auto decal_prop = decal_array->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
CORRADE_INTERNAL_ASSERT(decal_prop);
|
||||||
|
auto& decal = decals[i];
|
||||||
|
|
||||||
|
decal.id = decal_prop->at<Gvas::Types::IntProperty>(MASS_DECAL_ID)->value;
|
||||||
|
auto colour_prop = decal_prop->at<Gvas::Types::ColourStructProperty>(MASS_DECAL_COLOUR);
|
||||||
|
decal.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a};
|
||||||
|
auto pos_prop = decal_prop->at<Gvas::Types::VectorStructProperty>(MASS_DECAL_POSITION);
|
||||||
|
decal.position = pos_prop->vector;
|
||||||
|
auto u_prop = decal_prop->at<Gvas::Types::VectorStructProperty>(MASS_DECAL_UAXIS);
|
||||||
|
decal.uAxis = u_prop->vector;
|
||||||
|
auto v_prop = decal_prop->at<Gvas::Types::VectorStructProperty>(MASS_DECAL_VAXIS);
|
||||||
|
decal.vAxis = v_prop->vector;
|
||||||
|
auto offset_prop = decal_prop->at<Gvas::Types::Vector2DStructProperty>(MASS_DECAL_OFFSET);
|
||||||
|
decal.offset = offset_prop->vector;
|
||||||
|
decal.scale = decal_prop->at<Gvas::Types::FloatProperty>(MASS_DECAL_SCALE)->value;
|
||||||
|
decal.rotation = decal_prop->at<Gvas::Types::FloatProperty>(MASS_DECAL_ROTATION)->value;
|
||||||
|
decal.flip = decal_prop->at<Gvas::Types::BoolProperty>(MASS_DECAL_FLIP)->value;
|
||||||
|
decal.wrap = decal_prop->at<Gvas::Types::BoolProperty>(MASS_DECAL_WRAP)->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::writeDecals(Containers::ArrayView<Decal> decals, Gvas::Types::ArrayProperty* decal_array) {
|
||||||
|
for(std::uint32_t i = 0; i < decal_array->items.size(); i++) {
|
||||||
|
auto decal_prop = decal_array->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
CORRADE_INTERNAL_ASSERT(decal_prop);
|
||||||
|
auto& decal = decals[i];
|
||||||
|
|
||||||
|
decal_prop->at<Gvas::Types::IntProperty>(MASS_DECAL_ID)->value = decal.id;
|
||||||
|
auto colour_prop = decal_prop->at<Gvas::Types::ColourStructProperty>(MASS_DECAL_COLOUR);
|
||||||
|
colour_prop->r = decal.colour.r();
|
||||||
|
colour_prop->g = decal.colour.g();
|
||||||
|
colour_prop->b = decal.colour.b();
|
||||||
|
colour_prop->a = decal.colour.a();
|
||||||
|
auto pos_prop = decal_prop->at<Gvas::Types::VectorStructProperty>(MASS_DECAL_POSITION);
|
||||||
|
pos_prop->vector = decal.position;
|
||||||
|
auto u_prop = decal_prop->at<Gvas::Types::VectorStructProperty>(MASS_DECAL_UAXIS);
|
||||||
|
u_prop->vector = decal.uAxis;
|
||||||
|
auto v_prop = decal_prop->at<Gvas::Types::VectorStructProperty>(MASS_DECAL_VAXIS);
|
||||||
|
v_prop->vector = decal.vAxis;
|
||||||
|
auto offset_prop = decal_prop->at<Gvas::Types::Vector2DStructProperty>(MASS_DECAL_OFFSET);
|
||||||
|
offset_prop->vector = decal.offset;
|
||||||
|
decal_prop->at<Gvas::Types::FloatProperty>(MASS_DECAL_SCALE)->value = decal.scale;
|
||||||
|
decal_prop->at<Gvas::Types::FloatProperty>(MASS_DECAL_ROTATION)->value = decal.rotation;
|
||||||
|
decal_prop->at<Gvas::Types::BoolProperty>(MASS_DECAL_FLIP)->value = decal.flip;
|
||||||
|
decal_prop->at<Gvas::Types::BoolProperty>(MASS_DECAL_WRAP)->value = decal.wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getAccessories(Containers::ArrayView<Accessory> accessories, Gvas::Types::ArrayProperty* accessory_array) {
|
||||||
|
for(std::uint32_t i = 0; i < accessory_array->items.size(); i++) {
|
||||||
|
auto acc_prop = accessory_array->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
CORRADE_INTERNAL_ASSERT(acc_prop);
|
||||||
|
auto& accessory = accessories[i];
|
||||||
|
|
||||||
|
accessory.attachIndex = acc_prop->at<Gvas::Types::IntProperty>(MASS_ACCESSORY_ATTACH_INDEX)->value;
|
||||||
|
accessory.id = acc_prop->at<Gvas::Types::IntProperty>(MASS_ACCESSORY_ID)->value;
|
||||||
|
auto acc_styles = acc_prop->at<Gvas::Types::ArrayProperty>(MASS_ACCESSORY_STYLES);
|
||||||
|
for(std::uint32_t j = 0; j < acc_styles->items.size(); j++) {
|
||||||
|
accessory.styles[j] = acc_styles->at<Gvas::Types::IntProperty>(j)->value;
|
||||||
|
}
|
||||||
|
auto rel_pos_prop = acc_prop->at<Gvas::Types::VectorStructProperty>(MASS_ACCESSORY_RELPOS);
|
||||||
|
accessory.relativePosition = rel_pos_prop->vector;
|
||||||
|
auto rel_pos_offset_prop = acc_prop->at<Gvas::Types::VectorStructProperty>(MASS_ACCESSORY_OFFPOS);
|
||||||
|
accessory.relativePositionOffset = rel_pos_offset_prop->vector;
|
||||||
|
auto rel_rot_prop = acc_prop->at<Gvas::Types::RotatorStructProperty>(MASS_ACCESSORY_RELROT);
|
||||||
|
accessory.relativeRotation = rel_rot_prop->vector;
|
||||||
|
auto rel_rot_offset_prop = acc_prop->at<Gvas::Types::RotatorStructProperty>(MASS_ACCESSORY_OFFROT);
|
||||||
|
accessory.relativeRotationOffset = rel_rot_offset_prop->vector;
|
||||||
|
auto local_scale_prop = acc_prop->at<Gvas::Types::VectorStructProperty>(MASS_ACCESSORY_SCALE);
|
||||||
|
accessory.localScale = local_scale_prop->vector;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::writeAccessories(Containers::ArrayView<Accessory> accessories, Gvas::Types::ArrayProperty* accs_array) {
|
||||||
|
for(std::uint32_t i = 0; i < accs_array->items.size(); i++) {
|
||||||
|
auto acc_prop = accs_array->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
CORRADE_INTERNAL_ASSERT(acc_prop);
|
||||||
|
auto& accessory = accessories[i];
|
||||||
|
|
||||||
|
acc_prop->at<Gvas::Types::IntProperty>(MASS_ACCESSORY_ATTACH_INDEX)->value = accessory.attachIndex;
|
||||||
|
acc_prop->at<Gvas::Types::IntProperty>(MASS_ACCESSORY_ID)->value = accessory.id;
|
||||||
|
auto acc_styles = acc_prop->at<Gvas::Types::ArrayProperty>(MASS_ACCESSORY_STYLES);
|
||||||
|
for(std::uint32_t j = 0; j < acc_styles->items.size(); j++) {
|
||||||
|
acc_styles->at<Gvas::Types::IntProperty>(j)->value = accessory.styles[j];
|
||||||
|
}
|
||||||
|
auto rel_pos_prop = acc_prop->at<Gvas::Types::VectorStructProperty>(MASS_ACCESSORY_RELPOS);
|
||||||
|
rel_pos_prop->vector = accessory.relativePosition;
|
||||||
|
auto rel_pos_offset_prop = acc_prop->at<Gvas::Types::VectorStructProperty>(MASS_ACCESSORY_OFFPOS);
|
||||||
|
rel_pos_offset_prop->vector = accessory.relativePositionOffset;
|
||||||
|
auto rel_rot_prop = acc_prop->at<Gvas::Types::RotatorStructProperty>(MASS_ACCESSORY_RELROT);
|
||||||
|
rel_rot_prop->vector = accessory.relativeRotation;
|
||||||
|
auto rel_rot_offset_prop = acc_prop->at<Gvas::Types::RotatorStructProperty>(MASS_ACCESSORY_OFFROT);
|
||||||
|
rel_rot_offset_prop->vector = accessory.relativeRotationOffset;
|
||||||
|
auto local_scale_prop = acc_prop->at<Gvas::Types::VectorStructProperty>(MASS_ACCESSORY_SCALE);
|
||||||
|
local_scale_prop->vector = accessory.localScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
411
src/GameObjects/Mass_Frame.cpp
Normal file
411
src/GameObjects/Mass_Frame.cpp
Normal file
|
@ -0,0 +1,411 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
#include "../Gvas/Types/ArrayProperty.h"
|
||||||
|
#include "../Gvas/Types/ColourStructProperty.h"
|
||||||
|
#include "../Gvas/Types/FloatProperty.h"
|
||||||
|
#include "../Gvas/Types/GenericStructProperty.h"
|
||||||
|
#include "../Gvas/Types/IntProperty.h"
|
||||||
|
|
||||||
|
#include "Mass.h"
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
|
Joints&
|
||||||
|
Mass::jointSliders() {
|
||||||
|
return _frame.joints;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getJointSliders() {
|
||||||
|
LOG_INFO("Getting joint sliders.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame_prop = unit_data->at<Gvas::Types::GenericStructProperty>(MASS_FRAME);
|
||||||
|
if(!frame_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_FRAME, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_NECK);
|
||||||
|
_frame.joints.neck = (length ? length->value : 0.0f);
|
||||||
|
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_BODY);
|
||||||
|
_frame.joints.body = (length ? length->value : 0.0f);
|
||||||
|
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_SHOULDER);
|
||||||
|
_frame.joints.shoulders = (length ? length->value : 0.0f);
|
||||||
|
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_HIP);
|
||||||
|
_frame.joints.hips = (length ? length->value : 0.0f);
|
||||||
|
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_ARM_UPPER);
|
||||||
|
_frame.joints.upperArms = (length ? length->value : 0.0f);
|
||||||
|
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_ARM_LOWER);
|
||||||
|
_frame.joints.lowerArms = (length ? length->value : 0.0f);
|
||||||
|
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_LEG_UPPER);
|
||||||
|
_frame.joints.upperLegs = (length ? length->value : 0.0f);
|
||||||
|
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_LEG_LOWER);
|
||||||
|
_frame.joints.lowerLegs = (length ? length->value : 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeJointSliders() {
|
||||||
|
LOG_INFO("Writing joint sliders");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame_prop = unit_data->at<Gvas::Types::GenericStructProperty>(MASS_FRAME);
|
||||||
|
|
||||||
|
if(!frame_prop) {
|
||||||
|
_lastError = "No frame data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::Array<Gvas::Types::UnrealPropertyBase::ptr> temp;
|
||||||
|
|
||||||
|
auto length = frame_prop->atMove<Gvas::Types::FloatProperty>(MASS_JOINT_NECK);
|
||||||
|
if(_frame.joints.neck != 0.0f) {
|
||||||
|
if(!length) {
|
||||||
|
length.emplace();
|
||||||
|
length->name.emplace(MASS_JOINT_NECK);
|
||||||
|
}
|
||||||
|
length->value = _frame.joints.neck;
|
||||||
|
arrayAppend(temp, Utility::move(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = frame_prop->atMove<Gvas::Types::FloatProperty>(MASS_JOINT_BODY);
|
||||||
|
if(_frame.joints.body != 0.0f) {
|
||||||
|
if(!length) {
|
||||||
|
length.emplace();
|
||||||
|
length->name.emplace(MASS_JOINT_BODY);
|
||||||
|
}
|
||||||
|
length->value = _frame.joints.body;
|
||||||
|
arrayAppend(temp, Utility::move(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = frame_prop->atMove<Gvas::Types::FloatProperty>(MASS_JOINT_SHOULDER);
|
||||||
|
if(_frame.joints.shoulders != 0.0f) {
|
||||||
|
if(!length) {
|
||||||
|
length.emplace();
|
||||||
|
length->name.emplace(MASS_JOINT_SHOULDER);
|
||||||
|
}
|
||||||
|
length->value = _frame.joints.shoulders;
|
||||||
|
arrayAppend(temp, Utility::move(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = frame_prop->atMove<Gvas::Types::FloatProperty>(MASS_JOINT_ARM_UPPER);
|
||||||
|
if(_frame.joints.upperArms != 0.0f) {
|
||||||
|
if(!length) {
|
||||||
|
length.emplace();
|
||||||
|
length->name.emplace(MASS_JOINT_ARM_UPPER);
|
||||||
|
}
|
||||||
|
length->value = _frame.joints.upperArms;
|
||||||
|
arrayAppend(temp, Utility::move(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = frame_prop->atMove<Gvas::Types::FloatProperty>(MASS_JOINT_ARM_LOWER);
|
||||||
|
if(_frame.joints.lowerArms != 0.0f) {
|
||||||
|
if(!length) {
|
||||||
|
length.emplace();
|
||||||
|
length->name.emplace(MASS_JOINT_ARM_LOWER);
|
||||||
|
}
|
||||||
|
length->value = _frame.joints.lowerArms;
|
||||||
|
arrayAppend(temp, Utility::move(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = frame_prop->atMove<Gvas::Types::FloatProperty>(MASS_JOINT_HIP);
|
||||||
|
if(_frame.joints.hips != 0.0f) {
|
||||||
|
if(!length) {
|
||||||
|
length.emplace();
|
||||||
|
length->name.emplace(MASS_JOINT_HIP);
|
||||||
|
}
|
||||||
|
length->value = _frame.joints.hips;
|
||||||
|
arrayAppend(temp, Utility::move(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = frame_prop->atMove<Gvas::Types::FloatProperty>(MASS_JOINT_LEG_UPPER);
|
||||||
|
if(_frame.joints.upperLegs != 0.0f) {
|
||||||
|
if(!length) {
|
||||||
|
length.emplace();
|
||||||
|
length->name.emplace(MASS_JOINT_LEG_UPPER);
|
||||||
|
}
|
||||||
|
length->value = _frame.joints.upperLegs;
|
||||||
|
arrayAppend(temp, Utility::move(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
length = frame_prop->atMove<Gvas::Types::FloatProperty>(MASS_JOINT_LEG_LOWER);
|
||||||
|
if(_frame.joints.lowerLegs != 0.0f) {
|
||||||
|
if(!length) {
|
||||||
|
length.emplace();
|
||||||
|
length->name.emplace(MASS_JOINT_LEG_LOWER);
|
||||||
|
}
|
||||||
|
length->value = _frame.joints.lowerLegs;
|
||||||
|
arrayAppend(temp, Utility::move(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayAppend(temp, Utility::move(frame_prop->properties[frame_prop->properties.size() - 3]));
|
||||||
|
arrayAppend(temp, Utility::move(frame_prop->properties[frame_prop->properties.size() - 2]));
|
||||||
|
arrayAppend(temp, Utility::move(frame_prop->properties[frame_prop->properties.size() - 1]));
|
||||||
|
|
||||||
|
frame_prop->properties = Utility::move(temp);
|
||||||
|
|
||||||
|
if(!_mass->saveToFile()) {
|
||||||
|
_lastError = _mass->lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<std::int32_t>
|
||||||
|
Mass::frameStyles() {
|
||||||
|
return _frame.styles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getFrameStyles() {
|
||||||
|
LOG_INFO("Getting frame styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame_prop = unit_data->at<Gvas::Types::GenericStructProperty>(MASS_FRAME);
|
||||||
|
if(!frame_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_FRAME, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame_styles = frame_prop->at<Gvas::Types::ArrayProperty>(MASS_FRAME_STYLES);
|
||||||
|
if(!frame_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_FRAME_STYLES, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::uint32_t i = 0; i < frame_styles->items.size(); i++) {
|
||||||
|
_frame.styles[i] = frame_styles->at<Gvas::Types::IntProperty>(i)->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeFrameStyles() {
|
||||||
|
LOG_INFO("Writing frame styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame = unit_data->at<Gvas::Types::GenericStructProperty>(MASS_FRAME);
|
||||||
|
if(!frame) {
|
||||||
|
_lastError = "No frame data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame_styles = frame->at<Gvas::Types::ArrayProperty>(MASS_FRAME_STYLES);
|
||||||
|
if(!frame_styles) {
|
||||||
|
_lastError = "No frame styles in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::uint32_t i = 0; i < frame_styles->items.size(); i++) {
|
||||||
|
frame_styles->at<Gvas::Types::IntProperty>(i)->value = _frame.styles[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_mass->saveToFile()) {
|
||||||
|
_lastError = _mass->lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color4&
|
||||||
|
Mass::eyeFlareColour() {
|
||||||
|
return _frame.eyeFlare;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getEyeFlareColour() {
|
||||||
|
LOG_INFO("Getting the eye flare colour.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame_prop = unit_data->at<Gvas::Types::GenericStructProperty>(MASS_FRAME);
|
||||||
|
if(!frame_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_FRAME, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eye_flare_prop = frame_prop->at<Gvas::Types::ColourStructProperty>(MASS_EYE_FLARE);
|
||||||
|
if(!eye_flare_prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_EYE_FLARE, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_frame.eyeFlare = Color4{eye_flare_prop->r, eye_flare_prop->g, eye_flare_prop->b, eye_flare_prop->a};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeEyeFlareColour() {
|
||||||
|
LOG_INFO("Writing the eye flare colour.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame = unit_data->at<Gvas::Types::GenericStructProperty>(MASS_FRAME);
|
||||||
|
if(!frame) {
|
||||||
|
_lastError = "No frame data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eye_flare_prop = frame->at<Gvas::Types::ColourStructProperty>(MASS_EYE_FLARE);
|
||||||
|
if(!eye_flare_prop) {
|
||||||
|
_lastError = "No eye flare property in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
eye_flare_prop->r = _frame.eyeFlare.r();
|
||||||
|
eye_flare_prop->g = _frame.eyeFlare.g();
|
||||||
|
eye_flare_prop->b = _frame.eyeFlare.b();
|
||||||
|
eye_flare_prop->a = _frame.eyeFlare.a();
|
||||||
|
|
||||||
|
if(!_mass->saveToFile()) {
|
||||||
|
_lastError = _mass->lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<CustomStyle>
|
||||||
|
Mass::frameCustomStyles() {
|
||||||
|
return _frame.customStyles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getFrameCustomStyles() {
|
||||||
|
LOG_INFO("Getting the frame's custom styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame_styles = unit_data->at<Gvas::Types::ArrayProperty>(MASS_CUSTOM_FRAME_STYLES);
|
||||||
|
if(!frame_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_CUSTOM_FRAME_STYLES, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCustomStyles(_frame.customStyles, frame_styles);
|
||||||
|
|
||||||
|
for(auto& style : _frame.customStyles) {
|
||||||
|
style.type = CustomStyle::Type::Frame;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeFrameCustomStyle(std::size_t index) {
|
||||||
|
LOG_INFO_FORMAT("Writing frame custom style number {}.", index);
|
||||||
|
|
||||||
|
if(index > _frame.customStyles.size()) {
|
||||||
|
_lastError = "Style index out of range."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame_styles = unit_data->at<Gvas::Types::ArrayProperty>(MASS_CUSTOM_FRAME_STYLES);
|
||||||
|
if(!frame_styles) {
|
||||||
|
_lastError = "No frame styles in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return writeCustomStyle(_frame.customStyles[index], index, frame_styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
158
src/GameObjects/Mass_Styles.cpp
Normal file
158
src/GameObjects/Mass_Styles.cpp
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
#include "../Gvas/Types/ArrayProperty.h"
|
||||||
|
#include "../Gvas/Types/ColourStructProperty.h"
|
||||||
|
#include "../Gvas/Types/FloatProperty.h"
|
||||||
|
#include "../Gvas/Types/GenericStructProperty.h"
|
||||||
|
#include "../Gvas/Types/IntProperty.h"
|
||||||
|
#include "../Gvas/Types/StringProperty.h"
|
||||||
|
|
||||||
|
#include "Mass.h"
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
|
Containers::ArrayView<CustomStyle>
|
||||||
|
Mass::globalStyles() {
|
||||||
|
return _globalStyles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getGlobalStyles() {
|
||||||
|
LOG_INFO("Getting global styles.");
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto global_styles = unit_data->at<Gvas::Types::ArrayProperty>(MASS_GLOBAL_STYLES);
|
||||||
|
if(!global_styles) {
|
||||||
|
LOG_WARNING_FORMAT("Couldn't find global styles in {}.", _filename);
|
||||||
|
_globalStyles = Containers::Array<CustomStyle>{0};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(global_styles->items.size() != _globalStyles.size()) {
|
||||||
|
_globalStyles = Containers::Array<CustomStyle>{global_styles->items.size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
getCustomStyles(_globalStyles, global_styles);
|
||||||
|
|
||||||
|
for(auto& style : _globalStyles) {
|
||||||
|
style.type = CustomStyle::Type::Global;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeGlobalStyle(std::size_t index) {
|
||||||
|
LOG_INFO_FORMAT("Writing global style number {}.", index);
|
||||||
|
|
||||||
|
if(index > _globalStyles.size()) {
|
||||||
|
_lastError = "Global style index out of range"_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
_lastError = "No unit data found in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto global_styles = unit_data->at<Gvas::Types::ArrayProperty>(MASS_GLOBAL_STYLES);
|
||||||
|
if(!global_styles) {
|
||||||
|
_lastError = "No global styles found in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return writeCustomStyle(_globalStyles[index], index, global_styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getCustomStyles(Containers::ArrayView<CustomStyle> styles, Gvas::Types::ArrayProperty* style_array) {
|
||||||
|
for(std::uint32_t i = 0; i < style_array->items.size(); i++) {
|
||||||
|
auto style_prop = style_array->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
auto& style = styles[i];
|
||||||
|
|
||||||
|
style.name = style_prop->at<Gvas::Types::StringProperty>(MASS_STYLE_NAME)->value;
|
||||||
|
auto colour_prop = style_prop->at<Gvas::Types::ColourStructProperty>(MASS_STYLE_COLOUR);
|
||||||
|
style.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a};
|
||||||
|
style.metallic = style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_METALLIC)->value;
|
||||||
|
style.gloss = style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_GLOSS)->value;
|
||||||
|
style.glow = colour_prop->a != 0.0f;
|
||||||
|
|
||||||
|
style.patternId = style_prop->at<Gvas::Types::IntProperty>(MASS_STYLE_PATTERN_ID)->value;
|
||||||
|
style.opacity = style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_OPACITY)->value;
|
||||||
|
style.offset = Vector2{
|
||||||
|
style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_OFFSETX)->value,
|
||||||
|
style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_OFFSETY)->value
|
||||||
|
};
|
||||||
|
style.rotation = style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_ROTATION)->value;
|
||||||
|
style.scale = style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_SCALE)->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeCustomStyle(const CustomStyle& style, std::size_t index, Gvas::Types::ArrayProperty* style_array) {
|
||||||
|
if(!style_array) {
|
||||||
|
_lastError = "style_array is null."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto style_prop = style_array->at<Gvas::Types::GenericStructProperty>(index);
|
||||||
|
if(!style_prop) {
|
||||||
|
_lastError = "Style index is out of range in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
style_prop->at<Gvas::Types::StringProperty>(MASS_STYLE_NAME)->value = style.name;
|
||||||
|
auto colour_prop = style_prop->at<Gvas::Types::ColourStructProperty>(MASS_STYLE_COLOUR);
|
||||||
|
colour_prop->r = style.colour.r();
|
||||||
|
colour_prop->g = style.colour.g();
|
||||||
|
colour_prop->b = style.colour.b();
|
||||||
|
colour_prop->a = style.glow ? 1.0f : 0.0f;
|
||||||
|
style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_METALLIC)->value = style.metallic;
|
||||||
|
style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_GLOSS)->value = style.gloss;
|
||||||
|
|
||||||
|
style_prop->at<Gvas::Types::IntProperty>(MASS_STYLE_PATTERN_ID)->value = style.patternId;
|
||||||
|
style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_OPACITY)->value = style.opacity;
|
||||||
|
style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_OFFSETX)->value = style.offset.x();
|
||||||
|
style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_OFFSETY)->value = style.offset.y();
|
||||||
|
style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_ROTATION)->value = style.rotation;
|
||||||
|
style_prop->at<Gvas::Types::FloatProperty>(MASS_STYLE_PATTERN_SCALE)->value = style.scale;
|
||||||
|
|
||||||
|
if(!_mass->saveToFile()) {
|
||||||
|
_lastError = _mass->lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
388
src/GameObjects/Mass_Weapons.cpp
Normal file
388
src/GameObjects/Mass_Weapons.cpp
Normal file
|
@ -0,0 +1,388 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
#include "../Gvas/Types/ArrayProperty.h"
|
||||||
|
#include "../Gvas/Types/BoolProperty.h"
|
||||||
|
#include "../Gvas/Types/ByteProperty.h"
|
||||||
|
#include "../Gvas/Types/ColourStructProperty.h"
|
||||||
|
#include "../Gvas/Types/GenericStructProperty.h"
|
||||||
|
#include "../Gvas/Types/IntProperty.h"
|
||||||
|
#include "../Gvas/Types/StringProperty.h"
|
||||||
|
|
||||||
|
#include "Mass.h"
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
|
Containers::ArrayView<Weapon>
|
||||||
|
Mass::meleeWeapons() {
|
||||||
|
return _weapons.melee;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getMeleeWeapons() {
|
||||||
|
LOG_INFO("Getting melee weapons.");
|
||||||
|
getWeaponType(MASS_WEAPONS_MELEE, _weapons.melee);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeMeleeWeapons() {
|
||||||
|
LOG_INFO("Writing melee weapons.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_MELEE, _weapons.melee);
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<Weapon>
|
||||||
|
Mass::shields() {
|
||||||
|
return _weapons.shields;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getShields() {
|
||||||
|
LOG_INFO("Getting shields.");
|
||||||
|
getWeaponType(MASS_WEAPONS_SHIELD, _weapons.shields);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeShields() {
|
||||||
|
LOG_INFO("Writing shields.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_SHIELD, _weapons.shields);
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<Weapon>
|
||||||
|
Mass::bulletShooters() {
|
||||||
|
return _weapons.bulletShooters;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getBulletShooters() {
|
||||||
|
LOG_INFO("Getting bullet shooters.");
|
||||||
|
getWeaponType(MASS_WEAPONS_BSHOOTER, _weapons.bulletShooters);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeBulletShooters() {
|
||||||
|
LOG_INFO("Writing bullet shooters.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_BSHOOTER, _weapons.bulletShooters);
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<Weapon>
|
||||||
|
Mass::energyShooters() {
|
||||||
|
return _weapons.energyShooters;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getEnergyShooters() {
|
||||||
|
LOG_INFO("Getting energy shooters.");
|
||||||
|
getWeaponType(MASS_WEAPONS_ESHOOTER, _weapons.energyShooters);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeEnergyShooters() {
|
||||||
|
LOG_INFO("Writing energy shooters.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_ESHOOTER, _weapons.energyShooters);
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<Weapon>
|
||||||
|
Mass::bulletLaunchers() {
|
||||||
|
return _weapons.bulletLaunchers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getBulletLaunchers() {
|
||||||
|
LOG_INFO("Getting bullet launchers.");
|
||||||
|
getWeaponType(MASS_WEAPONS_BLAUNCHER, _weapons.bulletLaunchers);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeBulletLaunchers() {
|
||||||
|
LOG_INFO("Writing bullet launchers.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_BLAUNCHER, _weapons.bulletLaunchers);
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<Weapon>
|
||||||
|
Mass::energyLaunchers() {
|
||||||
|
return _weapons.energyLaunchers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getEnergyLaunchers() {
|
||||||
|
LOG_INFO("Getting energy launchers.");
|
||||||
|
getWeaponType(MASS_WEAPONS_ELAUNCHER, _weapons.energyLaunchers);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeEnergyLaunchers() {
|
||||||
|
LOG_INFO("Writing energy launchers.");
|
||||||
|
return writeWeaponType(MASS_WEAPONS_ELAUNCHER, _weapons.energyLaunchers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) {
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto prop = unit_data->at<Gvas::Types::ArrayProperty>(prop_name);
|
||||||
|
if(!prop) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't find {} in {}.", prop_name, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::uint32_t i = 0; i < weapon_array.size(); i++) {
|
||||||
|
auto weapon_prop = prop->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
auto& weapon = weapon_array[i];
|
||||||
|
|
||||||
|
weapon.name = weapon_prop->at<Gvas::Types::StringProperty>(MASS_WEAPON_NAME)->value;
|
||||||
|
auto& weapon_type = weapon_prop->at<Gvas::Types::ByteProperty>(MASS_WEAPON_TYPE)->enumValue;
|
||||||
|
#define c(enumerator, strenum, name) if(weapon_type == (strenum)) { weapon.type = Weapon::Type::enumerator; } else
|
||||||
|
#include "../Maps/WeaponTypes.hpp"
|
||||||
|
#undef c
|
||||||
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid weapon type {} in {}.", weapon_type, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parts_prop = weapon_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_ELEMENT);
|
||||||
|
weapon.parts = Containers::Array<WeaponPart>{ValueInit, parts_prop->items.size()};
|
||||||
|
|
||||||
|
for(std::uint32_t j = 0; j < parts_prop->items.size(); j++) {
|
||||||
|
auto part_prop = parts_prop->at<Gvas::Types::GenericStructProperty>(j);
|
||||||
|
auto& part = weapon.parts[j];
|
||||||
|
|
||||||
|
part.id = part_prop->at<Gvas::Types::IntProperty>(MASS_WEAPON_PART_ID)->value;
|
||||||
|
|
||||||
|
auto part_styles = part_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_PART_STYLES);
|
||||||
|
for(std::uint32_t k = 0; k < part_styles->items.size(); k++) {
|
||||||
|
part.styles[k] = part_styles->at<Gvas::Types::IntProperty>(k)->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto part_decals = part_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_PART_DECALS);
|
||||||
|
if(part_decals->items.size() != part.decals.size()) {
|
||||||
|
part.decals = Containers::Array<Decal>{part_decals->items.size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
getDecals(part.decals, part_decals);
|
||||||
|
|
||||||
|
auto part_accs = part_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_PART_ACCESSORIES);
|
||||||
|
if(!part_accs) {
|
||||||
|
part.accessories = Containers::Array<Accessory>{0};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(part_accs->items.size() != part.accessories.size()) {
|
||||||
|
part.accessories = Containers::Array<Accessory>{part_accs->items.size()};
|
||||||
|
}
|
||||||
|
getAccessories(part.accessories, part_accs);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto custom_styles = weapon_prop->at<Gvas::Types::ArrayProperty>(MASS_CUSTOM_WEAPON_STYLES);
|
||||||
|
if(!custom_styles) {
|
||||||
|
LOG_ERROR_FORMAT("Can't find weapon custom styles in {}", _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getCustomStyles(weapon.customStyles, custom_styles);
|
||||||
|
|
||||||
|
for(auto& style : weapon.customStyles) {
|
||||||
|
style.type = CustomStyle::Type::Weapon;
|
||||||
|
}
|
||||||
|
|
||||||
|
weapon.attached = weapon_prop->at<Gvas::Types::BoolProperty>(MASS_WEAPON_ATTACH)->value;
|
||||||
|
auto& damage_type = weapon_prop->at<Gvas::Types::ByteProperty>(MASS_WEAPON_DAMAGE_TYPE)->enumValue;
|
||||||
|
#define c(enumerator, strenum) if(damage_type == (strenum)) { weapon.damageType = Weapon::DamageType::enumerator; } else
|
||||||
|
#include "../Maps/DamageTypes.hpp"
|
||||||
|
#undef c
|
||||||
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid damage type {} in {}.", damage_type, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
weapon.dualWield = weapon_prop->at<Gvas::Types::BoolProperty>(MASS_WEAPON_DUAL_WIELD)->value;
|
||||||
|
auto& effect_colour_mode = weapon_prop->at<Gvas::Types::ByteProperty>(MASS_WEAPON_COLOUR_EFX_MODE)->enumValue;
|
||||||
|
#define c(enumerator, strenum) if(effect_colour_mode == (strenum)) { weapon.effectColourMode = Weapon::EffectColourMode::enumerator; } else
|
||||||
|
#include "../Maps/EffectColourModes.hpp"
|
||||||
|
#undef c
|
||||||
|
{
|
||||||
|
LOG_ERROR_FORMAT("Invalid effect colour mode {} in {}.", effect_colour_mode, _filename);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto effect_colour = weapon_prop->at<Gvas::Types::ColourStructProperty>(MASS_WEAPON_COLOUR_EFX);
|
||||||
|
weapon.effectColour = Color4{effect_colour->r, effect_colour->g, effect_colour->b, effect_colour->a};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) {
|
||||||
|
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||||
|
if(!unit_data) {
|
||||||
|
_lastError = "No unit data in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto prop = unit_data->at<Gvas::Types::ArrayProperty>(prop_name);
|
||||||
|
if(!prop) {
|
||||||
|
_lastError = prop_name + " not found in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::uint32_t i = 0; i < weapon_array.size(); i++) {
|
||||||
|
auto weapon_prop = prop->at<Gvas::Types::GenericStructProperty>(i);
|
||||||
|
auto& weapon = weapon_array[i];
|
||||||
|
|
||||||
|
weapon_prop->at<Gvas::Types::StringProperty>(MASS_WEAPON_NAME)->value = weapon.name;
|
||||||
|
switch(weapon.type) {
|
||||||
|
#define c(enumerator, strenum, name) case Weapon::Type::enumerator: weapon_prop->at<Gvas::Types::ByteProperty>(MASS_WEAPON_TYPE)->enumValue = strenum; break;
|
||||||
|
#include "../Maps/WeaponTypes.hpp"
|
||||||
|
#undef c
|
||||||
|
default:
|
||||||
|
_lastError = Utility::format("Invalid weapon type at index {}.", i);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto parts_prop = weapon_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_ELEMENT);
|
||||||
|
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;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::uint32_t j = 0; j < parts_prop->items.size(); j++) {
|
||||||
|
auto part_prop = parts_prop->at<Gvas::Types::GenericStructProperty>(j);
|
||||||
|
auto& part = weapon.parts[j];
|
||||||
|
|
||||||
|
part_prop->at<Gvas::Types::IntProperty>(MASS_WEAPON_PART_ID)->value = part.id;
|
||||||
|
|
||||||
|
auto part_styles = part_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_PART_STYLES);
|
||||||
|
for(std::uint32_t k = 0; k < part_styles->items.size(); k++) {
|
||||||
|
part_styles->at<Gvas::Types::IntProperty>(k)->value = part.styles[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto part_decals = part_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_PART_DECALS);
|
||||||
|
writeDecals(part.decals, part_decals);
|
||||||
|
|
||||||
|
auto part_accs = part_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_PART_ACCESSORIES);
|
||||||
|
if(!part_accs) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeAccessories(part.accessories, part_accs);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto custom_styles = weapon_prop->at<Gvas::Types::ArrayProperty>(MASS_CUSTOM_WEAPON_STYLES);
|
||||||
|
if(!custom_styles) {
|
||||||
|
_lastError = "No custom styles found for weapon."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_state = State::Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::uint32_t j = 0; j < weapon.customStyles.size(); j++) {
|
||||||
|
writeCustomStyle(weapon.customStyles[j], j, custom_styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
weapon_prop->at<Gvas::Types::BoolProperty>(MASS_WEAPON_ATTACH)->value = weapon.attached;
|
||||||
|
switch(weapon.damageType) {
|
||||||
|
#define c(enumerator, strenum) case Weapon::DamageType::enumerator: weapon_prop->at<Gvas::Types::ByteProperty>(MASS_WEAPON_DAMAGE_TYPE)->enumValue = strenum; break;
|
||||||
|
#include "../Maps/DamageTypes.hpp"
|
||||||
|
#undef c
|
||||||
|
default:
|
||||||
|
_lastError = Utility::format("Invalid damage type at index {}.", i);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
weapon_prop->at<Gvas::Types::BoolProperty>(MASS_WEAPON_DUAL_WIELD)->value = weapon.dualWield;
|
||||||
|
switch(weapon.effectColourMode) {
|
||||||
|
#define c(enumerator, enumstr) case Weapon::EffectColourMode::enumerator: \
|
||||||
|
weapon_prop->at<Gvas::Types::ByteProperty>(MASS_WEAPON_COLOUR_EFX_MODE)->enumValue = enumstr; \
|
||||||
|
break;
|
||||||
|
#include "../Maps/EffectColourModes.hpp"
|
||||||
|
#undef c
|
||||||
|
default:
|
||||||
|
_lastError = Utility::format("Invalid damage type at index {}.", i);
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto effect_colour = weapon_prop->at<Gvas::Types::ColourStructProperty>(MASS_WEAPON_COLOUR_EFX);
|
||||||
|
effect_colour->r = weapon.effectColour.r();
|
||||||
|
effect_colour->g = weapon.effectColour.g();
|
||||||
|
effect_colour->b = weapon.effectColour.b();
|
||||||
|
effect_colour->a = weapon.effectColour.a();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_mass->saveToFile()) {
|
||||||
|
_lastError = _mass->lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
325
src/GameObjects/Profile.cpp
Normal file
325
src/GameObjects/Profile.cpp
Normal file
|
@ -0,0 +1,325 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/Pair.h>
|
||||||
|
#include <Corrade/Utility/Path.h>
|
||||||
|
|
||||||
|
#include "PropertyNames.h"
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
#include "../Gvas/Types/ArrayProperty.h"
|
||||||
|
#include "../Gvas/Types/ResourceItemValue.h"
|
||||||
|
#include "../Gvas/Types/IntProperty.h"
|
||||||
|
#include "../Gvas/Types/StringProperty.h"
|
||||||
|
|
||||||
|
#include "Profile.h"
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
|
Profile::Profile(Containers::StringView path):
|
||||||
|
_profile(path)
|
||||||
|
{
|
||||||
|
LOG_INFO_FORMAT("Reading profile at {}.", path);
|
||||||
|
|
||||||
|
if(!_profile.valid()) {
|
||||||
|
_lastError = _profile.lastError();
|
||||||
|
_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_filename = Utility::Path::split(path).second();
|
||||||
|
|
||||||
|
if(_filename.hasPrefix("Demo"_s)) {
|
||||||
|
_type = Type::Demo;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_type = Type::FullGame;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto account_prop = _profile.at<Gvas::Types::StringProperty>(PROFILE_ACCOUNT);
|
||||||
|
if(!account_prop) {
|
||||||
|
_lastError = "Couldn't find an account ID in "_s + _filename;
|
||||||
|
_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_account = account_prop->value;
|
||||||
|
|
||||||
|
refreshValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::valid() const {
|
||||||
|
return _valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::StringView
|
||||||
|
Profile::lastError() const {
|
||||||
|
return _lastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::StringView
|
||||||
|
Profile::filename() const {
|
||||||
|
return _filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
Profile::Type
|
||||||
|
Profile::type() const {
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::isDemo() const {
|
||||||
|
return _type == Type::Demo;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::StringView
|
||||||
|
Profile::account() const {
|
||||||
|
return _account;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Profile::refreshValues() {
|
||||||
|
if(!_profile.reloadData()) {
|
||||||
|
LOG_ERROR(_profile.lastError());
|
||||||
|
_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Gvas::Types::StringProperty>(PROFILE_NAME);
|
||||||
|
if(!name_prop) {
|
||||||
|
_lastError = "No company name in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_valid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_name = name_prop->value;
|
||||||
|
|
||||||
|
LOG_INFO("Getting the active frame slot.");
|
||||||
|
auto prop = _profile.at<Gvas::Types::IntProperty>(PROFILE_ACTIVE_FRAME_SLOT);
|
||||||
|
_activeFrameSlot = prop ? prop->value : 0;
|
||||||
|
|
||||||
|
LOG_INFO("Getting the credits.");
|
||||||
|
prop = _profile.at<Gvas::Types::IntProperty>(PROFILE_CREDITS);
|
||||||
|
_credits = prop ? prop->value : 0;
|
||||||
|
|
||||||
|
LOG_INFO("Getting the story progress.");
|
||||||
|
prop = _profile.at<Gvas::Types::IntProperty>(PROFILE_STORY_PROGRESS);
|
||||||
|
_storyProgress = prop ? prop->value : 0;
|
||||||
|
|
||||||
|
LOG_INFO("Getting the last mission ID.");
|
||||||
|
prop = _profile.at<Gvas::Types::IntProperty>(PROFILE_LAST_MISSION_ID);
|
||||||
|
_lastMissionId = prop ? prop->value : 0;
|
||||||
|
|
||||||
|
LOG_INFO("Getting the materials.");
|
||||||
|
_materials[GameData::MaterialID::VerseSteel] = getResource(PROFILE_MATERIAL, GameData::MaterialID::VerseSteel);
|
||||||
|
_materials[GameData::MaterialID::Undinium] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Undinium);
|
||||||
|
_materials[GameData::MaterialID::NecriumAlloy] = getResource(PROFILE_MATERIAL, GameData::MaterialID::NecriumAlloy);
|
||||||
|
_materials[GameData::MaterialID::Lunarite] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Lunarite);
|
||||||
|
_materials[GameData::MaterialID::Asterite] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Asterite);
|
||||||
|
_materials[GameData::MaterialID::HalliteFragma] = getResource(PROFILE_MATERIAL, GameData::MaterialID::HalliteFragma);
|
||||||
|
_materials[GameData::MaterialID::Unnoctinium] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Unnoctinium);
|
||||||
|
|
||||||
|
_materials[GameData::MaterialID::Ednil] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Ednil);
|
||||||
|
_materials[GameData::MaterialID::Nuflalt] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Nuflalt);
|
||||||
|
_materials[GameData::MaterialID::Aurelene] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Aurelene);
|
||||||
|
_materials[GameData::MaterialID::Soldus] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Soldus);
|
||||||
|
_materials[GameData::MaterialID::SynthesisedN] = getResource(PROFILE_MATERIAL, GameData::MaterialID::SynthesisedN);
|
||||||
|
_materials[GameData::MaterialID::Nanoc] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Nanoc);
|
||||||
|
_materials[GameData::MaterialID::Abyssillite] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Abyssillite);
|
||||||
|
|
||||||
|
_materials[GameData::MaterialID::Alcarbonite] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Alcarbonite);
|
||||||
|
_materials[GameData::MaterialID::Keriphene] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Keriphene);
|
||||||
|
_materials[GameData::MaterialID::NitinolCM] = getResource(PROFILE_MATERIAL, GameData::MaterialID::NitinolCM);
|
||||||
|
_materials[GameData::MaterialID::Quarkium] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Quarkium);
|
||||||
|
_materials[GameData::MaterialID::Alterene] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Alterene);
|
||||||
|
_materials[GameData::MaterialID::Cosmium] = getResource(PROFILE_MATERIAL, GameData::MaterialID::Cosmium);
|
||||||
|
_materials[GameData::MaterialID::PurifiedQuarkium] = getResource(PROFILE_MATERIAL, GameData::MaterialID::PurifiedQuarkium);
|
||||||
|
|
||||||
|
_materials[GameData::MaterialID::MixedComposition] = getResource(PROFILE_QUARK_DATA, GameData::MaterialID::MixedComposition);
|
||||||
|
_materials[GameData::MaterialID::VoidResidue] = getResource(PROFILE_QUARK_DATA, GameData::MaterialID::VoidResidue);
|
||||||
|
_materials[GameData::MaterialID::MuscularConstruction] = getResource(PROFILE_QUARK_DATA, GameData::MaterialID::MuscularConstruction);
|
||||||
|
_materials[GameData::MaterialID::MineralExoskeletology] = getResource(PROFILE_QUARK_DATA, GameData::MaterialID::MineralExoskeletology);
|
||||||
|
_materials[GameData::MaterialID::CarbonisedSkin] = getResource(PROFILE_QUARK_DATA, GameData::MaterialID::CarbonisedSkin);
|
||||||
|
_materials[GameData::MaterialID::IsolatedVoidParticle] = getResource(PROFILE_QUARK_DATA, GameData::MaterialID::IsolatedVoidParticle);
|
||||||
|
_materials[GameData::MaterialID::WeaponisedPhysiology] = getResource(PROFILE_QUARK_DATA, GameData::MaterialID::WeaponisedPhysiology);
|
||||||
|
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::StringView
|
||||||
|
Profile::companyName() const {
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::renameCompany(Containers::StringView new_name) {
|
||||||
|
auto name_prop = _profile.at<Gvas::Types::StringProperty>(PROFILE_NAME);
|
||||||
|
if(!name_prop) {
|
||||||
|
_lastError = "No company name in "_s + _filename;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
_valid = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
name_prop->value = new_name;
|
||||||
|
|
||||||
|
if(!_profile.saveToFile()) {
|
||||||
|
_lastError = _profile.lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
Profile::activeFrameSlot() const {
|
||||||
|
return _activeFrameSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
Profile::credits() const {
|
||||||
|
return _credits;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::setCredits(std::int32_t amount) {
|
||||||
|
auto credits_prop = _profile.at<Gvas::Types::IntProperty>(PROFILE_CREDITS);
|
||||||
|
|
||||||
|
if(!credits_prop) {
|
||||||
|
credits_prop = new Gvas::Types::IntProperty;
|
||||||
|
credits_prop->name.emplace("Credit"_s);
|
||||||
|
credits_prop->valueLength = sizeof(std::int32_t);
|
||||||
|
_profile.appendProperty(Gvas::Types::IntProperty::ptr{credits_prop});
|
||||||
|
}
|
||||||
|
|
||||||
|
credits_prop->value = amount;
|
||||||
|
|
||||||
|
if(!_profile.saveToFile()) {
|
||||||
|
_lastError = _profile.lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
Profile::storyProgress() const {
|
||||||
|
return _storyProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::setStoryProgress(std::int32_t progress) {
|
||||||
|
auto story_progress_prop = _profile.at<Gvas::Types::IntProperty>("StoryProgress"_s);
|
||||||
|
|
||||||
|
if(!story_progress_prop) {
|
||||||
|
story_progress_prop = new Gvas::Types::IntProperty;
|
||||||
|
story_progress_prop->name.emplace("StoryProgress"_s);
|
||||||
|
story_progress_prop->valueLength = sizeof(std::int32_t);
|
||||||
|
_profile.appendProperty(Gvas::Types::IntProperty::ptr{story_progress_prop});
|
||||||
|
}
|
||||||
|
|
||||||
|
story_progress_prop->value = progress;
|
||||||
|
|
||||||
|
if(!_profile.saveToFile()) {
|
||||||
|
_lastError = _profile.lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
Profile::lastMissionId() const {
|
||||||
|
return _lastMissionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
Profile::material(GameData::MaterialID id) const {
|
||||||
|
return _materials.at(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Profile::setMaterial(GameData::MaterialID id, std::int32_t amount) {
|
||||||
|
Containers::StringView container = id >= GameData::MaterialID::MixedComposition ? PROFILE_QUARK_DATA : PROFILE_MATERIAL;
|
||||||
|
auto mats_prop = _profile.at<Gvas::Types::ArrayProperty>(container);
|
||||||
|
|
||||||
|
if(!mats_prop) {
|
||||||
|
mats_prop = new Gvas::Types::ArrayProperty;
|
||||||
|
mats_prop->name.emplace(container);
|
||||||
|
mats_prop->itemType = "StructProperty";
|
||||||
|
_profile.appendProperty(Gvas::Types::ArrayProperty::ptr{mats_prop});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto predicate = [&id](Gvas::Types::UnrealPropertyBase::ptr& prop){
|
||||||
|
auto res_prop = dynamic_cast<Gvas::Types::ResourceItemValue*>(prop.get());
|
||||||
|
return res_prop->id == id;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = std::find_if(mats_prop->items.begin(), mats_prop->items.end(), predicate);
|
||||||
|
|
||||||
|
Gvas::Types::ResourceItemValue* res_prop;
|
||||||
|
if(it == mats_prop->items.end()) {
|
||||||
|
res_prop = new Gvas::Types::ResourceItemValue;
|
||||||
|
if(mats_prop->items.isEmpty()) {
|
||||||
|
res_prop->name.emplace(container);
|
||||||
|
}
|
||||||
|
res_prop->id = id;
|
||||||
|
Gvas::Types::ResourceItemValue::ptr prop{res_prop};
|
||||||
|
arrayAppend(mats_prop->items, Utility::move(prop));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res_prop = dynamic_cast<Gvas::Types::ResourceItemValue*>(it->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
res_prop->quantity = amount;
|
||||||
|
|
||||||
|
if(!_profile.saveToFile()) {
|
||||||
|
_lastError = _profile.lastError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int32_t
|
||||||
|
Profile::getResource(Containers::StringView container, GameData::MaterialID id) {
|
||||||
|
auto mats_prop = _profile.at<Gvas::Types::ArrayProperty>(container);
|
||||||
|
|
||||||
|
if(!mats_prop) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto predicate = [&id](Gvas::Types::UnrealPropertyBase::ptr& prop){
|
||||||
|
auto res_prop = dynamic_cast<Gvas::Types::ResourceItemValue*>(prop.get());
|
||||||
|
return res_prop->id == id;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = std::find_if(mats_prop->items.begin(), mats_prop->items.end(), predicate);
|
||||||
|
return it != mats_prop->items.end() ? dynamic_cast<Gvas::Types::ResourceItemValue*>(it->get())->quantity : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
92
src/GameObjects/Profile.h
Normal file
92
src/GameObjects/Profile.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <Corrade/Containers/String.h>
|
||||||
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
|
#include "../GameData/ResourceIDs.h"
|
||||||
|
#include "../Gvas/File.h"
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
|
class Profile {
|
||||||
|
public:
|
||||||
|
explicit Profile(Containers::StringView path);
|
||||||
|
|
||||||
|
bool valid() const;
|
||||||
|
|
||||||
|
auto lastError() const -> Containers::StringView;
|
||||||
|
|
||||||
|
auto filename() const -> Containers::StringView;
|
||||||
|
|
||||||
|
enum class Type: std::uint8_t {
|
||||||
|
Demo,
|
||||||
|
FullGame
|
||||||
|
};
|
||||||
|
|
||||||
|
auto type() const -> Type;
|
||||||
|
bool isDemo() const;
|
||||||
|
|
||||||
|
auto account() const -> Containers::StringView;
|
||||||
|
|
||||||
|
void refreshValues();
|
||||||
|
|
||||||
|
auto companyName() const -> Containers::StringView;
|
||||||
|
bool renameCompany(Containers::StringView new_name);
|
||||||
|
|
||||||
|
auto activeFrameSlot() const -> std::int32_t;
|
||||||
|
|
||||||
|
auto credits() const -> std::int32_t;
|
||||||
|
bool setCredits(std::int32_t credits);
|
||||||
|
|
||||||
|
auto storyProgress() const -> std::int32_t;
|
||||||
|
bool setStoryProgress(std::int32_t progress);
|
||||||
|
|
||||||
|
auto lastMissionId() const -> std::int32_t;
|
||||||
|
|
||||||
|
auto material(GameData::MaterialID id) const -> std::int32_t;
|
||||||
|
bool setMaterial(GameData::MaterialID id, std::int32_t amount);
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto getResource(Containers::StringView container, GameData::MaterialID id) -> std::int32_t;
|
||||||
|
|
||||||
|
Containers::String _filename;
|
||||||
|
|
||||||
|
Type _type;
|
||||||
|
|
||||||
|
Gvas::File _profile;
|
||||||
|
|
||||||
|
Containers::String _name;
|
||||||
|
std::int32_t _activeFrameSlot = 0;
|
||||||
|
std::int32_t _credits = 0;
|
||||||
|
std::int32_t _storyProgress = 0;
|
||||||
|
std::int32_t _lastMissionId = 0;
|
||||||
|
|
||||||
|
std::map<GameData::MaterialID, std::int32_t> _materials;
|
||||||
|
|
||||||
|
Containers::String _account;
|
||||||
|
|
||||||
|
bool _valid = false;
|
||||||
|
Containers::String _lastError;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
131
src/GameObjects/PropertyNames.h
Normal file
131
src/GameObjects/PropertyNames.h
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Profile stuff
|
||||||
|
#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"
|
||||||
|
|
||||||
|
// Basic MASS stuff
|
||||||
|
#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"
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,11 +16,13 @@
|
||||||
|
|
||||||
#include "Weapon.h"
|
#include "Weapon.h"
|
||||||
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
Weapon::Weapon(const Weapon& other) {
|
Weapon::Weapon(const Weapon& other) {
|
||||||
name = other.name;
|
name = other.name;
|
||||||
type = other.type;
|
type = other.type;
|
||||||
parts = Containers::Array<WeaponPart>{other.parts.size()};
|
parts = Containers::Array<WeaponPart>{other.parts.size()};
|
||||||
for(UnsignedInt i = 0; i < parts.size(); i++) {
|
for(std::uint32_t i = 0; i < parts.size(); i++) {
|
||||||
parts[i] = other.parts[i];
|
parts[i] = other.parts[i];
|
||||||
}
|
}
|
||||||
customStyles = other.customStyles;
|
customStyles = other.customStyles;
|
||||||
|
@ -31,11 +33,12 @@ Weapon::Weapon(const Weapon& other) {
|
||||||
effectColour = other.effectColour;
|
effectColour = other.effectColour;
|
||||||
}
|
}
|
||||||
|
|
||||||
Weapon& Weapon::operator=(const Weapon& other) {
|
Weapon&
|
||||||
|
Weapon::operator=(const Weapon& other) {
|
||||||
name = other.name;
|
name = other.name;
|
||||||
type = other.type;
|
type = other.type;
|
||||||
parts = Containers::Array<WeaponPart>{other.parts.size()};
|
parts = Containers::Array<WeaponPart>{other.parts.size()};
|
||||||
for(UnsignedInt i = 0; i < parts.size(); i++) {
|
for(std::uint32_t i = 0; i < parts.size(); i++) {
|
||||||
parts[i] = other.parts[i];
|
parts[i] = other.parts[i];
|
||||||
}
|
}
|
||||||
customStyles = other.customStyles;
|
customStyles = other.customStyles;
|
||||||
|
@ -47,3 +50,5 @@ Weapon& Weapon::operator=(const Weapon& other) {
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -29,19 +29,7 @@
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
using namespace Magnum;
|
||||||
|
|
||||||
#define c(enumerator, ...) enumerator,
|
namespace mbst::GameObjects {
|
||||||
enum class WeaponType {
|
|
||||||
#include "../Maps/WeaponTypes.hpp"
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class DamageType {
|
|
||||||
#include "../Maps/DamageTypes.hpp"
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class EffectColourMode {
|
|
||||||
#include "../Maps/EffectColourModes.hpp"
|
|
||||||
};
|
|
||||||
#undef c
|
|
||||||
|
|
||||||
struct Weapon {
|
struct Weapon {
|
||||||
Weapon() = default;
|
Weapon() = default;
|
||||||
|
@ -52,8 +40,20 @@ struct Weapon {
|
||||||
Weapon(Weapon&& other) = default;
|
Weapon(Weapon&& other) = default;
|
||||||
Weapon& operator=(Weapon&& other) = default;
|
Weapon& operator=(Weapon&& other) = default;
|
||||||
|
|
||||||
|
#define c(enumerator, ...) enumerator,
|
||||||
|
enum class Type {
|
||||||
|
#include "../Maps/WeaponTypes.hpp"
|
||||||
|
};
|
||||||
|
enum class DamageType {
|
||||||
|
#include "../Maps/DamageTypes.hpp"
|
||||||
|
};
|
||||||
|
enum class EffectColourMode {
|
||||||
|
#include "../Maps/EffectColourModes.hpp"
|
||||||
|
};
|
||||||
|
#undef c
|
||||||
|
|
||||||
Containers::String name;
|
Containers::String name;
|
||||||
WeaponType type = WeaponType::Melee;
|
Type type = Type::Melee;
|
||||||
Containers::Array<WeaponPart> parts;
|
Containers::Array<WeaponPart> parts;
|
||||||
Containers::StaticArray<16, CustomStyle> customStyles{ValueInit};
|
Containers::StaticArray<16, CustomStyle> customStyles{ValueInit};
|
||||||
bool attached = false;
|
bool attached = false;
|
||||||
|
@ -62,3 +62,5 @@ struct Weapon {
|
||||||
EffectColourMode effectColourMode = EffectColourMode::Default;
|
EffectColourMode effectColourMode = EffectColourMode::Default;
|
||||||
Color4 effectColour{0.0f};
|
Color4 effectColour{0.0f};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,13 +19,12 @@
|
||||||
#include <Corrade/Containers/Array.h>
|
#include <Corrade/Containers/Array.h>
|
||||||
#include <Corrade/Containers/StaticArray.h>
|
#include <Corrade/Containers/StaticArray.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
|
||||||
|
|
||||||
#include "Decal.h"
|
#include "Decal.h"
|
||||||
#include "Accessory.h"
|
#include "Accessory.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
|
||||||
|
namespace mbst::GameObjects {
|
||||||
|
|
||||||
struct WeaponPart {
|
struct WeaponPart {
|
||||||
WeaponPart() = default;
|
WeaponPart() = default;
|
||||||
|
@ -34,11 +33,11 @@ struct WeaponPart {
|
||||||
id = other.id;
|
id = other.id;
|
||||||
styles = other.styles;
|
styles = other.styles;
|
||||||
decals = Containers::Array<Decal>{other.decals.size()};
|
decals = Containers::Array<Decal>{other.decals.size()};
|
||||||
for(UnsignedInt i = 0; i < decals.size(); i++) {
|
for(auto i = 0u; i < decals.size(); i++) {
|
||||||
decals[i] = other.decals[i];
|
decals[i] = other.decals[i];
|
||||||
}
|
}
|
||||||
accessories = Containers::Array<Accessory>{other.accessories.size()};
|
accessories = Containers::Array<Accessory>{other.accessories.size()};
|
||||||
for(UnsignedInt i = 0; i < accessories.size(); i++) {
|
for(auto i = 0u; i < accessories.size(); i++) {
|
||||||
accessories[i] = other.accessories[i];
|
accessories[i] = other.accessories[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,11 +45,11 @@ struct WeaponPart {
|
||||||
id = other.id;
|
id = other.id;
|
||||||
styles = other.styles;
|
styles = other.styles;
|
||||||
decals = Containers::Array<Decal>{other.decals.size()};
|
decals = Containers::Array<Decal>{other.decals.size()};
|
||||||
for(UnsignedInt i = 0; i < decals.size(); i++) {
|
for(auto i = 0u; i < decals.size(); i++) {
|
||||||
decals[i] = other.decals[i];
|
decals[i] = other.decals[i];
|
||||||
}
|
}
|
||||||
accessories = Containers::Array<Accessory>{other.accessories.size()};
|
accessories = Containers::Array<Accessory>{other.accessories.size()};
|
||||||
for(UnsignedInt i = 0; i < accessories.size(); i++) {
|
for(auto i = 0u; i < accessories.size(); i++) {
|
||||||
accessories[i] = other.accessories[i];
|
accessories[i] = other.accessories[i];
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -59,8 +58,10 @@ struct WeaponPart {
|
||||||
WeaponPart(WeaponPart&& other) = default;
|
WeaponPart(WeaponPart&& other) = default;
|
||||||
WeaponPart& operator=(WeaponPart&& other) = default;
|
WeaponPart& operator=(WeaponPart&& other) = default;
|
||||||
|
|
||||||
Int id = 0;
|
std::int32_t id = 0;
|
||||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
Containers::StaticArray<4, std::int32_t> styles{ValueInit};
|
||||||
Containers::Array<Decal> decals{};
|
Containers::Array<Decal> decals{};
|
||||||
Containers::Array<Accessory> accessories{};
|
Containers::Array<Accessory> accessories{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -22,17 +22,20 @@
|
||||||
|
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
|
|
||||||
Utility::Debug& operator<<(Utility::Debug& debug, const ArrayProperty* prop) {
|
Utility::Debug&
|
||||||
|
operator<<(Utility::Debug& debug, const Gvas::Types::ArrayProperty* prop) {
|
||||||
return debug << (*prop->name) << Utility::Debug::nospace << ":" <<
|
return debug << (*prop->name) << Utility::Debug::nospace << ":" <<
|
||||||
prop->propertyType << "of" << prop->items.size() << prop->itemType;
|
prop->propertyType << "of" << prop->items.size() << prop->itemType;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utility::Debug& operator<<(Utility::Debug& debug, const SetProperty* prop) {
|
Utility::Debug&
|
||||||
|
operator<<(Utility::Debug& debug, const Gvas::Types::SetProperty* prop) {
|
||||||
return debug << (*prop->name) << Utility::Debug::nospace << ":" <<
|
return debug << (*prop->name) << Utility::Debug::nospace << ":" <<
|
||||||
prop->propertyType << "of" << prop->items.size() << prop->itemType;
|
prop->propertyType << "of" << prop->items.size() << prop->itemType;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utility::Debug& operator<<(Utility::Debug& debug, const GenericStructProperty* prop) {
|
Utility::Debug&
|
||||||
|
operator<<(Utility::Debug& debug, const Gvas::Types::GenericStructProperty* prop) {
|
||||||
debug << (*prop->name) << Utility::Debug::nospace << ":" <<
|
debug << (*prop->name) << Utility::Debug::nospace << ":" <<
|
||||||
prop->structType << "(" << Utility::Debug::nospace << prop->propertyType << Utility::Debug::nospace <<
|
prop->structType << "(" << Utility::Debug::nospace << prop->propertyType << Utility::Debug::nospace <<
|
||||||
") Contents:";
|
") Contents:";
|
||||||
|
@ -42,8 +45,9 @@ Utility::Debug& operator<<(Utility::Debug& debug, const GenericStructProperty* p
|
||||||
return debug;
|
return debug;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utility::Debug& operator<<(Utility::Debug& debug, const StructProperty* prop) {
|
Utility::Debug&
|
||||||
auto cast = dynamic_cast<const GenericStructProperty*>(prop);
|
operator<<(Utility::Debug& debug, const Gvas::Types::StructProperty* prop) {
|
||||||
|
auto cast = dynamic_cast<const Gvas::Types::GenericStructProperty*>(prop);
|
||||||
if(cast) {
|
if(cast) {
|
||||||
return debug << cast;
|
return debug << cast;
|
||||||
}
|
}
|
||||||
|
@ -52,21 +56,22 @@ Utility::Debug& operator<<(Utility::Debug& debug, const StructProperty* prop) {
|
||||||
prop->structType << "(" << Utility::Debug::nospace << prop->propertyType << Utility::Debug::nospace << ")";
|
prop->structType << "(" << Utility::Debug::nospace << prop->propertyType << Utility::Debug::nospace << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
Utility::Debug& operator<<(Utility::Debug& debug, const UnrealPropertyBase* prop) {
|
Utility::Debug&
|
||||||
|
operator<<(Utility::Debug& debug, const Gvas::Types::UnrealPropertyBase* prop) {
|
||||||
if(prop->propertyType == "ArrayProperty") {
|
if(prop->propertyType == "ArrayProperty") {
|
||||||
auto array_prop = dynamic_cast<const ArrayProperty*>(prop);
|
auto array_prop = dynamic_cast<const Gvas::Types::ArrayProperty*>(prop);
|
||||||
if(array_prop) {
|
if(array_prop) {
|
||||||
return debug << array_prop;
|
return debug << array_prop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(prop->propertyType == "SetProperty") {
|
else if(prop->propertyType == "SetProperty") {
|
||||||
auto set_prop = dynamic_cast<const SetProperty*>(prop);
|
auto set_prop = dynamic_cast<const Gvas::Types::SetProperty*>(prop);
|
||||||
if(set_prop) {
|
if(set_prop) {
|
||||||
return debug << set_prop;
|
return debug << set_prop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(prop->propertyType == "StructProperty") {
|
else if(prop->propertyType == "StructProperty") {
|
||||||
auto struct_prop = dynamic_cast<const StructProperty*>(prop);
|
auto struct_prop = dynamic_cast<const Gvas::Types::StructProperty*>(prop);
|
||||||
if(struct_prop) {
|
if(struct_prop) {
|
||||||
return debug << struct_prop;
|
return debug << struct_prop;
|
||||||
}
|
}
|
29
src/Gvas/Debug.h
Normal file
29
src/Gvas/Debug.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Utility/Debug.h>
|
||||||
|
|
||||||
|
#include "Types/Types.h"
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
|
||||||
|
Utility::Debug& operator<<(Utility::Debug& debug, const Gvas::Types::ArrayProperty* prop);
|
||||||
|
Utility::Debug& operator<<(Utility::Debug& debug, const Gvas::Types::SetProperty* prop);
|
||||||
|
Utility::Debug& operator<<(Utility::Debug& debug, const Gvas::Types::GenericStructProperty* prop);
|
||||||
|
Utility::Debug& operator<<(Utility::Debug& debug, const Gvas::Types::StructProperty* prop);
|
||||||
|
Utility::Debug& operator<<(Utility::Debug& debug, const Gvas::Types::UnrealPropertyBase* prop);
|
329
src/Gvas/File.cpp
Normal file
329
src/Gvas/File.cpp
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Containers/Optional.h>
|
||||||
|
#include <Corrade/Utility/Path.h>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "../BinaryIo/Reader.h"
|
||||||
|
#include "../BinaryIo/Writer.h"
|
||||||
|
|
||||||
|
#include "File.h"
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace Gvas {
|
||||||
|
|
||||||
|
File::File(Containers::String filepath):
|
||||||
|
_propSerialiser{PropertySerialiser::instance()}
|
||||||
|
{
|
||||||
|
_filepath = Utility::move(filepath);
|
||||||
|
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
File::valid() const {
|
||||||
|
return _valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::StringView
|
||||||
|
File::lastError() const {
|
||||||
|
return _lastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
File::reloadData() {
|
||||||
|
if(_noReloadAfterSave) {
|
||||||
|
_noReloadAfterSave = false;
|
||||||
|
return valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
_properties = Containers::Array<Types::UnrealPropertyBase::ptr>{};
|
||||||
|
loadData();
|
||||||
|
return valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::StringView
|
||||||
|
File::saveType() {
|
||||||
|
return _saveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
File::appendProperty(Types::UnrealPropertyBase::ptr prop) {
|
||||||
|
auto none_prop = Utility::move(_properties.back());
|
||||||
|
_properties.back() = Utility::move(prop);
|
||||||
|
arrayAppend(_properties, Utility::move(none_prop));
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::ArrayView<Types::UnrealPropertyBase::ptr>
|
||||||
|
File::props() {
|
||||||
|
return _properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
File::saveToFile() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryIo::Writer writer{_filepath + ".tmp"_s};
|
||||||
|
|
||||||
|
if(!writer.open()) {
|
||||||
|
_lastError = "Couldn't open the file for saving."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!writer.writeArray(arrayView(_magicBytes))) {
|
||||||
|
_lastError = "Couldn't write the magic bytes."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!writer.writeUint32(_saveVersion)) {
|
||||||
|
_lastError = "Couldn't write the save version."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!writer.writeUint32(_packageVersion)) {
|
||||||
|
_lastError = "Couldn't write the package version."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_saveVersion == 3) {
|
||||||
|
if(!writer.writeUint32(_unknown)) {
|
||||||
|
_lastError = "Couldn't write some unknown bytes."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!writer.writeUint16(_engineVersion.major) ||
|
||||||
|
!writer.writeUint16(_engineVersion.minor) ||
|
||||||
|
!writer.writeUint16(_engineVersion.patch) ||
|
||||||
|
!writer.writeUint32(_engineVersion.build) ||
|
||||||
|
!writer.writeUEString(_engineVersion.buildId))
|
||||||
|
{
|
||||||
|
_lastError = "Couldn't write the engine version."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!writer.writeUint32(_customFormatVersion) ||
|
||||||
|
!writer.writeUint32(_customFormatData.size()))
|
||||||
|
{
|
||||||
|
_lastError = "Couldn't write the custom format data."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& i : _customFormatData) {
|
||||||
|
if(!writer.writeStaticArray<16>(staticArrayView(i.id)) || !writer.writeUint32(i.value)) {
|
||||||
|
_lastError = "Couldn't write the custom format data."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!writer.writeUEString(_saveType)) {
|
||||||
|
_lastError = "Couldn't write the save type."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& prop : _properties) {
|
||||||
|
std::size_t bytes_written = 0;
|
||||||
|
if(!_propSerialiser->write(prop, bytes_written, writer)) {
|
||||||
|
_lastError = "Couldn't write the property "_s + *prop->name + " to the array."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!writer.flushToFile()) {
|
||||||
|
_lastError = "Couldn't write the property "_s + *prop->name + " to the file."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeUint32(0u);
|
||||||
|
|
||||||
|
writer.closeFile();
|
||||||
|
|
||||||
|
if(!Utility::Path::copy(_filepath + ".tmp"_s, _filepath)) {
|
||||||
|
_lastError = "Couldn't save the file properly.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utility::Path::remove(_filepath + ".tmp"_s);
|
||||||
|
|
||||||
|
_noReloadAfterSave = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
File::loadData() {
|
||||||
|
LOG_INFO_FORMAT("Reading data from {}.", _filepath);
|
||||||
|
|
||||||
|
_valid = false;
|
||||||
|
|
||||||
|
if(!Utility::Path::exists(_filepath)) {
|
||||||
|
_lastError = "The file couldn't be found.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BinaryIo::Reader reader{_filepath};
|
||||||
|
|
||||||
|
if(!reader.open()) {
|
||||||
|
_lastError = _filepath + " couldn't be opened."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::Array<char> magic;
|
||||||
|
if(!reader.readArray(magic, 4)) {
|
||||||
|
_lastError = "Couldn't read magic bytes in "_s + _filepath;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(std::strncmp(magic.data(), _magicBytes.data(), 4) != 0) {
|
||||||
|
_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readUint32(_saveVersion)) {
|
||||||
|
_lastError = "Couldn't read save version.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readUint32(_packageVersion)) {
|
||||||
|
_lastError = "Couldn't read package version.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_saveVersion == 3) {
|
||||||
|
if(!reader.readUint32(_unknown)) {
|
||||||
|
_lastError = "Couldn't read some unknown bytes.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readUint16(_engineVersion.major)) {
|
||||||
|
_lastError = "Couldn't read major engine version.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readUint16(_engineVersion.minor)) {
|
||||||
|
_lastError = "Couldn't read minor engine version.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readUint16(_engineVersion.patch)) {
|
||||||
|
_lastError = "Couldn't read patch engine version.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readUint32(_engineVersion.build)) {
|
||||||
|
_lastError = "Couldn't read engine build.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readUEString(_engineVersion.buildId))
|
||||||
|
{
|
||||||
|
_lastError = "Couldn't read engine build ID string.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readUint32(_customFormatVersion)) {
|
||||||
|
_lastError = "Couldn't read the custom format version.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t custom_format_data_size = 0;
|
||||||
|
|
||||||
|
if(!reader.readUint32(custom_format_data_size)) {
|
||||||
|
_lastError = "Couldn't read the custom format data size.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_customFormatData = Containers::Array<CustomFormatDataEntry>{custom_format_data_size};
|
||||||
|
|
||||||
|
for(auto& entry : _customFormatData) {
|
||||||
|
if(!reader.readStaticArray(entry.id) ||
|
||||||
|
!reader.readInt32(entry.value))
|
||||||
|
{
|
||||||
|
_lastError = "Couldn't read the custom format data";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readUEString(_saveType)) {
|
||||||
|
_lastError = "Couldn't read the save type.";
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr prop;
|
||||||
|
while((prop = _propSerialiser->read(reader)) != nullptr) {
|
||||||
|
arrayAppend(_properties, Utility::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) {
|
||||||
|
_lastError = "Couldn't find a final NoneProperty."_s;
|
||||||
|
LOG_ERROR(_lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.closeFile();
|
||||||
|
|
||||||
|
_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -17,34 +17,32 @@
|
||||||
// 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/ArrayView.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>
|
||||||
#include <Corrade/Containers/String.h>
|
#include <Corrade/Containers/String.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Magnum.h>
|
|
||||||
|
|
||||||
#include "Types/UnrealPropertyBase.h"
|
#include "Types/UnrealPropertyBase.h"
|
||||||
|
|
||||||
#include "PropertySerialiser.h"
|
#include "PropertySerialiser.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
class UESaveFile {
|
namespace Gvas {
|
||||||
|
|
||||||
|
class File {
|
||||||
public:
|
public:
|
||||||
explicit UESaveFile(Containers::String filepath);
|
explicit File(Containers::String filepath);
|
||||||
|
|
||||||
auto valid() const -> bool;
|
bool valid() const;
|
||||||
auto lastError() const -> Containers::StringView;
|
auto lastError() const -> Containers::StringView;
|
||||||
|
|
||||||
auto reloadData() -> bool;
|
bool reloadData();
|
||||||
|
|
||||||
auto saveType() -> Containers::StringView;
|
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<Types::UnrealPropertyBase, T>::value, T*>
|
||||||
at(Containers::StringView name) {
|
at(Containers::StringView name) {
|
||||||
for(auto& prop : _properties) {
|
for(auto& prop : _properties) {
|
||||||
if(prop->name == name) {
|
if(prop->name == name) {
|
||||||
|
@ -54,11 +52,11 @@ class UESaveFile {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendProperty(UnrealPropertyBase::ptr prop);
|
void appendProperty(Types::UnrealPropertyBase::ptr prop);
|
||||||
|
|
||||||
auto props() -> Containers::ArrayView<UnrealPropertyBase::ptr>;
|
auto props() -> Containers::ArrayView<Types::UnrealPropertyBase::ptr>;
|
||||||
|
|
||||||
auto saveToFile() -> bool;
|
bool saveToFile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadData();
|
void loadData();
|
||||||
|
@ -72,26 +70,29 @@ class UESaveFile {
|
||||||
|
|
||||||
Containers::StaticArray<4, char> _magicBytes{'G', 'V', 'A', 'S'};
|
Containers::StaticArray<4, char> _magicBytes{'G', 'V', 'A', 'S'};
|
||||||
|
|
||||||
UnsignedInt _saveVersion = 0;
|
std::uint32_t _saveVersion = 0;
|
||||||
UnsignedInt _packageVersion = 0;
|
std::uint32_t _packageVersion = 0;
|
||||||
|
std::uint32_t _unknown = 0;
|
||||||
struct {
|
struct {
|
||||||
UnsignedShort major = 0;
|
std::uint16_t major = 0;
|
||||||
UnsignedShort minor = 0;
|
std::uint16_t minor = 0;
|
||||||
UnsignedShort patch = 0;
|
std::uint16_t patch = 0;
|
||||||
UnsignedInt build = 0;
|
std::uint32_t build = 0;
|
||||||
Containers::String buildId;
|
Containers::String buildId;
|
||||||
} _engineVersion;
|
} _engineVersion;
|
||||||
|
|
||||||
UnsignedInt _customFormatVersion = 0;
|
std::uint32_t _customFormatVersion = 0;
|
||||||
struct CustomFormatDataEntry {
|
struct CustomFormatDataEntry {
|
||||||
Containers::StaticArray<16, char> id;
|
Containers::StaticArray<16, char> id;
|
||||||
Int value = 0;
|
std::int32_t value = 0;
|
||||||
};
|
};
|
||||||
Containers::Array<CustomFormatDataEntry> _customFormatData;
|
Containers::Array<CustomFormatDataEntry> _customFormatData;
|
||||||
|
|
||||||
Containers::String _saveType;
|
Containers::String _saveType;
|
||||||
|
|
||||||
Containers::Array<UnrealPropertyBase::ptr> _properties;
|
Containers::Array<Types::UnrealPropertyBase::ptr> _properties;
|
||||||
|
|
||||||
Containers::Reference<PropertySerialiser> _propSerialiser;
|
Containers::Reference<PropertySerialiser> _propSerialiser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
24
src/Gvas/Gvas.h
Normal file
24
src/Gvas/Gvas.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace Gvas {
|
||||||
|
|
||||||
|
class File;
|
||||||
|
class PropertySerialiser;
|
||||||
|
|
||||||
|
}
|
276
src/Gvas/PropertySerialiser.cpp
Normal file
276
src/Gvas/PropertySerialiser.cpp
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "Serialisers/ArrayProperty.h"
|
||||||
|
#include "Serialisers/BoolProperty.h"
|
||||||
|
#include "Serialisers/ByteProperty.h"
|
||||||
|
#include "Serialisers/ColourProperty.h"
|
||||||
|
#include "Serialisers/DateTimeProperty.h"
|
||||||
|
#include "Serialisers/EnumProperty.h"
|
||||||
|
#include "Serialisers/FloatProperty.h"
|
||||||
|
#include "Serialisers/GuidProperty.h"
|
||||||
|
#include "Serialisers/IntProperty.h"
|
||||||
|
#include "Serialisers/MapProperty.h"
|
||||||
|
#include "Serialisers/ResourceProperty.h"
|
||||||
|
#include "Serialisers/RotatorProperty.h"
|
||||||
|
#include "Serialisers/StringProperty.h"
|
||||||
|
#include "Serialisers/SetProperty.h"
|
||||||
|
#include "Serialisers/Struct.h"
|
||||||
|
#include "Serialisers/TextProperty.h"
|
||||||
|
#include "Serialisers/VectorProperty.h"
|
||||||
|
#include "Serialisers/Vector2DProperty.h"
|
||||||
|
|
||||||
|
#include "Types/NoneProperty.h"
|
||||||
|
|
||||||
|
#include "../BinaryIo/Reader.h"
|
||||||
|
#include "../BinaryIo/Writer.h"
|
||||||
|
|
||||||
|
#include "PropertySerialiser.h"
|
||||||
|
|
||||||
|
namespace Gvas {
|
||||||
|
|
||||||
|
PropertySerialiser::PropertySerialiser() {
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::ArrayProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::BoolProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::ByteProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::ColourProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::DateTimeProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::EnumProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::FloatProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::GuidProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::IntProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::MapProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::ResourceProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::RotatorProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::StringProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::SetProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::TextProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::VectorProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::Vector2DProperty>());
|
||||||
|
arrayAppend(_serialisers, Containers::pointer<Serialisers::Struct>());
|
||||||
|
|
||||||
|
arrayAppend(_collectionSerialisers, Containers::pointer<Serialisers::Struct>());
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertySerialiser&
|
||||||
|
PropertySerialiser::instance() {
|
||||||
|
static PropertySerialiser serialiser;
|
||||||
|
return serialiser;
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
PropertySerialiser::read(BinaryIo::Reader& reader) {
|
||||||
|
if(reader.peekChar() < 0 || reader.eof()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::String name;
|
||||||
|
if(!reader.readUEString(name)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name == "None") {
|
||||||
|
return Containers::pointer<Types::NoneProperty>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::String type;
|
||||||
|
if(!reader.readUEString(type)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t value_length;
|
||||||
|
if(!reader.readUint64(value_length)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deserialise(Utility::move(name), Utility::move(type), value_length, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
PropertySerialiser::readItem(BinaryIo::Reader& reader, Containers::String type, std::size_t value_length,
|
||||||
|
Containers::String name)
|
||||||
|
{
|
||||||
|
if(reader.peekChar() < 0 || reader.eof()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deserialise(Utility::move(name), Utility::move(type), value_length, reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::Array<Types::UnrealPropertyBase::ptr>
|
||||||
|
PropertySerialiser::readSet(BinaryIo::Reader& reader, Containers::StringView item_type, std::uint32_t count) {
|
||||||
|
if(reader.peekChar() < 0 || reader.eof()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto serialiser = getCollectionSerialiser(item_type);
|
||||||
|
|
||||||
|
Containers::Array<Types::UnrealPropertyBase::ptr> array;
|
||||||
|
|
||||||
|
if(serialiser) {
|
||||||
|
Containers::String name;
|
||||||
|
if(!reader.readUEString(name)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::String type;
|
||||||
|
if(!reader.readUEString(type)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t value_length;
|
||||||
|
if(!reader.readUint64(value_length)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
array = serialiser->deserialise(name, type, value_length, count, reader, *this);
|
||||||
|
|
||||||
|
for(auto& item : array) {
|
||||||
|
if(item->name == Containers::NullOpt) {
|
||||||
|
item->name.emplace(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(std::uint32_t i = 0; i < count; i++) {
|
||||||
|
auto item = readItem(reader, item_type, std::size_t(-1), "");
|
||||||
|
arrayAppend(array, Utility::move(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
PropertySerialiser::deserialise(Containers::String name, Containers::String type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader)
|
||||||
|
{
|
||||||
|
Types::UnrealPropertyBase::ptr prop;
|
||||||
|
auto serialiser = getSerialiser(type);
|
||||||
|
|
||||||
|
if(serialiser == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop = serialiser->deserialise(name, type, value_length, reader, *this);
|
||||||
|
|
||||||
|
if(!prop) {
|
||||||
|
LOG_ERROR("No property.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop->name = Utility::move(name);
|
||||||
|
prop->propertyType = Utility::move(type);
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertySerialiser::serialise(Types::UnrealPropertyBase::ptr& prop, Containers::StringView item_type,
|
||||||
|
std::size_t& bytes_written, BinaryIo::Writer& writer)
|
||||||
|
{
|
||||||
|
auto serialiser = getSerialiser(item_type);
|
||||||
|
if(!serialiser) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return serialiser->serialise(prop, bytes_written, writer, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PropertySerialiser::write(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer) {
|
||||||
|
if(prop->name == "None" && prop->propertyType == "NoneProperty" && dynamic_cast<Types::NoneProperty*>(prop.get())) {
|
||||||
|
bytes_written += writer.writeUEStringToArray(*prop->name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_written += writer.writeUEStringToArray(*prop->name);
|
||||||
|
bytes_written += writer.writeUEStringToArray(prop->propertyType);
|
||||||
|
|
||||||
|
std::size_t value_length = 0;
|
||||||
|
std::size_t vl_position = writer.arrayPosition();
|
||||||
|
|
||||||
|
bytes_written += writer.writeValueToArray<std::size_t>(value_length);
|
||||||
|
|
||||||
|
bool ret = serialise(prop, prop->propertyType, value_length, writer);
|
||||||
|
|
||||||
|
writer.writeValueToArrayAt(value_length, vl_position);
|
||||||
|
|
||||||
|
bytes_written += value_length;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
PropertySerialiser::writeItem(Types::UnrealPropertyBase::ptr& prop, Containers::StringView item_type,
|
||||||
|
std::size_t& bytes_written, BinaryIo::Writer& writer)
|
||||||
|
{
|
||||||
|
if(prop->name == "None" && prop->propertyType == "NoneProperty" && dynamic_cast<Types::NoneProperty*>(prop.get())) {
|
||||||
|
bytes_written += writer.writeUEStringToArray(*prop->name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return serialise(prop, item_type, bytes_written, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertySerialiser::writeSet(Containers::ArrayView<Types::UnrealPropertyBase::ptr> props,
|
||||||
|
Containers::StringView item_type, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer)
|
||||||
|
{
|
||||||
|
auto serialiser = getCollectionSerialiser(item_type);
|
||||||
|
if(serialiser) {
|
||||||
|
return serialiser->serialise(props, item_type, bytes_written, writer, *this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(auto& prop : props) {
|
||||||
|
if(!writeItem(prop, item_type, bytes_written, writer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Serialisers::AbstractUnrealProperty*
|
||||||
|
PropertySerialiser::getSerialiser(Containers::StringView item_type) {
|
||||||
|
for(auto& item : _serialisers) {
|
||||||
|
for(auto serialiser_type : item->types()) {
|
||||||
|
if(item_type == serialiser_type) {
|
||||||
|
return item.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serialisers::AbstractUnrealCollectionProperty*
|
||||||
|
PropertySerialiser::getCollectionSerialiser(Containers::StringView item_type) {
|
||||||
|
for(auto& item : _collectionSerialisers) {
|
||||||
|
for(Containers::StringView serialiser_type : item->types()) {
|
||||||
|
if(item_type == serialiser_type) {
|
||||||
|
return item.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
64
src/Gvas/PropertySerialiser.h
Normal file
64
src/Gvas/PropertySerialiser.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Containers/GrowableArray.h>
|
||||||
|
#include <Corrade/Containers/String.h>
|
||||||
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
|
#include "Serialisers/AbstractUnrealProperty.h"
|
||||||
|
#include "Serialisers/AbstractUnrealCollectionProperty.h"
|
||||||
|
|
||||||
|
#include "Types/UnrealPropertyBase.h"
|
||||||
|
|
||||||
|
#include "../BinaryIo/BinaryIo.h"
|
||||||
|
|
||||||
|
using namespace Corrade;
|
||||||
|
|
||||||
|
namespace Gvas {
|
||||||
|
|
||||||
|
class PropertySerialiser {
|
||||||
|
public:
|
||||||
|
static auto instance() -> PropertySerialiser&;
|
||||||
|
|
||||||
|
auto read(BinaryIo::Reader& reader) -> Types::UnrealPropertyBase::ptr;
|
||||||
|
auto readItem(BinaryIo::Reader& reader, Containers::String type, std::size_t value_length, Containers::String name)
|
||||||
|
-> Types::UnrealPropertyBase::ptr;
|
||||||
|
auto readSet(BinaryIo::Reader& reader, Containers::StringView item_type, std::uint32_t count)
|
||||||
|
-> Containers::Array<Types::UnrealPropertyBase::ptr>;
|
||||||
|
auto deserialise(Containers::String name, Containers::String type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader) -> Types::UnrealPropertyBase::ptr;
|
||||||
|
|
||||||
|
bool serialise(Types::UnrealPropertyBase::ptr& prop, Containers::StringView item_type,
|
||||||
|
std::size_t& bytes_written, BinaryIo::Writer& writer);
|
||||||
|
bool write(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer);
|
||||||
|
bool writeItem(Types::UnrealPropertyBase::ptr& prop, Containers::StringView item_type,
|
||||||
|
std::size_t& bytes_written, BinaryIo::Writer& writer);
|
||||||
|
bool writeSet(Containers::ArrayView<Types::UnrealPropertyBase::ptr> props, Containers::StringView item_type,
|
||||||
|
std::size_t& bytes_written, BinaryIo::Writer& writer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
PropertySerialiser();
|
||||||
|
|
||||||
|
auto getSerialiser(Containers::StringView item_type) -> Serialisers::AbstractUnrealProperty*;
|
||||||
|
auto getCollectionSerialiser(Containers::StringView item_type) -> Serialisers::AbstractUnrealCollectionProperty*;
|
||||||
|
|
||||||
|
Containers::Array<Serialisers::AbstractUnrealProperty::ptr> _serialisers;
|
||||||
|
Containers::Array<Serialisers::AbstractUnrealCollectionProperty::ptr> _collectionSerialisers;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,29 +21,33 @@
|
||||||
#include <Corrade/Containers/Pointer.h>
|
#include <Corrade/Containers/Pointer.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
#include "../Gvas.h"
|
||||||
|
#include "../../BinaryIo/BinaryIo.h"
|
||||||
#include "../Types/UnrealPropertyBase.h"
|
#include "../Types/UnrealPropertyBase.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
class BinaryReader;
|
namespace Gvas::Serialisers {
|
||||||
class BinaryWriter;
|
|
||||||
class PropertySerialiser;
|
|
||||||
|
|
||||||
class AbstractUnrealCollectionPropertySerialiser {
|
using PropertyArray = Containers::Array<Types::UnrealPropertyBase::ptr>;
|
||||||
|
using PropertyArrayView = Containers::ArrayView<Types::UnrealPropertyBase::ptr>;
|
||||||
|
using StringArrayView = Containers::ArrayView<const Containers::String>;
|
||||||
|
|
||||||
|
class AbstractUnrealCollectionProperty {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<AbstractUnrealCollectionPropertySerialiser>;
|
using ptr = Containers::Pointer<AbstractUnrealCollectionProperty>;
|
||||||
|
|
||||||
virtual ~AbstractUnrealCollectionPropertySerialiser() = default;
|
virtual ~AbstractUnrealCollectionProperty() = default;
|
||||||
|
|
||||||
virtual auto types() -> Containers::ArrayView<const Containers::String> = 0;
|
virtual auto types() -> StringArrayView = 0;
|
||||||
|
|
||||||
virtual auto deserialise(Containers::StringView name, Containers::StringView type,
|
virtual auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
UnsignedLong value_length, UnsignedInt count, BinaryReader& reader,
|
std::uint32_t count, BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
PropertySerialiser& serialiser) -> Containers::Array<UnrealPropertyBase::ptr> = 0;
|
-> PropertyArray = 0;
|
||||||
|
|
||||||
virtual auto serialise(Containers::ArrayView<UnrealPropertyBase::ptr> props, Containers::StringView item_type,
|
virtual bool serialise(PropertyArrayView props, Containers::StringView item_type,
|
||||||
UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool = 0;
|
std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,28 +20,30 @@
|
||||||
#include <Corrade/Containers/Pointer.h>
|
#include <Corrade/Containers/Pointer.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
#include "../Gvas.h"
|
||||||
|
#include "../../BinaryIo/BinaryIo.h"
|
||||||
#include "../Types/UnrealPropertyBase.h"
|
#include "../Types/UnrealPropertyBase.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
class BinaryReader;
|
namespace Gvas::Serialisers {
|
||||||
class BinaryWriter;
|
|
||||||
class PropertySerialiser;
|
|
||||||
|
|
||||||
class AbstractUnrealPropertySerialiser {
|
using StringArrayView = Containers::ArrayView<const Containers::String>;
|
||||||
|
|
||||||
|
class AbstractUnrealProperty {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<AbstractUnrealPropertySerialiser>;
|
using ptr = Containers::Pointer<AbstractUnrealProperty>;
|
||||||
|
|
||||||
virtual ~AbstractUnrealPropertySerialiser() = default;
|
virtual ~AbstractUnrealProperty() = default;
|
||||||
|
|
||||||
virtual auto types() -> Containers::ArrayView<const Containers::String> = 0;
|
virtual auto types() -> StringArrayView = 0;
|
||||||
|
|
||||||
virtual auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
virtual auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr = 0;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
-> Types::UnrealPropertyBase::ptr = 0;
|
||||||
|
|
||||||
virtual auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
virtual bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
PropertySerialiser& serialiser) -> bool = 0;
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,26 +21,26 @@
|
||||||
#include <Corrade/Containers/Pointer.h>
|
#include <Corrade/Containers/Pointer.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
#include "../Gvas.h"
|
||||||
|
#include "../../BinaryIo/BinaryIo.h"
|
||||||
#include "../Types/UnrealPropertyBase.h"
|
#include "../Types/UnrealPropertyBase.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
class BinaryReader;
|
namespace Gvas::Serialisers {
|
||||||
class BinaryWriter;
|
|
||||||
|
|
||||||
class AbstractUnrealStructSerialiser {
|
class AbstractUnrealStruct {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<AbstractUnrealStructSerialiser>;
|
using ptr = Containers::Pointer<AbstractUnrealStruct>;
|
||||||
|
|
||||||
virtual ~AbstractUnrealStructSerialiser() = default;
|
virtual ~AbstractUnrealStruct() = default;
|
||||||
|
|
||||||
virtual auto supportsType(Containers::StringView type) -> bool = 0;
|
virtual bool supportsType(Containers::StringView type) = 0;
|
||||||
|
|
||||||
virtual auto deserialise(BinaryReader& reader) -> UnrealPropertyBase::ptr = 0;
|
virtual auto deserialise(BinaryIo::Reader& reader) -> Types::UnrealPropertyBase::ptr = 0;
|
||||||
|
|
||||||
virtual auto serialise(UnrealPropertyBase::ptr& structProp, BinaryWriter& writer,
|
virtual bool serialise(Types::UnrealPropertyBase::ptr& structProp, BinaryIo::Writer& writer,
|
||||||
UnsignedLong& bytes_written) -> bool = 0;
|
std::size_t& bytes_written) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,54 +16,64 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/String.h>
|
#include <Corrade/Containers/String.h>
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../../BinaryIo/Reader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../../BinaryIo/Writer.h"
|
||||||
#include "../PropertySerialiser.h"
|
#include "../PropertySerialiser.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "ArrayPropertySerialiser.h"
|
#include "ArrayProperty.h"
|
||||||
|
|
||||||
auto ArrayPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
namespace Gvas::Serialisers {
|
||||||
UnsignedLong value_length, BinaryReader& reader,
|
|
||||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
Types::UnrealPropertyBase::ptr
|
||||||
|
ArrayProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
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;
|
std::uint32_t item_count;
|
||||||
if(!reader.readUnsignedInt(item_count)) {
|
if(!reader.readUint32(item_count)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read array property {}'s item count.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto prop = Containers::pointer<ArrayProperty>();
|
auto prop = Containers::pointer<Types::ArrayProperty>();
|
||||||
prop->itemType = std::move(item_type);
|
prop->itemType = Utility::move(item_type);
|
||||||
prop->items = serialiser.readSet(reader, prop->itemType, item_count);
|
prop->items = serialiser.readSet(reader, prop->itemType, item_count);
|
||||||
|
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ArrayPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
bool
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
ArrayProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto array_prop = dynamic_cast<ArrayProperty*>(prop.get());
|
auto array_prop = dynamic_cast<Types::ArrayProperty*>(prop.get());
|
||||||
if(!array_prop) {
|
if(!array_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid array property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.writeUEStringToArray(array_prop->itemType);
|
writer.writeUEStringToArray(array_prop->itemType);
|
||||||
writer.writeValueToArray<char>('\0');
|
writer.writeValueToArray<char>('\0');
|
||||||
bytes_written += writer.writeValueToArray<UnsignedInt>(UnsignedInt(array_prop->items.size()));
|
bytes_written += writer.writeValueToArray<std::uint32_t>(std::uint32_t(array_prop->items.size()));
|
||||||
|
|
||||||
UnsignedLong start_pos = writer.arrayPosition();
|
std::size_t start_pos = writer.arrayPosition();
|
||||||
UnsignedLong dummy_bytes_written = 0;
|
std::size_t dummy_bytes_written = 0;
|
||||||
bool ret = serialiser.writeSet(array_prop->items, array_prop->itemType, dummy_bytes_written, writer);
|
bool ret = serialiser.writeSet(array_prop->items, array_prop->itemType, dummy_bytes_written, writer);
|
||||||
bytes_written += writer.arrayPosition() - start_pos;
|
bytes_written += writer.arrayPosition() - start_pos;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,22 +18,24 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include <Magnum/Types.h>
|
#include "../Gvas.h"
|
||||||
|
#include "UnrealProperty.h"
|
||||||
#include "UnrealPropertySerialiser.h"
|
|
||||||
|
|
||||||
#include "../Types/ArrayProperty.h"
|
#include "../Types/ArrayProperty.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
using namespace Magnum;
|
|
||||||
|
|
||||||
class ArrayPropertySerialiser : public UnrealPropertySerialiser<ArrayProperty> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class ArrayProperty : public UnrealProperty<Types::ArrayProperty> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<ArrayPropertySerialiser>;
|
using ptr = Containers::Pointer<ArrayProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
73
src/Gvas/Serialisers/BoolProperty.cpp
Normal file
73
src/Gvas/Serialisers/BoolProperty.cpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "../../BinaryIo/Reader.h"
|
||||||
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "BoolProperty.h"
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
StringArrayView
|
||||||
|
BoolProperty::types() {
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
static const Containers::Array<Containers::String> types{InPlaceInit, {"BoolProperty"_s}};
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
BoolProperty::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
if(value_length != 0) {
|
||||||
|
LOG_ERROR_FORMAT("Invalid value length for bool property {}. Expected 0, got {} instead.", name, value_length);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::int16_t value;
|
||||||
|
if(!reader.readInt16(value)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read bool property {}'s value.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(value > 1 || value < 0) {
|
||||||
|
LOG_ERROR_FORMAT("Bool property {}'s value is invalid. Expected 1 or 0, got {} instead.", name, value);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto prop = Containers::pointer<Types::BoolProperty>();
|
||||||
|
prop->value = value;
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BoolProperty::serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto bool_prop = dynamic_cast<Types::BoolProperty*>(prop.get());
|
||||||
|
if(!bool_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid bool property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeValueToArray<std::int16_t>(std::int16_t(bool_prop->value));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,21 +19,26 @@
|
||||||
#include <Corrade/Containers/ArrayView.h>
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "AbstractUnrealPropertySerialiser.h"
|
#include "AbstractUnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/BoolProperty.h"
|
#include "../Types/BoolProperty.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
|
|
||||||
class BoolPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class BoolProperty : public AbstractUnrealProperty {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<BoolPropertySerialiser>;
|
using ptr = Containers::Pointer<BoolProperty>;
|
||||||
|
|
||||||
auto types() -> Containers::ArrayView<const Containers::String> override;
|
auto types() -> StringArrayView override;
|
||||||
|
|
||||||
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
|
|
||||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,42 +14,49 @@
|
||||||
// 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 "../BinaryReader.h"
|
#include "../../BinaryIo/Reader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "BytePropertySerialiser.h"
|
#include "ByteProperty.h"
|
||||||
|
|
||||||
auto BytePropertySerialiser::types() -> Containers::ArrayView<const Containers::String> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
StringArrayView
|
||||||
|
ByteProperty::types() {
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
static const Containers::Array<Containers::String> types{InPlaceInit, {"ByteProperty"_s}};
|
static const Containers::Array<Containers::String> types{InPlaceInit, {"ByteProperty"_s}};
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto BytePropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type,
|
Types::UnrealPropertyBase::ptr
|
||||||
UnsignedLong value_length, BinaryReader& reader,
|
ByteProperty::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto prop = Containers::pointer<ByteProperty>();
|
auto prop = Containers::pointer<Types::ByteProperty>();
|
||||||
|
|
||||||
if(value_length != UnsignedLong(-1)) {
|
if(value_length != std::size_t(-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;
|
||||||
}
|
}
|
||||||
|
|
||||||
prop->valueLength = value_length;
|
prop->valueLength = value_length;
|
||||||
|
|
||||||
//UnsignedInt count = 0;
|
//std::uint32_t count = 0;
|
||||||
//if(!reader.readUnsignedInt(count)) {
|
//if(!reader.readstd::uint32_t(count)) {
|
||||||
// return nullptr;
|
// return nullptr;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
@ -60,20 +67,21 @@ auto BytePropertySerialiser::deserialise(Containers::StringView name, Containers
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto BytePropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
bool
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
ByteProperty::serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto byte_prop = dynamic_cast<ByteProperty*>(prop.get());
|
auto byte_prop = dynamic_cast<Types::ByteProperty*>(prop.get());
|
||||||
|
|
||||||
if(!byte_prop) {
|
if(!byte_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid byte property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//writer.writeValueToArray<char>('\0');
|
//writer.writeValueToArray<char>('\0');
|
||||||
//bytes_written += writer.writeValueToArray<UnsignedInt>(byte_prop->value.size());
|
//bytes_written += writer.writeValueToArray<std::uint32_t>(byte_prop->value.size());
|
||||||
//bytes_written += writer.writeDataToArray<char>(byte_prop->value);
|
//bytes_written += writer.writeDataToArray<char>(byte_prop->value);
|
||||||
|
|
||||||
if(byte_prop->valueLength != UnsignedLong(-1)) {
|
if(byte_prop->valueLength != std::size_t(-1)) {
|
||||||
writer.writeUEStringToArray(byte_prop->enumType);
|
writer.writeUEStringToArray(byte_prop->enumType);
|
||||||
writer.writeValueToArray<char>('\0');
|
writer.writeValueToArray<char>('\0');
|
||||||
}
|
}
|
||||||
|
@ -82,3 +90,5 @@ auto BytePropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,19 +19,24 @@
|
||||||
#include <Corrade/Containers/ArrayView.h>
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "AbstractUnrealPropertySerialiser.h"
|
#include "AbstractUnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/ByteProperty.h"
|
#include "../Types/ByteProperty.h"
|
||||||
|
|
||||||
class BytePropertySerialiser : public AbstractUnrealPropertySerialiser {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class ByteProperty : public AbstractUnrealProperty {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<BytePropertySerialiser>;
|
using ptr = Containers::Pointer<ByteProperty>;
|
||||||
|
|
||||||
auto types() -> Containers::ArrayView<const Containers::String> override;
|
auto types() -> StringArrayView override;
|
||||||
|
|
||||||
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
|
|
||||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
59
src/Gvas/Serialisers/ColourProperty.cpp
Normal file
59
src/Gvas/Serialisers/ColourProperty.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "../../BinaryIo/Reader.h"
|
||||||
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "ColourProperty.h"
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
ColourProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto prop = Containers::pointer<Types::ColourStructProperty>();
|
||||||
|
|
||||||
|
if(!reader.readFloat(prop->r) || !reader.readFloat(prop->g) ||
|
||||||
|
!reader.readFloat(prop->b) || !reader.readFloat(prop->a))
|
||||||
|
{
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read colour property {}'s value.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ColourProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto colour_prop = dynamic_cast<Types::ColourStructProperty*>(prop.get());
|
||||||
|
if(!colour_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid colour property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_written += writer.writeValueToArray<float>(colour_prop->r) +
|
||||||
|
writer.writeValueToArray<float>(colour_prop->g) +
|
||||||
|
writer.writeValueToArray<float>(colour_prop->b) +
|
||||||
|
writer.writeValueToArray<float>(colour_prop->a);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,19 +18,24 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "UnrealPropertySerialiser.h"
|
#include "UnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/ColourStructProperty.h"
|
#include "../Types/ColourStructProperty.h"
|
||||||
|
|
||||||
using namespace Corrade;
|
using namespace Corrade;
|
||||||
|
|
||||||
class ColourPropertySerialiser : public UnrealPropertySerialiser<ColourStructProperty> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class ColourProperty : public UnrealProperty<Types::ColourStructProperty> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<ColourPropertySerialiser>;
|
using ptr = Containers::Pointer<ColourProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
54
src/Gvas/Serialisers/DateTimeProperty.cpp
Normal file
54
src/Gvas/Serialisers/DateTimeProperty.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "../../BinaryIo/Reader.h"
|
||||||
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "DateTimeProperty.h"
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
DateTimeProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||||
|
std::size_t value_length, BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto prop = Containers::pointer<Types::DateTimeStructProperty>();
|
||||||
|
|
||||||
|
if(!reader.readInt64(prop->timestamp)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read date/time property {}'s value.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
DateTimeProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto dt_prop = dynamic_cast<Types::DateTimeStructProperty*>(prop.get());
|
||||||
|
if(!dt_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid date/time property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_written += writer.writeValueToArray<std::int64_t>(dt_prop->timestamp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,17 +18,22 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "UnrealPropertySerialiser.h"
|
#include "UnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/DateTimeStructProperty.h"
|
#include "../Types/DateTimeStructProperty.h"
|
||||||
|
|
||||||
class DateTimePropertySerialiser : public UnrealPropertySerialiser<DateTimeStructProperty> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class DateTimeProperty : public UnrealProperty<Types::DateTimeStructProperty> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<DateTimePropertySerialiser>;
|
using ptr = Containers::Pointer<DateTimeProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,45 +14,53 @@
|
||||||
// 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 "../BinaryReader.h"
|
#include "../../BinaryIo/Reader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "EnumPropertySerialiser.h"
|
#include "EnumProperty.h"
|
||||||
|
|
||||||
auto EnumPropertySerialiser::types() -> Containers::ArrayView<const Containers::String> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
StringArrayView
|
||||||
|
EnumProperty::types() {
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
static const Containers::Array<Containers::String> types{InPlaceInit, {"EnumProperty"_s}};
|
static const Containers::Array<Containers::String> types{InPlaceInit, {"EnumProperty"_s}};
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EnumPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type,
|
Types::UnrealPropertyBase::ptr
|
||||||
UnsignedLong value_length, BinaryReader& reader,
|
EnumProperty::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto prop = Containers::pointer<EnumProperty>();
|
auto prop = Containers::pointer<Types::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto EnumPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
bool
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
EnumProperty::serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto enum_prop = dynamic_cast<EnumProperty*>(prop.get());
|
auto enum_prop = dynamic_cast<Types::EnumProperty*>(prop.get());
|
||||||
|
|
||||||
if(!enum_prop) {
|
if(!enum_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid enum property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,3 +70,5 @@ auto EnumPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,19 +19,24 @@
|
||||||
#include <Corrade/Containers/ArrayView.h>
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "AbstractUnrealPropertySerialiser.h"
|
#include "AbstractUnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/EnumProperty.h"
|
#include "../Types/EnumProperty.h"
|
||||||
|
|
||||||
class EnumPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class EnumProperty : public AbstractUnrealProperty {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<EnumPropertySerialiser>;
|
using ptr = Containers::Pointer<EnumProperty>;
|
||||||
|
|
||||||
auto types() -> Containers::ArrayView<const Containers::String> override;
|
auto types() -> StringArrayView override;
|
||||||
|
|
||||||
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
|
|
||||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,46 +14,55 @@
|
||||||
// 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 "../BinaryReader.h"
|
#include "../../BinaryIo/Reader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "FloatPropertySerialiser.h"
|
#include "FloatProperty.h"
|
||||||
|
|
||||||
auto FloatPropertySerialiser::types() -> Containers::ArrayView<const Containers::String> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
StringArrayView
|
||||||
|
FloatProperty::types() {
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
static const Containers::Array<Containers::String> types{InPlaceInit, {"FloatProperty"_s}};
|
static const Containers::Array<Containers::String> types{InPlaceInit, {"FloatProperty"_s}};
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FloatPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type,
|
Types::UnrealPropertyBase::ptr
|
||||||
UnsignedLong value_length, BinaryReader& reader,
|
FloatProperty::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto prop = Containers::pointer<FloatProperty>();
|
auto prop = Containers::pointer<Types::FloatProperty>();
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto FloatPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
bool
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
FloatProperty::serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto float_prop = dynamic_cast<FloatProperty*>(prop.get());
|
auto float_prop = dynamic_cast<Types::FloatProperty*>(prop.get());
|
||||||
|
|
||||||
if(!float_prop) {
|
if(!float_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid float property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.writeValueToArray<char>('\0');
|
writer.writeValueToArray<char>('\0');
|
||||||
bytes_written += writer.writeValueToArray<Float>(float_prop->value);
|
bytes_written += writer.writeValueToArray<float>(float_prop->value);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,19 +19,24 @@
|
||||||
#include <Corrade/Containers/ArrayView.h>
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "AbstractUnrealPropertySerialiser.h"
|
#include "AbstractUnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/FloatProperty.h"
|
#include "../Types/FloatProperty.h"
|
||||||
|
|
||||||
class FloatPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class FloatProperty : public AbstractUnrealProperty {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<FloatPropertySerialiser>;
|
using ptr = Containers::Pointer<FloatProperty>;
|
||||||
|
|
||||||
auto types() -> Containers::ArrayView<const Containers::String> override;
|
auto types() -> StringArrayView override;
|
||||||
|
|
||||||
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
|
|
||||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,33 +14,37 @@
|
||||||
// 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 "../BinaryReader.h"
|
#include "../../BinaryIo/Reader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "GuidPropertySerialiser.h"
|
#include "GuidProperty.h"
|
||||||
|
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
auto GuidPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
namespace Gvas::Serialisers {
|
||||||
UnsignedLong value_length, BinaryReader& reader,
|
|
||||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
Types::UnrealPropertyBase::ptr
|
||||||
|
GuidProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto prop = Containers::pointer<GuidStructProperty>();
|
auto prop = Containers::pointer<Types::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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GuidPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
bool
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
GuidProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto guid_prop = dynamic_cast<GuidStructProperty*>(prop.get());
|
auto guid_prop = dynamic_cast<Types::GuidStructProperty*>(prop.get());
|
||||||
|
|
||||||
if(!guid_prop) {
|
if(!guid_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid GUID property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,3 +52,5 @@ auto GuidPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Un
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,17 +18,22 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "UnrealPropertySerialiser.h"
|
#include "UnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/GuidStructProperty.h"
|
#include "../Types/GuidStructProperty.h"
|
||||||
|
|
||||||
class GuidPropertySerialiser : public UnrealPropertySerialiser<GuidStructProperty> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class GuidProperty : public UnrealProperty<Types::GuidStructProperty> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<GuidPropertySerialiser>;
|
using ptr = Containers::Pointer<GuidProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
76
src/Gvas/Serialisers/IntProperty.cpp
Normal file
76
src/Gvas/Serialisers/IntProperty.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "../../BinaryIo/Reader.h"
|
||||||
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "IntProperty.h"
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
IntProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto prop = Containers::pointer<Types::IntProperty>();
|
||||||
|
|
||||||
|
if(value_length == std::size_t(-1)) {
|
||||||
|
if(!reader.readInt32(prop->value)) {
|
||||||
|
LOG_ERROR("Couldn't read int property's value.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop->valueLength = std::size_t(-1);
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
char terminator;
|
||||||
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in int property {}.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!reader.readInt32(prop->value)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read int property {}'s value.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop->name.emplace(name);
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
IntProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto int_prop = dynamic_cast<Types::IntProperty*>(prop.get());
|
||||||
|
if(!int_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid int property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(prop->valueLength != std::size_t(-1)) {
|
||||||
|
writer.writeValueToArray<char>('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_written += writer.writeValueToArray<std::int32_t>(int_prop->value);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,17 +18,22 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "UnrealPropertySerialiser.h"
|
#include "UnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/IntProperty.h"
|
#include "../Types/IntProperty.h"
|
||||||
|
|
||||||
class IntPropertySerialiser : public UnrealPropertySerialiser<IntProperty> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class IntProperty : public UnrealProperty<Types::IntProperty> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<IntPropertySerialiser>;
|
using ptr = Containers::Pointer<IntProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,42 +14,49 @@
|
||||||
// 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 "../BinaryReader.h"
|
#include "../../BinaryIo/Reader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../../BinaryIo/Writer.h"
|
||||||
#include "../PropertySerialiser.h"
|
#include "../PropertySerialiser.h"
|
||||||
|
|
||||||
#include "../Types/NoneProperty.h"
|
#include "../Types/NoneProperty.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "MapPropertySerialiser.h"
|
#include "MapProperty.h"
|
||||||
|
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
namespace Gvas::Serialisers {
|
||||||
UnsignedLong value_length, BinaryReader& reader,
|
|
||||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
Types::UnrealPropertyBase::ptr
|
||||||
|
MapProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto prop = Containers::pointer<MapProperty>();
|
auto prop = Containers::pointer<Types::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;
|
std::uint32_t null;
|
||||||
if(!reader.readUnsignedInt(null) || null != 0u) {
|
if(!reader.readUint32(null) || null != 0u) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null int in map property {}.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnsignedInt count;
|
std::uint32_t count;
|
||||||
if(!reader.readUnsignedInt(count)) {
|
if(!reader.readUint32(count)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read map property {}'s item count.", name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,27 +65,29 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
||||||
|
|
||||||
arrayReserve(prop->map, count);
|
arrayReserve(prop->map, count);
|
||||||
|
|
||||||
for(UnsignedInt i = 0; i < count; i++) {
|
for(std::uint32_t i = 0; i < count; i++) {
|
||||||
MapProperty::KeyValuePair pair;
|
Types::MapProperty::KeyValuePair pair;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnrealPropertyBase::ptr value_item;
|
Types::UnrealPropertyBase::ptr value_item;
|
||||||
if(prop->valueType == "StructProperty"_s) {
|
if(prop->valueType == "StructProperty"_s) {
|
||||||
while((value_item = serialiser.read(reader)) != nullptr) {
|
while((value_item = serialiser.read(reader)) != nullptr) {
|
||||||
arrayAppend(pair.values, std::move(value_item));
|
arrayAppend(pair.values, Utility::move(value_item));
|
||||||
|
|
||||||
if(pair.values.back()->name == "None"_s &&
|
if(pair.values.back()->name == "None"_s &&
|
||||||
pair.values.back()->propertyType == "NoneProperty"_s &&
|
pair.values.back()->propertyType == "NoneProperty"_s &&
|
||||||
dynamic_cast<NoneProperty*>(pair.values.back().get()) != nullptr)
|
dynamic_cast<Types::NoneProperty*>(pair.values.back().get()) != nullptr)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -89,10 +98,10 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayAppend(pair.values, std::move(value_item));
|
arrayAppend(pair.values, Utility::move(value_item));
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayAppend(prop->map, std::move(pair));
|
arrayAppend(prop->map, Utility::move(pair));
|
||||||
}
|
}
|
||||||
|
|
||||||
// End dirty code
|
// End dirty code
|
||||||
|
@ -100,11 +109,13 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
bool
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
MapProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto map_prop = dynamic_cast<MapProperty*>(prop.get());
|
auto map_prop = dynamic_cast<Types::MapProperty*>(prop.get());
|
||||||
if(!map_prop) {
|
if(!map_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid map property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,25 +123,28 @@ auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
|
||||||
writer.writeUEStringToArray(map_prop->valueType);
|
writer.writeUEStringToArray(map_prop->valueType);
|
||||||
writer.writeValueToArray<char>('\0');
|
writer.writeValueToArray<char>('\0');
|
||||||
|
|
||||||
UnsignedLong value_start = writer.arrayPosition();
|
std::size_t value_start = writer.arrayPosition();
|
||||||
writer.writeValueToArray<UnsignedInt>(0u);
|
writer.writeValueToArray<std::uint32_t>(0u);
|
||||||
|
|
||||||
writer.writeValueToArray<UnsignedInt>(UnsignedInt(map_prop->map.size()));
|
writer.writeValueToArray<std::uint32_t>(std::uint32_t(map_prop->map.size()));
|
||||||
|
|
||||||
UnsignedLong dummy_bytes_written = 0;
|
std::size_t 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,3 +155,5 @@ auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,17 +18,22 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "UnrealPropertySerialiser.h"
|
#include "UnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/MapProperty.h"
|
#include "../Types/MapProperty.h"
|
||||||
|
|
||||||
class MapPropertySerialiser : public UnrealPropertySerialiser<MapProperty> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class MapProperty : public UnrealProperty<Types::MapProperty> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<MapPropertySerialiser>;
|
using ptr = Containers::Pointer<MapProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
110
src/Gvas/Serialisers/ResourceProperty.cpp
Normal file
110
src/Gvas/Serialisers/ResourceProperty.cpp
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "../../BinaryIo/Reader.h"
|
||||||
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../PropertySerialiser.h"
|
||||||
|
#include "../Types/IntProperty.h"
|
||||||
|
#include "../Types/NoneProperty.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "ResourceProperty.h"
|
||||||
|
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
ResourceProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||||
|
std::size_t value_length, BinaryIo::Reader& reader,
|
||||||
|
PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto prop = Containers::pointer<Types::ResourceItemValue>();
|
||||||
|
|
||||||
|
auto id_prop = serialiser.read(reader);
|
||||||
|
if(!id_prop) {
|
||||||
|
LOG_ERROR("Couldn't read the ID property."_s);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((*id_prop->name) != "ID_4_AAE08F17428E229EC7A2209F51081A21"_s ||
|
||||||
|
id_prop->propertyType != "IntProperty"_s ||
|
||||||
|
dynamic_cast<Types::IntProperty*>(id_prop.get()) == nullptr)
|
||||||
|
{
|
||||||
|
LOG_ERROR("The ID property is invalid."_s);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop->id = dynamic_cast<Types::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((*value_prop->name) != "Quantity_3_560F09B5485C365D3041888910019CE3"_s ||
|
||||||
|
value_prop->propertyType != "IntProperty"_s ||
|
||||||
|
dynamic_cast<Types::IntProperty*>(value_prop.get()) == nullptr)
|
||||||
|
{
|
||||||
|
LOG_ERROR("The value property is invalid."_s);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop->quantity = dynamic_cast<Types::IntProperty*>(value_prop.get())->value;
|
||||||
|
|
||||||
|
auto none_prop = serialiser.read(reader);
|
||||||
|
|
||||||
|
if(!none_prop ||
|
||||||
|
(*none_prop->name) != "None"_s ||
|
||||||
|
none_prop->propertyType != "NoneProperty"_s ||
|
||||||
|
!dynamic_cast<Types::NoneProperty*>(none_prop.get()))
|
||||||
|
{
|
||||||
|
LOG_ERROR("Couldn't find a terminating NoneProperty."_s);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ResourceProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto res_prop = dynamic_cast<Types::ResourceItemValue*>(prop.get());
|
||||||
|
if(!res_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid ResourceItemValue property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_written += writer.writeUEStringToArray("ID_4_AAE08F17428E229EC7A2209F51081A21"_s) +
|
||||||
|
writer.writeUEStringToArray("IntProperty"_s) +
|
||||||
|
writer.writeValueToArray<std::size_t>(4ull) +
|
||||||
|
writer.writeValueToArray<char>('\0') +
|
||||||
|
writer.writeValueToArray<std::int32_t>(res_prop->id);
|
||||||
|
|
||||||
|
bytes_written += writer.writeUEStringToArray("Quantity_3_560F09B5485C365D3041888910019CE3"_s) +
|
||||||
|
writer.writeUEStringToArray("IntProperty"_s) +
|
||||||
|
writer.writeValueToArray<std::size_t>(4ull) +
|
||||||
|
writer.writeValueToArray<char>('\0') +
|
||||||
|
writer.writeValueToArray<std::int32_t>(res_prop->quantity);
|
||||||
|
|
||||||
|
bytes_written += writer.writeUEStringToArray("None"_s);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,17 +18,22 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "UnrealPropertySerialiser.h"
|
#include "UnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/ResourceItemValue.h"
|
#include "../Types/ResourceItemValue.h"
|
||||||
|
|
||||||
class ResourcePropertySerialiser : public UnrealPropertySerialiser<ResourceItemValue> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class ResourceProperty : public UnrealProperty<Types::ResourceItemValue> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<ResourcePropertySerialiser>;
|
using ptr = Containers::Pointer<ResourceProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
84
src/Gvas/Serialisers/RotatorProperty.cpp
Normal file
84
src/Gvas/Serialisers/RotatorProperty.cpp
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "../../BinaryIo/Reader.h"
|
||||||
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "RotatorProperty.h"
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
RotatorProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto prop = Containers::pointer<Types::RotatorStructProperty>();
|
||||||
|
|
||||||
|
if(value_length == 12) { // UE4
|
||||||
|
float x, y, z;
|
||||||
|
|
||||||
|
if(!reader.readFloat(x) || !reader.readFloat(y) || !reader.readFloat(z)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read rotator property {}'s value.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop->vector = Vector3{x, y, z};
|
||||||
|
}
|
||||||
|
else if(value_length == 24) { // UE5
|
||||||
|
double x, y, z;
|
||||||
|
|
||||||
|
if(!reader.readDouble(x) || !reader.readDouble(y) || !reader.readDouble(z)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read rotator property {}'s value.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
prop->vector = Vector3d{x, y, z};
|
||||||
|
}
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RotatorProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto rotator = dynamic_cast<Types::RotatorStructProperty*>(prop.get());
|
||||||
|
if(!rotator) {
|
||||||
|
LOG_ERROR("The property is not a valid rotator property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::visit(
|
||||||
|
[&bytes_written, &writer](auto& arg){
|
||||||
|
using T = std::decay_t<decltype(arg)>;
|
||||||
|
if constexpr (std::is_same_v<T, Vector3>) {
|
||||||
|
bytes_written += writer.writeValueToArray<float>(arg.x()) +
|
||||||
|
writer.writeValueToArray<float>(arg.y()) +
|
||||||
|
writer.writeValueToArray<float>(arg.z());
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||||
|
bytes_written += writer.writeValueToArray<double>(arg.x()) +
|
||||||
|
writer.writeValueToArray<double>(arg.y()) +
|
||||||
|
writer.writeValueToArray<double>(arg.z());
|
||||||
|
}
|
||||||
|
}, rotator->vector
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,17 +18,22 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "UnrealPropertySerialiser.h"
|
#include "UnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/RotatorStructProperty.h"
|
#include "../Types/RotatorStructProperty.h"
|
||||||
|
|
||||||
class RotatorPropertySerialiser : public UnrealPropertySerialiser<RotatorStructProperty> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class RotatorProperty : public UnrealProperty<Types::RotatorStructProperty> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<RotatorPropertySerialiser>;
|
using ptr = Containers::Pointer<RotatorProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
44
src/Gvas/Serialisers/Serialisers.h
Normal file
44
src/Gvas/Serialisers/Serialisers.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class AbstractUnrealCollectionProperty;
|
||||||
|
class AbstractUnrealProperty;
|
||||||
|
class AbstractUnrealStruct;
|
||||||
|
class ArrayProperty;
|
||||||
|
class BoolProperty;
|
||||||
|
class ByteProperty;
|
||||||
|
class ColourProperty;
|
||||||
|
class DateTimeProperty;
|
||||||
|
class EnumProperty;
|
||||||
|
class FloatProperty;
|
||||||
|
class GuidProperty;
|
||||||
|
class IntProperty;
|
||||||
|
class MapProperty;
|
||||||
|
class ResourceProperty;
|
||||||
|
class RotatorProperty;
|
||||||
|
class SetProperty;
|
||||||
|
class StringProperty;
|
||||||
|
class Struct;
|
||||||
|
class TextProperty;
|
||||||
|
class UnrealProperty;
|
||||||
|
class Vector2DProperty;
|
||||||
|
class VectorProperty;
|
||||||
|
|
||||||
|
}
|
85
src/Gvas/Serialisers/SetProperty.cpp
Normal file
85
src/Gvas/Serialisers/SetProperty.cpp
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "../../BinaryIo/Reader.h"
|
||||||
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../PropertySerialiser.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "SetProperty.h"
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
SetProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
Containers::String item_type;
|
||||||
|
if(!reader.readUEString(item_type)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read set property {}'s item type.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char terminator;
|
||||||
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in set property {}.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t four_bytes;
|
||||||
|
if(!reader.readUint32(four_bytes) || four_bytes != 0u) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read four null bytes in set property {}.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t item_count;
|
||||||
|
if(!reader.readUint32(item_count)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read set property {}'s item count.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto prop = Containers::pointer<Types::SetProperty>();
|
||||||
|
prop->itemType = Utility::move(item_type);
|
||||||
|
prop->items = serialiser.readSet(reader, prop->itemType, item_count);
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SetProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto set_prop = dynamic_cast<Types::SetProperty*>(prop.get());
|
||||||
|
if(!set_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid set property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeUEStringToArray(set_prop->itemType);
|
||||||
|
writer.writeValueToArray<char>('\0');
|
||||||
|
|
||||||
|
bytes_written += writer.writeValueToArray<std::uint32_t>(0u);
|
||||||
|
bytes_written += writer.writeValueToArray<std::uint32_t>(std::uint32_t(set_prop->items.size()));
|
||||||
|
|
||||||
|
std::size_t start_pos = writer.arrayPosition();
|
||||||
|
std::size_t dummy_bytes_written = 0;
|
||||||
|
serialiser.writeSet(set_prop->items, set_prop->itemType, dummy_bytes_written, writer);
|
||||||
|
bytes_written += writer.arrayPosition() - start_pos;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,17 +18,22 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "UnrealPropertySerialiser.h"
|
#include "UnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/SetProperty.h"
|
#include "../Types/SetProperty.h"
|
||||||
|
|
||||||
class SetPropertySerialiser : public UnrealPropertySerialiser<SetProperty> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class SetProperty : public UnrealProperty<Types::SetProperty> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<SetPropertySerialiser>;
|
using ptr = Containers::Pointer<SetProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -14,33 +14,39 @@
|
||||||
// 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 "../BinaryReader.h"
|
#include "../../BinaryIo/Reader.h"
|
||||||
#include "../BinaryWriter.h"
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
#include "StringPropertySerialiser.h"
|
#include "StringProperty.h"
|
||||||
|
|
||||||
auto StringPropertySerialiser::types() -> Containers::ArrayView<const Containers::String> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
StringArrayView
|
||||||
|
StringProperty::types() {
|
||||||
using namespace Containers::Literals;
|
using namespace Containers::Literals;
|
||||||
static const Containers::Array<Containers::String> types{InPlaceInit,
|
static const Containers::Array<Containers::String> types{InPlaceInit, {
|
||||||
{"NameProperty"_s, "StrProperty"_s,
|
"NameProperty"_s, "StrProperty"_s, "SoftObjectProperty"_s, "ObjectProperty"_s
|
||||||
"SoftObjectProperty"_s, "ObjectProperty"_s}};
|
}};
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto StringPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type,
|
Types::UnrealPropertyBase::ptr
|
||||||
UnsignedLong value_length, BinaryReader& reader,
|
StringProperty::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto prop = Containers::pointer<StringProperty>(type);
|
auto prop = Containers::pointer<Types::StringProperty>(type);
|
||||||
|
|
||||||
if(value_length != UnsignedLong(-1)) {
|
if(value_length != std::size_t(-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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,16 +55,17 @@ auto StringPropertySerialiser::deserialise(Containers::StringView name, Containe
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto StringPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
bool
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
StringProperty::serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto str_prop = dynamic_cast<StringProperty*>(prop.get());
|
auto str_prop = dynamic_cast<Types::StringProperty*>(prop.get());
|
||||||
|
|
||||||
if(!str_prop) {
|
if(!str_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid string property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(str_prop->valueLength != UnsignedLong(-1)) {
|
if(str_prop->valueLength != std::size_t(-1)) {
|
||||||
writer.writeValueToArray<char>('\0');
|
writer.writeValueToArray<char>('\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,3 +73,5 @@ auto StringPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, Unsigned
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,19 +19,24 @@
|
||||||
#include <Corrade/Containers/ArrayView.h>
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "AbstractUnrealPropertySerialiser.h"
|
#include "AbstractUnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/StringProperty.h"
|
#include "../Types/StringProperty.h"
|
||||||
|
|
||||||
class StringPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class StringProperty : public AbstractUnrealProperty {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<StringPropertySerialiser>;
|
using ptr = Containers::Pointer<StringProperty>;
|
||||||
|
|
||||||
auto types() -> Containers::ArrayView<const Containers::String> override;
|
auto types() -> StringArrayView override;
|
||||||
|
|
||||||
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
|
|
||||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
245
src/Gvas/Serialisers/Struct.cpp
Normal file
245
src/Gvas/Serialisers/Struct.cpp
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Containers/String.h>
|
||||||
|
|
||||||
|
#include "../../BinaryIo/Reader.h"
|
||||||
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
#include "../PropertySerialiser.h"
|
||||||
|
#include "../Types/GenericStructProperty.h"
|
||||||
|
#include "../Types/NoneProperty.h"
|
||||||
|
#include "../../Logger/Logger.h"
|
||||||
|
|
||||||
|
#include "Struct.h"
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
StringArrayView
|
||||||
|
Struct::types() {
|
||||||
|
using namespace Containers::Literals;
|
||||||
|
static const Containers::Array<Containers::String> types{InPlaceInit, {"StructProperty"_s}};
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyArray
|
||||||
|
Struct::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
std::uint32_t count, BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
Containers::String item_type;
|
||||||
|
if(!reader.readUEString(item_type)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s item type.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::StaticArray<16, char> guid{ValueInit};
|
||||||
|
if(!reader.readStaticArray(guid)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s GUID.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char terminator;
|
||||||
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in struct property {}.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::Array<Types::UnrealPropertyBase::ptr> array;
|
||||||
|
|
||||||
|
if(count == 0) {
|
||||||
|
auto prop = Containers::pointer<Types::GenericStructProperty>();
|
||||||
|
prop->structType = Utility::move(item_type);
|
||||||
|
prop->structGuid = guid;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(std::uint32_t i = 0; i < count; i++) {
|
||||||
|
auto prop = Containers::pointer<Types::UnrealPropertyBase>();
|
||||||
|
|
||||||
|
prop = serialiser.readItem(reader, item_type, std::size_t(-1), name);
|
||||||
|
|
||||||
|
if(!prop) {
|
||||||
|
prop = readStructValue(name, item_type, value_length, reader, serialiser);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!prop) {
|
||||||
|
LOG_ERROR("Invalid property");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic_cast<Types::StructProperty*>(prop.get())->structGuid = guid;
|
||||||
|
|
||||||
|
arrayAppend(array, Utility::move(prop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
Struct::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
Containers::String item_type;
|
||||||
|
if(!reader.readUEString(item_type)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s item type.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(item_type == "None") {
|
||||||
|
return Containers::pointer<Types::NoneProperty>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Containers::StaticArray<16, char> guid{ValueInit};
|
||||||
|
if(!reader.readStaticArray(guid)) {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s GUID.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char terminator;
|
||||||
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
LOG_ERROR_FORMAT("Couldn't read a null byte in byte property {}.", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto prop = serialiser.readItem(reader, item_type, value_length, name);
|
||||||
|
|
||||||
|
if(!prop) {
|
||||||
|
prop = readStructValue(name, item_type, value_length, reader, serialiser);
|
||||||
|
if(prop) {
|
||||||
|
dynamic_cast<Types::GenericStructProperty*>(prop.get())->structGuid = guid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Struct::serialise(PropertyArrayView props, Containers::StringView item_type, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
bytes_written += writer.writeUEStringToArray(*(props.front()->name));
|
||||||
|
bytes_written += writer.writeUEStringToArray(item_type);
|
||||||
|
std::size_t vl_pos = writer.arrayPosition();
|
||||||
|
bytes_written += writer.writeValueToArray<std::size_t>(0ull);
|
||||||
|
|
||||||
|
auto struct_prop = dynamic_cast<Types::StructProperty*>(props.front().get());
|
||||||
|
if(!struct_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid struct property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_written += writer.writeUEStringToArray(struct_prop->structType);
|
||||||
|
bytes_written += writer.writeDataToArray(arrayView(struct_prop->structGuid));
|
||||||
|
bytes_written += writer.writeValueToArray<char>('\0');
|
||||||
|
|
||||||
|
std::size_t vl_start = writer.arrayPosition();
|
||||||
|
|
||||||
|
std::size_t bytes_written_here = 0;
|
||||||
|
for(auto& prop : props) {
|
||||||
|
struct_prop = dynamic_cast<Types::StructProperty*>(prop.get());
|
||||||
|
if(!struct_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid struct property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!serialiser.writeItem(prop, struct_prop->structType, bytes_written_here, writer)) {
|
||||||
|
if(!writeStructValue(struct_prop, bytes_written_here, writer, serialiser)) {
|
||||||
|
LOG_ERROR("Couldn't write the struct value.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t vl_stop = writer.arrayPosition() - vl_start;
|
||||||
|
writer.writeValueToArrayAt(vl_stop, vl_pos);
|
||||||
|
bytes_written += vl_stop;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Struct::serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto struct_prop = dynamic_cast<Types::StructProperty*>(prop.get());
|
||||||
|
if(!struct_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid struct property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.writeUEStringToArray(struct_prop->structType);
|
||||||
|
writer.writeDataToArray(arrayView(struct_prop->structGuid));
|
||||||
|
writer.writeValueToArray<char>('\0');
|
||||||
|
|
||||||
|
if(!serialiser.writeItem(prop, struct_prop->structType, bytes_written, writer)) {
|
||||||
|
std::size_t dummy_bytes_written = 0;
|
||||||
|
std::size_t vl_start = writer.arrayPosition();
|
||||||
|
if(!writeStructValue(struct_prop, dummy_bytes_written, writer, serialiser)) {
|
||||||
|
LOG_ERROR("Couldn't write the struct value.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bytes_written += writer.arrayPosition() - vl_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Types::StructProperty::ptr
|
||||||
|
Struct::readStructValue(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
static_cast<void>(value_length);
|
||||||
|
|
||||||
|
auto st_prop = Containers::pointer<Types::GenericStructProperty>();
|
||||||
|
st_prop->structType = type;
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr prop;
|
||||||
|
while((prop = serialiser.read(reader)) != nullptr) {
|
||||||
|
arrayAppend(st_prop->properties, Utility::move(prop));
|
||||||
|
|
||||||
|
if(st_prop->properties.back()->name == "None" &&
|
||||||
|
st_prop->properties.back()->propertyType == "NoneProperty" &&
|
||||||
|
dynamic_cast<Types::NoneProperty*>(st_prop->properties.back().get()) != nullptr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
st_prop->name.emplace(name);
|
||||||
|
|
||||||
|
return st_prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Struct::writeStructValue(Types::StructProperty* prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser)
|
||||||
|
{
|
||||||
|
auto struct_prop = dynamic_cast<Types::GenericStructProperty*>(prop);
|
||||||
|
if(!struct_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid struct property.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto& item : struct_prop->properties) {
|
||||||
|
if(!serialiser.write(item, bytes_written, writer)) {
|
||||||
|
LOG_ERROR("Couldn't write the struct's data.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
55
src/Gvas/Serialisers/Struct.h
Normal file
55
src/Gvas/Serialisers/Struct.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// MassBuilderSaveTool
|
||||||
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <Corrade/Containers/ArrayView.h>
|
||||||
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
|
#include "AbstractUnrealCollectionProperty.h"
|
||||||
|
#include "AbstractUnrealProperty.h"
|
||||||
|
#include "AbstractUnrealStruct.h"
|
||||||
|
|
||||||
|
#include "../Types/StructProperty.h"
|
||||||
|
|
||||||
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class Struct : public AbstractUnrealProperty, public AbstractUnrealCollectionProperty {
|
||||||
|
public:
|
||||||
|
using ptr = Containers::Pointer<Struct>;
|
||||||
|
|
||||||
|
auto types() -> StringArrayView override;
|
||||||
|
|
||||||
|
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
std::uint32_t count, BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
-> PropertyArray override;
|
||||||
|
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
|
|
||||||
|
bool serialise(PropertyArrayView props, Containers::StringView item_type, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
|
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
auto readStructValue(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser) -> Types::StructProperty::ptr;
|
||||||
|
bool writeStructValue(Types::StructProperty* prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||||
|
PropertySerialiser& serialiser);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,18 +16,22 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/String.h>
|
#include <Corrade/Containers/String.h>
|
||||||
|
|
||||||
#include "../BinaryReader.h"
|
#include "../../Logger/Logger.h"
|
||||||
#include "../BinaryWriter.h"
|
|
||||||
|
|
||||||
#include "TextPropertySerialiser.h"
|
#include "../../BinaryIo/Reader.h"
|
||||||
|
#include "../../BinaryIo/Writer.h"
|
||||||
|
|
||||||
auto TextPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
#include "TextProperty.h"
|
||||||
UnsignedLong value_length, BinaryReader& reader,
|
|
||||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
Types::UnrealPropertyBase::ptr
|
||||||
|
TextProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto prop = Containers::pointer<TextProperty>();
|
auto prop = Containers::pointer<Types::TextProperty>();
|
||||||
|
|
||||||
Long start_position = reader.position();
|
auto start_position = reader.position();
|
||||||
|
|
||||||
char terminator;
|
char terminator;
|
||||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||||
|
@ -49,7 +53,7 @@ auto TextPropertySerialiser::deserialiseProperty(Containers::StringView name, Co
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto interval = reader.position() - start_position;
|
std::int64_t interval;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
Containers::String str;
|
Containers::String str;
|
||||||
|
@ -58,22 +62,23 @@ auto TextPropertySerialiser::deserialiseProperty(Containers::StringView name, Co
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
arrayAppend(prop->data, std::move(str));
|
arrayAppend(prop->data, Utility::move(str));
|
||||||
|
|
||||||
interval = reader.position() - start_position;
|
interval = reader.position() - start_position;
|
||||||
} while(UnsignedLong(interval) < value_length);
|
} while(std::size_t(interval) < value_length);
|
||||||
|
|
||||||
prop->value = prop->data.back();
|
prop->value = prop->data.back();
|
||||||
|
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto TextPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
bool
|
||||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
TextProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||||
{
|
{
|
||||||
auto text_prop = dynamic_cast<TextProperty*>(prop.get());
|
auto text_prop = dynamic_cast<Types::TextProperty*>(prop.get());
|
||||||
|
|
||||||
if(!text_prop) {
|
if(!text_prop) {
|
||||||
|
LOG_ERROR("The property is not a valid text property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,3 +90,5 @@ auto TextPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Un
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// MassBuilderSaveTool
|
// MassBuilderSaveTool
|
||||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
||||||
//
|
//
|
||||||
// This program is free software: you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,17 +18,22 @@
|
||||||
|
|
||||||
#include <Corrade/Containers/StringView.h>
|
#include <Corrade/Containers/StringView.h>
|
||||||
|
|
||||||
#include "UnrealPropertySerialiser.h"
|
#include "UnrealProperty.h"
|
||||||
|
|
||||||
#include "../Types/TextProperty.h"
|
#include "../Types/TextProperty.h"
|
||||||
|
|
||||||
class TextPropertySerialiser : public UnrealPropertySerialiser<TextProperty> {
|
namespace Gvas::Serialisers {
|
||||||
|
|
||||||
|
class TextProperty : public UnrealProperty<Types::TextProperty> {
|
||||||
public:
|
public:
|
||||||
using ptr = Containers::Pointer<TextPropertySerialiser>;
|
using ptr = Containers::Pointer<TextProperty>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
-> Types::UnrealPropertyBase::ptr override;
|
||||||
PropertySerialiser& serialiser) -> bool override;
|
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||||
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue