Compare commits
126 commits
7b64d78b5b
...
40f2d88433
Author | SHA1 | Date | |
---|---|---|---|
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 |
199 changed files with 9755 additions and 7148 deletions
4
.gitmodules
vendored
4
.gitmodules
vendored
|
@ -17,11 +17,11 @@
|
|||
[submodule "SDL2"]
|
||||
path = third-party/SDL
|
||||
url = https://github.com/libsdl-org/SDL
|
||||
branch = main
|
||||
branch = SDL2
|
||||
[submodule "libzip"]
|
||||
path = third-party/libzip
|
||||
url = https://github.com/nih-at/libzip
|
||||
branch = master
|
||||
branch = main
|
||||
[submodule "efsw"]
|
||||
path = third-party/efsw
|
||||
url = https://github.com/SpartanJ/efsw
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# 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
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,26 +14,30 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# 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)
|
||||
|
||||
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)
|
||||
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)
|
||||
set(CORRADE_UTILITY_USE_ANSI_COLORS ON CACHE BOOL "" FORCE)
|
||||
add_subdirectory(third-party/corrade EXCLUDE_FROM_ALL)
|
||||
option(SAVETOOL_USE_SYSTEM_LIBS "Use system-wide versions of the dependencies instead of the versions provided by submodules." OFF)
|
||||
|
||||
include(CMakeDependentOption)
|
||||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_CORRADE_MAGNUM "Use system-wide versions of Corrade and Magnum." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_SDL2 "Use a system-wide version of SDL2." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_LIBZIP "Use a system-wide version of libzip." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_EFSW "Use a system-wide version of EFSW." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
cmake_dependent_option(SAVETOOL_USE_SYSTEM_LIBCURL "Use a system-wide version of libcurl." ON "SAVETOOL_USE_SYSTEM_LIBS" OFF)
|
||||
|
||||
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))
|
||||
# Generic variables shared by multiple libs that don't provide their own.
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_STATIC_LIBS ON CACHE BOOL "" FORCE)
|
||||
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
||||
endif()
|
||||
|
||||
if(NOT SAVETOOL_USE_SYSTEM_SDL2)
|
||||
set(DIRECTX OFF CACHE BOOL "" FORCE) # We use OpenGL.
|
||||
set(SDL_ATOMIC OFF CACHE BOOL "" FORCE)
|
||||
set(SDL_CPUINFO OFF CACHE BOOL "" FORCE)
|
||||
|
@ -49,6 +53,19 @@ 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)
|
||||
endif(NOT SAVETOOL_USE_SYSTEM_SDL2)
|
||||
|
||||
if(NOT SAVETOOL_USE_SYSTEM_CORRADE_MAGNUM)
|
||||
set(CORRADE_BUILD_DEPRECATED OFF CACHE BOOL "" FORCE)
|
||||
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(MAGNUM_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
||||
set(MAGNUM_BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
|
||||
|
@ -79,7 +96,9 @@ add_subdirectory(third-party/magnum EXCLUDE_FROM_ALL)
|
|||
set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third-party/imgui)
|
||||
set(MAGNUM_WITH_IMGUI ON CACHE BOOL "" FORCE)
|
||||
add_subdirectory(third-party/magnum-integration EXCLUDE_FROM_ALL)
|
||||
endif(NOT SAVETOOL_USE_SYSTEM_CORRADE_MAGNUM)
|
||||
|
||||
if(NOT SAVETOOL_USE_SYSTEM_LIBZIP)
|
||||
set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
|
||||
set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE)
|
||||
set(ENABLE_MBEDTLS OFF CACHE BOOL "" FORCE)
|
||||
|
@ -93,15 +112,17 @@ 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)
|
||||
|
||||
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
|
||||
if(NOT SAVETOOL_USE_SYSTEM_LIBCURL)
|
||||
set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE)
|
||||
set(BUILD_SHARED_LIBS 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)
|
||||
|
@ -114,5 +135,6 @@ 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)
|
||||
|
|
|
@ -13,7 +13,7 @@ launch `MassBuilderSaveTool-<version>.exe`.
|
|||
|
||||
1. Install the 64-bit (`x86_64`) version of [MSYS2](https://www.msys2.org/) in its default path (`C:\msys64`), and
|
||||
update it fully.
|
||||
2. Run `pacman -S git mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-ninja`.
|
||||
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`.
|
||||
5. Type `cmake -GNinja -DCMAKE_BUILD_TYPE=Release ..`
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
# components, which are:
|
||||
#
|
||||
# Containers - Containers library
|
||||
# Interconnect - Interconnect library
|
||||
# Main - Main library
|
||||
# PluginManager - PluginManager library
|
||||
# TestSuite - TestSuite library
|
||||
# Utility - Utility library
|
||||
|
@ -68,7 +70,7 @@
|
|||
# mode for MSVC 2017
|
||||
# CORRADE_MSVC2015_COMPATIBILITY - Defined if compiled with compatibility
|
||||
# mode for MSVC 2015
|
||||
# CORRADE_BUILD_DEPRECATED - Defined if compiled with deprecated APIs
|
||||
# CORRADE_BUILD_DEPRECATED - Defined if compiled with deprecated features
|
||||
# included
|
||||
# CORRADE_BUILD_STATIC - Defined if compiled as static libraries.
|
||||
# Default are shared libraries.
|
||||
|
@ -78,6 +80,9 @@
|
|||
# CORRADE_BUILD_MULTITHREADED - Defined if compiled in a way that makes it
|
||||
# possible to safely use certain Corrade features simultaneously in multiple
|
||||
# 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
|
||||
# (Linux, BSD, macOS)
|
||||
# CORRADE_TARGET_APPLE - Defined if compiled for Apple platforms
|
||||
|
@ -98,6 +103,8 @@
|
|||
# CORRADE_TARGET_MSVC - Defined if compiling with MSVC or Clang with
|
||||
# a MSVC frontend
|
||||
# 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
|
||||
# doesn't support dynamic plugin loading due to platform limitations
|
||||
# CORRADE_TESTSUITE_TARGET_XCTEST - Defined if TestSuite is targeting Xcode
|
||||
|
@ -115,6 +122,7 @@
|
|||
# automatically)
|
||||
# CORRADE_TESTSUITE_XCTEST_RUNNER - Path to XCTestRunner.mm.in 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
|
||||
# for targets with :prop_tgt:`CORRADE_USE_PEDANTIC_FLAGS` enabled
|
||||
# CORRADE_PEDANTIC_COMPILER_DEFINITIONS - List of pedantic compiler
|
||||
|
@ -208,7 +216,7 @@
|
|||
# <metadata file>
|
||||
# <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
|
||||
# :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
|
||||
|
@ -264,7 +272,7 @@
|
|||
# This file is part of Corrade.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
|
@ -317,6 +325,7 @@ set(_corradeFlags
|
|||
BUILD_STATIC
|
||||
BUILD_STATIC_UNIQUE_GLOBALS
|
||||
BUILD_MULTITHREADED
|
||||
BUILD_CPU_RUNTIME_DISPATCH
|
||||
TARGET_UNIX
|
||||
TARGET_APPLE
|
||||
TARGET_IOS
|
||||
|
@ -325,10 +334,12 @@ set(_corradeFlags
|
|||
TARGET_WINDOWS_RT
|
||||
TARGET_EMSCRIPTEN
|
||||
TARGET_ANDROID
|
||||
# TARGET_X86 etc and TARGET_LIBCXX are not exposed to CMake as the meaning
|
||||
# is unclear on platforms with multi-arch binaries or when mixing different
|
||||
# STL implementations. TARGET_GCC etc are figured out via UseCorrade.cmake,
|
||||
# as the compiler can be different when compiling the lib & when using it.
|
||||
# TARGET_X86 etc, TARGET_32BIT, TARGET_BIG_ENDIAN and TARGET_LIBCXX etc.
|
||||
# are not exposed to CMake as the meaning is unclear on platforms with
|
||||
# multi-arch binaries or when mixing different STL implementations.
|
||||
# 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
|
||||
TESTSUITE_TARGET_XCTEST
|
||||
UTILITY_USE_ANSI_COLORS)
|
||||
|
@ -406,6 +417,8 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
|
|||
if(TARGET Corrade::${_component})
|
||||
set(Corrade_${_component}_FOUND TRUE)
|
||||
else()
|
||||
unset(Corrade_${_component}_FOUND)
|
||||
|
||||
# Library (and not 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)
|
||||
|
@ -461,8 +474,9 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
|
|||
# Interconnect library
|
||||
if(_component STREQUAL Interconnect)
|
||||
# Disable /OPT:ICF on MSVC, which merges functions with identical
|
||||
# contents and thus breaks signal comparison
|
||||
if(CORRADE_TARGET_WINDOWS AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
# contents and thus breaks signal comparison. Same case is for
|
||||
# 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)
|
||||
set_property(TARGET Corrade::${_component} PROPERTY
|
||||
INTERFACE_LINK_LIBRARIES "-OPT:NOICF,REF")
|
||||
|
@ -496,25 +510,33 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
|
|||
elseif(_component STREQUAL PluginManager)
|
||||
# -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)
|
||||
# XCTest runner file
|
||||
if(CORRADE_TESTSUITE_TARGET_XCTEST)
|
||||
find_file(CORRADE_TESTSUITE_XCTEST_RUNNER XCTestRunner.mm.in
|
||||
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
|
||||
elseif(CORRADE_TARGET_ANDROID)
|
||||
find_file(CORRADE_TESTSUITE_ADB_RUNNER AdbRunner.sh
|
||||
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
|
||||
elseif(CORRADE_TARGET_EMSCRIPTEN)
|
||||
find_file(CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER EmscriptenRunner.html.in
|
||||
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()
|
||||
|
||||
# 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
|
||||
INTERFACE_LINK_LIBRARIES "log")
|
||||
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()
|
||||
|
||||
# Find library includes
|
||||
|
@ -559,13 +590,16 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
|
|||
endforeach()
|
||||
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))
|
||||
set(Corrade_${_component}_FOUND TRUE)
|
||||
else()
|
||||
set(Corrade_${_component}_FOUND FALSE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# 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.
|
||||
elseif(NOT _component IN_LIST _CORRADE_IMPLICITLY_ENABLED_COMPONENTS)
|
||||
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
|
||||
# misleading.
|
||||
else()
|
||||
|
@ -606,9 +640,6 @@ find_package_handle_standard_args(Corrade REQUIRED_VARS
|
|||
CORRADE_INCLUDE_DIR
|
||||
_CORRADE_MODULE_DIR
|
||||
_CORRADE_CONFIGURE_FILE
|
||||
${CORRADE_TESTSUITE_XCTEST_RUNNER_NEEDED}
|
||||
${CORRADE_TESTSUITE_ADB_RUNNER_NEEDED}
|
||||
${CORRADE_TESTSUITE_EMSCRIPTEN_RUNNER_NEEDED}
|
||||
HANDLE_COMPONENTS
|
||||
${_CORRADE_REASON_FAILURE_MESSAGE})
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
# This file is part of Magnum.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
# Audio - Audio library
|
||||
# DebugTools - DebugTools library
|
||||
# GL - GL library
|
||||
# MaterialTools - MaterialTools library
|
||||
# MeshTools - MeshTools library
|
||||
# Primitives - Primitives library
|
||||
# SceneGraph - SceneGraph library
|
||||
|
@ -78,7 +79,6 @@
|
|||
# WindowlessGlxApplication - Windowless GLX application
|
||||
# WindowlessIosApplication - Windowless iOS application
|
||||
# WindowlessWglApplication - Windowless WGL application
|
||||
# WindowlessWindowsEglApplication - Windowless Windows/EGL application
|
||||
# CglContext - CGL context
|
||||
# EglContext - EGL context
|
||||
# GlxContext - GLX context
|
||||
|
@ -128,19 +128,18 @@
|
|||
#
|
||||
# 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
|
||||
# MAGNUM_BUILD_STATIC - Defined if compiled as static libraries
|
||||
# MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS - Defined if static libraries keep the
|
||||
# globals unique even across different shared libraries
|
||||
# MAGNUM_TARGET_GL - Defined if compiled with OpenGL interop
|
||||
# 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_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
|
||||
#
|
||||
# The following variables are provided for backwards compatibility purposes
|
||||
|
@ -149,6 +148,12 @@
|
|||
#
|
||||
# MAGNUM_BUILD_MULTITHREADED - Alias to CORRADE_BUILD_MULTITHREADED. Use
|
||||
# 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:
|
||||
#
|
||||
|
@ -159,6 +164,7 @@
|
|||
# MAGNUM_*_LIBRARY - Component libraries (w/o dependencies)
|
||||
# MAGNUM_*_LIBRARY_DEBUG - Debug 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_LIBRARY_INSTALL_DIR - Library installation directory
|
||||
# MAGNUM_DATA_INSTALL_DIR - Data installation directory
|
||||
|
@ -202,7 +208,7 @@
|
|||
# This file is part of Magnum.
|
||||
#
|
||||
# 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
|
||||
# copy of this software and associated documentation files (the "Software"),
|
||||
|
@ -223,18 +229,37 @@
|
|||
# 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
|
||||
set(_MAGNUM_CORRADE_DEPENDENCIES )
|
||||
foreach(_component ${Magnum_FIND_COMPONENTS})
|
||||
string(TOUPPER ${_component} _COMPONENT)
|
||||
foreach(_magnum_component ${Magnum_FIND_COMPONENTS})
|
||||
set(_MAGNUM_${_magnum_component}_CORRADE_DEPENDENCIES )
|
||||
|
||||
# Unrolling the transitive dependencies here so this doesn't need to be
|
||||
# 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)$")
|
||||
set(_MAGNUM_${_COMPONENT}_CORRADE_DEPENDENCIES PluginManager)
|
||||
if(_magnum_component MATCHES "^(Audio|DebugTools|MeshTools|Primitives|SceneTools|ShaderTools|Text|TextureTools|Trade|.+Importer|.+ImageConverter|.+Font|.+ShaderConverter)$")
|
||||
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()
|
||||
|
||||
list(APPEND _MAGNUM_CORRADE_DEPENDENCIES ${_MAGNUM_${_COMPONENT}_CORRADE_DEPENDENCIES})
|
||||
list(APPEND _MAGNUM_CORRADE_DEPENDENCIES ${_MAGNUM_${_magnum_component}_CORRADE_DEPENDENCIES})
|
||||
endforeach()
|
||||
find_package(Corrade REQUIRED Utility ${_MAGNUM_CORRADE_DEPENDENCIES})
|
||||
|
||||
|
@ -268,10 +293,8 @@ set(_magnumFlags
|
|||
TARGET_GL
|
||||
TARGET_GLES
|
||||
TARGET_GLES2
|
||||
TARGET_GLES3
|
||||
TARGET_DESKTOP_GLES
|
||||
TARGET_WEBGL
|
||||
TARGET_HEADLESS
|
||||
TARGET_EGL
|
||||
TARGET_VK)
|
||||
foreach(_magnumFlag ${_magnumFlags})
|
||||
list(FIND _magnumConfigure "#define MAGNUM_${_magnumFlag}" _magnum_${_magnumFlag})
|
||||
|
@ -280,17 +303,23 @@ foreach(_magnumFlag ${_magnumFlags})
|
|||
endif()
|
||||
endforeach()
|
||||
|
||||
# For compatibility only, to be removed at some point
|
||||
if(MAGNUM_BUILD_DEPRECATED AND CORRADE_BUILD_MULTITHREADED)
|
||||
# For compatibility only, to be removed at some point. Refer to
|
||||
# src/Magnum/configure.h.cmake for the decision logic here.
|
||||
if(MAGNUM_BUILD_DEPRECATED)
|
||||
if(CORRADE_BUILD_MULTITHREADED)
|
||||
set(MAGNUM_BUILD_MULTITHREADED 1)
|
||||
endif()
|
||||
|
||||
# OpenGL library preference. Prefer to use GLVND, since that's the better
|
||||
# approach nowadays, but allow the users to override it from outside in case
|
||||
# it is broken for some reason (Nvidia drivers in Debian's testing (Buster) --
|
||||
# reported on 2019-04-09).
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.10 AND NOT OpenGL_GL_PREFERENCE)
|
||||
set(OpenGL_GL_PREFERENCE GLVND)
|
||||
if(NOT CORRADE_TARGET_IOS AND NOT CORRADE_TARGET_ANDROID AND NOT CORRADE_TARGET_EMSCRIPTEN AND NOT CORRADE_TARGET_WINDOWS_RT)
|
||||
if(NOT MAGNUM_TARGET_GLES AND MAGNUM_TARGET_EGL)
|
||||
set(MAGNUM_TARGET_HEADLESS 1)
|
||||
endif()
|
||||
if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_EGL)
|
||||
set(MAGNUM_TARGET_DESKTOP_GLES 1)
|
||||
endif()
|
||||
endif()
|
||||
if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_GLES2)
|
||||
set(MAGNUM_TARGET_GLES3 1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Base Magnum library
|
||||
|
@ -355,8 +384,8 @@ endif()
|
|||
# Component distinction (listing them explicitly to avoid mistakes with finding
|
||||
# components from other repositories)
|
||||
set(_MAGNUM_LIBRARY_COMPONENTS
|
||||
Audio DebugTools GL MeshTools Primitives SceneGraph SceneTools Shaders
|
||||
ShaderTools Text TextureTools Trade
|
||||
Audio DebugTools GL MaterialTools MeshTools Primitives SceneGraph
|
||||
SceneTools Shaders ShaderTools Text TextureTools Trade
|
||||
WindowlessEglApplication EglContext OpenGLTester)
|
||||
set(_MAGNUM_PLUGIN_COMPONENTS
|
||||
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)
|
||||
endif()
|
||||
if(CORRADE_TARGET_WINDOWS)
|
||||
list(APPEND _MAGNUM_LIBRARY_COMPONENTS WindowlessWglApplication WglContext WindowlessWindowsEglApplication)
|
||||
list(APPEND _MAGNUM_LIBRARY_COMPONENTS WindowlessWglApplication WglContext)
|
||||
endif()
|
||||
if(CORRADE_TARGET_UNIX OR CORRADE_TARGET_WINDOWS)
|
||||
list(APPEND _MAGNUM_EXECUTABLE_COMPONENTS fontconverter distancefieldconverter)
|
||||
|
@ -420,30 +449,24 @@ if(MAGNUM_TARGET_GL)
|
|||
set(_MAGNUM_DebugTools_GL_DEPENDENCY_IS_OPTIONAL ON)
|
||||
endif()
|
||||
|
||||
set(_MAGNUM_MaterialTools_DEPENDENCIES Trade)
|
||||
|
||||
set(_MAGNUM_MeshTools_DEPENDENCIES Trade)
|
||||
if(MAGNUM_TARGET_GL)
|
||||
list(APPEND _MAGNUM_MeshTools_DEPENDENCIES GL)
|
||||
endif()
|
||||
|
||||
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)
|
||||
elseif(CORRADE_TARGET_IOS)
|
||||
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)
|
||||
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)
|
||||
endif()
|
||||
elseif(CORRADE_TARGET_WINDOWS)
|
||||
if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES)
|
||||
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessWglApplication)
|
||||
else()
|
||||
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessWindowsEglApplication)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(_MAGNUM_Primitives_DEPENDENCIES MeshTools Trade)
|
||||
|
@ -492,7 +515,6 @@ set(_MAGNUM_WindowlessEglApplication_DEPENDENCIES GL)
|
|||
set(_MAGNUM_WindowlessGlxApplication_DEPENDENCIES GL)
|
||||
set(_MAGNUM_WindowlessIosApplication_DEPENDENCIES GL)
|
||||
set(_MAGNUM_WindowlessWglApplication_DEPENDENCIES GL)
|
||||
set(_MAGNUM_WindowlessWindowsEglApplication_DEPENDENCIES GL)
|
||||
set(_MAGNUM_XEglApplication_DEPENDENCIES GL)
|
||||
set(_MAGNUM_CglContext_DEPENDENCIES GL)
|
||||
set(_MAGNUM_EglContext_DEPENDENCIES GL)
|
||||
|
@ -680,7 +702,17 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
|||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
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
|
||||
elseif(_component STREQUAL GlfwApplication)
|
||||
|
@ -699,7 +731,7 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
|||
INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})
|
||||
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
|
||||
# our own EGL find module, which makes things simpler. The
|
||||
# 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_GL_PREFERENCE is explicitly set to LEGACY.
|
||||
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)
|
||||
if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)
|
||||
set_property(TARGET Magnum::${_component} APPEND
|
||||
PROPERTY INTERFACE_LINK_LIBRARIES OpenGL::GLX)
|
||||
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()
|
||||
|
||||
|
@ -736,9 +768,17 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
|||
elseif(CORRADE_TARGET_UNIX)
|
||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
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()
|
||||
|
||||
# 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
|
||||
# our own EGL find module, which makes things simpler. The
|
||||
# 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_GL_PREFERENCE is explicitly set to LEGACY.
|
||||
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)
|
||||
if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)
|
||||
set_property(TARGET Magnum::${_component} APPEND
|
||||
PROPERTY INTERFACE_LINK_LIBRARIES OpenGL::GLX)
|
||||
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()
|
||||
|
||||
|
@ -768,12 +808,19 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
|||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
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
|
||||
# OpenGL_OpenGL_FOUND, because that one is set also if GLVND is
|
||||
# *not* found. WTF. Also can't just check for
|
||||
# OPENGL_opengl_LIBRARY because that's set even if
|
||||
# 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)
|
||||
if(OPENGL_opengl_LIBRARY AND OpenGL_GL_PREFERENCE STREQUAL GLVND)
|
||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
|
@ -799,12 +846,6 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
|||
|
||||
# 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
|
||||
elseif(_component STREQUAL XEglApplication)
|
||||
find_package(EGL)
|
||||
|
@ -822,7 +863,7 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
|||
|
||||
# GLX context dependencies
|
||||
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
|
||||
# OpenGL_OpenGL_FOUND, because that one is set also if GLVND is
|
||||
# *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)
|
||||
find_package(OpenAL)
|
||||
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
|
||||
|
||||
# GL library
|
||||
elseif(_component STREQUAL GL)
|
||||
if(NOT MAGNUM_TARGET_GLES OR MAGNUM_TARGET_DESKTOP_GLES)
|
||||
# If the GLVND library (CMake 3.11+) was found, link to the
|
||||
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.10+) was found, link to the
|
||||
# imported target. Otherwise (and also on all systems except
|
||||
# Linux) link to the classic libGL. Can't use
|
||||
# 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)
|
||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
INTERFACE_LINK_LIBRARIES OpenGLES2::OpenGLES2)
|
||||
elseif(MAGNUM_TARGET_GLES3)
|
||||
else()
|
||||
find_package(OpenGLES3 REQUIRED)
|
||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
INTERFACE_LINK_LIBRARIES OpenGLES3::OpenGLES3)
|
||||
endif()
|
||||
|
||||
# MaterialTools library
|
||||
elseif(_component STREQUAL MaterialTools)
|
||||
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES PhongToPbrMetallicRoughness.h)
|
||||
|
||||
# MeshTools library
|
||||
elseif(_component STREQUAL MeshTools)
|
||||
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES CompressIndices.h)
|
||||
|
@ -904,26 +949,19 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
|||
|
||||
# No special setup for SceneGraph library
|
||||
|
||||
# ShaderTools library
|
||||
elseif(_component STREQUAL ShaderTools)
|
||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
INTERFACE_LINK_LIBRARIES Corrade::PluginManager)
|
||||
# SceneTools library
|
||||
elseif(_component STREQUAL SceneTools)
|
||||
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Hierarchy.h)
|
||||
|
||||
# No special setup for ShaderTools library
|
||||
# No special setup for Shaders library
|
||||
|
||||
# Text library
|
||||
elseif(_component STREQUAL Text)
|
||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
INTERFACE_LINK_LIBRARIES Corrade::PluginManager)
|
||||
# No special setup for Text library
|
||||
|
||||
# TextureTools library
|
||||
elseif(_component STREQUAL TextureTools)
|
||||
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Atlas.h)
|
||||
|
||||
# Trade library
|
||||
elseif(_component STREQUAL Trade)
|
||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
INTERFACE_LINK_LIBRARIES Corrade::PluginManager)
|
||||
# No special setup for Trade library
|
||||
|
||||
# Vk library
|
||||
elseif(_component STREQUAL Vk)
|
||||
|
@ -952,8 +990,13 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
|||
endif()
|
||||
|
||||
# Automatic import of static plugins. Skip in case the include dir was
|
||||
# not found -- that'll fail later with a proper message.
|
||||
if(_component IN_LIST _MAGNUM_PLUGIN_COMPONENTS AND _MAGNUM_${_COMPONENT}_INCLUDE_DIR)
|
||||
# not found -- that'll fail later with a proper message. Skip it also
|
||||
# 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
|
||||
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)
|
||||
|
@ -967,9 +1010,13 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
|
|||
# are optional dependencies, defer adding them to later once we know if
|
||||
# they were found or not.
|
||||
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
|
||||
INTERFACE_LINK_LIBRARIES Magnum::Magnum)
|
||||
set(_MAGNUM_${component}_OPTIONAL_DEPENDENCIES_TO_ADD )
|
||||
set(_MAGNUM_${_component}_OPTIONAL_DEPENDENCIES_TO_ADD )
|
||||
foreach(_dependency ${_MAGNUM_${_component}_DEPENDENCIES})
|
||||
if(NOT _MAGNUM_${_component}_${_dependency}_DEPENDENCY_IS_OPTIONAL)
|
||||
set_property(TARGET Magnum::${_component} APPEND PROPERTY
|
||||
|
@ -1031,20 +1078,6 @@ if(CORRADE_TARGET_EMSCRIPTEN)
|
|||
MAGNUM_EMSCRIPTENAPPLICATION_JS
|
||||
MAGNUM_WINDOWLESSEMSCRIPTENAPPLICATION_JS
|
||||
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()
|
||||
|
||||
# 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.
|
||||
elseif(NOT _component IN_LIST _MAGNUM_IMPLICITLY_ENABLED_COMPONENTS)
|
||||
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
|
||||
# misleading.
|
||||
else()
|
||||
|
@ -1271,3 +1304,6 @@ if(MAGNUM_PLUGINS_RELEASE_DIR)
|
|||
set(MAGNUM_PLUGINS_SCENECONVERTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/sceneconverters)
|
||||
set(MAGNUM_PLUGINS_AUDIOIMPORTER_RELEASE_DIR ${MAGNUM_PLUGINS_RELEASE_DIR}/audioimporters)
|
||||
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.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
# 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})
|
||||
endif()
|
||||
|
||||
# Global integration include dir
|
||||
find_path(MAGNUMINTEGRATION_INCLUDE_DIR Magnum
|
||||
# Global include dir that's unique to Magnum Integration. Often it will be
|
||||
# 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})
|
||||
mark_as_advanced(MAGNUMINTEGRATION_INCLUDE_DIR)
|
||||
|
||||
|
@ -314,7 +320,7 @@ if(NOT CMAKE_VERSION VERSION_LESS 3.16)
|
|||
# misleading messages.
|
||||
elseif(NOT _component IN_LIST _MAGNUMINTEGRATION_IMPLICITLY_ENABLED_COMPONENTS)
|
||||
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
|
||||
# misleading.
|
||||
else()
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
# This file is part of Magnum.
|
||||
#
|
||||
# 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>
|
||||
#
|
||||
# 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
|
||||
# the dylib first so it is preferred. Not sure how this maps to debug
|
||||
# config though :/
|
||||
NAMES SDL2-2.0 SDL2
|
||||
NAMES SDL2-2.0 SDL2 SDL2-static
|
||||
PATH_SUFFIXES ${_SDL2_LIBRARY_PATH_SUFFIX})
|
||||
find_library(SDL2_LIBRARY_DEBUG
|
||||
NAMES SDL2d
|
||||
NAMES SDL2d SDL2-staticd
|
||||
PATH_SUFFIXES ${_SDL2_LIBRARY_PATH_SUFFIX})
|
||||
# FPHSA needs one of the _DEBUG/_RELEASE variables to check that the
|
||||
# library was found -- using SDL_LIBRARY, which will get populated by
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,8 +14,6 @@
|
|||
// 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 "SaveTool.h"
|
||||
|
||||
#include <Corrade/Containers/ScopeGuard.h>
|
||||
#include <Corrade/Utility/Unicode.h>
|
||||
|
||||
|
@ -29,14 +27,18 @@
|
|||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <curl/curl.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};
|
||||
|
@ -45,20 +47,24 @@ extern const ImVec2 center_pivot = {0.5f, 0.5f};
|
|||
Utility::Tweakable tweak;
|
||||
#endif
|
||||
|
||||
SaveTool::SaveTool(const Arguments& arguments):
|
||||
namespace mbst {
|
||||
|
||||
Application::Application(const Arguments& arguments):
|
||||
Platform::Sdl2Application{arguments,
|
||||
Configuration{}.setTitle("M.A.S.S. Builder Save Tool " SAVETOOL_VERSION " (\"" SAVETOOL_CODENAME "\")")
|
||||
Configuration{}.setTitle("M.A.S.S. Builder Save Tool " SAVETOOL_VERSION_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::disable(GL::Renderer::Feature::FaceCulling);
|
||||
GL::Renderer::disable(GL::Renderer::Feature::DepthTest);
|
||||
GL::Renderer::setBlendFunction(GL::Renderer::BlendFunction::SourceAlpha,
|
||||
GL::Renderer::BlendFunction::OneMinusSourceAlpha);
|
||||
GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add,
|
||||
|
@ -78,9 +84,9 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
#endif
|
||||
|
||||
LOG_INFO("Registering custom events.");
|
||||
if((_initEventId = SDL_RegisterEvents(3)) == UnsignedInt(-1)) {
|
||||
if((_initEventId = SDL_RegisterEvents(3)) == std::uint32_t(-1)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
"SDL_RegisterEvents() failed in SaveTool::SaveTool(). Exiting...", window());
|
||||
"SDL_RegisterEvents() failed in Application::SaveTool(). Exiting...", window());
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
@ -99,24 +105,10 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
|
||||
initialiseGui();
|
||||
|
||||
if(!initialiseToolDirectories()) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app",
|
||||
_lastError.data(), window());
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!findGameDataDirectory()) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app",
|
||||
_lastError.data(), window());
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
checkGameState();
|
||||
_gameCheckTimerId = SDL_AddTimer(2000,
|
||||
[](UnsignedInt interval, void* param)->UnsignedInt{
|
||||
static_cast<SaveTool*>(param)->checkGameState();
|
||||
[](std::uint32_t interval, void* param)->std::uint32_t{
|
||||
static_cast<Application*>(param)->checkGameState();
|
||||
return interval;
|
||||
}, this);
|
||||
if(_gameCheckTimerId == 0) {
|
||||
|
@ -128,9 +120,7 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
|
||||
initialiseConfiguration();
|
||||
|
||||
LOG_INFO("Initialising update checker.");
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
if(_checkUpdatesOnStartup) {
|
||||
if(conf().checkUpdatesOnStartup()) {
|
||||
_queue.addToast(Toast::Type::Default, "Checking for updates..."_s);
|
||||
_updateThread = std::thread{[this]{ checkForUpdates(); }};
|
||||
}
|
||||
|
@ -141,7 +131,7 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
GL::DebugOutput::setEnabled(GL::DebugOutput::Source::Api, GL::DebugOutput::Type::Other, {131185}, false);
|
||||
}
|
||||
|
||||
if(_skipDisclaimer) {
|
||||
if(conf().skipDisclaimer()) {
|
||||
_uiState = UiState::Initialising;
|
||||
_initThread = std::thread{[this]{ initialiseManager(); }};
|
||||
}
|
||||
|
@ -149,29 +139,20 @@ SaveTool::SaveTool(const Arguments& arguments):
|
|||
_timeline.start();
|
||||
}
|
||||
|
||||
SaveTool::~SaveTool() {
|
||||
Application::~Application() {
|
||||
LOG_INFO("Cleaning up.");
|
||||
|
||||
LOG_INFO("Shutting libcurl down.");
|
||||
curl_global_cleanup();
|
||||
|
||||
SDL_RemoveTimer(_gameCheckTimerId);
|
||||
|
||||
LOG_INFO("Saving the configuration.");
|
||||
|
||||
_conf.setValue("cheat_mode"_s, _cheatMode);
|
||||
_conf.setValue("advanced_mode"_s, _advancedMode);
|
||||
_conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup);
|
||||
_conf.setValue("skip_disclaimer"_s, _skipDisclaimer);
|
||||
_conf.setValue("swap_interval"_s, _swapInterval);
|
||||
_conf.setValue("fps_cap"_s, _fpsCap);
|
||||
|
||||
_conf.save();
|
||||
conf().save();
|
||||
|
||||
LOG_INFO("Exiting.");
|
||||
}
|
||||
|
||||
void SaveTool::drawEvent() {
|
||||
void
|
||||
Application::drawEvent() {
|
||||
#ifdef SAVETOOL_DEBUG_BUILD
|
||||
tweak.update();
|
||||
#endif
|
||||
|
@ -182,8 +163,8 @@ void SaveTool::drawEvent() {
|
|||
|
||||
swapBuffers();
|
||||
|
||||
if(_swapInterval == 0 && _fpsCap < 301.0f) {
|
||||
while(_timeline.currentFrameDuration() < (1.0f / _fpsCap));
|
||||
if(conf().swapInterval() == 0 && conf().fpsCap() < 301.0f) {
|
||||
while(_timeline.currentFrameDuration() < (1.0f / conf().fpsCap()));
|
||||
}
|
||||
|
||||
redraw();
|
||||
|
@ -191,45 +172,54 @@ void SaveTool::drawEvent() {
|
|||
_timeline.nextFrame();
|
||||
}
|
||||
|
||||
void SaveTool::viewportEvent(ViewportEvent& event) {
|
||||
void
|
||||
Application::viewportEvent(ViewportEvent& event) {
|
||||
GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()});
|
||||
|
||||
const Vector2 size = Vector2{windowSize()}/dpiScaling();
|
||||
const auto size = Vector2{windowSize()}/dpiScaling();
|
||||
_imgui.relayout(size, windowSize(), framebufferSize());
|
||||
}
|
||||
|
||||
void SaveTool::keyPressEvent(KeyEvent& event) {
|
||||
void
|
||||
Application::keyPressEvent(KeyEvent& event) {
|
||||
if(_imgui.handleKeyPressEvent(event)) return;
|
||||
}
|
||||
|
||||
void SaveTool::keyReleaseEvent(KeyEvent& event) {
|
||||
void
|
||||
Application::keyReleaseEvent(KeyEvent& event) {
|
||||
if(_imgui.handleKeyReleaseEvent(event)) return;
|
||||
}
|
||||
|
||||
void SaveTool::mousePressEvent(MouseEvent& event) {
|
||||
void
|
||||
Application::mousePressEvent(MouseEvent& event) {
|
||||
if(_imgui.handleMousePressEvent(event)) return;
|
||||
}
|
||||
|
||||
void SaveTool::mouseReleaseEvent(MouseEvent& event) {
|
||||
void
|
||||
Application::mouseReleaseEvent(MouseEvent& event) {
|
||||
if(_imgui.handleMouseReleaseEvent(event)) return;
|
||||
}
|
||||
|
||||
void SaveTool::mouseMoveEvent(MouseMoveEvent& event) {
|
||||
void
|
||||
Application::mouseMoveEvent(MouseMoveEvent& event) {
|
||||
if(_imgui.handleMouseMoveEvent(event)) return;
|
||||
}
|
||||
|
||||
void SaveTool::mouseScrollEvent(MouseScrollEvent& event) {
|
||||
void
|
||||
Application::mouseScrollEvent(MouseScrollEvent& event) {
|
||||
if(_imgui.handleMouseScrollEvent(event)) {
|
||||
event.setAccepted();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void SaveTool::textInputEvent(TextInputEvent& event) {
|
||||
void
|
||||
Application::textInputEvent(TextInputEvent& event) {
|
||||
if(_imgui.handleTextInputEvent(event)) return;
|
||||
}
|
||||
|
||||
void SaveTool::anyEvent(SDL_Event& event) {
|
||||
void
|
||||
Application::anyEvent(SDL_Event& event) {
|
||||
if(event.type == _initEventId) {
|
||||
initEvent(event);
|
||||
}
|
||||
|
@ -241,7 +231,8 @@ void SaveTool::anyEvent(SDL_Event& event) {
|
|||
}
|
||||
}
|
||||
|
||||
void SaveTool::drawImGui() {
|
||||
void
|
||||
Application::drawImGui() {
|
||||
_imgui.newFrame();
|
||||
|
||||
if(ImGui::GetIO().WantTextInput && !isTextInputActive()) {
|
||||
|
@ -258,7 +249,8 @@ void SaveTool::drawImGui() {
|
|||
_imgui.drawFrame();
|
||||
}
|
||||
|
||||
void SaveTool::drawGui() {
|
||||
void
|
||||
Application::drawGui() {
|
||||
drawMainMenu();
|
||||
|
||||
switch(_uiState) {
|
||||
|
@ -300,8 +292,9 @@ void SaveTool::drawGui() {
|
|||
_queue.draw(windowSize());
|
||||
}
|
||||
|
||||
void SaveTool::drawDisclaimer() {
|
||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
||||
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|
|
||||
|
@ -330,7 +323,13 @@ void SaveTool::drawDisclaimer() {
|
|||
|
||||
ImGui::Bullet();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted("This version of the application was tested on M.A.S.S. Builder early access version " SUPPORTED_GAME_VERSION ". It may or may not work with other versions of the game.");
|
||||
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();
|
||||
|
||||
|
@ -344,7 +343,9 @@ void SaveTool::drawDisclaimer() {
|
|||
ImGui::Dummy({0.0f, 5.0f});
|
||||
ImGui::Dummy({4.0f, 0.0f});
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("Don't show next time", &_skipDisclaimer);
|
||||
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")) {
|
||||
|
@ -359,8 +360,9 @@ void SaveTool::drawDisclaimer() {
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
void SaveTool::drawInitialisation() {
|
||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
||||
void
|
||||
Application::drawInitialisation() {
|
||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f} / dpiScaling()}, ImGuiCond_Always, center_pivot);
|
||||
|
||||
if(ImGui::BeginPopupModal("##InitPopup", nullptr,
|
||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar))
|
||||
|
@ -372,7 +374,8 @@ void SaveTool::drawInitialisation() {
|
|||
ImGui::OpenPopup("##InitPopup");
|
||||
}
|
||||
|
||||
void SaveTool::drawGameState() {
|
||||
void
|
||||
Application::drawGameState() {
|
||||
ImGui::TextUnformatted("Game state:");
|
||||
ImGui::SameLine();
|
||||
{
|
||||
|
@ -393,18 +396,19 @@ void SaveTool::drawGameState() {
|
|||
}
|
||||
}
|
||||
|
||||
void SaveTool::drawHelpMarker(Containers::StringView text, Float wrap_pos) {
|
||||
void
|
||||
Application::drawHelpMarker(Containers::StringView text, float wrap_pos) {
|
||||
ImGui::TextUnformatted(ICON_FA_QUESTION_CIRCLE);
|
||||
drawTooltip(text, wrap_pos);
|
||||
}
|
||||
|
||||
void SaveTool::drawTooltip(Containers::StringView text, Float wrap_pos) {
|
||||
if(ImGui::IsItemHovered()){
|
||||
ImGui::BeginTooltip();
|
||||
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.data());
|
||||
ImGui::TextUnformatted(text.cbegin(), text.cend());
|
||||
if(wrap_pos > 0.0f) {
|
||||
ImGui::PopTextWrapPos();
|
||||
}
|
||||
|
@ -412,11 +416,121 @@ void SaveTool::drawTooltip(Containers::StringView text, Float wrap_pos) {
|
|||
}
|
||||
}
|
||||
|
||||
void SaveTool::openUri(Containers::StringView uri) {
|
||||
ShellExecuteW(nullptr, nullptr, Utility::Unicode::widen(uri.data()), nullptr, nullptr, SW_SHOWDEFAULT);
|
||||
bool
|
||||
Application::drawCheckbox(Containers::StringView label, bool value) {
|
||||
return ImGui::Checkbox(label.data(), &value);
|
||||
}
|
||||
|
||||
void SaveTool::checkGameState() {
|
||||
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;
|
||||
|
||||
|
@ -437,3 +551,5 @@ void SaveTool::checkGameState() {
|
|||
_gameState = GameState::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,12 +16,12 @@
|
|||
// 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/Configuration.h>
|
||||
#include <Corrade/Utility/Resource.h>
|
||||
#ifdef SAVETOOL_DEBUG_BUILD
|
||||
#include <Corrade/Utility/Tweakable.h>
|
||||
|
@ -34,13 +34,15 @@
|
|||
#include <SDL_timer.h>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include <efsw/efsw.hpp>
|
||||
|
||||
#include "../ProfileManager/ProfileManager.h"
|
||||
#include "../MassManager/MassManager.h"
|
||||
#include "../Managers/BackupManager.h"
|
||||
#include "../Managers/MassManager.h"
|
||||
#include "../Managers/ProfileManager.h"
|
||||
#include "../Managers/StagedMassManager.h"
|
||||
#include "../ToastQueue/ToastQueue.h"
|
||||
#include "../UpdateChecker/UpdateChecker.h"
|
||||
|
||||
#ifdef SAVETOOL_DEBUG_BUILD
|
||||
#define tw CORRADE_TWEAKABLE
|
||||
|
@ -50,17 +52,19 @@ using namespace Corrade;
|
|||
using namespace Containers::Literals;
|
||||
using namespace Magnum;
|
||||
|
||||
class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener {
|
||||
public:
|
||||
explicit SaveTool(const Arguments& arguments);
|
||||
namespace mbst {
|
||||
|
||||
~SaveTool() override;
|
||||
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;
|
||||
std::string old_filename) override;
|
||||
|
||||
private:
|
||||
// Events
|
||||
|
@ -78,20 +82,15 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
|
||||
void anyEvent(SDL_Event& event) override;
|
||||
|
||||
enum InitStatus: Int {
|
||||
enum InitStatus: std::int32_t {
|
||||
InitSuccess,
|
||||
ProfileManagerFailure
|
||||
};
|
||||
void initEvent(SDL_Event& event);
|
||||
|
||||
enum UpdateCheckStatus : Int {
|
||||
CurlInitFailed = 0,
|
||||
CurlError = 1,
|
||||
CurlTimeout = 2,
|
||||
};
|
||||
void updateCheckEvent(SDL_Event& event);
|
||||
|
||||
enum FileEventType: Int {
|
||||
enum FileEventType: std::int32_t {
|
||||
FileAdded = efsw::Action::Add,
|
||||
FileDeleted = efsw::Action::Delete,
|
||||
FileModified = efsw::Action::Modified,
|
||||
|
@ -104,8 +103,6 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
void initialiseConfiguration();
|
||||
void initialiseGui();
|
||||
void initialiseManager();
|
||||
auto initialiseToolDirectories() -> bool;
|
||||
auto findGameDataDirectory() -> bool;
|
||||
void initialiseMassManager();
|
||||
void initialiseFileWatcher();
|
||||
|
||||
|
@ -117,21 +114,21 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
void drawInitialisation();
|
||||
|
||||
void drawProfileManager();
|
||||
auto drawBackupListPopup() -> ImGuiID;
|
||||
auto drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID;
|
||||
auto drawDeleteProfilePopup(std::size_t profile_index) -> ImGuiID;
|
||||
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();
|
||||
auto drawIntEditPopup(int* value_to_edit, int max) -> bool;
|
||||
auto drawRenamePopup(Containers::ArrayView<char> name_view) -> bool;
|
||||
bool drawIntEditPopup(int* value_to_edit, int max);
|
||||
bool drawRenamePopup(Containers::ArrayView<char> name_view);
|
||||
void drawGeneralInfo();
|
||||
void drawResearchInventory();
|
||||
template<typename Getter, typename Setter>
|
||||
void drawMaterialRow(Containers::StringView name, Int tier, Getter getter, Setter setter);
|
||||
void drawUnavailableMaterialRow(Containers::StringView name, Int tier);
|
||||
void drawMaterialRow(Containers::StringView name, std::int32_t tier, GameData::MaterialID id);
|
||||
void drawMassManager();
|
||||
auto drawDeleteMassPopup(int mass_index) -> ImGuiID;
|
||||
auto drawDeleteStagedMassPopup(Containers::StringView filename) -> ImGuiID;
|
||||
void drawDeleteMassPopup(int mass_index);
|
||||
void drawDeleteStagedMassPopup(Containers::StringView filename);
|
||||
|
||||
void drawMassViewer();
|
||||
void drawFrameInfo();
|
||||
|
@ -140,33 +137,55 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
void drawEyeColourPicker();
|
||||
void drawCustomFrameStyles();
|
||||
void drawArmour();
|
||||
void drawBLAttachment();
|
||||
void drawCustomArmourStyles();
|
||||
void drawWeapons();
|
||||
void drawWeaponCategory(Containers::StringView name, Containers::ArrayView<Weapon> weapons_view, bool& dirty,
|
||||
Containers::StringView payload_type, Containers::StringView payload_tooltip);
|
||||
void drawWeaponEditor(Weapon& weapon);
|
||||
void 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(Decal& decal);
|
||||
void drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<CustomStyle> style_view);
|
||||
auto getStyleName(Int id, Containers::ArrayView<CustomStyle> view) -> Containers::StringView;
|
||||
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(CustomStyle& style) -> DCSResult;
|
||||
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);
|
||||
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>
|
||||
auto drawUnsafeWidget(Functor func, Args... args) -> bool {
|
||||
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)...);
|
||||
|
@ -197,7 +216,6 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
|
||||
void checkForUpdates();
|
||||
|
||||
Utility::Configuration _conf{"MassBuilderSaveTool.ini"_s};
|
||||
Utility::Resource _rs{"assets"_s};
|
||||
|
||||
// GUI-related members
|
||||
|
@ -211,11 +229,11 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
MassViewer
|
||||
} _uiState{UiState::Disclaimer};
|
||||
|
||||
bool _aboutPopup{false};
|
||||
bool _aboutPopup = false;
|
||||
#ifdef SAVETOOL_DEBUG_BUILD
|
||||
bool _demoWindow{false};
|
||||
bool _styleEditor{false};
|
||||
bool _metricsWindow{false};
|
||||
bool _demoWindow = false;
|
||||
bool _styleEditor = false;
|
||||
bool _metricsWindow = false;
|
||||
#endif
|
||||
|
||||
ToastQueue _queue;
|
||||
|
@ -223,37 +241,29 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
std::thread _initThread;
|
||||
std::thread _updateThread;
|
||||
|
||||
UnsignedInt _initEventId;
|
||||
UnsignedInt _updateEventId;
|
||||
UnsignedInt _fileEventId;
|
||||
std::uint32_t _initEventId;
|
||||
std::uint32_t _updateEventId;
|
||||
std::uint32_t _fileEventId;
|
||||
|
||||
Containers::String _lastError;
|
||||
|
||||
Containers::String _gameDataDir;
|
||||
Containers::String _configDir;
|
||||
Containers::String _saveDir;
|
||||
Containers::String _screenshotsDir;
|
||||
|
||||
Containers::String _backupsDir;
|
||||
Containers::String _stagingDir;
|
||||
//Containers::String _armouryDir;
|
||||
//Containers::String _armoursDir;
|
||||
//Containers::String _weaponsDir;
|
||||
//Containers::String _stylesDir;
|
||||
|
||||
enum class GameState : UnsignedByte {
|
||||
enum class GameState : std::uint8_t {
|
||||
Unknown, NotRunning, Running
|
||||
} _gameState{GameState::Unknown};
|
||||
|
||||
SDL_TimerID _gameCheckTimerId = 0;
|
||||
|
||||
Containers::Pointer<ProfileManager> _profileManager;
|
||||
Profile* _currentProfile{nullptr};
|
||||
Containers::Pointer<Managers::ProfileManager> _profileManager;
|
||||
GameObjects::Profile* _currentProfile = nullptr;
|
||||
|
||||
Containers::Pointer<MassManager> _massManager;
|
||||
Mass* _currentMass{nullptr};
|
||||
Containers::Pointer<Managers::BackupManager> _backupManager;
|
||||
|
||||
Weapon* _currentWeapon = nullptr;
|
||||
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 {
|
||||
|
@ -262,36 +272,29 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
|
|||
};
|
||||
Containers::StaticArray<2, efsw::WatchID> _watchIDs;
|
||||
|
||||
int _swapInterval = 1;
|
||||
float _fpsCap = 60.0f;
|
||||
Containers::Optional<UpdateChecker> _checker{Containers::NullOpt};
|
||||
std::mutex _checkerMutex;
|
||||
|
||||
bool _skipDisclaimer{false};
|
||||
bool _checkUpdatesOnStartup{true};
|
||||
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;
|
||||
|
||||
bool _updateAvailable{false};
|
||||
Containers::String _latestVersion;
|
||||
Containers::String _releaseLink;
|
||||
Containers::String _downloadLink;
|
||||
|
||||
bool _modifiedBySaveTool{false};
|
||||
bool _jointsDirty{false};
|
||||
bool _stylesDirty{false};
|
||||
bool _eyeFlareDirty{false};
|
||||
Containers::StaticArray<38, Int> _selectedArmourDecals{ValueInit};
|
||||
Containers::StaticArray<38, Int> _selectedArmourAccessories{ValueInit};
|
||||
Int _selectedBLPlacement{0};
|
||||
Int _selectedWeaponPart{0};
|
||||
Int _selectedWeaponDecal{0};
|
||||
Int _selectedWeaponAccessory{0};
|
||||
bool _meleeDirty{false};
|
||||
bool _shieldsDirty{false};
|
||||
bool _bShootersDirty{false};
|
||||
bool _eShootersDirty{false};
|
||||
bool _bLaunchersDirty{false};
|
||||
bool _eLaunchersDirty{false};
|
||||
|
||||
bool _cheatMode{false};
|
||||
bool _advancedMode{false};
|
||||
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
|
||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -24,13 +24,13 @@
|
|||
#include <fileapi.h>
|
||||
#include <handleapi.h>
|
||||
|
||||
#include "SaveTool.h"
|
||||
#include "Application.h"
|
||||
|
||||
void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
||||
const std::string&,
|
||||
const std::string& filename,
|
||||
efsw::Action action,
|
||||
std::string old_filename)
|
||||
namespace mbst {
|
||||
|
||||
void
|
||||
Application::handleFileAction(efsw::WatchID watch_id, const std::string&, const std::string& filename,
|
||||
efsw::Action action, std::string old_filename)
|
||||
{
|
||||
SDL_Event event;
|
||||
SDL_zero(event);
|
||||
|
@ -48,7 +48,9 @@ void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
|||
return;
|
||||
} // TODO: actually do something when config files will finally be handled
|
||||
|
||||
if(!Utility::String::endsWith(filename, Utility::format("Profile{}.sav", _currentProfile->account()).data())) {
|
||||
if(!Utility::String::endsWith(filename, Utility::format("Profile{}.sav", _currentProfile->account()).data()) &&
|
||||
filename.find("Unit") == std::string::npos)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -60,19 +62,20 @@ void SaveTool::handleFileAction(efsw::WatchID watch_id,
|
|||
SDL_PushEvent(&event);
|
||||
}
|
||||
|
||||
void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
||||
void
|
||||
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) {
|
||||
_massManager->refreshStagedMass(filename);
|
||||
_stagedMassManager->refreshMass(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
Containers::String old_filename;
|
||||
|
||||
Int index = 0;
|
||||
Int old_index = 0;
|
||||
std::int32_t index = 0;
|
||||
std::int32_t old_index = 0;
|
||||
bool is_current_profile = filename == _currentProfile->filename();
|
||||
bool is_unit = filename.hasPrefix(_currentProfile->isDemo() ? "DemoUnit"_s : "Unit"_s);
|
||||
if(is_unit) {
|
||||
|
@ -81,7 +84,8 @@ void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
|||
}
|
||||
|
||||
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_filename[_currentProfile->isDemo() ? 9 : 5] - 0x30);
|
||||
}
|
||||
|
@ -123,8 +127,8 @@ void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
|||
}
|
||||
else {
|
||||
if(_modifiedBySaveTool && _currentMass->filename() == filename) {
|
||||
auto handle = CreateFileW(Utility::Unicode::widen(Containers::StringView{filename}), GENERIC_READ, 0,
|
||||
nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
auto handle = CreateFileW(Utility::Unicode::widen(Containers::StringView{filename}),
|
||||
GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if(handle && handle != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(handle);
|
||||
_modifiedBySaveTool = false;
|
||||
|
@ -148,3 +152,5 @@ void SaveTool::fileUpdateEvent(SDL_Event& event) {
|
|||
_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
|
||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -16,20 +16,27 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include <Corrade/Containers/ScopeGuard.h>
|
||||
#include <Corrade/Utility/Format.h>
|
||||
#include <Corrade/Utility/Path.h>
|
||||
|
||||
#include <Magnum/ImGuiIntegration/Integration.h>
|
||||
|
||||
#include <SDL_messagebox.h>
|
||||
|
||||
#include "../Configuration/Configuration.h"
|
||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||
#include "../Maps/LastMissionId.h"
|
||||
#include "../Maps/StoryProgress.h"
|
||||
#include "../GameData/LastMissionId.h"
|
||||
#include "../GameData/StoryProgress.h"
|
||||
|
||||
#include "SaveTool.h"
|
||||
#include "Application.h"
|
||||
|
||||
void SaveTool::drawManager() {
|
||||
namespace mbst {
|
||||
|
||||
void
|
||||
Application::drawManager() {
|
||||
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);
|
||||
if(!ImGui::Begin("##MainWindow", nullptr,
|
||||
ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_NoMove|
|
||||
|
@ -52,7 +59,7 @@ void SaveTool::drawManager() {
|
|||
|
||||
if(ImGui::BeginChild("##ProfileInfo",
|
||||
{ImGui::GetContentRegionAvail().x * 0.60f, 0.0f},
|
||||
true, ImGuiWindowFlags_MenuBar))
|
||||
ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar))
|
||||
{
|
||||
if(ImGui::BeginMenuBar()) {
|
||||
ImGui::TextUnformatted("Profile information");
|
||||
|
@ -79,7 +86,7 @@ void SaveTool::drawManager() {
|
|||
ImGui::SameLine();
|
||||
|
||||
if(ImGui::BeginChild("##MASSManager", {0.0f, 0.0f},
|
||||
true, ImGuiWindowFlags_MenuBar))
|
||||
ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar))
|
||||
{
|
||||
if(ImGui::BeginMenuBar()) {
|
||||
ImGui::TextUnformatted("M.A.S.S. management");
|
||||
|
@ -94,7 +101,8 @@ void SaveTool::drawManager() {
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
auto SaveTool::drawIntEditPopup(int* value_to_edit, int max) -> bool {
|
||||
bool
|
||||
Application::drawIntEditPopup(int* value_to_edit, int max) {
|
||||
bool apply = false;
|
||||
if(ImGui::BeginPopup("int_edit")) {
|
||||
ImGui::Text("Please enter a value between 0 and %i:", max);
|
||||
|
@ -103,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"
|
||||
"or click on it while holding Ctrl to edit the value directly.");
|
||||
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);
|
||||
ImGui::SameLine();
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button("Apply"); })) {
|
||||
|
@ -117,7 +125,8 @@ auto SaveTool::drawIntEditPopup(int* value_to_edit, int max) -> bool {
|
|||
return apply;
|
||||
}
|
||||
|
||||
auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
|
||||
bool
|
||||
Application::drawRenamePopup(Containers::ArrayView<char> name_view) {
|
||||
bool apply = false;
|
||||
if(ImGui::BeginPopup("name_edit")) {
|
||||
ImGui::TextUnformatted("Please enter a new name. Conditions:");
|
||||
|
@ -133,13 +142,15 @@ auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
|
|||
(name_view[0] != ' ' && name_view[len - 1] != ' ') ? ICON_FA_CHECK : ICON_FA_TIMES);
|
||||
|
||||
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 1;
|
||||
};
|
||||
|
||||
drawUnsafeWidget([](auto... args){ return ImGui::InputText("", args...); },
|
||||
drawUnsafeWidget([](auto... args){ return ImGui::InputText("##NameField", args...); },
|
||||
name_view.data(), name_view.size(),
|
||||
ImGuiInputTextFlags_CallbackCharFilter,
|
||||
callback, nullptr);
|
||||
|
@ -169,16 +180,17 @@ auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
|
|||
return apply;
|
||||
}
|
||||
|
||||
void SaveTool::drawGeneralInfo() {
|
||||
void
|
||||
Application::drawGeneralInfo() {
|
||||
if(!_currentProfile) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("Credits: %i", _currentProfile->credits());
|
||||
|
||||
auto it = std::find_if(story_progress.begin(), story_progress.end(),
|
||||
[this](const StoryProgressPoint& p){ return p.id == _currentProfile->storyProgress(); });
|
||||
if(it != story_progress.end())
|
||||
auto it = std::find_if(GameData::story_progress.begin(), GameData::story_progress.end(),
|
||||
[this](const GameData::StoryProgressPoint& p){ return p.id == _currentProfile->storyProgress(); });
|
||||
if(it != GameData::story_progress.end())
|
||||
{
|
||||
ImGui::TextUnformatted("Story progress:");
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.x / 4.0f);
|
||||
|
@ -193,8 +205,8 @@ void SaveTool::drawGeneralInfo() {
|
|||
ImGui::Text("Story progress: 0x%x", _currentProfile->storyProgress());
|
||||
}
|
||||
|
||||
if(mission_id_map.find(_currentProfile->lastMissionId()) != mission_id_map.cend()) {
|
||||
ImGui::Text("Last mission: %s", mission_id_map.at(_currentProfile->lastMissionId()).data());
|
||||
if(GameData::mission_id_map.find(_currentProfile->lastMissionId()) != GameData::mission_id_map.cend()) {
|
||||
ImGui::Text("Last mission: %s", GameData::mission_id_map.at(_currentProfile->lastMissionId()).data());
|
||||
}
|
||||
else if(_currentProfile->lastMissionId() == -1) {
|
||||
ImGui::TextUnformatted("Last mission: none");
|
||||
|
@ -205,7 +217,7 @@ void SaveTool::drawGeneralInfo() {
|
|||
drawTooltip("This is the last mission selected in the mission selection screen, not the last mission played.",
|
||||
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::Separator();
|
||||
|
@ -224,13 +236,13 @@ void SaveTool::drawGeneralInfo() {
|
|||
}
|
||||
}
|
||||
|
||||
if(!_cheatMode) {
|
||||
if(!conf().cheatMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
static Int credits;
|
||||
static std::int32_t credits;
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button("Edit credits"); })) {
|
||||
credits = _currentProfile->credits();
|
||||
ImGui::OpenPopup("int_edit");
|
||||
|
@ -251,7 +263,7 @@ void SaveTool::drawGeneralInfo() {
|
|||
if(_gameState != GameState::NotRunning) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
for(const auto& sp : story_progress) {
|
||||
for(const auto& sp : GameData::story_progress) {
|
||||
if(ImGui::BeginMenu(sp.chapter.data())) {
|
||||
if(!sp.after) {
|
||||
if(ImGui::MenuItem(sp.point.data())) {
|
||||
|
@ -277,7 +289,8 @@ void SaveTool::drawGeneralInfo() {
|
|||
}
|
||||
}
|
||||
|
||||
void SaveTool::drawResearchInventory() {
|
||||
void
|
||||
Application::drawResearchInventory() {
|
||||
if(!_currentProfile) {
|
||||
return;
|
||||
}
|
||||
|
@ -292,156 +305,90 @@ void SaveTool::drawResearchInventory() {
|
|||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::Text("Engine materials");
|
||||
ImGui::TextUnformatted("Engine materials");
|
||||
|
||||
drawMaterialRow("Verse steel", 1,
|
||||
[this]{ return _currentProfile->verseSteel(); },
|
||||
[this](Int amount){ return _currentProfile->setVerseSteel(amount); });
|
||||
drawMaterialRow("Undinium", 2,
|
||||
[this]{ return _currentProfile->undinium(); },
|
||||
[this](Int amount){ return _currentProfile->setUndinium(amount); });
|
||||
drawMaterialRow("Necrium alloy", 3,
|
||||
[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); });
|
||||
drawMaterialRow("Hallite fragma", 6,
|
||||
[this]{ return _currentProfile->halliteFragma(); },
|
||||
[this](Int amount){ return _currentProfile->setHalliteFragma(amount); });
|
||||
drawUnavailableMaterialRow("Unnoctinium", 7);
|
||||
drawMaterialRow("Verse steel", 1, GameData::MaterialID::VerseSteel);
|
||||
drawMaterialRow("Undinium", 2, GameData::MaterialID::Undinium);
|
||||
drawMaterialRow("Necrium alloy", 3, GameData::MaterialID::NecriumAlloy);
|
||||
drawMaterialRow("Lunarite", 4, GameData::MaterialID::Lunarite);
|
||||
drawMaterialRow("Asterite", 5, GameData::MaterialID::Asterite);
|
||||
drawMaterialRow("Hallite fragma", 6, GameData::MaterialID::HalliteFragma);
|
||||
drawMaterialRow("Unnoctinium", 7, GameData::MaterialID::Unnoctinium);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::Text("OS materials");
|
||||
ImGui::TextUnformatted("OS materials");
|
||||
|
||||
drawMaterialRow("Ednil", 1,
|
||||
[this]{ return _currentProfile->ednil(); },
|
||||
[this](Int amount){ return _currentProfile->setEdnil(amount); });
|
||||
drawMaterialRow("Nuflalt", 2,
|
||||
[this]{ return _currentProfile->nuflalt(); },
|
||||
[this](Int amount){ return _currentProfile->setNuflalt(amount); });
|
||||
drawMaterialRow("Aurelene", 3,
|
||||
[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); });
|
||||
drawMaterialRow("Nanoc", 6,
|
||||
[this]{ return _currentProfile->nanoc(); },
|
||||
[this](Int amount){ return _currentProfile->setNanoc(amount); });
|
||||
drawUnavailableMaterialRow("Abyssillite", 7);
|
||||
drawMaterialRow("Ednil", 1, GameData::MaterialID::Ednil);
|
||||
drawMaterialRow("Nuflalt", 2, GameData::MaterialID::Nuflalt);
|
||||
drawMaterialRow("Aurelene", 3, GameData::MaterialID::Aurelene);
|
||||
drawMaterialRow("Soldus", 4, GameData::MaterialID::Soldus);
|
||||
drawMaterialRow("Synthesized N", 5, GameData::MaterialID::SynthesisedN);
|
||||
drawMaterialRow("Nanoc", 6, GameData::MaterialID::Nanoc);
|
||||
drawMaterialRow("Abyssillite", 7, GameData::MaterialID::Abyssillite);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::Text("Architect materials");
|
||||
ImGui::TextUnformatted("Architect materials");
|
||||
|
||||
drawMaterialRow("Alcarbonite", 1,
|
||||
[this]{ return _currentProfile->alcarbonite(); },
|
||||
[this](Int amount){ return _currentProfile->setAlcarbonite(amount); });
|
||||
drawMaterialRow("Keripehene", 2,
|
||||
[this]{ return _currentProfile->keriphene(); },
|
||||
[this](Int amount){ return _currentProfile->setKeriphene(amount); });
|
||||
drawMaterialRow("Nitinol-CM", 3,
|
||||
[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); });
|
||||
drawMaterialRow("Cosmium", 6,
|
||||
[this]{ return _currentProfile->cosmium(); },
|
||||
[this](Int amount){ return _currentProfile->setCosmium(amount); });
|
||||
drawUnavailableMaterialRow("Purified quarkium", 7);
|
||||
drawMaterialRow("Alcarbonite", 1, GameData::MaterialID::Alcarbonite);
|
||||
drawMaterialRow("Keriphene", 2, GameData::MaterialID::Keriphene);
|
||||
drawMaterialRow("Nitinol-CM", 3, GameData::MaterialID::NitinolCM);
|
||||
drawMaterialRow("Quarkium", 4, GameData::MaterialID::Quarkium);
|
||||
drawMaterialRow("Alterene", 5, GameData::MaterialID::Alterene);
|
||||
drawMaterialRow("Cosmium", 6, GameData::MaterialID::Cosmium);
|
||||
drawMaterialRow("Purified quarkium", 7, GameData::MaterialID::PurifiedQuarkium);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::Text("Quark data");
|
||||
ImGui::TextUnformatted("Quark data");
|
||||
|
||||
drawMaterialRow("Mixed composition", 1,
|
||||
[this]{ return _currentProfile->mixedComposition(); },
|
||||
[this](Int amount){ return _currentProfile->setMixedComposition(amount); });
|
||||
drawMaterialRow("Void residue", 2,
|
||||
[this]{ return _currentProfile->voidResidue(); },
|
||||
[this](Int amount){ return _currentProfile->setVoidResidue(amount); });
|
||||
drawMaterialRow("Muscular construction", 3,
|
||||
[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); });
|
||||
drawMaterialRow("Isolated void particle", 6,
|
||||
[this]{ return _currentProfile->isolatedVoidParticle(); },
|
||||
[this](Int amount){ return _currentProfile->setIsolatedVoidParticle(amount); });
|
||||
drawUnavailableMaterialRow("Weaponised physiology", 7);
|
||||
drawMaterialRow("Mixed composition", 1, GameData::MaterialID::MixedComposition);
|
||||
drawMaterialRow("Void residue", 2, GameData::MaterialID::VoidResidue);
|
||||
drawMaterialRow("Muscular construction", 3, GameData::MaterialID::MuscularConstruction);
|
||||
drawMaterialRow("Mineral exoskeletology", 4, GameData::MaterialID::MineralExoskeletology);
|
||||
drawMaterialRow("Carbonized skin", 5, GameData::MaterialID::CarbonisedSkin);
|
||||
drawMaterialRow("Isolated void particle", 6, GameData::MaterialID::IsolatedVoidParticle);
|
||||
drawMaterialRow("Weaponised physiology", 7, GameData::MaterialID::WeaponisedPhysiology);
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Getter, typename Setter>
|
||||
void SaveTool::drawMaterialRow(Containers::StringView name, Int tier, Getter getter, Setter setter) {
|
||||
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.");
|
||||
|
||||
void
|
||||
Application::drawMaterialRow(Containers::StringView name, std::int32_t tier, GameData::MaterialID id) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::Text("T%i", tier);
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::TextUnformatted(name.data());
|
||||
ImGui::TextUnformatted(name.cbegin(), name.cend());
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
if(getter() != -1) {
|
||||
ImGui::Text("%i", getter());
|
||||
if(_cheatMode) {
|
||||
ImGui::Text("%i", _currentProfile->material(id));
|
||||
if(conf().cheatMode()) {
|
||||
ImGui::TableSetColumnIndex(3);
|
||||
ImGui::PushID(name.data());
|
||||
static Int var = 0;
|
||||
static std::int32_t var = 0;
|
||||
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_EDIT)) {
|
||||
(var) = getter();
|
||||
var = _currentProfile->material(id);
|
||||
ImGui::OpenPopup("int_edit");
|
||||
}
|
||||
drawTooltip("Edit");
|
||||
if(drawIntEditPopup(&(var), 9999)) {
|
||||
if(!setter(var)) {
|
||||
if(drawIntEditPopup(&var, 9999)) {
|
||||
if(!_currentProfile->setMaterial(id, var)) {
|
||||
_queue.addToast(Toast::Type::Error, _currentProfile->lastError());
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
else {
|
||||
ImGui::TextDisabled("Not found in the save file");
|
||||
}
|
||||
}
|
||||
|
||||
void SaveTool::drawUnavailableMaterialRow(Containers::StringView name, Int tier) {
|
||||
ImGui::TableNextRow();
|
||||
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() {
|
||||
void
|
||||
Application::drawMassManager() {
|
||||
if(!_massManager) {
|
||||
return;
|
||||
}
|
||||
|
||||
static int mass_to_delete = 0;
|
||||
static ImGuiID mass_deletion_popup_ID = drawDeleteMassPopup(mass_to_delete);
|
||||
|
||||
if(ImGui::BeginTable("##HangarsTable", 4,
|
||||
ImGuiTableFlags_BordersOuter|ImGuiTableFlags_RowBg|ImGuiTableFlags_ScrollY,
|
||||
|
@ -470,7 +417,7 @@ void SaveTool::drawMassManager() {
|
|||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::Selectable(Utility::format("{:.2d}", i + 1).data(),
|
||||
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))
|
||||
{
|
||||
drag_drop_index = i;
|
||||
|
@ -484,21 +431,21 @@ void SaveTool::drawMassManager() {
|
|||
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("StagedMass")) {
|
||||
if(payload->DataSize != sizeof(Containers::String)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
||||
"payload->DataSize != sizeof(Containers::String) in SaveTool::drawMassManager()",
|
||||
"payload->DataSize != sizeof(Containers::String) in Application::drawMassManager()",
|
||||
window());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
else if((payload = ImGui::AcceptDragDropPayload("Mass"))) {
|
||||
if(payload->DataSize != sizeof(int)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
||||
"payload->DataSize != sizeof(int) in SaveTool::drawMassManager()",
|
||||
"payload->DataSize != sizeof(int) in Application::drawMassManager()",
|
||||
window());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -515,14 +462,15 @@ void SaveTool::drawMassManager() {
|
|||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
switch(_massManager->hangar(i).state()) {
|
||||
case Mass::State::Empty:
|
||||
case GameObjects::Mass::State::Empty:
|
||||
ImGui::TextDisabled("<empty>");
|
||||
break;
|
||||
case Mass::State::Invalid:
|
||||
case GameObjects::Mass::State::Invalid:
|
||||
ImGui::TextDisabled("<invalid>");
|
||||
break;
|
||||
case Mass::State::Valid:
|
||||
ImGui::TextUnformatted(_massManager->hangar(i).name().data());
|
||||
case GameObjects::Mass::State::Valid:
|
||||
ImGui::TextUnformatted(_massManager->hangar(i).name().cbegin(),
|
||||
_massManager->hangar(i).name().cend());
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -532,10 +480,10 @@ void SaveTool::drawMassManager() {
|
|||
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::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)) {
|
||||
_currentMass = &_massManager->hangar(i);
|
||||
_uiState = UiState::MassViewer;
|
||||
|
@ -550,9 +498,10 @@ void SaveTool::drawMassManager() {
|
|||
ImGui::SameLine(0.0f, 2.0f);
|
||||
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) {
|
||||
mass_to_delete = i;
|
||||
ImGui::OpenPopup(mass_deletion_popup_ID);
|
||||
ImGui::OpenPopup("Confirmation##DeleteMassConfirmation");
|
||||
}
|
||||
drawTooltip("Delete");
|
||||
drawDeleteMassPopup(mass_to_delete);
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
@ -562,7 +511,6 @@ void SaveTool::drawMassManager() {
|
|||
|
||||
drawDeleteMassPopup(mass_to_delete);
|
||||
|
||||
static ImGuiID staged_mass_deletion_popup_ID = drawDeleteStagedMassPopup("");
|
||||
static Containers::StringView staged_mass_to_delete;
|
||||
|
||||
if(ImGui::BeginTable("##StagingArea", 2,
|
||||
|
@ -579,32 +527,33 @@ void SaveTool::drawMassManager() {
|
|||
ImGui::TextUnformatted("Staging area");
|
||||
ImGui::SameLine();
|
||||
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::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());
|
||||
if((ImGui::CalcTextSize(staged_formatted.data()).x + ImGui::GetStyle().FramePadding.x) > ImGui::GetContentRegionAvail().x) {
|
||||
drawTooltip(staged_formatted.data());
|
||||
}
|
||||
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::TableSetColumnIndex(1);
|
||||
ImGui::PushID(pair.first.data());
|
||||
ImGui::PushID(mass.filename.data());
|
||||
if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) {
|
||||
staged_mass_to_delete = pair.first;
|
||||
ImGui::OpenPopup(staged_mass_deletion_popup_ID);
|
||||
staged_mass_to_delete = mass.filename;
|
||||
ImGui::OpenPopup("Confirmation##DeleteStagedMassConfirmation");
|
||||
}
|
||||
drawTooltip("Delete");
|
||||
drawDeleteStagedMassPopup(staged_mass_to_delete);
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
|
@ -614,7 +563,7 @@ void SaveTool::drawMassManager() {
|
|||
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("Mass")) {
|
||||
if(payload->DataSize != sizeof(int)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
|
||||
"payload->DataSize != sizeof(int) in SaveTool::drawMassManager()",
|
||||
"payload->DataSize != sizeof(int) in Application::drawMassManager()",
|
||||
window());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -632,27 +581,28 @@ void SaveTool::drawMassManager() {
|
|||
drawDeleteStagedMassPopup(staged_mass_to_delete);
|
||||
}
|
||||
|
||||
auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID {
|
||||
void
|
||||
Application::drawDeleteMassPopup(int mass_index) {
|
||||
if(!ImGui::BeginPopupModal("Confirmation##DeleteMassConfirmation", nullptr,
|
||||
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::EndPopup();
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(_gameState != GameState::NotRunning) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
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.",
|
||||
mass_index + 1);
|
||||
}
|
||||
|
@ -682,22 +632,19 @@ auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID {
|
|||
|
||||
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,
|
||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
||||
{
|
||||
return ImGui::GetID("Confirmation##DeleteStagedMassConfirmation");
|
||||
return;
|
||||
}
|
||||
|
||||
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.",
|
||||
_massManager->stagedMasses().at(filename).data());
|
||||
_stagedMassManager->at(filename).filename.cbegin());
|
||||
ImGui::PopTextWrapPos();
|
||||
|
||||
if(ImGui::BeginTable("##DeleteStagedMassLayout", 2)) {
|
||||
|
@ -708,8 +655,9 @@ auto SaveTool::drawDeleteStagedMassPopup(Containers::StringView filename) -> ImG
|
|||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::Button("Yes")) {
|
||||
if(!_massManager->deleteStagedMass(filename)) {
|
||||
_queue.addToast(Toast::Type::Error, _massManager->lastError());
|
||||
if(!_stagedMassManager->remove(filename)) {
|
||||
_queue.addToast(Toast::Type::Error,
|
||||
"Couldn't delete the staged M.A.S.S. at " + filename + ": " + _stagedMassManager->lastError());
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
@ -722,6 +670,6 @@ auto SaveTool::drawDeleteStagedMassPopup(Containers::StringView filename) -> ImG
|
|||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -19,15 +19,22 @@
|
|||
|
||||
#include <Magnum/ImGuiIntegration/Integration.h>
|
||||
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include "../Configuration/Configuration.h"
|
||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||
#include "../Maps/Accessories.h"
|
||||
#include "../GameData/Accessories.h"
|
||||
#define STYLENAMES_DEFINITION
|
||||
#include "../Maps/StyleNames.h"
|
||||
#include "../GameData/StyleNames.h"
|
||||
#include "../ImportExport/Export.h"
|
||||
|
||||
#include "SaveTool.h"
|
||||
#include "Application.h"
|
||||
|
||||
void SaveTool::drawMassViewer() {
|
||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
||||
namespace mbst {
|
||||
|
||||
void
|
||||
Application::drawMassViewer() {
|
||||
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||
_currentMass = nullptr;
|
||||
_currentWeapon = nullptr;
|
||||
_uiState = UiState::MainManager;
|
||||
|
@ -36,7 +43,7 @@ void SaveTool::drawMassViewer() {
|
|||
}
|
||||
|
||||
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);
|
||||
if(!ImGui::Begin("##MassViewer", nullptr,
|
||||
ImGuiWindowFlags_NoDecoration|ImGuiWindowFlags_NoMove|
|
||||
|
@ -48,7 +55,7 @@ void SaveTool::drawMassViewer() {
|
|||
|
||||
if(ImGui::BeginChild("##MassInfo",
|
||||
{0.0f, 0.0f},
|
||||
true, ImGuiWindowFlags_MenuBar))
|
||||
ImGuiChildFlags_Border, ImGuiWindowFlags_MenuBar))
|
||||
{
|
||||
if(ImGui::BeginMenuBar()) {
|
||||
if(ImGui::BeginTable("##MassViewerMenuTable", 4)) {
|
||||
|
@ -84,8 +91,9 @@ void SaveTool::drawMassViewer() {
|
|||
_jointsDirty = false;
|
||||
_stylesDirty = false;
|
||||
_eyeFlareDirty = false;
|
||||
_selectedArmourDecals = Containers::StaticArray<38, Int>{ValueInit};
|
||||
_selectedArmourAccessories = Containers::StaticArray<38, Int>{ValueInit};
|
||||
_selectedArmourSlot = Containers::NullOpt;
|
||||
_selectedArmourDecals = Containers::StaticArray<38, std::int32_t>{ValueInit};
|
||||
_selectedArmourAccessories = Containers::StaticArray<38, std::int32_t>{ValueInit};
|
||||
_selectedBLPlacement = 0;
|
||||
_selectedWeaponPart = 0;
|
||||
_selectedWeaponDecal = 0;
|
||||
|
@ -122,6 +130,13 @@ void SaveTool::drawMassViewer() {
|
|||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if(_currentMass->bulletLauncherAttachmentStyle() != GameObjects::BulletLauncherAttachmentStyle::NotFound &&
|
||||
ImGui::BeginTabItem("Bullet launcher attachment"))
|
||||
{
|
||||
drawBLAttachment();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if(ImGui::BeginTabItem("Custom armour styles")) {
|
||||
drawCustomArmourStyles();
|
||||
ImGui::EndTabItem();
|
||||
|
@ -132,7 +147,7 @@ void SaveTool::drawMassViewer() {
|
|||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if(_currentMass->globalStyles().size() != 0 && ImGui::BeginTabItem("Global styles")) {
|
||||
if(!_currentMass->globalStyles().isEmpty() && ImGui::BeginTabItem("Global styles")) {
|
||||
drawGlobalStyles();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
@ -153,8 +168,9 @@ void SaveTool::drawMassViewer() {
|
|||
ImGui::End();
|
||||
}
|
||||
|
||||
void SaveTool::drawGlobalStyles() {
|
||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
||||
void
|
||||
Application::drawGlobalStyles() {
|
||||
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||
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.");
|
||||
|
||||
for(UnsignedInt i = 0; i < _currentMass->globalStyles().size(); i++) {
|
||||
for(std::uint32_t i = 0; i < _currentMass->globalStyles().size(); i++) {
|
||||
ImGui::PushID(int(i));
|
||||
DCSResult result;
|
||||
result = drawCustomStyle(_currentMass->globalStyles()[i]);
|
||||
auto result = drawCustomStyle(_currentMass->globalStyles()[i]);
|
||||
switch(result) {
|
||||
case DCS_ResetStyle:
|
||||
_currentMass->getGlobalStyles();
|
||||
|
@ -189,8 +204,9 @@ void SaveTool::drawGlobalStyles() {
|
|||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void SaveTool::drawTuning() {
|
||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
||||
void
|
||||
Application::drawTuning() {
|
||||
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -221,7 +237,7 @@ void SaveTool::drawTuning() {
|
|||
ImGui::TableNextColumn();
|
||||
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::TableNextColumn();
|
||||
ImGui::Text("%i", _currentMass->gears()[i]);
|
||||
|
@ -247,7 +263,7 @@ void SaveTool::drawTuning() {
|
|||
ImGui::TableNextColumn();
|
||||
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::TableNextColumn();
|
||||
ImGui::Text("%i", _currentMass->modules()[i]);
|
||||
|
@ -273,7 +289,7 @@ void SaveTool::drawTuning() {
|
|||
ImGui::TableNextColumn();
|
||||
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::TableNextColumn();
|
||||
ImGui::Text("%i", _currentMass->techs()[i]);
|
||||
|
@ -285,8 +301,9 @@ void SaveTool::drawTuning() {
|
|||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
|
||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
||||
Application::DCSResult
|
||||
Application::drawCustomStyle(GameObjects::CustomStyle& style) {
|
||||
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||
return DCS_Fail;
|
||||
}
|
||||
|
||||
|
@ -296,13 +313,15 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
|
|||
|
||||
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();
|
||||
return DCS_Fail;
|
||||
}
|
||||
|
||||
if(ImGui::BeginMenuBar()) {
|
||||
ImGui::TextUnformatted(style.name.data());
|
||||
ImGui::TextUnformatted(style.name.cbegin(), style.name.cend());
|
||||
|
||||
static Containers::StaticArray<33, char> name_buf{ValueInit};
|
||||
if(ImGui::SmallButton(ICON_FA_EDIT " Rename")) {
|
||||
|
@ -316,6 +335,18 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
|
|||
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();
|
||||
}
|
||||
|
||||
|
@ -390,13 +421,14 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
|
|||
return return_value;
|
||||
}
|
||||
|
||||
void SaveTool::drawDecalEditor(Decal& decal) {
|
||||
void
|
||||
Application::drawDecalEditor(GameObjects::Decal& decal) {
|
||||
ImGui::Text("ID: %i", decal.id);
|
||||
|
||||
if(ImGui::BeginTable("##DecalTable", _advancedMode ? 2 : 1, ImGuiTableFlags_BordersInnerV)) {
|
||||
if(ImGui::BeginTable("##DecalTable", conf().advancedMode() ? 2 : 1, ImGuiTableFlags_BordersInnerV)) {
|
||||
ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
if(_advancedMode) {
|
||||
if(conf().advancedMode()) {
|
||||
ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch);
|
||||
}
|
||||
|
||||
|
@ -420,12 +452,17 @@ void SaveTool::drawDecalEditor(Decal& decal) {
|
|||
ImGui::SameLine();
|
||||
drawHelpMarker("Right-click for more option, click the coloured square for the full picker.");
|
||||
|
||||
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
||||
ImGui::SliderFloat("##OffsetX", &decal.offset.x(), 0.0f, 1.0f, "X: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::SliderFloat("##OffsetY", &decal.offset.y(), 0.0f, 1.0f, "Y: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
std::visit(
|
||||
[this](auto& arg){
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Vector2>) {
|
||||
drawVector2Slider("##Offset", arg, Vector2{0.0f}, Vector2{1.0f}, "X: %.3f", "Y: %.3f");
|
||||
}
|
||||
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();
|
||||
drawHelpMarker("0.0 = -100 in-game\n1.0 = 100 in-game");
|
||||
|
||||
|
@ -442,7 +479,7 @@ void SaveTool::drawDecalEditor(Decal& decal) {
|
|||
ImGui::Checkbox("##Wrap", &decal.wrap);
|
||||
ImGui::EndGroup();
|
||||
|
||||
if(_advancedMode) {
|
||||
if(conf().advancedMode()) {
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
|
||||
|
@ -458,34 +495,49 @@ void SaveTool::drawDecalEditor(Decal& decal) {
|
|||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||
ImGui::DragFloat("##PosX", &decal.position.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::DragFloat("##PosY", &decal.position.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::DragFloat("##PosZ", &decal.position.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::PushItemWidth(-1.0f);
|
||||
std::visit(
|
||||
[this](auto& arg){
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Vector3>) {
|
||||
drawVector3Drag("##Position", 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("##Position", arg, 1.0f, Vector3d{-DBL_MAX}, Vector3d{DBL_MAX}, "X: %.3f",
|
||||
"Y: %.3f", "Z: %.3f");
|
||||
}
|
||||
}, decal.position
|
||||
);
|
||||
|
||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||
ImGui::DragFloat("##UX", &decal.uAxis.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::DragFloat("##UY", &decal.uAxis.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::DragFloat("##UZ", &decal.uAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
std::visit(
|
||||
[this](auto& arg){
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Vector3>) {
|
||||
drawVector3Drag("##U", 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("##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::EndGroup();
|
||||
}
|
||||
|
@ -494,12 +546,13 @@ void SaveTool::drawDecalEditor(Decal& decal) {
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
ImGui::TextUnformatted("Accessory: <none>");
|
||||
}
|
||||
else if(accessories.find(accessory.id) != accessories.cend()) {
|
||||
ImGui::Text("Accessory #%.4i - %s", accessory.id, accessories.at(accessory.id).name.data());
|
||||
else if(GameData::accessories.find(accessory.id) != GameData::accessories.cend()) {
|
||||
ImGui::Text("Accessory #%.4i - %s", accessory.id, GameData::accessories.at(accessory.id).name.data());
|
||||
}
|
||||
else {
|
||||
ImGui::Text("Accessory #%i", accessory.id);
|
||||
|
@ -508,8 +561,8 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
|||
|
||||
ImGui::SameLine();
|
||||
|
||||
static Int tab = 0;
|
||||
static Containers::Optional<AccessorySize> size = Containers::NullOpt;
|
||||
static std::int32_t tab = 0;
|
||||
static Containers::Optional<GameData::Accessory::Size> size = Containers::NullOpt;
|
||||
if(ImGui::SmallButton("Change")) {
|
||||
ImGui::OpenPopup("##AccessoryPopup");
|
||||
if(accessory.id >= 3000) {
|
||||
|
@ -532,7 +585,7 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
|||
"L",
|
||||
"XL"
|
||||
};
|
||||
static const Float selectable_width = 90.0f;
|
||||
static const float selectable_width = 90.0f;
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
|
||||
if(ImGui::Selectable("Primitives", tab == 0, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
|
||||
|
@ -567,53 +620,53 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
|||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Selectable("S", size && *size == AccessorySize::S, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||
if(ImGui::Selectable("S", size && *size == GameData::Accessory::Size::S, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||
if(!size) {
|
||||
size.emplace();
|
||||
}
|
||||
*size = AccessorySize::S;
|
||||
*size = GameData::Accessory::Size::S;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Selectable("M", size && *size == AccessorySize::M, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||
if(ImGui::Selectable("M", size && *size == GameData::Accessory::Size::M, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||
if(!size) {
|
||||
size.emplace();
|
||||
}
|
||||
*size = AccessorySize::M;
|
||||
*size = GameData::Accessory::Size::M;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Selectable("L", size && *size == AccessorySize::L, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||
if(ImGui::Selectable("L", size && *size == GameData::Accessory::Size::L, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||
if(!size) {
|
||||
size.emplace();
|
||||
}
|
||||
*size = AccessorySize::L;
|
||||
*size = GameData::Accessory::Size::L;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Selectable("XL", size && *size == AccessorySize::XL, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||
if(ImGui::Selectable("XL", size && *size == GameData::Accessory::Size::XL, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
|
||||
if(!size) {
|
||||
size.emplace();
|
||||
}
|
||||
*size = AccessorySize::XL;
|
||||
*size = GameData::Accessory::Size::XL;
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if(ImGui::BeginListBox("##AccessoryListbox", {-1.0f, 0.0f})) {
|
||||
for(const auto& acc : accessories) {
|
||||
if(acc.first >= tab * 1000 && acc.first < ((tab + 1) * 1000) && (!size || *size == acc.second.size)) {
|
||||
if(ImGui::Selectable(Utility::format("#{:.4d} - {} ({})", acc.first, acc.second.name, size_labels[acc.second.size]).data(),
|
||||
acc.first == accessory.id))
|
||||
for(const auto& [id, acc] : GameData::accessories) {
|
||||
if(id >= tab * 1000 && id < ((tab + 1) * 1000) && (!size || *size == acc.size)) {
|
||||
if(ImGui::Selectable(Utility::format("#{:.4d} - {} ({})", id, acc.name, size_labels[acc.size]).data(),
|
||||
id == accessory.id))
|
||||
{
|
||||
accessory.id = acc.first;
|
||||
accessory.id = id;
|
||||
accessory.attachIndex = 0;
|
||||
}
|
||||
if(acc.first == accessory.id) {
|
||||
if(id == accessory.id) {
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
|
@ -635,11 +688,11 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
|||
|
||||
ImGui::BeginGroup();
|
||||
drawAlignedText("Styles:");
|
||||
if(_advancedMode) {
|
||||
if(conf().advancedMode()) {
|
||||
drawAlignedText("Base position:");
|
||||
}
|
||||
drawAlignedText("Position offset:");
|
||||
if(_advancedMode) {
|
||||
if(conf().advancedMode()) {
|
||||
drawAlignedText("Base rotation:");
|
||||
}
|
||||
drawAlignedText("Rotation offset:");
|
||||
|
@ -651,7 +704,7 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
|||
ImGui::BeginGroup();
|
||||
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
|
||||
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)) {
|
||||
accessory.styles[0] = style.first;
|
||||
}
|
||||
|
@ -662,7 +715,7 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
|||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
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)) {
|
||||
accessory.styles[1] = style.first;
|
||||
}
|
||||
|
@ -672,67 +725,86 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
|
|||
}
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
if(_advancedMode) {
|
||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||
ImGui::DragFloat("##PosX", &accessory.relativePosition.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::DragFloat("##PosY", &accessory.relativePosition.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::DragFloat("##PosZ", &accessory.relativePosition.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
if(conf().advancedMode()) {
|
||||
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");
|
||||
}
|
||||
}, accessory.relativePosition
|
||||
);
|
||||
}
|
||||
|
||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||
ImGui::SliderFloat("##PosOffsetX", &accessory.relativePositionOffset.x(), -500.0f, +500.0f, "X: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::SliderFloat("##PosOffsetY", &accessory.relativePositionOffset.y(), -500.0f, +500.0f, "Y: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::SliderFloat("##PosOffsetZ", &accessory.relativePositionOffset.z(), -500.0f, +500.0f, "Z: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
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");
|
||||
}
|
||||
}, accessory.relativePositionOffset
|
||||
);
|
||||
ImGui::SameLine();
|
||||
drawHelpMarker("+/-500.0 = +/-250 in-game");
|
||||
|
||||
if(_advancedMode) {
|
||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||
ImGui::DragFloat("##RotX", &accessory.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::DragFloat("##RotY", &accessory.relativeRotation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Yaw: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::DragFloat("##RotZ", &accessory.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
if(conf().advancedMode()) {
|
||||
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}, "Roll: %.3f",
|
||||
"Yaw: %.3f", "Pitch: %.3f");
|
||||
}
|
||||
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());
|
||||
ImGui::SliderFloat("##RotOffsetX", &accessory.relativeRotationOffset.x(), -180.0f, +180.0f, "Roll: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::SliderFloat("##RotOffsetY", &accessory.relativeRotationOffset.y(), -180.0f, +180.0f, "Yaw: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::SliderFloat("##RotOffsetZ", &accessory.relativeRotationOffset.z(), -180.0f, +180.0f, "Pitch: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
std::visit(
|
||||
[this](auto& arg){
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Vector3>) {
|
||||
drawVector3Slider("##OffsetRotation", arg, Vector3{-180.0f}, Vector3{180.0f}, "Roll: %.3f",
|
||||
"Yaw: %.3f", "Pitch: %.3f");
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||
drawVector3dSlider("##OffsetRotation", arg, Vector3d{-180.0}, Vector3d{180.0}, "Roll: %.3f",
|
||||
"Yaw: %.3f", "Pitch: %.3f");
|
||||
}
|
||||
}, accessory.relativeRotationOffset
|
||||
);
|
||||
|
||||
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
|
||||
ImGui::SliderFloat("##ScaleX", &accessory.localScale.x(), -3.0f, +3.0f, "X: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::SliderFloat("##ScaleY", &accessory.localScale.y(), -3.0f, +3.0f, "Y: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
|
||||
ImGui::SliderFloat("##ScaleZ", &accessory.localScale.z(), -3.0f, +3.0f, "Z: %.3f");
|
||||
ImGui::PopItemWidth();
|
||||
std::visit(
|
||||
[this](auto& arg){
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Vector3>) {
|
||||
drawVector3Slider("##Scale", arg, Vector3{-3.0f}, Vector3{3.0f}, "X: %.3f", "Y: %.3f", "Z: %.3f");
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Vector3d>) {
|
||||
drawVector3dSlider("##Scale", arg, Vector3d{-3.0}, Vector3d{3.0}, "X: %.3f", "Y: %.3f", "Z: %.3f");
|
||||
}
|
||||
}, accessory.localScale
|
||||
);
|
||||
ImGui::SameLine();
|
||||
drawHelpMarker("+/-3.0 = +/-150 in-game");
|
||||
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) {
|
||||
return view[id].name;
|
||||
}
|
||||
|
@ -740,6 +812,8 @@ auto SaveTool::getStyleName(Int id, Containers::ArrayView<CustomStyle> view) ->
|
|||
return _currentMass->globalStyles()[id - 50].name;
|
||||
}
|
||||
else {
|
||||
return style_names.at(id);
|
||||
return GameData::builtin_style_names.at(id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
392
src/Application/Application_MassViewer_Armour.cpp
Normal file
392
src/Application/Application_MassViewer_Armour.cpp
Normal file
|
@ -0,0 +1,392 @@
|
|||
// 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: %u", part.id);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if(ImGui::SmallButton("Change")) {
|
||||
ImGui::OpenPopup("##ArmourPartPopup");
|
||||
}
|
||||
if(ImGui::BeginPopup("##ArmourPartPopup")) {
|
||||
if(ImGui::BeginListBox("##ChangePart")) {
|
||||
for(auto& set : GameData::armour_sets) {
|
||||
if(part.slot != GameObjects::ArmourPart::Slot::Neck || set.second.neck_compatible) {
|
||||
if(ImGui::Selectable(set.second.name.data(), set.first == part.id,
|
||||
ImGuiSelectableFlags_SpanAvailWidth))
|
||||
{
|
||||
part.id = set.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -16,18 +16,21 @@
|
|||
|
||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||
|
||||
#include "../Maps/StyleNames.h"
|
||||
#include "../Maps/WeaponParts.h"
|
||||
#include "../GameData/StyleNames.h"
|
||||
#include "../GameData/WeaponParts.h"
|
||||
|
||||
#include "SaveTool.h"
|
||||
#include "Application.h"
|
||||
|
||||
void SaveTool::drawWeapons() {
|
||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid) {
|
||||
namespace mbst {
|
||||
|
||||
void
|
||||
Application::drawWeapons() {
|
||||
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid) {
|
||||
_currentWeapon = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
const Float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
|
||||
const float footer_height_to_reserve = ImGui::GetFrameHeightWithSpacing();
|
||||
|
||||
ImGui::BeginGroup();
|
||||
|
||||
|
@ -52,11 +55,9 @@ void SaveTool::drawWeapons() {
|
|||
|
||||
bool dirty = _meleeDirty || _shieldsDirty || _bShootersDirty || _eShootersDirty || _bLaunchersDirty || _eLaunchersDirty;
|
||||
|
||||
if(!dirty) {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
ImGui::BeginDisabled(!dirty);
|
||||
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
|
||||
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save order"); })) {
|
||||
if(_meleeDirty) {
|
||||
_modifiedBySaveTool = true;
|
||||
if(!_currentMass->writeMeleeWeapons()) {
|
||||
|
@ -153,9 +154,7 @@ void SaveTool::drawWeapons() {
|
|||
}
|
||||
}
|
||||
|
||||
if(!dirty) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
|
@ -177,42 +176,40 @@ void SaveTool::drawWeapons() {
|
|||
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if(drawUnsafeWidget([](){ return ImGui::Button(ICON_FA_SAVE " Save changes to weapon category"); })) {
|
||||
_modifiedBySaveTool = true;
|
||||
switch(_currentWeapon->type) {
|
||||
case WeaponType::Melee:
|
||||
case GameObjects::Weapon::Type::Melee:
|
||||
if(!_currentMass->writeMeleeWeapons()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case WeaponType::Shield:
|
||||
case GameObjects::Weapon::Type::Shield:
|
||||
if(!_currentMass->writeShields()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case WeaponType::BulletShooter:
|
||||
case GameObjects::Weapon::Type::BulletShooter:
|
||||
if(!_currentMass->writeBulletShooters()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case WeaponType::EnergyShooter:
|
||||
case GameObjects::Weapon::Type::EnergyShooter:
|
||||
if(!_currentMass->writeEnergyShooters()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case WeaponType::BulletLauncher:
|
||||
case GameObjects::Weapon::Type::BulletLauncher:
|
||||
if(!_currentMass->writeBulletLaunchers()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
}
|
||||
break;
|
||||
case WeaponType::EnergyLauncher:
|
||||
case GameObjects::Weapon::Type::EnergyLauncher:
|
||||
if(!_currentMass->writeEnergyLaunchers()) {
|
||||
_modifiedBySaveTool = false;
|
||||
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
|
||||
|
@ -228,22 +225,22 @@ void SaveTool::drawWeapons() {
|
|||
|
||||
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset weapon category")) {
|
||||
switch(_currentWeapon->type) {
|
||||
case WeaponType::Melee:
|
||||
case GameObjects::Weapon::Type::Melee:
|
||||
_currentMass->getMeleeWeapons();
|
||||
break;
|
||||
case WeaponType::Shield:
|
||||
case GameObjects::Weapon::Type::Shield:
|
||||
_currentMass->getShields();
|
||||
break;
|
||||
case WeaponType::BulletShooter:
|
||||
case GameObjects::Weapon::Type::BulletShooter:
|
||||
_currentMass->getBulletShooters();
|
||||
break;
|
||||
case WeaponType::EnergyShooter:
|
||||
case GameObjects::Weapon::Type::EnergyShooter:
|
||||
_currentMass->getEnergyShooters();
|
||||
break;
|
||||
case WeaponType::BulletLauncher:
|
||||
case GameObjects::Weapon::Type::BulletLauncher:
|
||||
_currentMass->getBulletLaunchers();
|
||||
break;
|
||||
case WeaponType::EnergyLauncher:
|
||||
case GameObjects::Weapon::Type::EnergyLauncher:
|
||||
_currentMass->getEnergyLaunchers();
|
||||
break;
|
||||
default:
|
||||
|
@ -254,16 +251,17 @@ void SaveTool::drawWeapons() {
|
|||
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)
|
||||
{
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(name.data());
|
||||
ImGui::TextUnformatted(name.cbegin(), name.cend());
|
||||
|
||||
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];
|
||||
|
||||
ImGui::TableNextRow();
|
||||
|
@ -275,7 +273,7 @@ void SaveTool::drawWeaponCategory(Containers::StringView name, Containers::Array
|
|||
_currentWeapon = &weapon;
|
||||
}
|
||||
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) {
|
||||
ImGui::Text("%s %i - %s (copy)", payload_tooltip.data(), i + 1, weapon.name.data());
|
||||
}
|
||||
|
@ -317,8 +315,9 @@ void SaveTool::drawWeaponCategory(Containers::StringView name, Containers::Array
|
|||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
||||
if(!_currentMass || _currentMass->state() != Mass::State::Valid || !_currentWeapon) {
|
||||
void
|
||||
Application::drawWeaponEditor(GameObjects::Weapon& weapon) {
|
||||
if(!_currentMass || _currentMass->state() != GameObjects::Mass::State::Valid || !_currentWeapon) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -328,7 +327,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
#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();
|
||||
|
||||
|
@ -347,11 +346,11 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
ImGui::BeginGroup();
|
||||
drawAlignedText("Equipped:");
|
||||
|
||||
if(weapon.type != WeaponType::Shield) {
|
||||
if(weapon.type != GameObjects::Weapon::Type::Shield) {
|
||||
drawAlignedText("Damage type:");
|
||||
}
|
||||
|
||||
if(weapon.type == WeaponType::Melee) {
|
||||
if(weapon.type == GameObjects::Weapon::Type::Melee) {
|
||||
drawAlignedText("Dual-wield:");
|
||||
|
||||
drawAlignedText("Custom effect mode:");
|
||||
|
@ -365,48 +364,48 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
ImGui::BeginGroup();
|
||||
ImGui::Checkbox("##EquippedCheckbox", &weapon.attached);
|
||||
|
||||
if(weapon.type != WeaponType::Shield) {
|
||||
if(weapon.type == WeaponType::Melee &&
|
||||
ImGui::RadioButton("Physical##NoElement", weapon.damageType == DamageType::Physical))
|
||||
if(weapon.type != GameObjects::Weapon::Type::Shield) {
|
||||
if(weapon.type == GameObjects::Weapon::Type::Melee &&
|
||||
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) &&
|
||||
ImGui::RadioButton("Piercing##NoElement", weapon.damageType == DamageType::Piercing))
|
||||
else if((weapon.type == GameObjects::Weapon::Type::BulletShooter || weapon.type == GameObjects::Weapon::Type::BulletLauncher) &&
|
||||
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) &&
|
||||
ImGui::RadioButton("Plasma##NoElement", weapon.damageType == DamageType::Plasma))
|
||||
else if((weapon.type == GameObjects::Weapon::Type::EnergyShooter || weapon.type == GameObjects::Weapon::Type::EnergyLauncher) &&
|
||||
ImGui::RadioButton("Plasma##NoElement", weapon.damageType == GameObjects::Weapon::DamageType::Plasma))
|
||||
{
|
||||
weapon.damageType = DamageType::Plasma;
|
||||
weapon.damageType = GameObjects::Weapon::DamageType::Plasma;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::RadioButton("Heat##Heat", weapon.damageType == DamageType::Heat)) {
|
||||
weapon.damageType = DamageType::Heat;
|
||||
if(ImGui::RadioButton("Heat##Heat", weapon.damageType == GameObjects::Weapon::DamageType::Heat)) {
|
||||
weapon.damageType = GameObjects::Weapon::DamageType::Heat;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::RadioButton("Freeze##Freeze", weapon.damageType == DamageType::Freeze)) {
|
||||
weapon.damageType = DamageType::Freeze;
|
||||
if(ImGui::RadioButton("Freeze##Freeze", weapon.damageType == GameObjects::Weapon::DamageType::Freeze)) {
|
||||
weapon.damageType = GameObjects::Weapon::DamageType::Freeze;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::RadioButton("Shock##Shock", weapon.damageType == DamageType::Shock)) {
|
||||
weapon.damageType = DamageType::Shock;
|
||||
if(ImGui::RadioButton("Shock##Shock", weapon.damageType == GameObjects::Weapon::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);
|
||||
|
||||
if(ImGui::RadioButton("Default##Default", weapon.effectColourMode == EffectColourMode::Default)) {
|
||||
weapon.effectColourMode = EffectColourMode::Default;
|
||||
if(ImGui::RadioButton("Default##Default", weapon.effectColourMode == GameObjects::Weapon::EffectColourMode::Default)) {
|
||||
weapon.effectColourMode = GameObjects::Weapon::EffectColourMode::Default;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::RadioButton("Custom##Custom", weapon.effectColourMode == EffectColourMode::Custom)) {
|
||||
weapon.effectColourMode = EffectColourMode::Custom;
|
||||
if(ImGui::RadioButton("Custom##Custom", weapon.effectColourMode == GameObjects::Weapon::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) {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
|
@ -425,8 +424,8 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
|
||||
if(ImGui::CollapsingHeader("Weapon parts")) {
|
||||
drawAlignedText("Viewing/editing part:");
|
||||
for(Int i = 0; UnsignedLong(i) < weapon.parts.size(); i++) {
|
||||
if(UnsignedLong(_selectedWeaponPart) >= weapon.parts.size()) {
|
||||
for(std::int32_t i = 0; std::size_t(i) < weapon.parts.size(); i++) {
|
||||
if(std::size_t(_selectedWeaponPart) >= weapon.parts.size()) {
|
||||
_selectedWeaponPart = 0;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
@ -435,20 +434,20 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
|
||||
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) {
|
||||
case WeaponType::Melee:
|
||||
return _selectedWeaponPart == 0 ? &melee_grips : &melee_assaulters;
|
||||
case WeaponType::Shield:
|
||||
return _selectedWeaponPart == 0 ? &shield_handles : &shield_shells;
|
||||
case WeaponType::BulletShooter:
|
||||
return _selectedWeaponPart == 0 ? &bshooter_triggers : &bshooter_barrels;
|
||||
case WeaponType::EnergyShooter:
|
||||
return _selectedWeaponPart == 0 ? &eshooter_triggers : &eshooter_busters;
|
||||
case WeaponType::BulletLauncher:
|
||||
return _selectedWeaponPart == 0 ? &blauncher_pods : &blauncher_projectiles;
|
||||
case WeaponType::EnergyLauncher:
|
||||
return _selectedWeaponPart == 0 ? &elauncher_generators : &elauncher_pods;
|
||||
case GameObjects::Weapon::Type::Melee:
|
||||
return _selectedWeaponPart == 0 ? &GameData::melee_grips : &GameData::melee_assaulters;
|
||||
case GameObjects::Weapon::Type::Shield:
|
||||
return _selectedWeaponPart == 0 ? &GameData::shield_handles : &GameData::shield_shells;
|
||||
case GameObjects::Weapon::Type::BulletShooter:
|
||||
return _selectedWeaponPart == 0 ? &GameData::bshooter_triggers : &GameData::bshooter_barrels;
|
||||
case GameObjects::Weapon::Type::EnergyShooter:
|
||||
return _selectedWeaponPart == 0 ? &GameData::eshooter_triggers : &GameData::eshooter_busters;
|
||||
case GameObjects::Weapon::Type::BulletLauncher:
|
||||
return _selectedWeaponPart == 0 ? &GameData::blauncher_pods : &GameData::blauncher_projectiles;
|
||||
case GameObjects::Weapon::Type::EnergyLauncher:
|
||||
return _selectedWeaponPart == 0 ? &GameData::elauncher_generators : &GameData::elauncher_pods;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -459,7 +458,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
}
|
||||
|
||||
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) {
|
||||
ImGui::TextUnformatted("<none>");
|
||||
|
@ -490,14 +489,14 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
}
|
||||
}
|
||||
|
||||
if(weapon.type == WeaponType::Shield ||
|
||||
(weapon.type == WeaponType::BulletLauncher && _selectedWeaponPart != 0))
|
||||
if(weapon.type == GameObjects::Weapon::Type::Shield ||
|
||||
(weapon.type == GameObjects::Weapon::Type::BulletLauncher && _selectedWeaponPart != 0))
|
||||
{
|
||||
ImGui::SameLine();
|
||||
if(ImGui::SmallButton("Unequip")) {
|
||||
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.");
|
||||
}
|
||||
else {
|
||||
|
@ -505,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:");
|
||||
|
||||
for(Int i = 0; i < 4; i++) {
|
||||
for(std::int32_t i = 0; i < 4; i++) {
|
||||
drawAlignedText("Slot %d:", i + 1);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
@ -516,7 +515,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
ImGui::PushID(i);
|
||||
|
||||
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(),
|
||||
part.styles[i] == style.first)) {
|
||||
part.styles[i] = style.first;
|
||||
|
@ -534,7 +533,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
ImGui::PushID("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::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponDecal, int(i));
|
||||
}
|
||||
|
@ -543,13 +542,13 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
|
||||
ImGui::PopID();
|
||||
|
||||
if(part.accessories.size() != 0) {
|
||||
if(!part.accessories.isEmpty()) {
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushID("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::RadioButton(std::string{char(65 + i)}.c_str(), &_selectedWeaponAccessory, int(i));
|
||||
}
|
||||
|
@ -563,3 +562,5 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
|
|||
ImGui::EndChild();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,14 +20,17 @@
|
|||
|
||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||
|
||||
#include "SaveTool.h"
|
||||
#include "Application.h"
|
||||
|
||||
extern const ImVec2 center_pivot;
|
||||
|
||||
void SaveTool::drawProfileManager() {
|
||||
namespace mbst {
|
||||
|
||||
void
|
||||
Application::drawProfileManager() {
|
||||
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,
|
||||
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoBringToFrontOnFocus|
|
||||
ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_MenuBar))
|
||||
|
@ -37,10 +40,6 @@ void SaveTool::drawProfileManager() {
|
|||
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)) {
|
||||
ImGui::TableSetupColumn("##Label", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("##Refresh", ImGuiTableColumnFlags_WidthFixed);
|
||||
|
@ -59,9 +58,10 @@ void SaveTool::drawProfileManager() {
|
|||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::SmallButton("Backups")) {
|
||||
_profileManager->refreshBackups();
|
||||
ImGui::OpenPopup(backup_list_popup_id);
|
||||
_backupManager->refresh();
|
||||
ImGui::OpenPopup("Backups##BackupsModal");
|
||||
}
|
||||
drawBackupListPopup();
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ void SaveTool::drawProfileManager() {
|
|||
ImGui::TextUnformatted("Actions");
|
||||
|
||||
for(std::size_t i = 0; i < _profileManager->profiles().size(); ++i) {
|
||||
Profile& profile = _profileManager->profiles()[i];
|
||||
GameObjects::Profile& profile = _profileManager->profiles()[i];
|
||||
|
||||
ImGui::TableNextRow();
|
||||
|
||||
|
@ -100,16 +100,21 @@ void SaveTool::drawProfileManager() {
|
|||
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
if(ImGui::SmallButton(ICON_FA_FILE_ARCHIVE)) {
|
||||
profile_index = i;
|
||||
ImGui::OpenPopup(backup_popup_id);
|
||||
if(!_backupManager->create(_profileManager->profiles()[i])) {
|
||||
_queue.addToast(Toast::Type::Error, _backupManager->lastError(), std::chrono::seconds{5});
|
||||
}
|
||||
else {
|
||||
_queue.addToast(Toast::Type::Success, "Backup created successfully!"_s);
|
||||
}
|
||||
}
|
||||
drawTooltip("Backup");
|
||||
ImGui::SameLine(0.0f, 2.0f);
|
||||
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) {
|
||||
profile_index = i;
|
||||
ImGui::OpenPopup(delete_popup_id);
|
||||
ImGui::OpenPopup("Confirmation##DeleteProfileConfirmation");
|
||||
}
|
||||
drawTooltip("Delete");
|
||||
drawDeleteProfilePopup(profile_index);
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::EndTable();
|
||||
|
@ -118,107 +123,20 @@ void SaveTool::drawProfileManager() {
|
|||
ImGui::TextUnformatted("Click a profile to manage it.");
|
||||
}
|
||||
|
||||
drawBackupListPopup();
|
||||
drawBackupProfilePopup(profile_index);
|
||||
drawDeleteProfilePopup(profile_index);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
|
||||
void
|
||||
Application::drawBackupListPopup() {
|
||||
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f} / dpiScaling()}, ImGuiCond_Always, center_pivot);
|
||||
if(!ImGui::BeginPopupModal("Backups##BackupsModal", nullptr,
|
||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
||||
{
|
||||
return ImGui::GetID("Backups##BackupsModal");
|
||||
return;
|
||||
}
|
||||
|
||||
static std::size_t backup_index;
|
||||
|
||||
if(ImGui::BeginPopupModal("Restore backup", nullptr,
|
||||
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f);
|
||||
ImGui::Text("Are you sure you want to restore the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? Any existing data will be overwritten.",
|
||||
_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());
|
||||
}
|
||||
if(!_profileManager->refreshProfiles()) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_profileManager->lastError().data(), window());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
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(float(windowSize().x()) * 0.40f);
|
||||
ImGui::Text("Are you sure you want to delete the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? This operation is irreversible.",
|
||||
_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)) {
|
||||
ImGui::TableSetupColumn("##Label", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("##Refresh", ImGuiTableColumnFlags_WidthFixed);
|
||||
|
@ -229,13 +147,13 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
|||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::SmallButton("Refresh")) {
|
||||
_profileManager->refreshBackups();
|
||||
_backupManager->refresh();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
if(_profileManager->backups().isEmpty()) {
|
||||
if(_backupManager->backups().isEmpty()) {
|
||||
ImGui::TextDisabled("No backups were found.");
|
||||
}
|
||||
else if(ImGui::BeginTable("##Backups", 4,
|
||||
|
@ -257,16 +175,17 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
|||
ImGui::TableSetColumnIndex(3);
|
||||
ImGui::TextUnformatted("Actions");
|
||||
|
||||
for(std::size_t i = 0; i < _profileManager->backups().size(); ++i) {
|
||||
auto& backup = _profileManager->backups()[i];
|
||||
//drawBackupFolder(_backupManager->vfs());
|
||||
|
||||
for(std::size_t i = 0; i < _backupManager->backups().size(); ++i) {
|
||||
auto& backup = _backupManager->backups()[i];
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::TextUnformatted(backup.company.data());
|
||||
if(ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(backup.company.cbegin(), backup.company.cend());
|
||||
if(ImGui::IsItemHovered() && ImGui::BeginTooltip()) {
|
||||
for(const auto& file : backup.includedFiles) {
|
||||
ImGui::TextUnformatted(file.data());
|
||||
ImGui::TextUnformatted(file.cbegin());
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
@ -281,27 +200,29 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
|||
backup.timestamp.second);
|
||||
|
||||
ImGui::TableSetColumnIndex(2);
|
||||
ImGui::TextUnformatted(backup.type == ProfileType::Demo ? "Demo" : "Full");
|
||||
ImGui::TextUnformatted(backup.demo ? "Demo" : "Full");
|
||||
|
||||
ImGui::TableSetColumnIndex(3);
|
||||
ImGui::PushID(int(i));
|
||||
if(ImGui::SmallButton(ICON_FA_UNDO)) {
|
||||
backup_index = i;
|
||||
ImGui::OpenPopup(restore_backup_popup_id);
|
||||
ImGui::OpenPopup("Restore backup##RestoreBackupModal");
|
||||
}
|
||||
drawTooltip("Restore");
|
||||
drawBackupRestorePopup(backup_index);
|
||||
ImGui::SameLine(0.0f, 2.0f);
|
||||
if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) {
|
||||
backup_index = i;
|
||||
ImGui::OpenPopup(delete_backup_popup_id);
|
||||
ImGui::OpenPopup("Delete backup##DeleteBackupModal");
|
||||
}
|
||||
drawTooltip("Delete");
|
||||
drawBackupDeletePopup(backup_index);
|
||||
ImGui::PopID();
|
||||
}
|
||||
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::PopTextWrapPos();
|
||||
|
||||
|
@ -320,20 +241,91 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
|
|||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto SaveTool::drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID {
|
||||
if(!ImGui::BeginPopupModal("Include builds ?##IncludeBuildsDialog", nullptr,
|
||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
||||
void
|
||||
Application::drawBackupFolder(const Managers::Vfs::Directory<Managers::Backup>& dir) {
|
||||
if(dir.files().isEmpty() && dir.subdirs().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(auto& subdir : dir.subdirs()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
bool open = ImGui::TreeNodeEx(subdir.name().cbegin(), ImGuiTreeNodeFlags_SpanAllColumns);
|
||||
|
||||
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::GetID("Include builds ?##IncludeBuildsDialog");
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted("Should builds be added to the backup ?");
|
||||
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("##NameBackupLayout", 2)) {
|
||||
if(ImGui::BeginTable("##RestoreBackupLayout", 2)) {
|
||||
ImGui::TableSetupColumn("##Dummy", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("##YesNo", ImGuiTableColumnFlags_WidthFixed);
|
||||
|
||||
|
@ -341,22 +333,18 @@ auto SaveTool::drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID {
|
|||
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
if(ImGui::Button("Yes")) {
|
||||
if(!_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::SameLine();
|
||||
if(ImGui::Button("No", ImGui::GetItemRectSize())) {
|
||||
if(!_profileManager->backupProfile(profile_index, false)) {
|
||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
|
||||
_profileManager->lastError().data(), window());
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Cancel")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
|
@ -364,15 +352,58 @@ auto SaveTool::drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID {
|
|||
}
|
||||
|
||||
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,
|
||||
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
|
||||
{
|
||||
return ImGui::GetID("Confirmation##DeleteProfileConfirmation");
|
||||
return;
|
||||
}
|
||||
|
||||
static bool delete_builds = false;
|
||||
|
@ -410,6 +441,6 @@ auto SaveTool::drawDeleteProfilePopup(std::size_t profile_index) -> ImGuiID {
|
|||
}
|
||||
|
||||
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
|
||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -14,8 +14,6 @@
|
|||
// 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 "SaveTool.h"
|
||||
|
||||
#include <Corrade/version.h>
|
||||
|
||||
#include <Magnum/version.h>
|
||||
|
@ -29,9 +27,14 @@
|
|||
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||
#include "../FontAwesome/IconsFontAwesome5Brands.h"
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
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::SetNextWindowSize({float(windowSize().x()) * 0.8f, float(windowSize().y()) * 0.75f}, ImGuiCond_Always);
|
||||
|
||||
|
@ -59,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), "
|
||||
"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);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
|
@ -69,7 +72,7 @@ void SaveTool::drawAbout() {
|
|||
if(ImGui::Button("Open in browser")) {
|
||||
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);
|
||||
ImGui::SameLine();
|
||||
if(ImGui::Button("Copy to clipboard")) {
|
||||
|
@ -83,12 +86,13 @@ void SaveTool::drawAbout() {
|
|||
ImGui::Separator();
|
||||
|
||||
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, float(windowSize().y()) * 0.3f}, true)) {
|
||||
if(ImGui::BeginChild("##GPL", {0.0f, float(windowSize().y()) * 0.3f}, ImGuiChildFlags_Border)) {
|
||||
static auto licence = _rs.getRaw("COPYING");
|
||||
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::EndChild();
|
||||
|
@ -114,14 +118,6 @@ void SaveTool::drawAbout() {
|
|||
|
||||
ImGui::TextUnformatted("Licence: MIT");
|
||||
|
||||
static auto corrade_licence = _rs.getRaw("COPYING.Corrade");
|
||||
if(ImGui::BeginChild("##CorradeLicence", {0.0f, float(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();
|
||||
}
|
||||
|
||||
|
@ -142,14 +138,6 @@ void SaveTool::drawAbout() {
|
|||
|
||||
ImGui::TextUnformatted("Licence: MIT");
|
||||
|
||||
static auto magnum_licence = _rs.getRaw("COPYING.Magnum");
|
||||
if(ImGui::BeginChild("##MagnumLicence", {0.0f, float(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();
|
||||
}
|
||||
|
||||
|
@ -168,14 +156,6 @@ void SaveTool::drawAbout() {
|
|||
|
||||
ImGui::TextUnformatted("Licence: MIT");
|
||||
|
||||
static auto imgui_licence = _rs.getRaw("LICENSE.ImGui");
|
||||
if(ImGui::BeginChild("##ImGuiLicence", {0.0f, float(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();
|
||||
}
|
||||
|
||||
|
@ -194,14 +174,6 @@ void SaveTool::drawAbout() {
|
|||
|
||||
ImGui::TextUnformatted("Licence: zlib");
|
||||
|
||||
static auto sdl_licence = _rs.getRaw("LICENSE.SDL");
|
||||
if(ImGui::BeginChild("##SDLLicence", {0.0f, float(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();
|
||||
}
|
||||
|
||||
|
@ -220,14 +192,6 @@ void SaveTool::drawAbout() {
|
|||
|
||||
ImGui::TextUnformatted("Licence: 3-clause BSD");
|
||||
|
||||
static auto libzip_licence = _rs.getRaw("LICENSE.libzip");
|
||||
if(ImGui::BeginChild("##libzipLicence", {0.0f, float(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();
|
||||
}
|
||||
|
||||
|
@ -245,14 +209,6 @@ void SaveTool::drawAbout() {
|
|||
|
||||
ImGui::TextUnformatted("Licence: MIT");
|
||||
|
||||
static auto efsw_licence = _rs.getRaw("LICENSE.efsw");
|
||||
if(ImGui::BeginChild("##efswLicence", {0.0f, float(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();
|
||||
}
|
||||
|
||||
|
@ -271,14 +227,6 @@ void SaveTool::drawAbout() {
|
|||
|
||||
ImGui::TextUnformatted("Licence: MIT/X derivative");
|
||||
|
||||
static auto curl_licence = _rs.getRaw("LICENSE.curl");
|
||||
if(ImGui::BeginChild("##libcurlLicence", {0.0f, float(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();
|
||||
}
|
||||
|
||||
|
@ -322,3 +270,5 @@ void SaveTool::drawAbout() {
|
|||
|
||||
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
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
#include <Corrade/Containers/ArrayView.h>
|
||||
|
@ -23,81 +24,80 @@
|
|||
#include <Corrade/Containers/StaticArray.h>
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
class BinaryWriter {
|
||||
namespace BinaryIo {
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
explicit BinaryWriter(Containers::StringView filename);
|
||||
~BinaryWriter();
|
||||
explicit Writer(Containers::StringView filename);
|
||||
~Writer();
|
||||
|
||||
BinaryWriter(const BinaryWriter& other) = delete;
|
||||
BinaryWriter& operator=(const BinaryWriter& other) = delete;
|
||||
Writer(const Writer& other) = delete;
|
||||
Writer& operator=(const Writer& other) = delete;
|
||||
|
||||
BinaryWriter(BinaryWriter&& other) = default;
|
||||
BinaryWriter& operator=(BinaryWriter&& other) = default;
|
||||
Writer(Writer&& other) = default;
|
||||
Writer& operator=(Writer&& other) = default;
|
||||
|
||||
auto open() -> bool;
|
||||
bool open();
|
||||
|
||||
void closeFile();
|
||||
|
||||
auto position() -> Long;
|
||||
auto position() -> std::int64_t;
|
||||
|
||||
auto array() const -> Containers::ArrayView<const char>;
|
||||
auto arrayPosition() const -> UnsignedLong;
|
||||
auto flushToFile() -> bool;
|
||||
auto arrayPosition() const -> std::size_t;
|
||||
bool flushToFile();
|
||||
|
||||
auto writeByte(Byte value) -> bool;
|
||||
auto writeChar(char value) -> bool;
|
||||
auto writeUnsignedByte(UnsignedByte value) -> bool;
|
||||
auto writeShort(Short value) -> bool;
|
||||
auto writeUnsignedShort(UnsignedShort value) -> bool;
|
||||
auto writeInt(Int value) -> bool;
|
||||
auto writeUnsignedInt(UnsignedInt value) -> bool;
|
||||
auto writeLong(Long value) -> bool;
|
||||
auto writeUnsignedLong(UnsignedLong value) -> bool;
|
||||
auto writeFloat(Float value) -> bool;
|
||||
auto writeDouble(Double value) -> bool;
|
||||
auto writeArray(Containers::ArrayView<const char> array) -> bool;
|
||||
bool writeChar(char value);
|
||||
bool writeInt8(std::int8_t value);
|
||||
bool writeUint8(std::uint8_t value);
|
||||
bool writeInt16(std::int16_t value);
|
||||
bool writeUint16(std::uint16_t value);
|
||||
bool writeInt32(std::int32_t value);
|
||||
bool writeUint32(std::uint32_t value);
|
||||
bool writeInt64(std::int64_t value);
|
||||
bool writeUint64(std::uint64_t value);
|
||||
bool writeFloat(float value);
|
||||
bool writeDouble(double value);
|
||||
bool writeArray(Containers::ArrayView<const char> array);
|
||||
template<std::size_t size>
|
||||
auto writeString(const char(&str)[size]) -> bool {
|
||||
bool writeString(const char(&str)[size]) {
|
||||
return writeArray({str, size - 1});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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&>>
|
||||
auto writeValueToArray(U value) -> UnsignedLong {
|
||||
auto writeValueToArray(U value) -> std::size_t {
|
||||
Containers::ArrayView<T> view{&value, 1};
|
||||
return writeDataToArray(view);
|
||||
}
|
||||
|
||||
auto writeUEStringToArray(Containers::StringView value) -> UnsignedLong;
|
||||
auto writeUEStringToArray(Containers::StringView value) -> std::size_t;
|
||||
|
||||
template<typename T>
|
||||
void writeValueToArrayAt(T& value, UnsignedLong position) {
|
||||
void writeValueToArrayAt(T& value, std::size_t position) {
|
||||
Containers::ArrayView<T> view{&value, 1};
|
||||
writeDataToArrayAt(view, position);
|
||||
}
|
||||
|
||||
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));
|
||||
_index += sizeof(T) * view.size();
|
||||
return sizeof(T) * view.size();
|
||||
}
|
||||
|
||||
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);
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
@ -106,5 +106,7 @@ class BinaryWriter {
|
|||
FILE* _file = nullptr;
|
||||
|
||||
Containers::Array<char> _data;
|
||||
UnsignedLong _index = 0;
|
||||
std::size_t _index = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
# 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
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,21 +14,36 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# 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_EXTENSIONS OFF)
|
||||
|
||||
set(SAVETOOL_PROJECT_VERSION 1.4.3)
|
||||
set(SAVETOOL_PROJECT_VERSION 1.5.0)
|
||||
|
||||
find_package(Corrade REQUIRED Main Containers Utility)
|
||||
find_package(Corrade REQUIRED Containers Utility)
|
||||
if(CORRADE_TARGET_WINDOWS)
|
||||
find_package(Corrade REQUIRED Main)
|
||||
endif()
|
||||
find_package(Magnum REQUIRED GL Sdl2Application)
|
||||
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)
|
||||
|
||||
corrade_add_resource(Assets assets.conf)
|
||||
|
||||
add_library(Logger STATIC EXCLUDE_FROM_ALL
|
||||
set(Logger_SOURCES
|
||||
Logger/Logger.h
|
||||
Logger/Logger.cpp
|
||||
Logger/EntryType.h
|
||||
|
@ -36,164 +51,200 @@ add_library(Logger STATIC EXCLUDE_FROM_ALL
|
|||
Logger/MagnumLogBuffer.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(Logger PRIVATE
|
||||
Corrade::Utility
|
||||
Magnum::Magnum
|
||||
set(BinaryIo_SOURCES
|
||||
BinaryIo/BinaryIo.h
|
||||
BinaryIo/Reader.h
|
||||
BinaryIo/Reader.cpp
|
||||
BinaryIo/Writer.h
|
||||
BinaryIo/Writer.cpp
|
||||
)
|
||||
|
||||
add_library(UESaveFile STATIC EXCLUDE_FROM_ALL
|
||||
UESaveFile/Serialisers/AbstractUnrealCollectionPropertySerialiser.h
|
||||
UESaveFile/Serialisers/AbstractUnrealPropertySerialiser.h
|
||||
UESaveFile/Serialisers/AbstractUnrealStructSerialiser.h
|
||||
UESaveFile/Serialisers/ArrayPropertySerialiser.h
|
||||
UESaveFile/Serialisers/ArrayPropertySerialiser.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
|
||||
set(Gvas_SOURCES
|
||||
Gvas/Serialisers/Serialisers.h
|
||||
Gvas/Serialisers/AbstractUnrealCollectionProperty.h
|
||||
Gvas/Serialisers/AbstractUnrealProperty.h
|
||||
Gvas/Serialisers/AbstractUnrealStruct.h
|
||||
Gvas/Serialisers/ArrayProperty.h
|
||||
Gvas/Serialisers/ArrayProperty.cpp
|
||||
Gvas/Serialisers/BoolProperty.h
|
||||
Gvas/Serialisers/BoolProperty.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
|
||||
|
||||
UESaveFile/Types/ArrayProperty.h
|
||||
UESaveFile/Types/BoolProperty.h
|
||||
UESaveFile/Types/ByteProperty.h
|
||||
UESaveFile/Types/ColourStructProperty.h
|
||||
UESaveFile/Types/DateTimeStructProperty.h
|
||||
UESaveFile/Types/EnumProperty.h
|
||||
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
|
||||
Gvas/Types/Types.h
|
||||
Gvas/Types/ArrayProperty.h
|
||||
Gvas/Types/BoolProperty.h
|
||||
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
|
||||
|
||||
UESaveFile/Debug.h
|
||||
UESaveFile/Debug.cpp
|
||||
UESaveFile/UESaveFile.h
|
||||
UESaveFile/UESaveFile.cpp
|
||||
UESaveFile/BinaryReader.h
|
||||
UESaveFile/BinaryReader.cpp
|
||||
UESaveFile/BinaryWriter.h
|
||||
UESaveFile/BinaryWriter.cpp
|
||||
UESaveFile/PropertySerialiser.h
|
||||
UESaveFile/PropertySerialiser.cpp
|
||||
Gvas/Gvas.h
|
||||
Gvas/Debug.h
|
||||
Gvas/Debug.cpp
|
||||
Gvas/File.h
|
||||
Gvas/File.cpp
|
||||
Gvas/PropertySerialiser.h
|
||||
Gvas/PropertySerialiser.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(UESaveFile PRIVATE
|
||||
Corrade::Containers
|
||||
Corrade::Utility
|
||||
Magnum::Magnum
|
||||
Logger
|
||||
set(ImportExport_SOURCES
|
||||
ImportExport/Import.h
|
||||
ImportExport/Import.cpp
|
||||
ImportExport/Export.h
|
||||
ImportExport/Export.cpp
|
||||
ImportExport/Keys.h
|
||||
)
|
||||
|
||||
add_executable(MassBuilderSaveTool WIN32
|
||||
if(CORRADE_TARGET_WINDOWS)
|
||||
set(SAVETOOL_RC_FILE resource.rc)
|
||||
endif()
|
||||
|
||||
add_executable(MassBuilderSaveTool
|
||||
main.cpp
|
||||
SaveTool/SaveTool.h
|
||||
SaveTool/SaveTool.cpp
|
||||
SaveTool/SaveTool_drawAbout.cpp
|
||||
SaveTool/SaveTool_drawMainMenu.cpp
|
||||
SaveTool/SaveTool_FileWatcher.cpp
|
||||
SaveTool/SaveTool_Initialisation.cpp
|
||||
SaveTool/SaveTool_MainManager.cpp
|
||||
SaveTool/SaveTool_MassViewer.cpp
|
||||
SaveTool/SaveTool_MassViewer_Frame.cpp
|
||||
SaveTool/SaveTool_MassViewer_Armour.cpp
|
||||
SaveTool/SaveTool_MassViewer_Weapons.cpp
|
||||
SaveTool/SaveTool_ProfileManager.cpp
|
||||
SaveTool/SaveTool_UpdateChecker.cpp
|
||||
ProfileManager/ProfileManager.h
|
||||
ProfileManager/ProfileManager.cpp
|
||||
Profile/Profile.h
|
||||
Profile/Profile.cpp
|
||||
Profile/PropertyNames.h
|
||||
Profile/ResourceIDs.h
|
||||
MassManager/MassManager.h
|
||||
MassManager/MassManager.cpp
|
||||
Mass/Accessory.h
|
||||
Mass/ArmourPart.h
|
||||
Mass/BulletLauncherAttachment.h
|
||||
Mass/CustomStyle.h
|
||||
Mass/Decal.h
|
||||
Mass/Joints.h
|
||||
Mass/Mass.h
|
||||
Mass/Mass.cpp
|
||||
Mass/Mass_Frame.cpp
|
||||
Mass/Mass_Armour.cpp
|
||||
Mass/Mass_Weapons.cpp
|
||||
Mass/Mass_Styles.cpp
|
||||
Mass/Mass_DecalsAccessories.cpp
|
||||
Mass/PropertyNames.h
|
||||
Mass/Weapon.h
|
||||
Mass/Weapon.cpp
|
||||
Mass/WeaponPart.h
|
||||
Maps/Accessories.h
|
||||
Maps/ArmourSets.h
|
||||
Application/Application.h
|
||||
Application/Application.cpp
|
||||
Application/Application_drawAbout.cpp
|
||||
Application/Application_drawMainMenu.cpp
|
||||
Application/Application_FileWatcher.cpp
|
||||
Application/Application_Initialisation.cpp
|
||||
Application/Application_MainManager.cpp
|
||||
Application/Application_MassViewer.cpp
|
||||
Application/Application_MassViewer_Frame.cpp
|
||||
Application/Application_MassViewer_Armour.cpp
|
||||
Application/Application_MassViewer_Weapons.cpp
|
||||
Application/Application_ProfileManager.cpp
|
||||
Application/Application_UpdateChecker.cpp
|
||||
Configuration/Configuration.h
|
||||
Configuration/Configuration.cpp
|
||||
FontAwesome/IconsFontAwesome5.h
|
||||
FontAwesome/IconsFontAwesome5Brands.h
|
||||
GameData/Accessories.h
|
||||
GameData/ArmourSets.h
|
||||
GameData/LastMissionId.h
|
||||
GameData/ResourceIDs.h
|
||||
GameData/StoryProgress.h
|
||||
GameData/StyleNames.h
|
||||
GameData/WeaponParts.h
|
||||
GameObjects/Accessory.h
|
||||
GameObjects/ArmourPart.h
|
||||
GameObjects/BulletLauncherAttachment.h
|
||||
GameObjects/CustomStyle.h
|
||||
GameObjects/Decal.h
|
||||
GameObjects/Joints.h
|
||||
GameObjects/Mass.h
|
||||
GameObjects/Mass.cpp
|
||||
GameObjects/Mass_Frame.cpp
|
||||
GameObjects/Mass_Armour.cpp
|
||||
GameObjects/Mass_Weapons.cpp
|
||||
GameObjects/Mass_Styles.cpp
|
||||
GameObjects/Mass_DecalsAccessories.cpp
|
||||
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/BulletLauncherAttachmentStyles.hpp
|
||||
Maps/BulletLauncherSockets.hpp
|
||||
Maps/DamageTypes.hpp
|
||||
Maps/EffectColourModes.hpp
|
||||
Maps/LastMissionId.h
|
||||
Maps/StoryProgress.h
|
||||
Maps/StyleNames.h
|
||||
Maps/WeaponParts.h
|
||||
Maps/WeaponTypes.hpp
|
||||
ToastQueue/ToastQueue.h
|
||||
ToastQueue/ToastQueue.cpp
|
||||
UpdateChecker/UpdateChecker.h
|
||||
UpdateChecker/UpdateChecker.cpp
|
||||
Utilities/Crc32.h
|
||||
FontAwesome/IconsFontAwesome5.h
|
||||
FontAwesome/IconsFontAwesome5Brands.h
|
||||
resource.rc
|
||||
Utilities/Crc32.cpp
|
||||
Utilities/Temp.h
|
||||
Utilities/Temp.cpp
|
||||
Version/Version.h
|
||||
Version/Version.cpp
|
||||
${Logger_SOURCES}
|
||||
${BinaryIo_SOURCES}
|
||||
${Gvas_SOURCES}
|
||||
${ImportExport_SOURCES}
|
||||
${SAVETOOL_RC_FILE}
|
||||
${Assets}
|
||||
)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
add_compile_definitions(SAVETOOL_DEBUG_BUILD)
|
||||
if(CORRADE_TARGET_WINDOWS)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE $<CONFIG:Release>)
|
||||
endif()
|
||||
add_compile_definitions(
|
||||
SAVETOOL_VERSION="${SAVETOOL_PROJECT_VERSION}"
|
||||
SAVETOOL_CODENAME="Enigmatic Ellenier"
|
||||
SUPPORTED_GAME_VERSION="0.9.x"
|
||||
|
||||
target_compile_definitions(MassBuilderSaveTool PRIVATE
|
||||
SAVETOOL_VERSION_STRING="${SAVETOOL_PROJECT_VERSION}"
|
||||
SAVETOOL_VERSION_MAJOR=1
|
||||
SAVETOOL_VERSION_MINOR=5
|
||||
SAVETOOL_VERSION_PATCH=0
|
||||
SAVETOOL_VERSION_PRERELEASE=false
|
||||
SAVETOOL_CODENAME="Fuckin' UE5..."
|
||||
SAVETOOL_SUPPORTED_GAME_VERSION="0.11.x"
|
||||
)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Debug)
|
||||
target_compile_definitions(MassBuilderSaveTool PRIVATE SAVETOOL_DEBUG_BUILD)
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Release)
|
||||
set_target_properties(MassBuilderSaveTool PROPERTIES OUTPUT_NAME MassBuilderSaveTool-${SAVETOOL_PROJECT_VERSION})
|
||||
endif()
|
||||
|
@ -207,16 +258,29 @@ endif()
|
|||
target_link_libraries(MassBuilderSaveTool PRIVATE
|
||||
Corrade::Containers
|
||||
Corrade::Utility
|
||||
Corrade::Main
|
||||
Magnum::Magnum
|
||||
Magnum::GL
|
||||
Magnum::Sdl2Application
|
||||
MagnumIntegration::ImGui
|
||||
Logger
|
||||
UESaveFile
|
||||
efsw
|
||||
zip
|
||||
libcurl
|
||||
CURL::libcurl_static
|
||||
)
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,22 +16,23 @@
|
|||
// 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>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Containers::Literals;
|
||||
using namespace Magnum;
|
||||
|
||||
namespace mbst::GameData {
|
||||
|
||||
struct ArmourSet {
|
||||
Containers::StringView name;
|
||||
bool neck_compatible;
|
||||
};
|
||||
|
||||
static const std::map<Int, ArmourSet> armour_sets {
|
||||
static const std::map<std::int32_t, ArmourSet> armour_sets {
|
||||
{-1, {"<unequipped>"_s, true}},
|
||||
{0, {"Vanguard"_s, true}},
|
||||
{1, {"Assault Mk.I"_s, true}},
|
||||
|
@ -55,4 +56,9 @@ static const std::map<Int, ArmourSet> armour_sets {
|
|||
{25, {"Axial Core R-Type"_s, true}},
|
||||
{26, {"Axial Core S-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
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,17 +16,16 @@
|
|||
// 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 <Magnum/Types.h>
|
||||
namespace mbst::GameData {
|
||||
|
||||
using namespace Magnum;
|
||||
|
||||
enum MaterialID : Int {
|
||||
enum MaterialID : std::int32_t {
|
||||
VerseSteel = 0xC3500,
|
||||
Undinium = 0xC3501,
|
||||
NecriumAlloy = 0xC3502,
|
||||
Lunarite = 0xC3503,
|
||||
Asterite = 0xC3504,
|
||||
HalliteFragma = 0xC3505,
|
||||
Unnoctinium = 0xC3506,
|
||||
|
||||
Ednil = 0xC350A,
|
||||
Nuflalt = 0xC350B,
|
||||
|
@ -34,6 +33,7 @@ enum MaterialID : Int {
|
|||
Soldus = 0xC350D,
|
||||
SynthesisedN = 0xC350E,
|
||||
Nanoc = 0xC350F,
|
||||
Abyssillite = 0xC3510,
|
||||
|
||||
Alcarbonite = 0xC3514,
|
||||
Keriphene = 0xC3515,
|
||||
|
@ -41,6 +41,7 @@ enum MaterialID : Int {
|
|||
Quarkium = 0xC3517,
|
||||
Alterene = 0xC3518,
|
||||
Cosmium = 0xC3519,
|
||||
PurifiedQuarkium = 0xC351A,
|
||||
|
||||
MixedComposition = 0xDBBA0,
|
||||
VoidResidue = 0xDBBA1,
|
||||
|
@ -48,4 +49,7 @@ enum MaterialID : Int {
|
|||
MineralExoskeletology = 0xDBBA3,
|
||||
CarbonisedSkin = 0xDBBA4,
|
||||
IsolatedVoidParticle = 0xDBBA5,
|
||||
WeaponisedPhysiology = 0xDBBA6,
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StringView.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Containers::Literals;
|
||||
using namespace Magnum;
|
||||
|
||||
namespace mbst::GameData {
|
||||
|
||||
struct StoryProgressPoint {
|
||||
Int id;
|
||||
Containers::StringView chapter;
|
||||
Containers::StringView point;
|
||||
std::int32_t id{};
|
||||
Containers::StringView chapter = nullptr;
|
||||
Containers::StringView point = nullptr;
|
||||
Containers::StringView after = nullptr;
|
||||
};
|
||||
|
||||
|
@ -109,6 +108,28 @@ static const Corrade::Containers::Array<StoryProgressPoint> story_progress
|
|||
{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
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include <Magnum/Magnum.h>
|
||||
|
||||
using namespace Corrade;
|
||||
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
|
||||
{
|
||||
{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},
|
||||
{101, "Silver"_s},
|
||||
{102, "Gold"_s},
|
||||
|
@ -194,3 +161,5 @@ extern const std::map<Int, Containers::StringView> style_names
|
|||
}
|
||||
#endif
|
||||
;
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
// 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
|
||||
// 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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
using namespace Containers::Literals;
|
||||
|
||||
namespace mbst::GameData {
|
||||
|
||||
// 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},
|
||||
{1, "Knuckle 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},
|
||||
{6, "Knight Guard Grip (1H)"_s},
|
||||
{7, "Saber Guard Grip (1H)"_s},
|
||||
{8, "Base Grip (1H)"_s},
|
||||
|
||||
{100, "Combat 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},
|
||||
{104, "Locked 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},
|
||||
{201, "Hollowed 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},
|
||||
{401, "Sepal Twin Grip (1H)"_s},
|
||||
{402, "Hollowed Twin Grip (1H)"_s},
|
||||
{403, "Knuckle Guard Twin Grip (1H)"_s},
|
||||
{404, "Arched Twin Grip (1H)"_s},
|
||||
{405, "Handguard Twin Grip (1H)"_s},
|
||||
{406, "Fullguard Twin Grip (1H)"_s},
|
||||
{407, "Base Twin Grip (1H)"_s},
|
||||
|
||||
{1000, "Combat Knuckle (R/L)"_s},
|
||||
{1001, "Battle Fist (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},
|
||||
{2001, "Dual Guard Polearm (2H)"_s},
|
||||
{2002, "Sepal Polearm (2H)"_s},
|
||||
{2003, "Fin 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},
|
||||
{2101, "Plated Side Polearm (2H)"_s},
|
||||
{2102, "Locked 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},
|
||||
{2201, "Studded Dual Polearm (2H)"_s},
|
||||
{2202, "Circular Dual Polearm (2H)"_s},
|
||||
|
||||
{2400, "Combat Twin Blade (2H)"_s},
|
||||
{2401, "Guard Twin Blade (2H)"_s},
|
||||
{2402, "Sepal Twin Blade (2H)"_s},
|
||||
{2403, "Fin Twin Blade (2H)"_s},
|
||||
{2404, "Arched Twin Blade (2H)"_s},
|
||||
{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},
|
||||
{1, "Long Assault 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},
|
||||
{10, "Long Curved Blade"_s},
|
||||
{11, "Long Broad Blade"_s},
|
||||
{12, "Base L Sword"_s},
|
||||
|
||||
{20, "Long Combat 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},
|
||||
{101, "Short Assault Blade"_s},
|
||||
{102, "Short Fin Blade"_s},
|
||||
{103, "Base S Sword"_s},
|
||||
|
||||
{120, "Short Combat Edge"_s},
|
||||
|
||||
|
@ -119,6 +144,7 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
|||
|
||||
{200, "Bracer"_s},
|
||||
{201, "Custom Bracer"_s},
|
||||
{202, "Base Hammer"_s},
|
||||
|
||||
{210, "Expanded Bracer"_s},
|
||||
{211, "Expanded Custom Bracer"_s},
|
||||
|
@ -126,10 +152,18 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
|||
{300, "Heavy Smasher"_s},
|
||||
{301, "Heavy Basher"_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},
|
||||
{401, "Light Basher"_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},
|
||||
{421, "Great Hammer"_s},
|
||||
|
@ -141,13 +175,16 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
|||
|
||||
{500, "Combat Lance"_s},
|
||||
{501, "Gouger Lance"_s},
|
||||
|
||||
{502, "Pointy Lance"_s},
|
||||
{503, "Spinning Pointy Lance (Motion)"_s},
|
||||
{504, "Crystal Lance"_s},
|
||||
{510, "Piercer"_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},
|
||||
|
||||
{610, "Short Piercer"_s},
|
||||
|
||||
{700, "Combat Axe"_s},
|
||||
|
@ -172,7 +209,7 @@ static const std::map<Int, Containers::StringView> melee_assaulters {
|
|||
// endregion
|
||||
|
||||
// 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},
|
||||
{1, "Expanded Handle"_s},
|
||||
{2, "Lowguard Handle"_s},
|
||||
|
@ -191,7 +228,7 @@ static const std::map<Int, Containers::StringView> shield_handles {
|
|||
{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},
|
||||
{1, "Compass Shell"_s},
|
||||
{2, "Uppoint Shell"_s},
|
||||
|
@ -212,7 +249,7 @@ static const std::map<Int, Containers::StringView> shield_shells {
|
|||
// endregion
|
||||
|
||||
// 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},
|
||||
{1, "Light Machine Trigger (1H)"_s},
|
||||
{2, "Tactical Trigger (1H)"_s},
|
||||
|
@ -230,7 +267,7 @@ static const std::map<Int, Containers::StringView> bshooter_triggers {
|
|||
{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},
|
||||
{1, "Shock Absorb Barrel (1 shot) (Motion)"_s},
|
||||
{2, "Muzzlemod Barrel (1 shot)"_s},
|
||||
|
@ -263,11 +300,16 @@ static const std::map<Int, Containers::StringView> bshooter_barrels {
|
|||
{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
|
||||
|
||||
//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},
|
||||
{1, "Underarm Trigger (1H)"_s},
|
||||
{2, "EN-Inverted Trigger (1H)"_s},
|
||||
|
@ -285,7 +327,7 @@ static const std::map<Int, Containers::StringView> eshooter_triggers {
|
|||
{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},
|
||||
{1, "Delta Cycler (1 shot) (Motion)"_s},
|
||||
{2, "EN-Longbarrel Buster (1 shot)"_s},
|
||||
|
@ -317,11 +359,16 @@ static const std::map<Int, Containers::StringView> eshooter_busters {
|
|||
{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
|
||||
|
||||
// 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},
|
||||
{1, "BL-Twin Pack Launcher (Missile x12)"_s},
|
||||
{2, "Detector Launcher (Missile x12)"_s},
|
||||
|
@ -351,7 +398,7 @@ static const std::map<Int, Containers::StringView> blauncher_pods {
|
|||
{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},
|
||||
{1, "Warhead Missile"_s},
|
||||
{2, "Pointhead Missile"_s},
|
||||
|
@ -361,7 +408,7 @@ static const std::map<Int, Containers::StringView> blauncher_projectiles {
|
|||
// endregion
|
||||
|
||||
// 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},
|
||||
{1, "Assault Unit (Motion)"_s},
|
||||
{2, "Falcon Unit"_s},
|
||||
|
@ -393,7 +440,7 @@ static const std::map<Int, Containers::StringView> elauncher_generators {
|
|||
{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},
|
||||
{1, "EN-Assault Launcher (Echo)"_s},
|
||||
{2, "EN-Tactical Launcher (Echo)"_s},
|
||||
|
@ -431,3 +478,5 @@ static const std::map<Int, Containers::StringView> elauncher_pods {
|
|||
{399, "P Base EPod (Photon)"_s},
|
||||
};
|
||||
// endregion
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include <Corrade/Containers/StaticArray.h>
|
||||
|
||||
#include <Magnum/Magnum.h>
|
||||
|
@ -24,13 +26,19 @@
|
|||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
typedef std::variant<Vector3, Vector3d> Vector3Variant;
|
||||
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
struct Accessory {
|
||||
Int attachIndex = -1;
|
||||
Int id = -1;
|
||||
Containers::StaticArray<2, Int> styles{ValueInit};
|
||||
Vector3 relativePosition{0.0f};
|
||||
Vector3 relativePositionOffset{0.0f};
|
||||
Vector3 relativeRotation{0.0f};
|
||||
Vector3 relativeRotationOffset{0.0f};
|
||||
Vector3 localScale{1.0f};
|
||||
std::int32_t attachIndex = -1;
|
||||
std::int32_t id = -1;
|
||||
Containers::StaticArray<2, std::int32_t> styles{ValueInit};
|
||||
Vector3Variant relativePosition{Vector3{}};
|
||||
Vector3Variant relativePositionOffset{Vector3{}};
|
||||
Vector3Variant relativeRotation{Vector3{}};
|
||||
Vector3Variant relativeRotationOffset{Vector3{}};
|
||||
Vector3Variant localScale{Vector3{1.0f}};
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StaticArray.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
#include "Decal.h"
|
||||
#include "Accessory.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
enum class ArmourSlot {
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
struct ArmourPart {
|
||||
enum class Slot {
|
||||
#define c(enumerator, enumstr, name) enumerator,
|
||||
#include "../Maps/ArmourSlots.hpp"
|
||||
#undef c
|
||||
};
|
||||
|
||||
struct ArmourPart {
|
||||
ArmourSlot slot = ArmourSlot::Face;
|
||||
Int id = 0;
|
||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
||||
Slot slot = Slot::Face;
|
||||
std::int32_t id = 0;
|
||||
Containers::StaticArray<4, std::int32_t> styles{ValueInit};
|
||||
Containers::Array<Decal> decals;
|
||||
Containers::Array<Accessory> accessories;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// 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/Math/Vector3.h>
|
||||
|
@ -24,23 +24,28 @@
|
|||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
typedef std::variant<Vector3, Vector3d> Vector3Variant;
|
||||
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
enum class BulletLauncherAttachmentStyle {
|
||||
#define c(enumerator, enumstr) enumerator,
|
||||
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
|
||||
#undef c
|
||||
};
|
||||
|
||||
enum class BulletLauncherSocket {
|
||||
struct BulletLauncherAttachment {
|
||||
enum class Socket {
|
||||
#define c(enumerator, enumstr, name) enumerator,
|
||||
#include "../Maps/BulletLauncherSockets.hpp"
|
||||
#undef c
|
||||
};
|
||||
|
||||
struct BulletLauncherAttachment {
|
||||
BulletLauncherSocket socket = BulletLauncherSocket::Auto;
|
||||
Vector3 relativeLocation;
|
||||
Vector3 offsetLocation;
|
||||
Vector3 relativeRotation;
|
||||
Vector3 offsetRotation;
|
||||
Vector3 relativeScale;
|
||||
Socket socket = Socket::Auto;
|
||||
Vector3Variant relativeLocation;
|
||||
Vector3Variant offsetLocation;
|
||||
Vector3Variant relativeRotation;
|
||||
Vector3Variant offsetRotation;
|
||||
Vector3Variant relativeScale;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -25,16 +25,29 @@
|
|||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
struct CustomStyle {
|
||||
Containers::String name;
|
||||
Color4 colour{0.0f};
|
||||
Float metallic = 0.5f;
|
||||
Float gloss = 0.5f;
|
||||
float metallic = 0.5f;
|
||||
float gloss = 0.5f;
|
||||
bool glow = false;
|
||||
|
||||
Int patternId = 0;
|
||||
Float opacity = 0.5f;
|
||||
std::int32_t patternId = 0;
|
||||
float opacity = 0.5f;
|
||||
Vector2 offset{0.5f};
|
||||
Float rotation = 0.0f;
|
||||
Float scale = 0.5f;
|
||||
float rotation = 0.0f;
|
||||
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
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include <Magnum/Magnum.h>
|
||||
#include <Magnum/Math/Color.h>
|
||||
#include <Magnum/Math/Vector2.h>
|
||||
#include <Magnum/Math/Vector3.h>
|
||||
|
||||
using namespace Magnum;
|
||||
|
||||
typedef std::variant<Vector2, Vector2d> Vector2Variant;
|
||||
typedef std::variant<Vector3, Vector3d> Vector3Variant;
|
||||
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
struct Decal {
|
||||
Int id = -1;
|
||||
std::int32_t id = -1;
|
||||
Color4 colour{0.0f};
|
||||
Vector3 position{0.0f};
|
||||
Vector3 uAxis{0.0f};
|
||||
Vector3 vAxis{0.0f};
|
||||
Vector2 offset{0.5f};
|
||||
Float scale = 0.5f;
|
||||
Float rotation = 0.0f;
|
||||
Vector3Variant position{Vector3{}};
|
||||
Vector3Variant uAxis{Vector3{}};
|
||||
Vector3Variant vAxis{Vector3{}};
|
||||
Vector2Variant offset{Vector2{0.5f}};
|
||||
float scale = 0.5f;
|
||||
float rotation = 0.0f;
|
||||
bool flip = false;
|
||||
bool wrap = false;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
using namespace Magnum;
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
struct Joints {
|
||||
Float neck = 0.0f;
|
||||
Float body = 0.0f;
|
||||
Float shoulders = 0.0f;
|
||||
Float hips = 0.0f;
|
||||
Float upperArms = 0.0f;
|
||||
Float lowerArms = 0.0f;
|
||||
Float upperLegs = 0.0f;
|
||||
Float lowerLegs = 0.0f;
|
||||
float neck = 0.0f;
|
||||
float body = 0.0f;
|
||||
float shoulders = 0.0f;
|
||||
float hips = 0.0f;
|
||||
float upperArms = 0.0f;
|
||||
float lowerArms = 0.0f;
|
||||
float upperLegs = 0.0f;
|
||||
float lowerLegs = 0.0f;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -23,17 +23,19 @@
|
|||
|
||||
#include "PropertyNames.h"
|
||||
#include "../Logger/Logger.h"
|
||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||
#include "../UESaveFile/Types/BoolProperty.h"
|
||||
#include "../UESaveFile/Types/ColourStructProperty.h"
|
||||
#include "../UESaveFile/Types/GenericStructProperty.h"
|
||||
#include "../UESaveFile/Types/IntProperty.h"
|
||||
#include "../UESaveFile/Types/StringProperty.h"
|
||||
#include "../Gvas/Types/ArrayProperty.h"
|
||||
#include "../Gvas/Types/BoolProperty.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 {
|
||||
|
||||
Mass::Mass(Containers::StringView path) {
|
||||
auto split = Utility::Path::split(path);
|
||||
_folder = split.first();
|
||||
|
@ -42,31 +44,33 @@ Mass::Mass(Containers::StringView path) {
|
|||
refreshValues();
|
||||
}
|
||||
|
||||
auto Mass::lastError() -> Containers::StringView {
|
||||
Containers::StringView
|
||||
Mass::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)) {
|
||||
LOG_ERROR_FORMAT("{} couldn't be found.", path);
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
UESaveFile mass{path};
|
||||
Gvas::File mass{path};
|
||||
|
||||
if(!mass.valid()) {
|
||||
LOG_ERROR_FORMAT("{} is invalid: {}", path, mass.lastError());
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
auto unit_data = mass.at<GenericStructProperty>(MASS_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, path);
|
||||
return Containers::NullOpt;
|
||||
}
|
||||
|
||||
auto name_prop = unit_data->at<StringProperty>(MASS_NAME);
|
||||
auto name_prop = unit_data->at<Gvas::Types::StringProperty>(MASS_NAME);
|
||||
|
||||
if(!name_prop) {
|
||||
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_NAME, path);
|
||||
|
@ -76,7 +80,8 @@ auto Mass::getNameFromFile(Containers::StringView path) -> Containers::Optional<
|
|||
return {name_prop->value};
|
||||
}
|
||||
|
||||
void Mass::refreshValues() {
|
||||
void
|
||||
Mass::refreshValues() {
|
||||
LOG_INFO_FORMAT("Refreshing values for {}.", _filename);
|
||||
|
||||
logger().lockMutex();
|
||||
|
@ -122,7 +127,7 @@ void Mass::refreshValues() {
|
|||
}
|
||||
|
||||
LOG_INFO("Getting the unit data.");
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_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;
|
||||
|
@ -130,7 +135,7 @@ void Mass::refreshValues() {
|
|||
}
|
||||
|
||||
LOG_INFO("Reading the M.A.S.S. name.");
|
||||
auto name_prop = unit_data->at<StringProperty>(MASS_NAME);
|
||||
auto name_prop = unit_data->at<Gvas::Types::StringProperty>(MASS_NAME);
|
||||
|
||||
if(!name_prop) {
|
||||
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_NAME, _filename);
|
||||
|
@ -217,7 +222,7 @@ void Mass::refreshValues() {
|
|||
}
|
||||
|
||||
LOG_INFO("Getting the associated account.");
|
||||
auto account_prop = _mass->at<StringProperty>("Account"_s);
|
||||
auto account_prop = _mass->at<Gvas::Types::StringProperty>("Account"_s);
|
||||
if(!account_prop) {
|
||||
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_ACCOUNT, _filename);
|
||||
_state = State::Invalid;
|
||||
|
@ -229,19 +234,22 @@ void Mass::refreshValues() {
|
|||
_state = State::Valid;
|
||||
}
|
||||
|
||||
auto Mass::filename() -> Containers::StringView {
|
||||
Containers::StringView
|
||||
Mass::filename() {
|
||||
return _filename;
|
||||
}
|
||||
|
||||
auto Mass::name() -> Containers::StringView {
|
||||
Containers::StringView
|
||||
Mass::name() {
|
||||
CORRADE_INTERNAL_ASSERT(_name);
|
||||
return *_name;
|
||||
}
|
||||
|
||||
auto Mass::setName(Containers::StringView new_name) -> bool {
|
||||
bool
|
||||
Mass::setName(Containers::StringView 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) {
|
||||
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
|
||||
|
@ -249,7 +257,7 @@ auto Mass::setName(Containers::StringView new_name) -> bool {
|
|||
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) {
|
||||
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_NAME, _filename);
|
||||
|
@ -267,19 +275,22 @@ auto Mass::setName(Containers::StringView new_name) -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto Mass::state() -> State {
|
||||
Mass::State
|
||||
Mass::state() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
auto Mass::dirty() const -> bool {
|
||||
bool Mass::dirty() const {
|
||||
return _dirty;
|
||||
}
|
||||
|
||||
void Mass::setDirty(bool dirty) {
|
||||
void
|
||||
Mass::setDirty(bool dirty) {
|
||||
_dirty = dirty;
|
||||
}
|
||||
|
||||
void Mass::getTuning() {
|
||||
void
|
||||
Mass::getTuning() {
|
||||
getTuningCategory(MASS_ENGINE, _tuning.engineId,
|
||||
MASS_GEARS, _tuning.gearIds);
|
||||
if(_state == State::Invalid) {
|
||||
|
@ -299,38 +310,46 @@ void Mass::getTuning() {
|
|||
}
|
||||
}
|
||||
|
||||
auto Mass::engine() -> Int& {
|
||||
std::int32_t&
|
||||
Mass::engine() {
|
||||
return _tuning.engineId;
|
||||
}
|
||||
|
||||
auto Mass::gears() -> Containers::ArrayView<Int> {
|
||||
Containers::ArrayView<std::int32_t>
|
||||
Mass::gears() {
|
||||
return _tuning.gearIds;
|
||||
}
|
||||
|
||||
auto Mass::os() -> Int& {
|
||||
std::int32_t&
|
||||
Mass::os() {
|
||||
return _tuning.osId;
|
||||
}
|
||||
|
||||
auto Mass::modules() -> Containers::ArrayView<Int> {
|
||||
Containers::ArrayView<std::int32_t>
|
||||
Mass::modules() {
|
||||
return _tuning.moduleIds;
|
||||
}
|
||||
|
||||
auto Mass::architecture() -> Int& {
|
||||
std::int32_t&
|
||||
Mass::architecture() {
|
||||
return _tuning.archId;
|
||||
}
|
||||
|
||||
auto Mass::techs() -> Containers::ArrayView<Int> {
|
||||
Containers::ArrayView<std::int32_t>
|
||||
Mass::techs() {
|
||||
return _tuning.techIds;
|
||||
}
|
||||
|
||||
auto Mass::account() -> Containers::StringView {
|
||||
Containers::StringView
|
||||
Mass::account() {
|
||||
return _account;
|
||||
}
|
||||
|
||||
auto Mass::updateAccount(Containers::StringView new_account) -> bool {
|
||||
bool
|
||||
Mass::updateAccount(Containers::StringView new_account) {
|
||||
_account = new_account;
|
||||
|
||||
auto account = _mass->at<StringProperty>(MASS_ACCOUNT);
|
||||
auto account = _mass->at<Gvas::Types::StringProperty>(MASS_ACCOUNT);
|
||||
if(!account) {
|
||||
_lastError = "Couldn't find the " MASS_ACCOUNT " property."_s;
|
||||
_state = State::Invalid;
|
||||
|
@ -347,12 +366,14 @@ auto Mass::updateAccount(Containers::StringView new_account) -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Mass::getTuningCategory(Containers::StringView big_node_prop_name, Int& big_node_id,
|
||||
Containers::StringView small_nodes_prop_name, Containers::ArrayView<Int> small_nodes_ids)
|
||||
void
|
||||
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)
|
||||
{
|
||||
LOG_INFO_FORMAT("Getting tuning data ({}, {}).", big_node_prop_name, small_nodes_prop_name);
|
||||
|
||||
auto node_id = _mass->at<IntProperty>(big_node_prop_name);
|
||||
auto node_id = _mass->at<Gvas::Types::IntProperty>(big_node_prop_name);
|
||||
if(!node_id) {
|
||||
LOG_ERROR_FORMAT("Couldn't find {} in {}.", big_node_prop_name, _filename);
|
||||
_state = State::Invalid;
|
||||
|
@ -360,7 +381,7 @@ void Mass::getTuningCategory(Containers::StringView big_node_prop_name, Int& big
|
|||
}
|
||||
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) {
|
||||
LOG_ERROR_FORMAT("Couldn't find {} in {}.", small_nodes_prop_name, _filename);
|
||||
_state = State::Invalid;
|
||||
|
@ -374,9 +395,11 @@ void Mass::getTuningCategory(Containers::StringView big_node_prop_name, Int& big
|
|||
return;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < small_nodes_ids.size(); i++) {
|
||||
auto small_node_id = node_ids->at<IntProperty>(i);
|
||||
for(std::uint32_t i = 0; i < small_nodes_ids.size(); i++) {
|
||||
auto small_node_id = node_ids->at<Gvas::Types::IntProperty>(i);
|
||||
CORRADE_INTERNAL_ASSERT(small_node_id);
|
||||
small_nodes_ids[i] = small_node_id->value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -36,19 +36,16 @@
|
|||
#include "WeaponPart.h"
|
||||
#include "Weapon.h"
|
||||
|
||||
#include "../UESaveFile/UESaveFile.h"
|
||||
#include "../Gvas/File.h"
|
||||
#include "../Gvas/Types/Types.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
struct ArrayProperty;
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
class Mass {
|
||||
public:
|
||||
enum class State : UnsignedByte {
|
||||
Empty, Invalid, Valid
|
||||
};
|
||||
|
||||
explicit Mass(Containers::StringView path);
|
||||
|
||||
Mass(const Mass&) = delete;
|
||||
|
@ -66,101 +63,106 @@ class Mass {
|
|||
auto filename() -> 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 dirty() const -> bool;
|
||||
bool dirty() const;
|
||||
void setDirty(bool dirty = true);
|
||||
|
||||
auto jointSliders() -> Joints&;
|
||||
void getJointSliders();
|
||||
auto writeJointSliders() -> bool;
|
||||
bool writeJointSliders();
|
||||
|
||||
auto frameStyles() -> Containers::ArrayView<Int>;
|
||||
auto frameStyles() -> Containers::ArrayView<std::int32_t>;
|
||||
void getFrameStyles();
|
||||
auto writeFrameStyles() -> bool;
|
||||
bool writeFrameStyles();
|
||||
|
||||
auto eyeFlareColour() -> Color4&;
|
||||
void getEyeFlareColour();
|
||||
auto writeEyeFlareColour() -> bool;
|
||||
bool writeEyeFlareColour();
|
||||
|
||||
auto frameCustomStyles() -> Containers::ArrayView<CustomStyle>;
|
||||
void getFrameCustomStyles();
|
||||
auto writeFrameCustomStyle(UnsignedLong index) -> bool;
|
||||
bool writeFrameCustomStyle(std::size_t index);
|
||||
|
||||
auto armourParts() -> Containers::ArrayView<ArmourPart>;
|
||||
void getArmourParts();
|
||||
auto writeArmourPart(ArmourSlot slot) -> bool;
|
||||
bool writeArmourPart(ArmourPart::Slot slot);
|
||||
|
||||
auto bulletLauncherAttachmentStyle() -> BulletLauncherAttachmentStyle&;
|
||||
auto bulletLauncherAttachments() -> Containers::ArrayView<BulletLauncherAttachment>;
|
||||
void getBulletLauncherAttachments();
|
||||
auto writeBulletLauncherAttachments() -> bool;
|
||||
bool writeBulletLauncherAttachments();
|
||||
|
||||
auto armourCustomStyles() -> Containers::ArrayView<CustomStyle>;
|
||||
void getArmourCustomStyles();
|
||||
auto writeArmourCustomStyle(UnsignedLong index) -> bool;
|
||||
bool writeArmourCustomStyle(std::size_t index);
|
||||
|
||||
auto meleeWeapons() -> Containers::ArrayView<Weapon>;
|
||||
void getMeleeWeapons();
|
||||
auto writeMeleeWeapons() -> bool;
|
||||
bool writeMeleeWeapons();
|
||||
|
||||
auto shields() -> Containers::ArrayView<Weapon>;
|
||||
void getShields();
|
||||
auto writeShields() -> bool;
|
||||
bool writeShields();
|
||||
|
||||
auto bulletShooters() -> Containers::ArrayView<Weapon>;
|
||||
void getBulletShooters();
|
||||
auto writeBulletShooters() -> bool;
|
||||
bool writeBulletShooters();
|
||||
|
||||
auto energyShooters() -> Containers::ArrayView<Weapon>;
|
||||
void getEnergyShooters();
|
||||
auto writeEnergyShooters() -> bool;
|
||||
bool writeEnergyShooters();
|
||||
|
||||
auto bulletLaunchers() -> Containers::ArrayView<Weapon>;
|
||||
void getBulletLaunchers();
|
||||
auto writeBulletLaunchers() -> bool;
|
||||
bool writeBulletLaunchers();
|
||||
|
||||
auto energyLaunchers() -> Containers::ArrayView<Weapon>;
|
||||
void getEnergyLaunchers();
|
||||
auto writeEnergyLaunchers() -> bool;
|
||||
bool writeEnergyLaunchers();
|
||||
|
||||
auto globalStyles() -> Containers::ArrayView<CustomStyle>;
|
||||
void getGlobalStyles();
|
||||
auto writeGlobalStyle(UnsignedLong index) -> bool;
|
||||
bool writeGlobalStyle(std::size_t index);
|
||||
|
||||
void getTuning();
|
||||
|
||||
auto engine() -> Int&;
|
||||
auto gears() -> Containers::ArrayView<Int>;
|
||||
auto engine() -> std::int32_t&;
|
||||
auto gears() -> Containers::ArrayView<std::int32_t>;
|
||||
|
||||
auto os() -> Int&;
|
||||
auto modules() -> Containers::ArrayView<Int>;
|
||||
auto os() -> std::int32_t&;
|
||||
auto modules() -> Containers::ArrayView<std::int32_t>;
|
||||
|
||||
auto architecture() -> Int&;
|
||||
auto techs() -> Containers::ArrayView<Int>;
|
||||
auto architecture() -> std::int32_t&;
|
||||
auto techs() -> Containers::ArrayView<std::int32_t>;
|
||||
|
||||
auto account() -> Containers::StringView;
|
||||
auto updateAccount(Containers::StringView new_account) -> bool;
|
||||
bool updateAccount(Containers::StringView new_account);
|
||||
|
||||
private:
|
||||
void getCustomStyles(Containers::ArrayView<CustomStyle> styles, ArrayProperty* style_array);
|
||||
auto writeCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool;
|
||||
void getCustomStyles(Containers::ArrayView<CustomStyle> styles, Gvas::Types::ArrayProperty* style_array);
|
||||
bool writeCustomStyle(const CustomStyle& style, std::size_t index, Gvas::Types::ArrayProperty* style_array);
|
||||
|
||||
void getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array);
|
||||
void writeDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array);
|
||||
void getDecals(Containers::ArrayView<Decal> decals, Gvas::Types::ArrayProperty* decal_array);
|
||||
void writeDecals(Containers::ArrayView<Decal> decals, Gvas::Types::ArrayProperty* decal_array);
|
||||
|
||||
void getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array);
|
||||
void writeAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accs_array);
|
||||
void getAccessories(Containers::ArrayView<Accessory> accessories, Gvas::Types::ArrayProperty* accessory_array);
|
||||
void writeAccessories(Containers::ArrayView<Accessory> accessories, Gvas::Types::ArrayProperty* accs_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,
|
||||
Containers::StringView small_nodes_prop_name, Containers::ArrayView<Int> small_nodes_ids);
|
||||
void 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);
|
||||
|
||||
Containers::Optional<UESaveFile> _mass;
|
||||
Containers::Optional<Gvas::File> _mass;
|
||||
|
||||
Containers::String _lastError;
|
||||
|
||||
|
@ -174,7 +176,7 @@ class Mass {
|
|||
|
||||
struct {
|
||||
Joints joints{};
|
||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
||||
Containers::StaticArray<4, std::int32_t> styles{ValueInit};
|
||||
Color4 eyeFlare{0.0f};
|
||||
Containers::StaticArray<16, CustomStyle> customStyles;
|
||||
} _frame;
|
||||
|
@ -198,15 +200,17 @@ class Mass {
|
|||
Containers::Array<CustomStyle> _globalStyles;
|
||||
|
||||
struct {
|
||||
Int engineId;
|
||||
Containers::StaticArray<7, Int> gearIds;
|
||||
std::int32_t engineId;
|
||||
Containers::StaticArray<7, std::int32_t> gearIds;
|
||||
|
||||
Int osId;
|
||||
Containers::StaticArray<7, Int> moduleIds;
|
||||
std::int32_t osId;
|
||||
Containers::StaticArray<7, std::int32_t> moduleIds;
|
||||
|
||||
Int archId;
|
||||
Containers::StaticArray<7, Int> techIds;
|
||||
std::int32_t archId;
|
||||
Containers::StaticArray<7, std::int32_t> techIds;
|
||||
} _tuning;
|
||||
|
||||
Containers::String _account;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,32 +18,36 @@
|
|||
|
||||
#include "PropertyNames.h"
|
||||
#include "../Logger/Logger.h"
|
||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||
#include "../UESaveFile/Types/ByteProperty.h"
|
||||
#include "../UESaveFile/Types/GenericStructProperty.h"
|
||||
#include "../UESaveFile/Types/IntProperty.h"
|
||||
#include "../UESaveFile/Types/StringProperty.h"
|
||||
#include "../UESaveFile/Types/VectorStructProperty.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;
|
||||
|
||||
auto Mass::armourParts() -> Containers::ArrayView<ArmourPart> {
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
Containers::ArrayView<ArmourPart>
|
||||
Mass::armourParts() {
|
||||
return _armour.parts;
|
||||
}
|
||||
|
||||
void Mass::getArmourParts() {
|
||||
void
|
||||
Mass::getArmourParts() {
|
||||
LOG_INFO("Getting armour parts.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_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;
|
||||
}
|
||||
|
||||
auto armour_array = unit_data->at<ArrayProperty>(MASS_ARMOUR_PARTS);
|
||||
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;
|
||||
|
@ -57,12 +61,12 @@ void Mass::getArmourParts() {
|
|||
return;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < armour_array->items.size(); i++) {
|
||||
auto part_prop = armour_array->at<GenericStructProperty>(i);
|
||||
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<ByteProperty>(MASS_ARMOUR_SLOT)->enumValue;
|
||||
#define c(enumerator, strenum, name) if(armour_slot == (strenum)) { part.slot = ArmourSlot::enumerator; } else
|
||||
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
|
||||
{
|
||||
|
@ -71,9 +75,9 @@ void Mass::getArmourParts() {
|
|||
return;
|
||||
}
|
||||
|
||||
part.id = part_prop->at<IntProperty>(MASS_ARMOUR_ID)->value;
|
||||
part.id = part_prop->at<Gvas::Types::IntProperty>(MASS_ARMOUR_ID)->value;
|
||||
|
||||
auto part_styles = part_prop->at<ArrayProperty>(MASS_ARMOUR_STYLES);
|
||||
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;
|
||||
|
@ -87,11 +91,11 @@ void Mass::getArmourParts() {
|
|||
return;
|
||||
}
|
||||
|
||||
for(UnsignedInt j = 0; j < part_styles->items.size(); j++) {
|
||||
part.styles[j] = part_styles->at<IntProperty>(j)->value;
|
||||
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<ArrayProperty>(MASS_ARMOUR_DECALS);
|
||||
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;
|
||||
|
@ -102,7 +106,7 @@ void Mass::getArmourParts() {
|
|||
|
||||
getDecals(part.decals, decals_array);
|
||||
|
||||
auto accs_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_ACCESSORIES);
|
||||
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>{};
|
||||
|
@ -117,12 +121,13 @@ void Mass::getArmourParts() {
|
|||
}
|
||||
}
|
||||
|
||||
auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
||||
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<GenericStructProperty>(MASS_UNIT_DATA);
|
||||
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);
|
||||
|
@ -130,7 +135,7 @@ auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto armour_array = unit_data->at<ArrayProperty>(MASS_ARMOUR_PARTS);
|
||||
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);
|
||||
|
@ -140,18 +145,18 @@ auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
|||
|
||||
Containers::StringView slot_str = nullptr;
|
||||
switch(slot) {
|
||||
#define c(enumerator, strenum, name) case ArmourSlot::enumerator: \
|
||||
#define c(enumerator, strenum, name) case ArmourPart::Slot::enumerator: \
|
||||
slot_str = strenum; \
|
||||
break;
|
||||
#include "../Maps/ArmourSlots.hpp"
|
||||
#undef c
|
||||
}
|
||||
|
||||
GenericStructProperty* part_prop = nullptr;
|
||||
Gvas::Types::GenericStructProperty* part_prop = nullptr;
|
||||
|
||||
for(UnsignedInt i = 0; i < armour_array->items.size(); i++) {
|
||||
part_prop = armour_array->at<GenericStructProperty>(i);
|
||||
if(slot_str == part_prop->at<ByteProperty>(MASS_ARMOUR_SLOT)->enumValue) {
|
||||
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 {
|
||||
|
@ -162,7 +167,7 @@ auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
|||
if(!part_prop) {
|
||||
auto prefix = "Couldn't find the armour part for slot "_s;
|
||||
switch(slot) {
|
||||
#define c(enumerator, strenum, name) case ArmourSlot::enumerator: \
|
||||
#define c(enumerator, strenum, name) case ArmourPart::Slot::enumerator: \
|
||||
_lastError = prefix + "ArmourSlot::" #enumerator "."_s; \
|
||||
break;
|
||||
#include "../Maps/ArmourSlots.hpp"
|
||||
|
@ -172,18 +177,18 @@ auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
part_prop->at<IntProperty>(MASS_ARMOUR_ID)->value = part.id;
|
||||
part_prop->at<Gvas::Types::IntProperty>(MASS_ARMOUR_ID)->value = part.id;
|
||||
|
||||
auto part_styles = part_prop->at<ArrayProperty>(MASS_ARMOUR_STYLES);
|
||||
for(UnsignedInt i = 0; i < part.styles.size(); i++) {
|
||||
part_styles->at<IntProperty>(i)->value = part.styles[i];
|
||||
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<ArrayProperty>(MASS_ARMOUR_DECALS);
|
||||
auto decals_array = part_prop->at<Gvas::Types::ArrayProperty>(MASS_ARMOUR_DECALS);
|
||||
writeDecals(part.decals, decals_array);
|
||||
|
||||
if(part.accessories.size() != 0) {
|
||||
auto accs_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_ACCESSORIES);
|
||||
if(!part.accessories.isEmpty()) {
|
||||
auto accs_array = part_prop->at<Gvas::Types::ArrayProperty>(MASS_ARMOUR_ACCESSORIES);
|
||||
writeAccessories(part.accessories, accs_array);
|
||||
}
|
||||
|
||||
|
@ -195,26 +200,29 @@ auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto Mass::bulletLauncherAttachmentStyle() -> BulletLauncherAttachmentStyle& {
|
||||
BulletLauncherAttachmentStyle&
|
||||
Mass::bulletLauncherAttachmentStyle() {
|
||||
return _armour.blAttachmentStyle;
|
||||
}
|
||||
|
||||
auto Mass::bulletLauncherAttachments() -> Containers::ArrayView<BulletLauncherAttachment> {
|
||||
Containers::ArrayView<BulletLauncherAttachment>
|
||||
Mass::bulletLauncherAttachments() {
|
||||
return _armour.blAttachment;
|
||||
}
|
||||
|
||||
void Mass::getBulletLauncherAttachments() {
|
||||
void
|
||||
Mass::getBulletLauncherAttachments() {
|
||||
LOG_INFO("Getting the bullet launcher attachment data.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_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;
|
||||
}
|
||||
|
||||
auto attach_style_prop = unit_data->at<ByteProperty>(MASS_BL_ATTACHMENT_STYLE);
|
||||
auto attach_array = unit_data->at<ArrayProperty>(MASS_BL_ATTACHMENTS);
|
||||
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);
|
||||
|
@ -232,12 +240,12 @@ void Mass::getBulletLauncherAttachments() {
|
|||
if(attach_array->items.size() == _weapons.bulletLaunchers.size() &&
|
||||
attach_array->items.size() == _armour.blAttachment.size())
|
||||
{
|
||||
for(UnsignedInt i = 0; i < attach_array->items.size(); i++) {
|
||||
auto attachment_prop = attach_array->at<GenericStructProperty>(i);
|
||||
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<StringProperty>(MASS_BL_ATTACHMENT_SOCKET)->value;
|
||||
#define c(enumerator, strenum, name) if(socket == (strenum)) { attachment.socket = BulletLauncherSocket::enumerator; } else
|
||||
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
|
||||
{
|
||||
|
@ -246,16 +254,16 @@ void Mass::getBulletLauncherAttachments() {
|
|||
return;
|
||||
}
|
||||
|
||||
auto rel_loc_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELLOC);
|
||||
attachment.relativeLocation = Vector3{rel_loc_prop->x, rel_loc_prop->y, rel_loc_prop->z};
|
||||
auto off_loc_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_OFFLOC);
|
||||
attachment.offsetLocation = Vector3{off_loc_prop->x, off_loc_prop->y, off_loc_prop->z};
|
||||
auto rel_rot_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELROT);
|
||||
attachment.relativeRotation = Vector3{rel_rot_prop->x, rel_rot_prop->y, rel_rot_prop->z};
|
||||
auto off_rot_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_OFFROT);
|
||||
attachment.offsetRotation = Vector3{off_rot_prop->x, off_rot_prop->y, off_rot_prop->z};
|
||||
auto rel_scale_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELSCALE);
|
||||
attachment.relativeScale = Vector3{rel_scale_prop->x, rel_scale_prop->y, rel_scale_prop->z};
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,10 +282,11 @@ void Mass::getBulletLauncherAttachments() {
|
|||
}
|
||||
}
|
||||
|
||||
auto Mass::writeBulletLauncherAttachments() -> bool {
|
||||
bool
|
||||
Mass::writeBulletLauncherAttachments() {
|
||||
LOG_INFO("Writing bullet launcher attachments.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||
if(!unit_data) {
|
||||
_lastError = "No unit data in " + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
|
@ -285,8 +294,8 @@ auto Mass::writeBulletLauncherAttachments() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto attach_style_prop = unit_data->at<ByteProperty>(MASS_BL_ATTACHMENT_STYLE);
|
||||
auto attach_array = unit_data->at<ArrayProperty>(MASS_BL_ATTACHMENTS);
|
||||
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;
|
||||
|
@ -306,13 +315,13 @@ auto Mass::writeBulletLauncherAttachments() -> bool {
|
|||
if(attach_array->items.size() == _weapons.bulletLaunchers.size() &&
|
||||
attach_array->items.size() == _armour.blAttachment.size())
|
||||
{
|
||||
for(UnsignedInt i = 0; i < attach_array->items.size(); i++) {
|
||||
auto attachment_prop = attach_array->at<GenericStructProperty>(i);
|
||||
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<StringProperty>(MASS_BL_ATTACHMENT_SOCKET)->value;
|
||||
auto& socket = attachment_prop->at<Gvas::Types::StringProperty>(MASS_BL_ATTACHMENT_SOCKET)->value;
|
||||
switch(attachment.socket) {
|
||||
#define c(enumerator, strenum, name) case BulletLauncherSocket::enumerator: socket = strenum; break;
|
||||
#define c(enumerator, strenum, name) case BulletLauncherAttachment::Socket::enumerator: socket = strenum; break;
|
||||
#include "../Maps/BulletLauncherSockets.hpp"
|
||||
#undef c
|
||||
default:
|
||||
|
@ -321,35 +330,25 @@ auto Mass::writeBulletLauncherAttachments() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto rel_loc_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELLOC);
|
||||
rel_loc_prop->x = attachment.relativeLocation.x();
|
||||
rel_loc_prop->y = attachment.relativeLocation.y();
|
||||
rel_loc_prop->z = attachment.relativeLocation.z();
|
||||
auto off_loc_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_OFFLOC);
|
||||
off_loc_prop->x = attachment.offsetLocation.x();
|
||||
off_loc_prop->y = attachment.offsetLocation.y();
|
||||
off_loc_prop->z = attachment.offsetLocation.z();
|
||||
auto rel_rot_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELROT);
|
||||
rel_rot_prop->x = attachment.relativeRotation.x();
|
||||
rel_rot_prop->y = attachment.relativeRotation.y();
|
||||
rel_rot_prop->z = attachment.relativeRotation.z();
|
||||
auto off_rot_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_OFFROT);
|
||||
off_rot_prop->x = attachment.offsetRotation.x();
|
||||
off_rot_prop->y = attachment.offsetRotation.y();
|
||||
off_rot_prop->z = attachment.offsetRotation.z();
|
||||
auto rel_scale_prop = attachment_prop->at<VectorStructProperty>(MASS_BL_ATTACHMENT_RELSCALE);
|
||||
rel_scale_prop->x = attachment.relativeScale.x();
|
||||
rel_scale_prop->y = attachment.relativeScale.y();
|
||||
rel_scale_prop->z = attachment.relativeScale.z();
|
||||
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 ByteProperty;
|
||||
attach_style_prop = new Gvas::Types::ByteProperty;
|
||||
attach_style_prop->name.emplace(MASS_BL_ATTACHMENT_STYLE);
|
||||
attach_style_prop->enumType = "enuBLAttachmentStyle"_s;
|
||||
ByteProperty::ptr prop{attach_style_prop};
|
||||
arrayAppend(unit_data->properties, std::move(prop));
|
||||
Gvas::Types::ByteProperty::ptr prop{attach_style_prop};
|
||||
arrayAppend(unit_data->properties, Utility::move(prop));
|
||||
}
|
||||
|
||||
auto& attach_style = attach_style_prop->enumValue;
|
||||
|
@ -373,21 +372,23 @@ auto Mass::writeBulletLauncherAttachments() -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto Mass::armourCustomStyles() -> Containers::ArrayView<CustomStyle> {
|
||||
Containers::ArrayView<CustomStyle>
|
||||
Mass::armourCustomStyles() {
|
||||
return _armour.customStyles;
|
||||
}
|
||||
|
||||
void Mass::getArmourCustomStyles() {
|
||||
void
|
||||
Mass::getArmourCustomStyles() {
|
||||
LOG_INFO("Getting the custom armour styles.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_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;
|
||||
}
|
||||
|
||||
auto armour_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_ARMOUR_STYLES);
|
||||
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;
|
||||
|
@ -402,9 +403,14 @@ void Mass::getArmourCustomStyles() {
|
|||
}
|
||||
|
||||
getCustomStyles(_armour.customStyles, armour_styles);
|
||||
|
||||
for(auto& style : _armour.customStyles) {
|
||||
style.type = CustomStyle::Type::Armour;
|
||||
}
|
||||
}
|
||||
|
||||
auto Mass::writeArmourCustomStyle(UnsignedLong index) -> bool {
|
||||
bool
|
||||
Mass::writeArmourCustomStyle(std::size_t index) {
|
||||
LOG_INFO_FORMAT("Writing custom armour style {}.", index);
|
||||
|
||||
if(index > _armour.customStyles.size()) {
|
||||
|
@ -413,7 +419,7 @@ auto Mass::writeArmourCustomStyle(UnsignedLong index) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||
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);
|
||||
|
@ -421,7 +427,7 @@ auto Mass::writeArmourCustomStyle(UnsignedLong index) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto armour_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_ARMOUR_STYLES);
|
||||
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);
|
||||
|
@ -431,3 +437,5 @@ auto Mass::writeArmourCustomStyle(UnsignedLong index) -> bool {
|
|||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,59 +16,64 @@
|
|||
|
||||
#include "PropertyNames.h"
|
||||
#include "../Logger/Logger.h"
|
||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||
#include "../UESaveFile/Types/ColourStructProperty.h"
|
||||
#include "../UESaveFile/Types/FloatProperty.h"
|
||||
#include "../UESaveFile/Types/GenericStructProperty.h"
|
||||
#include "../UESaveFile/Types/IntProperty.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;
|
||||
|
||||
auto Mass::jointSliders() -> Joints& {
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
Joints&
|
||||
Mass::jointSliders() {
|
||||
return _frame.joints;
|
||||
}
|
||||
|
||||
void Mass::getJointSliders() {
|
||||
void
|
||||
Mass::getJointSliders() {
|
||||
LOG_INFO("Getting joint sliders.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_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;
|
||||
}
|
||||
|
||||
auto frame_prop = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||
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<FloatProperty>(MASS_JOINT_NECK);
|
||||
auto length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_NECK);
|
||||
_frame.joints.neck = (length ? length->value : 0.0f);
|
||||
length = frame_prop->at<FloatProperty>(MASS_JOINT_BODY);
|
||||
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_BODY);
|
||||
_frame.joints.body = (length ? length->value : 0.0f);
|
||||
length = frame_prop->at<FloatProperty>(MASS_JOINT_SHOULDER);
|
||||
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_SHOULDER);
|
||||
_frame.joints.shoulders = (length ? length->value : 0.0f);
|
||||
length = frame_prop->at<FloatProperty>(MASS_JOINT_HIP);
|
||||
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_HIP);
|
||||
_frame.joints.hips = (length ? length->value : 0.0f);
|
||||
length = frame_prop->at<FloatProperty>(MASS_JOINT_ARM_UPPER);
|
||||
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_ARM_UPPER);
|
||||
_frame.joints.upperArms = (length ? length->value : 0.0f);
|
||||
length = frame_prop->at<FloatProperty>(MASS_JOINT_ARM_LOWER);
|
||||
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_ARM_LOWER);
|
||||
_frame.joints.lowerArms = (length ? length->value : 0.0f);
|
||||
length = frame_prop->at<FloatProperty>(MASS_JOINT_LEG_UPPER);
|
||||
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_LEG_UPPER);
|
||||
_frame.joints.upperLegs = (length ? length->value : 0.0f);
|
||||
length = frame_prop->at<FloatProperty>(MASS_JOINT_LEG_LOWER);
|
||||
length = frame_prop->at<Gvas::Types::FloatProperty>(MASS_JOINT_LEG_LOWER);
|
||||
_frame.joints.lowerLegs = (length ? length->value : 0.0f);
|
||||
}
|
||||
|
||||
auto Mass::writeJointSliders() -> bool {
|
||||
bool
|
||||
Mass::writeJointSliders() {
|
||||
LOG_INFO("Writing joint sliders");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||
if(!unit_data) {
|
||||
_lastError = "No unit data in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
|
@ -76,7 +81,7 @@ auto Mass::writeJointSliders() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto frame_prop = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||
auto frame_prop = unit_data->at<Gvas::Types::GenericStructProperty>(MASS_FRAME);
|
||||
|
||||
if(!frame_prop) {
|
||||
_lastError = "No frame data in "_s + _filename;
|
||||
|
@ -85,93 +90,93 @@ auto Mass::writeJointSliders() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
Containers::Array<UnrealPropertyBase::ptr> temp;
|
||||
Containers::Array<Gvas::Types::UnrealPropertyBase::ptr> temp;
|
||||
|
||||
auto length = frame_prop->atMove<FloatProperty>(MASS_JOINT_NECK);
|
||||
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, std::move(length));
|
||||
arrayAppend(temp, Utility::move(length));
|
||||
}
|
||||
|
||||
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_BODY);
|
||||
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, std::move(length));
|
||||
arrayAppend(temp, Utility::move(length));
|
||||
}
|
||||
|
||||
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_SHOULDER);
|
||||
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, std::move(length));
|
||||
arrayAppend(temp, Utility::move(length));
|
||||
}
|
||||
|
||||
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_ARM_UPPER);
|
||||
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, std::move(length));
|
||||
arrayAppend(temp, Utility::move(length));
|
||||
}
|
||||
|
||||
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_ARM_LOWER);
|
||||
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, std::move(length));
|
||||
arrayAppend(temp, Utility::move(length));
|
||||
}
|
||||
|
||||
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_HIP);
|
||||
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, std::move(length));
|
||||
arrayAppend(temp, Utility::move(length));
|
||||
}
|
||||
|
||||
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_LEG_UPPER);
|
||||
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, std::move(length));
|
||||
arrayAppend(temp, Utility::move(length));
|
||||
}
|
||||
|
||||
length = frame_prop->atMove<FloatProperty>(MASS_JOINT_LEG_LOWER);
|
||||
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, std::move(length));
|
||||
arrayAppend(temp, Utility::move(length));
|
||||
}
|
||||
|
||||
arrayAppend(temp, std::move(frame_prop->properties[frame_prop->properties.size() - 3]));
|
||||
arrayAppend(temp, std::move(frame_prop->properties[frame_prop->properties.size() - 2]));
|
||||
arrayAppend(temp, std::move(frame_prop->properties[frame_prop->properties.size() - 1]));
|
||||
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 = std::move(temp);
|
||||
frame_prop->properties = Utility::move(temp);
|
||||
|
||||
if(!_mass->saveToFile()) {
|
||||
_lastError = _mass->lastError();
|
||||
|
@ -181,28 +186,30 @@ auto Mass::writeJointSliders() -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto Mass::frameStyles() -> Containers::ArrayView<Int> {
|
||||
Containers::ArrayView<std::int32_t>
|
||||
Mass::frameStyles() {
|
||||
return _frame.styles;
|
||||
}
|
||||
|
||||
void Mass::getFrameStyles() {
|
||||
void
|
||||
Mass::getFrameStyles() {
|
||||
LOG_INFO("Getting frame styles.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_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;
|
||||
}
|
||||
|
||||
auto frame_prop = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||
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<ArrayProperty>(MASS_FRAME_STYLES);
|
||||
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;
|
||||
|
@ -216,15 +223,16 @@ void Mass::getFrameStyles() {
|
|||
return;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < frame_styles->items.size(); i++) {
|
||||
_frame.styles[i] = frame_styles->at<IntProperty>(i)->value;
|
||||
for(std::uint32_t i = 0; i < frame_styles->items.size(); i++) {
|
||||
_frame.styles[i] = frame_styles->at<Gvas::Types::IntProperty>(i)->value;
|
||||
}
|
||||
}
|
||||
|
||||
auto Mass::writeFrameStyles() -> bool {
|
||||
bool
|
||||
Mass::writeFrameStyles() {
|
||||
LOG_INFO("Writing frame styles.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||
if(!unit_data) {
|
||||
_lastError = "No unit data in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
|
@ -232,7 +240,7 @@ auto Mass::writeFrameStyles() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto frame = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||
auto frame = unit_data->at<Gvas::Types::GenericStructProperty>(MASS_FRAME);
|
||||
if(!frame) {
|
||||
_lastError = "No frame data in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
|
@ -240,7 +248,7 @@ auto Mass::writeFrameStyles() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto frame_styles = frame->at<ArrayProperty>(MASS_FRAME_STYLES);
|
||||
auto frame_styles = frame->at<Gvas::Types::ArrayProperty>(MASS_FRAME_STYLES);
|
||||
if(!frame_styles) {
|
||||
_lastError = "No frame styles in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
|
@ -248,8 +256,8 @@ auto Mass::writeFrameStyles() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < frame_styles->items.size(); i++) {
|
||||
frame_styles->at<IntProperty>(i)->value = _frame.styles[i];
|
||||
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()) {
|
||||
|
@ -260,28 +268,30 @@ auto Mass::writeFrameStyles() -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto Mass::eyeFlareColour() -> Color4& {
|
||||
Color4&
|
||||
Mass::eyeFlareColour() {
|
||||
return _frame.eyeFlare;
|
||||
}
|
||||
|
||||
void Mass::getEyeFlareColour() {
|
||||
void
|
||||
Mass::getEyeFlareColour() {
|
||||
LOG_INFO("Getting the eye flare colour.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_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;
|
||||
}
|
||||
|
||||
auto frame_prop = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||
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<ColourStructProperty>(MASS_EYE_FLARE);
|
||||
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;
|
||||
|
@ -291,10 +301,11 @@ void Mass::getEyeFlareColour() {
|
|||
_frame.eyeFlare = Color4{eye_flare_prop->r, eye_flare_prop->g, eye_flare_prop->b, eye_flare_prop->a};
|
||||
}
|
||||
|
||||
auto Mass::writeEyeFlareColour() -> bool {
|
||||
bool
|
||||
Mass::writeEyeFlareColour() {
|
||||
LOG_INFO("Writing the eye flare colour.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||
if(!unit_data) {
|
||||
_lastError = "No unit data in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
|
@ -302,7 +313,7 @@ auto Mass::writeEyeFlareColour() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto frame = unit_data->at<GenericStructProperty>(MASS_FRAME);
|
||||
auto frame = unit_data->at<Gvas::Types::GenericStructProperty>(MASS_FRAME);
|
||||
if(!frame) {
|
||||
_lastError = "No frame data in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
|
@ -310,7 +321,7 @@ auto Mass::writeEyeFlareColour() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto eye_flare_prop = frame->at<ColourStructProperty>(MASS_EYE_FLARE);
|
||||
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);
|
||||
|
@ -331,21 +342,23 @@ auto Mass::writeEyeFlareColour() -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
auto Mass::frameCustomStyles() -> Containers::ArrayView<CustomStyle> {
|
||||
Containers::ArrayView<CustomStyle>
|
||||
Mass::frameCustomStyles() {
|
||||
return _frame.customStyles;
|
||||
}
|
||||
|
||||
void Mass::getFrameCustomStyles() {
|
||||
void
|
||||
Mass::getFrameCustomStyles() {
|
||||
LOG_INFO("Getting the frame's custom styles.");
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_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;
|
||||
}
|
||||
|
||||
auto frame_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_FRAME_STYLES);
|
||||
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;
|
||||
|
@ -360,9 +373,14 @@ void Mass::getFrameCustomStyles() {
|
|||
}
|
||||
|
||||
getCustomStyles(_frame.customStyles, frame_styles);
|
||||
|
||||
for(auto& style : _frame.customStyles) {
|
||||
style.type = CustomStyle::Type::Frame;
|
||||
}
|
||||
}
|
||||
|
||||
auto Mass::writeFrameCustomStyle(UnsignedLong index) -> bool {
|
||||
bool
|
||||
Mass::writeFrameCustomStyle(std::size_t index) {
|
||||
LOG_INFO_FORMAT("Writing frame custom style number {}.", index);
|
||||
|
||||
if(index > _frame.customStyles.size()) {
|
||||
|
@ -371,7 +389,7 @@ auto Mass::writeFrameCustomStyle(UnsignedLong index) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||
auto unit_data = _mass->at<Gvas::Types::GenericStructProperty>(MASS_UNIT_DATA);
|
||||
if(!unit_data) {
|
||||
_lastError = "No unit data in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
|
@ -379,7 +397,7 @@ auto Mass::writeFrameCustomStyle(UnsignedLong index) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto frame_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_FRAME_STYLES);
|
||||
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);
|
||||
|
@ -389,3 +407,5 @@ auto Mass::writeFrameCustomStyle(UnsignedLong index) -> bool {
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,111 +16,132 @@
|
|||
|
||||
#include "PropertyNames.h"
|
||||
#include "../Logger/Logger.h"
|
||||
#include "../UESaveFile/Types/ArrayProperty.h"
|
||||
#include "../UESaveFile/Types/BoolProperty.h"
|
||||
#include "../UESaveFile/Types/ByteProperty.h"
|
||||
#include "../UESaveFile/Types/ColourStructProperty.h"
|
||||
#include "../UESaveFile/Types/GenericStructProperty.h"
|
||||
#include "../UESaveFile/Types/IntProperty.h"
|
||||
#include "../UESaveFile/Types/StringProperty.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;
|
||||
|
||||
auto Mass::meleeWeapons() -> Containers::ArrayView<Weapon> {
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
Containers::ArrayView<Weapon>
|
||||
Mass::meleeWeapons() {
|
||||
return _weapons.melee;
|
||||
}
|
||||
|
||||
void Mass::getMeleeWeapons() {
|
||||
void
|
||||
Mass::getMeleeWeapons() {
|
||||
LOG_INFO("Getting melee weapons.");
|
||||
getWeaponType(MASS_WEAPONS_MELEE, _weapons.melee);
|
||||
}
|
||||
|
||||
auto Mass::writeMeleeWeapons() -> bool {
|
||||
bool
|
||||
Mass::writeMeleeWeapons() {
|
||||
LOG_INFO("Writing melee weapons.");
|
||||
return writeWeaponType(MASS_WEAPONS_MELEE, _weapons.melee);
|
||||
}
|
||||
|
||||
auto Mass::shields() -> Containers::ArrayView<Weapon> {
|
||||
Containers::ArrayView<Weapon>
|
||||
Mass::shields() {
|
||||
return _weapons.shields;
|
||||
}
|
||||
|
||||
void Mass::getShields() {
|
||||
void
|
||||
Mass::getShields() {
|
||||
LOG_INFO("Getting shields.");
|
||||
getWeaponType(MASS_WEAPONS_SHIELD, _weapons.shields);
|
||||
}
|
||||
|
||||
auto Mass::writeShields() -> bool {
|
||||
bool
|
||||
Mass::writeShields() {
|
||||
LOG_INFO("Writing shields.");
|
||||
return writeWeaponType(MASS_WEAPONS_SHIELD, _weapons.shields);
|
||||
}
|
||||
|
||||
auto Mass::bulletShooters() -> Containers::ArrayView<Weapon> {
|
||||
Containers::ArrayView<Weapon>
|
||||
Mass::bulletShooters() {
|
||||
return _weapons.bulletShooters;
|
||||
}
|
||||
|
||||
void Mass::getBulletShooters() {
|
||||
void
|
||||
Mass::getBulletShooters() {
|
||||
LOG_INFO("Getting bullet shooters.");
|
||||
getWeaponType(MASS_WEAPONS_BSHOOTER, _weapons.bulletShooters);
|
||||
}
|
||||
|
||||
auto Mass::writeBulletShooters() -> bool {
|
||||
bool
|
||||
Mass::writeBulletShooters() {
|
||||
LOG_INFO("Writing bullet shooters.");
|
||||
return writeWeaponType(MASS_WEAPONS_BSHOOTER, _weapons.bulletShooters);
|
||||
}
|
||||
|
||||
auto Mass::energyShooters() -> Containers::ArrayView<Weapon> {
|
||||
Containers::ArrayView<Weapon>
|
||||
Mass::energyShooters() {
|
||||
return _weapons.energyShooters;
|
||||
}
|
||||
|
||||
void Mass::getEnergyShooters() {
|
||||
void
|
||||
Mass::getEnergyShooters() {
|
||||
LOG_INFO("Getting energy shooters.");
|
||||
getWeaponType(MASS_WEAPONS_ESHOOTER, _weapons.energyShooters);
|
||||
}
|
||||
|
||||
auto Mass::writeEnergyShooters() -> bool {
|
||||
bool
|
||||
Mass::writeEnergyShooters() {
|
||||
LOG_INFO("Writing energy shooters.");
|
||||
return writeWeaponType(MASS_WEAPONS_ESHOOTER, _weapons.energyShooters);
|
||||
}
|
||||
|
||||
auto Mass::bulletLaunchers() -> Containers::ArrayView<Weapon> {
|
||||
Containers::ArrayView<Weapon>
|
||||
Mass::bulletLaunchers() {
|
||||
return _weapons.bulletLaunchers;
|
||||
}
|
||||
|
||||
void Mass::getBulletLaunchers() {
|
||||
void
|
||||
Mass::getBulletLaunchers() {
|
||||
LOG_INFO("Getting bullet launchers.");
|
||||
getWeaponType(MASS_WEAPONS_BLAUNCHER, _weapons.bulletLaunchers);
|
||||
}
|
||||
|
||||
auto Mass::writeBulletLaunchers() -> bool {
|
||||
bool
|
||||
Mass::writeBulletLaunchers() {
|
||||
LOG_INFO("Writing bullet launchers.");
|
||||
return writeWeaponType(MASS_WEAPONS_BLAUNCHER, _weapons.bulletLaunchers);
|
||||
}
|
||||
|
||||
auto Mass::energyLaunchers() -> Containers::ArrayView<Weapon> {
|
||||
Containers::ArrayView<Weapon>
|
||||
Mass::energyLaunchers() {
|
||||
return _weapons.energyLaunchers;
|
||||
}
|
||||
|
||||
void Mass::getEnergyLaunchers() {
|
||||
void
|
||||
Mass::getEnergyLaunchers() {
|
||||
LOG_INFO("Getting energy launchers.");
|
||||
getWeaponType(MASS_WEAPONS_ELAUNCHER, _weapons.energyLaunchers);
|
||||
}
|
||||
|
||||
auto Mass::writeEnergyLaunchers() -> bool {
|
||||
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<GenericStructProperty>(MASS_UNIT_DATA);
|
||||
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<ArrayProperty>(prop_name);
|
||||
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;
|
||||
|
@ -134,13 +155,13 @@ void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView
|
|||
return;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < weapon_array.size(); i++) {
|
||||
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
||||
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<StringProperty>(MASS_WEAPON_NAME)->value;
|
||||
auto& weapon_type = weapon_prop->at<ByteProperty>(MASS_WEAPON_TYPE)->enumValue;
|
||||
#define c(enumerator, strenum, name) if(weapon_type == (strenum)) { weapon.type = WeaponType::enumerator; } else
|
||||
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
|
||||
{
|
||||
|
@ -149,28 +170,28 @@ void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView
|
|||
return;
|
||||
}
|
||||
|
||||
auto parts_prop = weapon_prop->at<ArrayProperty>(MASS_WEAPON_ELEMENT);
|
||||
auto parts_prop = weapon_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_ELEMENT);
|
||||
weapon.parts = Containers::Array<WeaponPart>{ValueInit, parts_prop->items.size()};
|
||||
|
||||
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
||||
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
||||
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<IntProperty>(MASS_WEAPON_PART_ID)->value;
|
||||
part.id = part_prop->at<Gvas::Types::IntProperty>(MASS_WEAPON_PART_ID)->value;
|
||||
|
||||
auto part_styles = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_STYLES);
|
||||
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
||||
part.styles[k] = part_styles->at<IntProperty>(k)->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<ArrayProperty>(MASS_WEAPON_PART_DECALS);
|
||||
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<ArrayProperty>(MASS_WEAPON_PART_ACCESSORIES);
|
||||
auto part_accs = part_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_PART_ACCESSORIES);
|
||||
if(!part_accs) {
|
||||
part.accessories = Containers::Array<Accessory>{0};
|
||||
continue;
|
||||
|
@ -182,7 +203,7 @@ void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView
|
|||
getAccessories(part.accessories, part_accs);
|
||||
}
|
||||
|
||||
auto custom_styles = weapon_prop->at<ArrayProperty>(MASS_CUSTOM_WEAPON_STYLES);
|
||||
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;
|
||||
|
@ -198,9 +219,13 @@ void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView
|
|||
|
||||
getCustomStyles(weapon.customStyles, custom_styles);
|
||||
|
||||
weapon.attached = weapon_prop->at<BoolProperty>(MASS_WEAPON_ATTACH)->value;
|
||||
auto& damage_type = weapon_prop->at<ByteProperty>(MASS_WEAPON_DAMAGE_TYPE)->enumValue;
|
||||
#define c(enumerator, strenum) if(damage_type == (strenum)) { weapon.damageType = DamageType::enumerator; } else
|
||||
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
|
||||
{
|
||||
|
@ -208,9 +233,9 @@ void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView
|
|||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
weapon.dualWield = weapon_prop->at<BoolProperty>(MASS_WEAPON_DUAL_WIELD)->value;
|
||||
auto& effect_colour_mode = weapon_prop->at<ByteProperty>(MASS_WEAPON_COLOUR_EFX_MODE)->enumValue;
|
||||
#define c(enumerator, strenum) if(effect_colour_mode == (strenum)) { weapon.effectColourMode = EffectColourMode::enumerator; } else
|
||||
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
|
||||
{
|
||||
|
@ -218,13 +243,14 @@ void Mass::getWeaponType(Containers::StringView prop_name, Containers::ArrayView
|
|||
_state = State::Invalid;
|
||||
return;
|
||||
}
|
||||
auto effect_colour = weapon_prop->at<ColourStructProperty>(MASS_WEAPON_COLOUR_EFX);
|
||||
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};
|
||||
}
|
||||
}
|
||||
|
||||
auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool {
|
||||
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
|
||||
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);
|
||||
|
@ -232,7 +258,7 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
|||
return false;
|
||||
}
|
||||
|
||||
auto prop = unit_data->at<ArrayProperty>(prop_name);
|
||||
auto prop = unit_data->at<Gvas::Types::ArrayProperty>(prop_name);
|
||||
if(!prop) {
|
||||
_lastError = prop_name + " not found in "_s + _filename;
|
||||
LOG_ERROR(_lastError);
|
||||
|
@ -248,13 +274,13 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
|||
return false;
|
||||
}
|
||||
|
||||
for(UnsignedInt i = 0; i < weapon_array.size(); i++) {
|
||||
auto weapon_prop = prop->at<GenericStructProperty>(i);
|
||||
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<StringProperty>(MASS_WEAPON_NAME)->value = weapon.name;
|
||||
weapon_prop->at<Gvas::Types::StringProperty>(MASS_WEAPON_NAME)->value = weapon.name;
|
||||
switch(weapon.type) {
|
||||
#define c(enumerator, strenum, name) case WeaponType::enumerator: weapon_prop->at<ByteProperty>(MASS_WEAPON_TYPE)->enumValue = strenum; break;
|
||||
#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:
|
||||
|
@ -263,7 +289,7 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
|||
return false;
|
||||
}
|
||||
|
||||
auto parts_prop = weapon_prop->at<ArrayProperty>(MASS_WEAPON_ELEMENT);
|
||||
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());
|
||||
|
@ -272,21 +298,21 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
|||
return false;
|
||||
}
|
||||
|
||||
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
|
||||
auto part_prop = parts_prop->at<GenericStructProperty>(j);
|
||||
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<IntProperty>(MASS_WEAPON_PART_ID)->value = part.id;
|
||||
part_prop->at<Gvas::Types::IntProperty>(MASS_WEAPON_PART_ID)->value = part.id;
|
||||
|
||||
auto part_styles = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_STYLES);
|
||||
for(UnsignedInt k = 0; k < part_styles->items.size(); k++) {
|
||||
part_styles->at<IntProperty>(k)->value = part.styles[k];
|
||||
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<ArrayProperty>(MASS_WEAPON_PART_DECALS);
|
||||
auto part_decals = part_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_PART_DECALS);
|
||||
writeDecals(part.decals, part_decals);
|
||||
|
||||
auto part_accs = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_ACCESSORIES);
|
||||
auto part_accs = part_prop->at<Gvas::Types::ArrayProperty>(MASS_WEAPON_PART_ACCESSORIES);
|
||||
if(!part_accs) {
|
||||
continue;
|
||||
}
|
||||
|
@ -302,7 +328,7 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
|||
writeAccessories(part.accessories, part_accs);
|
||||
}
|
||||
|
||||
auto custom_styles = weapon_prop->at<ArrayProperty>(MASS_CUSTOM_WEAPON_STYLES);
|
||||
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);
|
||||
|
@ -318,13 +344,13 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
|||
return false;
|
||||
}
|
||||
|
||||
for(UnsignedInt j = 0; j < weapon.customStyles.size(); j++) {
|
||||
for(std::uint32_t j = 0; j < weapon.customStyles.size(); j++) {
|
||||
writeCustomStyle(weapon.customStyles[j], j, custom_styles);
|
||||
}
|
||||
|
||||
weapon_prop->at<BoolProperty>(MASS_WEAPON_ATTACH)->value = weapon.attached;
|
||||
weapon_prop->at<Gvas::Types::BoolProperty>(MASS_WEAPON_ATTACH)->value = weapon.attached;
|
||||
switch(weapon.damageType) {
|
||||
#define c(enumerator, strenum) case DamageType::enumerator: weapon_prop->at<ByteProperty>(MASS_WEAPON_DAMAGE_TYPE)->enumValue = strenum; break;
|
||||
#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:
|
||||
|
@ -332,10 +358,10 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
|||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
weapon_prop->at<BoolProperty>(MASS_WEAPON_DUAL_WIELD)->value = weapon.dualWield;
|
||||
weapon_prop->at<Gvas::Types::BoolProperty>(MASS_WEAPON_DUAL_WIELD)->value = weapon.dualWield;
|
||||
switch(weapon.effectColourMode) {
|
||||
#define c(enumerator, enumstr) case EffectColourMode::enumerator: \
|
||||
weapon_prop->at<ByteProperty>(MASS_WEAPON_COLOUR_EFX_MODE)->enumValue = enumstr; \
|
||||
#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
|
||||
|
@ -344,7 +370,7 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
|||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
auto effect_colour = weapon_prop->at<ColourStructProperty>(MASS_WEAPON_COLOUR_EFX);
|
||||
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();
|
||||
|
@ -358,3 +384,5 @@ auto Mass::writeWeaponType(Containers::StringView prop_name, Containers::ArrayVi
|
|||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,32 @@
|
|||
#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"
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,11 +16,13 @@
|
|||
|
||||
#include "Weapon.h"
|
||||
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
Weapon::Weapon(const Weapon& other) {
|
||||
name = other.name;
|
||||
type = other.type;
|
||||
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];
|
||||
}
|
||||
customStyles = other.customStyles;
|
||||
|
@ -31,11 +33,12 @@ Weapon::Weapon(const Weapon& other) {
|
|||
effectColour = other.effectColour;
|
||||
}
|
||||
|
||||
Weapon& Weapon::operator=(const Weapon& other) {
|
||||
Weapon&
|
||||
Weapon::operator=(const Weapon& other) {
|
||||
name = other.name;
|
||||
type = other.type;
|
||||
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];
|
||||
}
|
||||
customStyles = other.customStyles;
|
||||
|
@ -47,3 +50,5 @@ Weapon& Weapon::operator=(const Weapon& other) {
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -29,19 +29,7 @@
|
|||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
#define c(enumerator, ...) enumerator,
|
||||
enum class WeaponType {
|
||||
#include "../Maps/WeaponTypes.hpp"
|
||||
};
|
||||
|
||||
enum class DamageType {
|
||||
#include "../Maps/DamageTypes.hpp"
|
||||
};
|
||||
|
||||
enum class EffectColourMode {
|
||||
#include "../Maps/EffectColourModes.hpp"
|
||||
};
|
||||
#undef c
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
struct Weapon {
|
||||
Weapon() = default;
|
||||
|
@ -52,8 +40,20 @@ struct Weapon {
|
|||
Weapon(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;
|
||||
WeaponType type = WeaponType::Melee;
|
||||
Type type = Type::Melee;
|
||||
Containers::Array<WeaponPart> parts;
|
||||
Containers::StaticArray<16, CustomStyle> customStyles{ValueInit};
|
||||
bool attached = false;
|
||||
|
@ -62,3 +62,5 @@ struct Weapon {
|
|||
EffectColourMode effectColourMode = EffectColourMode::Default;
|
||||
Color4 effectColour{0.0f};
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StaticArray.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
#include "Decal.h"
|
||||
#include "Accessory.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
namespace mbst::GameObjects {
|
||||
|
||||
struct WeaponPart {
|
||||
WeaponPart() = default;
|
||||
|
@ -34,11 +33,11 @@ struct WeaponPart {
|
|||
id = other.id;
|
||||
styles = other.styles;
|
||||
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];
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
@ -46,11 +45,11 @@ struct WeaponPart {
|
|||
id = other.id;
|
||||
styles = other.styles;
|
||||
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];
|
||||
}
|
||||
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];
|
||||
}
|
||||
return *this;
|
||||
|
@ -59,8 +58,10 @@ struct WeaponPart {
|
|||
WeaponPart(WeaponPart&& other) = default;
|
||||
WeaponPart& operator=(WeaponPart&& other) = default;
|
||||
|
||||
Int id = 0;
|
||||
Containers::StaticArray<4, Int> styles{ValueInit};
|
||||
std::int32_t id = 0;
|
||||
Containers::StaticArray<4, std::int32_t> styles{ValueInit};
|
||||
Containers::Array<Decal> decals{};
|
||||
Containers::Array<Accessory> accessories{};
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,17 +22,20 @@
|
|||
|
||||
#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 << ":" <<
|
||||
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 << ":" <<
|
||||
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 << ":" <<
|
||||
prop->structType << "(" << Utility::Debug::nospace << prop->propertyType << Utility::Debug::nospace <<
|
||||
") Contents:";
|
||||
|
@ -42,8 +45,9 @@ Utility::Debug& operator<<(Utility::Debug& debug, const GenericStructProperty* p
|
|||
return debug;
|
||||
}
|
||||
|
||||
Utility::Debug& operator<<(Utility::Debug& debug, const StructProperty* prop) {
|
||||
auto cast = dynamic_cast<const GenericStructProperty*>(prop);
|
||||
Utility::Debug&
|
||||
operator<<(Utility::Debug& debug, const Gvas::Types::StructProperty* prop) {
|
||||
auto cast = dynamic_cast<const Gvas::Types::GenericStructProperty*>(prop);
|
||||
if(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 << ")";
|
||||
}
|
||||
|
||||
Utility::Debug& operator<<(Utility::Debug& debug, const UnrealPropertyBase* prop) {
|
||||
Utility::Debug&
|
||||
operator<<(Utility::Debug& debug, const Gvas::Types::UnrealPropertyBase* prop) {
|
||||
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) {
|
||||
return debug << array_prop;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
return debug << set_prop;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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);
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,56 +17,66 @@
|
|||
#include <Corrade/Containers/Optional.h>
|
||||
#include <Corrade/Utility/Path.h>
|
||||
|
||||
#include "BinaryReader.h"
|
||||
#include "BinaryWriter.h"
|
||||
#include "../Logger/Logger.h"
|
||||
|
||||
#include "UESaveFile.h"
|
||||
#include "../BinaryIo/Reader.h"
|
||||
#include "../BinaryIo/Writer.h"
|
||||
|
||||
#include "File.h"
|
||||
|
||||
using namespace Containers::Literals;
|
||||
|
||||
UESaveFile::UESaveFile(Containers::String filepath):
|
||||
namespace Gvas {
|
||||
|
||||
File::File(Containers::String filepath):
|
||||
_propSerialiser{PropertySerialiser::instance()}
|
||||
{
|
||||
_filepath = std::move(filepath);
|
||||
_filepath = Utility::move(filepath);
|
||||
|
||||
loadData();
|
||||
}
|
||||
|
||||
auto UESaveFile::valid() const -> bool {
|
||||
bool
|
||||
File::valid() const {
|
||||
return _valid;
|
||||
}
|
||||
|
||||
auto UESaveFile::lastError() const -> Containers::StringView {
|
||||
Containers::StringView
|
||||
File::lastError() const {
|
||||
return _lastError;
|
||||
}
|
||||
|
||||
auto UESaveFile::reloadData() -> bool {
|
||||
bool
|
||||
File::reloadData() {
|
||||
if(_noReloadAfterSave) {
|
||||
_noReloadAfterSave = false;
|
||||
return valid();
|
||||
}
|
||||
|
||||
_properties = Containers::Array<UnrealPropertyBase::ptr>{};
|
||||
_properties = Containers::Array<Types::UnrealPropertyBase::ptr>{};
|
||||
loadData();
|
||||
return valid();
|
||||
}
|
||||
|
||||
auto UESaveFile::saveType() -> Containers::StringView {
|
||||
Containers::StringView
|
||||
File::saveType() {
|
||||
return _saveType;
|
||||
}
|
||||
|
||||
void UESaveFile::appendProperty(UnrealPropertyBase::ptr prop) {
|
||||
auto none_prop = std::move(_properties.back());
|
||||
_properties.back() = std::move(prop);
|
||||
arrayAppend(_properties, std::move(none_prop));
|
||||
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));
|
||||
}
|
||||
|
||||
auto UESaveFile::props() -> Containers::ArrayView<UnrealPropertyBase::ptr> {
|
||||
Containers::ArrayView<Types::UnrealPropertyBase::ptr>
|
||||
File::props() {
|
||||
return _properties;
|
||||
}
|
||||
|
||||
auto UESaveFile::saveToFile() -> bool {
|
||||
bool
|
||||
File::saveToFile() {
|
||||
LOG_INFO_FORMAT("Writing to {}.", _filepath);
|
||||
|
||||
bool temp_file = _filepath.hasSuffix(".tmp");
|
||||
|
@ -77,7 +87,7 @@ auto UESaveFile::saveToFile() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
BinaryWriter writer{_filepath + ".tmp"_s};
|
||||
BinaryIo::Writer writer{_filepath + ".tmp"_s};
|
||||
|
||||
if(!writer.open()) {
|
||||
_lastError = "Couldn't open the file for saving."_s;
|
||||
|
@ -85,32 +95,53 @@ auto UESaveFile::saveToFile() -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
if(!writer.writeArray(arrayView(_magicBytes)) ||
|
||||
!writer.writeUnsignedInt(_saveVersion) ||
|
||||
!writer.writeUnsignedInt(_packageVersion) ||
|
||||
!writer.writeUnsignedShort(_engineVersion.major) ||
|
||||
!writer.writeUnsignedShort(_engineVersion.minor) ||
|
||||
!writer.writeUnsignedShort(_engineVersion.patch) ||
|
||||
!writer.writeUnsignedInt(_engineVersion.build) ||
|
||||
!writer.writeUEString(_engineVersion.buildId))
|
||||
{
|
||||
_lastError = "Couldn't write the header."_s;
|
||||
if(!writer.writeArray(arrayView(_magicBytes))) {
|
||||
_lastError = "Couldn't write the magic bytes."_s;
|
||||
LOG_ERROR(_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!writer.writeUnsignedInt(_customFormatVersion) ||
|
||||
!writer.writeUnsignedInt(_customFormatData.size()))
|
||||
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(UnsignedLong i = 0; i < _customFormatData.size(); i++) {
|
||||
if(!writer.writeStaticArray(Containers::StaticArrayView<16, const char>{_customFormatData[i].id}) ||
|
||||
!writer.writeUnsignedInt(_customFormatData[i].value))
|
||||
{
|
||||
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;
|
||||
|
@ -124,7 +155,7 @@ auto UESaveFile::saveToFile() -> bool {
|
|||
}
|
||||
|
||||
for(auto& prop : _properties) {
|
||||
UnsignedLong bytes_written = 0;
|
||||
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);
|
||||
|
@ -138,7 +169,7 @@ auto UESaveFile::saveToFile() -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
writer.writeUnsignedInt(0);
|
||||
writer.writeUint32(0u);
|
||||
|
||||
writer.closeFile();
|
||||
|
||||
|
@ -155,7 +186,8 @@ auto UESaveFile::saveToFile() -> bool {
|
|||
return true;
|
||||
}
|
||||
|
||||
void UESaveFile::loadData() {
|
||||
void
|
||||
File::loadData() {
|
||||
LOG_INFO_FORMAT("Reading data from {}.", _filepath);
|
||||
|
||||
_valid = false;
|
||||
|
@ -166,7 +198,7 @@ void UESaveFile::loadData() {
|
|||
return;
|
||||
}
|
||||
|
||||
BinaryReader reader{_filepath};
|
||||
BinaryIo::Reader reader{_filepath};
|
||||
|
||||
if(!reader.open()) {
|
||||
_lastError = _filepath + " couldn't be opened."_s;
|
||||
|
@ -189,28 +221,66 @@ void UESaveFile::loadData() {
|
|||
return;
|
||||
}
|
||||
|
||||
if(!reader.readUnsignedInt(_saveVersion) ||
|
||||
!reader.readUnsignedInt(_packageVersion) ||
|
||||
!reader.readUnsignedShort(_engineVersion.major) ||
|
||||
!reader.readUnsignedShort(_engineVersion.minor) ||
|
||||
!reader.readUnsignedShort(_engineVersion.patch) ||
|
||||
!reader.readUnsignedInt(_engineVersion.build) ||
|
||||
!reader.readUEString(_engineVersion.buildId))
|
||||
{
|
||||
_lastError = "Couldn't read version data.";
|
||||
if(!reader.readUint32(_saveVersion)) {
|
||||
_lastError = "Couldn't read save version.";
|
||||
LOG_ERROR(_lastError);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!reader.readUnsignedInt(_customFormatVersion)) {
|
||||
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;
|
||||
}
|
||||
|
||||
UnsignedInt custom_format_data_size = 0;
|
||||
std::uint32_t custom_format_data_size = 0;
|
||||
|
||||
if(!reader.readUnsignedInt(custom_format_data_size)) {
|
||||
if(!reader.readUint32(custom_format_data_size)) {
|
||||
_lastError = "Couldn't read the custom format data size.";
|
||||
LOG_ERROR(_lastError);
|
||||
return;
|
||||
|
@ -218,18 +288,14 @@ void UESaveFile::loadData() {
|
|||
|
||||
_customFormatData = Containers::Array<CustomFormatDataEntry>{custom_format_data_size};
|
||||
|
||||
for(UnsignedInt i = 0; i < custom_format_data_size; i++) {
|
||||
CustomFormatDataEntry entry;
|
||||
|
||||
for(auto& entry : _customFormatData) {
|
||||
if(!reader.readStaticArray(entry.id) ||
|
||||
!reader.readInt(entry.value))
|
||||
!reader.readInt32(entry.value))
|
||||
{
|
||||
_lastError = "Couldn't read the custom format data";
|
||||
LOG_ERROR(_lastError);
|
||||
return;
|
||||
}
|
||||
|
||||
_customFormatData[i] = std::move(entry);
|
||||
}
|
||||
|
||||
if(!reader.readUEString(_saveType)) {
|
||||
|
@ -238,9 +304,9 @@ void UESaveFile::loadData() {
|
|||
return;
|
||||
}
|
||||
|
||||
UnrealPropertyBase::ptr prop;
|
||||
Types::UnrealPropertyBase::ptr prop;
|
||||
while((prop = _propSerialiser->read(reader)) != nullptr) {
|
||||
arrayAppend(_properties, std::move(prop));
|
||||
arrayAppend(_properties, Utility::move(prop));
|
||||
}
|
||||
|
||||
if(_properties.isEmpty()) {
|
||||
|
@ -259,3 +325,5 @@ void UESaveFile::loadData() {
|
|||
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/>.
|
||||
|
||||
#include <Corrade/Containers/ArrayView.h>
|
||||
#include <Corrade/Containers/GrowableArray.h>
|
||||
#include <Corrade/Containers/Reference.h>
|
||||
#include <Corrade/Containers/StaticArray.h>
|
||||
#include <Corrade/Containers/String.h>
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include <Magnum/Magnum.h>
|
||||
|
||||
#include "Types/UnrealPropertyBase.h"
|
||||
|
||||
#include "PropertySerialiser.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
class UESaveFile {
|
||||
namespace Gvas {
|
||||
|
||||
class File {
|
||||
public:
|
||||
explicit UESaveFile(Containers::String filepath);
|
||||
explicit File(Containers::String filepath);
|
||||
|
||||
auto valid() const -> bool;
|
||||
bool valid() const;
|
||||
auto lastError() const -> Containers::StringView;
|
||||
|
||||
auto reloadData() -> bool;
|
||||
bool reloadData();
|
||||
|
||||
auto saveType() -> Containers::StringView;
|
||||
|
||||
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) {
|
||||
for(auto& prop : _properties) {
|
||||
if(prop->name == name) {
|
||||
|
@ -54,11 +52,11 @@ class UESaveFile {
|
|||
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:
|
||||
void loadData();
|
||||
|
@ -72,26 +70,29 @@ class UESaveFile {
|
|||
|
||||
Containers::StaticArray<4, char> _magicBytes{'G', 'V', 'A', 'S'};
|
||||
|
||||
UnsignedInt _saveVersion = 0;
|
||||
UnsignedInt _packageVersion = 0;
|
||||
std::uint32_t _saveVersion = 0;
|
||||
std::uint32_t _packageVersion = 0;
|
||||
std::uint32_t _unknown = 0;
|
||||
struct {
|
||||
UnsignedShort major = 0;
|
||||
UnsignedShort minor = 0;
|
||||
UnsignedShort patch = 0;
|
||||
UnsignedInt build = 0;
|
||||
std::uint16_t major = 0;
|
||||
std::uint16_t minor = 0;
|
||||
std::uint16_t patch = 0;
|
||||
std::uint32_t build = 0;
|
||||
Containers::String buildId;
|
||||
} _engineVersion;
|
||||
|
||||
UnsignedInt _customFormatVersion = 0;
|
||||
std::uint32_t _customFormatVersion = 0;
|
||||
struct CustomFormatDataEntry {
|
||||
Containers::StaticArray<16, char> id;
|
||||
Int value = 0;
|
||||
std::int32_t value = 0;
|
||||
};
|
||||
Containers::Array<CustomFormatDataEntry> _customFormatData;
|
||||
|
||||
Containers::String _saveType;
|
||||
|
||||
Containers::Array<UnrealPropertyBase::ptr> _properties;
|
||||
Containers::Array<Types::UnrealPropertyBase::ptr> _properties;
|
||||
|
||||
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
|
||||
|
||||
// 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
|
||||
// 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/StringView.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
#include "../Gvas.h"
|
||||
#include "../../BinaryIo/BinaryIo.h"
|
||||
#include "../Types/UnrealPropertyBase.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
class BinaryReader;
|
||||
class BinaryWriter;
|
||||
class PropertySerialiser;
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
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:
|
||||
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,
|
||||
UnsignedLong value_length, UnsignedInt count, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> Containers::Array<UnrealPropertyBase::ptr> = 0;
|
||||
virtual auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
std::uint32_t count, BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> PropertyArray = 0;
|
||||
|
||||
virtual auto serialise(Containers::ArrayView<UnrealPropertyBase::ptr> props, Containers::StringView item_type,
|
||||
UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool = 0;
|
||||
virtual bool serialise(PropertyArrayView props, Containers::StringView item_type,
|
||||
std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser) = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StringView.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
#include "../Gvas.h"
|
||||
#include "../../BinaryIo/BinaryIo.h"
|
||||
#include "../Types/UnrealPropertyBase.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
class BinaryReader;
|
||||
class BinaryWriter;
|
||||
class PropertySerialiser;
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class AbstractUnrealPropertySerialiser {
|
||||
using StringArrayView = Containers::ArrayView<const Containers::String>;
|
||||
|
||||
class AbstractUnrealProperty {
|
||||
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,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr = 0;
|
||||
virtual auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr = 0;
|
||||
|
||||
virtual auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool = 0;
|
||||
virtual bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StringView.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
#include "../Gvas.h"
|
||||
#include "../../BinaryIo/BinaryIo.h"
|
||||
#include "../Types/UnrealPropertyBase.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
class BinaryReader;
|
||||
class BinaryWriter;
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class AbstractUnrealStructSerialiser {
|
||||
class AbstractUnrealStruct {
|
||||
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,
|
||||
UnsignedLong& bytes_written) -> bool = 0;
|
||||
virtual bool serialise(Types::UnrealPropertyBase::ptr& structProp, BinaryIo::Writer& writer,
|
||||
std::size_t& bytes_written) = 0;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,16 +16,18 @@
|
|||
|
||||
#include <Corrade/Containers/String.h>
|
||||
|
||||
#include "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
#include "../PropertySerialiser.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "ArrayPropertySerialiser.h"
|
||||
#include "ArrayProperty.h"
|
||||
|
||||
auto ArrayPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
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;
|
||||
if(!reader.readUEString(item_type)) {
|
||||
|
@ -39,23 +41,24 @@ auto ArrayPropertySerialiser::deserialiseProperty(Containers::StringView name, C
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
UnsignedInt item_count;
|
||||
if(!reader.readUnsignedInt(item_count)) {
|
||||
std::uint32_t item_count;
|
||||
if(!reader.readUint32(item_count)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read array property {}'s item count.", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto prop = Containers::pointer<ArrayProperty>();
|
||||
prop->itemType = std::move(item_type);
|
||||
auto prop = Containers::pointer<Types::ArrayProperty>();
|
||||
prop->itemType = Utility::move(item_type);
|
||||
prop->items = serialiser.readSet(reader, prop->itemType, item_count);
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
auto ArrayPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
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) {
|
||||
LOG_ERROR("The property is not a valid array property.");
|
||||
return false;
|
||||
|
@ -63,12 +66,14 @@ auto ArrayPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, U
|
|||
|
||||
writer.writeUEStringToArray(array_prop->itemType);
|
||||
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();
|
||||
UnsignedLong dummy_bytes_written = 0;
|
||||
std::size_t start_pos = writer.arrayPosition();
|
||||
std::size_t dummy_bytes_written = 0;
|
||||
bool ret = serialiser.writeSet(array_prop->items, array_prop->itemType, dummy_bytes_written, writer);
|
||||
bytes_written += writer.arrayPosition() - start_pos;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,22 +18,24 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include <Magnum/Types.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
|
||||
#include "../Gvas.h"
|
||||
#include "UnrealProperty.h"
|
||||
#include "../Types/ArrayProperty.h"
|
||||
|
||||
using namespace Corrade;
|
||||
using namespace Magnum;
|
||||
|
||||
class ArrayPropertySerialiser : public UnrealPropertySerialiser<ArrayProperty> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class ArrayProperty : public UnrealProperty<Types::ArrayProperty> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<ArrayPropertySerialiser>;
|
||||
using ptr = Containers::Pointer<ArrayProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,29 +14,32 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "BoolPropertySerialiser.h"
|
||||
#include "BoolProperty.h"
|
||||
|
||||
auto BoolPropertySerialiser::types() -> Containers::ArrayView<const Containers::String> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
StringArrayView
|
||||
BoolProperty::types() {
|
||||
using namespace Containers::Literals;
|
||||
static const Containers::Array<Containers::String> types{InPlaceInit, {"BoolProperty"_s}};
|
||||
return types;
|
||||
}
|
||||
|
||||
auto BoolPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
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;
|
||||
}
|
||||
|
||||
Short value;
|
||||
if(!reader.readShort(value)) {
|
||||
std::int16_t value;
|
||||
if(!reader.readInt16(value)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read bool property {}'s value.", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -46,22 +49,25 @@ auto BoolPropertySerialiser::deserialise(Containers::StringView name, Containers
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto prop = Containers::pointer<BoolProperty>();
|
||||
auto prop = Containers::pointer<Types::BoolProperty>();
|
||||
prop->value = value;
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
auto BoolPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
bool
|
||||
BoolProperty::serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser)
|
||||
{
|
||||
auto bool_prop = dynamic_cast<BoolProperty*>(prop.get());
|
||||
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<Short>(Short(bool_prop->value));
|
||||
writer.writeValueToArray<std::int16_t>(std::int16_t(bool_prop->value));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StringView.h>
|
||||
|
||||
#include "AbstractUnrealPropertySerialiser.h"
|
||||
#include "AbstractUnrealProperty.h"
|
||||
|
||||
#include "../Types/BoolProperty.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
||||
class BoolPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class BoolProperty : public AbstractUnrealProperty {
|
||||
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,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
|
||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,25 +14,28 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.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;
|
||||
static const Containers::Array<Containers::String> types{InPlaceInit, {"ByteProperty"_s}};
|
||||
return types;
|
||||
}
|
||||
|
||||
auto BytePropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
Types::UnrealPropertyBase::ptr
|
||||
ByteProperty::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
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)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read byte property {}'s enum type.", name);
|
||||
return nullptr;
|
||||
|
@ -52,8 +55,8 @@ auto BytePropertySerialiser::deserialise(Containers::StringView name, Containers
|
|||
|
||||
prop->valueLength = value_length;
|
||||
|
||||
//UnsignedInt count = 0;
|
||||
//if(!reader.readUnsignedInt(count)) {
|
||||
//std::uint32_t count = 0;
|
||||
//if(!reader.readstd::uint32_t(count)) {
|
||||
// return nullptr;
|
||||
//}
|
||||
|
||||
|
@ -64,20 +67,21 @@ auto BytePropertySerialiser::deserialise(Containers::StringView name, Containers
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto BytePropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
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) {
|
||||
LOG_ERROR("The property is not a valid byte property.");
|
||||
return false;
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
if(byte_prop->valueLength != UnsignedLong(-1)) {
|
||||
if(byte_prop->valueLength != std::size_t(-1)) {
|
||||
writer.writeUEStringToArray(byte_prop->enumType);
|
||||
writer.writeValueToArray<char>('\0');
|
||||
}
|
||||
|
@ -86,3 +90,5 @@ auto BytePropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StringView.h>
|
||||
|
||||
#include "AbstractUnrealPropertySerialiser.h"
|
||||
#include "AbstractUnrealProperty.h"
|
||||
|
||||
#include "../Types/ByteProperty.h"
|
||||
|
||||
class BytePropertySerialiser : public AbstractUnrealPropertySerialiser {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class ByteProperty : public AbstractUnrealProperty {
|
||||
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,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
|
||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,17 +14,19 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "ColourPropertySerialiser.h"
|
||||
#include "ColourProperty.h"
|
||||
|
||||
auto ColourPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
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<ColourStructProperty>();
|
||||
auto prop = Containers::pointer<Types::ColourStructProperty>();
|
||||
|
||||
if(!reader.readFloat(prop->r) || !reader.readFloat(prop->g) ||
|
||||
!reader.readFloat(prop->b) || !reader.readFloat(prop->a))
|
||||
|
@ -36,17 +38,22 @@ auto ColourPropertySerialiser::deserialiseProperty(Containers::StringView name,
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto ColourPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
bool
|
||||
ColourProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||
{
|
||||
auto colour_prop = dynamic_cast<ColourStructProperty*>(prop.get());
|
||||
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);
|
||||
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
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,19 +18,24 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
#include "UnrealProperty.h"
|
||||
|
||||
#include "../Types/ColourStructProperty.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
||||
class ColourPropertySerialiser : public UnrealPropertySerialiser<ColourStructProperty> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class ColourProperty : public UnrealProperty<Types::ColourStructProperty> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<ColourPropertySerialiser>;
|
||||
using ptr = Containers::Pointer<ColourProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,19 +14,21 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "DateTimePropertySerialiser.h"
|
||||
#include "DateTimeProperty.h"
|
||||
|
||||
auto DateTimePropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
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<DateTimeStructProperty>();
|
||||
auto prop = Containers::pointer<Types::DateTimeStructProperty>();
|
||||
|
||||
if(!reader.readUnsignedLong(prop->timestamp)) {
|
||||
if(!reader.readInt64(prop->timestamp)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read date/time property {}'s value.", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -34,16 +36,19 @@ auto DateTimePropertySerialiser::deserialiseProperty(Containers::StringView name
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto DateTimePropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
bool
|
||||
DateTimeProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||
{
|
||||
auto dt_prop = dynamic_cast<DateTimeStructProperty*>(prop.get());
|
||||
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<UnsignedLong>(dt_prop->timestamp);
|
||||
bytes_written += writer.writeValueToArray<std::int64_t>(dt_prop->timestamp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,17 +18,22 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
#include "UnrealProperty.h"
|
||||
|
||||
#include "../Types/DateTimeStructProperty.h"
|
||||
|
||||
class DateTimePropertySerialiser : public UnrealPropertySerialiser<DateTimeStructProperty> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class DateTimeProperty : public UnrealProperty<Types::DateTimeStructProperty> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<DateTimePropertySerialiser>;
|
||||
using ptr = Containers::Pointer<DateTimeProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,23 +14,26 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.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;
|
||||
static const Containers::Array<Containers::String> types{InPlaceInit, {"EnumProperty"_s}};
|
||||
return types;
|
||||
}
|
||||
|
||||
auto EnumPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
Types::UnrealPropertyBase::ptr
|
||||
EnumProperty::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
{
|
||||
auto prop = Containers::pointer<EnumProperty>();
|
||||
auto prop = Containers::pointer<Types::EnumProperty>();
|
||||
|
||||
if(!reader.readUEString(prop->enumType)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read enum property {}'s enum type.", name);
|
||||
|
@ -51,10 +54,11 @@ auto EnumPropertySerialiser::deserialise(Containers::StringView name, Containers
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto EnumPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
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) {
|
||||
LOG_ERROR("The property is not a valid enum property.");
|
||||
return false;
|
||||
|
@ -66,3 +70,5 @@ auto EnumPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StringView.h>
|
||||
|
||||
#include "AbstractUnrealPropertySerialiser.h"
|
||||
#include "AbstractUnrealProperty.h"
|
||||
|
||||
#include "../Types/EnumProperty.h"
|
||||
|
||||
class EnumPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class EnumProperty : public AbstractUnrealProperty {
|
||||
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,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
|
||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,23 +14,26 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.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;
|
||||
static const Containers::Array<Containers::String> types{InPlaceInit, {"FloatProperty"_s}};
|
||||
return types;
|
||||
}
|
||||
|
||||
auto FloatPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
Types::UnrealPropertyBase::ptr
|
||||
FloatProperty::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
{
|
||||
auto prop = Containers::pointer<FloatProperty>();
|
||||
auto prop = Containers::pointer<Types::FloatProperty>();
|
||||
|
||||
char terminator;
|
||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||
|
@ -46,17 +49,20 @@ auto FloatPropertySerialiser::deserialise(Containers::StringView name, Container
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto FloatPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
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) {
|
||||
LOG_ERROR("The property is not a valid float property.");
|
||||
return false;
|
||||
}
|
||||
|
||||
writer.writeValueToArray<char>('\0');
|
||||
bytes_written += writer.writeValueToArray<Float>(float_prop->value);
|
||||
bytes_written += writer.writeValueToArray<float>(float_prop->value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StringView.h>
|
||||
|
||||
#include "AbstractUnrealPropertySerialiser.h"
|
||||
#include "AbstractUnrealProperty.h"
|
||||
|
||||
#include "../Types/FloatProperty.h"
|
||||
|
||||
class FloatPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class FloatProperty : public AbstractUnrealProperty {
|
||||
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,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
|
||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,19 +14,21 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "GuidPropertySerialiser.h"
|
||||
#include "GuidProperty.h"
|
||||
|
||||
using namespace Containers::Literals;
|
||||
|
||||
auto GuidPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
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)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read GUID property {}'s value.", name);
|
||||
|
@ -36,12 +38,13 @@ auto GuidPropertySerialiser::deserialiseProperty(Containers::StringView name, Co
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto GuidPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
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) {
|
||||
LOG_ERROR("The property is not a valid byte property.");
|
||||
LOG_ERROR("The property is not a valid GUID property.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -49,3 +52,5 @@ auto GuidPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Un
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,17 +18,22 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
#include "UnrealProperty.h"
|
||||
|
||||
#include "../Types/GuidStructProperty.h"
|
||||
|
||||
class GuidPropertySerialiser : public UnrealPropertySerialiser<GuidStructProperty> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class GuidProperty : public UnrealProperty<Types::GuidStructProperty> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<GuidPropertySerialiser>;
|
||||
using ptr = Containers::Pointer<GuidProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,25 +14,27 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "IntPropertySerialiser.h"
|
||||
#include "IntProperty.h"
|
||||
|
||||
auto IntPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
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<IntProperty>();
|
||||
auto prop = Containers::pointer<Types::IntProperty>();
|
||||
|
||||
if(value_length == UnsignedLong(-1)) {
|
||||
if(!reader.readInt(prop->value)) {
|
||||
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 = UnsignedLong(-1);
|
||||
prop->valueLength = std::size_t(-1);
|
||||
return prop;
|
||||
}
|
||||
|
||||
|
@ -42,7 +44,7 @@ auto IntPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if(!reader.readInt(prop->value)) {
|
||||
if(!reader.readInt32(prop->value)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read int property {}'s value.", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -52,20 +54,23 @@ auto IntPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto IntPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
bool
|
||||
IntProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||
{
|
||||
auto int_prop = dynamic_cast<IntProperty*>(prop.get());
|
||||
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 != UnsignedLong(-1)) {
|
||||
if(prop->valueLength != std::size_t(-1)) {
|
||||
writer.writeValueToArray<char>('\0');
|
||||
}
|
||||
|
||||
bytes_written += writer.writeValueToArray<Int>(int_prop->value);
|
||||
bytes_written += writer.writeValueToArray<std::int32_t>(int_prop->value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,17 +18,22 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
#include "UnrealProperty.h"
|
||||
|
||||
#include "../Types/IntProperty.h"
|
||||
|
||||
class IntPropertySerialiser : public UnrealPropertySerialiser<IntProperty> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class IntProperty : public UnrealProperty<Types::IntProperty> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<IntPropertySerialiser>;
|
||||
using ptr = Containers::Pointer<IntProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,21 +14,23 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
#include "../PropertySerialiser.h"
|
||||
#include "../Types/NoneProperty.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "MapPropertySerialiser.h"
|
||||
#include "MapProperty.h"
|
||||
|
||||
using namespace Containers::Literals;
|
||||
|
||||
auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
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)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read map property {}'s key type.", name);
|
||||
|
@ -46,14 +48,14 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
UnsignedInt null;
|
||||
if(!reader.readUnsignedInt(null) || null != 0u) {
|
||||
std::uint32_t null;
|
||||
if(!reader.readUint32(null) || null != 0u) {
|
||||
LOG_ERROR_FORMAT("Couldn't read a null int in map property {}.", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UnsignedInt count;
|
||||
if(!reader.readUnsignedInt(count)) {
|
||||
std::uint32_t count;
|
||||
if(!reader.readUint32(count)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read map property {}'s item count.", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -63,8 +65,8 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
|||
|
||||
arrayReserve(prop->map, count);
|
||||
|
||||
for(UnsignedInt i = 0; i < count; i++) {
|
||||
MapProperty::KeyValuePair pair;
|
||||
for(std::uint32_t i = 0; i < count; i++) {
|
||||
Types::MapProperty::KeyValuePair pair;
|
||||
|
||||
if(prop->keyType == "IntProperty"_s || prop->keyType == "StrProperty"_s) {
|
||||
pair.key = serialiser.readItem(reader, prop->keyType, -1, name);
|
||||
|
@ -78,14 +80,14 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
UnrealPropertyBase::ptr value_item;
|
||||
Types::UnrealPropertyBase::ptr value_item;
|
||||
if(prop->valueType == "StructProperty"_s) {
|
||||
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 &&
|
||||
pair.values.back()->propertyType == "NoneProperty"_s &&
|
||||
dynamic_cast<NoneProperty*>(pair.values.back().get()) != nullptr)
|
||||
dynamic_cast<Types::NoneProperty*>(pair.values.back().get()) != nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -96,10 +98,10 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
|||
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
|
||||
|
@ -107,10 +109,11 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
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) {
|
||||
LOG_ERROR("The property is not a valid map property.");
|
||||
return false;
|
||||
|
@ -120,12 +123,12 @@ auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
|
|||
writer.writeUEStringToArray(map_prop->valueType);
|
||||
writer.writeValueToArray<char>('\0');
|
||||
|
||||
UnsignedLong value_start = writer.arrayPosition();
|
||||
writer.writeValueToArray<UnsignedInt>(0u);
|
||||
std::size_t value_start = writer.arrayPosition();
|
||||
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) {
|
||||
if(!serialiser.writeItem(pair.key, map_prop->keyType, dummy_bytes_written, writer)) {
|
||||
LOG_ERROR("Couldn't write a key.");
|
||||
|
@ -152,3 +155,5 @@ auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,17 +18,22 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
#include "UnrealProperty.h"
|
||||
|
||||
#include "../Types/MapProperty.h"
|
||||
|
||||
class MapPropertySerialiser : public UnrealPropertySerialiser<MapProperty> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class MapProperty : public UnrealProperty<Types::MapProperty> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<MapPropertySerialiser>;
|
||||
using ptr = Containers::Pointer<MapProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,22 +14,25 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
#include "../PropertySerialiser.h"
|
||||
#include "../Types/IntProperty.h"
|
||||
#include "../Types/NoneProperty.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "ResourcePropertySerialiser.h"
|
||||
#include "ResourceProperty.h"
|
||||
|
||||
using namespace Containers::Literals;
|
||||
|
||||
auto ResourcePropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
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<ResourceItemValue>();
|
||||
auto prop = Containers::pointer<Types::ResourceItemValue>();
|
||||
|
||||
auto id_prop = serialiser.read(reader);
|
||||
if(!id_prop) {
|
||||
|
@ -39,13 +42,13 @@ auto ResourcePropertySerialiser::deserialiseProperty(Containers::StringView name
|
|||
|
||||
if((*id_prop->name) != "ID_4_AAE08F17428E229EC7A2209F51081A21"_s ||
|
||||
id_prop->propertyType != "IntProperty"_s ||
|
||||
dynamic_cast<IntProperty*>(id_prop.get()) == nullptr)
|
||||
dynamic_cast<Types::IntProperty*>(id_prop.get()) == nullptr)
|
||||
{
|
||||
LOG_ERROR("The ID property is invalid."_s);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
prop->id = dynamic_cast<IntProperty*>(id_prop.get())->value;
|
||||
prop->id = dynamic_cast<Types::IntProperty*>(id_prop.get())->value;
|
||||
|
||||
auto value_prop = serialiser.read(reader);
|
||||
if(!value_prop) {
|
||||
|
@ -55,20 +58,20 @@ auto ResourcePropertySerialiser::deserialiseProperty(Containers::StringView name
|
|||
|
||||
if((*value_prop->name) != "Quantity_3_560F09B5485C365D3041888910019CE3"_s ||
|
||||
value_prop->propertyType != "IntProperty"_s ||
|
||||
dynamic_cast<IntProperty*>(value_prop.get()) == nullptr)
|
||||
dynamic_cast<Types::IntProperty*>(value_prop.get()) == nullptr)
|
||||
{
|
||||
LOG_ERROR("The value property is invalid."_s);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
prop->quantity = dynamic_cast<IntProperty*>(value_prop.get())->value;
|
||||
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<NoneProperty*>(none_prop.get()))
|
||||
!dynamic_cast<Types::NoneProperty*>(none_prop.get()))
|
||||
{
|
||||
LOG_ERROR("Couldn't find a terminating NoneProperty."_s);
|
||||
return nullptr;
|
||||
|
@ -77,10 +80,11 @@ auto ResourcePropertySerialiser::deserialiseProperty(Containers::StringView name
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto ResourcePropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
bool
|
||||
ResourceProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||
{
|
||||
auto res_prop = dynamic_cast<ResourceItemValue*>(prop.get());
|
||||
auto res_prop = dynamic_cast<Types::ResourceItemValue*>(prop.get());
|
||||
if(!res_prop) {
|
||||
LOG_ERROR("The property is not a valid ResourceItemValue property.");
|
||||
return false;
|
||||
|
@ -88,17 +92,19 @@ auto ResourcePropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop
|
|||
|
||||
bytes_written += writer.writeUEStringToArray("ID_4_AAE08F17428E229EC7A2209F51081A21"_s) +
|
||||
writer.writeUEStringToArray("IntProperty"_s) +
|
||||
writer.writeValueToArray<UnsignedLong>(4ull) +
|
||||
writer.writeValueToArray<std::size_t>(4ull) +
|
||||
writer.writeValueToArray<char>('\0') +
|
||||
writer.writeValueToArray<Int>(res_prop->id);
|
||||
writer.writeValueToArray<std::int32_t>(res_prop->id);
|
||||
|
||||
bytes_written += writer.writeUEStringToArray("Quantity_3_560F09B5485C365D3041888910019CE3"_s) +
|
||||
writer.writeUEStringToArray("IntProperty"_s) +
|
||||
writer.writeValueToArray<UnsignedLong>(4ull) +
|
||||
writer.writeValueToArray<std::size_t>(4ull) +
|
||||
writer.writeValueToArray<char>('\0') +
|
||||
writer.writeValueToArray<Int>(res_prop->quantity);
|
||||
writer.writeValueToArray<std::int32_t>(res_prop->quantity);
|
||||
|
||||
bytes_written += writer.writeUEStringToArray("None"_s);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,17 +18,22 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
#include "UnrealProperty.h"
|
||||
|
||||
#include "../Types/ResourceItemValue.h"
|
||||
|
||||
class ResourcePropertySerialiser : public UnrealPropertySerialiser<ResourceItemValue> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class ResourceProperty : public UnrealProperty<Types::ResourceItemValue> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<ResourcePropertySerialiser>;
|
||||
using ptr = Containers::Pointer<ResourceProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr 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
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,17 +18,22 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
#include "UnrealProperty.h"
|
||||
|
||||
#include "../Types/RotatorStructProperty.h"
|
||||
|
||||
class RotatorPropertySerialiser : public UnrealPropertySerialiser<RotatorStructProperty> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class RotatorProperty : public UnrealProperty<Types::RotatorStructProperty> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<RotatorPropertySerialiser>;
|
||||
using ptr = Containers::Pointer<RotatorProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr 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;
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,16 +14,18 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
#include "../PropertySerialiser.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "SetPropertySerialiser.h"
|
||||
#include "SetProperty.h"
|
||||
|
||||
auto SetPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
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)) {
|
||||
|
@ -37,29 +39,30 @@ auto SetPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
UnsignedInt four_bytes;
|
||||
if(!reader.readUnsignedInt(four_bytes) || four_bytes != 0u) {
|
||||
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;
|
||||
}
|
||||
|
||||
UnsignedInt item_count;
|
||||
if(!reader.readUnsignedInt(item_count)) {
|
||||
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<SetProperty>();
|
||||
prop->itemType = std::move(item_type);
|
||||
auto prop = Containers::pointer<Types::SetProperty>();
|
||||
prop->itemType = Utility::move(item_type);
|
||||
prop->items = serialiser.readSet(reader, prop->itemType, item_count);
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
auto SetPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
bool
|
||||
SetProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||
{
|
||||
auto set_prop = dynamic_cast<SetProperty*>(prop.get());
|
||||
auto set_prop = dynamic_cast<Types::SetProperty*>(prop.get());
|
||||
if(!set_prop) {
|
||||
LOG_ERROR("The property is not a valid set property.");
|
||||
return false;
|
||||
|
@ -68,13 +71,15 @@ auto SetPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
|
|||
writer.writeUEStringToArray(set_prop->itemType);
|
||||
writer.writeValueToArray<char>('\0');
|
||||
|
||||
bytes_written += writer.writeValueToArray<UnsignedInt>(0u);
|
||||
bytes_written += writer.writeValueToArray<UnsignedInt>(UnsignedInt(set_prop->items.size()));
|
||||
bytes_written += writer.writeValueToArray<std::uint32_t>(0u);
|
||||
bytes_written += writer.writeValueToArray<std::uint32_t>(std::uint32_t(set_prop->items.size()));
|
||||
|
||||
UnsignedLong start_pos = writer.arrayPosition();
|
||||
UnsignedLong dummy_bytes_written = 0;
|
||||
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
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,17 +18,22 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
#include "UnrealProperty.h"
|
||||
|
||||
#include "../Types/SetProperty.h"
|
||||
|
||||
class SetPropertySerialiser : public UnrealPropertySerialiser<SetProperty> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class SetProperty : public UnrealProperty<Types::SetProperty> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<SetPropertySerialiser>;
|
||||
using ptr = Containers::Pointer<SetProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -14,27 +14,30 @@
|
|||
// 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 "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../BinaryIo/Reader.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;
|
||||
static const Containers::Array<Containers::String> types{InPlaceInit,
|
||||
{"NameProperty"_s, "StrProperty"_s,
|
||||
"SoftObjectProperty"_s, "ObjectProperty"_s}};
|
||||
static const Containers::Array<Containers::String> types{InPlaceInit, {
|
||||
"NameProperty"_s, "StrProperty"_s, "SoftObjectProperty"_s, "ObjectProperty"_s
|
||||
}};
|
||||
return types;
|
||||
}
|
||||
|
||||
auto StringPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
Types::UnrealPropertyBase::ptr
|
||||
StringProperty::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
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;
|
||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||
LOG_ERROR_FORMAT("Couldn't read a null byte in string property {}.", name);
|
||||
|
@ -52,16 +55,17 @@ auto StringPropertySerialiser::deserialise(Containers::StringView name, Containe
|
|||
return prop;
|
||||
}
|
||||
|
||||
auto StringPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
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) {
|
||||
LOG_ERROR("The property is not a valid string property.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(str_prop->valueLength != UnsignedLong(-1)) {
|
||||
if(str_prop->valueLength != std::size_t(-1)) {
|
||||
writer.writeValueToArray<char>('\0');
|
||||
}
|
||||
|
||||
|
@ -69,3 +73,5 @@ auto StringPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, Unsigned
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// 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/StringView.h>
|
||||
|
||||
#include "AbstractUnrealPropertySerialiser.h"
|
||||
#include "AbstractUnrealProperty.h"
|
||||
|
||||
#include "../Types/StringProperty.h"
|
||||
|
||||
class StringPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class StringProperty : public AbstractUnrealProperty {
|
||||
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,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
|
||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -16,23 +16,27 @@
|
|||
|
||||
#include <Corrade/Containers/String.h>
|
||||
|
||||
#include "../BinaryReader.h"
|
||||
#include "../BinaryWriter.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 "StructSerialiser.h"
|
||||
#include "Struct.h"
|
||||
|
||||
auto StructSerialiser::types() -> Containers::ArrayView<const Containers::String> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
StringArrayView
|
||||
Struct::types() {
|
||||
using namespace Containers::Literals;
|
||||
static const Containers::Array<Containers::String> types{InPlaceInit, {"StructProperty"_s}};
|
||||
return types;
|
||||
}
|
||||
|
||||
auto StructSerialiser::deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
UnsignedInt count, BinaryReader& reader, PropertySerialiser& serialiser) -> Containers::Array<UnrealPropertyBase::ptr>
|
||||
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)) {
|
||||
|
@ -52,18 +56,18 @@ auto StructSerialiser::deserialise(Containers::StringView name, Containers::Stri
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
Containers::Array<UnrealPropertyBase::ptr> array;
|
||||
Containers::Array<Types::UnrealPropertyBase::ptr> array;
|
||||
|
||||
if(count == 0) {
|
||||
auto prop = Containers::pointer<GenericStructProperty>();
|
||||
prop->structType = std::move(item_type);
|
||||
prop->structGuid = std::move(guid);
|
||||
auto prop = Containers::pointer<Types::GenericStructProperty>();
|
||||
prop->structType = Utility::move(item_type);
|
||||
prop->structGuid = guid;
|
||||
}
|
||||
else {
|
||||
for(UnsignedInt i = 0; i < count; i++) {
|
||||
auto prop = Containers::pointer<UnrealPropertyBase>();
|
||||
for(std::uint32_t i = 0; i < count; i++) {
|
||||
auto prop = Containers::pointer<Types::UnrealPropertyBase>();
|
||||
|
||||
prop = serialiser.readItem(reader, item_type, UnsignedLong(-1), name);
|
||||
prop = serialiser.readItem(reader, item_type, std::size_t(-1), name);
|
||||
|
||||
if(!prop) {
|
||||
prop = readStructValue(name, item_type, value_length, reader, serialiser);
|
||||
|
@ -74,17 +78,18 @@ auto StructSerialiser::deserialise(Containers::StringView name, Containers::Stri
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
dynamic_cast<StructProperty*>(prop.get())->structGuid = guid;
|
||||
dynamic_cast<Types::StructProperty*>(prop.get())->structGuid = guid;
|
||||
|
||||
arrayAppend(array, std::move(prop));
|
||||
arrayAppend(array, Utility::move(prop));
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
auto StructSerialiser::deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
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)) {
|
||||
|
@ -93,7 +98,7 @@ auto StructSerialiser::deserialise(Containers::StringView name, Containers::Stri
|
|||
}
|
||||
|
||||
if(item_type == "None") {
|
||||
return NoneProperty::ptr{};
|
||||
return Containers::pointer<Types::NoneProperty>();
|
||||
}
|
||||
|
||||
Containers::StaticArray<16, char> guid{ValueInit};
|
||||
|
@ -108,27 +113,28 @@ auto StructSerialiser::deserialise(Containers::StringView name, Containers::Stri
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
UnrealPropertyBase::ptr prop = serialiser.readItem(reader, item_type, value_length, name);
|
||||
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<GenericStructProperty*>(prop.get())->structGuid = std::move(guid);
|
||||
dynamic_cast<Types::GenericStructProperty*>(prop.get())->structGuid = guid;
|
||||
}
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
auto StructSerialiser::serialise(Containers::ArrayView<UnrealPropertyBase::ptr> props, Containers::StringView item_type,
|
||||
UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
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);
|
||||
UnsignedLong vl_pos = writer.arrayPosition();
|
||||
bytes_written += writer.writeValueToArray<UnsignedLong>(0ull);
|
||||
std::size_t vl_pos = writer.arrayPosition();
|
||||
bytes_written += writer.writeValueToArray<std::size_t>(0ull);
|
||||
|
||||
auto struct_prop = dynamic_cast<StructProperty*>(props.front().get());
|
||||
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;
|
||||
|
@ -138,11 +144,11 @@ auto StructSerialiser::serialise(Containers::ArrayView<UnrealPropertyBase::ptr>
|
|||
bytes_written += writer.writeDataToArray(arrayView(struct_prop->structGuid));
|
||||
bytes_written += writer.writeValueToArray<char>('\0');
|
||||
|
||||
UnsignedLong vl_start = writer.arrayPosition();
|
||||
std::size_t vl_start = writer.arrayPosition();
|
||||
|
||||
UnsignedLong bytes_written_here = 0;
|
||||
std::size_t bytes_written_here = 0;
|
||||
for(auto& prop : props) {
|
||||
struct_prop = dynamic_cast<StructProperty*>(prop.get());
|
||||
struct_prop = dynamic_cast<Types::StructProperty*>(prop.get());
|
||||
if(!struct_prop) {
|
||||
LOG_ERROR("The property is not a valid struct property.");
|
||||
return false;
|
||||
|
@ -156,17 +162,18 @@ auto StructSerialiser::serialise(Containers::ArrayView<UnrealPropertyBase::ptr>
|
|||
}
|
||||
}
|
||||
|
||||
UnsignedLong vl_stop = writer.arrayPosition() - vl_start;
|
||||
std::size_t vl_stop = writer.arrayPosition() - vl_start;
|
||||
writer.writeValueToArrayAt(vl_stop, vl_pos);
|
||||
bytes_written += vl_stop;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
auto StructSerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
bool
|
||||
Struct::serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser)
|
||||
{
|
||||
auto struct_prop = dynamic_cast<StructProperty*>(prop.get());
|
||||
auto struct_prop = dynamic_cast<Types::StructProperty*>(prop.get());
|
||||
if(!struct_prop) {
|
||||
LOG_ERROR("The property is not a valid struct property.");
|
||||
return false;
|
||||
|
@ -177,8 +184,8 @@ auto StructSerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& by
|
|||
writer.writeValueToArray<char>('\0');
|
||||
|
||||
if(!serialiser.writeItem(prop, struct_prop->structType, bytes_written, writer)) {
|
||||
UnsignedLong dummy_bytes_written = 0;
|
||||
UnsignedLong vl_start = writer.arrayPosition();
|
||||
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;
|
||||
|
@ -189,19 +196,22 @@ auto StructSerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& by
|
|||
return true;
|
||||
}
|
||||
|
||||
auto StructSerialiser::readStructValue(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> StructProperty::ptr
|
||||
Types::StructProperty::ptr
|
||||
Struct::readStructValue(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
{
|
||||
auto st_prop = Containers::pointer<GenericStructProperty>();
|
||||
static_cast<void>(value_length);
|
||||
|
||||
auto st_prop = Containers::pointer<Types::GenericStructProperty>();
|
||||
st_prop->structType = type;
|
||||
|
||||
UnrealPropertyBase::ptr prop;
|
||||
Types::UnrealPropertyBase::ptr prop;
|
||||
while((prop = serialiser.read(reader)) != nullptr) {
|
||||
arrayAppend(st_prop->properties, std::move(prop));
|
||||
arrayAppend(st_prop->properties, Utility::move(prop));
|
||||
|
||||
if(st_prop->properties.back()->name == "None" &&
|
||||
st_prop->properties.back()->propertyType == "NoneProperty" &&
|
||||
dynamic_cast<NoneProperty*>(st_prop->properties.back().get()) != nullptr)
|
||||
dynamic_cast<Types::NoneProperty*>(st_prop->properties.back().get()) != nullptr)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -212,10 +222,11 @@ auto StructSerialiser::readStructValue(Containers::StringView name, Containers::
|
|||
return st_prop;
|
||||
}
|
||||
|
||||
auto StructSerialiser::writeStructValue(StructProperty* prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
bool
|
||||
Struct::writeStructValue(Types::StructProperty* prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser)
|
||||
{
|
||||
auto struct_prop = dynamic_cast<GenericStructProperty*>(prop);
|
||||
auto struct_prop = dynamic_cast<Types::GenericStructProperty*>(prop);
|
||||
if(!struct_prop) {
|
||||
LOG_ERROR("The property is not a valid struct property.");
|
||||
return false;
|
||||
|
@ -230,3 +241,5 @@ auto StructSerialiser::writeStructValue(StructProperty* prop, UnsignedLong& byte
|
|||
|
||||
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
|
||||
// Copyright (C) 2021-2022 Guillaume Jacquemin
|
||||
// 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
|
||||
|
@ -16,18 +16,22 @@
|
|||
|
||||
#include <Corrade/Containers/String.h>
|
||||
|
||||
#include "../BinaryReader.h"
|
||||
#include "../BinaryWriter.h"
|
||||
#include "../../Logger/Logger.h"
|
||||
|
||||
#include "TextPropertySerialiser.h"
|
||||
#include "../../BinaryIo/Reader.h"
|
||||
#include "../../BinaryIo/Writer.h"
|
||||
|
||||
auto TextPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
||||
#include "TextProperty.h"
|
||||
|
||||
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;
|
||||
if(!reader.readChar(terminator) || terminator != '\0') {
|
||||
|
@ -49,7 +53,7 @@ auto TextPropertySerialiser::deserialiseProperty(Containers::StringView name, Co
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto interval = reader.position() - start_position;
|
||||
std::int64_t interval;
|
||||
|
||||
do {
|
||||
Containers::String str;
|
||||
|
@ -58,22 +62,23 @@ auto TextPropertySerialiser::deserialiseProperty(Containers::StringView name, Co
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
arrayAppend(prop->data, std::move(str));
|
||||
arrayAppend(prop->data, Utility::move(str));
|
||||
|
||||
interval = reader.position() - start_position;
|
||||
} while(UnsignedLong(interval) < value_length);
|
||||
} while(std::size_t(interval) < value_length);
|
||||
|
||||
prop->value = prop->data.back();
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
auto TextPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
||||
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) {
|
||||
LOG_ERROR("The property is not a valid text property.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -85,3 +90,5 @@ auto TextPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Un
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,17 +18,22 @@
|
|||
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "UnrealPropertySerialiser.h"
|
||||
#include "UnrealProperty.h"
|
||||
|
||||
#include "../Types/TextProperty.h"
|
||||
|
||||
class TextPropertySerialiser : public UnrealPropertySerialiser<TextProperty> {
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
class TextProperty : public UnrealProperty<Types::TextProperty> {
|
||||
public:
|
||||
using ptr = Containers::Pointer<TextPropertySerialiser>;
|
||||
using ptr = Containers::Pointer<TextProperty>;
|
||||
|
||||
private:
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
|
||||
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override;
|
||||
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override;
|
||||
bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
// 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
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -22,22 +22,26 @@
|
|||
#include <Corrade/Containers/ArrayView.h>
|
||||
#include <Corrade/Containers/StringView.h>
|
||||
|
||||
#include "AbstractUnrealPropertySerialiser.h"
|
||||
#include "AbstractUnrealProperty.h"
|
||||
#include "../Types/StructProperty.h"
|
||||
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
template<typename T>
|
||||
class UnrealPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
||||
static_assert(std::is_base_of<UnrealPropertyBase, T>::value, "T must be derived from UnrealPropertyBase.");
|
||||
class UnrealProperty : public AbstractUnrealProperty {
|
||||
static_assert(std::is_base_of<Types::UnrealPropertyBase, T>::value, "T must be derived from UnrealPropertyBase.");
|
||||
|
||||
public:
|
||||
using ptr = Containers::Pointer<UnrealPropertySerialiser<T>>;
|
||||
using ptr = Containers::Pointer<UnrealProperty<T>>;
|
||||
|
||||
auto types() -> Containers::ArrayView<const Containers::String> override {
|
||||
auto types() -> StringArrayView override {
|
||||
static const Containers::Array<Containers::String> types = []{
|
||||
Containers::Array<Containers::String> array;
|
||||
Containers::Pointer<T> p(new T);
|
||||
if(std::is_base_of<StructProperty, T>::value) {
|
||||
array = Containers::Array<Containers::String>{InPlaceInit, {dynamic_cast<StructProperty*>(p.get())->structType}};
|
||||
if(std::is_base_of<Types::StructProperty, T>::value) {
|
||||
array = Containers::Array<Containers::String>{InPlaceInit, {
|
||||
dynamic_cast<Types::StructProperty*>(p.get())->structType
|
||||
}};
|
||||
}
|
||||
else {
|
||||
array = Containers::Array<Containers::String>{InPlaceInit, {p->propertyType}};
|
||||
|
@ -47,23 +51,26 @@ class UnrealPropertySerialiser : public AbstractUnrealPropertySerialiser {
|
|||
return types;
|
||||
}
|
||||
|
||||
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length,
|
||||
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override
|
||||
auto deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
||||
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
||||
-> Types::UnrealPropertyBase::ptr override
|
||||
{
|
||||
return deserialiseProperty(name, type, value_length, reader, serialiser);
|
||||
}
|
||||
|
||||
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
|
||||
PropertySerialiser& serialiser) -> bool override
|
||||
bool serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
||||
PropertySerialiser& serialiser) override
|
||||
{
|
||||
return serialiseProperty(prop, bytes_written, writer, serialiser);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual auto deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
UnsignedLong value_length, BinaryReader& reader,
|
||||
PropertySerialiser& serialiser) -> typename UnrealPropertyBase::ptr = 0;
|
||||
std::size_t value_length, BinaryIo::Reader& reader,
|
||||
PropertySerialiser& serialiser) -> Types::UnrealPropertyBase::ptr = 0;
|
||||
|
||||
virtual auto serialiseProperty(typename UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
||||
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool = 0;
|
||||
virtual bool serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser) = 0;
|
||||
};
|
||||
|
||||
}
|
83
src/Gvas/Serialisers/Vector2DProperty.cpp
Normal file
83
src/Gvas/Serialisers/Vector2DProperty.cpp
Normal file
|
@ -0,0 +1,83 @@
|
|||
// 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 "Vector2DProperty.h"
|
||||
|
||||
namespace Gvas::Serialisers {
|
||||
|
||||
Types::UnrealPropertyBase::ptr
|
||||
Vector2DProperty::deserialiseProperty(Containers::StringView name, Containers::StringView type,
|
||||
std::size_t value_length, BinaryIo::Reader& reader,
|
||||
PropertySerialiser& serialiser)
|
||||
{
|
||||
auto prop = Containers::pointer<Types::Vector2DStructProperty>();
|
||||
|
||||
if(value_length == 8) { // UE4
|
||||
float x, y;
|
||||
|
||||
if(!reader.readFloat(x) || !reader.readFloat(y)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read 2D vector property {}'s value.", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
prop->vector = Vector2{x, y};
|
||||
}
|
||||
else if(value_length == 16) { // UE5
|
||||
double x, y;
|
||||
|
||||
if(!reader.readDouble(x) || !reader.readDouble(y)) {
|
||||
LOG_ERROR_FORMAT("Couldn't read 2D vector property {}'s value.", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
prop->vector = Vector2d{x, y};
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
bool
|
||||
Vector2DProperty::serialiseProperty(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written,
|
||||
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
||||
{
|
||||
auto vector = dynamic_cast<Types::Vector2DStructProperty*>(prop.get());
|
||||
if(!vector) {
|
||||
LOG_ERROR("The property is not a valid 2D vector property.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::visit(
|
||||
[&bytes_written, &writer](auto& arg){
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, Vector2>) {
|
||||
bytes_written += writer.writeValueToArray<float>(arg.x()) +
|
||||
writer.writeValueToArray<float>(arg.y());
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, Vector2d>) {
|
||||
bytes_written += writer.writeValueToArray<double>(arg.x()) +
|
||||
writer.writeValueToArray<double>(arg.y());
|
||||
}
|
||||
}, vector->vector
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue