Compare commits

..

No commits in common. "master" and "mass-viewer" have entirely different histories.

147 changed files with 3209 additions and 6550 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
*build*/ build*/
.idea/ .idea/
*.kdev4 *.kdev4
*~ *~

10
.gitmodules vendored
View File

@ -26,7 +26,11 @@
path = third-party/efsw path = third-party/efsw
url = https://github.com/SpartanJ/efsw url = https://github.com/SpartanJ/efsw
branch = master branch = master
[submodule "libcurl"] [submodule "third-party/cpr"]
path = third-party/curl path = third-party/cpr
url = https://github.com/curl/curl url = https://github.com/whoshuu/cpr
branch = master
[submodule "json.hpp"]
path = third-party/json
url = https://github.com/nlohmann/json
branch = master branch = master

View File

@ -21,20 +21,16 @@ set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/modules/" ${CMAKE_MODULE_PATH})
SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) SET(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CORRADE_BUILD_DEPRECATED OFF CACHE BOOL "" FORCE) set(BUILD_STATIC ON CACHE BOOL "" FORCE)
set(CORRADE_BUILD_STATIC ON CACHE BOOL "" FORCE) set(BUILD_STATIC_PIC ON CACHE BOOL "" FORCE)
set(CORRADE_BUILD_STATIC_PIC ON CACHE BOOL "" FORCE) set(BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
set(CORRADE_BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE)
set(CORRADE_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(WITH_INTERCONNECT ON CACHE BOOL "" FORCE)
set(CORRADE_WITH_INTERCONNECT OFF CACHE BOOL "" FORCE) set(WITH_PLUGINMANAGER ON CACHE BOOL "" FORCE)
set(CORRADE_WITH_PLUGINMANAGER OFF CACHE BOOL "" FORCE) set(WITH_TESTSUITE OFF CACHE BOOL "" FORCE)
set(CORRADE_WITH_TESTSUITE OFF CACHE BOOL "" FORCE) set(WITH_MAIN ON CACHE BOOL "" FORCE)
set(CORRADE_WITH_MAIN ON CACHE BOOL "" FORCE)
set(CORRADE_UTILITY_USE_ANSI_COLORS ON CACHE BOOL "" FORCE)
add_subdirectory(third-party/corrade EXCLUDE_FROM_ALL) add_subdirectory(third-party/corrade EXCLUDE_FROM_ALL)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(DIRECTX OFF CACHE BOOL "" FORCE) # We use OpenGL.
set(SDL_ATOMIC OFF CACHE BOOL "" FORCE) set(SDL_ATOMIC OFF CACHE BOOL "" FORCE)
set(SDL_CPUINFO OFF CACHE BOOL "" FORCE) set(SDL_CPUINFO OFF CACHE BOOL "" FORCE)
set(SDL_EVENTS ON CACHE BOOL "" FORCE) set(SDL_EVENTS ON CACHE BOOL "" FORCE)
@ -50,34 +46,26 @@ set(SDL_TIMERS ON CACHE BOOL "" FORCE)
set(SDL_SHARED OFF CACHE BOOL "" FORCE) set(SDL_SHARED OFF CACHE BOOL "" FORCE)
add_subdirectory(third-party/SDL EXCLUDE_FROM_ALL) add_subdirectory(third-party/SDL EXCLUDE_FROM_ALL)
set(MAGNUM_BUILD_STATIC ON CACHE BOOL "" FORCE) set(TARGET_GL ON CACHE BOOL "" FORCE)
set(MAGNUM_BUILD_STATIC_PIC ON CACHE BOOL "" FORCE) set(TARGET_GLES OFF CACHE BOOL "" FORCE)
set(MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS OFF CACHE BOOL "" FORCE) set(TARGET_VK OFF CACHE BOOL "" FORCE)
set(MAGNUM_BUILD_DEPRECATED OFF CACHE BOOL "" FORCE) set(WITH_AUDIO OFF CACHE BOOL "" FORCE)
set(MAGNUM_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(WITH_DEBUGTOOLS OFF CACHE BOOL "" FORCE)
set(WITH_GL ON CACHE BOOL "" FORCE)
set(MAGNUM_TARGET_GL ON CACHE BOOL "" FORCE) set(WITH_MESHTOOLS OFF CACHE BOOL "" FORCE)
set(MAGNUM_TARGET_GLES OFF CACHE BOOL "" FORCE) set(WITH_PRIMITIVES OFF CACHE BOOL "" FORCE)
set(MAGNUM_TARGET_VK OFF CACHE BOOL "" FORCE) set(WITH_SCENEGRAPH OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_AUDIO OFF CACHE BOOL "" FORCE) set(WITH_SHADERS ON CACHE BOOL "" FORCE)
set(MAGNUM_WITH_DEBUGTOOLS OFF CACHE BOOL "" FORCE) set(WITH_SHADERTOOLS OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_GL ON CACHE BOOL "" FORCE) set(WITH_TEXT OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_MATERIALTOOLS OFF CACHE BOOL "" FORCE) set(WITH_TEXTURETOOLS OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_MESHTOOLS OFF CACHE BOOL "" FORCE) set(WITH_TRADE OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_PRIMITIVES OFF CACHE BOOL "" FORCE) set(WITH_VK OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_SCENEGRAPH OFF CACHE BOOL "" FORCE) set(WITH_SDL2APPLICATION ON CACHE BOOL "" FORCE)
set(MAGNUM_WITH_SCENETOOLS OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_SHADERS ON CACHE BOOL "" FORCE)
set(MAGNUM_WITH_SHADERTOOLS OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_TEXT OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_TEXTURETOOLS OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_TRADE OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_VK OFF CACHE BOOL "" FORCE)
set(MAGNUM_WITH_SDL2APPLICATION ON CACHE BOOL "" FORCE)
add_subdirectory(third-party/magnum EXCLUDE_FROM_ALL) add_subdirectory(third-party/magnum EXCLUDE_FROM_ALL)
set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third-party/imgui) set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third-party/imgui)
set(MAGNUM_WITH_IMGUI ON CACHE BOOL "" FORCE) set(WITH_IMGUI ON CACHE BOOL "" FORCE)
add_subdirectory(third-party/magnum-integration EXCLUDE_FROM_ALL) add_subdirectory(third-party/magnum-integration EXCLUDE_FROM_ALL)
set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE) set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
@ -92,6 +80,7 @@ set(BUILD_TOOLS OFF CACHE BOOL "" FORCE)
set(BUILD_REGRESS OFF CACHE BOOL "" FORCE) set(BUILD_REGRESS OFF CACHE BOOL "" FORCE)
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(BUILD_DOC OFF CACHE BOOL "" FORCE) set(BUILD_DOC OFF CACHE BOOL "" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
add_subdirectory(third-party/libzip EXCLUDE_FROM_ALL) add_subdirectory(third-party/libzip EXCLUDE_FROM_ALL)
set(VERBOSE OFF CACHE BOOL "" FORCE) set(VERBOSE OFF CACHE BOOL "" FORCE)
@ -99,20 +88,11 @@ set(BUILD_TEST_APP OFF CACHE BOOL "" FORCE)
set(EFSW_INSTALL OFF CACHE BOOL "" FORCE) set(EFSW_INSTALL OFF CACHE BOOL "" FORCE)
add_subdirectory(third-party/efsw EXCLUDE_FROM_ALL) add_subdirectory(third-party/efsw EXCLUDE_FROM_ALL)
set(BUILD_TESTING OFF CACHE BOOL "" FORCE) set(CPR_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(BUILD_CURL_EXE OFF CACHE BOOL "" FORCE) set(CMAKE_USE_LIBSSH2 OFF CACHE BOOL "" FORCE) # For some reason, even when HTTP_ONLY is set to ON, libcurl will try to link to libssh2.
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) add_subdirectory(third-party/cpr EXCLUDE_FROM_ALL)
set(ENABLE_UNICODE ON CACHE BOOL "" FORCE)
set(ENABLE_INET_PTON OFF CACHE BOOL "" FORCE) set(JSON_BuildTests OFF CACHE BOOL "" FORCE)
set(ENABLE_DEBUG OFF CACHE BOOL "" FORCE) add_subdirectory(third-party/json)
set(ENABLE_THREADED_RESOLVER OFF CACHE BOOL "" FORCE)
set(HTTP_ONLY ON CACHE BOOL "" FORCE)
set(USE_LIBIDN2 OFF CACHE BOOL "" FORCE)
set(USE_WIN32_IDN ON CACHE BOOL "" FORCE)
set(CURL_USE_LIBPSL OFF CACHE BOOL "" FORCE)
set(CURL_STATIC_CRT OFF CACHE BOOL "" FORCE)
set(CURL_USE_SCHANNEL ON CACHE BOOL "" FORCE)
set(CURL_USE_LIBSSH2 OFF CACHE BOOL "" FORCE) # For some reason, even when HTTP_ONLY is set to ON, libcurl will try to link to libssh2.
add_subdirectory(third-party/curl EXCLUDE_FROM_ALL)
add_subdirectory(src) add_subdirectory(src)

View File

@ -1,20 +1,16 @@
# M.A.S.S. Builder Save Tool # M.A.S.S. Builder Save Tool
A save file manager and editor for M.A.S.S. Builder. Based on [wxMASSManager](https://git.williamjcm.ovh/williamjcm/wxMASSManager), A save file manager and editor for M.A.S.S. Builder. Based on [wxMASSManager](https://williamjcm.ovh/git/williamjcm/wxMASSManager), this is a fork using Magnum and ImGui for the UI.
this is a fork using Magnum and ImGui for the UI.
## Installing ## Installing
Get the `MassBuilderSaveTool-<version>.zip` file from the [the main website](https://williamjcm.ovh/mbst) or on the Get the `MassBuilderSaveTool-<version>.zip` file from the [Releases](https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool/releases) page, and extract it somewhere. Then, launch `MassBuilderSaveTool.exe`.
[Releases](https://git.williamjcm.ovh/williamjcm/MassBuilderSaveTool/releases) page, and extract it somewhere. Then,
launch `MassBuilderSaveTool-<version>.exe`.
## Building on MSYS2 - IGNORE IF YOU JUST WANT TO USE THE APP! ## Building on MSYS2 - IGNORE IF YOU JUST WANT TO USE THE APP!
1. Install the 64-bit (`x86_64`) version of [MSYS2](https://www.msys2.org/) in its default path (`C:\msys64`), and 1. Install the 64-bit (`x86_64`) version of [MSYS2](https://www.msys2.org/) in its default path (`C:\msys64`), and update it fully.
update it fully. 2. Run `pacman -S git mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-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`. 3. In a `MINGW64` shell, type `git clone https://github.com/williamjcm/MassBuilderSaveTool`.
3. In a `URCT64` shell, type `git clone https://github.com/williamjcm/MassBuilderSaveTool`.
4. Type `cd MassBuilderSaveTool && git submodule init && git submodule update && mkdir build && cd build`. 4. Type `cd MassBuilderSaveTool && git submodule init && git submodule update && mkdir build && cd build`.
5. Type `cmake -GNinja -DCMAKE_BUILD_TYPE=Release ..` 5. Type `cmake -GNinja -DCMAKE_BUILD_TYPE=Release ..`
6. Type `ninja` 6. Type `ninja`

View File

@ -62,8 +62,8 @@
# #
# Features of found Corrade library are exposed in these variables: # Features of found Corrade library are exposed in these variables:
# #
# CORRADE_MSVC_COMPATIBILITY - Defined if compiled with compatibility # CORRADE_MSVC2019_COMPATIBILITY - Defined if compiled with compatibility
# mode for MSVC 2019+ without the /permissive- flag set # mode for MSVC 2019
# CORRADE_MSVC2017_COMPATIBILITY - Defined if compiled with compatibility # CORRADE_MSVC2017_COMPATIBILITY - Defined if compiled with compatibility
# mode for MSVC 2017 # mode for MSVC 2017
# CORRADE_MSVC2015_COMPATIBILITY - Defined if compiled with compatibility # CORRADE_MSVC2015_COMPATIBILITY - Defined if compiled with compatibility
@ -100,7 +100,7 @@
# CORRADE_TARGET_MINGW - Defined if compiling under MinGW # CORRADE_TARGET_MINGW - Defined if compiling under MinGW
# CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT - Defined if PluginManager # CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT - Defined if PluginManager
# doesn't support dynamic plugin loading due to platform limitations # doesn't support dynamic plugin loading due to platform limitations
# CORRADE_TESTSUITE_TARGET_XCTEST - Defined if TestSuite is targeting Xcode # CORRADE_TESTSUITE_TARGET_XCTEST - Defined if TestSuite is targetting Xcode
# XCTest # XCTest
# CORRADE_UTILITY_USE_ANSI_COLORS - Defined if ANSI escape sequences are used # CORRADE_UTILITY_USE_ANSI_COLORS - Defined if ANSI escape sequences are used
# for colored output with Utility::Debug on Windows # for colored output with Utility::Debug on Windows
@ -264,7 +264,7 @@
# This file is part of Corrade. # This file is part of Corrade.
# #
# Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, # Copyright © 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
# 2017, 2018, 2019, 2020, 2021, 2022 # 2017, 2018, 2019, 2020, 2021
# Vladimír Vondruš <mosra@centrum.cz> # Vladimír Vondruš <mosra@centrum.cz>
# #
# Permission is hereby granted, free of charge, to any person obtaining a # Permission is hereby granted, free of charge, to any person obtaining a
@ -312,7 +312,7 @@ string(REGEX REPLACE "\n" ";" _corradeConfigure "${_corradeConfigure}")
set(_corradeFlags set(_corradeFlags
MSVC2015_COMPATIBILITY MSVC2015_COMPATIBILITY
MSVC2017_COMPATIBILITY MSVC2017_COMPATIBILITY
MSVC_COMPATIBILITY MSVC2019_COMPATIBILITY
BUILD_DEPRECATED BUILD_DEPRECATED
BUILD_STATIC BUILD_STATIC
BUILD_STATIC_UNIQUE_GLOBALS BUILD_STATIC_UNIQUE_GLOBALS
@ -529,7 +529,7 @@ foreach(_component ${Corrade_FIND_COMPONENTS})
set_property(TARGET Corrade::${_component} APPEND PROPERTY set_property(TARGET Corrade::${_component} APPEND PROPERTY
COMPATIBLE_INTERFACE_NUMBER_MAX CORRADE_CXX_STANDARD) COMPATIBLE_INTERFACE_NUMBER_MAX CORRADE_CXX_STANDARD)
# Path::libraryLocation() needs this # Directory::libraryLocation() needs this
if(CORRADE_TARGET_UNIX) if(CORRADE_TARGET_UNIX)
set_property(TARGET Corrade::${_component} APPEND PROPERTY set_property(TARGET Corrade::${_component} APPEND PROPERTY
INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS}) INTERFACE_LINK_LIBRARIES ${CMAKE_DL_LIBS})

View File

@ -36,7 +36,7 @@
# This file is part of Magnum. # This file is part of Magnum.
# #
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, # Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
# 2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> # 2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
# Copyright © 2018 Jonathan Hale <squareys@googlemail.com> # Copyright © 2018 Jonathan Hale <squareys@googlemail.com>
# #
# Permission is hereby granted, free of charge, to any person obtaining a # Permission is hereby granted, free of charge, to any person obtaining a
@ -59,18 +59,11 @@
# #
# In 1.71 ImGui depends on the ApplicationServices framework for macOS # In 1.71 ImGui depends on the ApplicationServices framework for macOS
# clipboard support. Since 1.72 the dependency is optional and used only if # clipboard support. It's removed again in 1.72. TODO: remove once obsolete
# IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS is enabled, but link to it
# always to be nice to users.
if(CORRADE_TARGET_APPLE) if(CORRADE_TARGET_APPLE)
find_library(_IMGUI_ApplicationServices_LIBRARY ApplicationServices) find_library(_IMGUI_ApplicationServices_LIBRARY ApplicationServices)
mark_as_advanced(_IMGUI_ApplicationServices_LIBRARY) mark_as_advanced(_IMGUI_ApplicationServices_LIBRARY)
set(_IMGUI_EXTRA_LIBRARIES ${_IMGUI_ApplicationServices_LIBRARY}) set(_IMGUI_EXTRA_LIBRARIES ${_IMGUI_ApplicationServices_LIBRARY})
# Since 1.82, ImGui on MinGW needs the imm32 library. For MSVC the library
# seems to be linked implicitly so this is not needed.
elseif(CORRADE_TARGET_WINDOWS AND CORRADE_TARGET_MINGW)
set(_IMGUI_EXTRA_LIBRARIES imm32)
endif() endif()
# Vcpkg distributes imgui as a library with a config file, so try that first -- # Vcpkg distributes imgui as a library with a config file, so try that first --
@ -82,6 +75,7 @@ endif()
if(NOT IMGUI_DIR AND TARGET imgui::imgui) if(NOT IMGUI_DIR AND TARGET imgui::imgui)
if(NOT TARGET ImGui::ImGui) if(NOT TARGET ImGui::ImGui)
add_library(ImGui::ImGui INTERFACE IMPORTED) add_library(ImGui::ImGui INTERFACE IMPORTED)
# TODO: remove once 1.71 is obsolete
set_property(TARGET ImGui::ImGui APPEND PROPERTY set_property(TARGET ImGui::ImGui APPEND PROPERTY
INTERFACE_LINK_LIBRARIES imgui::imgui ${_IMGUI_EXTRA_LIBRARIES}) INTERFACE_LINK_LIBRARIES imgui::imgui ${_IMGUI_EXTRA_LIBRARIES})
@ -110,6 +104,7 @@ else()
add_library(ImGui::ImGui INTERFACE IMPORTED) add_library(ImGui::ImGui INTERFACE IMPORTED)
set_property(TARGET ImGui::ImGui APPEND PROPERTY set_property(TARGET ImGui::ImGui APPEND PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${ImGui_INCLUDE_DIR}) INTERFACE_INCLUDE_DIRECTORIES ${ImGui_INCLUDE_DIR})
# TODO: remove once 1.71 is obsolete
if(_IMGUI_EXTRA_LIBRARIES) if(_IMGUI_EXTRA_LIBRARIES)
set_property(TARGET ImGui::ImGui APPEND PROPERTY set_property(TARGET ImGui::ImGui APPEND PROPERTY
INTERFACE_LINK_LIBRARIES ${_IMGUI_EXTRA_LIBRARIES}) INTERFACE_LINK_LIBRARIES ${_IMGUI_EXTRA_LIBRARIES})

View File

@ -60,7 +60,6 @@
# MeshTools - MeshTools library # MeshTools - MeshTools library
# Primitives - Primitives library # Primitives - Primitives library
# SceneGraph - SceneGraph library # SceneGraph - SceneGraph library
# SceneTools - SceneTools library
# Shaders - Shaders library # Shaders - Shaders library
# ShaderTools - ShaderTools library # ShaderTools - ShaderTools library
# Text - Text library # Text - Text library
@ -202,7 +201,7 @@
# This file is part of Magnum. # This file is part of Magnum.
# #
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, # Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
# 2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> # 2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
# #
# Permission is hereby granted, free of charge, to any person obtaining a # Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"), # copy of this software and associated documentation files (the "Software"),
@ -230,7 +229,7 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
# Unrolling the transitive dependencies here so this doesn't need to be # Unrolling the transitive dependencies here so this doesn't need to be
# after resolving inter-component dependencies. Listing also all plugins. # after resolving inter-component dependencies. Listing also all plugins.
if(_component MATCHES "^(Audio|DebugTools|MeshTools|Primitives|SceneTools|ShaderTools|Text|TextureTools|Trade|.+Importer|.+ImageConverter|.+Font|.+ShaderConverter)$") if(_component MATCHES "^(Audio|DebugTools|MeshTools|Primitives|ShaderTools|Text|TextureTools|Trade|.+Importer|.+ImageConverter|.+Font|.+ShaderConverter)$")
set(_MAGNUM_${_COMPONENT}_CORRADE_DEPENDENCIES PluginManager) set(_MAGNUM_${_COMPONENT}_CORRADE_DEPENDENCIES PluginManager)
endif() endif()
@ -355,8 +354,8 @@ endif()
# Component distinction (listing them explicitly to avoid mistakes with finding # Component distinction (listing them explicitly to avoid mistakes with finding
# components from other repositories) # components from other repositories)
set(_MAGNUM_LIBRARY_COMPONENTS set(_MAGNUM_LIBRARY_COMPONENTS
Audio DebugTools GL MeshTools Primitives SceneGraph SceneTools Shaders Audio DebugTools GL MeshTools Primitives SceneGraph Shaders ShaderTools
ShaderTools Text TextureTools Trade Text TextureTools Trade
WindowlessEglApplication EglContext OpenGLTester) WindowlessEglApplication EglContext OpenGLTester)
set(_MAGNUM_PLUGIN_COMPONENTS set(_MAGNUM_PLUGIN_COMPONENTS
AnyAudioImporter AnyImageConverter AnyImageImporter AnySceneConverter AnyAudioImporter AnyImageConverter AnyImageImporter AnySceneConverter
@ -388,7 +387,8 @@ if(CORRADE_TARGET_EMSCRIPTEN)
endif() endif()
if(CORRADE_TARGET_IOS) if(CORRADE_TARGET_IOS)
list(APPEND _MAGNUM_LIBRARY_COMPONENTS WindowlessIosApplication) list(APPEND _MAGNUM_LIBRARY_COMPONENTS WindowlessIosApplication)
elseif(CORRADE_TARGET_APPLE AND NOT MAGNUM_TARGET_GLES) endif()
if(CORRADE_TARGET_APPLE AND NOT CORRADE_TARGET_IOS)
list(APPEND _MAGNUM_LIBRARY_COMPONENTS WindowlessCglApplication CglContext) list(APPEND _MAGNUM_LIBRARY_COMPONENTS WindowlessCglApplication CglContext)
endif() endif()
if(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE) if(CORRADE_TARGET_UNIX AND NOT CORRADE_TARGET_APPLE)
@ -430,7 +430,7 @@ if(MAGNUM_TARGET_HEADLESS OR CORRADE_TARGET_EMSCRIPTEN OR CORRADE_TARGET_ANDROID
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessEglApplication) list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessEglApplication)
elseif(CORRADE_TARGET_IOS) elseif(CORRADE_TARGET_IOS)
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessIosApplication) list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessIosApplication)
elseif(CORRADE_TARGET_APPLE AND NOT MAGNUM_TARGET_GLES) elseif(CORRADE_TARGET_APPLE)
list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessCglApplication) list(APPEND _MAGNUM_OpenGLTester_DEPENDENCIES WindowlessCglApplication)
elseif(CORRADE_TARGET_UNIX) elseif(CORRADE_TARGET_UNIX)
if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_DESKTOP_GLES) if(MAGNUM_TARGET_GLES AND NOT MAGNUM_TARGET_DESKTOP_GLES)
@ -451,11 +451,8 @@ if(MAGNUM_TARGET_GL)
# GL not required by Primitives themselves, but transitively by MeshTools # GL not required by Primitives themselves, but transitively by MeshTools
list(APPEND _MAGNUM_Primitives_DEPENDENCIES GL) list(APPEND _MAGNUM_Primitives_DEPENDENCIES GL)
endif() endif()
set(_MAGNUM_SceneGraph_DEPENDENCIES ) set(_MAGNUM_SceneGraph_DEPENDENCIES )
set(_MAGNUM_SceneTools_DEPENDENCIES Trade)
set(_MAGNUM_Shaders_DEPENDENCIES GL) set(_MAGNUM_Shaders_DEPENDENCIES GL)
set(_MAGNUM_Text_DEPENDENCIES TextureTools) set(_MAGNUM_Text_DEPENDENCIES TextureTools)
if(MAGNUM_TARGET_GL) if(MAGNUM_TARGET_GL)
list(APPEND _MAGNUM_Text_DEPENDENCIES GL) list(APPEND _MAGNUM_Text_DEPENDENCIES GL)
@ -469,7 +466,6 @@ endif()
set(_MAGNUM_Trade_DEPENDENCIES ) set(_MAGNUM_Trade_DEPENDENCIES )
set(_MAGNUM_VulkanTester_DEPENDENCIES Vk) set(_MAGNUM_VulkanTester_DEPENDENCIES Vk)
set(_MAGNUM_AndroidApplication_DEPENDENCIES GL) set(_MAGNUM_AndroidApplication_DEPENDENCIES GL)
set(_MAGNUM_EmscriptenApplication_DEPENDENCIES) set(_MAGNUM_EmscriptenApplication_DEPENDENCIES)
if(MAGNUM_TARGET_GL) if(MAGNUM_TARGET_GL)
list(APPEND _MAGNUM_EmscriptenApplication_DEPENDENCIES GL) list(APPEND _MAGNUM_EmscriptenApplication_DEPENDENCIES GL)
@ -612,7 +608,7 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
# Dynamic plugins don't have any prefix (e.g. `lib` on Linux), # Dynamic plugins don't have any prefix (e.g. `lib` on Linux),
# search with empty prefix and then reset that back so we don't # search with empty prefix and then reset that back so we don't
# accidentally break something else # accidentaly break something else
set(_tmp_prefixes "${CMAKE_FIND_LIBRARY_PREFIXES}") set(_tmp_prefixes "${CMAKE_FIND_LIBRARY_PREFIXES}")
set(CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES};") set(CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES};")

View File

@ -48,7 +48,7 @@
# This file is part of Magnum. # This file is part of Magnum.
# #
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, # Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
# 2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> # 2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
# Copyright © 2018 Konstantinos Chatzilygeroudis <costashatz@gmail.com> # Copyright © 2018 Konstantinos Chatzilygeroudis <costashatz@gmail.com>
# #
# Permission is hereby granted, free of charge, to any person obtaining a # Permission is hereby granted, free of charge, to any person obtaining a

View File

@ -20,7 +20,7 @@
# This file is part of Magnum. # This file is part of Magnum.
# #
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, # Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
# 2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> # 2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
# Copyright © 2018 Jonathan Hale <squareys@googlemail.com> # Copyright © 2018 Jonathan Hale <squareys@googlemail.com>
# #
# Permission is hereby granted, free of charge, to any person obtaining a # Permission is hereby granted, free of charge, to any person obtaining a
@ -168,38 +168,37 @@ find_path(SDL2_INCLUDE_DIR
if(CORRADE_TARGET_WINDOWS) if(CORRADE_TARGET_WINDOWS)
find_file(SDL2_DLL_RELEASE find_file(SDL2_DLL_RELEASE
NAMES SDL2.dll NAMES SDL2.dll
PATH_SUFFIXES bin ${_SDL2_RUNTIME_PATH_SUFFIX} ${_SDL2_LIBRARY_PATH_SUFFIX}) PATH_SUFFIXES ${_SDL2_RUNTIME_PATH_SUFFIX} ${_SDL2_LIBRARY_PATH_SUFFIX})
find_file(SDL2_DLL_DEBUG find_file(SDL2_DLL_DEBUG
NAMES SDL2d.dll # not sure? NAMES SDL2d.dll # not sure?
PATH_SUFFIXES bin ${_SDL2_RUNTIME_PATH_SUFFIX} ${_SDL2_LIBRARY_PATH_SUFFIX}) PATH_SUFFIXES ${_SDL2_RUNTIME_PATH_SUFFIX} ${_SDL2_LIBRARY_PATH_SUFFIX})
endif() endif()
# (Static) macOS / iOS dependencies. On macOS these were mainly needed when # (Static) macOS / iOS dependencies
# building SDL statically using its CMake project, on iOS always. if(CORRADE_TARGET_APPLE AND SDL2_LIBRARY MATCHES "${CMAKE_STATIC_LIBRARY_SUFFIX}$")
if(CORRADE_TARGET_APPLE AND (SDL2_LIBRARY_DEBUG MATCHES "${CMAKE_STATIC_LIBRARY_SUFFIX}$" OR SDL2_LIBRARY_RELEASE MATCHES "${CMAKE_STATIC_LIBRARY_SUFFIX}$")) if(CORRADE_TARGET_IOS)
set(_SDL2_FRAMEWORKS set(_SDL2_FRAMEWORKS
iconv # should be in the system, needed by iOS as well now
AudioToolbox AudioToolbox
AVFoundation AVFoundation
CoreHaptics # needed since 2.0.18(?) on iOS and macOS
Foundation
Metal # needed since 2.0.8 on iOS, since 2.0.14 on macOS
GameController) # needed since 2.0.18(?) on macOS as well
if(CORRADE_TARGET_IOS)
list(APPEND _SDL2_FRAMEWORKS
CoreBluetooth # needed since 2.0.10
CoreGraphics CoreGraphics
CoreMotion CoreMotion
Foundation Foundation
GameController
Metal # needed since 2.0.8
QuartzCore QuartzCore
UIKit) UIKit)
else() else()
list(APPEND _SDL2_FRAMEWORKS # Those are needed when building SDL statically using its CMake project
set(_SDL2_FRAMEWORKS
iconv # should be in the system
AudioToolbox
AVFoundation
Carbon Carbon
Cocoa Cocoa
CoreAudio CoreAudio
CoreVideo CoreVideo
ForceFeedback ForceFeedback
Foundation
IOKit) IOKit)
endif() endif()
set(_SDL2_FRAMEWORK_LIBRARIES ) set(_SDL2_FRAMEWORK_LIBRARIES )
@ -248,7 +247,7 @@ if(NOT TARGET SDL2::SDL2)
endif() endif()
# Link frameworks on macOS / iOS if we have a static SDL # Link frameworks on macOS / iOS if we have a static SDL
if(CORRADE_TARGET_APPLE AND (SDL2_LIBRARY_DEBUG MATCHES "${CMAKE_STATIC_LIBRARY_SUFFIX}$" OR SDL2_LIBRARY_RELEASE MATCHES "${CMAKE_STATIC_LIBRARY_SUFFIX}$")) if(CORRADE_TARGET_APPLE AND SDL2_LIBRARY MATCHES ".*libSDL2.a$")
set_property(TARGET SDL2::SDL2 APPEND PROPERTY set_property(TARGET SDL2::SDL2 APPEND PROPERTY
INTERFACE_LINK_LIBRARIES ${_SDL2_FRAMEWORK_LIBRARIES}) INTERFACE_LINK_LIBRARIES ${_SDL2_FRAMEWORK_LIBRARIES})
endif() endif()

View File

@ -11,16 +11,4 @@
/> />
</dependentAssembly> </dependentAssembly>
</dependency> </dependency>
<asmv3:application>
<asmv3:windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
UTF-8
</activeCodePage>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
true/pm</dpiAware> <!-- legacy -->
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
permonitorv2,permonitor
</dpiAwareness> <!-- falls back to pm if pmv2 is not available -->
</asmv3:windowsSettings>
</asmv3:application>
</assembly> </assembly>

View File

@ -18,9 +18,9 @@ set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
set(SAVETOOL_PROJECT_VERSION 1.4.3) set(SAVETOOL_PROJECT_VERSION 1.3.0-pre)
find_package(Corrade REQUIRED Main Containers Utility) find_package(Corrade REQUIRED Main Containers Utility Interconnect)
find_package(Magnum REQUIRED GL Sdl2Application) find_package(Magnum REQUIRED GL Sdl2Application)
find_package(MagnumIntegration REQUIRED ImGui) find_package(MagnumIntegration REQUIRED ImGui)
@ -28,19 +28,6 @@ set_directory_properties(PROPERTIES CORRADE_USE_PEDANTIC_FLAGS ON)
corrade_add_resource(Assets assets.conf) corrade_add_resource(Assets assets.conf)
add_library(Logger STATIC EXCLUDE_FROM_ALL
Logger/Logger.h
Logger/Logger.cpp
Logger/EntryType.h
Logger/MagnumLogBuffer.h
Logger/MagnumLogBuffer.cpp
)
target_link_libraries(Logger PRIVATE
Corrade::Utility
Magnum::Magnum
)
add_library(UESaveFile STATIC EXCLUDE_FROM_ALL add_library(UESaveFile STATIC EXCLUDE_FROM_ALL
UESaveFile/Serialisers/AbstractUnrealCollectionPropertySerialiser.h UESaveFile/Serialisers/AbstractUnrealCollectionPropertySerialiser.h
UESaveFile/Serialisers/AbstractUnrealPropertySerialiser.h UESaveFile/Serialisers/AbstractUnrealPropertySerialiser.h
@ -114,15 +101,12 @@ add_library(UESaveFile STATIC EXCLUDE_FROM_ALL
UESaveFile/BinaryWriter.h UESaveFile/BinaryWriter.h
UESaveFile/BinaryWriter.cpp UESaveFile/BinaryWriter.cpp
UESaveFile/PropertySerialiser.h UESaveFile/PropertySerialiser.h
UESaveFile/PropertySerialiser.cpp UESaveFile/PropertySerialiser.cpp)
)
target_link_libraries(UESaveFile PRIVATE target_link_libraries(UESaveFile PRIVATE
Corrade::Containers Corrade::Containers
Corrade::Utility Corrade::Utility
Magnum::Magnum Magnum::Magnum)
Logger
)
add_executable(MassBuilderSaveTool WIN32 add_executable(MassBuilderSaveTool WIN32
main.cpp main.cpp
@ -130,51 +114,37 @@ add_executable(MassBuilderSaveTool WIN32
SaveTool/SaveTool.cpp SaveTool/SaveTool.cpp
SaveTool/SaveTool_drawAbout.cpp SaveTool/SaveTool_drawAbout.cpp
SaveTool/SaveTool_drawMainMenu.cpp SaveTool/SaveTool_drawMainMenu.cpp
SaveTool/SaveTool_FileWatcher.cpp
SaveTool/SaveTool_Initialisation.cpp
SaveTool/SaveTool_MainManager.cpp SaveTool/SaveTool_MainManager.cpp
SaveTool/SaveTool_MassViewer.cpp SaveTool/SaveTool_MassViewer.cpp
SaveTool/SaveTool_MassViewer_Frame.cpp SaveTool/SaveTool_MassViewer_Frame.cpp
SaveTool/SaveTool_MassViewer_Armour.cpp SaveTool/SaveTool_MassViewer_Armour.cpp
SaveTool/SaveTool_MassViewer_Weapons.cpp SaveTool/SaveTool_MassViewer_Weapons.cpp
SaveTool/SaveTool_ProfileManager.cpp SaveTool/SaveTool_ProfileManager.cpp
SaveTool/SaveTool_UpdateChecker.cpp
ProfileManager/ProfileManager.h ProfileManager/ProfileManager.h
ProfileManager/ProfileManager.cpp ProfileManager/ProfileManager.cpp
Profile/Profile.h Profile/Profile.h
Profile/Profile.cpp Profile/Profile.cpp
Profile/PropertyNames.h
Profile/ResourceIDs.h Profile/ResourceIDs.h
MassManager/MassManager.h MassManager/MassManager.h
MassManager/MassManager.cpp MassManager/MassManager.cpp
Mass/Accessory.h Mass/Accessory.h
Mass/ArmourPart.h Mass/ArmourPart.h
Mass/BulletLauncherAttachment.h
Mass/CustomStyle.h Mass/CustomStyle.h
Mass/Decal.h Mass/Decal.h
Mass/Joints.h Mass/Joints.h
Mass/Mass.h Mass/Mass.h
Mass/Mass.cpp 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.h
Mass/Weapon.cpp Mass/Weapon.cpp
Mass/WeaponPart.h Mass/WeaponPart.h
Maps/Accessories.h Maps/Accessories.h
Maps/ArmourSets.h Maps/ArmourSets.h
Maps/ArmourSlots.hpp Maps/ArmourSlots.hpp
Maps/BulletLauncherAttachmentStyles.hpp
Maps/BulletLauncherSockets.hpp
Maps/DamageTypes.hpp Maps/DamageTypes.hpp
Maps/EffectColourModes.hpp Maps/EffectColourModes.hpp
Maps/LastMissionId.h Maps/LastMissionId.h
Maps/StoryProgress.h Maps/StoryProgress.h
Maps/StyleNames.h Maps/StyleNames.h
Maps/WeaponParts.h
Maps/WeaponTypes.hpp Maps/WeaponTypes.hpp
ToastQueue/ToastQueue.h ToastQueue/ToastQueue.h
ToastQueue/ToastQueue.cpp ToastQueue/ToastQueue.cpp
@ -182,17 +152,14 @@ add_executable(MassBuilderSaveTool WIN32
FontAwesome/IconsFontAwesome5.h FontAwesome/IconsFontAwesome5.h
FontAwesome/IconsFontAwesome5Brands.h FontAwesome/IconsFontAwesome5Brands.h
resource.rc resource.rc
${Assets} ${Assets})
)
if(CMAKE_BUILD_TYPE STREQUAL Debug) if(CMAKE_BUILD_TYPE STREQUAL Debug)
add_compile_definitions(SAVETOOL_DEBUG_BUILD) add_compile_definitions(SAVETOOL_DEBUG_BUILD)
endif() endif()
add_compile_definitions( add_compile_definitions(SAVETOOL_VERSION="${SAVETOOL_PROJECT_VERSION}"
SAVETOOL_VERSION="${SAVETOOL_PROJECT_VERSION}" SAVETOOL_CODENAME="Dickish Cyclops"
SAVETOOL_CODENAME="Enigmatic Ellenier" SUPPORTED_GAME_VERSION="0.7.6")
SUPPORTED_GAME_VERSION="0.9.x"
)
if(CMAKE_BUILD_TYPE STREQUAL Release) if(CMAKE_BUILD_TYPE STREQUAL Release)
set_target_properties(MassBuilderSaveTool PROPERTIES OUTPUT_NAME MassBuilderSaveTool-${SAVETOOL_PROJECT_VERSION}) set_target_properties(MassBuilderSaveTool PROPERTIES OUTPUT_NAME MassBuilderSaveTool-${SAVETOOL_PROJECT_VERSION})
@ -207,16 +174,16 @@ endif()
target_link_libraries(MassBuilderSaveTool PRIVATE target_link_libraries(MassBuilderSaveTool PRIVATE
Corrade::Containers Corrade::Containers
Corrade::Utility Corrade::Utility
Corrade::Interconnect
Corrade::Main Corrade::Main
Magnum::Magnum Magnum::Magnum
Magnum::GL Magnum::GL
Magnum::Sdl2Application Magnum::Sdl2Application
MagnumIntegration::ImGui MagnumIntegration::ImGui
Logger
UESaveFile UESaveFile
efsw efsw
zip zip
libcurl cpr::cpr
nlohmann_json::nlohmann_json
imm32 imm32
wtsapi32 wtsapi32)
)

View File

@ -1,23 +0,0 @@
#pragma once
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
enum class EntryType {
Info,
Warning,
Error,
};

View File

@ -1,112 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <iostream>
#include <Corrade/Utility/Debug.h>
#include "Logger.h"
using Containers::Array;
using Utility::Debug;
using Utility::Warning;
using Utility::Error;
using namespace Magnum;
Logger&
Logger::instance() {
static Logger logger;
return logger;
}
void
Logger::initialise() {
#ifndef SAVETOOL_DEBUG_BUILD
_logFile.open("SaveToolLog.txt", std::ios::trunc);
_logFile << "In case you encounter a bug:\n" <<
"1. Do not run the Save Tool again, as this log will be cleared.\n" <<
"2. Go to either the official Sekai Project Discord guild, or the community M.A.S.S. Builder one.\n" <<
"3. Mention me (William JCM#2301) to get my attention, with a description of the bug.\n"
" Please include as many details as possible, I don't want to play \"20 questions\", and neither do you.\n" <<
"4. Send me this file _when I ask for it_, preferably in DMs.\n" <<
std::endl;
#endif
}
void
Logger::indent() {
_indentLevel++;
}
void
Logger::unindent() {
if(_indentLevel > 0) {
_indentLevel--;
}
}
void
Logger::log(EntryType type, StringView location, StringView message) {
Debug d{
#ifndef SAVETOOL_DEBUG_BUILD
&_logFile
#else
&std::cout
#endif
};
#ifdef SAVETOOL_DEBUG_BUILD
#define COLOURED_TEXT(colour, text) Debug::color(Debug::Color::colour) << (text) << Debug::resetColor
#else
#define COLOURED_TEXT(colour, text) (text)
#endif
switch(type) {
case EntryType::Info:
d << COLOURED_TEXT(Default, "[ INFO]"_s);
break;
case EntryType::Warning:
d << COLOURED_TEXT(Yellow, "[WARNING]"_s);
break;
case EntryType::Error:
d << COLOURED_TEXT(Red, "[ ERROR]"_s);
break;
}
#undef COLOURED_TEXT
d << "["_s << Debug::nospace << location << Debug::nospace << "]";
for(UnsignedInt i = 0; i < _indentLevel; i++) {
d << Debug::nospace << " "_s << Debug::nospace;
}
d << ((message.back() == '\n') ? message.exceptSuffix(1) : message);
}
void
Logger::lockMutex() {
_logMutex.lock();
}
void
Logger::unlockMutex() {
_logMutex.unlock();
}
Logger&
logger() {
return Logger::instance();
}

View File

@ -1,90 +0,0 @@
#pragma once
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <ctime>
#include <mutex>
#ifndef SAVETOOL_DEBUG_BUILD
#include <fstream>
#endif
#include <Corrade/Containers/String.h>
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Utility/Format.h>
#include <Magnum/Types.h>
#include "EntryType.h"
using namespace Corrade;
using Containers::ArrayView;
using Containers::String;
using Containers::StringView;
using namespace Magnum;
using namespace Containers::Literals;
class Logger {
public:
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
Logger(Logger&&) = delete;
Logger& operator=(Logger&&) = delete;
static auto instance() -> Logger&;
void initialise();
void indent();
void unindent();
void log(EntryType type, StringView location, StringView message);
void lockMutex();
void unlockMutex();
private:
Logger() = default;
#ifndef SAVETOOL_DEBUG_BUILD
std::ofstream _logFile;
#endif
UnsignedInt _indentLevel = 0;
std::mutex _logMutex{};
};
auto logger() -> Logger&;
#define LOG(entry_type, message) logger().lockMutex(); \
logger().log(EntryType::entry_type, \
Utility::format("{}:{}", StringView{__builtin_FILE()}.find("src"_s).data() + 4, __builtin_LINE()), \
message); \
logger().unlockMutex()
#define LOG_INFO(message) LOG(Info, message)
#define LOG_WARNING(message) LOG(Warning, message)
#define LOG_ERROR(message) LOG(Error, message)
#define LOG_INFO_FORMAT(message, ...) LOG_INFO(Utility::format(message, __VA_ARGS__))
#define LOG_WARNING_FORMAT(message, ...) LOG_WARNING(Utility::format(message, __VA_ARGS__))
#define LOG_ERROR_FORMAT(message, ...) LOG_ERROR(Utility::format(message, __VA_ARGS__))

View File

@ -1,30 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "MagnumLogBuffer.h"
MagnumLogBuffer::MagnumLogBuffer(EntryType type): std::stringbuf(std::ios_base::out), _type{type} {}
MagnumLogBuffer::~MagnumLogBuffer() = default;
int
MagnumLogBuffer::sync() {
logger().lockMutex();
logger().log(_type, "Corrade/Magnum"_s, str().c_str());
logger().unlockMutex();
str({});
return 0;
}

View File

@ -1,34 +0,0 @@
#pragma once
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <sstream>
#include "Logger.h"
#include "EntryType.h"
class MagnumLogBuffer : public std::stringbuf {
public:
explicit MagnumLogBuffer(EntryType type);
~MagnumLogBuffer();
private:
int sync() override;
EntryType _type;
};

View File

@ -18,667 +18,57 @@
#include <map> #include <map>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Types.h> #include <Magnum/Types.h>
using namespace Corrade;
using namespace Containers::Literals;
using namespace Magnum; using namespace Magnum;
enum AccessorySize { static const std::map<Int, const char*> accessories {
S, // Primitives
M, {1, "Cube (S)"},
L, {2, "Pentagon (S)"},
XL {3, "Hexagon (S)"},
}; {4, "Cylinder (S)"},
{5, "Sphere (S)"},
struct AccessoryData{ {6, "TriPyramid (S)"},
Containers::StringView name; {7, "SquPyramid (S)"},
AccessorySize size = AccessorySize::S; {8, "PenPyramid (S)"},
}; {9, "HexPyramid (S)"},
{10, "Cone (S)"},
static const std::map<Int, AccessoryData> accessories { {11, "SquStick (S)"},
// region Primitives {12, "PenStick (S)"},
{1, {"Cube"_s, AccessorySize::S}}, {13, "HexStick (S)"},
{2, {"Pentagon"_s, AccessorySize::S}}, {14, "CycStick (S)"},
{3, {"Hexagon"_s, AccessorySize::S}}, {15, "Capsule (S)"},
{4, {"Cylinder"_s, AccessorySize::S}}, {16, "Decal Pad 01 (S)"},
{5, {"Sphere"_s, AccessorySize::S}}, {17, "Decal Pad 02 (S)"},
{6, {"TriPyramid"_s, AccessorySize::S}}, {18, "Decal Pad 03 (S)"},
{7, {"SquPyramid"_s, AccessorySize::S}}, {19, "Decal Pad 04 (S)"},
{8, {"PenPyramid"_s, AccessorySize::S}}, {20, "Decal Pad 05 (S)"},
{9, {"HexPyramid"_s, AccessorySize::S}},
{10, {"Cone"_s, AccessorySize::S}}, {51, "SquBevel (S)"},
{11, {"SquStick"_s, AccessorySize::S}}, {52, "TriBevel (S)"},
{12, {"PenStick"_s, AccessorySize::S}}, {53, "PenBevel (S)"},
{13, {"HexStick"_s, AccessorySize::S}}, {54, "HexBevel (S)"},
{14, {"CycStick"_s, AccessorySize::S}}, {55, "CycBevel (S)"},
{15, {"Capsule"_s, AccessorySize::S}}, {56, "RecBevel (S)"},
{16, {"Decal Pad 01"_s, AccessorySize::S}}, {57, "DaiBevel (S)"},
{17, {"Decal Pad 02"_s, AccessorySize::S}}, {58, "MonBevel (S)"},
{18, {"Decal Pad 03"_s, AccessorySize::S}}, {59, "CofBevel (S)"},
{19, {"Decal Pad 04"_s, AccessorySize::S}}, {60, "JevBevel (S)"},
{20, {"Decal Pad 05"_s, AccessorySize::S}}, {61, "SquEmboss (S)"},
{21, {"Triangle"_s, AccessorySize::S}}, {62, "TriEmboss (S)"},
{22, {"ThinStar"_s, AccessorySize::S}}, {63, "PenEmboss (S)"},
{23, {"Star"_s, AccessorySize::S}}, {64, "HexEmboss (S)"},
{24, {"SixSideStar"_s, AccessorySize::S}}, {65, "CycEmboss (S)"},
{25, {"Asterisk"_s, AccessorySize::S}}, {66, "RecEmboss (S)"},
{26, {"Ring"_s, AccessorySize::S}}, {67, "DaiEmboss (S)"},
{27, {"SawedRing"_s, AccessorySize::S}}, {68, "MonEmboss (S)"},
{28, {"HalfRing"_s, AccessorySize::S}}, {69, "CofEmboss (S)"},
{29, {"Cresent"_s, AccessorySize::S}}, {70, "JevEmboss (S)"},
{30, {"Donut"_s, AccessorySize::S}},
{31, {"FiveCogWheel"_s, AccessorySize::S}}, // Armours
{32, {"SixCogWheel"_s, AccessorySize::S}},
{33, {"SevenCogWheel"_s, AccessorySize::S}}, // Components
{34, {"EightCogWheel"_s, AccessorySize::S}},
{35, {"TwelveCogWheel"_s, AccessorySize::S}}, // Connectors
{51, {"SquBevel"_s, AccessorySize::S}},
{52, {"TriBevel"_s, AccessorySize::S}},
{53, {"PenBevel"_s, AccessorySize::S}},
{54, {"HexBevel"_s, AccessorySize::S}},
{55, {"CycBevel"_s, AccessorySize::S}},
{56, {"RecBevel"_s, AccessorySize::S}},
{57, {"DaiBevel"_s, AccessorySize::S}},
{58, {"MonBevel"_s, AccessorySize::S}},
{59, {"CofBevel"_s, AccessorySize::S}},
{60, {"JevBevel"_s, AccessorySize::S}},
{61, {"SquEmboss"_s, AccessorySize::S}},
{62, {"TriEmboss"_s, AccessorySize::S}},
{63, {"PenEmboss"_s, AccessorySize::S}},
{64, {"HexEmboss"_s, AccessorySize::S}},
{65, {"CycEmboss"_s, AccessorySize::S}},
{66, {"RecEmboss"_s, AccessorySize::S}},
{67, {"DaiEmboss"_s, AccessorySize::S}},
{68, {"MonEmboss"_s, AccessorySize::S}},
{69, {"CofEmboss"_s, AccessorySize::S}},
{70, {"JevEmboss"_s, AccessorySize::S}},
{101, {"Flat Hex Pin"_s, AccessorySize::S}},
{102, {"Cross Circle Pin"_s, AccessorySize::S}},
{103, {"Flat Circle Pin"_s, AccessorySize::S}},
{104, {"Hex Circle Pin"_s, AccessorySize::S}},
{105, {"Circle Button Pin"_s, AccessorySize::S}},
{106, {"Hexagon Pin"_s, AccessorySize::S}},
{107, {"Cross Square Pin"_s, AccessorySize::S}},
{108, {"Flat Square Pin"_s, AccessorySize::S}},
{109, {"Quad Corner Pin"_s, AccessorySize::S}},
{110, {"Bi Corner Pin"_s, AccessorySize::S}},
{111, {"Circle Pin"_s, AccessorySize::S}},
{112, {"Flat End Pin"_s, AccessorySize::S}},
{113, {"Flat Cut Pin"_s, AccessorySize::S}},
{114, {"Radial Pin"_s, AccessorySize::S}},
{115, {"Diamiter Pin"_s, AccessorySize::S}},
{151, {"TriPoint"_s, AccessorySize::S}},
{152, {"SquPoint"_s, AccessorySize::S}},
{153, {"PenPoint"_s, AccessorySize::S}},
{154, {"HexPoint"_s, AccessorySize::S}},
{155, {"CycPoint"_s, AccessorySize::S}},
{156, {"Bevel SquCutPoint"_s, AccessorySize::S}},
{157, {"Bevel HexCutPoint"_s, AccessorySize::S}},
{158, {"Bevel HexPoint"_s, AccessorySize::S}},
{159, {"Bevel CycCutPoint"_s, AccessorySize::S}},
{160, {"Bevel CycPoint"_s, AccessorySize::S}},
{201, {"Shaped Edge 01"_s, AccessorySize::M}},
{202, {"Shaped Edge 02"_s, AccessorySize::M}},
{203, {"Shaped Edge 03"_s, AccessorySize::M}},
{204, {"Shaped Edge 04"_s, AccessorySize::M}},
{205, {"Shaped Edge 05"_s, AccessorySize::M}},
{206, {"Shaped Edge 06"_s, AccessorySize::M}},
{207, {"Shaped Edge 07"_s, AccessorySize::M}},
{208, {"Shaped Edge 08"_s, AccessorySize::M}},
{209, {"Shaped Edge 09"_s, AccessorySize::M}},
{210, {"Shaped Edge 10"_s, AccessorySize::M}},
{211, {"Shaped Edge 11"_s, AccessorySize::M}},
{212, {"Shaped Edge 12"_s, AccessorySize::M}},
{213, {"Shaped Edge 13"_s, AccessorySize::M}},
{214, {"Shaped Edge 14"_s, AccessorySize::M}},
{215, {"Shaped Edge 15"_s, AccessorySize::M}},
{216, {"Shaped Edge 16"_s, AccessorySize::M}},
{217, {"Shaped Edge 17"_s, AccessorySize::M}},
{218, {"Shaped Edge 18"_s, AccessorySize::M}},
{219, {"Shaped Edge 19"_s, AccessorySize::M}},
{220, {"Shaped Edge 20"_s, AccessorySize::M}},
{251, {"Fish Tail 01"_s, AccessorySize::M}},
{252, {"Fish Tail 02"_s, AccessorySize::M}},
{253, {"Fish Tail 03"_s, AccessorySize::M}},
{254, {"Fish Tail 04"_s, AccessorySize::M}},
{255, {"Fish Tail 05"_s, AccessorySize::M}},
{256, {"Based Separator 01"_s, AccessorySize::M}},
{257, {"Based Separator 02"_s, AccessorySize::M}},
{258, {"Based Separator 03"_s, AccessorySize::M}},
{259, {"Based Separator 04"_s, AccessorySize::M}},
{260, {"Based Separator 05"_s, AccessorySize::M}},
{261, {"Based Separator 06"_s, AccessorySize::M}},
{262, {"Based Separator 07"_s, AccessorySize::M}},
{263, {"Based Separator 08"_s, AccessorySize::M}},
{264, {"Based Separator 09"_s, AccessorySize::M}},
{265, {"Based Separator 10"_s, AccessorySize::M}},
{301, {"Rectangular Box 01"_s, AccessorySize::M}},
{302, {"Rectangular Box 02"_s, AccessorySize::M}},
{303, {"Rectangular Box 03"_s, AccessorySize::M}},
{304, {"Rectangular Box 04"_s, AccessorySize::M}},
{305, {"Rectangular Box 05"_s, AccessorySize::M}},
{306, {"CofBox 01"_s, AccessorySize::M}},
{307, {"CofBox 02"_s, AccessorySize::M}},
{308, {"CofBox 03"_s, AccessorySize::M}},
{309, {"CofBox 04"_s, AccessorySize::M}},
{310, {"CofBox 05"_s, AccessorySize::M}},
{311, {"Triangular Box 01"_s, AccessorySize::M}},
{312, {"Triangular Box 02"_s, AccessorySize::M}},
{313, {"Triangular Box 03"_s, AccessorySize::M}},
{314, {"Triangular Box 04"_s, AccessorySize::M}},
{315, {"Triangular Box 05"_s, AccessorySize::M}},
{316, {"Diagonal Box A01"_s, AccessorySize::M}},
{317, {"Diagonal Box A02"_s, AccessorySize::M}},
{318, {"Diagonal Box A03"_s, AccessorySize::M}},
{319, {"Diagonal Box A04"_s, AccessorySize::M}},
{320, {"Diagonal Box A05"_s, AccessorySize::M}},
{321, {"Diagonal Box B01"_s, AccessorySize::M}},
{322, {"Diagonal Box B02"_s, AccessorySize::M}},
{323, {"Diagonal Box B03"_s, AccessorySize::M}},
{324, {"Diagonal Box B04"_s, AccessorySize::M}},
{325, {"Diagonal Box B05"_s, AccessorySize::M}},
// endregion
// region Armours
{1001, {"Short Layer 01"_s, AccessorySize::M}},
{1002, {"Short Layer 02"_s, AccessorySize::M}},
{1003, {"Short Layer 03"_s, AccessorySize::M}},
{1004, {"Short Layer 04"_s, AccessorySize::M}},
{1005, {"Short Layer 05"_s, AccessorySize::M}},
{1006, {"Long Layer 01"_s, AccessorySize::M}},
{1007, {"Long Layer 02"_s, AccessorySize::M}},
{1008, {"Long Layer 03"_s, AccessorySize::M}},
{1009, {"Long Layer 04"_s, AccessorySize::M}},
{1010, {"Long Layer 05"_s, AccessorySize::M}},
{1011, {"Diagonal Long Layer 01"_s, AccessorySize::M}},
{1012, {"Diagonal Long Layer 02"_s, AccessorySize::M}},
{1013, {"Diagonal Long Layer 03"_s, AccessorySize::M}},
{1014, {"Diagonal Long Layer 04"_s, AccessorySize::M}},
{1015, {"Diagonal Long Layer 05"_s, AccessorySize::M}},
{1051, {"Sloped Layer 01"_s, AccessorySize::M}},
{1052, {"Sloped Layer 02"_s, AccessorySize::M}},
{1053, {"Sloped Layer 03"_s, AccessorySize::M}},
{1054, {"Sloped Layer 04"_s, AccessorySize::M}},
{1055, {"Sloped Layer 05"_s, AccessorySize::M}},
{1056, {"Sloped Layer 06"_s, AccessorySize::M}},
{1057, {"Sloped Layer 07"_s, AccessorySize::M}},
{1058, {"Sloped Layer 08"_s, AccessorySize::M}},
{1059, {"Sloped Layer 09"_s, AccessorySize::M}},
{1060, {"Sloped Layer 10"_s, AccessorySize::M}},
{1061, {"Sloped Layer 11"_s, AccessorySize::M}},
{1062, {"Sloped Layer 12"_s, AccessorySize::M}},
{1063, {"Sloped Layer 13"_s, AccessorySize::M}},
{1064, {"Sloped Layer 14"_s, AccessorySize::M}},
{1065, {"Sloped Layer 15"_s, AccessorySize::M}},
{1101, {"Raised Center 01"_s, AccessorySize::M}},
{1102, {"Raised Center 02"_s, AccessorySize::M}},
{1103, {"Raised Center 03"_s, AccessorySize::M}},
{1104, {"Raised Center 04"_s, AccessorySize::M}},
{1105, {"Raised Center 05"_s, AccessorySize::M}},
{1106, {"Raised Block 01"_s, AccessorySize::M}},
{1107, {"Raised Block 02"_s, AccessorySize::M}},
{1108, {"Raised Block 03"_s, AccessorySize::M}},
{1109, {"Raised Pointed"_s, AccessorySize::M}},
{1110, {"Raised Cover"_s, AccessorySize::M}},
{1111, {"Raised Slant 01"_s, AccessorySize::M}},
{1112, {"Raised Slant 02"_s, AccessorySize::M}},
{1113, {"Raised Slant 03"_s, AccessorySize::M}},
{1114, {"Raised Slant 04"_s, AccessorySize::M}},
{1115, {"Raised Slant 05"_s, AccessorySize::M}},
{1151, {"Wide Patch 01"_s, AccessorySize::L}},
{1152, {"Wide Patch 02"_s, AccessorySize::L}},
{1153, {"Wide Patch 03"_s, AccessorySize::L}},
{1154, {"Wide Patch 04"_s, AccessorySize::L}},
{1155, {"Wide Patch 05"_s, AccessorySize::L}},
{1201, {"Pointed Armour 01"_s, AccessorySize::L}},
{1202, {"Pointed Armour 02"_s, AccessorySize::L}},
{1203, {"Pointed Armour 03"_s, AccessorySize::L}},
{1204, {"Pointed Armour 04"_s, AccessorySize::L}},
{1205, {"Pointed Armour 05"_s, AccessorySize::L}},
{1206, {"Pointed Armour 06"_s, AccessorySize::L}},
{1207, {"Pointed Armour 07"_s, AccessorySize::L}},
{1208, {"Pointed Armour 08"_s, AccessorySize::L}},
{1209, {"Pointed Armour 09"_s, AccessorySize::L}},
{1210, {"Pointed Armour 10"_s, AccessorySize::L}},
{1211, {"Pointed Armour 11"_s, AccessorySize::L}},
{1212, {"Pointed Armour 12"_s, AccessorySize::L}},
{1213, {"Pointed Armour 13"_s, AccessorySize::L}},
{1214, {"Pointed Armour 14"_s, AccessorySize::L}},
{1215, {"Pointed Armour 15"_s, AccessorySize::L}},
{1251, {"E Limb Cover 01"_s, AccessorySize::L}},
{1252, {"E Limb Cover 02"_s, AccessorySize::L}},
{1253, {"E Limb Cover 03"_s, AccessorySize::L}},
{1254, {"E Limb Cover 04"_s, AccessorySize::L}},
{1255, {"E Limb Cover 05"_s, AccessorySize::L}},
{1256, {"E Limb Cover 06"_s, AccessorySize::L}},
{1257, {"E Limb Cover 07"_s, AccessorySize::L}},
{1258, {"E Limb Cover 08"_s, AccessorySize::L}},
{1259, {"E Limb Cover 09"_s, AccessorySize::L}},
{1260, {"E Limb Cover 10"_s, AccessorySize::L}},
{1301, {"C Limb Cover 01"_s, AccessorySize::L}},
{1302, {"C Limb Cover 02"_s, AccessorySize::L}},
{1303, {"C Limb Cover 03"_s, AccessorySize::L}},
{1304, {"C Limb Cover 04"_s, AccessorySize::L}},
{1305, {"C Limb Cover 05"_s, AccessorySize::L}},
{1306, {"C Limb Cover 06"_s, AccessorySize::L}},
{1307, {"C Limb Cover 07"_s, AccessorySize::L}},
{1308, {"C Limb Cover 08"_s, AccessorySize::L}},
{1309, {"C Limb Cover 09"_s, AccessorySize::L}},
{1310, {"C Limb Cover 10"_s, AccessorySize::L}},
{1311, {"C Limb Cover 11"_s, AccessorySize::L}},
{1312, {"C Limb Cover 12"_s, AccessorySize::L}},
{1313, {"C Limb Cover 13"_s, AccessorySize::L}},
{1314, {"C Limb Cover 14"_s, AccessorySize::L}},
{1315, {"C Limb Cover 15"_s, AccessorySize::L}},
{1316, {"C Limb Cover 16"_s, AccessorySize::L}},
{1317, {"C Limb Cover 17"_s, AccessorySize::L}},
{1318, {"C Limb Cover 18"_s, AccessorySize::L}},
{1319, {"C Limb Cover 19"_s, AccessorySize::L}},
{1320, {"C Limb Cover 20"_s, AccessorySize::L}},
{1351, {"P Limb Cover 01"_s, AccessorySize::XL}},
{1352, {"P Limb Cover 02"_s, AccessorySize::XL}},
{1353, {"P Limb Cover 03"_s, AccessorySize::XL}},
{1354, {"P Limb Cover 04"_s, AccessorySize::XL}},
{1355, {"P Limb Cover 05"_s, AccessorySize::XL}},
{1401, {"Flat Cover 01"_s, AccessorySize::XL}},
{1402, {"Flat Cover 02"_s, AccessorySize::XL}},
{1403, {"Flat Cover 03"_s, AccessorySize::XL}},
{1404, {"Flat Cover 04"_s, AccessorySize::XL}},
{1405, {"Flat Cover 05"_s, AccessorySize::XL}},
{1406, {"Flat Cover 06"_s, AccessorySize::XL}},
{1407, {"Flat Cover 07"_s, AccessorySize::XL}},
{1408, {"Flat Cover 08"_s, AccessorySize::XL}},
{1409, {"Flat Cover 09"_s, AccessorySize::XL}},
{1410, {"Flat Cover 10"_s, AccessorySize::XL}},
{1451, {"L Side Opening 01"_s, AccessorySize::XL}},
{1452, {"L Side Opening 02"_s, AccessorySize::XL}},
{1453, {"L Side Opening 03"_s, AccessorySize::XL}},
{1454, {"L Side Opening 04"_s, AccessorySize::XL}},
{1455, {"L Side Opening 05"_s, AccessorySize::XL}},
{1456, {"L Side Opening 06"_s, AccessorySize::XL}},
{1457, {"L Side Opening 07"_s, AccessorySize::XL}},
{1458, {"L Side Opening 08"_s, AccessorySize::XL}},
{1459, {"L Side Opening 09"_s, AccessorySize::XL}},
{1460, {"L Side Opening 10"_s, AccessorySize::XL}},
// endregion
// region Components
{2001, {"Disc Padding 01"_s, AccessorySize::M}},
{2002, {"Disc Padding 02"_s, AccessorySize::M}},
{2003, {"Disc Padding 03"_s, AccessorySize::M}},
{2004, {"Disc Padding 04"_s, AccessorySize::M}},
{2005, {"Disc Padding 05"_s, AccessorySize::M}},
{2006, {"Thin Padding 01"_s, AccessorySize::M}},
{2007, {"Thin Padding 02"_s, AccessorySize::M}},
{2008, {"Thin Padding 03"_s, AccessorySize::M}},
{2009, {"Thin Padding 04"_s, AccessorySize::M}},
{2010, {"Thin Padding 05"_s, AccessorySize::M}},
{2011, {"Thick Padding 01"_s, AccessorySize::M}},
{2012, {"Thick Padding 02"_s, AccessorySize::M}},
{2013, {"Thick Padding 03"_s, AccessorySize::M}},
{2014, {"Thick Padding 04"_s, AccessorySize::M}},
{2015, {"Thick Padding 05"_s, AccessorySize::M}},
{2016, {"Thick Padding 06"_s, AccessorySize::M}},
{2017, {"Thick Padding 07"_s, AccessorySize::M}},
{2018, {"Thick Padding 08"_s, AccessorySize::M}},
{2019, {"Thick Padding 09"_s, AccessorySize::M}},
{2020, {"Thick Padding 10"_s, AccessorySize::M}},
{2021, {"CSide Padding 01"_s, AccessorySize::M}},
{2022, {"CSide Padding 02"_s, AccessorySize::M}},
{2023, {"CSide Padding 03"_s, AccessorySize::M}},
{2024, {"CSide Padding 04"_s, AccessorySize::M}},
{2025, {"CSide Padding 05"_s, AccessorySize::M}},
{2051, {"Container 01"_s, AccessorySize::L}},
{2052, {"Container 02"_s, AccessorySize::L}},
{2053, {"Container 03"_s, AccessorySize::L}},
{2054, {"Container 04"_s, AccessorySize::L}},
{2055, {"Container 05"_s, AccessorySize::L}},
{2101, {"Plating 01"_s, AccessorySize::L}},
{2102, {"Plating 02"_s, AccessorySize::L}},
{2103, {"Plating 03"_s, AccessorySize::L}},
{2104, {"Plating 04"_s, AccessorySize::L}},
{2105, {"Plating 05"_s, AccessorySize::L}},
{2151, {"Complex Base 01"_s, AccessorySize::L}},
{2152, {"Complex Base 02"_s, AccessorySize::L}},
{2153, {"Complex Base 03"_s, AccessorySize::L}},
{2154, {"Complex Base 04"_s, AccessorySize::L}},
{2155, {"Complex Base 05"_s, AccessorySize::L}},
{2156, {"Complex Base 06"_s, AccessorySize::L}},
{2157, {"Complex Base 07"_s, AccessorySize::L}},
{2158, {"Complex Base 08"_s, AccessorySize::L}},
{2159, {"Complex Base 09"_s, AccessorySize::L}},
{2160, {"Complex Base 10"_s, AccessorySize::L}},
{2201, {"Long Base 01"_s, AccessorySize::XL}},
{2202, {"Long Base 02"_s, AccessorySize::XL}},
{2203, {"Long Base 03"_s, AccessorySize::XL}},
{2204, {"Long Base 04"_s, AccessorySize::XL}},
{2205, {"Long Base 05"_s, AccessorySize::XL}},
{2251, {"Straight Wing 01"_s, AccessorySize::XL}},
{2252, {"Straight Wing 02"_s, AccessorySize::XL}},
{2253, {"Straight Wing 03"_s, AccessorySize::XL}},
{2254, {"Straight Wing 04"_s, AccessorySize::XL}},
{2255, {"Straight Wing 05"_s, AccessorySize::XL}},
{2256, {"Straight Wing 06"_s, AccessorySize::XL}},
{2257, {"Straight Wing 07"_s, AccessorySize::XL}},
{2258, {"Straight Wing 08"_s, AccessorySize::XL}},
{2259, {"Straight Wing 09"_s, AccessorySize::XL}},
{2260, {"Straight Wing 10"_s, AccessorySize::XL}},
{2301, {"Triangular Wing 01"_s, AccessorySize::XL}},
{2302, {"Triangular Wing 02"_s, AccessorySize::XL}},
{2303, {"Triangular Wing 03"_s, AccessorySize::XL}},
{2304, {"Triangular Wing 04"_s, AccessorySize::XL}},
{2305, {"Triangular Wing 05"_s, AccessorySize::XL}},
{2306, {"Triangular Wing 06"_s, AccessorySize::XL}},
{2307, {"Triangular Wing 07"_s, AccessorySize::XL}},
{2308, {"Triangular Wing 08"_s, AccessorySize::XL}},
{2309, {"Triangular Wing 09"_s, AccessorySize::XL}},
{2310, {"Triangular Wing 10"_s, AccessorySize::XL}},
{2311, {"Triangular Wing 11"_s, AccessorySize::L}},
{2312, {"Triangular Wing 12"_s, AccessorySize::L}},
{2313, {"Triangular Wing 13"_s, AccessorySize::L}},
{2314, {"Triangular Wing 14"_s, AccessorySize::L}},
{2315, {"Triangular Wing 15"_s, AccessorySize::L}},
{2351, {"Complex Wing 01"_s, AccessorySize::XL}},
{2352, {"Complex Wing 02"_s, AccessorySize::XL}},
{2353, {"Complex Wing 03"_s, AccessorySize::XL}},
{2354, {"Complex Wing 04"_s, AccessorySize::XL}},
{2355, {"Complex Wing 05"_s, AccessorySize::XL}},
{2356, {"Complex Wing 06"_s, AccessorySize::L}},
{2357, {"Complex Wing 07"_s, AccessorySize::L}},
{2358, {"Complex Wing 08"_s, AccessorySize::L}},
{2359, {"Complex Wing 09"_s, AccessorySize::L}},
{2360, {"Complex Wing 10"_s, AccessorySize::L}},
{2401, {"Blade 01"_s, AccessorySize::XL}},
{2402, {"Blade 02"_s, AccessorySize::XL}},
{2403, {"Blade 03"_s, AccessorySize::XL}},
{2404, {"Blade 04"_s, AccessorySize::XL}},
{2405, {"Blade 05"_s, AccessorySize::XL}},
{2406, {"Blade 06"_s, AccessorySize::XL}},
{2407, {"Blade 07"_s, AccessorySize::XL}},
{2408, {"Blade 08"_s, AccessorySize::XL}},
{2409, {"Blade 09"_s, AccessorySize::XL}},
{2410, {"Blade 10"_s, AccessorySize::XL}},
{2411, {"Blade 11"_s, AccessorySize::XL}},
{2412, {"Blade 12"_s, AccessorySize::XL}},
{2413, {"Blade 13"_s, AccessorySize::XL}},
{2414, {"Blade 14"_s, AccessorySize::XL}},
{2415, {"Blade 15"_s, AccessorySize::XL}},
{2426, {"Curved Blade 01"_s, AccessorySize::XL}},
{2427, {"Curved Blade 02"_s, AccessorySize::XL}},
{2428, {"Curved Blade 03"_s, AccessorySize::XL}},
{2429, {"Curved Blade 04"_s, AccessorySize::XL}},
{2430, {"Curved Blade 05"_s, AccessorySize::XL}},
{2431, {"Axe Head 01"_s, AccessorySize::XL}},
{2432, {"Axe Head 02"_s, AccessorySize::XL}},
{2433, {"Axe Head 03"_s, AccessorySize::XL}},
{2434, {"Axe Head 04"_s, AccessorySize::XL}},
{2435, {"Axe Head 05"_s, AccessorySize::XL}},
{2451, {"Horn 01"_s, AccessorySize::M}},
{2452, {"Horn 02"_s, AccessorySize::M}},
{2453, {"Horn 03"_s, AccessorySize::M}},
{2454, {"Horn 04"_s, AccessorySize::M}},
{2455, {"Horn 05"_s, AccessorySize::M}},
{2456, {"Horn 06"_s, AccessorySize::M}},
{2457, {"Horn 07"_s, AccessorySize::M}},
{2458, {"Horn 08"_s, AccessorySize::M}},
{2459, {"Horn 09"_s, AccessorySize::M}},
{2460, {"Horn 10"_s, AccessorySize::M}},
{2461, {"Horn 11"_s, AccessorySize::M}},
{2462, {"Horn 12"_s, AccessorySize::M}},
{2463, {"Horn 13"_s, AccessorySize::M}},
{2464, {"Horn 14"_s, AccessorySize::M}},
{2465, {"Horn 15"_s, AccessorySize::M}},
{2471, {"Mask"_s, AccessorySize::M}},
{2472, {"Droplet"_s, AccessorySize::M}},
{2473, {"Thigh"_s, AccessorySize::M}},
{2474, {"LegS"_s, AccessorySize::M}},
{2475, {"LegTH"_s, AccessorySize::M}},
{2476, {"Plume 01"_s, AccessorySize::M}},
{2477, {"Plume 02"_s, AccessorySize::M}},
{2478, {"Plume 03"_s, AccessorySize::M}},
{2479, {"Plume 04"_s, AccessorySize::M}},
{2480, {"Plume 05"_s, AccessorySize::M}},
{2491, {"Tail 01"_s, AccessorySize::XL}},
{2492, {"Tail 02"_s, AccessorySize::XL}},
{2493, {"Tail 03"_s, AccessorySize::XL}},
{2494, {"Tail 04"_s, AccessorySize::XL}},
{2495, {"Tail 05"_s, AccessorySize::XL}},
{2501, {"Finger 01"_s, AccessorySize::M}},
{2502, {"Finger 02"_s, AccessorySize::M}},
{2503, {"Finger 03"_s, AccessorySize::M}},
{2504, {"Finger 04"_s, AccessorySize::M}},
{2505, {"Finger 05"_s, AccessorySize::M}},
{2510, {"Clamp 01"_s, AccessorySize::M}},
{2511, {"Clamp 02"_s, AccessorySize::M}},
{2512, {"Clamp 03"_s, AccessorySize::M}},
{2513, {"Clamp 04"_s, AccessorySize::M}},
{2514, {"Clamp 05"_s, AccessorySize::M}},
{2521, {"Fabric 01"_s, AccessorySize::XL}},
{2522, {"Fabric 02"_s, AccessorySize::XL}},
{2523, {"Fabric 03"_s, AccessorySize::XL}},
{2524, {"Fabric 04"_s, AccessorySize::XL}},
{2525, {"Fabric 05"_s, AccessorySize::XL}},
{2551, {"Energy Barrel 01"_s, AccessorySize::XL}},
{2552, {"Energy Barrel 02"_s, AccessorySize::XL}},
{2553, {"Energy Barrel 03"_s, AccessorySize::XL}},
{2554, {"Energy Barrel 04"_s, AccessorySize::XL}},
{2555, {"Energy Barrel 05"_s, AccessorySize::XL}},
{2601, {"L Bullet Barrel 01"_s, AccessorySize::XL}},
{2602, {"L Bullet Barrel 02"_s, AccessorySize::XL}},
{2603, {"L Bullet Barrel 03"_s, AccessorySize::XL}},
{2604, {"L Bullet Barrel 04"_s, AccessorySize::XL}},
{2605, {"L Bullet Barrel 05"_s, AccessorySize::XL}},
{2606, {"S Bullet Barrel 01"_s, AccessorySize::XL}},
{2607, {"S Bullet Barrel 02"_s, AccessorySize::XL}},
{2608, {"S Bullet Barrel 03"_s, AccessorySize::XL}},
{2609, {"S Bullet Barrel 04"_s, AccessorySize::XL}},
{2610, {"S Bullet Barrel 05"_s, AccessorySize::XL}},
{2611, {"B Bullet Barrel 01"_s, AccessorySize::XL}},
{2612, {"B Bullet Barrel 02"_s, AccessorySize::XL}},
{2613, {"B Bullet Barrel 03"_s, AccessorySize::XL}},
{2614, {"B Bullet Barrel 04"_s, AccessorySize::XL}},
{2615, {"B Bullet Barrel 05"_s, AccessorySize::XL}},
{2616, {"B Bullet Barrel 06"_s, AccessorySize::XL}},
{2617, {"B Bullet Barrel 07"_s, AccessorySize::XL}},
{2618, {"B Bullet Barrel 08"_s, AccessorySize::XL}},
{2619, {"B Bullet Barrel 09"_s, AccessorySize::XL}},
{2620, {"B Bullet Barrel 10"_s, AccessorySize::XL}},
{2651, {"Cylinder Scope 01"_s, AccessorySize::M}},
{2652, {"Cylinder Scope 02"_s, AccessorySize::M}},
{2653, {"Cylinder Scope 03"_s, AccessorySize::M}},
{2654, {"Cylinder Scope 04"_s, AccessorySize::M}},
{2655, {"Cylinder Scope 05"_s, AccessorySize::M}},
{2656, {"Elec Scope 01"_s, AccessorySize::M}},
{2657, {"Elec Scope 02"_s, AccessorySize::M}},
{2658, {"Elec Scope 03"_s, AccessorySize::M}},
{2659, {"Elec Scope 04"_s, AccessorySize::M}},
{2660, {"Elec Scope 05"_s, AccessorySize::M}},
{2661, {"Mark Scope 01"_s, AccessorySize::S}},
{2662, {"Mark Scope 02"_s, AccessorySize::S}},
{2663, {"Mark Scope 03"_s, AccessorySize::S}},
{2664, {"Mark Scope 04"_s, AccessorySize::S}},
{2665, {"Mark Scope 05"_s, AccessorySize::S}},
{2701, {"S Single Weaponry"_s, AccessorySize::M}},
{2702, {"S Packed Weaponry 01"_s, AccessorySize::M}},
{2703, {"S Packed Weaponry 02"_s, AccessorySize::M}},
{2704, {"S Packed Weaponry 03"_s, AccessorySize::M}},
{2705, {"S Packed Weaponry 04"_s, AccessorySize::M}},
{2706, {"L Single Weaponry"_s, AccessorySize::XL}},
{2707, {"L Packed Weaponry 01"_s, AccessorySize::XL}},
{2708, {"L Packed Weaponry 02"_s, AccessorySize::XL}},
{2709, {"L Packed Weaponry 03"_s, AccessorySize::XL}},
{2710, {"L Packed Weaponry 04"_s, AccessorySize::XL}},
{2711, {"Atk Single Weaponry"_s, AccessorySize::XL}},
{2712, {"Atk Packed Weaponry 01"_s, AccessorySize::XL}},
{2713, {"Atk Packed Weaponry 02"_s, AccessorySize::XL}},
{2714, {"Atk Packed Weaponry 03"_s, AccessorySize::XL}},
{2715, {"Atk Packed Weaponry 04"_s, AccessorySize::XL}},
{2751, {"Vent 01"_s, AccessorySize::M}},
{2752, {"Vent 02"_s, AccessorySize::M}},
{2753, {"Vent 03"_s, AccessorySize::M}},
{2754, {"Vent 04"_s, AccessorySize::M}},
{2755, {"Vent 05"_s, AccessorySize::M}},
{2756, {"Vent 06"_s, AccessorySize::M}},
{2757, {"Vent 07"_s, AccessorySize::M}},
{2758, {"Vent 08"_s, AccessorySize::M}},
{2759, {"Vent 09"_s, AccessorySize::M}},
{2760, {"Vent 10"_s, AccessorySize::M}},
{2901, {"Complex Construct 01"_s, AccessorySize::L}},
{2902, {"Complex Construct 02"_s, AccessorySize::L}},
{2903, {"Complex Construct 03"_s, AccessorySize::L}},
{2904, {"Complex Construct 04"_s, AccessorySize::L}},
{2905, {"Complex Construct 05"_s, AccessorySize::L}},
{2950, {"Q Mask 01"_s, AccessorySize::M}},
{2951, {"Q Mask 02"_s, AccessorySize::M}},
{2952, {"Q Mask 03"_s, AccessorySize::M}},
{2953, {"Q Mask 04"_s, AccessorySize::M}},
{2954, {"Q Mask 05"_s, AccessorySize::M}},
// endregion
// region Connectors
{3001, {"Circular Vent 01"_s, AccessorySize::M}},
{3002, {"Circular Vent 02"_s, AccessorySize::M}},
{3003, {"Circular Vent 03"_s, AccessorySize::M}},
{3004, {"Circular Vent 04"_s, AccessorySize::M}},
{3005, {"Circular Vent 05"_s, AccessorySize::M}},
{3006, {"Circular Vent 06"_s, AccessorySize::M}},
{3007, {"Circular Vent 07"_s, AccessorySize::M}},
{3008, {"Circular Vent 08"_s, AccessorySize::M}},
{3009, {"Circular Vent 09"_s, AccessorySize::M}},
{3010, {"Circular Vent 10"_s, AccessorySize::M}},
{3011, {"Circular Vent 11"_s, AccessorySize::M}},
{3012, {"Circular Vent 12"_s, AccessorySize::M}},
{3013, {"Circular Vent 13"_s, AccessorySize::M}},
{3014, {"Circular Vent 14"_s, AccessorySize::M}},
{3015, {"Circular Vent 15"_s, AccessorySize::M}},
{3051, {"Reactor 01"_s, AccessorySize::L}},
{3052, {"Reactor 02"_s, AccessorySize::L}},
{3053, {"Reactor 03"_s, AccessorySize::L}},
{3054, {"Reactor 04"_s, AccessorySize::L}},
{3055, {"Reactor 05"_s, AccessorySize::L}},
{3101, {"Connecting Tube 01"_s, AccessorySize::XL}},
{3102, {"Connecting Tube 02"_s, AccessorySize::XL}},
{3103, {"Connecting Tube 03"_s, AccessorySize::XL}},
{3104, {"Connecting Tube 04"_s, AccessorySize::XL}},
{3105, {"Connecting Tube 05"_s, AccessorySize::XL}},
{3151, {"Latch 01"_s, AccessorySize::M}},
{3152, {"Latch 02"_s, AccessorySize::M}},
{3153, {"Latch 03"_s, AccessorySize::M}},
{3154, {"Latch 04"_s, AccessorySize::M}},
{3155, {"Latch 05"_s, AccessorySize::M}},
{3156, {"Latch 06"_s, AccessorySize::M}},
{3157, {"Latch 07"_s, AccessorySize::M}},
{3158, {"Latch 08"_s, AccessorySize::M}},
{3159, {"Latch 09"_s, AccessorySize::M}},
{3160, {"Latch 10"_s, AccessorySize::M}},
{3161, {"Latch 11"_s, AccessorySize::M}},
{3162, {"Latch 12"_s, AccessorySize::M}},
{3163, {"Latch 13"_s, AccessorySize::M}},
{3164, {"Latch 14"_s, AccessorySize::M}},
{3165, {"Latch 15"_s, AccessorySize::M}},
{3201, {"Short Connector 01"_s, AccessorySize::M}},
{3202, {"Short Connector 02"_s, AccessorySize::M}},
{3203, {"Short Connector 03"_s, AccessorySize::M}},
{3204, {"Short Connector 04"_s, AccessorySize::M}},
{3205, {"Short Connector 05"_s, AccessorySize::M}},
{3206, {"Antenna 01"_s, AccessorySize::S}},
{3207, {"Antenna 02"_s, AccessorySize::S}},
{3208, {"Antenna 03"_s, AccessorySize::S}},
{3209, {"Antenna 04"_s, AccessorySize::S}},
{3210, {"Antenna 05"_s, AccessorySize::S}},
{3226, {"Long Connector 01"_s, AccessorySize::XL}},
{3227, {"Long Connector 02"_s, AccessorySize::XL}},
{3228, {"Long Connector 03"_s, AccessorySize::XL}},
{3229, {"Long Connector 04"_s, AccessorySize::XL}},
{3230, {"Long Connector 05"_s, AccessorySize::XL}},
{3231, {"Long Connector 06"_s, AccessorySize::XL}},
{3232, {"Long Connector 07"_s, AccessorySize::XL}},
{3233, {"Long Connector 08"_s, AccessorySize::XL}},
{3234, {"Long Connector 09"_s, AccessorySize::XL}},
{3235, {"Long Connector 10"_s, AccessorySize::XL}},
{3251, {"Complex Connector 01"_s, AccessorySize::XL}},
{3252, {"Complex Connector 02"_s, AccessorySize::XL}},
{3253, {"Complex Connector 03"_s, AccessorySize::XL}},
{3254, {"Complex Connector 04"_s, AccessorySize::XL}},
{3255, {"Complex Connector 05"_s, AccessorySize::XL}},
{3301, {"Tube Line 01"_s, AccessorySize::L}},
{3302, {"Tube Line 02"_s, AccessorySize::L}},
{3303, {"Tube Line 03"_s, AccessorySize::L}},
{3304, {"Tube Line 04"_s, AccessorySize::XL}},
{3305, {"Tube Line 05"_s, AccessorySize::XL}},
{3306, {"Tube Line 06"_s, AccessorySize::M}},
{3307, {"Tube Line 07"_s, AccessorySize::M}},
{3308, {"Tube Line 08"_s, AccessorySize::M}},
{3309, {"Tube Line 09"_s, AccessorySize::L}},
{3310, {"Tube Line 10"_s, AccessorySize::L}},
{3351, {"Radar Plate 01"_s, AccessorySize::M}},
{3352, {"Radar Plate 02"_s, AccessorySize::M}},
{3353, {"Radar Plate 03"_s, AccessorySize::M}},
{3354, {"Radar Plate 04"_s, AccessorySize::M}},
{3355, {"Radar Plate 05"_s, AccessorySize::M}},
{3356, {"Radar Pod 01"_s, AccessorySize::M}},
{3357, {"Radar Pod 02"_s, AccessorySize::M}},
{3358, {"Radar Pod 03"_s, AccessorySize::M}},
{3359, {"Radar Pod 04"_s, AccessorySize::M}},
{3360, {"Radar Pod 05"_s, AccessorySize::M}},
{3401, {"Tri Pod 01"_s, AccessorySize::M}},
{3402, {"Tri Pod 02"_s, AccessorySize::M}},
{3403, {"Tri Pod 03"_s, AccessorySize::M}},
{3404, {"Tri Pod 04"_s, AccessorySize::M}},
{3405, {"Tri Pod 05"_s, AccessorySize::M}},
{3406, {"Signal Pod 01"_s, AccessorySize::M}},
{3407, {"Signal Pod 02"_s, AccessorySize::M}},
{3408, {"Signal Pod 03"_s, AccessorySize::M}},
{3409, {"Signal Pod 04"_s, AccessorySize::M}},
{3410, {"Signal Pod 05"_s, AccessorySize::M}},
// endregion
}; };

View File

@ -18,41 +18,34 @@
#include <map> #include <map>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Types.h> #include <Magnum/Types.h>
using namespace Corrade;
using namespace Containers::Literals;
using namespace Magnum; using namespace Magnum;
struct ArmourSet { struct ArmourSet {
Containers::StringView name; const char* name;
bool neck_compatible; bool neck_compatible;
}; };
static const std::map<Int, ArmourSet> armour_sets { static const std::map<Int, ArmourSet> armour_sets {
{-1, {"<unequipped>"_s, true}}, {-1, {"<unequipped>", true}},
{0, {"Vanguard"_s, true}}, {0, {"Vanguard", true}},
{1, {"Assault Mk.I"_s, true}}, {1, {"Assault Mk.I", true}},
{2, {"Assault Mk.II"_s, false}}, {2, {"Assault Mk.II", false}},
{3, {"Assault Mk.III"_s, false}}, {3, {"Assault Mk.III", false}},
{7, {"Titan 001"_s, true}}, {7, {"Titan 001", true}},
{8, {"Titan 002"_s, false}}, {8, {"Titan 002", false}},
{9, {"Titan 003"_s, false}}, {9, {"Titan 003", false}},
{13, {"Blitz X"_s, true}}, {13, {"Blitz X", true}},
{14, {"Blitz EX"_s, false}}, {14, {"Blitz EX", false}},
{15, {"Blitz EXS"_s, false}}, {15, {"Blitz EXS", false}},
{16, {"Kaiser S-R0"_s, true}}, {16, {"Kaiser S-R0", true}},
{17, {"Kaiser S-R1"_s, false}}, {17, {"Kaiser S-R1", false}},
{18, {"Kaiser S-R2"_s, false}}, {18, {"Kaiser S-R2", false}},
{19, {"Hammerfall MG-A"_s, true}}, {19, {"Hammerfall MG-A", true}},
{20, {"Hammerfall MG-S"_s, false}}, {20, {"Hammerfall MG-S", false}},
{21, {"Hammerfall MG-X"_s, false}}, {21, {"Hammerfall MG-X", false}},
{22, {"Panzer S-UC"_s, true}}, {22, {"Panzer S-UC", true}},
{23, {"Panzer L-UC"_s, false}}, {23, {"Panzer L-UC", false}},
{24, {"Panzer H-UC"_s, false}}, {24, {"Panzer H-UC", false}},
{25, {"Axial Core R-Type"_s, true}},
{26, {"Axial Core S-Type"_s, false}},
{27, {"Axial Core X-Type"_s, false}},
}; };

View File

@ -15,42 +15,42 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifdef c #ifdef c
c(Face, "enuArmorSlots::NewEnumerator0"_s, "Face"_s) c(Face, "enuArmorSlots::NewEnumerator0", "Face")
c(UpperHead, "enuArmorSlots::NewEnumerator1"_s, "Upper head"_s) c(UpperHead, "enuArmorSlots::NewEnumerator1", "Upper head")
c(LowerHead, "enuArmorSlots::NewEnumerator2"_s, "Lower head"_s) c(LowerHead, "enuArmorSlots::NewEnumerator2", "Lower head")
c(Neck, "enuArmorSlots::NewEnumerator3"_s, "Neck"_s) c(Neck, "enuArmorSlots::NewEnumerator3", "Neck")
c(UpperBody, "enuArmorSlots::NewEnumerator4"_s, "Upper body"_s) c(UpperBody, "enuArmorSlots::NewEnumerator4", "Upper body")
c(MiddleBody, "enuArmorSlots::NewEnumerator5"_s, "Middle body"_s) c(MiddleBody, "enuArmorSlots::NewEnumerator5", "Middle body")
c(LowerBody, "enuArmorSlots::NewEnumerator6"_s, "Lower body"_s) c(LowerBody, "enuArmorSlots::NewEnumerator6", "Lower body")
c(FrontWaist, "enuArmorSlots::NewEnumerator7"_s, "Front waist"_s) c(FrontWaist, "enuArmorSlots::NewEnumerator7", "Front waist")
c(LeftFrontSkirt, "enuArmorSlots::NewEnumerator8"_s, "Left front skirt"_s) c(LeftFrontSkirt, "enuArmorSlots::NewEnumerator8", "Left front skirt")
c(RightFrontSkirt, "enuArmorSlots::NewEnumerator9"_s, "Right front skirt"_s) c(RightFrontSkirt, "enuArmorSlots::NewEnumerator9", "Right front skirt")
c(LeftSideSkirt, "enuArmorSlots::NewEnumerator10"_s, "Left side skirt"_s) c(LeftSideSkirt, "enuArmorSlots::NewEnumerator10", "Left side skirt")
c(RightSideSkirt, "enuArmorSlots::NewEnumerator11"_s, "Right side skirt"_s) c(RightSideSkirt, "enuArmorSlots::NewEnumerator11", "Right side skirt")
c(LeftBackSkirt, "enuArmorSlots::NewEnumerator12"_s, "Left back skirt"_s) c(LeftBackSkirt, "enuArmorSlots::NewEnumerator12", "Left back skirt")
c(RightBackSkirt, "enuArmorSlots::NewEnumerator13"_s, "Right back skirt"_s) c(RightBackSkirt, "enuArmorSlots::NewEnumerator13", "Right back skirt")
c(BackWaist, "enuArmorSlots::NewEnumerator14"_s, "Back waist"_s) c(BackWaist, "enuArmorSlots::NewEnumerator14", "Back waist")
c(LeftShoulder, "enuArmorSlots::NewEnumerator15"_s, "Left shoulder"_s) c(LeftShoulder, "enuArmorSlots::NewEnumerator15", "Left shoulder")
c(RightShoulder, "enuArmorSlots::NewEnumerator16"_s, "Right shoulder"_s) c(RightShoulder, "enuArmorSlots::NewEnumerator16", "Right shoulder")
c(LeftUpperArm, "enuArmorSlots::NewEnumerator17"_s, "Left upper arm"_s) c(LeftUpperArm, "enuArmorSlots::NewEnumerator17", "Left upper arm")
c(RightUpperArm, "enuArmorSlots::NewEnumerator18"_s, "Right upper arm"_s) c(RightUpperArm, "enuArmorSlots::NewEnumerator18", "Right upper arm")
c(LeftElbow, "enuArmorSlots::NewEnumerator19"_s, "Left elbow"_s) c(LeftElbow, "enuArmorSlots::NewEnumerator19", "Left elbow")
c(RightElbow, "enuArmorSlots::NewEnumerator20"_s, "Right elbow"_s) c(RightElbow, "enuArmorSlots::NewEnumerator20", "Right elbow")
c(LeftLowerArm, "enuArmorSlots::NewEnumerator21"_s, "Left lower arm"_s) c(LeftLowerArm, "enuArmorSlots::NewEnumerator21", "Left lower arm")
c(RightLowerArm, "enuArmorSlots::NewEnumerator22"_s, "Right lower arm"_s) c(RightLowerArm, "enuArmorSlots::NewEnumerator22", "Right lower arm")
c(Backpack, "enuArmorSlots::NewEnumerator23"_s, "Backpack"_s) c(Backpack, "enuArmorSlots::NewEnumerator23", "Backpack")
c(LeftHand, "enuArmorSlots::NewEnumerator24"_s, "Left hand"_s) c(LeftHand, "enuArmorSlots::NewEnumerator24", "Left hand")
c(RightHand, "enuArmorSlots::NewEnumerator25"_s, "Right hand"_s) c(RightHand, "enuArmorSlots::NewEnumerator25", "Right hand")
c(LeftUpperLeg, "enuArmorSlots::NewEnumerator26"_s, "Left upper leg"_s) c(LeftUpperLeg, "enuArmorSlots::NewEnumerator26", "Left upper leg")
c(RightUpperLeg, "enuArmorSlots::NewEnumerator27"_s, "Right upper leg"_s) c(RightUpperLeg, "enuArmorSlots::NewEnumerator27", "Right upper leg")
c(LeftKnee, "enuArmorSlots::NewEnumerator28"_s, "Left knee"_s) c(LeftKnee, "enuArmorSlots::NewEnumerator28", "Left knee")
c(RightKnee, "enuArmorSlots::NewEnumerator29"_s, "Right knee"_s) c(RightKnee, "enuArmorSlots::NewEnumerator29", "Right knee")
c(LeftLowerLeg, "enuArmorSlots::NewEnumerator30"_s, "Left lower leg"_s) c(LeftLowerLeg, "enuArmorSlots::NewEnumerator30", "Left lower leg")
c(RightLowerLeg, "enuArmorSlots::NewEnumerator31"_s, "Right lower leg"_s) c(RightLowerLeg, "enuArmorSlots::NewEnumerator31", "Right lower leg")
c(LeftAnkle, "enuArmorSlots::NewEnumerator32"_s, "Left ankle"_s) c(LeftAnkle, "enuArmorSlots::NewEnumerator32", "Left ankle")
c(RightAnkle, "enuArmorSlots::NewEnumerator33"_s, "Right ankle"_s) c(RightAnkle, "enuArmorSlots::NewEnumerator33", "Right ankle")
c(LeftHeel, "enuArmorSlots::NewEnumerator34"_s, "Left heel"_s) c(LeftHeel, "enuArmorSlots::NewEnumerator34", "Left heel")
c(RightHeel, "enuArmorSlots::NewEnumerator35"_s, "Right heel"_s) c(RightHeel, "enuArmorSlots::NewEnumerator35", "Right heel")
c(LeftFoot, "enuArmorSlots::NewEnumerator36"_s, "Left foot"_s) c(LeftFoot, "enuArmorSlots::NewEnumerator36", "Left foot")
c(RightFoot, "enuArmorSlots::NewEnumerator37"_s, "Right foot"_s) c(RightFoot, "enuArmorSlots::NewEnumerator37", "Right foot")
#endif #endif

View File

@ -1,22 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifdef c
c(NotFound, "NotARealValue"_s)
c(ActiveOne, "enuBLAttachmentStyle::NewEnumerator0"_s)
c(ActiveOnePerSlot, "enuBLAttachmentStyle::NewEnumerator1"_s)
c(AllEquipped, "enuBLAttachmentStyle::NewEnumerator2"_s)
#endif

View File

@ -1,24 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifdef c
c(Auto, "None"_s, "Auto"_s)
c(Shoulders, "Shoulder"_s, "Shoulders"_s)
c(Body, "Body"_s, "Body"_s)
c(Backpack, "Backpack"_s, "Backpack"_s)
c(Hip, "Hip"_s, "Hips"_s)
c(LowerLegs, "LowerLeg"_s, "Lower legs"_s)
#endif

View File

@ -15,10 +15,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifdef c #ifdef c
c(Physical, "enuDamageProperty::NewEnumerator0"_s) c(Physical, "enuDamageProperty::NewEnumerator0")
c(Piercing, "enuDamageProperty::NewEnumerator1"_s) c(Piercing, "enuDamageProperty::NewEnumerator1")
c(Heat, "enuDamageProperty::NewEnumerator2"_s) c(Heat, "enuDamageProperty::NewEnumerator2")
c(Freeze, "enuDamageProperty::NewEnumerator3"_s) c(Freeze, "enuDamageProperty::NewEnumerator3")
c(Shock, "enuDamageProperty::NewEnumerator4"_s) c(Shock, "enuDamageProperty::NewEnumerator4")
c(Plasma, "enuDamageProperty::NewEnumerator5"_s) c(Plasma, "enuDamageProperty::NewEnumerator5")
#endif #endif

View File

@ -15,6 +15,6 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifdef c #ifdef c
c(Default, "enuWeaponEffectColorMode::NewEnumerator0"_s) c(Default, "enuWeaponEffectColorMode::NewEnumerator0")
c(Custom, "enuWeaponEffectColorMode::NewEnumerator1"_s) c(Custom, "enuWeaponEffectColorMode::NewEnumerator1")
#endif #endif

View File

@ -18,44 +18,31 @@
#include <map> #include <map>
#include <Corrade/Containers/StringView.h> static const std::map<Int, const char*> mission_id_map {{
#include <Magnum/Types.h>
using namespace Corrade;
using namespace Containers::Literals;
using namespace Magnum;
static const std::map<Int, Containers::StringView> mission_id_map {{
// Story missions // Story missions
{0x0064, "Mission 1 - Training"_s}, {0x0064, "Mission 1 - Training"},
{0x0065, "Mission 2 - Patrol Operation"_s}, {0x0065, "Mission 2 - Patrol Operation"},
{0x0066, "Mission 3 - Fusion Cells in the Snow"_s}, {0x0066, "Mission 3 - Fusion Cells in the Snow"},
{0x0067, "Mission 4 - Earning Changes"_s}, {0x0067, "Mission 4 - Earning Changes"},
{0x0068, "Mission 5 - Unexpected Coordination"_s}, {0x0068, "Mission 5 - Unexpected Coordination"},
{0x0069, "Mission 6 - Empowering Void"_s}, {0x0069, "Mission 6 - Empowering Void"},
{0x006A, "Mission 7 - Logisitics Obstacles"_s}, {0x006A, "Mission 7 - Logisitics Obstacles"},
{0x006B, "Mission 8 - Wrath of the Wastelands"_s}, {0x006B, "Mission 8 - Wrath of the Wastelands"},
{0x006C, "Mission 9 - Suspicious Originator"_s}, {0x006C, "Mission 9 - Suspicious Originator"},
{0x006D, "Mission 10 - Researchers Data Recovery"_s}, {0x006D, "Mission 10 - Researchers Data Recovery"},
{0x006E, "Mission 11 - Tempestuous Sector"_s}, {0x006E, "Mission 11 - Tempestuous Sector"},
{0x006F, "Mission 12 - Clashes of Metal"_s}, {0x006F, "Mission 12 - Clashes of Metal"},
{0x0070, "Mission 13 - The Sandstorm Glutton"_s}, {0x0070, "Mission 13 - The Sandstorm Glutton"},
{0x0071, "Mission 14 - An Icy Investigation"_s}, {0x0071, "Mission 14 - An Icy Investigation"},
{0x0072, "Mission 15 - Outposts Line of Defense"_s},
{0x0073, "Mission 16 - Hidden in the Pass"_s},
{0x0074, "Mission 17 - Homebase Security"_s},
// Hunting grounds // Hunting grounds
{0x00C8, "Hunt 1 - Desert Pathway Safety"_s}, {0x00C8, "Hunt 1 - Desert Pathway Safety"},
{0x00C9, "Hunt 2 - Snowfield Custodian"_s}, {0x00C9, "Hunt 2 - Snowfield Custodian"},
{0x00CA, "Hunt 3 - Abandoned Valley Raid"_s}, {0x00CA, "Hunt 3 - Abandoned Valley Raid"},
{0x00CB, "Hunt 4 - Depths of the Machineries"_s}, {0x00CB, "Hunt 4 - Depths of the Machineries"},
{0x00CC, "Hunt 5 - Crater Crashers"_s},
{0x00CD, "Hunt 6 - Prototype Performance Tests"_s},
// Challenges // Challenges
{0x012C, "Challenge 1 - Redline Battlefront"_s}, {0x012C, "Challenge 1 - Redline Battlefront"},
{0x0140, "Challenge 2 - Void Convergence"_s}, {0x0140, "Challenge 2 - Void Convergence"},
{0x0190, "Challenge 3 - Gates of Ascension"_s} {0x0190, "Challenge 3 - Gates of Ascension"}
}}; }};

View File

@ -17,98 +17,78 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Types.h>
using namespace Corrade;
using namespace Containers::Literals;
using namespace Magnum;
struct StoryProgressPoint { struct StoryProgressPoint {
Int id; Int id;
Containers::StringView chapter; const char* chapter;
Containers::StringView point; const char* point;
Containers::StringView after = nullptr; const char* after = nullptr;
}; };
static const Corrade::Containers::Array<StoryProgressPoint> story_progress static const Corrade::Containers::Array<StoryProgressPoint> story_progress
{ {
InPlaceInit, InPlaceInit,
{ {
{0x0000, "Chapter 1"_s, "Chapter start (company isn't named yet)"_s}, {0x0000, "Chapter 1", "Chapter start (company isn't named yet)"},
{0x0064, "Chapter 1"_s, "First time in the hangar"_s}, {0x0064, "Chapter 1", "First time in the hangar"},
{0x0065, "Chapter 1"_s, "After 1st meeting with Quin in mission section"_s}, {0x0065, "Chapter 1", "After 1st meeting with Quin in mission section"},
{0x0066, "Chapter 1"_s, "Talking with Reina and Quin in hangar"_s, "After training"_s}, {0x0066, "Chapter 1", "Talking with Reina and Quin in hangar", "After training"},
{0x0067, "Chapter 1"_s, "Returned to hangar"_s, "After training"_s}, {0x0067, "Chapter 1", "Returned to hangar", "After training"},
{0x0068, "Chapter 1"_s, "Talked with Quin in development section"_s, "After training"_s}, {0x0068, "Chapter 1", "Talked with Quin in development section", "After training"},
{0x0069, "Chapter 1"_s, "Talked with Waltz in armour section"_s, "After training"_s}, {0x0069, "Chapter 1", "Talked with Waltz in armour section", "After training"},
{0x00C8, "Chapter 1"_s, "Talked with Kael in tuning section"_s, "After training"_s}, {0x00C8, "Chapter 1", "Talked with Kael in tuning section", "After training"},
{0x00C9, "Chapter 1"_s, "Got mission 2 briefing"_s, "After training"_s}, {0x00C9, "Chapter 1", "Got mission 2 briefing", "After training"},
{0x012C, "Chapter 1"_s, "Talking with Reina"_s, "After mission 2"_s}, {0x012C, "Chapter 1", "Talking with Reina", "After mission 2"},
{0x012D, "Chapter 1"_s, "Returned to hangar"_s, "After mission 2"_s}, {0x012D, "Chapter 1", "Returned to hangar", "After mission 2"},
{0x012E, "Chapter 1"_s, "Talked with Kael in tuning section"_s, "After mission 2"_s}, {0x012E, "Chapter 1", "Talked with Kael in tuning section", "After mission 2"},
{0x012F, "Chapter 1"_s, "Talked with Reina in hangar"_s, "After mission 2"_s}, {0x012F, "Chapter 1", "Talked with Reina in hangar", "After mission 2"},
{0x0130, "Chapter 1"_s, "Got mission 3 briefing"_s, "After mission 2"_s}, {0x0130, "Chapter 1", "Got mission 3 briefing", "After mission 2"},
{0x0190, "Chapter 1"_s, "Talking with Reina"_s, "After mission 3"_s}, {0x0190, "Chapter 1", "Talking with Reina", "After mission 3"},
{0x0191, "Chapter 1"_s, "Returned to hangar"_s, "After mission 3"_s}, {0x0191, "Chapter 1", "Returned to hangar", "After mission 3"},
{0x0192, "Chapter 1"_s, "Talked with Waltz in armour section"_s, "After mission 3"_s}, {0x0192, "Chapter 1", "Talked with Waltz in armour section", "After mission 3"},
{0x0193, "Chapter 1"_s, "Got mission 4 briefing"_s, "After mission 3"_s}, {0x0193, "Chapter 1", "Got mission 4 briefing", "After mission 3"},
{0x01F4, "Chapter 1"_s, "Talking with Reina"_s, "After mission 4"_s}, {0x01F4, "Chapter 1", "Talking with Reina", "After mission 4"},
{0x01F5, "Chapter 1"_s, "Returned to hangar"_s, "After mission 4"_s}, {0x01F5, "Chapter 1", "Returned to hangar", "After mission 4"},
{0x01F6, "Chapter 1"_s, "Talked with Waltz in armour section"_s, "After mission 4"_s}, {0x01F6, "Chapter 1", "Talked with Waltz in armour section", "After mission 4"},
{0x01F7, "Chapter 1"_s, "Talked with Reina in hangar"_s, "After mission 4"_s}, {0x01F7, "Chapter 1", "Talked with Reina in hangar", "After mission 4"},
{0x01F8, "Chapter 1"_s, "Got mission 5 and hunt 1 briefing"_s, "After mission 4"_s}, {0x01F8, "Chapter 1", "Got mission 5 and hunt 1 briefing", "After mission 4"},
{0x0258, "Chapter 1"_s, "Meeting Neon and Aine"_s, "After mission 5"_s}, {0x0258, "Chapter 1", "Meeting Neon and Aine", "After mission 5"},
{0x0259, "Chapter 1"_s, "Returned to hangar"_s, "After mission 5"_s}, {0x0259, "Chapter 1", "Returned to hangar", "After mission 5"},
{0x025A, "Chapter 1"_s, "Got mission 6 briefing"_s, "After mission 5"_s}, {0x025A, "Chapter 1", "Got mission 6 briefing", "After mission 5"},
{0x02BC, "Chapter 1"_s, "Talking with Reina"_s, "After mission 6"_s}, {0x02BC, "Chapter 1", "Talking with Reina", "After mission 6"},
{0x02BD, "Chapter 1"_s, "Returned to hangar"_s, "After mission 6"_s}, {0x02BD, "Chapter 1", "Returned to hangar", "After mission 6"},
{0x02BE, "Chapter 1"_s, "Got hunt 2 briefing"_s, "After mission 6"_s}, {0x02BE, "Chapter 1", "Got hunt 2 briefing", "After mission 6"},
{0x02BF, "Chapter 1"_s, "Met Ellenier"_s, "After mission 6"_s}, {0x02BF, "Chapter 1", "Met Ellenier", "After mission 6"},
{0x02C0, "Chapter 1"_s, "Got mission 7 briefing"_s, "After mission 6"_s}, {0x02C0, "Chapter 1", "Got mission 7 briefing", "After mission 6"},
{0x0320, "Chapter 1"_s, "Talking with Nier"_s, "After mission 7"_s}, {0x0320, "Chapter 1", "Talking with Nier", "After mission 7"},
{0x0321, "Chapter 1"_s, "Returned to hangar"_s, "After mission 7"_s}, {0x0321, "Chapter 1", "Returned to hangar", "After mission 7"},
{0x0322, "Chapter 1"_s, "Talked with Quin, Reina, and Nier in development section"_s, "After mission 7"_s}, {0x0322, "Chapter 1", "Talked with Quin, Reina, and Nier in development section", "After mission 7"},
{0x0323, "Chapter 1"_s, "Got mission 8 briefing"_s, "After mission 7"_s}, {0x0323, "Chapter 1", "Got mission 8 briefing", "After mission 7"},
{0x0384, "Chapter 1"_s, "Talking with crew in hangar"_s, "After mission 8"_s}, {0x0384, "Chapter 1", "Talking with crew in hangar", "After mission 8"},
{0x0385, "Chapter 1"_s, "Returned to hangar"_s, "After mission 8"_s}, {0x0385, "Chapter 1", "Returned to hangar", "After mission 8"},
{0x0386, "Chapter 1"_s, "Got hunt 3 briefing"_s, "After mission 8"_s}, {0x0386, "Chapter 1", "Got hunt 3 briefing", "After mission 8"},
{0x0387, "Chapter 1"_s, "Talked with Reina, Nier, and Quin in development section"_s, "After mission 8"_s}, {0x0387, "Chapter 1", "Talked with Reina, Nier, and Quin in development section", "After mission 8"},
{0x0388, "Chapter 2"_s, "Chapter start"_s}, {0x0388, "Chapter 2", "Chapter start"},
{0x0389, "Chapter 2"_s, "Got mission 9 briefing"_s}, {0x0389, "Chapter 2", "Got mission 9 briefing"},
{0x03E8, "Chapter 2"_s, "Talking with Reina in hangar"_s, "After mission 9"_s}, {0x03E8, "Chapter 2", "Talking with Reina in hangar", "After mission 9"},
{0x03E9, "Chapter 2"_s, "Returned to hangar"_s, "After mission 9"_s}, {0x03E9, "Chapter 2", "Returned to hangar", "After mission 9"},
{0x03EA, "Chapter 2"_s, "Talked with crew in armour section"_s, "After mission 9"_s}, {0x03EA, "Chapter 2", "Talked with crew in armour section", "After mission 9"},
{0x03EB, "Chapter 2"_s, "Got mission 10 briefing"_s, "After mission 9"_s}, {0x03EB, "Chapter 2", "Got mission 10 briefing", "After mission 9"},
{0x044C, "Chapter 2"_s, "Talking with Reina in hangar"_s, "After mission 10"_s}, {0x044C, "Chapter 2", "Talking with Reina in hangar", "After mission 10"},
{0x044D, "Chapter 2"_s, "Returned to hangar"_s, "After mission 10"_s}, {0x044D, "Chapter 2", "Returned to hangar", "After mission 10"},
{0x044E, "Chapter 2"_s, "Got mission 11 briefing"_s, "After mission 10"_s}, {0x044E, "Chapter 2", "Got mission 11 briefing", "After mission 10"},
{0x04B0, "Chapter 2"_s, "Talking with Reina and Nier in hangar"_s, "After mission 11"_s}, {0x04B0, "Chapter 2", "Talking with Reina and Nier in hangar", "After mission 11"},
{0x04B1, "Chapter 2"_s, "Returned to hangar"_s, "After mission 11"_s}, {0x04B1, "Chapter 2", "Returned to hangar", "After mission 11"},
{0x04B2, "Chapter 2"_s, "Got mission 12 briefing"_s, "After mission 11"_s}, {0x04B2, "Chapter 2", "Got mission 12 briefing", "After mission 11"},
{0x0514, "Chapter 2"_s, "Talking with Reina and Waltz in hangar"_s, "After mission 12"_s}, {0x0514, "Chapter 2", "Talking with Reina and Waltz in hangar", "After mission 12"},
{0x0515, "Chapter 2"_s, "Returned to hangar"_s, "After mission 12"_s}, {0x0515, "Chapter 2", "Returned to hangar", "After mission 12"},
{0x0516, "Chapter 2"_s, "Got hunt 4 and mission 13 briefing"_s, "After mission 12"_s}, {0x0516, "Chapter 2", "Got hunt 4 and mission 13 briefing", "After mission 12"},
{0x0578, "Chapter 2", "Talking with Reina in hangar", "After mission 13"},
{0x0578, "Chapter 3"_s, "Chapter start, talking with Reina"_s, "After mission 13"_s}, {0x0579, "Chapter 2", "Returned to hangar", "After mission 13"},
{0x0579, "Chapter 3"_s, "Returned to hangar"_s, "After mission 13"_s}, {0x057A, "Chapter 2", "Talked with Reina in development section", "After mission 13"},
{0x057A, "Chapter 3"_s, "Talked with Reina in development section"_s, "After mission 13"_s}, {0x057B, "Chapter 2", "Got briefing for challenges 1, 2, and 3", "After mission 13"},
{0x057B, "Chapter 3"_s, "Got briefing for challenges 1, 2, and 3"_s, "After mission 13"_s}, {0x057C, "Chapter 2", "Talked with Reina about device", "After mission 13"},
{0x057C, "Chapter 3"_s, "Talked with Reina about device"_s, "After mission 13"_s}, {0x057D, "Chapter 2", "Got mission 14 briefing", "After mission 13"},
{0x057D, "Chapter 3"_s, "Got mission 14 briefing"_s, "After mission 13"_s},
{0x05DC, "Chapter 3"_s, "Talking with Reina and Nier"_s, "After mission 14"_s},
{0x05DD, "Chapter 3"_s, "Returned to hangar"_s, "After mission 14"_s},
{0x05DE, "Chapter 3"_s, "Got briefing for mission 15 and hunt 5"_s, "After mission 14"_s},
{0x0640, "Chapter 3"_s, "Talking with Nier and Kazu, and Reina"_s, "After mission 15"_s},
{0x0641, "Chapter 3"_s, "Returned to hangar"_s, "After mission 15"_s},
{0x0642, "Chapter 3"_s, "Talked with Reina and Nier in dev section"_s, "After mission 15"_s},
{0x0643, "Chapter 3"_s, "Got briefing for mission 16"_s, "After mission 15"_s},
{0x06A4, "Chapter 3"_s, "Talking with Kunai"_s, "After mission 16"_s},
{0x06A5, "Chapter 3"_s, "Returned to hangar"_s, "After mission 16"_s},
{0x06A6, "Chapter 3"_s, "Got mission 17 briefing"_s, "After mission 16"_s},
{0x0708, "Chapter 3"_s, "Debriefing"_s, "After mission 17"_s},
{0x070A, "Chapter 3"_s, "Got hunt 6 briefing"_s, "After mission 17"_s},
} }
}; };

View File

@ -18,179 +18,175 @@
#include <map> #include <map>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Magnum.h> #include <Magnum/Magnum.h>
using namespace Corrade;
using namespace Containers::Literals;
using namespace Magnum; using namespace Magnum;
extern const std::map<Int, Containers::StringView> style_names extern const std::map<Int, const char*> style_names
#ifdef STYLENAMES_DEFINITION #ifdef STYLENAMES_DEFINITION
{ {
{0, "Custom Style 1"_s}, {0, "Custom Style 1"},
{1, "Custom Style 2"_s}, {1, "Custom Style 2"},
{2, "Custom Style 3"_s}, {2, "Custom Style 3"},
{3, "Custom Style 4"_s}, {3, "Custom Style 4"},
{4, "Custom Style 5"_s}, {4, "Custom Style 5"},
{5, "Custom Style 6"_s}, {5, "Custom Style 6"},
{6, "Custom Style 7"_s}, {6, "Custom Style 7"},
{7, "Custom Style 8"_s}, {7, "Custom Style 8"},
{8, "Custom Style 9"_s}, {8, "Custom Style 9"},
{9, "Custom Style 10"_s}, {9, "Custom Style 10"},
{10, "Custom Style 11"_s}, {10, "Custom Style 11"},
{11, "Custom Style 12"_s}, {11, "Custom Style 12"},
{12, "Custom Style 13"_s}, {12, "Custom Style 13"},
{13, "Custom Style 14"_s}, {13, "Custom Style 14"},
{14, "Custom Style 15"_s}, {14, "Custom Style 15"},
{15, "Custom Style 16"_s}, {15, "Custom Style 16"},
{50, "Global Style 1"_s}, {50, "Global Style 1"},
{51, "Global Style 2"_s}, {51, "Global Style 2"},
{52, "Global Style 3"_s}, {52, "Global Style 3"},
{53, "Global Style 4"_s}, {53, "Global Style 4"},
{54, "Global Style 5"_s}, {54, "Global Style 5"},
{55, "Global Style 6"_s}, {55, "Global Style 6"},
{56, "Global Style 7"_s}, {56, "Global Style 7"},
{57, "Global Style 8"_s}, {57, "Global Style 8"},
{58, "Global Style 9"_s}, {58, "Global Style 9"},
{59, "Global Style 10"_s}, {59, "Global Style 10"},
{60, "Global Style 11"_s}, {60, "Global Style 11"},
{61, "Global Style 12"_s}, {61, "Global Style 12"},
{62, "Global Style 13"_s}, {62, "Global Style 13"},
{63, "Global Style 14"_s}, {63, "Global Style 14"},
{64, "Global Style 15"_s}, {64, "Global Style 15"},
{65, "Global Style 16"_s}, {65, "Global Style 16"},
{100, "Iron"_s}, {100, "Iron"},
{101, "Silver"_s}, {101, "Silver"},
{102, "Gold"_s}, {102, "Gold"},
{103, "Bronze"_s}, {103, "Bronze"},
{104, "Copper"_s}, {104, "Copper"},
{105, "Nickel"_s}, {105, "Nickel"},
{106, "Cobalt"_s}, {106, "Cobalt"},
{107, "Aluminium"_s}, {107, "Aluminium"},
{108, "Titanium"_s}, {108, "Titanium"},
{109, "Platinum"_s}, {109, "Platinum"},
{110, "Gun Metal"_s}, {110, "Gun Metal"},
{111, "White"_s}, {111, "White"},
{112, "White Metal"_s}, {112, "White Metal"},
{113, "White Gloss"_s}, {113, "White Gloss"},
{114, "Grey"_s}, {114, "Grey"},
{115, "Grey Metal"_s}, {115, "Grey Metal"},
{116, "Grey Gloss"_s}, {116, "Grey Gloss"},
{117, "Dark Grey"_s}, {117, "Dark Grey"},
{118, "Dark Grey Metal"_s}, {118, "Dark Grey Metal"},
{119, "Dark Grey Gloss"_s}, {119, "Dark Grey Gloss"},
{120, "Black"_s}, {120, "Black"},
{121, "Black Metal"_s}, {121, "Black Metal"},
{122, "Black Gloss"_s}, {122, "Black Gloss"},
{123, "Red"_s}, {123, "Red"},
{124, "Red Metal"_s}, {124, "Red Metal"},
{125, "Red Gloss"_s}, {125, "Red Gloss"},
{126, "Dark Red"_s}, {126, "Dark Red"},
{127, "Dark Red Metal"_s}, {127, "Dark Red Metal"},
{128, "Dark Red Gloss"_s}, {128, "Dark Red Gloss"},
{129, "Orange"_s}, {129, "Orange"},
{130, "Orange Metal"_s}, {130, "Orange Metal"},
{131, "Orange Gloss"_s}, {131, "Orange Gloss"},
{132, "Dark Orange"_s}, {132, "Dark Orange"},
{133, "Dark Orange Metal"_s}, {133, "Dark Orange Metal"},
{134, "Dark Orange Gloss"_s}, {134, "Dark Orange Gloss"},
{135, "Yellow"_s}, {135, "Yellow"},
{136, "Yellow Metal"_s}, {136, "Yellow Metal"},
{137, "Yellow Gloss"_s}, {137, "Yellow Gloss"},
{138, "Brown"_s}, {138, "Brown"},
{139, "Brown Metal"_s}, {139, "Brown Metal"},
{140, "Brown Gloss"_s}, {140, "Brown Gloss"},
{141, "Dark Brown"_s}, {141, "Dark Brown"},
{142, "Dark Brown Metal"_s}, {142, "Dark Brown Metal"},
{143, "Dark Brown Gloss"_s}, {143, "Dark Brown Gloss"},
{144, "Leafgreen"_s}, {144, "Leafgreen"},
{145, "Leafgreen Metal"_s}, {145, "Leafgreen Metal"},
{146, "Leafgreen Gloss"_s}, {146, "Leafgreen Gloss"},
{147, "Military Green"_s}, {147, "Military Green"},
{148, "Military Green Metal"_s}, {148, "Military Green Metal"},
{149, "Military Green Gloss"_s}, {149, "Military Green Gloss"},
{150, "Green"_s}, {150, "Green"},
{151, "Green Metal"_s}, {151, "Green Metal"},
{152, "Green Gloss"_s}, {152, "Green Gloss"},
{153, "Dark Green"_s}, {153, "Dark Green"},
{154, "Dark Green Metal"_s}, {154, "Dark Green Metal"},
{155, "Dark Green Gloss"_s}, {155, "Dark Green Gloss"},
{156, "Teal"_s}, {156, "Teal"},
{157, "Teal Metal"_s}, {157, "Teal Metal"},
{158, "Teal Gloss"_s}, {158, "Teal Gloss"},
{159, "Cyan"_s}, {159, "Cyan"},
{160, "Cyan Metal"_s}, {160, "Cyan Metal"},
{161, "Cyan Gloss"_s}, {161, "Cyan Gloss"},
{162, "Blue"_s}, {162, "Blue"},
{163, "Blue Metal"_s}, {163, "Blue Metal"},
{164, "Blue Gloss"_s}, {164, "Blue Gloss"},
{165, "Blue Sky"_s}, {165, "Blue Sky"},
{166, "Blue Sky Metal"_s}, {166, "Blue Sky Metal"},
{167, "Blue Sky Gloss"_s}, {167, "Blue Sky Gloss"},
{168, "Dark Blue"_s}, {168, "Dark Blue"},
{169, "Dark Blue Metal"_s}, {169, "Dark Blue Metal"},
{170, "Dark Blue Gloss"_s}, {170, "Dark Blue Gloss"},
{171, "Purple"_s}, {171, "Purple"},
{172, "Purple Metal"_s}, {172, "Purple Metal"},
{173, "Purple Gloss"_s}, {173, "Purple Gloss"},
{174, "Dark Purple"_s}, {174, "Dark Purple"},
{175, "Dark Purple Metal"_s}, {175, "Dark Purple Metal"},
{176, "Dark Purple Gloss"_s}, {176, "Dark Purple Gloss"},
{177, "Pink"_s}, {177, "Pink"},
{178, "Pink Metal"_s}, {178, "Pink Metal"},
{179, "Pink Gloss"_s}, {179, "Pink Gloss"},
{180, "Rosy Brown"_s}, {180, "Rosy Brown"},
{181, "Rosy Brown Metal"_s}, {181, "Rosy Brown Metal"},
{182, "Rosy Brown Gloss"_s}, {182, "Rosy Brown Gloss"},
{183, "Ivory"_s}, {183, "Ivory"},
{184, "Ivory Metal"_s}, {184, "Ivory Metal"},
{185, "Ivory Gloss"_s}, {185, "Ivory Gloss"},
{186, "Slate Brown"_s}, {186, "Slate Brown"},
{187, "Slate Brown Metal"_s}, {187, "Slate Brown Metal"},
{188, "Slate Brown Gloss"_s}, {188, "Slate Brown Gloss"},
{189, "Slate Green"_s}, {189, "Slate Green"},
{190, "Slate Green Metal"_s}, {190, "Slate Green Metal"},
{191, "Slate Green Gloss"_s}, {191, "Slate Green Gloss"},
{192, "Slate Blue"_s}, {192, "Slate Blue"},
{193, "Slate Blue Metal"_s}, {193, "Slate Blue Metal"},
{194, "Slate Blue Gloss"_s}, {194, "Slate Blue Gloss"},
{195, "Slate Purple"_s}, {195, "Slate Purple"},
{196, "Slate Purple Metal"_s}, {196, "Slate Purple Metal"},
{197, "Slate Purple Gloss"_s}, {197, "Slate Purple Gloss"},
{198, "White Glow"_s}, {198, "White Glow"},
{199, "White Radiance"_s}, {199, "White Radiance"},
{200, "Red Glow"_s}, {200, "Red Glow"},
{201, "Red Radiance"_s}, {201, "Red Radiance"},
{202, "Orange Glow"_s}, {202, "Orange Glow"},
{203, "Orange Radiance"_s}, {203, "Orange Radiance"},
{204, "Yellow Glow"_s}, {204, "Yellow Glow"},
{205, "Yellow Radiance"_s}, {205, "Yellow Radiance"},
{206, "Leafgreen Glow"_s}, {206, "Leafgreen Glow"},
{207, "Leafgreen Radiance"_s}, {207, "Leafgreen Radiance"},
{208, "Green Glow"_s}, {208, "Green Glow"},
{209, "Green Radiance"_s}, {209, "Green Radiance"},
{210, "Teal Glow"_s}, {210, "Teal Glow"},
{211, "Teal Radiance"_s}, {211, "Teal Radiance"},
{212, "Cyan Glow"_s}, {212, "Cyan Glow"},
{213, "Cyan Radiance"_s}, {213, "Cyan Radiance"},
{214, "Blue Glow"_s}, {214, "Blue Glow"},
{215, "Blue Radiance"_s}, {215, "Blue Radiance"},
{216, "Purple Glow"_s}, {216, "Purple Glow"},
{217, "Purple Radiance"_s}, {217, "Purple Radiance"},
{218, "Pink Glow"_s}, {218, "Pink Glow"},
{219, "Pink Radiance"_s}, {219, "Pink Radiance"},
{220, "Grey Camo"_s}, {220, "Grey Camo"},
{221, "Dark Grey Camo"_s}, {221, "Dark Grey Camo"},
{222, "Green Camo"_s}, {222, "Green Camo"},
{223, "Dark Green Camo"_s}, {223, "Dark Green Camo"},
{224, "Brown Camo"_s}, {224, "Brown Camo"},
{225, "Dark Brown Camo"_s}, {225, "Dark Brown Camo"},
{226, "Blue Camo"_s}, {226, "Blue Camo"},
{227, "Dark Blue Camo"_s}, {227, "Dark Blue Camo"},
} }
#endif #endif
; ;

View File

@ -1,433 +0,0 @@
#pragma once
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <map>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Types.h>
using namespace Corrade;
using namespace Magnum;
using namespace Containers::Literals;
// region Melee
static const std::map<Int, Containers::StringView> melee_grips {
{0, "Combat Grip (1H)"_s},
{1, "Knuckle Guard Grip (1H)"_s},
{2, "Dual Guard Grip (1H)"_s},
{3, "Sepal Grip (1H)"_s},
{4, "Warrior Grip (1H)"_s},
{5, "Guardian Grip (1H)"_s},
{6, "Knight Guard Grip (1H)"_s},
{7, "Saber Guard Grip (1H)"_s},
{100, "Combat Side Grip (1H)"_s},
{101, "Hollowed Side Grip (1H)"_s},
{102, "Pulled Back Side Grip (1H)"_s},
{103, "Plated Side Grip (1H)"_s},
{104, "Locked Side Grip (1H)"_s},
{105, "Longpoint Side Grip (1H)"_s},
{200, "Combat Dual Grip (1H)"_s},
{201, "Hollowed Dual Grip (1H)"_s},
{202, "Plated Dual Grip (1H)"_s},
{400, "Combat Twin Grip (1H)"_s},
{401, "Sepal Twin Grip (1H)"_s},
{402, "Hollowed Twin Grip (1H)"_s},
{403, "Knuckle Guard Twin Grip (1H)"_s},
{404, "Arched Twin Grip (1H)"_s},
{1000, "Combat Knuckle (R/L)"_s},
{1001, "Battle Fist (R/L)"_s},
{1002, "Guard Knuckle (R/L)"_s},
{2000, "Combat Polearm (2H)"_s},
{2001, "Dual Guard Polearm (2H)"_s},
{2002, "Sepal Polearm (2H)"_s},
{2003, "Fin Polearm (2H)"_s},
{2004, "Arched Polearm (2H)"_s},
{2100, "Combat Side Polearm (2H)"_s},
{2101, "Plated Side Polearm (2H)"_s},
{2102, "Locked Side Polearm (2H)"_s},
{2103, "Fin Side Polearm (2H)"_s},
{2200, "Combat Dual Polearm (2H)"_s},
{2400, "Combat Twin Blade (2H)"_s},
{2401, "Guard Twin Blade (2H)"_s},
{2402, "Sepal Twin Blade (2H)"_s},
{2403, "Fin Twin Blade (2H)"_s},
{2404, "Arched Twin Blade (2H)"_s},
};
static const std::map<Int, Containers::StringView> melee_assaulters {
{0, "Long Metal Blade"_s},
{1, "Long Assault Blade"_s},
{2, "Long Fin Blade"_s},
{3, "Long Double Blades"_s},
{4, "Long Straight Blade"_s},
{5, "Long Faceted Blade"_s},
{6, "Long Interlocked Blade"_s},
{7, "Long Frontbreak Blade"_s},
{8, "Long Encased Blade"_s},
{9, "Long Flat Gouger"_s},
{10, "Long Curved Blade"_s},
{11, "Long Broad Blade"_s},
{20, "Long Combat Edge"_s},
{21, "Long Attached Edge"_s},
{40, "Katana Blade"_s},
{41, "Custom Katana Blade"_s},
{60, "Energy Blade (Motion)"_s},
{61, "Powered Blade"_s},
{100, "Short Metal Blade"_s},
{101, "Short Assault Blade"_s},
{102, "Short Fin Blade"_s},
{120, "Short Combat Edge"_s},
{160, "Short Energy Blade (Motion)"_s},
{161, "Short Powered Blade"_s},
{180, "Triclaw"_s},
{181, "Straight Triclaw"_s},
{182, "Griphold Claw"_s},
{183, "Energy Claw"_s},
{184, "Openhold Claw"_s},
{185, "Hooktusk Claw"_s},
{200, "Bracer"_s},
{201, "Custom Bracer"_s},
{210, "Expanded Bracer"_s},
{211, "Expanded Custom Bracer"_s},
{300, "Heavy Smasher"_s},
{301, "Heavy Basher"_s},
{302, "Heavy Torch Mace"_s},
{400, "Light Smasher"_s},
{401, "Light Basher"_s},
{402, "Light Torch Mace"_s},
{420, "War Hammer"_s},
{421, "Great Hammer"_s},
{422, "Spiked Hammer"_s},
{423, "Broadhead Hammer"_s},
{440, "Morning Star"_s},
{441, "Spike Ball"_s},
{500, "Combat Lance"_s},
{501, "Gouger Lance"_s},
{510, "Piercer"_s},
{600, "Short Combat Lance"_s},
{605, "Short Combat Drill (Motion)"_s},
{610, "Short Piercer"_s},
{700, "Combat Axe"_s},
{701, "Custom Combat Axe"_s},
{702, "Piercing Axe"_s},
{703, "Frontbreak Axe"_s},
{704, "Maiming Axe"_s},
{705, "Delta Axe"_s},
{800, "Combat Scythe"_s},
{801, "Reaper Blade"_s},
{802, "Clawtooth Scythe"_s},
{803, "Wingpoint Scythe"_s},
{804, "Snakebone Scythe"_s},
{900, "Short Combat Scythe"_s},
{901, "Short Reaper Blade"_s},
{902, "Short Clawtooth Scythe"_s},
{903, "Short Wingpoint Scythe"_s},
{904, "Short Snakebone Scythe"_s},
};
// endregion
// region Shields
static const std::map<Int, Containers::StringView> shield_handles {
{0, "Balanced Handle"_s},
{1, "Expanded Handle"_s},
{2, "Lowguard Handle"_s},
{3, "Longblocker Handle"_s},
{4, "Winged Handle"_s},
{5, "Stopper Handle"_s},
{6, "Layered Handle"_s},
{7, "Riotguard Handle"_s},
{8, "Blitz Handle"_s},
{9, "Foldable Handle"_s},
{10, "Board Handle"_s},
{11, "Knight Handle"_s},
{12, "Cargwall Handle"_s},
{100, "Buckler Handle"_s},
{101, "Star Handle"_s},
};
static const std::map<Int, Containers::StringView> shield_shells {
{0, "Balanced Shell"_s},
{1, "Compass Shell"_s},
{2, "Uppoint Shell"_s},
{3, "Pointed Shell"_s},
{4, "Padded Shell"_s},
{5, "Pincer Shell"_s},
{6, "Fang Shell"_s},
{7, "Holder Shell"_s},
{8, "Composite Shell"_s},
{9, "Mechanical Shell"_s},
{10, "Layered Shell"_s},
{11, "Parted Shell"_s},
{12, "Tapst Shell"_s},
{13, "Sidloc Shell"_s},
{100, "V-Cross Shell"_s},
};
// endregion
// region Bullet Shooters
static const std::map<Int, Containers::StringView> bshooter_triggers {
{0, "BL-Combat Trigger (1H)"_s},
{1, "Light Machine Trigger (1H)"_s},
{2, "Tactical Trigger (1H)"_s},
{3, "Compact Trigger (1H)"_s},
{4, "Longhold Trigger (1H)"_s},
{5, "Downhold Trigger (1H)"_s},
{6, "Cellblock Trigger (1H)"_s},
{99, "Base Trigger (1H)"_s},
{100, "BL-Machine Trigger (2H)"_s},
{101, "BL-Short Trigger (2H)"_s},
{102, "Shielded Trigger (2H)"_s},
{103, "Platedframe Trigger (2H)"_s},
{104, "Sidebox Trigger (2H) (Motion)"_s},
{199, "2H Base Trigger (2H)"_s},
};
static const std::map<Int, Containers::StringView> bshooter_barrels {
{0, "BL-Combat Barrel (1 shot)"_s},
{1, "Shock Absorb Barrel (1 shot) (Motion)"_s},
{2, "Muzzlemod Barrel (1 shot)"_s},
{3, "Triangular Barrel (1 shot)"_s},
{4, "Recoilblock Barrel (1 shot) (Motion)"_s},
{97, "Short S Base Barrel (1 shot)"_s},
{98, "Medium S Base Barrel (1 shot)"_s},
{99, "Long S Base Barrel (1 shot)"_s},
{100, "Six-Barrel Gatling (Auto) (Motion)"_s},
{101, "Modded Six-Barrel Gatling (Auto) (Motion)"_s},
{102, "Four-Barrel Gatling (Auto) (Motion)"_s},
{103, "Retro Style Gatling (Auto) (Motion)"_s},
{197, "Short G Base Barrel (Auto)"_s},
{198, "Medium G Base Barrel (Auto)"_s},
{199, "Long G Base Barrel (Auto)"_s},
{200, "Blast Barrel (Spread)"_s},
{201, "Wideblast Barrel (Spread) (Motion)"_s},
{202, "Pelleter Barrel (Spread) (Motion)"_s},
{203, "Lockhold Barrel (Spread) (Motion)"_s},
{297, "Short B Base Barrel (Spread)"_s},
{298, "Medium B Base Barrel (Spread)"_s},
{299, "Long B Base Barrel (Spread)"_s},
{300, "Propulsive Barrel (Detonate)"_s},
{301, "Roundbox Barrel (Detonate)"_s},
{302, "ShieldDet Barrel (Detonate)"_s},
{303, "RecoilDet Barrel (Detonate) (Motion)"_s},
{397, "Short D Base Barrel (Detonate)"_s},
{398, "Medium D Base Barrel (Detonate)"_s},
{399, "Long D Base Barrel (Detonate)"_s},
};
// endregion
//region Energy Shooters
static const std::map<Int, Containers::StringView> eshooter_triggers {
{0, "EN-Rifle Trigger (1H)"_s},
{1, "Underarm Trigger (1H)"_s},
{2, "EN-Inverted Trigger (1H)"_s},
{3, "EN-Submachine Trigger (1H) (Motion)"_s},
{4, "EN-Needler Trigger (1H)"_s},
{5, "Angular Trigger (1H)"_s},
{6, "Exposed Trigger (1H)"_s},
{99, "Base EnTrigger (1H)"_s},
{100, "EN-Combat Trigger (2H)"_s},
{101, "EN-Alternate Trigger (2H)"_s},
{102, "Framed Trigger (2H) (Motion)"_s},
{103, "Stabilised Trigger (2H)"_s},
{104, "EN-Heavy Trigger (2H)"_s},
{199, "2H Base EnTrigger (2H)"_s},
};
static const std::map<Int, Containers::StringView> eshooter_busters {
{0, "EN-Combat Buster (1 shot)"_s},
{1, "Delta Cycler (1 shot) (Motion)"_s},
{2, "EN-Longbarrel Buster (1 shot)"_s},
{3, "Kinetic Buster (1 shot) (Motion)"_s},
{97, "Short S Base Buster (1 shot)"_s},
{98, "Medium S Base Buster (1 shot)"_s},
{99, "Long S Base Buster (1 shot)"_s},
{100, "EN-Rifle Buster (Auto)"_s},
{101, "EN-Focus Buster (Auto)"_s},
{102, "Machinist Buster (Auto)"_s},
{103, "EN-Precision Buster (Auto) (Motion)"_s},
{197, "Short A Base Buster (Auto)"_s},
{198, "Medium A Base Buster (Auto)"_s},
{199, "Long A Base Buster (Auto)"_s},
{200, "Railcharge Buster (Ray) (Motion)"_s},
{201, "Clawcharge Buster (Ray)"_s},
{202, "Twizelcharge Buster (Ray)"_s},
{203, "Deltacharge Buster (Ray)"_s},
{297, "Short R Base Buster (Ray)"_s},
{298, "Medium R Base Buster (Ray)"_s},
{299, "Long R Base Buster (Ray)"_s},
{300, "Subsonic Buster (Wave)"_s},
{301, "Amplifier Buster (Wave) (Motion)"_s},
{302, "Cyclonwave Buster (Wave)"_s},
{303, "Warhorn Buster (Wave) (Motion)"_s},
{397, "Short W Base Buster (Wave)"_s},
{398, "Medium W Base Buster (Wave)"_s},
{399, "Long W Base Buster (Wave)"_s},
};
// endregion
// region Bullet Launchers
static const std::map<Int, Containers::StringView> blauncher_pods {
{0, "BL-Delta Pack Launcher (Missile x12)"_s},
{1, "BL-Twin Pack Launcher (Missile x12)"_s},
{2, "Detector Launcher (Missile x12)"_s},
{3, "BL-Triplet Pack Launcher (Missile x12)"_s},
{4, "Shielded Launcher (Missile x12)"_s},
{99, "H Base Pod (Missile x12)"_s},
{100, "Warhead Pod (Nuke x2)"_s},
{101, "Warhead Launcher (Nuke x2)"_s},
{102, "Triangular Warhead Pod (Nuke x2)"_s},
{103, "Expanded Warhead Pod (Nuke x2)"_s},
{104, "Shielded Warhead Pod (Nuke x2)"_s},
{199, "N Base Pod (Nuke x2)"_s},
{200, "Widepack Launcher (Salvo x24)"_s},
{201, "Covered Launcher (Salvo x24)"_s},
{202, "Double Delta Launcher (Salvo x24)"_s},
{203, "Hexagonal Launcher (Salvo x24)"_s},
{204, "Shielded Six Launcher (Salvo x24)"_s},
{299, "S Base Pod (Salvo x24)"_s},
{300, "Sentinel Cluster Pod (Cluster x40)"_s},
{301, "Pincer Cluster Pod (Cluster x40)"_s},
{302, "Elliptical Cluster Pod (Cluster x40)"_s},
{303, "Sawed Cluster Pod (Cluster x40)"_s},
{304, "Pentagonal Cluster Pod (Cluster x40)"_s},
{399, "C Base Pod (Cluster x40)"_s},
};
static const std::map<Int, Containers::StringView> blauncher_projectiles {
{0, "Flathead Missile"_s},
{1, "Warhead Missile"_s},
{2, "Pointhead Missile"_s},
{3, "Marker Missile"_s},
{4, "ArB Missile"_s},
};
// endregion
// region Energy Launchers
static const std::map<Int, Containers::StringView> elauncher_generators {
{0, "Fly Unit"_s},
{1, "Assault Unit (Motion)"_s},
{2, "Falcon Unit"_s},
{3, "Drake Unit (Motion)"_s},
{4, "Kingfisher Unit"_s},
{5, "Tri-Edge Unit"_s},
{6, "Flatline Unit"_s},
{7, "Boost Unit"_s},
{8, "Sparrow Unit"_s},
{9, "Guarded Unit"_s},
{10, "Sailtail Unit"_s},
{11, "Tri-Covered Unit"_s},
{12, "Pointy Unit"_s},
{13, "Scope-Like Unit"_s},
{14, "Rotating Unit (Motion)"_s},
{15, "Clamper Unit"_s},
{16, "Quadsat Unit"_s},
{17, "Squ-Rotating Unit (Motion)"_s},
{18, "Bloom Unit"_s},
{19, "Edge-Rotating Unit (Motion)"_s},
{20, "Shipend Unit"_s},
{21, "Revwing Unit"_s},
{22, "Viper Unit"_s},
{23, "EX Unit"_s},
{24, "Aery Unit"_s},
{25, "Carrier Unit"_s},
{26, "Compartment Unit"_s},
{27, "Flatedge Unit"_s},
{99, "Base Generator"},
};
static const std::map<Int, Containers::StringView> elauncher_pods {
{0, "EN-Dual Claw Launcher (Echo) (Motion)"_s},
{1, "EN-Assault Launcher (Echo)"_s},
{2, "EN-Tactical Launcher (Echo)"_s},
{3, "EN-Force Focus Launcher (Echo) (Motion)"_s},
{4, "EN-Needler Launcher (Echo)"_s},
{5, "Spark Launcher (Echo)"_s},
{6, "Pinpoint Launcher (Echo)"_s},
{99, "E Base EPod (Echo)"_s},
{100, "Raystream Launcher (Beam)"_s},
{101, "Perpetum Launcher (Beam)"_s},
{102, "Scorcher Launcher (Beam)"_s},
{103, "Concentrator Launcher (Beam)"_s},
{104, "Crosshair Launcher (Beam)"_s},
{105, "Powerlined Launcher (Beam)"_s},
{106, "Attached Launcher (Beam)"_s},
{199, "B Base EPod (Beam)"_s},
{200, "Hilt Launcher (Slash) (Motion)"_s},
{201, "Underangle Launcher (Slash)"_s},
{202, "Crossblade Launcher (Slash)"_s},
{203, "Deltablade Launcher (Slash) (Motion)"_s},
{204, "Spike Launcher (Slash)"_s},
{205, "Tri-Pronged Launcher (Slash) (Motion)"_s},
{206, "Heavyblade Launcher (Slash)"_s},
{299, "S Base EPod (Slash)"_s},
{300, "Covering Launcher (Photon)"_s},
{301, "Boxhead Launcher (Photon)"_s},
{302, "Stabilised Launcher (Photon)"_s},
{303, "Flatline Launcher (Photon)"_s},
{304, "Shelled Launcher (Photon)"_s},
{305, "Widearm Launcher (Photon)"_s},
{306, "Wingspan Launcher (Photon)"_s},
{399, "P Base EPod (Photon)"_s},
};
// endregion

View File

@ -15,10 +15,10 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifdef c #ifdef c
c(Melee, "enuWeaponTypes::NewEnumerator0"_s, "Melee weapon"_s) c(Melee, "enuWeaponTypes::NewEnumerator0", "Melee weapon")
c(BulletShooter, "enuWeaponTypes::NewEnumerator1"_s, "Bullet shooter"_s) c(BulletShooter, "enuWeaponTypes::NewEnumerator1", "Bullet shooter")
c(EnergyShooter, "enuWeaponTypes::NewEnumerator2"_s, "Energy shooter"_s) c(EnergyShooter, "enuWeaponTypes::NewEnumerator2", "Energy shooter")
c(BulletLauncher, "enuWeaponTypes::NewEnumerator3"_s, "Bullet launcher"_s) c(BulletLauncher, "enuWeaponTypes::NewEnumerator3", "Bullet launcher")
c(EnergyLauncher, "enuWeaponTypes::NewEnumerator4"_s, "Energy launcher"_s) c(EnergyLauncher, "enuWeaponTypes::NewEnumerator4", "Energy launcher")
c(Shield, "enuWeaponTypes::NewEnumerator5"_s, "Shield"_s) c(Shield, "enuWeaponTypes::NewEnumerator5", "Shield")
#endif #endif

View File

@ -16,6 +16,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StaticArray.h> #include <Corrade/Containers/StaticArray.h>
@ -28,9 +30,44 @@ using namespace Corrade;
using namespace Magnum; using namespace Magnum;
enum class ArmourSlot { enum class ArmourSlot {
#define c(enumerator, enumstr, name) enumerator, Face = 0,
#include "../Maps/ArmourSlots.hpp" UpperHead = 1,
#undef c LowerHead = 2,
Neck = 3,
UpperBody = 4,
MiddleBody = 5,
LowerBody = 6,
FrontWaist = 7,
LeftFrontSkirt = 8,
RightFrontSkirt = 9,
LeftSideSkirt = 10,
RightSideSkirt = 11,
LeftBackSkirt = 12,
RightBackSkirt = 13,
BackWaist = 14,
LeftShoulder = 15,
RightShoulder = 16,
LeftUpperArm = 17,
RightUpperArm = 18,
LeftElbow = 19,
RightElbow = 20,
LeftLowerArm = 21,
RightLowerArm = 22,
Backpack = 23,
LeftHand = 24,
RightHand = 25,
LeftUpperLeg = 26,
RightUpperLeg = 27,
LeftKnee = 28,
RightKnee = 29,
LeftLowerLeg = 30,
RightLowerLeg = 31,
LeftAnkle = 32,
RightAnkle = 33,
LeftHeel = 34,
RightHeel = 35,
LeftFoot = 36,
RightFoot = 37,
}; };
struct ArmourPart { struct ArmourPart {

View File

@ -1,46 +0,0 @@
#pragma once
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/String.h>
#include <Magnum/Magnum.h>
#include <Magnum/Math/Vector3.h>
using namespace Corrade;
using namespace Magnum;
enum class BulletLauncherAttachmentStyle {
#define c(enumerator, enumstr) enumerator,
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
#undef c
};
enum class BulletLauncherSocket {
#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;
};

View File

@ -16,17 +16,16 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/String.h> #include <string>
#include <Magnum/Magnum.h> #include <Magnum/Magnum.h>
#include <Magnum/Math/Color.h> #include <Magnum/Math/Color.h>
#include <Magnum/Math/Vector2.h> #include <Magnum/Math/Vector2.h>
using namespace Corrade;
using namespace Magnum; using namespace Magnum;
struct CustomStyle { struct CustomStyle {
Containers::String name; std::string name;
Color4 colour{0.0f}; Color4 colour{0.0f};
Float metallic = 0.5f; Float metallic = 0.5f;
Float gloss = 0.5f; Float gloss = 0.5f;

View File

@ -16,6 +16,8 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <Magnum/Magnum.h> #include <Magnum/Magnum.h>
#include <Magnum/Math/Color.h> #include <Magnum/Math/Color.h>
#include <Magnum/Math/Vector2.h> #include <Magnum/Math/Vector2.h>

File diff suppressed because it is too large Load Diff

View File

@ -16,11 +16,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <Corrade/Containers/Optional.h> #include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/Pointer.h> #include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/StaticArray.h> #include <Corrade/Containers/StaticArray.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Magnum.h> #include <Magnum/Magnum.h>
#include <Magnum/Math/Color.h> #include <Magnum/Math/Color.h>
@ -28,7 +28,6 @@
#include <Magnum/Math/Vector3.h> #include <Magnum/Math/Vector3.h>
#include "Joints.h" #include "Joints.h"
#include "BulletLauncherAttachment.h"
#include "CustomStyle.h" #include "CustomStyle.h"
#include "Decal.h" #include "Decal.h"
#include "Accessory.h" #include "Accessory.h"
@ -49,7 +48,7 @@ class Mass {
Empty, Invalid, Valid Empty, Invalid, Valid
}; };
explicit Mass(Containers::StringView path); explicit Mass(const std::string& path);
Mass(const Mass&) = delete; Mass(const Mass&) = delete;
Mass& operator=(const Mass&) = delete; Mass& operator=(const Mass&) = delete;
@ -57,16 +56,16 @@ class Mass {
Mass(Mass&&) = default; Mass(Mass&&) = default;
Mass& operator=(Mass&&) = default; Mass& operator=(Mass&&) = default;
auto lastError() -> Containers::StringView; auto lastError() -> std::string const&;
static auto getNameFromFile(Containers::StringView path) -> Containers::Optional<Containers::String>; static auto getNameFromFile(const std::string& path) -> Containers::Optional<std::string>;
void refreshValues(); void refreshValues();
auto filename() -> Containers::StringView; auto filename() -> std::string const&;
auto name() -> Containers::StringView; auto name() -> Containers::Optional<std::string> const&;
auto setName(Containers::StringView new_name) -> bool; auto setName(std::string new_name) -> bool;
auto state() -> State; auto state() -> State;
@ -93,11 +92,6 @@ class Mass {
void getArmourParts(); void getArmourParts();
auto writeArmourPart(ArmourSlot slot) -> bool; auto writeArmourPart(ArmourSlot slot) -> bool;
auto bulletLauncherAttachmentStyle() -> BulletLauncherAttachmentStyle&;
auto bulletLauncherAttachments() -> Containers::ArrayView<BulletLauncherAttachment>;
void getBulletLauncherAttachments();
auto writeBulletLauncherAttachments() -> bool;
auto armourCustomStyles() -> Containers::ArrayView<CustomStyle>; auto armourCustomStyles() -> Containers::ArrayView<CustomStyle>;
void getArmourCustomStyles(); void getArmourCustomStyles();
auto writeArmourCustomStyle(UnsignedLong index) -> bool; auto writeArmourCustomStyle(UnsignedLong index) -> bool;
@ -141,12 +135,12 @@ class Mass {
auto architecture() -> Int&; auto architecture() -> Int&;
auto techs() -> Containers::ArrayView<Int>; auto techs() -> Containers::ArrayView<Int>;
auto account() -> Containers::StringView; auto account() -> std::string const&;
auto updateAccount(Containers::StringView new_account) -> bool; auto updateAccount(const std::string& new_account) -> bool;
private: private:
void getCustomStyles(Containers::ArrayView<CustomStyle> styles, ArrayProperty* style_array); void getCustomStyles(Containers::ArrayView<CustomStyle> styles, ArrayProperty* style_array);
auto writeCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool; auto setCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool;
void getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array); void getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array);
void writeDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array); void writeDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array);
@ -154,36 +148,38 @@ class Mass {
void getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array); void getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array);
void writeAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accs_array); void writeAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accs_array);
void getWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array); void getWeaponType(const char* prop_name, Containers::ArrayView<Weapon> weapon_array);
auto writeWeaponType(Containers::StringView prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool; auto writeWeaponType(const char* prop_name, Containers::ArrayView<Weapon> weapon_array) -> bool;
void getTuningCategory(Containers::StringView big_node_prop_name, Int& big_node_id, void getTuningCategory(const char* big_node_prop_name, Int& big_node_id,
Containers::StringView small_nodes_prop_name, Containers::ArrayView<Int> small_nodes_ids); const char* small_nodes_prop_name, Containers::ArrayView<Int> small_nodes_ids);
Containers::Optional<UESaveFile> _mass; Containers::Optional<UESaveFile> _mass;
Containers::String _lastError; std::string _lastError;
Containers::String _folder; std::string _folder;
Containers::String _filename; std::string _filename;
State _state = State::Empty; State _state = State::Empty;
bool _dirty = false; bool _dirty = false;
Containers::Optional<Containers::String> _name = Containers::NullOpt; Containers::Optional<std::string> _name = Containers::NullOpt;
struct { struct {
Joints joints{}; Joints joints{};
Containers::StaticArray<4, Int> styles{ValueInit}; Containers::StaticArray<4, Int> styles{ValueInit};
Color4 eyeFlare{0.0f}; Color4 eyeFlare{0.0f};
Containers::StaticArray<16, CustomStyle> customStyles; Containers::StaticArray<16, CustomStyle> customStyles;
} _frame; } _frame;
struct { struct {
Containers::StaticArray<38, ArmourPart> parts; Containers::StaticArray<38, ArmourPart> parts;
Containers::StaticArray<16, CustomStyle> customStyles; Containers::StaticArray<16, CustomStyle> customStyles;
BulletLauncherAttachmentStyle blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
Containers::StaticArray<4, BulletLauncherAttachment> blAttachment;
} _armour; } _armour;
struct { struct {
@ -208,5 +204,5 @@ class Mass {
Containers::StaticArray<7, Int> techIds; Containers::StaticArray<7, Int> techIds;
} _tuning; } _tuning;
Containers::String _account; std::string _account;
}; };

View File

@ -1,433 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <algorithm>
#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 "Mass.h"
using namespace Containers::Literals;
auto Mass::armourParts() -> Containers::ArrayView<ArmourPart> {
return _armour.parts;
}
void Mass::getArmourParts() {
LOG_INFO("Getting armour parts.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
_state = State::Invalid;
return;
}
auto armour_array = unit_data->at<ArrayProperty>(MASS_ARMOUR_PARTS);
if(!armour_array) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_ARMOUR_PARTS, _filename);
_state = State::Invalid;
return;
}
if(armour_array->items.size() != _armour.parts.size()) {
LOG_ERROR_FORMAT("Armour part arrays are not of the same size. Expected {}, got {} instead.",
_armour.parts.size(), armour_array->items.size());
_state = State::Invalid;
return;
}
for(UnsignedInt i = 0; i < armour_array->items.size(); i++) {
auto part_prop = armour_array->at<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
#include "../Maps/ArmourSlots.hpp"
#undef c
{
LOG_ERROR_FORMAT("Invalid armour slot enumerator {}.", armour_slot);
_state = State::Invalid;
return;
}
part.id = part_prop->at<IntProperty>(MASS_ARMOUR_ID)->value;
auto part_styles = part_prop->at<ArrayProperty>(MASS_ARMOUR_STYLES);
if(!part_styles) {
LOG_ERROR_FORMAT("Part styles not found for part number {}.", i);
_state = State::Invalid;
return;
}
if(part_styles->items.size() != part.styles.size()) {
LOG_ERROR_FORMAT("Armour part style arrays are not of the same size. Expected {}, got {} instead.",
part.styles.size(), part_styles->items.size());
_state = State::Invalid;
return;
}
for(UnsignedInt j = 0; j < part_styles->items.size(); j++) {
part.styles[j] = part_styles->at<IntProperty>(j)->value;
}
auto decals_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_DECALS);
if(!decals_array) {
LOG_ERROR_FORMAT("Part decals not found for part number {}.", i);
_state = State::Invalid;
return;
}
part.decals = Containers::Array<Decal>{decals_array->items.size()};
getDecals(part.decals, decals_array);
auto accs_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_ACCESSORIES);
if(!accs_array) {
LOG_WARNING_FORMAT("Part accessories not found for part number {}.", i);
part.accessories = Containers::Array<Accessory>{};
continue;
}
if(part.accessories.size() != accs_array->items.size()) {
part.accessories = Containers::Array<Accessory>{accs_array->items.size()};
}
getAccessories(part.accessories, accs_array);
}
}
auto Mass::writeArmourPart(ArmourSlot slot) -> bool {
LOG_INFO_FORMAT("Writing armour part in slot {}.", static_cast<int>(slot));
auto& part = *std::find_if(_armour.parts.begin(), _armour.parts.end(), [&slot](const ArmourPart& part){ return slot == part.slot; });
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
_lastError = "Couldn't find the unit data in " + _filename + ".";
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto armour_array = unit_data->at<ArrayProperty>(MASS_ARMOUR_PARTS);
if(!armour_array) {
_lastError = "Couldn't find the armour part array in " + _filename + ".";
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
Containers::StringView slot_str = nullptr;
switch(slot) {
#define c(enumerator, strenum, name) case ArmourSlot::enumerator: \
slot_str = strenum; \
break;
#include "../Maps/ArmourSlots.hpp"
#undef c
}
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) {
break;
}
else {
part_prop = nullptr;
}
}
if(!part_prop) {
auto prefix = "Couldn't find the armour part for slot "_s;
switch(slot) {
#define c(enumerator, strenum, name) case ArmourSlot::enumerator: \
_lastError = prefix + "ArmourSlot::" #enumerator "."_s; \
break;
#include "../Maps/ArmourSlots.hpp"
#undef c
}
LOG_ERROR(_lastError);
return false;
}
part_prop->at<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 decals_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_DECALS);
writeDecals(part.decals, decals_array);
if(part.accessories.size() != 0) {
auto accs_array = part_prop->at<ArrayProperty>(MASS_ARMOUR_ACCESSORIES);
writeAccessories(part.accessories, accs_array);
}
if(!_mass->saveToFile()) {
_lastError = _mass->lastError();
return false;
}
return true;
}
auto Mass::bulletLauncherAttachmentStyle() -> BulletLauncherAttachmentStyle& {
return _armour.blAttachmentStyle;
}
auto Mass::bulletLauncherAttachments() -> Containers::ArrayView<BulletLauncherAttachment> {
return _armour.blAttachment;
}
void Mass::getBulletLauncherAttachments() {
LOG_INFO("Getting the bullet launcher attachment data.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
_state = State::Invalid;
return;
}
auto attach_style_prop = unit_data->at<ByteProperty>(MASS_BL_ATTACHMENT_STYLE);
auto attach_array = unit_data->at<ArrayProperty>(MASS_BL_ATTACHMENTS);
if(!attach_style_prop && !attach_array) {
LOG_WARNING_FORMAT("No bullet launcher attachment data found in {}.", _filename);
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
return;
}
if(attach_style_prop && !attach_array) {
LOG_WARNING_FORMAT("No bullet launcher attachments found in {}.", _filename);
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
_state = State::Invalid;
return;
}
if(attach_array->items.size() == _weapons.bulletLaunchers.size() &&
attach_array->items.size() == _armour.blAttachment.size())
{
for(UnsignedInt i = 0; i < attach_array->items.size(); i++) {
auto attachment_prop = attach_array->at<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
#include "../Maps/BulletLauncherSockets.hpp"
#undef c
{
LOG_ERROR_FORMAT("Invalid attachment socket {}.", socket);
_state = State::Invalid;
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};
}
}
if(attach_style_prop) {
Containers::StringView attach_style = attach_style_prop->enumValue;
#define c(enumerator, strenum) if(attach_style == (strenum)) { _armour.blAttachmentStyle = BulletLauncherAttachmentStyle::enumerator; } else
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
#undef c
{
LOG_ERROR_FORMAT("Invalid attachment style {}.", attach_style);
_state = State::Invalid;
}
}
else {
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::ActiveOne;
}
}
auto Mass::writeBulletLauncherAttachments() -> bool {
LOG_INFO("Writing bullet launcher attachments.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
_lastError = "No unit data in " + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto attach_style_prop = unit_data->at<ByteProperty>(MASS_BL_ATTACHMENT_STYLE);
auto attach_array = unit_data->at<ArrayProperty>(MASS_BL_ATTACHMENTS);
if(!attach_style_prop && !attach_array) {
_lastError = "No attachment properties to write to in " + _filename;
LOG_ERROR(_lastError);
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
return false;
}
if(attach_style_prop && !attach_array) {
_lastError = "Couldn't find the attachments in " + _filename;
LOG_ERROR(_lastError);
_armour.blAttachmentStyle = BulletLauncherAttachmentStyle::NotFound;
_state = State::Invalid;
return false;
}
if(attach_array->items.size() == _weapons.bulletLaunchers.size() &&
attach_array->items.size() == _armour.blAttachment.size())
{
for(UnsignedInt i = 0; i < attach_array->items.size(); i++) {
auto attachment_prop = attach_array->at<GenericStructProperty>(i);
auto& attachment = _armour.blAttachment[i];
auto& socket = attachment_prop->at<StringProperty>(MASS_BL_ATTACHMENT_SOCKET)->value;
switch(attachment.socket) {
#define c(enumerator, strenum, name) case BulletLauncherSocket::enumerator: socket = strenum; break;
#include "../Maps/BulletLauncherSockets.hpp"
#undef c
default:
_lastError = "Invalid socket type."_s;
LOG_ERROR(_lastError);
return false;
}
auto rel_loc_prop = attachment_prop->at<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();
}
}
if(!attach_style_prop) {
attach_style_prop = new 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));
}
auto& attach_style = attach_style_prop->enumValue;
switch(_armour.blAttachmentStyle) {
#define c(enumerator, strenum) case BulletLauncherAttachmentStyle::enumerator: \
attach_style = strenum; \
break;
#include "../Maps/BulletLauncherAttachmentStyles.hpp"
#undef c
default:
_lastError = "Unknown BL attachment style.";
LOG_ERROR(_lastError);
return false;
}
if(!_mass->saveToFile()) {
_lastError = _mass->lastError();
return false;
}
return true;
}
auto Mass::armourCustomStyles() -> Containers::ArrayView<CustomStyle> {
return _armour.customStyles;
}
void Mass::getArmourCustomStyles() {
LOG_INFO("Getting the custom armour styles.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
_state = State::Invalid;
return;
}
auto armour_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_ARMOUR_STYLES);
if(!armour_styles) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_CUSTOM_ARMOUR_STYLES, _filename);
_state = State::Invalid;
return;
}
if(armour_styles->items.size() != _armour.customStyles.size()) {
LOG_ERROR_FORMAT("Custom armour style arrays are not of the same size. Expected {}, got {} instead.",
_armour.customStyles.size(), armour_styles->items.size());
_state = State::Invalid;
return;
}
getCustomStyles(_armour.customStyles, armour_styles);
}
auto Mass::writeArmourCustomStyle(UnsignedLong index) -> bool {
LOG_INFO_FORMAT("Writing custom armour style {}.", index);
if(index > _armour.customStyles.size()) {
_lastError = "Style index out of range."_s;
LOG_ERROR(_lastError);
return false;
}
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
_lastError = "Couldn't find unit data in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto armour_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_ARMOUR_STYLES);
if(!armour_styles) {
_lastError = "Couldn't find armour custom styles in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
return writeCustomStyle(_armour.customStyles[index], index, armour_styles);
}

View File

@ -1,148 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "PropertyNames.h"
#include "../UESaveFile/Types/ArrayProperty.h"
#include "../UESaveFile/Types/BoolProperty.h"
#include "../UESaveFile/Types/ColourStructProperty.h"
#include "../UESaveFile/Types/FloatProperty.h"
#include "../UESaveFile/Types/GenericStructProperty.h"
#include "../UESaveFile/Types/RotatorStructProperty.h"
#include "../UESaveFile/Types/VectorStructProperty.h"
#include "../UESaveFile/Types/Vector2DStructProperty.h"
#include "../UESaveFile/Types/IntProperty.h"
#include "Mass.h"
using namespace Containers::Literals;
void Mass::getDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array) {
for(UnsignedInt i = 0; i < decal_array->items.size(); i++) {
auto decal_prop = decal_array->at<GenericStructProperty>(i);
CORRADE_INTERNAL_ASSERT(decal_prop);
auto& decal = decals[i];
decal.id = decal_prop->at<IntProperty>(MASS_DECAL_ID)->value;
auto colour_prop = decal_prop->at<ColourStructProperty>(MASS_DECAL_COLOUR);
decal.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a};
auto pos_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_POSITION);
decal.position = Vector3{pos_prop->x, pos_prop->y, pos_prop->z};
auto u_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_UAXIS);
decal.uAxis = Vector3{u_prop->x, u_prop->y, u_prop->z};
auto v_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_VAXIS);
decal.vAxis = Vector3{v_prop->x, v_prop->y, v_prop->z};
auto offset_prop = decal_prop->at<Vector2DStructProperty>(MASS_DECAL_OFFSET);
decal.offset = Vector2{offset_prop->x, offset_prop->y};
decal.scale = decal_prop->at<FloatProperty>(MASS_DECAL_SCALE)->value;
decal.rotation = decal_prop->at<FloatProperty>(MASS_DECAL_ROTATION)->value;
decal.flip = decal_prop->at<BoolProperty>(MASS_DECAL_FLIP)->value;
decal.wrap = decal_prop->at<BoolProperty>(MASS_DECAL_WRAP)->value;
}
}
void Mass::writeDecals(Containers::ArrayView<Decal> decals, ArrayProperty* decal_array) {
for(UnsignedInt i = 0; i < decal_array->items.size(); i++) {
auto decal_prop = decal_array->at<GenericStructProperty>(i);
CORRADE_INTERNAL_ASSERT(decal_prop);
auto& decal = decals[i];
decal_prop->at<IntProperty>(MASS_DECAL_ID)->value = decal.id;
auto colour_prop = decal_prop->at<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<VectorStructProperty>(MASS_DECAL_POSITION);
pos_prop->x = decal.position.x();
pos_prop->y = decal.position.y();
pos_prop->z = decal.position.z();
auto u_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_UAXIS);
u_prop->x = decal.uAxis.x();
u_prop->y = decal.uAxis.y();
u_prop->z = decal.uAxis.z();
auto v_prop = decal_prop->at<VectorStructProperty>(MASS_DECAL_VAXIS);
v_prop->x = decal.vAxis.x();
v_prop->y = decal.vAxis.y();
v_prop->z = decal.vAxis.z();
auto offset_prop = decal_prop->at<Vector2DStructProperty>(MASS_DECAL_OFFSET);
offset_prop->x = decal.offset.x();
offset_prop->y = decal.offset.y();
decal_prop->at<FloatProperty>(MASS_DECAL_SCALE)->value = decal.scale;
decal_prop->at<FloatProperty>(MASS_DECAL_ROTATION)->value = decal.rotation;
decal_prop->at<BoolProperty>(MASS_DECAL_FLIP)->value = decal.flip;
decal_prop->at<BoolProperty>(MASS_DECAL_WRAP)->value = decal.wrap;
}
}
void Mass::getAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accessory_array) {
for(UnsignedInt i = 0; i < accessory_array->items.size(); i++) {
auto acc_prop = accessory_array->at<GenericStructProperty>(i);
CORRADE_INTERNAL_ASSERT(acc_prop);
auto& accessory = accessories[i];
accessory.attachIndex = acc_prop->at<IntProperty>(MASS_ACCESSORY_ATTACH_INDEX)->value;
accessory.id = acc_prop->at<IntProperty>(MASS_ACCESSORY_ID)->value;
auto acc_styles = acc_prop->at<ArrayProperty>(MASS_ACCESSORY_STYLES);
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
accessory.styles[j] = acc_styles->at<IntProperty>(j)->value;
}
auto rel_pos_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_RELPOS);
accessory.relativePosition = Vector3{rel_pos_prop->x, rel_pos_prop->y, rel_pos_prop->z};
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_OFFPOS);
accessory.relativePositionOffset = Vector3{rel_pos_offset_prop->x, rel_pos_offset_prop->y, rel_pos_offset_prop->z};
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>(MASS_ACCESSORY_RELROT);
accessory.relativeRotation = Vector3{rel_rot_prop->x, rel_rot_prop->y, rel_rot_prop->z};
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>(MASS_ACCESSORY_OFFROT);
accessory.relativeRotationOffset = Vector3{rel_rot_offset_prop->x, rel_rot_offset_prop->y, rel_rot_offset_prop->z};
auto local_scale_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_SCALE);
accessory.localScale = Vector3{local_scale_prop->x, local_scale_prop->y, local_scale_prop->z};
}
}
void Mass::writeAccessories(Containers::ArrayView<Accessory> accessories, ArrayProperty* accs_array) {
for(UnsignedInt i = 0; i < accs_array->items.size(); i++) {
auto acc_prop = accs_array->at<GenericStructProperty>(i);
CORRADE_INTERNAL_ASSERT(acc_prop);
auto& accessory = accessories[i];
acc_prop->at<IntProperty>(MASS_ACCESSORY_ATTACH_INDEX)->value = accessory.attachIndex;
acc_prop->at<IntProperty>(MASS_ACCESSORY_ID)->value = accessory.id;
auto acc_styles = acc_prop->at<ArrayProperty>(MASS_ACCESSORY_STYLES);
for(UnsignedInt j = 0; j < acc_styles->items.size(); j++) {
acc_styles->at<IntProperty>(j)->value = accessory.styles[j];
}
auto rel_pos_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_RELPOS);
rel_pos_prop->x = accessory.relativePosition.x();
rel_pos_prop->y = accessory.relativePosition.y();
rel_pos_prop->z = accessory.relativePosition.z();
auto rel_pos_offset_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_OFFPOS);
rel_pos_offset_prop->x = accessory.relativePositionOffset.x();
rel_pos_offset_prop->y = accessory.relativePositionOffset.y();
rel_pos_offset_prop->z = accessory.relativePositionOffset.z();
auto rel_rot_prop = acc_prop->at<RotatorStructProperty>(MASS_ACCESSORY_RELROT);
rel_rot_prop->x = accessory.relativeRotation.x();
rel_rot_prop->y = accessory.relativeRotation.y();
rel_rot_prop->z = accessory.relativeRotation.z();
auto rel_rot_offset_prop = acc_prop->at<RotatorStructProperty>(MASS_ACCESSORY_OFFROT);
rel_rot_offset_prop->x = accessory.relativeRotationOffset.x();
rel_rot_offset_prop->y = accessory.relativeRotationOffset.y();
rel_rot_offset_prop->z = accessory.relativeRotationOffset.z();
auto local_scale_prop = acc_prop->at<VectorStructProperty>(MASS_ACCESSORY_SCALE);
local_scale_prop->x = accessory.localScale.x();
local_scale_prop->y = accessory.localScale.y();
local_scale_prop->z = accessory.localScale.z();
}
}

View File

@ -1,391 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "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 "Mass.h"
using namespace Containers::Literals;
auto Mass::jointSliders() -> Joints& {
return _frame.joints;
}
void Mass::getJointSliders() {
LOG_INFO("Getting joint sliders.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
_state = State::Invalid;
return;
}
auto frame_prop = unit_data->at<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);
_frame.joints.neck = (length ? length->value : 0.0f);
length = frame_prop->at<FloatProperty>(MASS_JOINT_BODY);
_frame.joints.body = (length ? length->value : 0.0f);
length = frame_prop->at<FloatProperty>(MASS_JOINT_SHOULDER);
_frame.joints.shoulders = (length ? length->value : 0.0f);
length = frame_prop->at<FloatProperty>(MASS_JOINT_HIP);
_frame.joints.hips = (length ? length->value : 0.0f);
length = frame_prop->at<FloatProperty>(MASS_JOINT_ARM_UPPER);
_frame.joints.upperArms = (length ? length->value : 0.0f);
length = frame_prop->at<FloatProperty>(MASS_JOINT_ARM_LOWER);
_frame.joints.lowerArms = (length ? length->value : 0.0f);
length = frame_prop->at<FloatProperty>(MASS_JOINT_LEG_UPPER);
_frame.joints.upperLegs = (length ? length->value : 0.0f);
length = frame_prop->at<FloatProperty>(MASS_JOINT_LEG_LOWER);
_frame.joints.lowerLegs = (length ? length->value : 0.0f);
}
auto Mass::writeJointSliders() -> bool {
LOG_INFO("Writing joint sliders");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
_lastError = "No unit data in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto frame_prop = unit_data->at<GenericStructProperty>(MASS_FRAME);
if(!frame_prop) {
_lastError = "No frame data in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
Containers::Array<UnrealPropertyBase::ptr> temp;
auto length = frame_prop->atMove<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));
}
length = frame_prop->atMove<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));
}
length = frame_prop->atMove<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));
}
length = frame_prop->atMove<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));
}
length = frame_prop->atMove<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));
}
length = frame_prop->atMove<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));
}
length = frame_prop->atMove<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));
}
length = frame_prop->atMove<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, 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]));
frame_prop->properties = std::move(temp);
if(!_mass->saveToFile()) {
_lastError = _mass->lastError();
return false;
}
return true;
}
auto Mass::frameStyles() -> Containers::ArrayView<Int> {
return _frame.styles;
}
void Mass::getFrameStyles() {
LOG_INFO("Getting frame styles.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
_state = State::Invalid;
return;
}
auto frame_prop = unit_data->at<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);
if(!frame_styles) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_FRAME_STYLES, _filename);
_state = State::Invalid;
return;
}
if(frame_styles->items.size() != _frame.styles.size()) {
LOG_ERROR_FORMAT("Frame style arrays are not of the same size. Expected {}, got {} instead.",
_frame.styles.size(), frame_styles->items.size());
_state = State::Invalid;
return;
}
for(UnsignedInt i = 0; i < frame_styles->items.size(); i++) {
_frame.styles[i] = frame_styles->at<IntProperty>(i)->value;
}
}
auto Mass::writeFrameStyles() -> bool {
LOG_INFO("Writing frame styles.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
_lastError = "No unit data in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto frame = unit_data->at<GenericStructProperty>(MASS_FRAME);
if(!frame) {
_lastError = "No frame data in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto frame_styles = frame->at<ArrayProperty>(MASS_FRAME_STYLES);
if(!frame_styles) {
_lastError = "No frame styles in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
for(UnsignedInt i = 0; i < frame_styles->items.size(); i++) {
frame_styles->at<IntProperty>(i)->value = _frame.styles[i];
}
if(!_mass->saveToFile()) {
_lastError = _mass->lastError();
return false;
}
return true;
}
auto Mass::eyeFlareColour() -> Color4& {
return _frame.eyeFlare;
}
void Mass::getEyeFlareColour() {
LOG_INFO("Getting the eye flare colour.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
_state = State::Invalid;
return;
}
auto frame_prop = unit_data->at<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);
if(!eye_flare_prop) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_EYE_FLARE, _filename);
_state = State::Invalid;
return;
}
_frame.eyeFlare = Color4{eye_flare_prop->r, eye_flare_prop->g, eye_flare_prop->b, eye_flare_prop->a};
}
auto Mass::writeEyeFlareColour() -> bool {
LOG_INFO("Writing the eye flare colour.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
_lastError = "No unit data in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto frame = unit_data->at<GenericStructProperty>(MASS_FRAME);
if(!frame) {
_lastError = "No frame data in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto eye_flare_prop = frame->at<ColourStructProperty>(MASS_EYE_FLARE);
if(!eye_flare_prop) {
_lastError = "No eye flare property in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
eye_flare_prop->r = _frame.eyeFlare.r();
eye_flare_prop->g = _frame.eyeFlare.g();
eye_flare_prop->b = _frame.eyeFlare.b();
eye_flare_prop->a = _frame.eyeFlare.a();
if(!_mass->saveToFile()) {
_lastError = _mass->lastError();
return false;
}
return true;
}
auto Mass::frameCustomStyles() -> Containers::ArrayView<CustomStyle> {
return _frame.customStyles;
}
void Mass::getFrameCustomStyles() {
LOG_INFO("Getting the frame's custom styles.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
_state = State::Invalid;
return;
}
auto frame_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_FRAME_STYLES);
if(!frame_styles) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_CUSTOM_FRAME_STYLES, _filename);
_state = State::Invalid;
return;
}
if(frame_styles->items.size() != _frame.customStyles.size()) {
LOG_ERROR_FORMAT("Frame custom style arrays are not of the same size. Expected {}, got {} instead.",
_frame.customStyles.size(), frame_styles->items.size());
_state = State::Invalid;
return;
}
getCustomStyles(_frame.customStyles, frame_styles);
}
auto Mass::writeFrameCustomStyle(UnsignedLong index) -> bool {
LOG_INFO_FORMAT("Writing frame custom style number {}.", index);
if(index > _frame.customStyles.size()) {
_lastError = "Style index out of range."_s;
LOG_ERROR(_lastError);
return false;
}
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
_lastError = "No unit data in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto frame_styles = unit_data->at<ArrayProperty>(MASS_CUSTOM_FRAME_STYLES);
if(!frame_styles) {
_lastError = "No frame styles in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
return writeCustomStyle(_frame.customStyles[index], index, frame_styles);
}

View File

@ -1,145 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "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 "../UESaveFile/Types/StringProperty.h"
#include "Mass.h"
using namespace Containers::Literals;
auto Mass::globalStyles() -> Containers::ArrayView<CustomStyle> {
return _globalStyles;
}
void Mass::getGlobalStyles() {
LOG_INFO("Getting global styles.");
auto unit_data = _mass->at<GenericStructProperty>(MASS_UNIT_DATA);
if(!unit_data) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", MASS_UNIT_DATA, _filename);
_state = State::Invalid;
return;
}
auto global_styles = unit_data->at<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);
}
auto Mass::writeGlobalStyle(UnsignedLong index) -> bool {
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<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<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, ArrayProperty* style_array) {
for(UnsignedInt i = 0; i < style_array->items.size(); i++) {
auto style_prop = style_array->at<GenericStructProperty>(i);
auto& style = styles[i];
style.name = style_prop->at<StringProperty>(MASS_STYLE_NAME)->value;
auto colour_prop = style_prop->at<ColourStructProperty>(MASS_STYLE_COLOUR);
style.colour = Color4{colour_prop->r, colour_prop->g, colour_prop->b, colour_prop->a};
style.metallic = style_prop->at<FloatProperty>(MASS_STYLE_METALLIC)->value;
style.gloss = style_prop->at<FloatProperty>(MASS_STYLE_GLOSS)->value;
style.glow = colour_prop->a != 0.0f;
style.patternId = style_prop->at<IntProperty>(MASS_STYLE_PATTERN_ID)->value;
style.opacity = style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OPACITY)->value;
style.offset = Vector2{
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OFFSETX)->value,
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OFFSETY)->value
};
style.rotation = style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_ROTATION)->value;
style.scale = style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_SCALE)->value;
}
}
auto Mass::writeCustomStyle(const CustomStyle& style, UnsignedLong index, ArrayProperty* style_array) -> bool {
if(!style_array) {
_lastError = "style_array is null."_s;
LOG_ERROR(_lastError);
return false;
}
auto style_prop = style_array->at<GenericStructProperty>(index);
if(!style_prop) {
_lastError = "Style index is out of range in "_s + _filename;
LOG_ERROR(_lastError);
return false;
}
style_prop->at<StringProperty>(MASS_STYLE_NAME)->value = style.name;
auto colour_prop = style_prop->at<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<FloatProperty>(MASS_STYLE_METALLIC)->value = style.metallic;
style_prop->at<FloatProperty>(MASS_STYLE_GLOSS)->value = style.gloss;
style_prop->at<IntProperty>(MASS_STYLE_PATTERN_ID)->value = style.patternId;
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OPACITY)->value = style.opacity;
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OFFSETX)->value = style.offset.x();
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_OFFSETY)->value = style.offset.y();
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_ROTATION)->value = style.rotation;
style_prop->at<FloatProperty>(MASS_STYLE_PATTERN_SCALE)->value = style.scale;
if(!_mass->saveToFile()) {
_lastError = _mass->lastError();
return false;
}
return true;
}

View File

@ -1,360 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "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 "Mass.h"
using namespace Containers::Literals;
auto Mass::meleeWeapons() -> Containers::ArrayView<Weapon> {
return _weapons.melee;
}
void Mass::getMeleeWeapons() {
LOG_INFO("Getting melee weapons.");
getWeaponType(MASS_WEAPONS_MELEE, _weapons.melee);
}
auto Mass::writeMeleeWeapons() -> bool {
LOG_INFO("Writing melee weapons.");
return writeWeaponType(MASS_WEAPONS_MELEE, _weapons.melee);
}
auto Mass::shields() -> Containers::ArrayView<Weapon> {
return _weapons.shields;
}
void Mass::getShields() {
LOG_INFO("Getting shields.");
getWeaponType(MASS_WEAPONS_SHIELD, _weapons.shields);
}
auto Mass::writeShields() -> bool {
LOG_INFO("Writing shields.");
return writeWeaponType(MASS_WEAPONS_SHIELD, _weapons.shields);
}
auto Mass::bulletShooters() -> Containers::ArrayView<Weapon> {
return _weapons.bulletShooters;
}
void Mass::getBulletShooters() {
LOG_INFO("Getting bullet shooters.");
getWeaponType(MASS_WEAPONS_BSHOOTER, _weapons.bulletShooters);
}
auto Mass::writeBulletShooters() -> bool {
LOG_INFO("Writing bullet shooters.");
return writeWeaponType(MASS_WEAPONS_BSHOOTER, _weapons.bulletShooters);
}
auto Mass::energyShooters() -> Containers::ArrayView<Weapon> {
return _weapons.energyShooters;
}
void Mass::getEnergyShooters() {
LOG_INFO("Getting energy shooters.");
getWeaponType(MASS_WEAPONS_ESHOOTER, _weapons.energyShooters);
}
auto Mass::writeEnergyShooters() -> bool {
LOG_INFO("Writing energy shooters.");
return writeWeaponType(MASS_WEAPONS_ESHOOTER, _weapons.energyShooters);
}
auto Mass::bulletLaunchers() -> Containers::ArrayView<Weapon> {
return _weapons.bulletLaunchers;
}
void Mass::getBulletLaunchers() {
LOG_INFO("Getting bullet launchers.");
getWeaponType(MASS_WEAPONS_BLAUNCHER, _weapons.bulletLaunchers);
}
auto Mass::writeBulletLaunchers() -> bool {
LOG_INFO("Writing bullet launchers.");
return writeWeaponType(MASS_WEAPONS_BLAUNCHER, _weapons.bulletLaunchers);
}
auto Mass::energyLaunchers() -> Containers::ArrayView<Weapon> {
return _weapons.energyLaunchers;
}
void Mass::getEnergyLaunchers() {
LOG_INFO("Getting energy launchers.");
getWeaponType(MASS_WEAPONS_ELAUNCHER, _weapons.energyLaunchers);
}
auto Mass::writeEnergyLaunchers() -> bool {
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);
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);
if(!prop) {
LOG_ERROR_FORMAT("Couldn't find {} in {}.", prop_name, _filename);
_state = State::Invalid;
return;
}
if(prop->items.size() != weapon_array.size()) {
LOG_ERROR_FORMAT("Weapon arrays are not of the same size. Expected {}, got {} instead.",
weapon_array.size(), prop->items.size());
_state = State::Invalid;
return;
}
for(UnsignedInt i = 0; i < weapon_array.size(); i++) {
auto weapon_prop = prop->at<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
#include "../Maps/WeaponTypes.hpp"
#undef c
{
LOG_ERROR_FORMAT("Invalid weapon type {} in {}.", weapon_type, _filename);
_state = State::Invalid;
return;
}
auto parts_prop = weapon_prop->at<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);
auto& part = weapon.parts[j];
part.id = part_prop->at<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_decals = part_prop->at<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);
if(!part_accs) {
part.accessories = Containers::Array<Accessory>{0};
continue;
}
if(part_accs->items.size() != part.accessories.size()) {
part.accessories = Containers::Array<Accessory>{part_accs->items.size()};
}
getAccessories(part.accessories, part_accs);
}
auto custom_styles = weapon_prop->at<ArrayProperty>(MASS_CUSTOM_WEAPON_STYLES);
if(!custom_styles) {
LOG_ERROR_FORMAT("Can't find weapon custom styles in {}", _filename);
_state = State::Invalid;
return;
}
if(custom_styles->items.size() != weapon.customStyles.size()) {
LOG_ERROR_FORMAT("Custom weapon style arrays are not of the same size. Expected {}, got {} instead.",
weapon.customStyles.size(), custom_styles->items.size());
_state = State::Invalid;
return;
}
getCustomStyles(weapon.customStyles, custom_styles);
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
#include "../Maps/DamageTypes.hpp"
#undef c
{
LOG_ERROR_FORMAT("Invalid damage type {} in {}.", damage_type, _filename);
_state = State::Invalid;
return;
}
weapon.dualWield = weapon_prop->at<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
#include "../Maps/EffectColourModes.hpp"
#undef c
{
LOG_ERROR_FORMAT("Invalid effect colour mode {} in {}.", effect_colour_mode, _filename);
_state = State::Invalid;
return;
}
auto effect_colour = weapon_prop->at<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);
if(!unit_data) {
_lastError = "No unit data in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
auto prop = unit_data->at<ArrayProperty>(prop_name);
if(!prop) {
_lastError = prop_name + " not found in "_s + _filename;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
if(prop->items.size() != weapon_array.size()) {
_lastError = Utility::format("Weapon arrays are not of the same size. Expected {}, got {} instead.",
weapon_array.size(), prop->items.size());
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
for(UnsignedInt i = 0; i < weapon_array.size(); i++) {
auto weapon_prop = prop->at<GenericStructProperty>(i);
auto& weapon = weapon_array[i];
weapon_prop->at<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;
#include "../Maps/WeaponTypes.hpp"
#undef c
default:
_lastError = Utility::format("Invalid weapon type at index {}.", i);
LOG_ERROR(_lastError);
return false;
}
auto parts_prop = weapon_prop->at<ArrayProperty>(MASS_WEAPON_ELEMENT);
if(parts_prop->items.size() != weapon.parts.size()) {
_lastError = Utility::format("Weapon part arrays are not of the same size. Expected {}, got {} instead.",
weapon.parts.size(), parts_prop->items.size());
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
for(UnsignedInt j = 0; j < parts_prop->items.size(); j++) {
auto part_prop = parts_prop->at<GenericStructProperty>(j);
auto& part = weapon.parts[j];
part_prop->at<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_decals = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_DECALS);
writeDecals(part.decals, part_decals);
auto part_accs = part_prop->at<ArrayProperty>(MASS_WEAPON_PART_ACCESSORIES);
if(!part_accs) {
continue;
}
if(part_accs->items.size() != part.accessories.size()) {
_lastError = Utility::format("Part accessory arrays are not of the same size. Expected {}, got {} instead.",
part.accessories.size(), part_accs->items.size());
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
writeAccessories(part.accessories, part_accs);
}
auto custom_styles = weapon_prop->at<ArrayProperty>(MASS_CUSTOM_WEAPON_STYLES);
if(!custom_styles) {
_lastError = "No custom styles found for weapon."_s;
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
if(custom_styles->items.size() != weapon.customStyles.size()) {
_lastError = Utility::format("Custom style arrays are not of the same size. Expected {}, got {} instead.",
weapon.customStyles.size(), custom_styles->items.size());
LOG_ERROR(_lastError);
_state = State::Invalid;
return false;
}
for(UnsignedInt j = 0; j < weapon.customStyles.size(); j++) {
writeCustomStyle(weapon.customStyles[j], j, custom_styles);
}
weapon_prop->at<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;
#include "../Maps/DamageTypes.hpp"
#undef c
default:
_lastError = Utility::format("Invalid damage type at index {}.", i);
LOG_ERROR(_lastError);
return false;
}
weapon_prop->at<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; \
break;
#include "../Maps/EffectColourModes.hpp"
#undef c
default:
_lastError = Utility::format("Invalid damage type at index {}.", i);
LOG_ERROR(_lastError);
return false;
}
auto effect_colour = weapon_prop->at<ColourStructProperty>(MASS_WEAPON_COLOUR_EFX);
effect_colour->r = weapon.effectColour.r();
effect_colour->g = weapon.effectColour.g();
effect_colour->b = weapon.effectColour.b();
effect_colour->a = weapon.effectColour.a();
}
if(!_mass->saveToFile()) {
_lastError = _mass->lastError();
return false;
}
return true;
}

View File

@ -1,104 +0,0 @@
#pragma once
#define MASS_UNIT_DATA "UnitData"
#define MASS_NAME "Name_45_A037C5D54E53456407BDF091344529BB"
#define MASS_ACCOUNT "Account"
#define MASS_GLOBAL_STYLES "GlobalStyles_57_6A681C114035241F7BDAAE9B43A8BF1B"
// Frame stuff
#define MASS_FRAME "Frame_3_F92B0F6A44A15088AF7F41B9FF290653"
#define MASS_JOINT_NECK "NeckLength_6_ED6AF79849C27CD1A9D523A09E2BFE58"
#define MASS_JOINT_BODY "BodyLength_7_C16287754CBA96C93BAE36A5C154996A"
#define MASS_JOINT_SHOULDER "ShoulderLength_8_220EDF304F1C1226F0D8D39117FB3883"
#define MASS_JOINT_ARM_UPPER "ArmUpperLength_10_249FDA3E4F3B399E7B9E5C9B7C765EAE"
#define MASS_JOINT_ARM_LOWER "ArmLowerLength_12_ACD0F02745C28882619376926292FB36"
#define MASS_JOINT_HIP "HipLength_14_02AEEEAC4376087B9C51F0AA7CC92818"
#define MASS_JOINT_LEG_UPPER "LegUpperLength_16_A7C4C71249A3776F7A543D96819C0C61"
#define MASS_JOINT_LEG_LOWER "LegLowerLength_18_D2DF39964EA0F2A2129D0491B08A032F"
#define MASS_FRAME_STYLES "Styles_32_00A3B3284B37F1E7819458844A20EB48"
#define MASS_EYE_FLARE "EyeFlareColor_36_AF79999C40FCA0E88A2F9A84488A38CA"
#define MASS_CUSTOM_FRAME_STYLES "FrameStyle_44_04A44C9440363CCEC5443D98BFAF22AA"
// Armour stuff
#define MASS_ARMOUR_PARTS "Armor_10_12E266C44116DDAF57E99ABB575A4B3C"
#define MASS_ARMOUR_SLOT "Slot_3_408BA56F4C9605C7E805CF91B642249C"
#define MASS_ARMOUR_ID "ID_5_ACD101864D3481DE96EDACACC09BDD25"
#define MASS_ARMOUR_STYLES "Styles_47_3E31870441DFD7DB8BEE5C85C26B365B"
#define MASS_ARMOUR_DECALS "Decals_42_F358794A4F18497970F56BA9627D3603"
#define MASS_ARMOUR_ACCESSORIES "Accessories_52_D902DD4241FA0050C2529596255153F3"
#define MASS_CUSTOM_ARMOUR_STYLES "ArmorStyle_42_E2F6AC3647788CB366BD469B3B7E899E"
// Weapon stuff
#define MASS_WEAPONS_MELEE "WeaponCC_22_0BBEC58C4A0EA1DB9E037B9339EE26A7"
#define MASS_WEAPONS_SHIELD "Shield_53_839BFD7945481BAEA3E43A9C5CA8E92E"
#define MASS_WEAPONS_BSHOOTER "WeaponBS_35_6EF6E0104FD7A138DF47F88CB57A83ED"
#define MASS_WEAPONS_ESHOOTER "WeaponES_37_1A295D544528623880A0B1AC2C7DEE99"
#define MASS_WEAPONS_BLAUNCHER "WeaponBL_36_5FD7C41E4613A75B44AB0E90B362846E"
#define MASS_WEAPONS_ELAUNCHER "WeaponEL_38_9D23F3884ACA15902C9E6CA6E4995995"
#define MASS_WEAPON_NAME "Name_13_7BF0D31F4E50C50C47231BB36A485D92"
#define MASS_WEAPON_TYPE "Type_2_35ABA8C3406F8D9BBF14A89CD6BCE976"
#define MASS_WEAPON_ELEMENT "Element_6_8E4617CC4B2C1F1490435599784EC6E0"
#define MASS_CUSTOM_WEAPON_STYLES "Styles_10_8C3C82444B986AD7A99595AD4985912D"
#define MASS_WEAPON_ATTACH "Attach_15_D00AABBD4AD6A04778D56D81E51927B3"
#define MASS_WEAPON_DAMAGE_TYPE "DamageType_18_E1FFA53540591A9087EC698117A65C83"
#define MASS_WEAPON_DUAL_WIELD "DualWield_20_B2EB2CEA4A6A233DC7575996B6DD1222"
#define MASS_WEAPON_COLOUR_EFX_MODE "ColorEfxMode_24_D254BCF943E852BF9ADB8AAA8FD80014"
#define MASS_WEAPON_COLOUR_EFX "ColorEfx_26_D921B62946C493E487455A831F4520AC"
// Weapon part stuff
#define MASS_WEAPON_PART_ID "ID_2_A74D75434308158E5926178822DD28EE"
#define MASS_WEAPON_PART_STYLES "Styles_17_994C97C34A90667BE5B716BFD0B97588"
#define MASS_WEAPON_PART_DECALS "Decals_13_8B81112B453D7230C0CDE982185E14F1"
#define MASS_WEAPON_PART_ACCESSORIES "Accessories_21_3878DE8B4ED0EA0DB725E98BCDC20E0C"
// BL attachment stuff
#define MASS_BL_ATTACHMENT_STYLE "WeaponBLAttachmentStyle_65_5943FCE8406F18D2C3F69285EB23A699"
#define MASS_BL_ATTACHMENTS "WeaponBLAttachment_61_442D08F547510A4CEE1501BBAF297BA0"
#define MASS_BL_ATTACHMENT_SOCKET "Socket_9_B9DBF30D4A1F0032A2BE2F8B342B35A9"
#define MASS_BL_ATTACHMENT_RELLOC "RelativeLocation_10_2F6E75DF4C40622658340E9A22D38B02"
#define MASS_BL_ATTACHMENT_OFFLOC "OffsetLocation_11_F42B3DA3436948FF85752DB33722382F"
#define MASS_BL_ATTACHMENT_RELROT "RelativeRotation_12_578140464621245132CFF2A2AD85E735"
#define MASS_BL_ATTACHMENT_OFFROT "OffsetRotation_13_B5980BCD47905D842D1490A1A520B064"
#define MASS_BL_ATTACHMENT_RELSCALE "RelativeScale_16_37BC80EF42699F79533F7AA7B3094E38"
// Style stuff
#define MASS_STYLE_NAME "Name_27_1532115A46EF2B2FA283908DF561A86B"
#define MASS_STYLE_COLOUR "Color_5_F0D383DF40474C9464AE48A0984A212E"
#define MASS_STYLE_METALLIC "Metallic_10_0A4CD1E4482CBF41CA61D0A856DE90B9"
#define MASS_STYLE_GLOSS "Gloss_11_9769599842CC275A401C4282A236E240"
#define MASS_STYLE_PATTERN_ID "PatternID_14_516DB85641DAF8ECFD2920BE2BDF1311"
#define MASS_STYLE_PATTERN_OPACITY "Opacity_30_53BD060B4DFCA1C92302D6A0F7831131"
#define MASS_STYLE_PATTERN_OFFSETX "OffsetX_23_70FC2E814C64BBB82452748D2AF9CD48"
#define MASS_STYLE_PATTERN_OFFSETY "OffsetY_24_5E1F866C4C054D9B2EE337ADC180C17F"
#define MASS_STYLE_PATTERN_ROTATION "Rotation_25_EC2DFAD84AD0A6BD3FA841ACD52EDD6D"
#define MASS_STYLE_PATTERN_SCALE "Scale_26_19DF0708409262183E1247B317137671"
// Decal stuff
#define MASS_DECAL_ID "ID_3_694C0B35404D8A3168AEC89026BC8CF9"
#define MASS_DECAL_COLOUR "Color_8_1B0B9D2B43DA6AAB9FA549B374D3E606"
#define MASS_DECAL_POSITION "Position_41_022C8FE84E1AAFE587261E88F2C72250"
#define MASS_DECAL_UAXIS "UAxis_37_EBEB715F45491AECACCC07A1AE4646D1"
#define MASS_DECAL_VAXIS "VAxis_39_C31EB2664EE202CAECFBBB84100B5E35"
#define MASS_DECAL_OFFSET "Offset_29_B02BBBB74FC60F5EDBEBAB8020738020"
#define MASS_DECAL_SCALE "Scale_32_959D1C2747AFD8D62808468235CBBA40"
#define MASS_DECAL_ROTATION "Rotation_27_12D7C314493D203D5C2326A03C5F910F"
#define MASS_DECAL_FLIP "Flip_35_CECCFB184CCD9412BD93FE9A8B656BE1"
#define MASS_DECAL_WRAP "Wrap_43_A7C68CDF4A92AF2ECDA53F953EE7CA62"
// Accessory stuff
#define MASS_ACCESSORY_ATTACH_INDEX "AttachIndex_2_4AFCF6024E4BA7426C6B9F80B8179D20"
#define MASS_ACCESSORY_ID "ID_4_5757B32647BAE263266259B8A7DFFFC1"
#define MASS_ACCESSORY_STYLES "Styles_7_91DEB0F24E24D13FC9472882C11D0DFD"
#define MASS_ACCESSORY_RELPOS "RelativePosition_14_BE8FB2A94074F34B3EDA6683B227D3A1"
#define MASS_ACCESSORY_OFFPOS "RelativePositionOffset_15_98FD0CE74E44BBAFC2D46FB4CA4E0ED6"
#define MASS_ACCESSORY_RELROT "RelativeRotation_20_C78C73274E6E78E7878F8C98ECA342C0"
#define MASS_ACCESSORY_OFFROT "RelativeRotationOffset_21_E07FA0EC46728B7BA763C6861249ABAA"
#define MASS_ACCESSORY_SCALE "LocalScale_24_DC2D93A742A41A46E7E61D988F15ED53"
// Tuning stuff
#define MASS_ENGINE "Engine"
#define MASS_GEARS "Gears"
#define MASS_OS "OS"
#define MASS_MODULES "Modules"
#define MASS_ARCHITECT "Architect"
#define MASS_TECHS "Techs"

View File

@ -16,9 +16,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StaticArray.h> #include <Corrade/Containers/StaticArray.h>
#include <Corrade/Containers/String.h>
#include <Magnum/Magnum.h> #include <Magnum/Magnum.h>
#include <Magnum/Math/Color.h> #include <Magnum/Math/Color.h>
@ -29,19 +30,28 @@
using namespace Corrade; using namespace Corrade;
using namespace Magnum; using namespace Magnum;
#define c(enumerator, ...) enumerator,
enum class WeaponType { enum class WeaponType {
#include "../Maps/WeaponTypes.hpp" Melee = 0,
Shield = 5,
BulletShooter = 1,
EnergyShooter = 2,
BulletLauncher = 3,
EnergyLauncher = 4,
}; };
enum class DamageType { enum class DamageType {
#include "../Maps/DamageTypes.hpp" Physical = 0,
Piercing = 1,
Plasma = 5,
Heat = 2,
Freeze = 3,
Shock = 4,
}; };
enum class EffectColourMode { enum class EffectColourMode {
#include "../Maps/EffectColourModes.hpp" Default = 0,
Custom = 1,
}; };
#undef c
struct Weapon { struct Weapon {
Weapon() = default; Weapon() = default;
@ -52,7 +62,7 @@ struct Weapon {
Weapon(Weapon&& other) = default; Weapon(Weapon&& other) = default;
Weapon& operator=(Weapon&& other) = default; Weapon& operator=(Weapon&& other) = default;
Containers::String name; std::string name;
WeaponType type = WeaponType::Melee; WeaponType type = WeaponType::Melee;
Containers::Array<WeaponPart> parts; Containers::Array<WeaponPart> parts;
Containers::StaticArray<16, CustomStyle> customStyles{ValueInit}; Containers::StaticArray<16, CustomStyle> customStyles{ValueInit};

View File

@ -16,30 +16,36 @@
#include <algorithm> #include <algorithm>
#include <Corrade/Utility/Format.h> #include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/Path.h> #include <Corrade/Utility/FormatStl.h>
#include <Corrade/Utility/String.h>
#include "../Logger/Logger.h"
#include "MassManager.h" #include "MassManager.h"
using namespace Containers::Literals; static const std::string empty_string = "";
MassManager::MassManager(Containers::StringView save_path, Containers::StringView account, bool demo, MassManager::MassManager(const std::string& save_path, const std::string& steam_id, bool demo, const std::string& staging_dir):
Containers::StringView staging_dir): _saveDirectory{save_path},
_saveDirectory{save_path}, _account{account}, _demo{demo}, _stagingAreaDirectory{staging_dir} _steamId{steam_id},
_demo{demo},
_stagingAreaDirectory{staging_dir}
{ {
Containers::String mass_filename = ""; Containers::arrayReserve(_hangars, 32);
for(UnsignedInt i = 0; i < _hangars.size(); i++) {
mass_filename = Utility::Path::join(_saveDirectory, std::string mass_filename = "";
Utility::format("{}Unit{:.2d}{}.sav", demo ? "Demo"_s : ""_s, i, _account)); for(int i = 0; i < 32; i++) {
new(&_hangars[i]) Mass{mass_filename}; mass_filename = Utility::Directory::join(_saveDirectory, Utility::formatString("{}Unit{:.2d}{}.sav", demo ? "Demo" : "", i, _steamId));
Containers::arrayAppend(_hangars, Mass{mass_filename});
}
if(!Utility::Directory::exists(_stagingAreaDirectory)) {
Utility::Directory::mkpath(_stagingAreaDirectory);
} }
refreshStagedMasses(); refreshStagedMasses();
} }
auto MassManager::lastError() -> Containers::StringView { auto MassManager::lastError() -> std::string const& {
return _lastError; return _lastError;
} }
@ -49,53 +55,47 @@ auto MassManager::hangar(Int hangar) -> Mass& {
void MassManager::refreshHangar(Int hangar) { void MassManager::refreshHangar(Int hangar) {
if(hangar < 0 || hangar >= 32) { if(hangar < 0 || hangar >= 32) {
_lastError = "Hangar index out of range.";
LOG_ERROR(_lastError);
return; return;
} }
Containers::String mass_filename = std::string mass_filename =
Utility::Path::join(_saveDirectory, Utility::Directory::join(_saveDirectory, Utility::formatString("{}Unit{:.2d}{}.sav", _demo ? "Demo" : "", hangar, _steamId));
Utility::format("{}Unit{:.2d}{}.sav", _demo ? "Demo" : "", hangar, _account));
_hangars[hangar] = Mass{mass_filename}; _hangars[hangar] = Mass{mass_filename};
} }
auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bool { auto MassManager::importMass(const std::string& staged_fn, Int hangar) -> bool {
if(hangar < 0 || hangar >= 32) { if(hangar < 0 || hangar >= 32) {
_lastError = "Hangar index out of range."; _lastError = "Hangar out of range in MassManager::importMass()";
LOG_ERROR(_lastError);
return false; return false;
} }
auto it = _stagedMasses.find(Containers::String::nullTerminatedView(staged_fn)); auto it = _stagedMasses.find(staged_fn);
if(it == _stagedMasses.end()) { if(it == _stagedMasses.end()) {
_lastError = "Couldn't find "_s + staged_fn + " in the staged M.A.S.S.es."_s; _lastError = "Couldn't find " + staged_fn + " in the staged M.A.S.S.es.";
LOG_ERROR(_lastError);
return false; return false;
} }
Containers::String source = Utility::Path::join(_stagingAreaDirectory, staged_fn); std::string source = Utility::Directory::join(_stagingAreaDirectory, staged_fn);
Utility::Path::copy(source, source + ".tmp"_s); Utility::Directory::copy(source, source + ".tmp");
{ {
Mass mass{source + ".tmp"_s}; Mass mass{source + ".tmp"};
if(!mass.updateAccount(_account)) { if(!mass.updateAccount(_steamId)) {
_lastError = mass.lastError(); _lastError = mass.lastError();
Utility::Path::remove(source + ".tmp"_s); Utility::Directory::rm(source + ".tmp");
return false; return false;
} }
} }
Containers::String dest = Utility::Path::join(_saveDirectory, _hangars[hangar].filename()); std::string dest = Utility::Directory::join(_saveDirectory, _hangars[hangar].filename());
if(Utility::Path::exists(dest)) { if(Utility::Directory::exists(dest)) {
Utility::Path::remove(dest); Utility::Directory::rm(dest);
} }
if(!Utility::Path::move(source + ".tmp"_s, dest)) { if(!Utility::Directory::move(source + ".tmp", dest)) {
_lastError = Utility::format("Couldn't move {} to hangar {:.2d}", staged_fn, hangar + 1); _lastError = Utility::formatString("Couldn't move {} to hangar {:.2d}", staged_fn, hangar + 1);
LOG_ERROR(_lastError);
return false; return false;
} }
@ -104,24 +104,21 @@ auto MassManager::importMass(Containers::StringView staged_fn, Int hangar) -> bo
auto MassManager::exportMass(Int hangar) -> bool { auto MassManager::exportMass(Int hangar) -> bool {
if(hangar < 0 || hangar >= 32) { if(hangar < 0 || hangar >= 32) {
_lastError = "Hangar index out of range."_s; _lastError = "Hangar out of range in MassManager::exportMass()";
LOG_ERROR(_lastError);
return false; return false;
} }
if(_hangars[hangar].state() != Mass::State::Valid) { if(_hangars[hangar].state() != Mass::State::Valid) {
_lastError = Utility::format("There is no valid data to export in hangar {:.2d}", hangar + 1); _lastError = Utility::formatString("There is no valid data to export in hangar {:.2d}", hangar + 1);
LOG_ERROR(_lastError);
return false; return false;
} }
Containers::String source = Utility::Path::join(_saveDirectory, _hangars[hangar].filename()); std::string source = Utility::Directory::join(_saveDirectory, _hangars[hangar].filename());
Containers::String dest = Utility::Path::join(_stagingAreaDirectory, std::string dest = Utility::Directory::join(_stagingAreaDirectory,
Utility::format("{}_{}.sav", _hangars[hangar].name(), _account)); Utility::formatString("{}_{}.sav", *_hangars[hangar].name(), _steamId));
if(!Utility::Path::copy(source, dest)) { if(!Utility::Directory::copy(source, dest)) {
_lastError = Utility::format("Couldn't export data from hangar {:.2d} to {}", hangar, dest); _lastError = Utility::formatString("Couldn't export data from hangar {:.2d} to {}", hangar, dest);
LOG_ERROR(_lastError);
return false; return false;
} }
@ -130,36 +127,34 @@ auto MassManager::exportMass(Int hangar) -> bool {
auto MassManager::moveMass(Int source, Int destination) -> bool { auto MassManager::moveMass(Int source, Int destination) -> bool {
if(source < 0 || source >= 32) { if(source < 0 || source >= 32) {
_lastError = "Source hangar index out of range."_s; _lastError = "Source hangar out of range.";
LOG_ERROR(_lastError);
return false; return false;
} }
if(destination < 0 || destination >= 32) { if(destination < 0 || destination >= 32) {
_lastError = "Destination hangar index out of range."_s; _lastError = "Destination hangar out of range.";
LOG_ERROR(_lastError);
return false; return false;
} }
Containers::String source_file = Utility::Path::join(_saveDirectory, _hangars[source].filename()); std::string source_file = Utility::Directory::join(_saveDirectory, _hangars[source].filename());
Containers::String dest_file = Utility::Path::join(_saveDirectory, _hangars[destination].filename()); std::string dest_file = Utility::Directory::join(_saveDirectory, _hangars[destination].filename());
Mass::State dest_state = _hangars[destination].state(); Mass::State dest_state = _hangars[destination].state();
switch(dest_state) { switch(dest_state) {
case Mass::State::Empty: case Mass::State::Empty:
break; break;
case Mass::State::Invalid: case Mass::State::Invalid:
Utility::Path::remove(dest_file); Utility::Directory::rm(dest_file);
break; break;
case Mass::State::Valid: case Mass::State::Valid:
Utility::Path::move(dest_file, dest_file + ".tmp"_s); Utility::Directory::move(dest_file, dest_file + ".tmp");
break; break;
} }
Utility::Path::move(source_file, dest_file); Utility::Directory::move(source_file, dest_file);
if(dest_state == Mass::State::Valid) { if(dest_state == Mass::State::Valid) {
Utility::Path::move(dest_file + ".tmp"_s, source_file); Utility::Directory::move(dest_file + ".tmp", source_file);
} }
return true; return true;
@ -167,86 +162,51 @@ auto MassManager::moveMass(Int source, Int destination) -> bool {
auto MassManager::deleteMass(Int hangar) -> bool { auto MassManager::deleteMass(Int hangar) -> bool {
if(hangar < 0 || hangar >= 32) { if(hangar < 0 || hangar >= 32) {
_lastError = "Hangar index out of range."_s; _lastError = "Hangar out of range.";
LOG_ERROR(_lastError);
return false; return false;
} }
if(!Utility::Path::remove(Utility::Path::join(_saveDirectory, _hangars[hangar].filename()))) { if(!Utility::Directory::rm(Utility::Directory::join(_saveDirectory, _hangars[hangar].filename()))) {
_lastError = Utility::format("Deletion failed: {}", std::strerror(errno)); _lastError = Utility::formatString("Deletion failed: {}", std::strerror(errno));
LOG_ERROR(_lastError);
return false; return false;
} }
return true; return true;
} }
auto MassManager::stagedMasses() -> std::map<Containers::String, Containers::String> const& { auto MassManager::stagedMasses() -> std::map<std::string, std::string> const& {
return _stagedMasses; return _stagedMasses;
} }
void MassManager::refreshStagedMasses() { void MassManager::refreshStagedMasses() {
_stagedMasses.clear(); _stagedMasses.clear();
using Utility::Path::ListFlag; using Utility::Directory::Flag;
auto file_list = Utility::Path::list(_stagingAreaDirectory, std::vector<std::string> file_list = Utility::Directory::list(_stagingAreaDirectory, Flag::SkipSpecial|Flag::SkipDirectories|Flag::SkipDotAndDotDot);
ListFlag::SkipSpecial|ListFlag::SkipDirectories|ListFlag::SkipDotAndDotDot);
if(!file_list) { auto iter = std::remove_if(file_list.begin(), file_list.end(), [](std::string& file){
LOG_ERROR_FORMAT("{} couldn't be opened.", _stagingAreaDirectory); return !Utility::String::endsWith(file, ".sav");
return;
}
auto iter = std::remove_if(file_list->begin(), file_list->end(), [](Containers::StringView file){
return !file.hasSuffix(".sav"_s);
}); });
auto list_view = file_list->exceptSuffix(file_list->end() - iter); file_list.erase(iter, file_list.end());
LOG_INFO("Scanning for staged M.A.S.S.es..."); for(const std::string& file : file_list) {
for(Containers::StringView file : list_view) { std::string name = *Mass::getNameFromFile(Utility::Directory::join(_stagingAreaDirectory, file));
auto name = Mass::getNameFromFile(Utility::Path::join(_stagingAreaDirectory, file));
if(name) { if(!name.empty()) {
LOG_INFO_FORMAT("Found staged M.A.S.S.: {}", *name); _stagedMasses[file] = name;
_stagedMasses[file] = *name;
}
else {
LOG_WARNING_FORMAT("Skipped {}.", file);
} }
} }
} }
void MassManager::refreshStagedMass(Containers::StringView filename) { auto MassManager::deleteStagedMass(const std::string& filename) -> bool {
LOG_INFO_FORMAT("Refreshing staged unit with filename {}.", filename);
bool file_exists = Utility::Path::exists(Utility::Path::join(_stagingAreaDirectory, filename));
auto it = _stagedMasses.find(filename);
if(file_exists) {
auto name = Mass::getNameFromFile(Utility::Path::join(_stagingAreaDirectory, filename));
if(name) {
_stagedMasses[filename] = *name;
}
else if(it != _stagedMasses.cend()) {
_stagedMasses.erase(it);
}
}
else if(it != _stagedMasses.cend()) {
_stagedMasses.erase(it);
}
}
auto MassManager::deleteStagedMass(Containers::StringView filename) -> bool {
if(_stagedMasses.find(filename) == _stagedMasses.cend()) { if(_stagedMasses.find(filename) == _stagedMasses.cend()) {
_lastError = "The file "_s + filename + " couldn't be found in the list of staged M.A.S.S.es."_s; _lastError = "The file " + filename + " couldn't be found in the list of staged M.A.S.S.es.";
LOG_ERROR(_lastError);
return false; return false;
} }
if(!Utility::Path::remove(Utility::Path::join(_stagingAreaDirectory, filename))) { if(!Utility::Directory::rm(Utility::Directory::join(_stagingAreaDirectory, filename))) {
_lastError = filename + " couldn't be deleted: " + std::strerror(errno); _lastError = Utility::formatString("{} couldn't be deleted: {}", filename, std::strerror(errno));
LOG_ERROR(_lastError);
return false; return false;
} }

View File

@ -17,10 +17,9 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <map> #include <map>
#include <string>
#include <Corrade/Containers/StaticArray.h> #include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Containers/StringView.h>
#include "../Mass/Mass.h" #include "../Mass/Mass.h"
@ -28,35 +27,34 @@ using namespace Corrade;
class MassManager { class MassManager {
public: public:
MassManager(Containers::StringView save_path, Containers::StringView account, bool demo, Containers::StringView staging_dir); MassManager(const std::string& save_path, const std::string& steam_id, bool demo, const std::string& staging_dir);
auto lastError() -> Containers::StringView; auto lastError() -> std::string const&;
auto hangar(int hangar) -> Mass&; auto hangar(int hangar) -> Mass&;
void refreshHangar(int hangar); void refreshHangar(int hangar);
auto importMass(Containers::StringView staged_fn, int hangar) -> bool; auto importMass(const std::string& staged_fn, int hangar) -> bool;
auto exportMass(int hangar) -> bool; auto exportMass(int hangar) -> bool;
auto moveMass(int source, int destination) -> bool; auto moveMass(int source, int destination) -> bool;
auto deleteMass(int hangar) -> bool; auto deleteMass(int hangar) -> bool;
auto stagedMasses() -> std::map<Containers::String, Containers::String> const&; auto stagedMasses() -> std::map<std::string, std::string> const&;
void refreshStagedMasses(); void refreshStagedMasses();
void refreshStagedMass(Containers::StringView filename); auto deleteStagedMass(const std::string& filename) -> bool;
auto deleteStagedMass(Containers::StringView filename) -> bool;
private: private:
Containers::StringView _saveDirectory; const std::string& _saveDirectory;
Containers::StringView _account; const std::string& _steamId;
bool _demo; bool _demo;
Containers::String _lastError; std::string _lastError;
Containers::StaticArray<32, Mass> _hangars{NoInit}; Containers::Array<Mass> _hangars;
Containers::StringView _stagingAreaDirectory; const std::string& _stagingAreaDirectory;
std::map<Containers::String, Containers::String> _stagedMasses; std::map<std::string, std::string> _stagedMasses;
}; };

View File

@ -16,11 +16,12 @@
#include <algorithm> #include <algorithm>
#include <Corrade/Containers/Pair.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Utility/Path.h> #include <Corrade/Containers/StaticArray.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Utility/String.h>
#include "PropertyNames.h"
#include "../Logger/Logger.h"
#include "../UESaveFile/Types/ArrayProperty.h" #include "../UESaveFile/Types/ArrayProperty.h"
#include "../UESaveFile/Types/ResourceItemValue.h" #include "../UESaveFile/Types/ResourceItemValue.h"
#include "../UESaveFile/Types/IntProperty.h" #include "../UESaveFile/Types/IntProperty.h"
@ -29,36 +30,34 @@
#include "Profile.h" #include "Profile.h"
using namespace Corrade; using namespace Corrade;
using namespace Containers::Literals;
Profile::Profile(Containers::StringView path): Profile::Profile(const std::string& path):
_profile(path) _profile(path)
{ {
LOG_INFO_FORMAT("Reading profile at {}.", path); _filename = Utility::Directory::filename(path);
if(!_profile.valid()) { if(Utility::String::beginsWith(_filename, "Demo")) {
_lastError = _profile.lastError();
_valid = false;
return;
}
_filename = Utility::Path::split(path).second();
if(_filename.hasPrefix("Demo"_s)) {
_type = ProfileType::Demo; _type = ProfileType::Demo;
} }
else { else {
_type = ProfileType::FullGame; _type = ProfileType::FullGame;
} }
auto account_prop = _profile.at<StringProperty>(PROFILE_ACCOUNT); auto account_prop = _profile.at<StringProperty>("Account");
if(!account_prop) { if(!account_prop) {
_lastError = "Couldn't find an account ID in "_s + _filename; _lastError = "Couldn't find an account ID in " + _filename;
_valid = false; _valid = false;
return; return;
} }
_account = account_prop->value; _account = account_prop->value;
if(Utility::String::beginsWith(_account, "PMCSlot")) {
_version = ProfileVersion::Normal;
}
else {
_version = ProfileVersion::Legacy;
}
refreshValues(); refreshValues();
} }
@ -66,11 +65,11 @@ auto Profile::valid() const -> bool {
return _valid; return _valid;
} }
auto Profile::lastError() const -> Containers::StringView { auto Profile::lastError() const -> std::string const& {
return _lastError; return _lastError;
} }
auto Profile::filename() const -> Containers::StringView { auto Profile::filename() const -> std::string const& {
return _filename; return _filename;
} }
@ -78,94 +77,76 @@ auto Profile::type() const -> ProfileType {
return _type; return _type;
} }
auto Profile::isDemo() const -> bool { auto Profile::version() const -> ProfileVersion {
return _type == ProfileType::Demo; return _version;
} }
auto Profile::account() const -> Containers::StringView { auto Profile::account() const -> std::string const& {
return _account; return _account;
} }
void Profile::refreshValues() { void Profile::refreshValues() {
if(!_profile.reloadData()) { if(!_profile.reloadData()) {
LOG_ERROR(_profile.lastError()); _lastError = _profile.lastError();
_valid = false; _valid = false;
return; return;
} }
if(_profile.saveType() != "/Game/Core/Save/bpSaveGameProfile.bpSaveGameProfile_C"_s) { auto name_prop = _profile.at<StringProperty>("CompanyName");
LOG_ERROR_FORMAT("{} is not a valid profile save.", _filename);
_valid = false;
return;
}
LOG_INFO("Getting the company name.");
auto name_prop = _profile.at<StringProperty>(PROFILE_NAME);
if(!name_prop) { if(!name_prop) {
_lastError = "No company name in "_s + _filename; _lastError = "No company name in " + _filename;
LOG_ERROR(_lastError);
_valid = false; _valid = false;
return; return;
} }
_name = name_prop->value; _name = name_prop->value;
LOG_INFO("Getting the active frame slot."); auto prop = _profile.at<IntProperty>("ActiveFrameSlot");
auto prop = _profile.at<IntProperty>(PROFILE_ACTIVE_FRAME_SLOT);
_activeFrameSlot = prop ? prop->value : 0; _activeFrameSlot = prop ? prop->value : 0;
LOG_INFO("Getting the credits."); prop = _profile.at<IntProperty>("Credit");
prop = _profile.at<IntProperty>(PROFILE_CREDITS);
_credits = prop ? prop->value : 0; _credits = prop ? prop->value : 0;
LOG_INFO("Getting the story progress."); prop = _profile.at<IntProperty>("StoryProgress");
prop = _profile.at<IntProperty>(PROFILE_STORY_PROGRESS);
_storyProgress = prop ? prop->value : 0; _storyProgress = prop ? prop->value : 0;
LOG_INFO("Getting the last mission ID."); prop = _profile.at<IntProperty>("LastMissionID");
prop = _profile.at<IntProperty>(PROFILE_LAST_MISSION_ID);
_lastMissionId = prop ? prop->value : 0; _lastMissionId = prop ? prop->value : 0;
LOG_INFO("Getting the materials."); _verseSteel = getResource("ResourceMaterial", VerseSteel);
_verseSteel = getResource(PROFILE_MATERIAL, VerseSteel); _undinium = getResource("ResourceMaterial", Undinium);
_undinium = getResource(PROFILE_MATERIAL, Undinium); _necriumAlloy = getResource("ResourceMaterial", NecriumAlloy);
_necriumAlloy = getResource(PROFILE_MATERIAL, NecriumAlloy); _lunarite = getResource("ResourceMaterial", Lunarite);
_lunarite = getResource(PROFILE_MATERIAL, Lunarite); _asterite = getResource("ResourceMaterial", Asterite);
_asterite = getResource(PROFILE_MATERIAL, Asterite);
_halliteFragma = getResource(PROFILE_MATERIAL, HalliteFragma);
_ednil = getResource(PROFILE_MATERIAL, Ednil); _ednil = getResource("ResourceMaterial", Ednil);
_nuflalt = getResource(PROFILE_MATERIAL, Nuflalt); _nuflalt = getResource("ResourceMaterial", Nuflalt);
_aurelene = getResource(PROFILE_MATERIAL, Aurelene); _aurelene = getResource("ResourceMaterial", Aurelene);
_soldus = getResource(PROFILE_MATERIAL, Soldus); _soldus = getResource("ResourceMaterial", Soldus);
_synthesisedN = getResource(PROFILE_MATERIAL, SynthesisedN); _synthesisedN = getResource("ResourceMaterial", SynthesisedN);
_nanoc = getResource(PROFILE_MATERIAL, Nanoc);
_alcarbonite = getResource(PROFILE_MATERIAL, Alcarbonite); _alcarbonite = getResource("ResourceMaterial", Alcarbonite);
_keriphene = getResource(PROFILE_MATERIAL, Keriphene); _keriphene = getResource("ResourceMaterial", Keriphene);
_nitinolCM = getResource(PROFILE_MATERIAL, NitinolCM); _nitinolCM = getResource("ResourceMaterial", NitinolCM);
_quarkium = getResource(PROFILE_MATERIAL, Quarkium); _quarkium = getResource("ResourceMaterial", Quarkium);
_alterene = getResource(PROFILE_MATERIAL, Alterene); _alterene = getResource("ResourceMaterial", Alterene);
_cosmium = getResource(PROFILE_MATERIAL, Cosmium);
_mixedComposition = getResource(PROFILE_QUARK_DATA, MixedComposition); _mixedComposition = getResource("ResourceQuarkData", MixedComposition);
_voidResidue = getResource(PROFILE_QUARK_DATA, VoidResidue); _voidResidue = getResource("ResourceQuarkData", VoidResidue);
_muscularConstruction = getResource(PROFILE_QUARK_DATA, MuscularConstruction); _muscularConstruction = getResource("ResourceQuarkData", MuscularConstruction);
_mineralExoskeletology = getResource(PROFILE_QUARK_DATA, MineralExoskeletology); _mineralExoskeletology = getResource("ResourceQuarkData", MineralExoskeletology);
_carbonisedSkin = getResource(PROFILE_QUARK_DATA, CarbonisedSkin); _carbonisedSkin = getResource("ResourceQuarkData", CarbonisedSkin);
_isolatedVoidParticle = getResource(PROFILE_QUARK_DATA, IsolatedVoidParticle);
_valid = true; _valid = true;
} }
auto Profile::companyName() const -> Containers::StringView { auto Profile::companyName() const -> std::string const& {
return _name; return _name;
} }
auto Profile::renameCompany(Containers::StringView new_name) -> bool { auto Profile::renameCompany(const std::string& new_name) -> bool {
auto name_prop = _profile.at<StringProperty>(PROFILE_NAME); auto name_prop = _profile.at<StringProperty>("CompanyName");
if(!name_prop) { if(!name_prop) {
_lastError = "No company name in "_s + _filename; _lastError = "No company name in " + _filename;
LOG_ERROR(_lastError);
_valid = false; _valid = false;
return false; return false;
} }
@ -189,12 +170,11 @@ auto Profile::credits() const -> Int {
} }
auto Profile::setCredits(Int amount) -> bool { auto Profile::setCredits(Int amount) -> bool {
auto credits_prop = _profile.at<IntProperty>(PROFILE_CREDITS); auto credits_prop = _profile.at<IntProperty>("Credit");
if(!credits_prop) { if(!credits_prop) {
credits_prop = new IntProperty; credits_prop = new IntProperty;
credits_prop->name.emplace("Credit"_s); credits_prop->name.emplace("Credit");
credits_prop->valueLength = sizeof(Int);
_profile.appendProperty(IntProperty::ptr{credits_prop}); _profile.appendProperty(IntProperty::ptr{credits_prop});
} }
@ -213,12 +193,11 @@ auto Profile::storyProgress() const -> Int {
} }
auto Profile::setStoryProgress(Int progress) -> bool { auto Profile::setStoryProgress(Int progress) -> bool {
auto story_progress_prop = _profile.at<IntProperty>("StoryProgress"_s); auto story_progress_prop = _profile.at<IntProperty>("StoryProgress");
if(!story_progress_prop) { if(!story_progress_prop) {
story_progress_prop = new IntProperty; story_progress_prop = new IntProperty;
story_progress_prop->name.emplace("StoryProgress"_s); story_progress_prop->name.emplace("StoryProgress");
story_progress_prop->valueLength = sizeof(Int);
_profile.appendProperty(IntProperty::ptr{story_progress_prop}); _profile.appendProperty(IntProperty::ptr{story_progress_prop});
} }
@ -241,7 +220,7 @@ auto Profile::verseSteel() const -> Int {
} }
auto Profile::setVerseSteel(Int amount) -> bool { auto Profile::setVerseSteel(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, VerseSteel, amount); return setResource("ResourceMaterial", VerseSteel, amount);
} }
auto Profile::undinium() const -> Int { auto Profile::undinium() const -> Int {
@ -249,7 +228,7 @@ auto Profile::undinium() const -> Int {
} }
auto Profile::setUndinium(Int amount) -> bool { auto Profile::setUndinium(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Undinium, amount); return setResource("ResourceMaterial", Undinium, amount);
} }
auto Profile::necriumAlloy() const -> Int { auto Profile::necriumAlloy() const -> Int {
@ -257,7 +236,7 @@ auto Profile::necriumAlloy() const -> Int {
} }
auto Profile::setNecriumAlloy(Int amount) -> bool { auto Profile::setNecriumAlloy(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, NecriumAlloy, amount); return setResource("ResourceMaterial", NecriumAlloy, amount);
} }
auto Profile::lunarite() const -> Int { auto Profile::lunarite() const -> Int {
@ -265,7 +244,7 @@ auto Profile::lunarite() const -> Int {
} }
auto Profile::setLunarite(Int amount) -> bool { auto Profile::setLunarite(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Lunarite, amount); return setResource("ResourceMaterial", Lunarite, amount);
} }
auto Profile::asterite() const -> Int { auto Profile::asterite() const -> Int {
@ -273,17 +252,7 @@ auto Profile::asterite() const -> Int {
} }
auto Profile::setAsterite(Int amount) -> bool { auto Profile::setAsterite(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Asterite, amount); return setResource("ResourceMaterial", Asterite, amount);
}
Int
Profile::halliteFragma() const {
return _halliteFragma;
}
bool
Profile::setHalliteFragma(Int amount) {
return setResource(PROFILE_MATERIAL, HalliteFragma, amount);
} }
auto Profile::ednil() const -> Int { auto Profile::ednil() const -> Int {
@ -291,7 +260,7 @@ auto Profile::ednil() const -> Int {
} }
auto Profile::setEdnil(Int amount) -> bool { auto Profile::setEdnil(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Ednil, amount); return setResource("ResourceMaterial", Ednil, amount);
} }
auto Profile::nuflalt() const -> Int { auto Profile::nuflalt() const -> Int {
@ -299,7 +268,7 @@ auto Profile::nuflalt() const -> Int {
} }
auto Profile::setNuflalt(Int amount) -> bool { auto Profile::setNuflalt(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Nuflalt, amount); return setResource("ResourceMaterial", Nuflalt, amount);
} }
auto Profile::aurelene() const -> Int { auto Profile::aurelene() const -> Int {
@ -307,7 +276,7 @@ auto Profile::aurelene() const -> Int {
} }
auto Profile::setAurelene(Int amount) -> bool { auto Profile::setAurelene(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Aurelene, amount); return setResource("ResourceMaterial", Aurelene, amount);
} }
auto Profile::soldus() const -> Int { auto Profile::soldus() const -> Int {
@ -315,7 +284,7 @@ auto Profile::soldus() const -> Int {
} }
auto Profile::setSoldus(Int amount) -> bool { auto Profile::setSoldus(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Soldus, amount); return setResource("ResourceMaterial", Soldus, amount);
} }
auto Profile::synthesisedN() const -> Int { auto Profile::synthesisedN() const -> Int {
@ -323,17 +292,7 @@ auto Profile::synthesisedN() const -> Int {
} }
auto Profile::setSynthesisedN(Int amount) -> bool { auto Profile::setSynthesisedN(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, SynthesisedN, amount); return setResource("ResourceMaterial", SynthesisedN, amount);
}
Int
Profile::nanoc() const {
return _nanoc;
}
bool
Profile::setNanoc(Int amount) {
return setResource(PROFILE_MATERIAL, Nanoc, amount);
} }
auto Profile::alcarbonite() const -> Int { auto Profile::alcarbonite() const -> Int {
@ -341,7 +300,7 @@ auto Profile::alcarbonite() const -> Int {
} }
auto Profile::setAlcarbonite(Int amount) -> bool { auto Profile::setAlcarbonite(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Alcarbonite, amount); return setResource("ResourceMaterial", Alcarbonite, amount);
} }
auto Profile::keriphene() const -> Int { auto Profile::keriphene() const -> Int {
@ -349,7 +308,7 @@ auto Profile::keriphene() const -> Int {
} }
auto Profile::setKeriphene(Int amount) -> bool { auto Profile::setKeriphene(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Keriphene, amount); return setResource("ResourceMaterial", Keriphene, amount);
} }
auto Profile::nitinolCM() const -> Int { auto Profile::nitinolCM() const -> Int {
@ -357,7 +316,7 @@ auto Profile::nitinolCM() const -> Int {
} }
auto Profile::setNitinolCM(Int amount) -> bool { auto Profile::setNitinolCM(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, NitinolCM, amount); return setResource("ResourceMaterial", NitinolCM, amount);
} }
auto Profile::quarkium() const -> Int { auto Profile::quarkium() const -> Int {
@ -365,7 +324,7 @@ auto Profile::quarkium() const -> Int {
} }
auto Profile::setQuarkium(Int amount) -> bool { auto Profile::setQuarkium(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Quarkium, amount); return setResource("ResourceMaterial", Quarkium, amount);
} }
auto Profile::alterene() const -> Int { auto Profile::alterene() const -> Int {
@ -373,17 +332,7 @@ auto Profile::alterene() const -> Int {
} }
auto Profile::setAlterene(Int amount) -> bool { auto Profile::setAlterene(Int amount) -> bool {
return setResource(PROFILE_MATERIAL, Alterene, amount); return setResource("ResourceMaterial", Alterene, amount);
}
Int
Profile::cosmium() const {
return _cosmium;
}
bool
Profile::setCosmium(Int amount) {
return setResource(PROFILE_MATERIAL, Cosmium, amount);
} }
auto Profile::mixedComposition() const -> Int { auto Profile::mixedComposition() const -> Int {
@ -391,7 +340,7 @@ auto Profile::mixedComposition() const -> Int {
} }
auto Profile::setMixedComposition(Int amount) -> bool { auto Profile::setMixedComposition(Int amount) -> bool {
return setResource(PROFILE_QUARK_DATA, MixedComposition, amount); return setResource("ResourceQuarkData", MixedComposition, amount);
} }
auto Profile::voidResidue() const -> Int { auto Profile::voidResidue() const -> Int {
@ -399,7 +348,7 @@ auto Profile::voidResidue() const -> Int {
} }
auto Profile::setVoidResidue(Int amount) -> bool { auto Profile::setVoidResidue(Int amount) -> bool {
return setResource(PROFILE_QUARK_DATA, VoidResidue, amount); return setResource("ResourceQuarkData", VoidResidue, amount);
} }
auto Profile::muscularConstruction() const -> Int { auto Profile::muscularConstruction() const -> Int {
@ -407,7 +356,7 @@ auto Profile::muscularConstruction() const -> Int {
} }
auto Profile::setMuscularConstruction(Int amount) -> bool { auto Profile::setMuscularConstruction(Int amount) -> bool {
return setResource(PROFILE_QUARK_DATA, MuscularConstruction, amount); return setResource("ResourceQuarkData", MuscularConstruction, amount);
} }
auto Profile::mineralExoskeletology() const -> Int { auto Profile::mineralExoskeletology() const -> Int {
@ -415,7 +364,7 @@ auto Profile::mineralExoskeletology() const -> Int {
} }
auto Profile::setMineralExoskeletology(Int amount) -> bool { auto Profile::setMineralExoskeletology(Int amount) -> bool {
return setResource(PROFILE_QUARK_DATA, MineralExoskeletology, amount); return setResource("ResourceQuarkData", MineralExoskeletology, amount);
} }
auto Profile::carbonisedSkin() const -> Int { auto Profile::carbonisedSkin() const -> Int {
@ -423,20 +372,10 @@ auto Profile::carbonisedSkin() const -> Int {
} }
auto Profile::setCarbonisedSkin(Int amount) -> bool { auto Profile::setCarbonisedSkin(Int amount) -> bool {
return setResource(PROFILE_QUARK_DATA, CarbonisedSkin, amount); return setResource("ResourceQuarkData", CarbonisedSkin, amount);
} }
Int auto Profile::getResource(const char* container, MaterialID id) -> Int {
Profile::isolatedVoidParticle() const {
return _isolatedVoidParticle;
}
bool
Profile::setIsolatedVoidParticle(Int amount) {
return setResource(PROFILE_QUARK_DATA, IsolatedVoidParticle, amount);
}
auto Profile::getResource(Containers::StringView container, MaterialID id) -> Int {
auto mats_prop = _profile.at<ArrayProperty>(container); auto mats_prop = _profile.at<ArrayProperty>(container);
if(!mats_prop) { if(!mats_prop) {
@ -452,14 +391,13 @@ auto Profile::getResource(Containers::StringView container, MaterialID id) -> In
return it != mats_prop->items.end() ? static_cast<ResourceItemValue*>(it->get())->quantity : 0; return it != mats_prop->items.end() ? static_cast<ResourceItemValue*>(it->get())->quantity : 0;
} }
auto Profile::setResource(Containers::StringView container, MaterialID id, Int amount) -> bool { auto Profile::setResource(const char* container, MaterialID id, Int amount) -> bool {
auto mats_prop = _profile.at<ArrayProperty>(container); auto mats_prop = _profile.at<ArrayProperty>(container);
if(!mats_prop) { if(!mats_prop) {
mats_prop = new ArrayProperty; _lastError = "Couldn't find " + std::string{container} + " in " + _filename;
mats_prop->name.emplace(container); _valid = false;
mats_prop->itemType = "StructProperty"; return false;
_profile.appendProperty(ArrayProperty::ptr{mats_prop});
} }
auto predicate = [&id](UnrealPropertyBase::ptr& prop){ auto predicate = [&id](UnrealPropertyBase::ptr& prop){
@ -472,9 +410,6 @@ auto Profile::setResource(Containers::StringView container, MaterialID id, Int a
ResourceItemValue* res_prop; ResourceItemValue* res_prop;
if(it == mats_prop->items.end()) { if(it == mats_prop->items.end()) {
res_prop = new ResourceItemValue; res_prop = new ResourceItemValue;
if(mats_prop->items.isEmpty()) {
res_prop->name.emplace(container);
}
res_prop->id = id; res_prop->id = id;
ResourceItemValue::ptr prop{res_prop}; ResourceItemValue::ptr prop{res_prop};
arrayAppend(mats_prop->items, std::move(prop)); arrayAppend(mats_prop->items, std::move(prop));

View File

@ -16,8 +16,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/String.h> #include <string>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Magnum.h> #include <Magnum/Magnum.h>
@ -25,7 +24,6 @@
#include "ResourceIDs.h" #include "ResourceIDs.h"
using namespace Corrade;
using namespace Magnum; using namespace Magnum;
enum class ProfileType : UnsignedByte { enum class ProfileType : UnsignedByte {
@ -33,25 +31,31 @@ enum class ProfileType : UnsignedByte {
FullGame FullGame
}; };
enum class ProfileVersion : UnsignedByte {
Legacy, // pre-0.8
Normal // 0.8 and later
};
class Profile { class Profile {
public: public:
explicit Profile(Containers::StringView path); explicit Profile(const std::string& path);
auto valid() const -> bool; auto valid() const -> bool;
auto lastError() const -> Containers::StringView; auto lastError() const -> std::string const&;
auto filename() const -> Containers::StringView; auto filename() const -> std::string const&;
auto type() const -> ProfileType; auto type() const -> ProfileType;
auto isDemo() const -> bool;
auto account() const -> Containers::StringView; auto version() const -> ProfileVersion;
auto account() const -> std::string const&;
void refreshValues(); void refreshValues();
auto companyName() const -> Containers::StringView; auto companyName() const -> std::string const&;
auto renameCompany(Containers::StringView new_name) -> bool; auto renameCompany(const std::string& new_name) -> bool;
auto activeFrameSlot() const -> Int; auto activeFrameSlot() const -> Int;
@ -78,9 +82,6 @@ class Profile {
auto asterite() const -> Int; auto asterite() const -> Int;
auto setAsterite(Int amount) -> bool; auto setAsterite(Int amount) -> bool;
Int halliteFragma() const;
bool setHalliteFragma(Int amount);
auto ednil() const -> Int; auto ednil() const -> Int;
auto setEdnil(Int amount) -> bool; auto setEdnil(Int amount) -> bool;
@ -96,9 +97,6 @@ class Profile {
auto synthesisedN() const -> Int; auto synthesisedN() const -> Int;
auto setSynthesisedN(Int amount) -> bool; auto setSynthesisedN(Int amount) -> bool;
Int nanoc() const;
bool setNanoc(Int amount);
auto alcarbonite() const -> Int; auto alcarbonite() const -> Int;
auto setAlcarbonite(Int amount) -> bool; auto setAlcarbonite(Int amount) -> bool;
@ -114,9 +112,6 @@ class Profile {
auto alterene() const -> Int; auto alterene() const -> Int;
auto setAlterene(Int amount) -> bool; auto setAlterene(Int amount) -> bool;
Int cosmium() const;
bool setCosmium(Int amount);
auto mixedComposition() const -> Int; auto mixedComposition() const -> Int;
auto setMixedComposition(Int amount) -> bool; auto setMixedComposition(Int amount) -> bool;
@ -132,20 +127,18 @@ class Profile {
auto carbonisedSkin() const -> Int; auto carbonisedSkin() const -> Int;
auto setCarbonisedSkin(Int amount) -> bool; auto setCarbonisedSkin(Int amount) -> bool;
Int isolatedVoidParticle() const;
bool setIsolatedVoidParticle(Int amount);
private: private:
auto getResource(Containers::StringView container, MaterialID id) -> Int; auto getResource(const char* container, MaterialID id) -> Int;
auto setResource(Containers::StringView container, MaterialID id, Int amount) -> bool; auto setResource(const char* container, MaterialID id, Int amount) -> bool;
Containers::String _filename; std::string _filename;
ProfileType _type; ProfileType _type;
ProfileVersion _version;
UESaveFile _profile; UESaveFile _profile;
Containers::String _name; std::string _name;
Int _activeFrameSlot = 0; Int _activeFrameSlot = 0;
Int _credits = 0; Int _credits = 0;
Int _storyProgress = 0; Int _storyProgress = 0;
@ -156,31 +149,27 @@ class Profile {
Int _necriumAlloy = 0; Int _necriumAlloy = 0;
Int _lunarite = 0; Int _lunarite = 0;
Int _asterite = 0; Int _asterite = 0;
Int _halliteFragma = 0;
Int _ednil = 0; Int _ednil = 0;
Int _nuflalt = 0; Int _nuflalt = 0;
Int _aurelene = 0; Int _aurelene = 0;
Int _soldus = 0; Int _soldus = 0;
Int _synthesisedN = 0; Int _synthesisedN = 0;
Int _nanoc = 0;
Int _alcarbonite = 0; Int _alcarbonite = 0;
Int _keriphene = 0; Int _keriphene = 0;
Int _nitinolCM = 0; Int _nitinolCM = 0;
Int _quarkium = 0; Int _quarkium = 0;
Int _alterene = 0; Int _alterene = 0;
Int _cosmium = 0;
Int _mixedComposition = 0; Int _mixedComposition = 0;
Int _voidResidue = 0; Int _voidResidue = 0;
Int _muscularConstruction = 0; Int _muscularConstruction = 0;
Int _mineralExoskeletology = 0; Int _mineralExoskeletology = 0;
Int _carbonisedSkin = 0; Int _carbonisedSkin = 0;
Int _isolatedVoidParticle = 0;
Containers::String _account; std::string _account;
bool _valid = false; bool _valid = false;
Containers::String _lastError; std::string _lastError;
}; };

View File

@ -1,10 +0,0 @@
#pragma once
#define PROFILE_NAME "CompanyName"
#define PROFILE_ACTIVE_FRAME_SLOT "ActiveFrameSlot"
#define PROFILE_CREDITS "Credit"
#define PROFILE_STORY_PROGRESS "StoryProgress"
#define PROFILE_LAST_MISSION_ID "LastMissionID"
#define PROFILE_MATERIAL "ResourceMaterial"
#define PROFILE_QUARK_DATA "ResourceQuarkData"
#define PROFILE_ACCOUNT "Account"

View File

@ -26,26 +26,22 @@ enum MaterialID : Int {
NecriumAlloy = 0xC3502, NecriumAlloy = 0xC3502,
Lunarite = 0xC3503, Lunarite = 0xC3503,
Asterite = 0xC3504, Asterite = 0xC3504,
HalliteFragma = 0xC3505,
Ednil = 0xC350A, Ednil = 0xC350A,
Nuflalt = 0xC350B, Nuflalt = 0xC350B,
Aurelene = 0xC350C, Aurelene = 0xC350C,
Soldus = 0xC350D, Soldus = 0xC350D,
SynthesisedN = 0xC350E, SynthesisedN = 0xC350E,
Nanoc = 0xC350F,
Alcarbonite = 0xC3514, Alcarbonite = 0xC3514,
Keriphene = 0xC3515, Keriphene = 0xC3515,
NitinolCM = 0xC3516, NitinolCM = 0xC3516,
Quarkium = 0xC3517, Quarkium = 0xC3517,
Alterene = 0xC3518, Alterene = 0xC3518,
Cosmium = 0xC3519,
MixedComposition = 0xDBBA0, MixedComposition = 0xDBBA0,
VoidResidue = 0xDBBA1, VoidResidue = 0xDBBA1,
MuscularConstruction = 0xDBBA2, MuscularConstruction = 0xDBBA2,
MineralExoskeletology = 0xDBBA3, MineralExoskeletology = 0xDBBA3,
CarbonisedSkin = 0xDBBA4, CarbonisedSkin = 0xDBBA4
IsolatedVoidParticle = 0xDBBA5,
}; };

View File

@ -18,22 +18,20 @@
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <iomanip>
#include <regex>
#include <Corrade/Containers/ScopeGuard.h> #include <Corrade/Containers/ScopeGuard.h>
#include <Corrade/Containers/StaticArray.h> #include <Corrade/Containers/StaticArray.h>
#include <Corrade/Utility/Format.h> #include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/Path.h> #include <Corrade/Utility/FormatStl.h>
#include <Corrade/Utility/String.h> #include <Corrade/Utility/String.h>
#include <zip.h> #include <zip.h>
#include "../Logger/Logger.h"
#include "ProfileManager.h" #include "ProfileManager.h"
using namespace Containers::Literals; ProfileManager::ProfileManager(const std::string& save_dir, const std::string& backup_dir):
ProfileManager::ProfileManager(Containers::StringView save_dir, Containers::StringView backup_dir):
_saveDirectory{save_dir}, _saveDirectory{save_dir},
_backupsDirectory{backup_dir} _backupsDirectory{backup_dir}
{ {
@ -44,7 +42,7 @@ auto ProfileManager::ready() const -> bool {
return _ready; return _ready;
} }
auto ProfileManager::lastError() -> Containers::StringView { auto ProfileManager::lastError() -> std::string const& {
return _lastError; return _lastError;
} }
@ -53,40 +51,32 @@ auto ProfileManager::profiles() -> Containers::ArrayView<Profile> {
} }
auto ProfileManager::refreshProfiles() -> bool { auto ProfileManager::refreshProfiles() -> bool {
LOG_INFO("Refreshing profiles.");
_profiles = Containers::Array<Profile>{}; _profiles = Containers::Array<Profile>{};
using Utility::Path::ListFlag; using Utility::Directory::Flag;
auto files = Utility::Path::list(_saveDirectory, std::vector<std::string> files = Utility::Directory::list(_saveDirectory, Flag::SkipSpecial|Flag::SkipDirectories|Flag::SkipDotAndDotDot);
ListFlag::SkipSpecial|ListFlag::SkipDirectories|ListFlag::SkipDotAndDotDot);
if(!files) { auto predicate = [](const std::string& file)->bool{
_lastError = _saveDirectory + " can't be opened."; std::regex regex("(Demo)?Profile[0-9]{17}\\.sav", std::regex::nosubs);
LOG_ERROR(_lastError); std::cmatch m;
return false; return !std::regex_match(file.c_str(), m, regex);
}
auto predicate = [](Containers::StringView file)->bool{
return !((file.hasPrefix("DemoProfile") || file.hasPrefix("Profile")) && file.hasSuffix(".sav"));
}; };
auto files_view = files->exceptSuffix(files->end() - std::remove_if(files->begin(), files->end(), predicate)); files.erase(std::remove_if(files.begin(), files.end(), predicate), files.end());
for(const auto& file : files_view) { for(const std::string& file : files) {
Profile profile{Utility::Path::join(_saveDirectory, file)}; Profile profile{Utility::Directory::join(_saveDirectory, file)};
if(!profile.valid()) { if(!profile.valid()) {
LOG_WARNING_FORMAT("Profile {} is invalid: {}", file, profile.lastError()); Utility::Warning{} << "Profile" << file.c_str() << "is invalid:" << profile.lastError().c_str();
continue; continue;
} }
arrayAppend(_profiles, std::move(profile)); arrayAppend(_profiles, std::move(profile));
} }
if(_profiles.isEmpty()) { if(_profiles.empty()) {
_lastError = "No valid profiles were found."_s; _lastError = "No valid profiles were found.";
LOG_ERROR(_lastError);
return false; return false;
} }
@ -98,26 +88,25 @@ auto ProfileManager::getProfile(std::size_t index) -> Profile* {
} }
auto ProfileManager::deleteProfile(std::size_t index, bool delete_builds) -> bool { auto ProfileManager::deleteProfile(std::size_t index, bool delete_builds) -> bool {
if(!Utility::Path::remove(Utility::Path::join(_saveDirectory, _profiles[index].filename()))) { if(!Utility::Directory::rm(Utility::Directory::join(_saveDirectory, _profiles[index].filename()))) {
_lastError = Utility::format("Couldn't delete {} (filename: {}).", _lastError = Utility::formatString("Couldn't delete {} (filename: {}).",
_profiles[index].companyName(), _profiles[index].companyName(),
_profiles[index].filename()); _profiles[index].filename());
LOG_ERROR(_lastError);
refreshProfiles(); refreshProfiles();
return false; return false;
} }
if(delete_builds) { if(delete_builds) {
for(UnsignedByte i = 0; i < 32; ++i) { for(UnsignedByte i = 0; i < 32; ++i) {
auto filename = Utility::format("{}Unit{:.2d}{}.sav", std::string filename = Utility::formatString("{}Unit{:.2d}{}.sav",
_profiles[index].type() == ProfileType::Demo ? "Demo": "", _profiles[index].type() == ProfileType::Demo ? "Demo": "",
i, _profiles[index].account()); i, _profiles[index].account());
Utility::Path::remove(Utility::Path::join(_saveDirectory, filename)); Utility::Directory::rm(Utility::Directory::join(_saveDirectory, filename));
} }
} }
auto file = _profiles[index].filename(); std::string file = _profiles[index].filename();
auto it = std::remove_if(_profiles.begin(), _profiles.end(), [&file](Profile& profile){ return profile.filename() == file; }); auto it = std::remove_if(_profiles.begin(), _profiles.end(), [&file](Profile& profile){return profile.filename() == file;});
if(it != _profiles.end()) { if(it != _profiles.end()) {
arrayRemoveSuffix(_profiles, 1); arrayRemoveSuffix(_profiles, 1);
@ -129,62 +118,59 @@ auto ProfileManager::deleteProfile(std::size_t index, bool delete_builds) -> boo
auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> bool { auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> bool {
std::time_t timestamp = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); std::time_t timestamp = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::tm* time = std::localtime(&timestamp); std::tm* time = std::localtime(&timestamp);
auto& profile = _profiles[index];
auto filename = Utility::format("{}_{}{:.2d}{:.2d}_{:.2d}{:.2d}{:.2d}.backup.mbst", std::string filename = Utility::formatString("{}_{}{:.2d}{:.2d}_{:.2d}{:.2d}{:.2d}.mbprofbackup",
Utility::String::replaceAll(profile.companyName().data(), " ", "_").c_str(), Utility::String::replaceAll(_profiles[index].companyName(), " ", "_"),
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
time->tm_hour, time->tm_min, time->tm_sec); time->tm_hour, time->tm_min, time->tm_sec);
int error_code = 0; int error_code = 0;
zip_error_t error; zip_error_t error;
zip_t* zip = zip_open(Utility::Path::join(_backupsDirectory, filename).data(), ZIP_CREATE|ZIP_TRUNCATE, &error_code); zip_t* zip = zip_open(Utility::Directory::join(_backupsDirectory, filename).c_str(), ZIP_CREATE|ZIP_TRUNCATE, &error_code);
if(zip == nullptr) { if(zip == nullptr) {
zip_error_init_with_code(&error, error_code); zip_error_init_with_code(&error, error_code);
_lastError = zip_error_strerror(&error); _lastError = zip_error_strerror(&error);
LOG_ERROR(_lastError);
return false; return false;
} }
zip_source_t* profile_source = zip_source_file(zip, Utility::Path::toNativeSeparators(Utility::Path::join(_saveDirectory, profile.filename())).data(), 0, 0); zip_source_t* profile_source = zip_source_file(zip, Utility::Directory::toNativeSeparators(Utility::Directory::join(_saveDirectory, _profiles[index].filename())).c_str(), 0, 0);
if(profile_source == nullptr) { if(profile_source == nullptr) {
_lastError = zip_strerror(zip); _lastError = zip_strerror(zip);
LOG_ERROR(_lastError);
zip_source_free(profile_source); zip_source_free(profile_source);
return false; return false;
} }
if(zip_file_add(zip, profile.filename().data(), profile_source, ZIP_FL_ENC_UTF_8) == -1) { if(zip_file_add(zip, _profiles[index].filename().c_str(), profile_source, ZIP_FL_ENC_UTF_8) == -1) {
_lastError = zip_strerror(zip); _lastError = zip_strerror(zip);
LOG_ERROR(_lastError);
zip_source_free(profile_source); zip_source_free(profile_source);
return false; return false;
} }
auto comment = Utility::format("{}|{}|{}-{:.2d}-{:.2d}-{:.2d}-{:.2d}-{:.2d}", std::string comment = Utility::String::join({_profiles[index].companyName(),
profile.companyName(), _profiles[index].type() == ProfileType::Demo ? "demo" : "full",
profile.isDemo() ? "demo"_s : "full"_s, Utility::formatString("{}-{:.2d}-{:.2d}-{:.2d}-{:.2d}-{:.2d}",
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
time->tm_hour, time->tm_min, time->tm_sec); time->tm_hour, time->tm_min, time->tm_sec)
zip_set_archive_comment(zip, comment.data(), comment.size()); }, '|');
zip_set_archive_comment(zip, comment.c_str(), comment.length());
if(backup_builds) { if(backup_builds) {
for(UnsignedByte i = 0; i < 32; ++i) { for(UnsignedByte i = 0; i < 32; ++i) {
auto build_filename = Utility::format("{}Unit{:.2d}{}.sav", std::string build_filename = Utility::formatString("{}Unit{:.2d}{}.sav",
profile.isDemo() ? "Demo"_s : ""_s, i, _profiles[index].type() == ProfileType::Demo ? "Demo": "",
profile.account()); i, _profiles[index].account());
if(!Utility::Path::exists(Utility::Path::join(_saveDirectory, build_filename))) { if(!Utility::Directory::exists(Utility::Directory::join(_saveDirectory, build_filename))) {
continue; continue;
} }
zip_source_t* build_source = zip_source_file(zip, Utility::Path::toNativeSeparators(Utility::Path::join(_saveDirectory, build_filename)).data(), 0, 0); zip_source_t* build_source = zip_source_file(zip, Utility::Directory::toNativeSeparators(Utility::Directory::join(_saveDirectory, build_filename)).c_str(), 0, 0);
if(build_source == nullptr) { if(build_source == nullptr) {
zip_source_free(build_source); zip_source_free(build_source);
continue; continue;
} }
if(zip_file_add(zip, build_filename.data(), build_source, ZIP_FL_ENC_UTF_8) == -1) { if(zip_file_add(zip, build_filename.c_str(), build_source, ZIP_FL_ENC_UTF_8) == -1) {
zip_source_free(build_source); zip_source_free(build_source);
continue; continue;
} }
@ -193,7 +179,6 @@ auto ProfileManager::backupProfile(std::size_t index, bool backup_builds) -> boo
if(zip_close(zip) == -1) { if(zip_close(zip) == -1) {
_lastError = zip_strerror(zip); _lastError = zip_strerror(zip);
LOG_ERROR(_lastError);
return false; return false;
} }
@ -209,76 +194,69 @@ auto ProfileManager::backups() -> Containers::ArrayView<Backup> {
void ProfileManager::refreshBackups() { void ProfileManager::refreshBackups() {
_backups = Containers::Array<Backup>{}; _backups = Containers::Array<Backup>{};
using Utility::Path::ListFlag; using Utility::Directory::Flag;
auto files = Utility::Path::list(_backupsDirectory, std::vector<std::string> files = Utility::Directory::list(_backupsDirectory, Flag::SkipSpecial|Flag::SkipDirectories|Flag::SkipDotAndDotDot);
ListFlag::SkipSpecial|ListFlag::SkipDirectories|ListFlag::SkipDotAndDotDot);
if(!files) { auto predicate = [](const std::string& file)->bool{
_lastError = _backupsDirectory + " can't be opened."; return !Utility::String::endsWith(file, ".mbprofbackup");
LOG_ERROR(_lastError);
return;
}
auto predicate = [](Containers::StringView file)->bool{
return !(file.hasSuffix(".mbprofbackup"_s) || file.hasSuffix(".backup.mbst"));
}; };
auto files_view = files->exceptSuffix(files->end() - std::remove_if(files->begin(), files->end(), predicate)); files.erase(std::remove_if(files.begin(), files.end(), predicate), files.end());
int error_code = 0; int error_code = 0;
zip_t* zip = nullptr; zip_t* zip = nullptr;
for(Containers::StringView file : files_view) { for(const std::string& file : files) {
Backup backup; Backup backup;
backup.filename = file; backup.filename = file;
zip = zip_open(Utility::Path::join(_backupsDirectory, file).data(), ZIP_RDONLY, &error_code); zip = zip_open(Utility::Directory::join(_backupsDirectory, file).c_str(), ZIP_RDONLY, &error_code);
if(zip == nullptr) { if(zip == nullptr) {
continue; continue;
} }
Containers::ScopeGuard guard{zip, zip_close}; Containers::ScopeGuard guard{zip, zip_close};
Long num_entries = zip_get_num_entries(zip, ZIP_FL_UNCHANGED);
if(num_entries == 0) {
continue;
}
int comment_length; int comment_length;
Containers::StringView comment = zip_get_archive_comment(zip, &comment_length, ZIP_FL_UNCHANGED); const char* comment = zip_get_archive_comment(zip, &comment_length, ZIP_FL_UNCHANGED);
if(comment == nullptr) { if(comment == nullptr) {
continue; continue;
} }
auto info = comment.split('|'); auto info = Utility::String::split(comment, '|');
if(info.size() != 3) { if(info.size() != 3) {
continue; continue;
} }
backup.company = info[0]; backup.company = info.at(0);
if(info[1].hasPrefix("full")) { if(info.at(1) == "full") {
backup.type = ProfileType::FullGame; backup.type = ProfileType::FullGame;
} }
else if(info[1].hasPrefix("demo")) { else if(info.at(1) == "demo") {
backup.type = ProfileType::Demo; backup.type = ProfileType::Demo;
} }
else { else {
continue; continue;
} }
auto ts = info[2].split('-'); auto ts = Utility::String::split(info.at(2), '-');
if(ts.size() != 6) { if(ts.size() != 6) {
continue; continue;
} }
backup.timestamp.year = std::strtol(ts[0].data(), nullptr, 10); backup.timestamp.year = std::stoi(ts.at(0));
backup.timestamp.month = std::strtol(ts[1].data(), nullptr, 10); backup.timestamp.month = std::stoi(ts.at(1));
backup.timestamp.day = std::strtol(ts[2].data(), nullptr, 10); backup.timestamp.day = std::stoi(ts.at(2));
backup.timestamp.hour = std::strtol(ts[3].data(), nullptr, 10); backup.timestamp.hour = std::stoi(ts.at(3));
backup.timestamp.minute = std::strtol(ts[4].data(), nullptr, 10); backup.timestamp.minute = std::stoi(ts.at(4));
backup.timestamp.second = std::strtol(ts[5].data(), nullptr, 10); backup.timestamp.second = std::stoi(ts.at(5));
Long num_entries = zip_get_num_entries(zip, ZIP_FL_UNCHANGED);
if(num_entries == 0) {
continue;
}
arrayReserve(backup.includedFiles, num_entries); arrayReserve(backup.includedFiles, num_entries);
@ -291,13 +269,12 @@ void ProfileManager::refreshBackups() {
} }
auto ProfileManager::deleteBackup(std::size_t index) -> bool { auto ProfileManager::deleteBackup(std::size_t index) -> bool {
if(!Utility::Path::remove(Utility::Path::join(_backupsDirectory, _backups[index].filename))) { if(!Utility::Directory::rm(Utility::Directory::join(_backupsDirectory, _backups[index].filename))) {
_lastError = "Couldn't delete " + _backups[index].filename; _lastError = "Couldn't delete " + _backups[index].filename;
LOG_ERROR(_lastError);
return false; return false;
} }
auto file = _backups[index].filename; std::string file = _backups[index].filename;
auto it = std::remove_if(_backups.begin(), _backups.end(), [&file](Backup& backup){return backup.filename == file;}); auto it = std::remove_if(_backups.begin(), _backups.end(), [&file](Backup& backup){return backup.filename == file;});
if(it != _backups.end()) { if(it != _backups.end()) {
@ -310,36 +287,33 @@ auto ProfileManager::deleteBackup(std::size_t index) -> bool {
auto ProfileManager::restoreBackup(std::size_t index) -> bool { auto ProfileManager::restoreBackup(std::size_t index) -> bool {
const Backup& backup = _backups[index]; const Backup& backup = _backups[index];
auto error_format = "Extraction of file {} failed: {}"_s; static const char* error_format = "Extraction of file {} failed: {}";
int error_code = 0; int error_code = 0;
zip_t* zip = nullptr; zip_t* zip = nullptr;
zip = zip_open(Utility::Path::join(_backupsDirectory, backup.filename).data(), ZIP_RDONLY, &error_code); zip = zip_open(Utility::Directory::join(_backupsDirectory, backup.filename).c_str(), ZIP_RDONLY, &error_code);
if(zip == nullptr) { if(zip == nullptr) {
zip_error_t error; zip_error_t error;
zip_error_init_with_code(&error, error_code); zip_error_init_with_code(&error, error_code);
_lastError = zip_error_strerror(&error); _lastError = zip_error_strerror(&error);
LOG_ERROR(_lastError);
return false; return false;
} }
Containers::ScopeGuard zip_guard{zip, zip_close}; Containers::ScopeGuard zip_guard{zip, zip_close};
for(Containers::StringView file : backup.includedFiles) { for(const std::string& file : backup.includedFiles) {
FILE* out = std::fopen(Utility::Path::join(_saveDirectory, file).data(), "wb"); FILE* out = std::fopen(Utility::Directory::join(_saveDirectory, file).c_str(), "wb");
if(out == nullptr) { if(out == nullptr) {
_lastError = Utility::format(error_format.data(), file, std::strerror(errno)); _lastError = Utility::formatString(error_format, file, std::strerror(errno));
LOG_ERROR(_lastError);
return false; return false;
} }
Containers::ScopeGuard out_guard{out, std::fclose}; Containers::ScopeGuard out_guard{out, std::fclose};
zip_file_t* zf = zip_fopen(zip, file.data(), ZIP_FL_ENC_GUESS); zip_file_t* zf = zip_fopen(zip, file.c_str(), ZIP_FL_ENC_GUESS);
if(zf == nullptr) { if(zf == nullptr) {
_lastError = Utility::format(error_format.data(), file, zip_strerror(zip)); _lastError = Utility::formatString(error_format, file, zip_strerror(zip));
LOG_ERROR(_lastError);
return false; return false;
} }
@ -350,15 +324,13 @@ auto ProfileManager::restoreBackup(std::size_t index) -> bool {
Long bytes_read = 0; Long bytes_read = 0;
while((bytes_read = zip_fread(zf, buf.data(), buf.size())) > 0) { while((bytes_read = zip_fread(zf, buf.data(), buf.size())) > 0) {
if(std::fwrite(buf.data(), sizeof(char), bytes_read, out) < static_cast<std::size_t>(bytes_read)) { if(std::fwrite(buf.data(), sizeof(char), bytes_read, out) < static_cast<std::size_t>(bytes_read)) {
_lastError = Utility::format(error_format.data(), file, "not enough bytes written."); _lastError = Utility::formatString(error_format, file, "not enough bytes written.");
LOG_ERROR(_lastError);
return false; return false;
} }
} }
if(bytes_read == -1) { if(bytes_read == -1) {
_lastError = Utility::format(error_format.data(), file, "couldn't read bytes from archive."); _lastError = Utility::formatString(error_format, file, "couldn't read bytes from archive.");
LOG_ERROR(_lastError);
return false; return false;
} }
} }

View File

@ -19,15 +19,14 @@
#include <string> #include <string>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/String.h>
#include "../Profile/Profile.h" #include "../Profile/Profile.h"
using namespace Corrade; using namespace Corrade;
struct Backup { struct Backup {
Containers::String filename; std::string filename;
Containers::String company; std::string company;
ProfileType type; ProfileType type;
struct { struct {
int year; int year;
@ -37,15 +36,15 @@ struct Backup {
int minute; int minute;
int second; int second;
} timestamp; } timestamp;
Containers::Array<Containers::String> includedFiles; Containers::Array<std::string> includedFiles;
}; };
class ProfileManager { class ProfileManager {
public: public:
explicit ProfileManager(Containers::StringView save_dir, Containers::StringView backup_dir); explicit ProfileManager(const std::string& save_dir, const std::string& backup_dir);
auto ready() const -> bool; auto ready() const -> bool;
auto lastError() -> Containers::StringView; auto lastError() -> std::string const&;
auto profiles() -> Containers::ArrayView<Profile>; auto profiles() -> Containers::ArrayView<Profile>;
auto refreshProfiles() -> bool; auto refreshProfiles() -> bool;
@ -62,10 +61,10 @@ class ProfileManager {
private: private:
bool _ready = false; bool _ready = false;
Containers::String _lastError; std::string _lastError;
Containers::StringView _saveDirectory; const std::string& _saveDirectory;
Containers::StringView _backupsDirectory; const std::string& _backupsDirectory;
Containers::Array<Profile> _profiles; Containers::Array<Profile> _profiles;
Containers::Array<Backup> _backups; Containers::Array<Backup> _backups;

View File

@ -16,7 +16,12 @@
#include "SaveTool.h" #include "SaveTool.h"
#include <cstring>
#include <Corrade/Containers/ScopeGuard.h> #include <Corrade/Containers/ScopeGuard.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/FormatStl.h>
#include <Corrade/Utility/String.h>
#include <Corrade/Utility/Unicode.h> #include <Corrade/Utility/Unicode.h>
#include <Magnum/GL/DebugOutput.h> #include <Magnum/GL/DebugOutput.h>
@ -27,17 +32,19 @@
#include <Magnum/ImGuiIntegration/Integration.h> #include <Magnum/ImGuiIntegration/Integration.h>
#include <Magnum/ImGuiIntegration/Context.hpp> #include <Magnum/ImGuiIntegration/Context.hpp>
#include <SDL.h> #include <cpr/cpr.h>
#include <curl/curl.h> #include <nlohmann/json.hpp>
#include <windef.h>
#include <winuser.h>
#include <processthreadsapi.h>
#include <shellapi.h> #include <shellapi.h>
#include <shlobj.h>
#include <wtsapi32.h> #include <wtsapi32.h>
#include "../FontAwesome/IconsFontAwesome5.h" #include "../FontAwesome/IconsFontAwesome5.h"
#include "../Logger/Logger.h" #include "../FontAwesome/IconsFontAwesome5Brands.h"
using namespace Containers::Literals;
extern const ImVec2 center_pivot = {0.5f, 0.5f}; extern const ImVec2 center_pivot = {0.5f, 0.5f};
@ -50,11 +57,22 @@ SaveTool::SaveTool(const Arguments& arguments):
Configuration{}.setTitle("M.A.S.S. Builder Save Tool " SAVETOOL_VERSION " (\"" SAVETOOL_CODENAME "\")") Configuration{}.setTitle("M.A.S.S. Builder Save Tool " SAVETOOL_VERSION " (\"" SAVETOOL_CODENAME "\")")
.setSize({960, 720})} .setSize({960, 720})}
{ {
#ifdef SAVETOOL_DEBUG_BUILD #ifdef SAVETOOL_DEBUG_BUILD
tweak.enable("", "../../"); tweak.enable("", "../../");
#endif #endif
if(SDL_VERSION_ATLEAST(2, 0, 5)) {
if(SDL_SetHintWithPriority(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1", SDL_HINT_OVERRIDE) == SDL_TRUE) {
Utility::Debug{} << "Clickthrough is available.";
}
else {
Utility::Warning{} << "Clickthrough is not available (hint couldn't be set).";
}
}
else {
Utility::Warning{} << "Clickthrough is not available (SDL2 is too old).";
}
LOG_INFO("Configuring OpenGL renderer.");
GL::Renderer::enable(GL::Renderer::Feature::Blending); GL::Renderer::enable(GL::Renderer::Feature::Blending);
GL::Renderer::enable(GL::Renderer::Feature::ScissorTest); GL::Renderer::enable(GL::Renderer::Feature::ScissorTest);
GL::Renderer::disable(GL::Renderer::Feature::FaceCulling); GL::Renderer::disable(GL::Renderer::Feature::FaceCulling);
@ -64,51 +82,60 @@ SaveTool::SaveTool(const Arguments& arguments):
GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add, GL::Renderer::setBlendEquation(GL::Renderer::BlendEquation::Add,
GL::Renderer::BlendEquation::Add); GL::Renderer::BlendEquation::Add);
LOG_INFO("Configuring SDL2."); initialiseGui();
#if SDL_VERSION_ATLEAST(2,0,5)
if(SDL_SetHintWithPriority(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1", SDL_HINT_OVERRIDE) == SDL_TRUE) {
LOG_INFO("Clickthrough is enabled.");
}
else {
LOG_WARNING("Clickthrough is disabled.");
}
#else
LOG_WARNING_FORMAT("Clickthrough is disabled: SDL2 version is too old ({}.{}.{})",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
#endif
LOG_INFO("Registering custom events."); if((_initEventId = SDL_RegisterEvents(2)) == UnsignedInt(-1)) {
if((_initEventId = SDL_RegisterEvents(3)) == UnsignedInt(-1)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
"SDL_RegisterEvents() failed in SaveTool::SaveTool(). Exiting...", window()); "SDL_RegisterEvents failed in SaveTool::SaveTool(). Exiting...", window());
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
return; return;
} }
_updateEventId = _initEventId + 1; _updateEventId = _initEventId + 1;
_fileEventId = _initEventId + 2;
LOG_INFO("Initialising the timer subsystem."); _backupsDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "backups");
if(SDL_InitSubSystem(SDL_INIT_TIMER) != 0) { _stagingDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "staging");
LOG_ERROR(SDL_GetError()); _armouryDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "armoury");
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", _armoursDir = Utility::Directory::join(_armouryDir, "armours");
SDL_GetError(), window()); _weaponsDir = Utility::Directory::join(_armouryDir, "weapons");
exit(EXIT_FAILURE); _stylesDir = Utility::Directory::join(_armouryDir, "styles");
return;
if(!Utility::Directory::exists(_backupsDir)) {
Utility::Directory::mkpath(_backupsDir);
} }
initialiseGui(); if(!Utility::Directory::exists(_stagingDir)) {
Utility::Directory::mkpath(_stagingDir);
}
if(!initialiseToolDirectories()) { if(!Utility::Directory::exists(_armouryDir)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", Utility::Directory::mkpath(_armouryDir);
_lastError.data(), window()); }
exit(EXIT_FAILURE);
return; if(!Utility::Directory::exists(_armoursDir)) {
Utility::Directory::mkpath(_armoursDir);
}
if(!Utility::Directory::exists(_weaponsDir)) {
Utility::Directory::mkpath(_weaponsDir);
}
if(!Utility::Directory::exists(_stylesDir)) {
Utility::Directory::mkpath(_stylesDir);
} }
if(!findGameDataDirectory()) { if(!findGameDataDirectory()) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", _lastError.c_str(), window());
_lastError.data(), window()); exit(EXIT_FAILURE);
return;
}
_configDir = Utility::Directory::join(_gameDataDir, "Saved/Config/WindowsNoEditor");
_saveDir = Utility::Directory::join(_gameDataDir, "Saved/SaveGames");
_screenshotsDir = Utility::Directory::join(_gameDataDir, "Saved/Screenshots/WindowsNoEditor");
if(SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising the app", SDL_GetError(), window());
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
return; return;
} }
@ -118,9 +145,9 @@ SaveTool::SaveTool(const Arguments& arguments):
[](UnsignedInt interval, void* param)->UnsignedInt{ [](UnsignedInt interval, void* param)->UnsignedInt{
static_cast<SaveTool*>(param)->checkGameState(); static_cast<SaveTool*>(param)->checkGameState();
return interval; return interval;
}, this); },
this);
if(_gameCheckTimerId == 0) { if(_gameCheckTimerId == 0) {
LOG_ERROR(SDL_GetError());
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), window()); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_GetError(), window());
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
return; return;
@ -128,11 +155,22 @@ SaveTool::SaveTool(const Arguments& arguments):
initialiseConfiguration(); initialiseConfiguration();
LOG_INFO("Initialising update checker."); switch(_framelimit) {
curl_global_init(CURL_GLOBAL_DEFAULT); case Framelimit::Vsync:
setSwapInterval(1);
break;
case Framelimit::HalfVsync:
setSwapInterval(2);
break;
case Framelimit::FpsCap:
setSwapInterval(0);
setMinimalLoopPeriod(1000/_fpsCap);
break;
}
if(_checkUpdatesOnStartup) { if(_checkUpdatesOnStartup) {
_queue.addToast(Toast::Type::Default, "Checking for updates..."_s);
_updateThread = std::thread{[this]{ checkForUpdates(); }}; _updateThread = std::thread{[this]{ checkForUpdates(); }};
_queue.addToast(Toast::Type::Default, "Checking for updates...");
} }
if(GL::Context::current().isExtensionSupported<GL::Extensions::KHR::debug>() && if(GL::Context::current().isExtensionSupported<GL::Extensions::KHR::debug>() &&
@ -145,57 +183,138 @@ SaveTool::SaveTool(const Arguments& arguments):
_uiState = UiState::Initialising; _uiState = UiState::Initialising;
_initThread = std::thread{[this]{ initialiseManager(); }}; _initThread = std::thread{[this]{ initialiseManager(); }};
} }
_timeline.start();
} }
SaveTool::~SaveTool() { SaveTool::~SaveTool() {
LOG_INFO("Cleaning up.");
LOG_INFO("Shutting libcurl down.");
curl_global_cleanup();
SDL_RemoveTimer(_gameCheckTimerId); SDL_RemoveTimer(_gameCheckTimerId);
LOG_INFO("Saving the configuration."); _conf.setValue("cheat_mode", _cheatMode);
_conf.setValue("unsafe_mode", _unsafeMode);
_conf.setValue("startup_update_check", _checkUpdatesOnStartup);
_conf.setValue("skip_disclaimer", _skipDisclaimer);
_conf.setValue("cheat_mode"_s, _cheatMode); switch(_framelimit) {
_conf.setValue("advanced_mode"_s, _advancedMode); case Framelimit::Vsync:
_conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup); _conf.setValue("frame_limit", "vsync");
_conf.setValue("skip_disclaimer"_s, _skipDisclaimer); break;
_conf.setValue("swap_interval"_s, _swapInterval); case Framelimit::HalfVsync:
_conf.setValue("fps_cap"_s, _fpsCap); _conf.setValue("frame_limit", "half_vsync");
break;
case Framelimit::FpsCap:
_conf.setValue<UnsignedInt>("frame_limit", _fpsCap);
break;
}
_conf.save(); _conf.save();
}
LOG_INFO("Exiting."); void SaveTool::handleFileAction(efsw::WatchID watch_id,
const std::string&,
const std::string& filename,
efsw::Action action,
std::string old_filename)
{
if(watch_id == _watchIDs[StagingDir] && Utility::String::endsWith(filename, ".sav")) {
_massManager->refreshStagedMasses();
return;
}
if(Utility::String::endsWith(filename, "Config.sav")) {
return;
}
static bool is_moved_after_save = false;
switch(action) {
case efsw::Actions::Add:
if(Utility::String::endsWith(filename, _currentProfile->account() + ".sav")) {
if(Utility::String::beginsWith(filename, Utility::formatString("{}Unit", _currentProfile->type() == ProfileType::Demo ? "Demo" : ""))) {
int index = ((filename[_currentProfile->type() == ProfileType::Demo ? 8 : 4] - 0x30) * 10) +
(filename[_currentProfile->type() == ProfileType::Demo ? 9 : 5] - 0x30);
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
_massManager->refreshHangar(index);
}
else {
_currentMass->setDirty();
}
}
}
break;
case efsw::Actions::Delete:
if(Utility::String::endsWith(filename, _currentProfile->account() + ".sav")) {
if(Utility::String::beginsWith(filename, Utility::formatString("{}Unit", _currentProfile->type() == ProfileType::Demo ? "Demo" : ""))) {
int index = ((filename[_currentProfile->type() == ProfileType::Demo ? 8 : 4] - 0x30) * 10) +
(filename[_currentProfile->type() == ProfileType::Demo ? 9 : 5] - 0x30);
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
_massManager->refreshHangar(index);
}
}
}
break;
case efsw::Actions::Modified:
if(filename == _currentProfile->filename()) {
_currentProfile->refreshValues();
}
else if(Utility::String::endsWith(filename, _currentProfile->account() + ".sav")) {
if(Utility::String::beginsWith(filename, Utility::formatString("{}Unit", _currentProfile->type() == ProfileType::Demo ? "Demo" : ""))) {
int index = ((filename[_currentProfile->type() == ProfileType::Demo ? 8 : 4] - 0x30) * 10) +
(filename[_currentProfile->type() == ProfileType::Demo ? 9 : 5] - 0x30);
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
_massManager->refreshHangar(index);
}
else {
if(!is_moved_after_save) {
is_moved_after_save = false;
_currentMass->setDirty();
}
}
}
}
break;
case efsw::Actions::Moved:
if(Utility::String::endsWith(filename, _currentProfile->account() + ".sav")) {
if(Utility::String::endsWith(old_filename, ".tmp")) {
is_moved_after_save = true;
return;
}
if(Utility::String::beginsWith(filename, Utility::formatString("{}Unit", _currentProfile->type() == ProfileType::Demo ? "Demo" : "")) &&
Utility::String::endsWith(old_filename, ".sav"))
{
int index = ((filename[_currentProfile->type() == ProfileType::Demo ? 8 : 4] - 0x30) * 10) +
(filename[_currentProfile->type() == ProfileType::Demo ? 9 : 5] - 0x30);
_massManager->refreshHangar(index);
int old_index = ((old_filename[_currentProfile->type() == ProfileType::Demo ? 8 : 4] - 0x30) * 10) +
(old_filename[_currentProfile->type() == ProfileType::Demo ? 9 : 5] - 0x30);
_massManager->refreshHangar(old_index);
}
}
break;
default:
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", "Unknown file watcher action type.", window());
break;
}
} }
void SaveTool::drawEvent() { void SaveTool::drawEvent() {
#ifdef SAVETOOL_DEBUG_BUILD #ifdef SAVETOOL_DEBUG_BUILD
tweak.update(); tweak.update();
#endif #endif
GL::defaultFramebuffer.clear(GL::FramebufferClear::Color); GL::defaultFramebuffer.clear(GL::FramebufferClear::Color);
drawImGui(); drawImGui();
swapBuffers(); swapBuffers();
if(_swapInterval == 0 && _fpsCap < 301.0f) {
while(_timeline.currentFrameDuration() < (1.0f / _fpsCap));
}
redraw(); redraw();
_timeline.nextFrame();
} }
void SaveTool::viewportEvent(ViewportEvent& event) { void SaveTool::viewportEvent(ViewportEvent& event) {
GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()}); GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()});
const Vector2 size = Vector2{windowSize()}/dpiScaling(); _imgui.relayout(event.windowSize());
_imgui.relayout(size, windowSize(), framebufferSize());
} }
void SaveTool::keyPressEvent(KeyEvent& event) { void SaveTool::keyPressEvent(KeyEvent& event) {
@ -236,11 +355,247 @@ void SaveTool::anyEvent(SDL_Event& event) {
else if(event.type == _updateEventId) { else if(event.type == _updateEventId) {
updateCheckEvent(event); updateCheckEvent(event);
} }
else if(event.type == _fileEventId) { }
fileUpdateEvent(event);
void SaveTool::initEvent(SDL_Event& event) {
_initThread.join();
switch(event.user.code) {
case InitSuccess:
_uiState = UiState::ProfileManager;
ImGui::CloseCurrentPopup();
break;
case ProfileManagerFailure:
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error initialising ProfileManager", _profileManager->lastError().c_str(), window());
exit(EXIT_FAILURE);
break;
default:
break;
} }
} }
void SaveTool::updateCheckEvent(SDL_Event& event) {
_updateThread.join();
cpr::Response r{std::move(*static_cast<cpr::Response*>(event.user.data1))};
delete static_cast<cpr::Response*>(event.user.data1);
if(r.elapsed > 10.0) {
_queue.addToast(Toast::Type::Error, "The request timed out.");
return;
}
if(r.status_code != 200) {
_queue.addToast(Toast::Type::Error, Utility::formatString("The request failed with error code {}: {}", r.status_code, r.reason));
return;
}
using json = nlohmann::json;
json response = json::parse(r.text);
struct Version {
explicit Version(const std::string& str) {
std::size_t start_point = 0;
if(str[0] == 'v') {
start_point++;
}
major = std::atoi(str.c_str() + start_point);
start_point = str.find('.', start_point) + 1;
minor = std::atoi(str.c_str() + start_point);
start_point = str.find('.', start_point) + 1;
patch = std::atoi(str.c_str() + start_point);
}
Int major;
Int minor;
Int patch;
bool operator==(const Version& other) const {
return (major == other.major) && (minor == other.minor) && (patch == other.patch);
}
bool operator>(const Version& other) const {
return ( major * 10000 + minor * 100 + patch) >
(other.major * 10000 + other.minor * 100 + other.patch);
}
operator std::string() const {
return Utility::formatString("{}.{}.{}", major, minor, patch);
}
};
static const Version current_ver{SAVETOOL_VERSION};
for(auto& release : response) {
if(release["prerelease"] == true) {
continue;
}
Version latest_ver{release["tag_name"]};
if(latest_ver > current_ver || (latest_ver == current_ver && Utility::String::endsWith(SAVETOOL_VERSION, "-pre"))) {
_queue.addToast(Toast::Type::Warning, "Your version is out of date.\nCheck the settings for more information.",
std::chrono::milliseconds{5000});
_updateAvailable = true;
_latestVersion = latest_ver;
_releaseLink = release["html_url"];
_downloadLink = release["assets"][0]["browser_download_url"];
}
else if(latest_ver == current_ver || (current_ver > latest_ver && Utility::String::endsWith(SAVETOOL_VERSION, "-pre"))) {
_queue.addToast(Toast::Type::Success, "The application is already up to date.");
}
else if(current_ver > latest_ver) {
_queue.addToast(Toast::Type::Warning, "Your version is more recent than the latest one in the repo. How???");
}
break;
}
}
void SaveTool::initialiseConfiguration() {
if(_conf.hasValue("cheat_mode")) {
_cheatMode = _conf.value<bool>("cheat_mode");
}
else {
_conf.setValue("cheat_mode", _cheatMode);
}
if(_conf.hasValue("unsafe_mode")) {
_unsafeMode = _conf.value<bool>("unsafe_mode");
}
else {
_conf.setValue("unsafe_mode", _unsafeMode);
}
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);
}
if(_conf.hasValue("frame_limit")) {
std::string frame_limit = _conf.value("frame_limit");
if(frame_limit == "vsync") {
_framelimit = Framelimit::Vsync;
}
else if(frame_limit == "half_vsync") {
_framelimit = Framelimit::HalfVsync;
}
else {
_framelimit = Framelimit::FpsCap;
_fpsCap = std::stoul(frame_limit);
}
}
else {
_conf.setValue("frame_limit", "vsync");
}
_conf.save();
}
void SaveTool::initialiseGui() {
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
auto reg_font = _rs.getRaw("SourceSansPro-Regular.ttf");
ImFontConfig font_config;
font_config.FontDataOwnedByAtlas = false;
std::strcpy(font_config.Name, "Source Sans Pro");
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(reg_font.data()), reg_font.size(), 20.0f, &font_config);
auto icon_font = _rs.getRaw(FONT_ICON_FILE_NAME_FAS);
static const ImWchar icon_range[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFontConfig icon_config;
icon_config.FontDataOwnedByAtlas = false;
icon_config.MergeMode = true;
icon_config.PixelSnapH = true;
icon_config.OversampleH = icon_config.OversampleV = 1;
icon_config.GlyphMinAdvanceX = 18.0f;
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(icon_font.data()), icon_font.size(), 16.0f, &icon_config, icon_range);
auto brand_font = _rs.getRaw(FONT_ICON_FILE_NAME_FAB);
static const ImWchar brand_range[] = { ICON_MIN_FAB, ICON_MAX_FAB, 0 };
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(brand_font.data()), brand_font.size(), 16.0f, &icon_config, brand_range);
auto mono_font = _rs.getRaw("SourceCodePro-Regular.ttf");
ImVector<ImWchar> range;
ImFontGlyphRangesBuilder builder;
builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
builder.AddChar(u'š'); // This allows displaying Vladimír Vondruš' name in Corrade's and Magnum's licences.
builder.BuildRanges(&range);
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(mono_font.data()), mono_font.size(), 18.0f, &font_config, range.Data);
_imgui = ImGuiIntegration::Context(*ImGui::GetCurrentContext(), windowSize());
io.IniFilename = nullptr;
ImGuiStyle& style = ImGui::GetStyle();
style.WindowTitleAlign = {0.5f, 0.5f};
style.FrameRounding = 3.2f;
style.Colors[ImGuiCol_WindowBg] = ImColor(0xff1f1f1f);
}
void SaveTool::initialiseManager() {
SDL_Event event;
SDL_zero(event);
event.type = _initEventId;
_profileManager.emplace(_saveDir, _backupsDir);
if(!_profileManager->ready()) {
event.user.code = ProfileManagerFailure;
SDL_PushEvent(&event);
return;
}
event.user.code = InitSuccess;
SDL_PushEvent(&event);
}
auto SaveTool::findGameDataDirectory() -> bool {
wchar_t* localappdata_path = nullptr;
Containers::ScopeGuard guard{localappdata_path, CoTaskMemFree};
if(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_NO_APPCONTAINER_REDIRECTION, nullptr, &localappdata_path) != S_OK)
{
_lastError = "SHGetKnownFolderPath() failed in SaveTool::findGameDataDirectory()";
return false;
}
_gameDataDir = Utility::Directory::join(Utility::Directory::fromNativeSeparators(Utility::Unicode::narrow(localappdata_path)), "MASS_Builder");
if(!Utility::Directory::exists(_gameDataDir)) {
_lastError = _gameDataDir + " wasn't found. Make sure to play the game at least once.";
return false;
}
return true;
}
void SaveTool::initialiseMassManager() {
_massManager.emplace(_saveDir,
_currentProfile->account(),
_currentProfile->type() == ProfileType::Demo,
_stagingDir);
initialiseFileWatcher();
}
void SaveTool::initialiseFileWatcher() {
_fileWatcher.emplace();
_watchIDs[SaveDir] = _fileWatcher->addWatch(_saveDir, this, false);
_watchIDs[StagingDir] = _fileWatcher->addWatch(_stagingDir, this, false);
_fileWatcher->watch();
}
void SaveTool::drawImGui() { void SaveTool::drawImGui() {
_imgui.newFrame(); _imgui.newFrame();
@ -283,7 +638,7 @@ void SaveTool::drawGui() {
drawAbout(); drawAbout();
} }
#ifdef SAVETOOL_DEBUG_BUILD #ifdef SAVETOOL_DEBUG_BUILD
if(_demoWindow) { if(_demoWindow) {
ImGui::ShowDemoWindow(&_demoWindow); ImGui::ShowDemoWindow(&_demoWindow);
} }
@ -295,7 +650,7 @@ void SaveTool::drawGui() {
if(_metricsWindow) { if(_metricsWindow) {
ImGui::ShowMetricsWindow(&_metricsWindow); ImGui::ShowMetricsWindow(&_metricsWindow);
} }
#endif #endif
_queue.draw(windowSize()); _queue.draw(windowSize());
} }
@ -314,11 +669,11 @@ void SaveTool::drawDisclaimer() {
ImGui::TextUnformatted("Before you start using the app, there are a few things you should know:"); ImGui::TextUnformatted("Before you start using the app, there are a few things you should know:");
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.67f); ImGui::PushTextWrapPos(windowSize().x() * 0.67f);
ImGui::Bullet(); ImGui::Bullet();
ImGui::SameLine(); ImGui::SameLine();
ImGui::TextUnformatted(R"(For this application to work properly, it is recommended to disable Steam Cloud syncing for the game. To disable it, right-click the game in your Steam library, click "Properties", go to the "General" tab, and uncheck "Keep game saves in the Steam Cloud for M.A.S.S. Builder".)"); ImGui::TextUnformatted("For this application to work properly, it is recommended to disable Steam Cloud syncing for the game. To disable it, right-click the game in your Steam library, click \"Properties\", go to the \"General\" tab, and uncheck \"Keep game saves in the Steam Cloud for M.A.S.S. Builder\".");
ImGui::Bullet(); ImGui::Bullet();
ImGui::SameLine(); ImGui::SameLine();
@ -393,18 +748,18 @@ void SaveTool::drawGameState() {
} }
} }
void SaveTool::drawHelpMarker(Containers::StringView text, Float wrap_pos) { void SaveTool::drawHelpMarker(const char* text, Float wrap_pos) {
ImGui::TextUnformatted(ICON_FA_QUESTION_CIRCLE); ImGui::TextUnformatted(ICON_FA_QUESTION_CIRCLE);
drawTooltip(text, wrap_pos); drawTooltip(text, wrap_pos);
} }
void SaveTool::drawTooltip(Containers::StringView text, Float wrap_pos) { void SaveTool::drawTooltip(const char* text, Float wrap_pos) {
if(ImGui::IsItemHovered()){ if(ImGui::IsItemHovered()){
ImGui::BeginTooltip(); ImGui::BeginTooltip();
if(wrap_pos > 0.0f) { if(wrap_pos > 0.0f) {
ImGui::PushTextWrapPos(wrap_pos); ImGui::PushTextWrapPos(wrap_pos);
} }
ImGui::TextUnformatted(text.data()); ImGui::TextUnformatted(text);
if(wrap_pos > 0.0f) { if(wrap_pos > 0.0f) {
ImGui::PopTextWrapPos(); ImGui::PopTextWrapPos();
} }
@ -412,8 +767,8 @@ void SaveTool::drawTooltip(Containers::StringView text, Float wrap_pos) {
} }
} }
void SaveTool::openUri(Containers::StringView uri) { void SaveTool::openUri(const std::string& uri) {
ShellExecuteW(nullptr, nullptr, Utility::Unicode::widen(uri.data()), nullptr, nullptr, SW_SHOWDEFAULT); ShellExecuteW(nullptr, nullptr, Utility::Unicode::widen(uri).c_str(), nullptr, nullptr, SW_SHOWDEFAULT);
} }
void SaveTool::checkGameState() { void SaveTool::checkGameState() {
@ -437,3 +792,14 @@ void SaveTool::checkGameState() {
_gameState = GameState::Unknown; _gameState = GameState::Unknown;
} }
} }
void SaveTool::checkForUpdates() {
cpr::Response r = cpr::Get(cpr::Url{"https://williamjcm.ovh/git/api/v1/repos/williamjcm/MassBuilderSaveTool/releases"}, cpr::Timeout{10000});
SDL_Event event;
SDL_zero(event);
event.type = _updateEventId;
event.user.code = r.status_code;
event.user.data1 = new cpr::Response{std::move(r)};
SDL_PushEvent(&event);
}

View File

@ -16,22 +16,16 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <thread> #include <thread>
#include <Corrade/Containers/Pointer.h> #include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Utility/Configuration.h> #include <Corrade/Utility/Configuration.h>
#include <Corrade/Utility/Resource.h> #include <Corrade/Utility/Resource.h>
#ifdef SAVETOOL_DEBUG_BUILD
#include <Corrade/Utility/Tweakable.h>
#endif
#include <Magnum/Timeline.h>
#include <Magnum/Platform/Sdl2Application.h> #include <Magnum/Platform/Sdl2Application.h>
#include <Magnum/ImGuiIntegration/Context.h> #include <Magnum/ImGuiIntegration/Context.h>
#include <SDL_timer.h> #include <SDL.h>
#include <imgui.h> #include <imgui.h>
#include <imgui_internal.h> #include <imgui_internal.h>
@ -43,11 +37,12 @@
#include "../ToastQueue/ToastQueue.h" #include "../ToastQueue/ToastQueue.h"
#ifdef SAVETOOL_DEBUG_BUILD #ifdef SAVETOOL_DEBUG_BUILD
#include <Corrade/Utility/Tweakable.h>
#define tw CORRADE_TWEAKABLE #define tw CORRADE_TWEAKABLE
#endif #endif
using namespace Corrade; using namespace Corrade;
using namespace Containers::Literals;
using namespace Magnum; using namespace Magnum;
class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener { class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener {
@ -83,28 +78,12 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
ProfileManagerFailure ProfileManagerFailure
}; };
void initEvent(SDL_Event& event); void initEvent(SDL_Event& event);
enum UpdateCheckStatus : Int {
CurlInitFailed = 0,
CurlError = 1,
CurlTimeout = 2,
};
void updateCheckEvent(SDL_Event& event); void updateCheckEvent(SDL_Event& event);
enum FileEventType: Int {
FileAdded = efsw::Action::Add,
FileDeleted = efsw::Action::Delete,
FileModified = efsw::Action::Modified,
FileMoved = efsw::Action::Moved,
StagedUpdate = 1 << 3
};
void fileUpdateEvent(SDL_Event& event);
// Initialisation methods // Initialisation methods
void initialiseConfiguration(); void initialiseConfiguration();
void initialiseGui(); void initialiseGui();
void initialiseManager(); void initialiseManager();
auto initialiseToolDirectories() -> bool;
auto findGameDataDirectory() -> bool; auto findGameDataDirectory() -> bool;
void initialiseMassManager(); void initialiseMassManager();
void initialiseFileWatcher(); void initialiseFileWatcher();
@ -127,11 +106,11 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
void drawGeneralInfo(); void drawGeneralInfo();
void drawResearchInventory(); void drawResearchInventory();
template<typename Getter, typename Setter> template<typename Getter, typename Setter>
void drawMaterialRow(Containers::StringView name, Int tier, Getter getter, Setter setter); void drawMaterialRow(const char* name, Int tier, Getter getter, Setter setter);
void drawUnavailableMaterialRow(Containers::StringView name, Int tier); void drawUnavailableMaterialRow(const char* name, Int tier);
void drawMassManager(); void drawMassManager();
auto drawDeleteMassPopup(int mass_index) -> ImGuiID; auto drawDeleteMassPopup(int mass_index) -> ImGuiID;
auto drawDeleteStagedMassPopup(Containers::StringView filename) -> ImGuiID; auto drawDeleteStagedMassPopup(const std::string& filename) -> ImGuiID;
void drawMassViewer(); void drawMassViewer();
void drawFrameInfo(); void drawFrameInfo();
@ -142,14 +121,13 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
void drawArmour(); void drawArmour();
void drawCustomArmourStyles(); void drawCustomArmourStyles();
void drawWeapons(); void drawWeapons();
void drawWeaponCategory(Containers::StringView name, Containers::ArrayView<Weapon> weapons_view, bool& dirty, void drawWeaponCategory(const char* name, Containers::ArrayView<Weapon> weapons_view, bool& dirty, const char* payload_type, const char* payload_tooltip);
Containers::StringView payload_type, Containers::StringView payload_tooltip);
void drawWeaponEditor(Weapon& weapon); void drawWeaponEditor(Weapon& weapon);
void drawGlobalStyles(); void drawGlobalStyles();
void drawTuning(); void drawTuning();
void drawDecalEditor(Decal& decal); void drawDecalEditor(Decal& decal);
void drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<CustomStyle> style_view); void drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<CustomStyle> style_view);
auto getStyleName(Int id, Containers::ArrayView<CustomStyle> view) -> Containers::StringView; auto getStyleName(Int id, Containers::ArrayView<CustomStyle> view) -> const char*;
enum DCSResult { enum DCSResult {
DCS_Fail, DCS_Fail,
@ -162,22 +140,31 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
void drawGameState(); void drawGameState();
// Convenience wrappers over ImGui stuff // Convenience wrappers over ImGui stuff
void drawHelpMarker(Containers::StringView text, Float wrap_pos = 0.0f); void drawHelpMarker(const char* text, Float wrap_pos = 0.0f);
void drawTooltip(Containers::StringView text, Float wrap_pos = 0.0f); void drawTooltip(const char* text, Float wrap_pos = 0.0f);
template<typename Functor, typename... Args> template<typename Functor, typename... Args>
auto drawUnsafeWidget(Functor func, Args... args) -> bool { auto drawUnsafeWidget(Functor func, Args... args) -> bool {
GameState game_state = _gameState; // Copying the value to reduce the risk of a data race. GameState game_state = _gameState; // Copying the value to reduce the risk of a data race.
ImGui::BeginDisabled(game_state != GameState::NotRunning); if(!_unsafeMode && game_state != GameState::NotRunning) {
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5f);
}
bool result = func(std::forward<Args>(args)...); bool result = func(std::forward<Args>(args)...);
ImGui::EndDisabled();
if(!_unsafeMode && game_state != GameState::NotRunning) {
ImGui::PopItemFlag();
ImGui::PopStyleVar();
}
return result; return result;
} // Obviously, should only be used with ImGui widgets that return a bool. } // Obviously, should only be used with ImGui widgets that return a bool.
// Also, func should be a lambda if there are any default arguments, like ImGui::Button(), etc... // Also, func should be a lambda if there are any default arguments, like ImGui::Button(), etc...
template<typename... Args> template<typename... Args>
void drawUnsafeText(const char* text, Args... args) { // Alternative to the above, for ImGui::Text*() variants. void drawUnsafeText(const char* text, Args... args) { // Alternative to the above, for ImGui::Text*() variants.
if(_gameState != GameState::NotRunning) { if(!_unsafeMode && _gameState != GameState::NotRunning) {
ImGui::TextDisabled(text, std::forward<Args>(args)...); ImGui::TextDisabled(text, std::forward<Args>(args)...);
} }
else { else {
@ -186,19 +173,19 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
} }
template<typename... Args> template<typename... Args>
void drawAlignedText(Containers::StringView text, Args... args) { void drawAlignedText(const char* text, Args... args) {
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
ImGui::Text(text.data(), std::forward<Args>(args)...); ImGui::Text(text, std::forward<Args>(args)...);
} }
void openUri(Containers::StringView uri); void openUri(const std::string& uri);
void checkGameState(); void checkGameState();
void checkForUpdates(); void checkForUpdates();
Utility::Configuration _conf{"MassBuilderSaveTool.ini"_s}; Utility::Configuration _conf{"MassBuilderSaveTool.ini"};
Utility::Resource _rs{"assets"_s}; Utility::Resource _rs{"assets"};
// GUI-related members // GUI-related members
ImGuiIntegration::Context _imgui{NoCreate}; ImGuiIntegration::Context _imgui{NoCreate};
@ -212,11 +199,11 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
} _uiState{UiState::Disclaimer}; } _uiState{UiState::Disclaimer};
bool _aboutPopup{false}; bool _aboutPopup{false};
#ifdef SAVETOOL_DEBUG_BUILD #ifdef SAVETOOL_DEBUG_BUILD
bool _demoWindow{false}; bool _demoWindow{false};
bool _styleEditor{false}; bool _styleEditor{false};
bool _metricsWindow{false}; bool _metricsWindow{false};
#endif #endif
ToastQueue _queue; ToastQueue _queue;
@ -225,21 +212,20 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
UnsignedInt _initEventId; UnsignedInt _initEventId;
UnsignedInt _updateEventId; UnsignedInt _updateEventId;
UnsignedInt _fileEventId;
Containers::String _lastError; std::string _lastError;
Containers::String _gameDataDir; std::string _gameDataDir;
Containers::String _configDir; std::string _configDir;
Containers::String _saveDir; std::string _saveDir;
Containers::String _screenshotsDir; std::string _screenshotsDir;
Containers::String _backupsDir; std::string _backupsDir;
Containers::String _stagingDir; std::string _stagingDir;
//Containers::String _armouryDir; std::string _armouryDir;
//Containers::String _armoursDir; std::string _armoursDir;
//Containers::String _weaponsDir; std::string _weaponsDir;
//Containers::String _stylesDir; std::string _stylesDir;
enum class GameState : UnsignedByte { enum class GameState : UnsignedByte {
Unknown, NotRunning, Running Unknown, NotRunning, Running
@ -262,24 +248,27 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
}; };
Containers::StaticArray<2, efsw::WatchID> _watchIDs; Containers::StaticArray<2, efsw::WatchID> _watchIDs;
int _swapInterval = 1; enum class Framelimit: UnsignedByte {
float _fpsCap = 60.0f; Vsync,
HalfVsync,
FpsCap
} _framelimit{Framelimit::Vsync};
UnsignedInt _fpsCap{60};
bool _skipDisclaimer{false}; bool _skipDisclaimer{false};
bool _checkUpdatesOnStartup{true}; bool _checkUpdatesOnStartup{true};
bool _unsafeMode{false};
bool _updateAvailable{false}; bool _updateAvailable{false};
Containers::String _latestVersion; std::string _latestVersion;
Containers::String _releaseLink; std::string _releaseLink;
Containers::String _downloadLink; std::string _downloadLink;
bool _modifiedBySaveTool{false};
bool _jointsDirty{false}; bool _jointsDirty{false};
bool _stylesDirty{false}; bool _stylesDirty{false};
bool _eyeFlareDirty{false}; bool _eyeFlareDirty{false};
Containers::StaticArray<38, Int> _selectedArmourDecals{ValueInit}; Containers::StaticArray<38, Int> _selectedArmourDecals{ValueInit};
Containers::StaticArray<38, Int> _selectedArmourAccessories{ValueInit}; Containers::StaticArray<38, Int> _selectedArmourAccessories{ValueInit};
Int _selectedBLPlacement{0};
Int _selectedWeaponPart{0}; Int _selectedWeaponPart{0};
Int _selectedWeaponDecal{0}; Int _selectedWeaponDecal{0};
Int _selectedWeaponAccessory{0}; Int _selectedWeaponAccessory{0};
@ -291,7 +280,4 @@ class SaveTool: public Platform::Sdl2Application, public efsw::FileWatchListener
bool _eLaunchersDirty{false}; bool _eLaunchersDirty{false};
bool _cheatMode{false}; bool _cheatMode{false};
bool _advancedMode{false};
Timeline _timeline;
}; };

View File

@ -1,150 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Utility/Format.h>
#include <Corrade/Utility/String.h>
#include <Corrade/Utility/Unicode.h>
#include <SDL_events.h>
#include <SDL_messagebox.h>
#include <fileapi.h>
#include <handleapi.h>
#include "SaveTool.h"
void SaveTool::handleFileAction(efsw::WatchID watch_id,
const std::string&,
const std::string& filename,
efsw::Action action,
std::string old_filename)
{
SDL_Event event;
SDL_zero(event);
event.type = _fileEventId;
event.user.data1 = Containers::String{Containers::AllocatedInit, filename.c_str()}.release();
if(watch_id == _watchIDs[StagingDir] && Utility::String::endsWith(filename, ".sav")) {
event.user.code = StagedUpdate | action;
SDL_PushEvent(&event);
return;
}
if(Utility::String::endsWith(filename, "Config.sav")) {
return;
} // TODO: actually do something when config files will finally be handled
if(!Utility::String::endsWith(filename, Utility::format("Profile{}.sav", _currentProfile->account()).data())) {
return;
}
event.user.code = action;
if(action == efsw::Actions::Moved) {
event.user.data2 = Containers::String{Containers::AllocatedInit, old_filename.c_str()}.release();
}
SDL_PushEvent(&event);
}
void SaveTool::fileUpdateEvent(SDL_Event& event) {
Containers::String filename{static_cast<char*>(event.user.data1),
std::strlen(static_cast<char*>(event.user.data1)), nullptr};
if((event.user.code & StagedUpdate) == StagedUpdate) {
_massManager->refreshStagedMass(filename);
return;
}
Containers::String old_filename;
Int index = 0;
Int old_index = 0;
bool is_current_profile = filename == _currentProfile->filename();
bool is_unit = filename.hasPrefix(_currentProfile->isDemo() ? "DemoUnit"_s : "Unit"_s);
if(is_unit) {
index = ((filename[_currentProfile->isDemo() ? 8 : 4] - 0x30) * 10) +
(filename[_currentProfile->isDemo() ? 9 : 5] - 0x30);
}
if(event.user.code == FileMoved) {
old_filename = Containers::String{static_cast<char*>(event.user.data2), std::strlen(static_cast<char*>(event.user.data2)), nullptr};
old_index = ((old_filename[_currentProfile->isDemo() ? 8 : 4] - 0x30) * 10) +
(old_filename[_currentProfile->isDemo() ? 9 : 5] - 0x30);
}
switch(event.user.code) {
case FileAdded:
if(is_unit) {
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
_massManager->refreshHangar(index);
}
else {
_currentMass->setDirty();
}
}
break;
case FileDeleted:
if(is_current_profile) {
_currentProfile = nullptr;
_uiState = UiState::ProfileManager;
if(!_profileManager->refreshProfiles()) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
_profileManager->lastError().data(), window());
exit(EXIT_FAILURE);
}
}
else if(is_unit) {
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
_massManager->refreshHangar(index);
}
}
break;
case FileModified:
if(is_current_profile) {
_currentProfile->refreshValues();
}
else if(is_unit) {
if(!_currentMass || _currentMass != &(_massManager->hangar(index))) {
_massManager->refreshHangar(index);
}
else {
if(_modifiedBySaveTool && _currentMass->filename() == filename) {
auto handle = CreateFileW(Utility::Unicode::widen(Containers::StringView{filename}), GENERIC_READ, 0,
nullptr, OPEN_EXISTING, 0, nullptr);
if(handle && handle != INVALID_HANDLE_VALUE) {
CloseHandle(handle);
_modifiedBySaveTool = false;
}
}
else {
_currentMass->setDirty();
}
}
}
break;
case FileMoved:
if(is_unit) {
if(old_filename.hasSuffix(".sav"_s)) {
_massManager->refreshHangar(index);
_massManager->refreshHangar(old_index);
}
}
break;
default:
_queue.addToast(Toast::Type::Warning, "Unknown file action type"_s);
}
}

View File

@ -1,280 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/Pair.h>
#include <Corrade/Containers/ScopeGuard.h>
#include <Corrade/Utility/Path.h>
#include <Corrade/Utility/Unicode.h>
#include <SDL_events.h>
#include <SDL_messagebox.h>
#include <shlobj.h>
#include "../FontAwesome/IconsFontAwesome5.h"
#include "../FontAwesome/IconsFontAwesome5Brands.h"
#include "../Logger/Logger.h"
#include "SaveTool.h"
void SaveTool::initEvent(SDL_Event& event) {
_initThread.join();
switch(event.user.code) {
case InitSuccess:
_uiState = UiState::ProfileManager;
ImGui::CloseCurrentPopup();
break;
case ProfileManagerFailure:
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error ",
_profileManager->lastError().data(), window());
exit(EXIT_FAILURE);
break;
default:
break;
}
}
void SaveTool::initialiseConfiguration() {
LOG_INFO("Reading configuration file.");
if(_conf.hasValue("cheat_mode"_s)) {
_cheatMode = _conf.value<bool>("cheat_mode"_s);
}
else {
_conf.setValue("cheat_mode"_s, _cheatMode);
}
if(_conf.hasValue("advanced_mode"_s)) {
_advancedMode = _conf.value<bool>("advanced_mode"_s);
}
else {
_conf.setValue("advanced_mode"_s, _advancedMode);
}
if(_conf.hasValue("startup_update_check"_s)) {
_checkUpdatesOnStartup = _conf.value<bool>("startup_update_check"_s);
}
else {
_conf.setValue("startup_update_check"_s, _checkUpdatesOnStartup);
}
if(_conf.hasValue("skip_disclaimer"_s)) {
_skipDisclaimer = _conf.value<bool>("skip_disclaimer"_s);
}
else {
_conf.setValue("skip_disclaimer"_s, _skipDisclaimer);
}
if(_conf.hasValue("swap_interval"_s)) {
_swapInterval = _conf.value<int>("swap_interval"_s);
}
else {
_conf.setValue("swap_interval"_s, 1);
}
if(_conf.hasValue("fps_cap"_s)) {
_fpsCap = _conf.value<float>("fps_cap");
}
else {
_conf.setValue("fps_cap", 60.0f);
}
if(_conf.hasValue("frame_limit"_s)) {
std::string frame_limit = _conf.value("frame_limit"_s);
if(frame_limit == "half_vsync"_s) {
_swapInterval = 2;
}
_conf.removeValue("frame_limit"_s);
}
setSwapInterval(_swapInterval);
if(_swapInterval == 0) {
setMinimalLoopPeriod(0);
}
_conf.save();
}
void SaveTool::initialiseGui() {
LOG_INFO("Initialising Dear ImGui.");
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
const auto size = Vector2{windowSize()}/dpiScaling();
auto reg_font = _rs.getRaw("SourceSansPro-Regular.ttf"_s);
ImFontConfig font_config;
font_config.FontDataOwnedByAtlas = false;
std::strcpy(font_config.Name, "Source Sans Pro");
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(reg_font.data()), int(reg_font.size()),
20.0f * Float(framebufferSize().x()) / size.x(), &font_config);
auto icon_font = _rs.getRaw(FONT_ICON_FILE_NAME_FAS);
static const ImWchar icon_range[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
ImFontConfig icon_config;
icon_config.FontDataOwnedByAtlas = false;
icon_config.MergeMode = true;
icon_config.PixelSnapH = true;
icon_config.OversampleH = icon_config.OversampleV = 1;
icon_config.GlyphMinAdvanceX = 18.0f;
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(icon_font.data()), int(icon_font.size()),
16.0f * Float(framebufferSize().x()) / size.x(), &icon_config, icon_range);
auto brand_font = _rs.getRaw(FONT_ICON_FILE_NAME_FAB);
static const ImWchar brand_range[] = { ICON_MIN_FAB, ICON_MAX_FAB, 0 };
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(brand_font.data()), int(brand_font.size()),
16.0f * Float(framebufferSize().x()) / size.x(), &icon_config, brand_range);
auto mono_font = _rs.getRaw("SourceCodePro-Regular.ttf"_s);
ImVector<ImWchar> range;
ImFontGlyphRangesBuilder builder;
builder.AddRanges(io.Fonts->GetGlyphRangesDefault());
builder.AddChar(u'š'); // This allows displaying Vladimír Vondruš' name in Corrade's and Magnum's licences.
builder.BuildRanges(&range);
io.Fonts->AddFontFromMemoryTTF(const_cast<char*>(mono_font.data()), int(mono_font.size()),
18.0f * Float(framebufferSize().x()) / size.x(), &font_config, range.Data);
_imgui = ImGuiIntegration::Context(*ImGui::GetCurrentContext(), windowSize());
io.IniFilename = nullptr;
ImGuiStyle& style = ImGui::GetStyle();
style.WindowTitleAlign = {0.5f, 0.5f};
style.FrameRounding = 3.2f;
style.Colors[ImGuiCol_WindowBg] = ImColor(0xff1f1f1f);
}
void SaveTool::initialiseManager() {
LOG_INFO("Initialising the profile manager.");
SDL_Event event;
SDL_zero(event);
event.type = _initEventId;
_profileManager.emplace(_saveDir, _backupsDir);
if(!_profileManager->ready()) {
event.user.code = ProfileManagerFailure;
SDL_PushEvent(&event);
return;
}
event.user.code = InitSuccess;
SDL_PushEvent(&event);
}
auto SaveTool::initialiseToolDirectories() -> bool {
LOG_INFO("Initialising Save Tool directories.");
_backupsDir = Utility::Path::join(Utility::Path::split(*Utility::Path::executableLocation()).first(), "backups");
_stagingDir = Utility::Path::join(Utility::Path::split(*Utility::Path::executableLocation()).first(), "staging");
//_armouryDir = Utility::Directory::join(Utility::Directory::path(Utility::Directory::executableLocation()), "armoury");
//_armoursDir = Utility::Directory::join(_armouryDir, "armours");
//_weaponsDir = Utility::Directory::join(_armouryDir, "weapons");
//_stylesDir = Utility::Directory::join(_armouryDir, "styles");
if(!Utility::Path::exists(_backupsDir)) {
LOG_WARNING("Backups directory not found, creating...");
if(!Utility::Path::make(_backupsDir)) {
LOG_ERROR(_lastError = "Couldn't create the backups directory.");
return false;
}
}
if(!Utility::Path::exists(_stagingDir)) {
LOG_WARNING("Staging directory not found, creating...");
if(!Utility::Path::make(_stagingDir)) {
LOG_ERROR(_lastError = "Couldn't create the staging directory.");
return false;
}
}
//if(!Utility::Directory::exists(_armouryDir)) {
// Utility::Debug{} << "Armoury directory not found, creating...";
// if(!Utility::Path::make(_armouryDir)) {
// Utility::Error{} << (_lastError = "Couldn't create the armoury directory.");
// return false;
// }
//}
//if(!Utility::Directory::exists(_armoursDir)) {
// Utility::Debug{} << "Armours directory not found, creating...";
// if(!Utility::Path::make(_armoursDir)) {
// Utility::Error{} << (_lastError = "Couldn't create the armours directory.");
// return false;
// }
//}
//if(!Utility::Directory::exists(_weaponsDir)) {
// Utility::Debug{} << "Weapons directory not found, creating...";
// if(!Utility::Path::make(_weaponsDir)) {
// Utility::Error{} << (_lastError = "Couldn't create the weapons directory.");
// return false;
// }
//}
//if(!Utility::Directory::exists(_stylesDir)) {
// Utility::Debug{} << "Styles directory not found, creating...";
// if(!Utility::Path::make(_stylesDir)) {
// Utility::Error{} << (_lastError = "Couldn't create the styles directory.");
// return false;
// }
//}
return true;
}
auto SaveTool::findGameDataDirectory() -> bool {
LOG_INFO("Searching for the game's save directory.");
wchar_t* localappdata_path = nullptr;
Containers::ScopeGuard guard{localappdata_path, CoTaskMemFree};
if(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_NO_APPCONTAINER_REDIRECTION, nullptr, &localappdata_path) != S_OK)
{
_lastError = Utility::format("SHGetKnownFolderPath() failed with error code {}.", GetLastError());
LOG_ERROR(_lastError);
return false;
}
_gameDataDir = Utility::Path::join(Utility::Path::fromNativeSeparators(Utility::Unicode::narrow(localappdata_path)), "MASS_Builder"_s);
if(!Utility::Path::exists(_gameDataDir)) {
LOG_ERROR(_lastError = _gameDataDir + " wasn't found. Make sure to play the game at least once."_s);
return false;
}
_configDir = Utility::Path::join(_gameDataDir, "Saved/Config/WindowsNoEditor"_s);
_saveDir = Utility::Path::join(_gameDataDir, "Saved/SaveGames"_s);
_screenshotsDir = Utility::Path::join(_gameDataDir, "Saved/Screenshots/WindowsNoEditor"_s);
return true;
}
void SaveTool::initialiseMassManager() {
LOG_INFO("Initialising the M.A.S.S. manager.");
_massManager.emplace(_saveDir, _currentProfile->account(), _currentProfile->isDemo(), _stagingDir);
}
void SaveTool::initialiseFileWatcher() {
LOG_INFO("Initialising the file watcher.");
_fileWatcher.emplace();
_watchIDs[SaveDir] = _fileWatcher->addWatch(_saveDir, this, false);
_watchIDs[StagingDir] = _fileWatcher->addWatch(_stagingDir, this, false);
_fileWatcher->watch();
}

View File

@ -14,18 +14,21 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "SaveTool.h"
#include <algorithm> #include <algorithm>
#include <Corrade/Utility/Format.h> #include <Corrade/Containers/Reference.h>
#include <Corrade/Utility/Path.h> #include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/FormatStl.h>
#include <SDL_messagebox.h> #include <Corrade/Utility/String.h>
#include "../FontAwesome/IconsFontAwesome5.h" #include "../FontAwesome/IconsFontAwesome5.h"
#include "../Maps/LastMissionId.h" #include "../Maps/LastMissionId.h"
#include "../Maps/StoryProgress.h" #include "../Maps/StoryProgress.h"
#include "SaveTool.h" static const std::string empty_str;
void SaveTool::drawManager() { void SaveTool::drawManager() {
ImGui::SetNextWindowPos({0.0f, ImGui::GetItemRectSize().y}, ImGuiCond_Always); ImGui::SetNextWindowPos({0.0f, ImGui::GetItemRectSize().y}, ImGuiCond_Always);
@ -40,8 +43,8 @@ void SaveTool::drawManager() {
} }
drawAlignedText("Current profile: %s (%s)", drawAlignedText("Current profile: %s (%s)",
_currentProfile->companyName().data(), _currentProfile->companyName().c_str(),
_currentProfile->isDemo() ? "demo" : "full game"); _currentProfile->type() == ProfileType::Demo ? "demo" : "full game");
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button(ICON_FA_ARROW_LEFT " Back to profile manager")) { if(ImGui::Button(ICON_FA_ARROW_LEFT " Back to profile manager")) {
_currentProfile = nullptr; _currentProfile = nullptr;
@ -51,7 +54,7 @@ void SaveTool::drawManager() {
} }
if(ImGui::BeginChild("##ProfileInfo", if(ImGui::BeginChild("##ProfileInfo",
{ImGui::GetContentRegionAvail().x * 0.60f, 0.0f}, {ImGui::GetContentRegionAvailWidth() * 0.60f, 0.0f},
true, ImGuiWindowFlags_MenuBar)) true, ImGuiWindowFlags_MenuBar))
{ {
if(ImGui::BeginMenuBar()) { if(ImGui::BeginMenuBar()) {
@ -145,11 +148,12 @@ auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
callback, nullptr); callback, nullptr);
ImGui::SameLine(); ImGui::SameLine();
GameState game_state = _gameState; GameState game_state = _gameState;
if(game_state != GameState::NotRunning || if((!_unsafeMode && game_state != GameState::NotRunning) ||
!(len >= 6 && len <= 32) || !(len >= 6 && len <= 32) ||
!(name_view[0] != ' ' && name_view[len - 1] != ' ')) !(name_view[0] != ' ' && name_view[len - 1] != ' '))
{ {
ImGui::BeginDisabled(); ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5f);
} }
if(ImGui::Button("Apply")) { if(ImGui::Button("Apply")) {
@ -157,11 +161,12 @@ auto SaveTool::drawRenamePopup(Containers::ArrayView<char> name_view) -> bool {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
if(game_state != GameState::NotRunning || if((!_unsafeMode && game_state != GameState::NotRunning) ||
!(len >= 6 && len <= 32) || !(len >= 6 && len <= 32) ||
!(name_view[0] != ' ' && name_view[len - 1] != ' ')) !(name_view[0] != ' ' && name_view[len - 1] != ' '))
{ {
ImGui::EndDisabled(); ImGui::PopItemFlag();
ImGui::PopStyleVar();
} }
ImGui::EndPopup(); ImGui::EndPopup();
@ -183,10 +188,10 @@ void SaveTool::drawGeneralInfo() {
ImGui::TextUnformatted("Story progress:"); ImGui::TextUnformatted("Story progress:");
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.x / 4.0f); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.x / 4.0f);
if(!it->after) { if(!it->after) {
ImGui::TextWrapped("%s - %s", it->chapter.data(), it->point.data()); ImGui::TextWrapped("%s - %s", it->chapter, it->point);
} }
else { else {
ImGui::TextWrapped("%s - %s - %s", it->chapter.data(), it->after.data(), it->point.data()); ImGui::TextWrapped("%s - %s - %s", it->chapter, it->after, it->point);
} }
} }
else { else {
@ -194,7 +199,7 @@ void SaveTool::drawGeneralInfo() {
} }
if(mission_id_map.find(_currentProfile->lastMissionId()) != mission_id_map.cend()) { if(mission_id_map.find(_currentProfile->lastMissionId()) != mission_id_map.cend()) {
ImGui::Text("Last mission: %s", mission_id_map.at(_currentProfile->lastMissionId()).data()); ImGui::Text("Last mission: %s", mission_id_map.at(_currentProfile->lastMissionId()));
} }
else if(_currentProfile->lastMissionId() == -1) { else if(_currentProfile->lastMissionId() == -1) {
ImGui::TextUnformatted("Last mission: none"); ImGui::TextUnformatted("Last mission: none");
@ -203,7 +208,7 @@ void SaveTool::drawGeneralInfo() {
ImGui::Text("Last mission: 0x%x", _currentProfile->lastMissionId()); ImGui::Text("Last mission: 0x%x", _currentProfile->lastMissionId());
} }
drawTooltip("This is the last mission selected in the mission selection screen, not the last mission played.", drawTooltip("This is the last mission selected in the mission selection screen, not the last mission played.",
float(windowSize().x()) * 0.35f); windowSize().x() * 0.35f);
const Float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing(); const Float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
ImGui::Dummy({ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - footer_height_to_reserve}); ImGui::Dummy({ImGui::GetContentRegionAvail().x, ImGui::GetContentRegionAvail().y - footer_height_to_reserve});
@ -215,7 +220,7 @@ void SaveTool::drawGeneralInfo() {
for(auto& c : name_buf) { for(auto& c : name_buf) {
c = '\0'; c = '\0';
} }
std::strncpy(name_buf.data(), _currentProfile->companyName().data(), 32); std::strncpy(name_buf.data(), _currentProfile->companyName().c_str(), 32);
ImGui::OpenPopup("name_edit"); ImGui::OpenPopup("name_edit");
} }
if(drawRenamePopup(name_buf)) { if(drawRenamePopup(name_buf)) {
@ -248,21 +253,21 @@ void SaveTool::drawGeneralInfo() {
} }
drawTooltip("Story progress directly affects unlocked levels."); drawTooltip("Story progress directly affects unlocked levels.");
if(ImGui::BeginPopup("StoryProgressMenu")) { if(ImGui::BeginPopup("StoryProgressMenu")) {
if(_gameState != GameState::NotRunning) { if(!_unsafeMode && _gameState != GameState::NotRunning) {
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
for(const auto& sp : story_progress) { for(const auto& sp : story_progress) {
if(ImGui::BeginMenu(sp.chapter.data())) { if(ImGui::BeginMenu(sp.chapter)) {
if(!sp.after) { if(!sp.after) {
if(ImGui::MenuItem(sp.point.data())) { if(ImGui::MenuItem(sp.point)) {
if(!_currentProfile->setStoryProgress(sp.id)) { if(!_currentProfile->setStoryProgress(sp.id)) {
_queue.addToast(Toast::Type::Error, _currentProfile->lastError()); _queue.addToast(Toast::Type::Error, _currentProfile->lastError());
} }
} }
} }
else { else {
if(ImGui::BeginMenu(sp.after.data())) { if(ImGui::BeginMenu(sp.after)) {
if(ImGui::MenuItem(sp.point.data())) { if(ImGui::MenuItem(sp.point)) {
if(!_currentProfile->setStoryProgress(sp.id)) { if(!_currentProfile->setStoryProgress(sp.id)) {
_queue.addToast(Toast::Type::Error, _currentProfile->lastError()); _queue.addToast(Toast::Type::Error, _currentProfile->lastError());
} }
@ -309,9 +314,7 @@ void SaveTool::drawResearchInventory() {
drawMaterialRow("Asterite", 5, drawMaterialRow("Asterite", 5,
[this]{ return _currentProfile->asterite(); }, [this]{ return _currentProfile->asterite(); },
[this](Int amount){ return _currentProfile->setAsterite(amount); }); [this](Int amount){ return _currentProfile->setAsterite(amount); });
drawMaterialRow("Hallite fragma", 6, drawUnavailableMaterialRow("Hallite fragma", 6);
[this]{ return _currentProfile->halliteFragma(); },
[this](Int amount){ return _currentProfile->setHalliteFragma(amount); });
drawUnavailableMaterialRow("Unnoctinium", 7); drawUnavailableMaterialRow("Unnoctinium", 7);
ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
@ -333,9 +336,7 @@ void SaveTool::drawResearchInventory() {
drawMaterialRow("Synthesized N", 5, drawMaterialRow("Synthesized N", 5,
[this]{ return _currentProfile->synthesisedN(); }, [this]{ return _currentProfile->synthesisedN(); },
[this](Int amount){ return _currentProfile->setSynthesisedN(amount); }); [this](Int amount){ return _currentProfile->setSynthesisedN(amount); });
drawMaterialRow("Nanoc", 6, drawUnavailableMaterialRow("Nanoc", 6);
[this]{ return _currentProfile->nanoc(); },
[this](Int amount){ return _currentProfile->setNanoc(amount); });
drawUnavailableMaterialRow("Abyssillite", 7); drawUnavailableMaterialRow("Abyssillite", 7);
ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
@ -357,9 +358,7 @@ void SaveTool::drawResearchInventory() {
drawMaterialRow("Alterene", 5, drawMaterialRow("Alterene", 5,
[this]{ return _currentProfile->alterene(); }, [this]{ return _currentProfile->alterene(); },
[this](Int amount){ return _currentProfile->setAlterene(amount); }); [this](Int amount){ return _currentProfile->setAlterene(amount); });
drawMaterialRow("Cosmium", 6, drawUnavailableMaterialRow("Cosmium", 6);
[this]{ return _currentProfile->cosmium(); },
[this](Int amount){ return _currentProfile->setCosmium(amount); });
drawUnavailableMaterialRow("Purified quarkium", 7); drawUnavailableMaterialRow("Purified quarkium", 7);
ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
@ -381,9 +380,7 @@ void SaveTool::drawResearchInventory() {
drawMaterialRow("Carbonized skin", 5, drawMaterialRow("Carbonized skin", 5,
[this]{ return _currentProfile->carbonisedSkin(); }, [this]{ return _currentProfile->carbonisedSkin(); },
[this](Int amount){ return _currentProfile->setCarbonisedSkin(amount); }); [this](Int amount){ return _currentProfile->setCarbonisedSkin(amount); });
drawMaterialRow("Isolated void particle", 6, drawUnavailableMaterialRow("Isolated void particle", 6);
[this]{ return _currentProfile->isolatedVoidParticle(); },
[this](Int amount){ return _currentProfile->setIsolatedVoidParticle(amount); });
drawUnavailableMaterialRow("Weaponised physiology", 7); drawUnavailableMaterialRow("Weaponised physiology", 7);
ImGui::EndTable(); ImGui::EndTable();
@ -391,7 +388,7 @@ void SaveTool::drawResearchInventory() {
} }
template<typename Getter, typename Setter> template<typename Getter, typename Setter>
void SaveTool::drawMaterialRow(Containers::StringView name, Int tier, Getter getter, Setter setter) { void SaveTool::drawMaterialRow(const char* 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(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."); 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.");
@ -399,19 +396,18 @@ void SaveTool::drawMaterialRow(Containers::StringView name, Int tier, Getter get
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
ImGui::Text("T%i", tier); ImGui::Text("T%i", tier);
ImGui::TableSetColumnIndex(1); ImGui::TableSetColumnIndex(1);
ImGui::TextUnformatted(name.data()); ImGui::TextUnformatted(name);
ImGui::TableSetColumnIndex(2); ImGui::TableSetColumnIndex(2);
if(getter() != -1) { if(getter() != -1) {
ImGui::Text("%i", getter()); ImGui::Text("%i", getter());
if(_cheatMode) { if(_cheatMode) {
ImGui::TableSetColumnIndex(3); ImGui::TableSetColumnIndex(3);
ImGui::PushID(name.data()); ImGui::PushID(name);
static Int var = 0; static Int var = 0;
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_EDIT)) { if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_EDIT)) {
(var) = getter(); (var) = getter();
ImGui::OpenPopup("int_edit"); ImGui::OpenPopup("int_edit");
} }
drawTooltip("Edit");
if(drawIntEditPopup(&(var), 9999)) { if(drawIntEditPopup(&(var), 9999)) {
if(!setter(var)) { if(!setter(var)) {
_queue.addToast(Toast::Type::Error, _currentProfile->lastError()); _queue.addToast(Toast::Type::Error, _currentProfile->lastError());
@ -425,12 +421,12 @@ void SaveTool::drawMaterialRow(Containers::StringView name, Int tier, Getter get
} }
} }
void SaveTool::drawUnavailableMaterialRow(Containers::StringView name, Int tier) { void SaveTool::drawUnavailableMaterialRow(const char* name, Int tier) {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
ImGui::Text("T%i", tier); ImGui::Text("T%i", tier);
ImGui::TableSetColumnIndex(1); ImGui::TableSetColumnIndex(1);
ImGui::TextUnformatted(name.data()); ImGui::TextUnformatted(name);
ImGui::TableSetColumnIndex(2); ImGui::TableSetColumnIndex(2);
ImGui::TextDisabled("Unavailable as of game version " SUPPORTED_GAME_VERSION); ImGui::TextDisabled("Unavailable as of game version " SUPPORTED_GAME_VERSION);
} }
@ -468,7 +464,7 @@ void SaveTool::drawMassManager() {
static int drag_drop_index = 0; static int drag_drop_index = 0;
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
ImGui::Selectable(Utility::format("{:.2d}", i + 1).data(), ImGui::Selectable(Utility::formatString("{:.2d}", i + 1).c_str(),
false, ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_AllowItemOverlap); false, ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_AllowItemOverlap);
if(_massManager->hangar(i).state() == Mass::State::Valid && if(_massManager->hangar(i).state() == Mass::State::Valid &&
ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoHoldToOpenOthers))
@ -476,20 +472,20 @@ void SaveTool::drawMassManager() {
drag_drop_index = i; drag_drop_index = i;
ImGui::SetDragDropPayload("Mass", &drag_drop_index, sizeof(int)); ImGui::SetDragDropPayload("Mass", &drag_drop_index, sizeof(int));
ImGui::Text("%s - Hangar %.2d", _massManager->hangar(i).name().data(), i + 1); ImGui::Text("%s - Hangar %.2d", (*_massManager->hangar(i).name()).c_str(), i + 1);
ImGui::EndDragDropSource(); ImGui::EndDragDropSource();
} }
if(_gameState == GameState::NotRunning && ImGui::BeginDragDropTarget()) { if((_unsafeMode || _gameState == GameState::NotRunning) && ImGui::BeginDragDropTarget()) {
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("StagedMass")) { if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("StagedMass")) {
if(payload->DataSize != sizeof(Containers::String)) { if(payload->DataSize != sizeof(std::string)) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error", SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal error",
"payload->DataSize != sizeof(Containers::String) in SaveTool::drawMassManager()", "payload->DataSize != sizeof(std::string) in SaveTool::drawMassManager()",
window()); window());
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
Containers::StringView file = *static_cast<Containers::String*>(payload->Data); std::string file = *(static_cast<std::string*>(payload->Data));
if(!_massManager->importMass(file, i)) { if(!_massManager->importMass(file, i)) {
_queue.addToast(Toast::Type::Error, _massManager->lastError()); _queue.addToast(Toast::Type::Error, _massManager->lastError());
@ -522,7 +518,7 @@ void SaveTool::drawMassManager() {
ImGui::TextDisabled("<invalid>"); ImGui::TextDisabled("<invalid>");
break; break;
case Mass::State::Valid: case Mass::State::Valid:
ImGui::TextUnformatted(_massManager->hangar(i).name().data()); ImGui::TextUnformatted((*_massManager->hangar(i).name()).c_str());
break; break;
} }
@ -540,19 +536,17 @@ void SaveTool::drawMassManager() {
_currentMass = &_massManager->hangar(i); _currentMass = &_massManager->hangar(i);
_uiState = UiState::MassViewer; _uiState = UiState::MassViewer;
} }
drawTooltip("Open in M.A.S.S. editor"); ImGui::SameLine(0.0f, 2.0f);
} }
else{ else{
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.0f);
ImGui::SmallButton(ICON_FA_SEARCH); ImGui::SmallButton(ICON_FA_SEARCH);
ImGui::PopStyleVar(); ImGui::PopStyleVar();
} }
ImGui::SameLine(0.0f, 2.0f);
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) { if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) {
mass_to_delete = i; mass_to_delete = i;
ImGui::OpenPopup(mass_deletion_popup_ID); ImGui::OpenPopup(mass_deletion_popup_ID);
} }
drawTooltip("Delete");
ImGui::PopID(); ImGui::PopID();
} }
} }
@ -563,7 +557,7 @@ void SaveTool::drawMassManager() {
drawDeleteMassPopup(mass_to_delete); drawDeleteMassPopup(mass_to_delete);
static ImGuiID staged_mass_deletion_popup_ID = drawDeleteStagedMassPopup(""); static ImGuiID staged_mass_deletion_popup_ID = drawDeleteStagedMassPopup("");
static Containers::StringView staged_mass_to_delete; static Containers::Reference<const std::string> staged_mass_to_delete{empty_str};
if(ImGui::BeginTable("##StagingArea", 2, if(ImGui::BeginTable("##StagingArea", 2,
ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_RowBg)) ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_RowBg))
@ -579,32 +573,31 @@ void SaveTool::drawMassManager() {
ImGui::TextUnformatted("Staging area"); ImGui::TextUnformatted("Staging area");
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::SmallButton(ICON_FA_FOLDER_OPEN " Open staging folder")) { if(ImGui::SmallButton(ICON_FA_FOLDER_OPEN " Open staging folder")) {
openUri(Utility::Path::toNativeSeparators(_stagingDir)); openUri(Utility::Directory::toNativeSeparators(_stagingDir));
} }
for(const auto& pair : _massManager->stagedMasses()) { for(const auto& pair : _massManager->stagedMasses()) {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
Containers::String staged_formatted = Utility::format("{} ({})", pair.second, pair.first); std::string staged_formatted = Utility::formatString("{} ({})", pair.second, pair.first);
ImGui::Selectable(staged_formatted.data()); ImGui::Selectable(staged_formatted.c_str());
if((ImGui::CalcTextSize(staged_formatted.data()).x + ImGui::GetStyle().FramePadding.x) > ImGui::GetContentRegionAvail().x) { if((ImGui::CalcTextSize(staged_formatted.c_str()).x + ImGui::GetStyle().FramePadding.x) > ImGui::GetContentRegionAvailWidth()) {
drawTooltip(staged_formatted.data()); drawTooltip(staged_formatted.c_str());
} }
if(ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) { if(ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceNoHoldToOpenOthers)) {
ImGui::SetDragDropPayload("StagedMass", &(pair.first), sizeof(Containers::String)); ImGui::SetDragDropPayload("StagedMass", &(pair.first), sizeof(std::string));
ImGui::Text("%s - Staged", pair.second.data()); ImGui::Text("%s - Staged", pair.second.c_str());
ImGui::EndDragDropSource(); ImGui::EndDragDropSource();
} }
ImGui::TableSetColumnIndex(1); ImGui::TableSetColumnIndex(1);
ImGui::PushID(pair.first.data()); ImGui::PushID(pair.first.c_str());
if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) { if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) {
staged_mass_to_delete = pair.first; staged_mass_to_delete = Containers::Reference<const std::string>{pair.first};
ImGui::OpenPopup(staged_mass_deletion_popup_ID); ImGui::OpenPopup(staged_mass_deletion_popup_ID);
} }
drawTooltip("Delete");
ImGui::PopID(); ImGui::PopID();
} }
@ -629,7 +622,7 @@ void SaveTool::drawMassManager() {
ImGui::EndDragDropTarget(); ImGui::EndDragDropTarget();
} }
drawDeleteStagedMassPopup(staged_mass_to_delete); drawDeleteStagedMassPopup(staged_mass_to_delete.get());
} }
auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID { auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID {
@ -651,14 +644,14 @@ auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID {
return 0; return 0;
} }
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f); ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
if(_massManager->hangar(mass_index).state() == Mass::State::Invalid) { if(_massManager->hangar(mass_index).state() == Mass::State::Invalid) {
ImGui::Text("Are you sure you want to delete the invalid M.A.S.S. data in hangar %.2i ? This operation is irreversible.", ImGui::Text("Are you sure you want to delete the invalid M.A.S.S. data in hangar %.2i ? This operation is irreversible.",
mass_index + 1); mass_index + 1);
} }
else { else {
ImGui::Text("Are you sure you want to delete the M.A.S.S. named %s in hangar %.2i ? This operation is irreversible.", ImGui::Text("Are you sure you want to delete the M.A.S.S. named %s in hangar %.2i ? This operation is irreversible.",
_massManager->hangar(mass_index).name().data(), mass_index + 1); (*_massManager->hangar(mass_index).name()).c_str(), mass_index + 1);
} }
ImGui::PopTextWrapPos(); ImGui::PopTextWrapPos();
@ -688,16 +681,16 @@ auto SaveTool::drawDeleteMassPopup(int mass_index) -> ImGuiID {
return 0; return 0;
} }
auto SaveTool::drawDeleteStagedMassPopup(Containers::StringView filename) -> ImGuiID { auto SaveTool::drawDeleteStagedMassPopup(const std::string& filename) -> ImGuiID {
if(!ImGui::BeginPopupModal("Confirmation##DeleteStagedMassConfirmation", nullptr, if(!ImGui::BeginPopupModal("Confirmation##DeleteStagedMassConfirmation", nullptr,
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove)) ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove))
{ {
return ImGui::GetID("Confirmation##DeleteStagedMassConfirmation"); return ImGui::GetID("Confirmation##DeleteStagedMassConfirmation");
} }
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f); ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
ImGui::Text("Are you sure you want to delete the staged M.A.S.S. named %s ? This operation is irreversible.", ImGui::Text("Are you sure you want to delete the staged M.A.S.S. named %s ? This operation is irreversible.",
_massManager->stagedMasses().at(filename).data()); _massManager->stagedMasses().at(filename).c_str());
ImGui::PopTextWrapPos(); ImGui::PopTextWrapPos();
if(ImGui::BeginTable("##DeleteStagedMassLayout", 2)) { if(ImGui::BeginTable("##DeleteStagedMassLayout", 2)) {

View File

@ -15,15 +15,16 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/ScopeGuard.h> #include <Corrade/Containers/ScopeGuard.h>
#include <Corrade/Utility/Format.h>
#include <Magnum/ImGuiIntegration/Integration.h> #include <Magnum/ImGuiIntegration/Integration.h>
#include "../FontAwesome/IconsFontAwesome5.h"
#include "../Maps/Accessories.h" #include "../Maps/Accessories.h"
#define STYLENAMES_DEFINITION #define STYLENAMES_DEFINITION
#include "../Maps/StyleNames.h" #include "../Maps/StyleNames.h"
#include "../FontAwesome/IconsFontAwesome5.h"
#include "SaveTool.h" #include "SaveTool.h"
void SaveTool::drawMassViewer() { void SaveTool::drawMassViewer() {
@ -60,8 +61,8 @@ void SaveTool::drawMassViewer() {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
ImGui::Text("M.A.S.S.: %s", _currentMass->name().data()); ImGui::Text("M.A.S.S.: %s", (*_currentMass->name()).c_str());
drawTooltip(_currentMass->filename()); drawTooltip(_currentMass->filename().c_str());
ImGui::TableSetColumnIndex(2); ImGui::TableSetColumnIndex(2);
if(_currentMass->dirty()) { if(_currentMass->dirty()) {
@ -86,11 +87,10 @@ void SaveTool::drawMassViewer() {
_eyeFlareDirty = false; _eyeFlareDirty = false;
_selectedArmourDecals = Containers::StaticArray<38, Int>{ValueInit}; _selectedArmourDecals = Containers::StaticArray<38, Int>{ValueInit};
_selectedArmourAccessories = Containers::StaticArray<38, Int>{ValueInit}; _selectedArmourAccessories = Containers::StaticArray<38, Int>{ValueInit};
_selectedBLPlacement = 0;
_selectedWeaponPart = 0; _selectedWeaponPart = 0;
_selectedWeaponDecal = 0; _selectedWeaponDecal = 0;
_selectedWeaponAccessory = 0; _selectedWeaponAccessory = 0;
} };
ImGui::EndTable(); ImGui::EndTable();
} }
@ -117,7 +117,7 @@ void SaveTool::drawMassViewer() {
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
if(ImGui::BeginTabItem("Armour")) { if(ImGui::BeginTabItem("Armour parts")) {
drawArmour(); drawArmour();
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
@ -127,7 +127,7 @@ void SaveTool::drawMassViewer() {
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
if(ImGui::BeginTabItem("Weapons")) { if(ImGui::BeginTabItem("Weapons (WIP)")) {
drawWeapons(); drawWeapons();
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
@ -137,12 +137,10 @@ void SaveTool::drawMassViewer() {
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
#ifdef SAVETOOL_DEBUG_BUILD
if(ImGui::BeginTabItem("Tuning (WIP)")) { if(ImGui::BeginTabItem("Tuning (WIP)")) {
drawTuning(); drawTuning();
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
#endif
ImGui::EndTabBar(); ImGui::EndTabBar();
} }
@ -166,7 +164,7 @@ void SaveTool::drawGlobalStyles() {
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game."); ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
for(UnsignedInt i = 0; i < _currentMass->globalStyles().size(); i++) { for(UnsignedInt i = 0; i < _currentMass->globalStyles().size(); i++) {
ImGui::PushID(int(i)); ImGui::PushID(i);
DCSResult result; DCSResult result;
result = drawCustomStyle(_currentMass->globalStyles()[i]); result = drawCustomStyle(_currentMass->globalStyles()[i]);
switch(result) { switch(result) {
@ -174,9 +172,7 @@ void SaveTool::drawGlobalStyles() {
_currentMass->getGlobalStyles(); _currentMass->getGlobalStyles();
break; break;
case DCS_Save: case DCS_Save:
_modifiedBySaveTool = true;
if(!_currentMass->writeGlobalStyle(i)) { if(!_currentMass->writeGlobalStyle(i)) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
break; break;
@ -302,14 +298,14 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
} }
if(ImGui::BeginMenuBar()) { if(ImGui::BeginMenuBar()) {
ImGui::TextUnformatted(style.name.data()); ImGui::TextUnformatted(style.name.c_str());
static Containers::StaticArray<33, char> name_buf{ValueInit}; static Containers::StaticArray<33, char> name_buf{ValueInit};
if(ImGui::SmallButton(ICON_FA_EDIT " Rename")) { if(ImGui::SmallButton(ICON_FA_EDIT " Rename")) {
for(auto& c : name_buf) { for(auto& c : name_buf) {
c = '\0'; c = '\0';
} }
std::strncpy(name_buf.data(), style.name.data(), 32); std::strncpy(name_buf.data(), style.name.c_str(), 32);
ImGui::OpenPopup("name_edit"); ImGui::OpenPopup("name_edit");
} }
if(drawRenamePopup(name_buf)) { if(drawRenamePopup(name_buf)) {
@ -393,12 +389,9 @@ auto SaveTool::drawCustomStyle(CustomStyle& style) -> DCSResult {
void SaveTool::drawDecalEditor(Decal& decal) { void SaveTool::drawDecalEditor(Decal& decal) {
ImGui::Text("ID: %i", decal.id); ImGui::Text("ID: %i", decal.id);
if(ImGui::BeginTable("##DecalTable", _advancedMode ? 2 : 1, ImGuiTableFlags_BordersInnerV)) { if(ImGui::BeginTable("##DecalTable", 2, ImGuiTableFlags_BordersInnerV)) {
ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("##Normal", ImGuiTableColumnFlags_WidthStretch);
if(_advancedMode) {
ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch); ImGui::TableSetupColumn("##Advanced", ImGuiTableColumnFlags_WidthStretch);
}
ImGui::TableNextRow(); ImGui::TableNextRow();
@ -442,7 +435,7 @@ void SaveTool::drawDecalEditor(Decal& decal) {
ImGui::Checkbox("##Wrap", &decal.wrap); ImGui::Checkbox("##Wrap", &decal.wrap);
ImGui::EndGroup(); ImGui::EndGroup();
if(_advancedMode) {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE); ImGui::TextColored(ImColor(255, 255, 0), ICON_FA_EXCLAMATION_TRIANGLE);
@ -488,7 +481,6 @@ void SaveTool::drawDecalEditor(Decal& decal) {
ImGui::DragFloat("##VZ", &decal.vAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f"); ImGui::DragFloat("##VZ", &decal.vAxis.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::EndGroup(); ImGui::EndGroup();
}
ImGui::EndTable(); ImGui::EndTable();
} }
@ -499,149 +491,23 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
ImGui::TextUnformatted("Accessory: <none>"); ImGui::TextUnformatted("Accessory: <none>");
} }
else if(accessories.find(accessory.id) != accessories.cend()) { else if(accessories.find(accessory.id) != accessories.cend()) {
ImGui::Text("Accessory #%.4i - %s", accessory.id, accessories.at(accessory.id).name.data()); ImGui::Text("Accessory #%i - %s", accessory.id, accessories.at(accessory.id));
} }
else { else {
ImGui::Text("Accessory #%i", accessory.id); ImGui::Text("Accessory #%i", accessory.id);
drawTooltip("WARNING: accessory mapping is a WIP."); drawTooltip("WARNING: accessory mapping is a WIP.");
} }
ImGui::SameLine(); #ifdef SAVETOOL_DEBUG_BUILD
ImGui::SameLine(0.0f, ImGui::GetStyle().FramePadding.x * 5.0f);
static Int tab = 0; ImGui::Text("Attach index: %i", accessory.attachIndex);
static Containers::Optional<AccessorySize> size = Containers::NullOpt; #endif
if(ImGui::SmallButton("Change")) {
ImGui::OpenPopup("##AccessoryPopup");
if(accessory.id >= 3000) {
tab = 3;
}
else if(accessory.id >= 2000) {
tab = 2;
}
else if(accessory.id >= 1000) {
tab = 1;
}
else {
tab = 0;
}
}
if(ImGui::BeginPopup("##AccessoryPopup")) {
static const char* size_labels[] = {
"S",
"M",
"L",
"XL"
};
static const Float selectable_width = 90.0f;
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
if(ImGui::Selectable("Primitives", tab == 0, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
tab = 0;
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
if(ImGui::Selectable("Armours", tab == 1, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
tab = 1;
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
if(ImGui::Selectable("Components", tab == 2, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
tab = 2;
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
if(ImGui::Selectable("Connectors", tab == 3, ImGuiSelectableFlags_DontClosePopups, {selectable_width, 0.0f})) {
tab = 3;
}
ImGui::PopStyleVar();
ImGui::Separator();
ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, {0.5f, 0.0f});
if(ImGui::Selectable("All", !size, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
size = Containers::NullOpt;
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
if(ImGui::Selectable("S", size && *size == AccessorySize::S, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
if(!size) {
size.emplace();
}
*size = AccessorySize::S;
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
if(ImGui::Selectable("M", size && *size == AccessorySize::M, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
if(!size) {
size.emplace();
}
*size = AccessorySize::M;
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
if(ImGui::Selectable("L", size && *size == AccessorySize::L, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
if(!size) {
size.emplace();
}
*size = AccessorySize::L;
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
if(ImGui::Selectable("XL", size && *size == AccessorySize::XL, ImGuiSelectableFlags_DontClosePopups, {70.0f, 0.0f})) {
if(!size) {
size.emplace();
}
*size = AccessorySize::XL;
}
ImGui::PopStyleVar();
ImGui::Separator();
if(ImGui::BeginListBox("##AccessoryListbox", {-1.0f, 0.0f})) {
for(const auto& acc : accessories) {
if(acc.first >= tab * 1000 && acc.first < ((tab + 1) * 1000) && (!size || *size == acc.second.size)) {
if(ImGui::Selectable(Utility::format("#{:.4d} - {} ({})", acc.first, acc.second.name, size_labels[acc.second.size]).data(),
acc.first == accessory.id))
{
accessory.id = acc.first;
accessory.attachIndex = 0;
}
if(acc.first == accessory.id) {
ImGui::SetItemDefaultFocus();
}
}
}
ImGui::EndListBox();
}
ImGui::EndPopup();
}
if(accessory.id > 0) {
ImGui::SameLine();
if(ImGui::SmallButton("Unequip")) {
accessory.id = 0;
accessory.attachIndex = -1;
}
}
ImGui::BeginGroup(); ImGui::BeginGroup();
drawAlignedText("Styles:"); drawAlignedText("Styles:");
if(_advancedMode) {
drawAlignedText("Base position:"); drawAlignedText("Base position:");
}
drawAlignedText("Position offset:"); drawAlignedText("Position offset:");
if(_advancedMode) {
drawAlignedText("Base rotation:"); drawAlignedText("Base rotation:");
}
drawAlignedText("Rotation offset:"); drawAlignedText("Rotation offset:");
drawAlignedText("Scale:"); drawAlignedText("Scale:");
ImGui::EndGroup(); ImGui::EndGroup();
@ -650,9 +516,9 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
ImGui::BeginGroup(); ImGui::BeginGroup();
ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth()); ImGui::PushMultiItemsWidths(2, ImGui::CalcItemWidth());
if(ImGui::BeginCombo("##Style1", getStyleName(accessory.styles[0], style_view).data())) { if(ImGui::BeginCombo("##Style1", getStyleName(accessory.styles[0], style_view))) {
for(const auto& style : style_names) { for(const auto& style : style_names) {
if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[0] == style.first)) { if(ImGui::Selectable(getStyleName(style.first, style_view), accessory.styles[0] == style.first)) {
accessory.styles[0] = style.first; accessory.styles[0] = style.first;
} }
} }
@ -661,9 +527,9 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
} }
ImGui::PopItemWidth(); ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
if(ImGui::BeginCombo("##Style2", getStyleName(accessory.styles[1], style_view).data())) { if(ImGui::BeginCombo("##Style2", getStyleName(accessory.styles[1], style_view))) {
for(const auto& style : style_names) { for(const auto& style : style_names) {
if(ImGui::Selectable(getStyleName(style.first, style_view).data(), accessory.styles[1] == style.first)) { if(ImGui::Selectable(getStyleName(style.first, style_view), accessory.styles[1] == style.first)) {
accessory.styles[1] = style.first; accessory.styles[1] = style.first;
} }
} }
@ -672,7 +538,6 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
} }
ImGui::PopItemWidth(); ImGui::PopItemWidth();
if(_advancedMode) {
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::DragFloat("##PosX", &accessory.relativePosition.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f"); ImGui::DragFloat("##PosX", &accessory.relativePosition.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
@ -682,7 +547,6 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::DragFloat("##PosZ", &accessory.relativePosition.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f"); ImGui::DragFloat("##PosZ", &accessory.relativePosition.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
}
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::SliderFloat("##PosOffsetX", &accessory.relativePositionOffset.x(), -500.0f, +500.0f, "X: %.3f"); ImGui::SliderFloat("##PosOffsetX", &accessory.relativePositionOffset.x(), -500.0f, +500.0f, "X: %.3f");
@ -696,7 +560,6 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
ImGui::SameLine(); ImGui::SameLine();
drawHelpMarker("+/-500.0 = +/-250 in-game"); drawHelpMarker("+/-500.0 = +/-250 in-game");
if(_advancedMode) {
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::DragFloat("##RotX", &accessory.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f"); ImGui::DragFloat("##RotX", &accessory.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
@ -706,7 +569,6 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::DragFloat("##RotZ", &accessory.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f"); ImGui::DragFloat("##RotZ", &accessory.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f");
ImGui::PopItemWidth(); ImGui::PopItemWidth();
}
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth()); ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::SliderFloat("##RotOffsetX", &accessory.relativeRotationOffset.x(), -180.0f, +180.0f, "Roll: %.3f"); ImGui::SliderFloat("##RotOffsetX", &accessory.relativeRotationOffset.x(), -180.0f, +180.0f, "Roll: %.3f");
@ -732,12 +594,12 @@ void SaveTool::drawAccessoryEditor(Accessory& accessory, Containers::ArrayView<C
ImGui::EndGroup(); ImGui::EndGroup();
} }
auto SaveTool::getStyleName(Int id, Containers::ArrayView<CustomStyle> view) -> Containers::StringView { auto SaveTool::getStyleName(Int id, Containers::ArrayView<CustomStyle> view) -> const char* {
if(id >= 0 && id <= 15) { if(id >= 0 && id <= 15) {
return view[id].name; return view[id].name.c_str();
} }
else if(id >= 50 && id <= 65) { else if(id >= 50 && id <= 65) {
return _currentMass->globalStyles()[id - 50].name; return _currentMass->globalStyles()[id - 50].name.c_str();
} }
else { else {
return style_names.at(id); return style_names.at(id);

View File

@ -28,22 +28,21 @@ void SaveTool::drawArmour() {
if(ImGui::Button(ICON_FA_UNDO_ALT " Reset all")) { if(ImGui::Button(ICON_FA_UNDO_ALT " Reset all")) {
_currentMass->getArmourParts(); _currentMass->getArmourParts();
_currentMass->getBulletLauncherAttachments();
} }
if(!ImGui::BeginChild("##ArmourParts", {0.0f, 0.0f}, true)) { if(!ImGui::BeginChild("##ArmourParts")) {
ImGui::EndChild(); ImGui::EndChild();
return; return;
} }
static Containers::StringView slot_labels[] = { static const char* slot_labels[] = {
#define c(enumerator, strenum, name) name, #define c(enumerator, strenum, name) name,
#include "../Maps/ArmourSlots.hpp" #include "../Maps/ArmourSlots.hpp"
#undef c #undef c
}; };
for(UnsignedInt i = 0; i < _currentMass->armourParts().size(); i++) { for(UnsignedInt i = 0; i < _currentMass->armourParts().size(); i++) {
ImGui::PushID(int(i)); ImGui::PushID(i);
auto& part = _currentMass->armourParts()[i]; auto& part = _currentMass->armourParts()[i];
@ -52,20 +51,20 @@ void SaveTool::drawArmour() {
std::memset(header, '\0', 129); std::memset(header, '\0', 129);
if(armour_sets.find(part.id) != armour_sets.cend()) { if(armour_sets.find(part.id) != armour_sets.cend()) {
std::snprintf(header, 128, "%s: %s###%u", slot_labels[UnsignedInt(part.slot)].data(), armour_sets.at(part.id).name.data(), UnsignedInt(part.slot)); std::snprintf(header, 128, "%s: %s###%u", slot_labels[UnsignedInt(part.slot)], armour_sets.at(part.id).name, UnsignedInt(part.slot));
} }
else { else {
std::snprintf(header, 128, "%s: %i###%u", slot_labels[UnsignedInt(part.slot)].data(), part.id, UnsignedInt(part.slot)); std::snprintf(header, 128, "%s: %i###%u", slot_labels[UnsignedInt(part.slot)], part.id, UnsignedInt(part.slot));
} }
if(ImGui::CollapsingHeader(header)) { if(ImGui::CollapsingHeader(header)) {
ImGui::BeginGroup(); ImGui::BeginGroup();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x * 0.491f); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() * 0.491f);
if(ImGui::BeginListBox("##ChangePart")) { if(ImGui::BeginListBox("##ChangePart")) {
if(std::strncmp("Neck", slot_labels[UnsignedInt(part.slot)].data(), 4) != 0) { if(std::strncmp("Neck", slot_labels[UnsignedInt(part.slot)], 4) != 0) {
for(auto& set : armour_sets) { for(auto& set : armour_sets) {
if(ImGui::Selectable(set.second.name.data(), set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) { if(ImGui::Selectable(set.second.name, set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) {
part.id = set.first; part.id = set.first;
} }
} }
@ -76,7 +75,7 @@ void SaveTool::drawArmour() {
continue; continue;
} }
if(ImGui::Selectable(set.second.name.data(), set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) { if(ImGui::Selectable(set.second.name, set.first == part.id, ImGuiSelectableFlags_SpanAvailWidth)) {
part.id = set.first; part.id = set.first;
} }
} }
@ -103,10 +102,10 @@ void SaveTool::drawArmour() {
ImGui::PushID(j); ImGui::PushID(j);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - 2.0f); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth() - 2.0f);
if(ImGui::BeginCombo("##Style", getStyleName(part.styles[j], _currentMass->armourCustomStyles()).data())) { if(ImGui::BeginCombo("##Style", getStyleName(part.styles[j], _currentMass->armourCustomStyles()))) {
for(const auto& style : style_names) { for(const auto& style : style_names) {
if(ImGui::Selectable(getStyleName(style.first, _currentMass->armourCustomStyles()).data(), part.styles[j] == style.first)) { if(ImGui::Selectable(getStyleName(style.first, _currentMass->armourCustomStyles()), part.styles[j] == style.first)) {
part.styles[j] = style.first; part.styles[j] = style.first;
} }
} }
@ -126,14 +125,14 @@ void SaveTool::drawArmour() {
drawAlignedText("Showing/editing decal"); drawAlignedText("Showing/editing decal");
for(UnsignedInt j = 0; j < part.decals.size(); j++) { for(UnsignedInt j = 0; j < part.decals.size(); j++) {
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton(std::to_string(j + 1).c_str(), &_selectedArmourDecals[i], int(j)); ImGui::RadioButton(std::to_string(j + 1).c_str(), &_selectedArmourDecals[i], j);
} }
drawDecalEditor(part.decals[_selectedArmourDecals[i]]); drawDecalEditor(part.decals[_selectedArmourDecals[i]]);
ImGui::PopID(); ImGui::PopID();
if(part.accessories.size() != 0) { if(!part.accessories.size()) {
ImGui::Separator(); ImGui::Separator();
ImGui::PushID("Accessory"); ImGui::PushID("Accessory");
@ -141,7 +140,7 @@ void SaveTool::drawArmour() {
drawAlignedText("Showing/editing accessory"); drawAlignedText("Showing/editing accessory");
for(UnsignedInt j = 0; j < part.accessories.size(); j++) { for(UnsignedInt j = 0; j < part.accessories.size(); j++) {
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton(std::string{char(65 + j)}.c_str(), &_selectedArmourAccessories[i], int(j)); ImGui::RadioButton(std::string{char(65 + j)}.c_str(), &_selectedArmourAccessories[i], j);
} }
drawAccessoryEditor(part.accessories[_selectedArmourAccessories[i]], _currentMass->armourCustomStyles()); drawAccessoryEditor(part.accessories[_selectedArmourAccessories[i]], _currentMass->armourCustomStyles());
@ -152,9 +151,7 @@ void SaveTool::drawArmour() {
ImGui::Separator(); ImGui::Separator();
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
_modifiedBySaveTool = true;
if(!_currentMass->writeArmourPart(part.slot)) { if(!_currentMass->writeArmourPart(part.slot)) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
} }
@ -163,128 +160,6 @@ void SaveTool::drawArmour() {
ImGui::PopID(); ImGui::PopID();
} }
if(_currentMass->bulletLauncherAttachmentStyle() != BulletLauncherAttachmentStyle::NotFound &&
ImGui::CollapsingHeader("Bullet launcher placement"))
{
drawAlignedText("Attachment style:"_s);
ImGui::SameLine();
ImGui::RadioButton("Active one",
_currentMass->bulletLauncherAttachmentStyle() == BulletLauncherAttachmentStyle::ActiveOne);
ImGui::SameLine();
ImGui::RadioButton("Active one per slot",
_currentMass->bulletLauncherAttachmentStyle() == BulletLauncherAttachmentStyle::ActiveOnePerSlot);
ImGui::SameLine();
ImGui::RadioButton("All equipped",
_currentMass->bulletLauncherAttachmentStyle() == BulletLauncherAttachmentStyle::AllEquipped);
ImGui::Separator();
drawAlignedText("Launcher slot:");
ImGui::SameLine();
ImGui::RadioButton("1", &_selectedBLPlacement, 0);
ImGui::SameLine();
ImGui::RadioButton("2", &_selectedBLPlacement, 1);
ImGui::SameLine();
ImGui::RadioButton("3", &_selectedBLPlacement, 2);
ImGui::SameLine();
ImGui::RadioButton("4", &_selectedBLPlacement, 3);
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[UnsignedInt(placement.socket)].data())) {
for(UnsignedInt i = 0; i < (sizeof(socket_labels) / sizeof(socket_labels[0])); i++) {
if(ImGui::Selectable(socket_labels[i].data(), i == UnsignedInt(placement.socket), ImGuiSelectableFlags_SpanAvailWidth)) {
placement.socket = static_cast<BulletLauncherSocket>(i);
}
}
ImGui::EndCombo();
}
if(placement.socket != BulletLauncherSocket::Auto) {
ImGui::BeginGroup();
drawAlignedText("Relative position:");
drawAlignedText("Offset position:");
drawAlignedText("Relative rotation:");
drawAlignedText("Offset rotation:");
drawAlignedText("Scale:");
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::DragFloat("##RelPosX", &placement.relativeLocation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "X: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::DragFloat("##RelPosY", &placement.relativeLocation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Y: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::DragFloat("##RelPosZ", &placement.relativeLocation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Z: %.3f");
ImGui::PopItemWidth();
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::SliderFloat("##OffPosX", &placement.offsetLocation.x(), -500.0f, +500.0f, "X: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::SliderFloat("##OffPosY", &placement.offsetLocation.y(), -500.0f, +500.0f, "Y: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::SliderFloat("##OffPosZ", &placement.offsetLocation.z(), -500.0f, +500.0f, "Z: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine();
drawHelpMarker("+/-500.0 = +/-250 in-game");
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::DragFloat("##RotX", &placement.relativeRotation.x(), 1.0f, -FLT_MAX, +FLT_MAX, "Roll: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::DragFloat("##RotY", &placement.relativeRotation.y(), 1.0f, -FLT_MAX, +FLT_MAX, "Yaw: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::DragFloat("##RotZ", &placement.relativeRotation.z(), 1.0f, -FLT_MAX, +FLT_MAX, "Pitch: %.3f");
ImGui::PopItemWidth();
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::SliderFloat("##RotOffsetZ", &placement.offsetRotation.z(), -180.0f, +180.0f, "Roll: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::SliderFloat("##RotOffsetX", &placement.offsetRotation.x(), -30.0f, +30.0f, "Pitch: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::SliderFloat("##RotOffsetY", &placement.offsetRotation.y(), -30.0f, +30.0f, "Yaw: %.3f");
ImGui::PopItemWidth();
ImGui::PushMultiItemsWidths(3, ImGui::CalcItemWidth());
ImGui::SliderFloat("##ScaleX", &placement.relativeScale.x(), 0.5f, 1.5f, "X: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::SliderFloat("##ScaleY", &placement.relativeScale.y(), 0.5f, 1.5f, "Y: %.3f");
ImGui::PopItemWidth();
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::SliderFloat("##ScaleZ", &placement.relativeScale.z(), 0.5f, 1.5f, "Z: %.3f");
ImGui::PopItemWidth();
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"); }) &&
!_currentMass->writeBulletLauncherAttachments())
{
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError());
}
}
ImGui::EndChild(); ImGui::EndChild();
} }
@ -301,7 +176,7 @@ void SaveTool::drawCustomArmourStyles() {
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game."); ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
for(UnsignedInt i = 0; i < _currentMass->armourCustomStyles().size(); i++) { for(UnsignedInt i = 0; i < _currentMass->armourCustomStyles().size(); i++) {
ImGui::PushID(int(i)); ImGui::PushID(i);
DCSResult result; DCSResult result;
result = drawCustomStyle(_currentMass->armourCustomStyles()[i]); result = drawCustomStyle(_currentMass->armourCustomStyles()[i]);
switch(result) { switch(result) {
@ -309,9 +184,7 @@ void SaveTool::drawCustomArmourStyles() {
_currentMass->getArmourCustomStyles(); _currentMass->getArmourCustomStyles();
break; break;
case DCS_Save: case DCS_Save:
_modifiedBySaveTool = true; if(_currentMass->writeArmourCustomStyle(i)) {
if(!_currentMass->writeArmourCustomStyle(i)) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
break; break;

View File

@ -32,7 +32,7 @@ void SaveTool::drawFrameInfo() {
ImGui::BeginGroup(); ImGui::BeginGroup();
if(ImGui::BeginChild("##JointSliders", {(ImGui::GetContentRegionAvail().x / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 300.0f}, true, ImGuiWindowFlags_MenuBar)) { if(ImGui::BeginChild("##JointSliders", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 300.0f}, true, ImGuiWindowFlags_MenuBar)) {
if(ImGui::BeginMenuBar()) { if(ImGui::BeginMenuBar()) {
ImGui::TextUnformatted("Joint sliders"); ImGui::TextUnformatted("Joint sliders");
@ -43,7 +43,7 @@ void SaveTool::drawFrameInfo() {
} }
ImGui::EndChild(); ImGui::EndChild();
if(ImGui::BeginChild("##FrameStyles", {(ImGui::GetContentRegionAvail().x / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 0.0f}, true, ImGuiWindowFlags_MenuBar)) { if(ImGui::BeginChild("##FrameStyles", {(ImGui::GetContentRegionAvailWidth() / 2.0f) - (ImGui::GetStyle().WindowPadding.x / 2.0f), 0.0f}, true, ImGuiWindowFlags_MenuBar)) {
if(ImGui::BeginMenuBar()) { if(ImGui::BeginMenuBar()) {
ImGui::TextUnformatted("Frame styles"); ImGui::TextUnformatted("Frame styles");
@ -180,9 +180,7 @@ void SaveTool::drawJointSliders() {
} }
else { else {
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
_modifiedBySaveTool = true;
if(!_currentMass->writeJointSliders()) { if(!_currentMass->writeJointSliders()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
_jointsDirty = false; _jointsDirty = false;
@ -207,9 +205,9 @@ void SaveTool::drawFrameStyles() {
ImGui::PushID(i); ImGui::PushID(i);
if(ImGui::BeginCombo("##Style", getStyleName(_currentMass->frameStyles()[i], _currentMass->frameCustomStyles()).data())) { if(ImGui::BeginCombo("##Style", getStyleName(_currentMass->frameStyles()[i], _currentMass->frameCustomStyles()))) {
for(const auto& style : style_names) { for(const auto& style : style_names) {
if(ImGui::Selectable(getStyleName(style.first, _currentMass->frameCustomStyles()).data(), _currentMass->frameStyles()[i] == style.first)) { if(ImGui::Selectable(getStyleName(style.first, _currentMass->frameCustomStyles()), _currentMass->frameStyles()[i] == style.first)) {
_currentMass->frameStyles()[i] = style.first; _currentMass->frameStyles()[i] = style.first;
_stylesDirty = true; _stylesDirty = true;
} }
@ -230,9 +228,7 @@ void SaveTool::drawFrameStyles() {
} }
else { else {
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
_modifiedBySaveTool = true;
if(!_currentMass->writeFrameStyles()) { if(!_currentMass->writeFrameStyles()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
_stylesDirty = false; _stylesDirty = false;
@ -263,9 +259,7 @@ void SaveTool::drawEyeColourPicker() {
} }
else { else {
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
_modifiedBySaveTool = true;
if(!_currentMass->writeEyeFlareColour()) { if(!_currentMass->writeEyeFlareColour()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
_eyeFlareDirty = false; _eyeFlareDirty = false;
@ -291,7 +285,7 @@ void SaveTool::drawCustomFrameStyles() {
ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game."); ImGui::TextWrapped("In-game values are multiplied by 100. For example, 0.500 here is equal to 50 in-game.");
for(UnsignedInt i = 0; i < _currentMass->frameCustomStyles().size(); i++) { for(UnsignedInt i = 0; i < _currentMass->frameCustomStyles().size(); i++) {
ImGui::PushID(int(i)); ImGui::PushID(i);
DCSResult result; DCSResult result;
result = drawCustomStyle(_currentMass->frameCustomStyles()[i]); result = drawCustomStyle(_currentMass->frameCustomStyles()[i]);
switch(result) { switch(result) {
@ -299,9 +293,7 @@ void SaveTool::drawCustomFrameStyles() {
_currentMass->getFrameCustomStyles(); _currentMass->getFrameCustomStyles();
break; break;
case DCS_Save: case DCS_Save:
_modifiedBySaveTool = true;
if(!_currentMass->writeFrameCustomStyle(i)) { if(!_currentMass->writeFrameCustomStyle(i)) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
break; break;

View File

@ -17,7 +17,6 @@
#include "../FontAwesome/IconsFontAwesome5.h" #include "../FontAwesome/IconsFontAwesome5.h"
#include "../Maps/StyleNames.h" #include "../Maps/StyleNames.h"
#include "../Maps/WeaponParts.h"
#include "SaveTool.h" #include "SaveTool.h"
@ -33,7 +32,7 @@ void SaveTool::drawWeapons() {
if(!ImGui::BeginTable("##WeaponsList", 1, if(!ImGui::BeginTable("##WeaponsList", 1,
ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_BordersInnerH, ImGuiTableFlags_ScrollY|ImGuiTableFlags_BordersOuter|ImGuiTableFlags_BordersInnerH,
{ImGui::GetContentRegionAvail().x * 0.2f, -footer_height_to_reserve})) {ImGui::GetContentRegionAvailWidth() * 0.2f, -footer_height_to_reserve}))
{ {
ImGui::EndGroup(); ImGui::EndGroup();
return; return;
@ -58,9 +57,7 @@ void SaveTool::drawWeapons() {
if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) { if(drawUnsafeWidget([]{ return ImGui::Button(ICON_FA_SAVE " Save"); })) {
if(_meleeDirty) { if(_meleeDirty) {
_modifiedBySaveTool = true;
if(!_currentMass->writeMeleeWeapons()) { if(!_currentMass->writeMeleeWeapons()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
else { else {
@ -69,9 +66,7 @@ void SaveTool::drawWeapons() {
} }
if(_shieldsDirty) { if(_shieldsDirty) {
_modifiedBySaveTool = true;
if(!_currentMass->writeShields()) { if(!_currentMass->writeShields()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
else { else {
@ -80,9 +75,7 @@ void SaveTool::drawWeapons() {
} }
if(_bShootersDirty) { if(_bShootersDirty) {
_modifiedBySaveTool = true;
if(!_currentMass->writeBulletShooters()) { if(!_currentMass->writeBulletShooters()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
else { else {
@ -91,9 +84,7 @@ void SaveTool::drawWeapons() {
} }
if(_eShootersDirty) { if(_eShootersDirty) {
_modifiedBySaveTool = true;
if(_currentMass->writeEnergyShooters()) { if(_currentMass->writeEnergyShooters()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
else { else {
@ -102,9 +93,7 @@ void SaveTool::drawWeapons() {
} }
if(_bLaunchersDirty) { if(_bLaunchersDirty) {
_modifiedBySaveTool = true;
if(_currentMass->writeBulletLaunchers()) { if(_currentMass->writeBulletLaunchers()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
else { else {
@ -113,9 +102,7 @@ void SaveTool::drawWeapons() {
} }
if(_eLaunchersDirty) { if(_eLaunchersDirty) {
_modifiedBySaveTool = true;
if(_currentMass->writeEnergyLaunchers()) { if(_currentMass->writeEnergyLaunchers()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
else { else {
@ -180,47 +167,40 @@ void SaveTool::drawWeapons() {
ImGui::Separator(); ImGui::Separator();
if(drawUnsafeWidget([](){ return ImGui::Button(ICON_FA_SAVE " Save changes to weapon category"); })) { if(drawUnsafeWidget([](){ return ImGui::Button(ICON_FA_SAVE " Save changes to weapon category"); })) {
_modifiedBySaveTool = true;
switch(_currentWeapon->type) { switch(_currentWeapon->type) {
case WeaponType::Melee: case WeaponType::Melee:
if(!_currentMass->writeMeleeWeapons()) { if(!_currentMass->writeMeleeWeapons()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
break; break;
case WeaponType::Shield: case WeaponType::Shield:
if(!_currentMass->writeShields()) { if(!_currentMass->writeShields()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
break; break;
case WeaponType::BulletShooter: case WeaponType::BulletShooter:
if(!_currentMass->writeBulletShooters()) { if(!_currentMass->writeBulletShooters()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
break; break;
case WeaponType::EnergyShooter: case WeaponType::EnergyShooter:
if(!_currentMass->writeEnergyShooters()) { if(!_currentMass->writeEnergyShooters()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
break; break;
case WeaponType::BulletLauncher: case WeaponType::BulletLauncher:
if(!_currentMass->writeBulletLaunchers()) { if(!_currentMass->writeBulletLaunchers()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
break; break;
case WeaponType::EnergyLauncher: case WeaponType::EnergyLauncher:
if(!_currentMass->writeEnergyLaunchers()) { if(!_currentMass->writeEnergyLaunchers()) {
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, _currentMass->lastError()); _queue.addToast(Toast::Type::Error, _currentMass->lastError());
} }
break; break;
default: default:
_modifiedBySaveTool = false;
_queue.addToast(Toast::Type::Error, "Unknown weapon type"); _queue.addToast(Toast::Type::Error, "Unknown weapon type");
} }
} }
@ -254,14 +234,14 @@ void SaveTool::drawWeapons() {
ImGui::EndGroup(); ImGui::EndGroup();
} }
void SaveTool::drawWeaponCategory(Containers::StringView name, Containers::ArrayView<Weapon> weapons_view, bool& dirty, void SaveTool::drawWeaponCategory(const char* name, Containers::ArrayView<Weapon> weapons_view, bool& dirty,
Containers::StringView payload_type, Containers::StringView payload_tooltip) const char* payload_type, const char* payload_tooltip)
{ {
ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::TextUnformatted(name.data()); ImGui::TextUnformatted(name);
ImGui::PushID(payload_type.data()); ImGui::PushID(payload_type);
for(UnsignedInt i = 0; i < weapons_view.size(); i++) { for(UnsignedInt i = 0; i < weapons_view.size(); i++) {
auto& weapon = weapons_view[i]; auto& weapon = weapons_view[i];
@ -269,23 +249,23 @@ void SaveTool::drawWeaponCategory(Containers::StringView name, Containers::Array
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::PushID(int(i)); ImGui::PushID(i);
if(ImGui::Selectable(weapon.name.data(), _currentWeapon == &weapon)) { if(ImGui::Selectable(weapon.name.c_str(), _currentWeapon == &weapon)) {
_currentWeapon = &weapon; _currentWeapon = &weapon;
} }
if(ImGui::BeginDragDropSource()) { if(ImGui::BeginDragDropSource()) {
ImGui::SetDragDropPayload(payload_type.data(), &i, sizeof(UnsignedInt)); ImGui::SetDragDropPayload(payload_type, &i, sizeof(UnsignedInt));
if(ImGui::GetIO().KeyCtrl) { if(ImGui::GetIO().KeyCtrl) {
ImGui::Text("%s %i - %s (copy)", payload_tooltip.data(), i + 1, weapon.name.data()); ImGui::Text("%s %i - %s (copy)", payload_tooltip, i + 1, weapon.name.c_str());
} }
else { else {
ImGui::Text("%s %i - %s", payload_tooltip.data(), i + 1, weapon.name.data()); ImGui::Text("%s %i - %s", payload_tooltip, i + 1, weapon.name.c_str());
} }
ImGui::EndDragDropSource(); ImGui::EndDragDropSource();
} }
if(ImGui::BeginDragDropTarget()) { if(ImGui::BeginDragDropTarget()) {
if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(payload_type.data())) { if(const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(payload_type)) {
int index = *static_cast<int*>(payload->Data); int index = *static_cast<int*>(payload->Data);
if(!ImGui::GetIO().KeyCtrl) { if(!ImGui::GetIO().KeyCtrl) {
@ -309,7 +289,7 @@ void SaveTool::drawWeaponCategory(Containers::StringView name, Containers::Array
ImGui::PopID(); ImGui::PopID();
if(weapon.attached) { if(weapon.attached == true) {
ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, 0x1F008CFFu); ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, 0x1F008CFFu);
} }
} }
@ -322,13 +302,13 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
return; return;
} }
static Containers::StringView labels[] { static const char* labels[] {
#define c(enumerator, strenum, name) name, #define c(enumerator, strenum, name) name,
#include "../Maps/WeaponTypes.hpp" #include "../Maps/WeaponTypes.hpp"
#undef c #undef c
}; };
drawAlignedText("%s: %s", labels[UnsignedInt(weapon.type)].data(), weapon.name.data()); drawAlignedText("%s: %s", labels[UnsignedInt(weapon.type)], weapon.name.c_str());
ImGui::SameLine(); ImGui::SameLine();
@ -337,7 +317,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
for(auto& c : name_buf) { for(auto& c : name_buf) {
c = '\0'; c = '\0';
} }
std::strncpy(name_buf.data(), weapon.name.data(), 32); std::strncpy(name_buf.data(), weapon.name.c_str(), 32);
ImGui::OpenPopup("name_edit"); ImGui::OpenPopup("name_edit");
} }
if(drawRenamePopup(name_buf)) { if(drawRenamePopup(name_buf)) {
@ -390,8 +370,8 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
weapon.damageType = DamageType::Freeze; weapon.damageType = DamageType::Freeze;
} }
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::RadioButton("Shock##Shock", weapon.damageType == DamageType::Shock)) { if(ImGui::RadioButton("Shock##Shock", weapon.damageType == DamageType::Freeze)) {
weapon.damageType = DamageType::Shock; weapon.damageType = DamageType::Freeze;
} }
} }
@ -412,8 +392,6 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
} }
ImGui::ColorEdit3("##CustomEffectColourPicker", &weapon.effectColour.x(), ImGuiColorEditFlags_HDR|ImGuiColorEditFlags_Float); ImGui::ColorEdit3("##CustomEffectColourPicker", &weapon.effectColour.x(), ImGuiColorEditFlags_HDR|ImGuiColorEditFlags_Float);
ImGui::SameLine();
drawHelpMarker("Click the coloured square for the full picker.");
if(!custom_effect) { if(!custom_effect) {
ImGui::EndDisabled(); ImGui::EndDisabled();
@ -430,80 +408,12 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
_selectedWeaponPart = 0; _selectedWeaponPart = 0;
} }
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton(std::to_string(i).c_str(), &_selectedWeaponPart, i); ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponPart, i);
} }
auto& part = weapon.parts[_selectedWeaponPart]; auto& part = weapon.parts[_selectedWeaponPart];
const auto* map = [this, &weapon]()-> const std::map<Int, Containers::StringView>* {
switch(weapon.type) {
case WeaponType::Melee:
return _selectedWeaponPart == 0 ? &melee_grips : &melee_assaulters;
case WeaponType::Shield:
return _selectedWeaponPart == 0 ? &shield_handles : &shield_shells;
case WeaponType::BulletShooter:
return _selectedWeaponPart == 0 ? &bshooter_triggers : &bshooter_barrels;
case WeaponType::EnergyShooter:
return _selectedWeaponPart == 0 ? &eshooter_triggers : &eshooter_busters;
case WeaponType::BulletLauncher:
return _selectedWeaponPart == 0 ? &blauncher_pods : &blauncher_projectiles;
case WeaponType::EnergyLauncher:
return _selectedWeaponPart == 0 ? &elauncher_generators : &elauncher_pods;
}
return nullptr;
}();
if(!map) {
return;
}
if(map->find(part.id) != map->cend()) {
ImGui::TextUnformatted(map->at(part.id).data());
}
else if(part.id == -1) {
ImGui::TextUnformatted("<none>");
}
else{
ImGui::Text("ID: %i", part.id); ImGui::Text("ID: %i", part.id);
}
if(!map->empty()) {
ImGui::SameLine();
if(ImGui::SmallButton("Change")) {
ImGui::OpenPopup("##WeaponPartPopup");
}
if(ImGui::BeginPopup("##WeaponPartPopup")) {
if(ImGui::BeginListBox("##WeaponParts")) {
for(const auto& mapped_part : *map) {
if(ImGui::Selectable(mapped_part.second.data(), mapped_part.first == part.id)) {
part.id = mapped_part.first;
}
if(mapped_part.first == part.id) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndListBox();
}
ImGui::EndPopup();
}
}
if(weapon.type == WeaponType::Shield ||
(weapon.type == WeaponType::BulletLauncher && _selectedWeaponPart != 0))
{
ImGui::SameLine();
if(ImGui::SmallButton("Unequip")) {
part.id = -1;
}
if(weapon.type == WeaponType::Shield && _selectedWeaponPart == 0) {
drawTooltip("This will make the whole shield and its accessories invisible.");
}
else {
drawTooltip("This will make accessories invisible as well.");
}
}
if(ImGui::BeginChild("##PartDetails", {0.0f, 0.0f}, true)) { if(ImGui::BeginChild("##PartDetails", {0.0f, 0.0f}, true)) {
ImGui::TextUnformatted("Styles:"); ImGui::TextUnformatted("Styles:");
@ -515,9 +425,9 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
ImGui::PushID(i); ImGui::PushID(i);
if(ImGui::BeginCombo("##Style", getStyleName(part.styles[i], weapon.customStyles).data())) { if(ImGui::BeginCombo("##Style", getStyleName(part.styles[i], weapon.customStyles))) {
for(const auto& style: style_names) { for(const auto& style: style_names) {
if(ImGui::Selectable(getStyleName(style.first, weapon.customStyles).data(), if(ImGui::Selectable(getStyleName(style.first, weapon.customStyles),
part.styles[i] == style.first)) { part.styles[i] == style.first)) {
part.styles[i] = style.first; part.styles[i] = style.first;
} }
@ -536,7 +446,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
drawAlignedText("Showing/editing decal"); drawAlignedText("Showing/editing decal");
for(UnsignedLong i = 0; i < part.decals.size(); i++) { for(UnsignedLong i = 0; i < part.decals.size(); i++) {
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponDecal, int(i)); ImGui::RadioButton(std::to_string(i + 1).c_str(), &_selectedWeaponDecal, i);
} }
drawDecalEditor(part.decals[_selectedWeaponDecal]); drawDecalEditor(part.decals[_selectedWeaponDecal]);
@ -551,7 +461,7 @@ void SaveTool::drawWeaponEditor(Weapon& weapon) {
drawAlignedText("Showing/editing accessory"); drawAlignedText("Showing/editing accessory");
for(UnsignedLong i = 0; i < part.accessories.size(); i++) { for(UnsignedLong i = 0; i < part.accessories.size(); i++) {
ImGui::SameLine(); ImGui::SameLine();
ImGui::RadioButton(std::string{char(65 + i)}.c_str(), &_selectedWeaponAccessory, int(i)); ImGui::RadioButton(std::string{char(65 + i)}.c_str(), &_selectedWeaponAccessory, i);
} }
drawAccessoryEditor(part.accessories[_selectedWeaponAccessory], weapon.customStyles); drawAccessoryEditor(part.accessories[_selectedWeaponAccessory], weapon.customStyles);

View File

@ -14,14 +14,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "SaveTool.h"
#include <Magnum/ImGuiIntegration/Integration.h> #include <Magnum/ImGuiIntegration/Integration.h>
#include <SDL_messagebox.h>
#include "../FontAwesome/IconsFontAwesome5.h" #include "../FontAwesome/IconsFontAwesome5.h"
#include "SaveTool.h"
extern const ImVec2 center_pivot; extern const ImVec2 center_pivot;
void SaveTool::drawProfileManager() { void SaveTool::drawProfileManager() {
@ -52,8 +50,7 @@ void SaveTool::drawProfileManager() {
ImGui::TableSetColumnIndex(1); ImGui::TableSetColumnIndex(1);
if(ImGui::SmallButton("Refresh")) { if(ImGui::SmallButton("Refresh")) {
if(!_profileManager->refreshProfiles()) { if(!_profileManager->refreshProfiles()) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error in ProfileManager", _profileManager->lastError().c_str(), window());
_profileManager->lastError().data(), window());
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
@ -80,36 +77,31 @@ void SaveTool::drawProfileManager() {
ImGui::TextUnformatted("Actions"); ImGui::TextUnformatted("Actions");
for(std::size_t i = 0; i < _profileManager->profiles().size(); ++i) { for(std::size_t i = 0; i < _profileManager->profiles().size(); ++i) {
Profile& profile = _profileManager->profiles()[i];
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
ImGui::PushID(int(i)); ImGui::PushID(i);
if(ImGui::Selectable(profile.companyName().data(), false, if(ImGui::Selectable(_profileManager->profiles()[i].companyName().c_str(), false,
ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_AllowItemOverlap)) ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_AllowItemOverlap))
{ {
_currentProfile = _profileManager->getProfile(i); _currentProfile = _profileManager->getProfile(i);
initialiseMassManager(); initialiseMassManager();
initialiseFileWatcher();
_uiState = UiState::MainManager; _uiState = UiState::MainManager;
} }
ImGui::TableSetColumnIndex(1); ImGui::TableSetColumnIndex(1);
ImGui::TextUnformatted(profile.isDemo() ? "Demo" : "Full"); ImGui::TextUnformatted(_profileManager->profiles()[i].type() == ProfileType::Demo ? "Demo (legacy)" : "Full (legacy)");
ImGui::TableSetColumnIndex(2); ImGui::TableSetColumnIndex(2);
if(ImGui::SmallButton(ICON_FA_FILE_ARCHIVE)) { if(ImGui::SmallButton(ICON_FA_FILE_ARCHIVE)) {
profile_index = i; profile_index = i;
ImGui::OpenPopup(backup_popup_id); ImGui::OpenPopup(backup_popup_id);
} }
drawTooltip("Backup");
ImGui::SameLine(0.0f, 2.0f); ImGui::SameLine(0.0f, 2.0f);
if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) { if(drawUnsafeWidget(ImGui::SmallButton, ICON_FA_TRASH_ALT)) {
profile_index = i; profile_index = i;
ImGui::OpenPopup(delete_popup_id); ImGui::OpenPopup(delete_popup_id);
} }
drawTooltip("Delete");
ImGui::PopID(); ImGui::PopID();
} }
ImGui::EndTable(); ImGui::EndTable();
@ -138,9 +130,9 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
if(ImGui::BeginPopupModal("Restore backup", nullptr, if(ImGui::BeginPopupModal("Restore backup", nullptr,
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize)) ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
{ {
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f); ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
ImGui::Text("Are you sure you want to restore the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? Any existing data will be overwritten.", ImGui::Text("Are you sure you want to restore the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? Any existing data will be overwritten.",
_profileManager->backups()[backup_index].company.data(), _profileManager->backups()[backup_index].company.c_str(),
_profileManager->backups()[backup_index].timestamp.year, _profileManager->backups()[backup_index].timestamp.year,
_profileManager->backups()[backup_index].timestamp.month, _profileManager->backups()[backup_index].timestamp.month,
_profileManager->backups()[backup_index].timestamp.day, _profileManager->backups()[backup_index].timestamp.day,
@ -160,11 +152,7 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
if(!_profileManager->restoreBackup(backup_index)) { if(!_profileManager->restoreBackup(backup_index)) {
_queue.addToast(Toast::Type::Error, _profileManager->lastError()); _queue.addToast(Toast::Type::Error, _profileManager->lastError());
} }
if(!_profileManager->refreshProfiles()) { _profileManager->refreshProfiles();
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
_profileManager->lastError().data(), window());
exit(EXIT_FAILURE);
}
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
ImGui::SameLine(); ImGui::SameLine();
@ -181,9 +169,9 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
if(ImGui::BeginPopupModal("Delete backup", nullptr, if(ImGui::BeginPopupModal("Delete backup", nullptr,
ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize)) ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_AlwaysAutoResize))
{ {
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f); ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
ImGui::Text("Are you sure you want to delete the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? This operation is irreversible.", ImGui::Text("Are you sure you want to delete the %s backup from %.4i-%.2i-%.2i %.2i:%.2i:%.2i ? This operation is irreversible.",
_profileManager->backups()[backup_index].company.data(), _profileManager->backups()[backup_index].company.c_str(),
_profileManager->backups()[backup_index].timestamp.year, _profileManager->backups()[backup_index].timestamp.year,
_profileManager->backups()[backup_index].timestamp.month, _profileManager->backups()[backup_index].timestamp.month,
_profileManager->backups()[backup_index].timestamp.day, _profileManager->backups()[backup_index].timestamp.day,
@ -235,7 +223,7 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
ImGui::EndTable(); ImGui::EndTable();
} }
if(_profileManager->backups().isEmpty()) { if(_profileManager->backups().empty()) {
ImGui::TextDisabled("No backups were found."); ImGui::TextDisabled("No backups were found.");
} }
else if(ImGui::BeginTable("##Backups", 4, else if(ImGui::BeginTable("##Backups", 4,
@ -258,44 +246,41 @@ auto SaveTool::drawBackupListPopup() -> ImGuiID {
ImGui::TextUnformatted("Actions"); ImGui::TextUnformatted("Actions");
for(std::size_t i = 0; i < _profileManager->backups().size(); ++i) { for(std::size_t i = 0; i < _profileManager->backups().size(); ++i) {
auto& backup = _profileManager->backups()[i];
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0); ImGui::TableSetColumnIndex(0);
ImGui::TextUnformatted(backup.company.data()); ImGui::TextUnformatted(_profileManager->backups()[i].company.c_str());
if(ImGui::IsItemHovered()) { if(ImGui::IsItemHovered()) {
ImGui::BeginTooltip(); ImGui::BeginTooltip();
for(const auto& file : backup.includedFiles) { for(const auto& file : _profileManager->backups()[i].includedFiles) {
ImGui::TextUnformatted(file.data()); ImGui::TextUnformatted(file.c_str());
} }
ImGui::EndTooltip(); ImGui::EndTooltip();
} }
ImGui::TableSetColumnIndex(1); ImGui::TableSetColumnIndex(1);
ImGui::Text("%.4i-%.2i-%.2i %.2i:%.2i:%.2i", ImGui::Text("%.4i-%.2i-%.2i %.2i:%.2i:%.2i",
backup.timestamp.year, _profileManager->backups()[i].timestamp.year,
backup.timestamp.month, _profileManager->backups()[i].timestamp.month,
backup.timestamp.day, _profileManager->backups()[i].timestamp.day,
backup.timestamp.hour, _profileManager->backups()[i].timestamp.hour,
backup.timestamp.minute, _profileManager->backups()[i].timestamp.minute,
backup.timestamp.second); _profileManager->backups()[i].timestamp.second);
ImGui::TableSetColumnIndex(2); ImGui::TableSetColumnIndex(2);
ImGui::TextUnformatted(backup.type == ProfileType::Demo ? "Demo" : "Full"); ImGui::TextUnformatted(_profileManager->backups()[i].type == ProfileType::Demo ? "Demo" : "Full");
ImGui::TableSetColumnIndex(3); ImGui::TableSetColumnIndex(3);
ImGui::PushID(int(i)); ImGui::PushID(i);
if(ImGui::SmallButton(ICON_FA_UNDO)) { if(ImGui::SmallButton(ICON_FA_UNDO)) {
backup_index = i; backup_index = i;
ImGui::OpenPopup(restore_backup_popup_id); ImGui::OpenPopup(restore_backup_popup_id);
} }
drawTooltip("Restore");
ImGui::SameLine(0.0f, 2.0f); ImGui::SameLine(0.0f, 2.0f);
if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) { if(ImGui::SmallButton(ICON_FA_TRASH_ALT)) {
backup_index = i; backup_index = i;
ImGui::OpenPopup(delete_backup_popup_id); ImGui::OpenPopup(delete_backup_popup_id);
} }
drawTooltip("Delete");
ImGui::PopID(); ImGui::PopID();
} }
ImGui::EndTable(); ImGui::EndTable();
@ -341,18 +326,12 @@ auto SaveTool::drawBackupProfilePopup(std::size_t profile_index) -> ImGuiID {
ImGui::TableSetColumnIndex(1); ImGui::TableSetColumnIndex(1);
if(ImGui::Button("Yes")) { if(ImGui::Button("Yes")) {
if(!_profileManager->backupProfile(profile_index, true)) { _profileManager->backupProfile(profile_index, true);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
_profileManager->lastError().data(), window());
}
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("No", ImGui::GetItemRectSize())) { if(ImGui::Button("No", ImGui::GetItemRectSize())) {
if(!_profileManager->backupProfile(profile_index, false)) { _profileManager->backupProfile(profile_index, false);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error",
_profileManager->lastError().data(), window());
}
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
ImGui::SameLine(); ImGui::SameLine();
@ -380,10 +359,10 @@ auto SaveTool::drawDeleteProfilePopup(std::size_t profile_index) -> ImGuiID {
delete_builds = false; delete_builds = false;
} }
ImGui::PushTextWrapPos(float(windowSize().x()) * 0.40f); ImGui::PushTextWrapPos(windowSize().x() * 0.40f);
ImGui::Text("Are you sure you want to delete the %s profile named %s ? This operation is irreversible.", ImGui::Text("Are you sure you want to delete the %s %s profile ? This operation is irreversible.",
_profileManager->profiles()[profile_index].isDemo() ? "demo" : "full game", _profileManager->profiles()[profile_index].companyName().c_str(),
_profileManager->profiles()[profile_index].companyName().data()); _profileManager->profiles()[profile_index].type() == ProfileType::Demo ? "demo" : "full game");
ImGui::PopTextWrapPos(); ImGui::PopTextWrapPos();
if(ImGui::BeginTable("##DeleteProfileLayout", 2)) { if(ImGui::BeginTable("##DeleteProfileLayout", 2)) {

View File

@ -1,176 +0,0 @@
// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Utility/Format.h>
#include <SDL_events.h>
#include <curl/curl.h>
#include "../Logger/Logger.h"
#include "SaveTool.h"
void SaveTool::updateCheckEvent(SDL_Event& event) {
_updateThread.join();
if(event.user.code == CurlInitFailed) {
_queue.addToast(Toast::Type::Error, "Couldn't initialise libcurl. Update check aborted."_s);
LOG_ERROR("Couldn't initialise libcurl. Update check aborted.");
return;
}
else if(event.user.code == CurlError) {
Containers::String error{static_cast<char*>(event.user.data2), CURL_ERROR_SIZE, nullptr};
_queue.addToast(Toast::Type::Error, error, std::chrono::milliseconds{5000});
_queue.addToast(Toast::Type::Error, static_cast<char*>(event.user.data1),
std::chrono::milliseconds{5000});
LOG_ERROR_FORMAT("{}: {}", static_cast<char*>(event.user.data1), static_cast<char*>(event.user.data2));
return;
}
else if(event.user.code == CurlTimeout) {
_queue.addToast(Toast::Type::Error, "The request timed out."_s);
LOG_ERROR("The request timed out.");
return;
}
else if(event.user.code != 200) {
_queue.addToast(Toast::Type::Error,
Utility::format("The request failed with error code {}.", event.user.code));
LOG_ERROR_FORMAT("The request failed with error code {}.", event.user.code);
return;
}
struct Version {
explicit Version(Containers::StringView str) {
std::size_t start_point = 0;
if(str[0] == 'v') {
start_point++;
}
auto components = Containers::StringView{str.data() + start_point}.split('.');
major = std::strtol(components[0].data(), nullptr, 10);
minor = std::strtol(components[1].data(), nullptr, 10);
patch = std::strtol(components[2].data(), nullptr, 10);
fullVersion = major * 10000 + minor * 100 + patch;
if(str.hasSuffix("-pre")) {
prerelease = true;
}
}
Int fullVersion;
Int major = 0;
Int minor = 0;
Int patch = 0;
bool prerelease = false;
bool operator==(const Version& other) const {
return fullVersion == other.fullVersion && prerelease == other.prerelease;
}
bool operator>(const Version& other) const {
if((fullVersion > other.fullVersion) ||
(fullVersion == other.fullVersion && !prerelease && other.prerelease))
{
return true;
}
else {
return false;
}
}
explicit operator Containers::String() const {
return Utility::format("{}.{}.{}{}", major, minor, patch, prerelease ? "-pre" : "");
}
};
static const Version current_ver{SAVETOOL_VERSION};
auto str = static_cast<char*>(event.user.data1);
Containers::String response{str, strlen(str), nullptr};
auto components = response.splitOnAnyWithoutEmptyParts("\r\n");
Version latest_ver{components.front()};
if(latest_ver > current_ver) {
_queue.addToast(Toast::Type::Warning,
"Your version is out of date.\nCheck the settings for more information."_s,
std::chrono::milliseconds{5000});
_updateAvailable = true;
_latestVersion = Containers::String{latest_ver};
_releaseLink = Utility::format("https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool/releases/tag/v{}",
components.front());
_downloadLink = components.back();
}
else if(latest_ver == current_ver || (current_ver > latest_ver && current_ver.prerelease)) {
_queue.addToast(Toast::Type::Success, "The application is already up to date."_s);
}
else if(current_ver > latest_ver && !current_ver.prerelease) {
_queue.addToast(Toast::Type::Warning,
"Your version is more recent than the latest one in the repo. How???"_s);
}
}
inline auto writeData(char* ptr, std::size_t size, std::size_t nmemb, Containers::String* buf)-> std::size_t {
if(!ptr || !buf) return 0;
(*buf) = Utility::format("{}{}", *buf, Containers::StringView{ptr, size * nmemb});
return size * nmemb;
}
void SaveTool::checkForUpdates() {
SDL_Event event;
SDL_zero(event);
event.type = _updateEventId;
auto curl = curl_easy_init();
if(!curl) {
event.user.code = CurlInitFailed;
}
if(curl) {
Containers::String response_body{Containers::AllocatedInit, ""};
Containers::String error_buffer{ValueInit, CURL_ERROR_SIZE * 2};
curl_easy_setopt(curl, CURLOPT_URL, "https://williamjcm.ovh/mbst/version");
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_body);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer.data());
curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, 10000L);
auto code = curl_easy_perform(curl);
if(code == CURLE_OK) {
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
event.user.code = Int(status);
event.user.data1 = response_body.release();
}
else if(code == CURLE_OPERATION_TIMEDOUT) {
event.user.code = CurlTimeout;
}
else {
event.user.code = CurlError;
event.user.data1 = const_cast<char*>(curl_easy_strerror(code));
event.user.data2 = Containers::String{error_buffer}.release();
}
curl_easy_cleanup(curl);
}
SDL_PushEvent(&event);
}

View File

@ -24,8 +24,6 @@
#include <zipconf.h> #include <zipconf.h>
#include <curl/curlver.h>
#include "../FontAwesome/IconsFontAwesome5.h" #include "../FontAwesome/IconsFontAwesome5.h"
#include "../FontAwesome/IconsFontAwesome5Brands.h" #include "../FontAwesome/IconsFontAwesome5Brands.h"
@ -33,7 +31,7 @@ extern const ImVec2 center_pivot;
void SaveTool::drawAbout() { void SaveTool::drawAbout() {
ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot); ImGui::SetNextWindowPos(ImVec2{Vector2{windowSize() / 2.0f}}, ImGuiCond_Always, center_pivot);
ImGui::SetNextWindowSize({float(windowSize().x()) * 0.8f, float(windowSize().y()) * 0.75f}, ImGuiCond_Always); ImGui::SetNextWindowSize({windowSize().x() * 0.8f, windowSize().y() * 0.75f}, ImGuiCond_Always);
ImGui::OpenPopup("About##AboutPopup"); ImGui::OpenPopup("About##AboutPopup");
if(!ImGui::BeginPopupModal("About##AboutPopup", &_aboutPopup, if(!ImGui::BeginPopupModal("About##AboutPopup", &_aboutPopup,
@ -59,17 +57,7 @@ void SaveTool::drawAbout() {
ImGui::TextWrapped("This application, made for the M.A.S.S. Builder community by Guillaume Jacquemin (aka William JCM), " ImGui::TextWrapped("This application, made for the M.A.S.S. Builder community by Guillaume Jacquemin (aka William JCM), "
"is a rewrite of the wxWidgets-powered M.A.S.S. Builder Save Tool (formerly known as wxMASSManager)."); "is a rewrite of the wxWidgets-powered M.A.S.S. Builder Save Tool (formerly known as wxMASSManager).");
auto website = "https://williamjcm.ovh/coding/mbst"; const char* repo = "https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool";
drawAlignedText(ICON_FA_GLOBE " %s", website);
ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) {
ImGui::SetClipboardText(website);
}
ImGui::SameLine();
if(ImGui::Button("Open in browser")) {
openUri(website);
}
auto repo = "https://williamjcm.ovh/git/williamjcm/MassBuilderSaveTool";
drawAlignedText(ICON_FA_GIT_ALT " %s", repo); drawAlignedText(ICON_FA_GIT_ALT " %s", repo);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {
@ -85,10 +73,10 @@ void SaveTool::drawAbout() {
if(ImGui::CollapsingHeader("Licence")) { if(ImGui::CollapsingHeader("Licence")) {
ImGui::TextWrapped("This application is made available under the terms of the GNU General Public License, version 3, the full text of which is available below:"); ImGui::TextWrapped("This application is made available under the terms of the GNU General Public License, version 3, the full text of which is available below:");
if(ImGui::BeginChild("##GPL", {0.0f, float(windowSize().y()) * 0.3f}, true)) { if(ImGui::BeginChild("##GPL", {0.0f, windowSize().y() * 0.3f}, true)) {
static auto licence = _rs.getRaw("COPYING"); static const auto licence = _rs.get("COPYING");
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
ImGui::TextEx(licence.data(), licence.data() + licence.size(), ImGuiTextFlags_None); ImGui::TextUnformatted(licence.c_str());
ImGui::PopFont(); ImGui::PopFont();
} }
ImGui::EndChild(); ImGui::EndChild();
@ -101,7 +89,7 @@ void SaveTool::drawAbout() {
if(ImGui::TreeNodeEx("Corrade", ImGuiTreeNodeFlags_SpanAvailWidth)) { if(ImGui::TreeNodeEx("Corrade", ImGuiTreeNodeFlags_SpanAvailWidth)) {
ImGui::Text("Version used: %s", CORRADE_VERSION_STRING); ImGui::Text("Version used: %s", CORRADE_VERSION_STRING);
auto corrade_website = "https://magnum.graphics/corrade"; const char* corrade_website = "https://magnum.graphics/corrade";
drawAlignedText(ICON_FA_GLOBE " %s", corrade_website); drawAlignedText(ICON_FA_GLOBE " %s", corrade_website);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {
@ -114,10 +102,10 @@ void SaveTool::drawAbout() {
ImGui::TextUnformatted("Licence: MIT"); ImGui::TextUnformatted("Licence: MIT");
static auto corrade_licence = _rs.getRaw("COPYING.Corrade"); static const auto corrade_licence = _rs.get("COPYING.Corrade");
if(ImGui::BeginChild("##CorradeLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) { if(ImGui::BeginChild("##CorradeLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
ImGui::TextEx(corrade_licence.data(), corrade_licence.data() + corrade_licence.size(), ImGuiTextFlags_None); ImGui::TextUnformatted(corrade_licence.c_str());
ImGui::PopFont(); ImGui::PopFont();
} }
ImGui::EndChild(); ImGui::EndChild();
@ -129,7 +117,7 @@ void SaveTool::drawAbout() {
ImGui::TextUnformatted("Versions used:"); ImGui::TextUnformatted("Versions used:");
ImGui::BulletText("Magnum: %s", MAGNUM_VERSION_STRING); ImGui::BulletText("Magnum: %s", MAGNUM_VERSION_STRING);
ImGui::BulletText("Integration: %s", MAGNUMINTEGRATION_VERSION_STRING); ImGui::BulletText("Integration: %s", MAGNUMINTEGRATION_VERSION_STRING);
auto magnum_website = "https://magnum.graphics"; const char* magnum_website = "https://magnum.graphics";
drawAlignedText(ICON_FA_GLOBE " %s", magnum_website); drawAlignedText(ICON_FA_GLOBE " %s", magnum_website);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {
@ -142,10 +130,10 @@ void SaveTool::drawAbout() {
ImGui::TextUnformatted("Licence: MIT"); ImGui::TextUnformatted("Licence: MIT");
static auto magnum_licence = _rs.getRaw("COPYING.Magnum"); static const auto magnum_licence = _rs.get("COPYING.Magnum");
if(ImGui::BeginChild("##MagnumLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) { if(ImGui::BeginChild("##MagnumLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
ImGui::TextEx(magnum_licence.data(), magnum_licence.data() + magnum_licence.size(), ImGuiTextFlags_None); ImGui::TextUnformatted(magnum_licence.c_str());
ImGui::PopFont(); ImGui::PopFont();
} }
ImGui::EndChild(); ImGui::EndChild();
@ -155,7 +143,7 @@ void SaveTool::drawAbout() {
if(ImGui::TreeNodeEx("Dear ImGui", ImGuiTreeNodeFlags_SpanAvailWidth)) { if(ImGui::TreeNodeEx("Dear ImGui", ImGuiTreeNodeFlags_SpanAvailWidth)) {
ImGui::Text("Version used: %s", IMGUI_VERSION); ImGui::Text("Version used: %s", IMGUI_VERSION);
auto imgui_repo = "https://github.com/ocornut/imgui"; const char* imgui_repo = "https://github.com/ocornut/imgui";
drawAlignedText(ICON_FA_GITHUB " %s", imgui_repo); drawAlignedText(ICON_FA_GITHUB " %s", imgui_repo);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {
@ -168,10 +156,10 @@ void SaveTool::drawAbout() {
ImGui::TextUnformatted("Licence: MIT"); ImGui::TextUnformatted("Licence: MIT");
static auto imgui_licence = _rs.getRaw("LICENSE.ImGui"); static const auto imgui_licence = _rs.get("LICENSE.ImGui");
if(ImGui::BeginChild("##ImGuiLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) { if(ImGui::BeginChild("##ImGuiLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
ImGui::TextEx(imgui_licence.data(), imgui_licence.data() + imgui_licence.size(), ImGuiTextFlags_None); ImGui::TextUnformatted(imgui_licence.c_str());
ImGui::PopFont(); ImGui::PopFont();
} }
ImGui::EndChild(); ImGui::EndChild();
@ -181,7 +169,7 @@ void SaveTool::drawAbout() {
if(ImGui::TreeNodeEx("Simple DirectMedia Layer (SDL) 2", ImGuiTreeNodeFlags_SpanAvailWidth)) { if(ImGui::TreeNodeEx("Simple DirectMedia Layer (SDL) 2", ImGuiTreeNodeFlags_SpanAvailWidth)) {
ImGui::Text("Version used: %i.%i.%i", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL); ImGui::Text("Version used: %i.%i.%i", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
auto sdl_website = "https://www.libsdl.org/"; const char* sdl_website = "https://www.libsdl.org/";
drawAlignedText(ICON_FA_GLOBE " %s", sdl_website); drawAlignedText(ICON_FA_GLOBE " %s", sdl_website);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {
@ -194,10 +182,10 @@ void SaveTool::drawAbout() {
ImGui::TextUnformatted("Licence: zlib"); ImGui::TextUnformatted("Licence: zlib");
static auto sdl_licence = _rs.getRaw("LICENSE.SDL"); static const auto sdl_licence = _rs.get("LICENSE.SDL");
if(ImGui::BeginChild("##SDLLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) { if(ImGui::BeginChild("##SDLLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
ImGui::TextEx(sdl_licence.data(), sdl_licence.data() + sdl_licence.size(), ImGuiTextFlags_None); ImGui::TextUnformatted(sdl_licence.c_str());
ImGui::PopFont(); ImGui::PopFont();
} }
ImGui::EndChild(); ImGui::EndChild();
@ -207,7 +195,7 @@ void SaveTool::drawAbout() {
if(ImGui::TreeNodeEx("libzip", ImGuiTreeNodeFlags_SpanAvailWidth)) { if(ImGui::TreeNodeEx("libzip", ImGuiTreeNodeFlags_SpanAvailWidth)) {
ImGui::Text("Version used: %s", LIBZIP_VERSION); ImGui::Text("Version used: %s", LIBZIP_VERSION);
auto libzip_website = "https://libzip.org/"; const char* libzip_website = "https://libzip.org/";
drawAlignedText(ICON_FA_GLOBE " %s", libzip_website); drawAlignedText(ICON_FA_GLOBE " %s", libzip_website);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {
@ -220,10 +208,10 @@ void SaveTool::drawAbout() {
ImGui::TextUnformatted("Licence: 3-clause BSD"); ImGui::TextUnformatted("Licence: 3-clause BSD");
static auto libzip_licence = _rs.getRaw("LICENSE.libzip"); static const auto libzip_licence = _rs.get("LICENSE.libzip");
if(ImGui::BeginChild("##libzipLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) { if(ImGui::BeginChild("##libzipLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
ImGui::TextEx(libzip_licence.data(), libzip_licence.data() + libzip_licence.size(), ImGuiTextFlags_None); ImGui::TextUnformatted(libzip_licence.c_str());
ImGui::PopFont(); ImGui::PopFont();
} }
ImGui::EndChild(); ImGui::EndChild();
@ -232,7 +220,7 @@ void SaveTool::drawAbout() {
} }
if(ImGui::TreeNodeEx("Entropia File System Watcher (efsw)", ImGuiTreeNodeFlags_SpanAvailWidth)) { if(ImGui::TreeNodeEx("Entropia File System Watcher (efsw)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
auto efsw_repo = "https://github.com/SpartanJ/efsw"; const char* efsw_repo = "https://github.com/SpartanJ/efsw";
drawAlignedText(ICON_FA_GITHUB " %s", efsw_repo); drawAlignedText(ICON_FA_GITHUB " %s", efsw_repo);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {
@ -245,10 +233,10 @@ void SaveTool::drawAbout() {
ImGui::TextUnformatted("Licence: MIT"); ImGui::TextUnformatted("Licence: MIT");
static auto efsw_licence = _rs.getRaw("LICENSE.efsw"); static const auto efsw_licence = _rs.get("LICENSE.efsw");
if(ImGui::BeginChild("##efswLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) { if(ImGui::BeginChild("##efswLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
ImGui::TextEx(efsw_licence.data(), efsw_licence.data() + efsw_licence.size(), ImGuiTextFlags_None); ImGui::TextUnformatted(efsw_licence.c_str());
ImGui::PopFont(); ImGui::PopFont();
} }
ImGui::EndChild(); ImGui::EndChild();
@ -256,25 +244,49 @@ void SaveTool::drawAbout() {
ImGui::TreePop(); ImGui::TreePop();
} }
if(ImGui::TreeNodeEx("libcurl", ImGuiTreeNodeFlags_SpanAvailWidth)) { if(ImGui::TreeNodeEx("C++ Requests (cpr)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
ImGui::Text("Version used: %s", LIBCURL_VERSION); const char* cpr_website = "https://whoshuu.github.io/cpr/";
auto curl_website = "https://curl.se/libcurl"; drawAlignedText(ICON_FA_GLOBE " %s", cpr_website);
drawAlignedText(ICON_FA_GLOBE " %s", curl_website);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {
ImGui::SetClipboardText(curl_website); ImGui::SetClipboardText(cpr_website);
} }
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Open in browser")) { if(ImGui::Button("Open in browser")) {
openUri(curl_website); openUri(cpr_website);
} }
ImGui::TextUnformatted("Licence: MIT/X derivative"); ImGui::TextUnformatted("Licence: MIT");
static auto curl_licence = _rs.getRaw("LICENSE.curl"); static const auto cpr_licence = _rs.get("LICENSE.cpr");
if(ImGui::BeginChild("##libcurlLicence", {0.0f, float(windowSize().y()) * 0.3f}, true)) { if(ImGui::BeginChild("##cprLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
ImGui::TextEx(curl_licence.data(), curl_licence.data() + curl_licence.size(), ImGuiTextFlags_None); ImGui::TextUnformatted(cpr_licence.c_str());
ImGui::PopFont();
}
ImGui::EndChild();
ImGui::TreePop();
}
if(ImGui::TreeNodeEx("JSON for Modern C++ (aka json.hpp)", ImGuiTreeNodeFlags_SpanAvailWidth)) {
const char* json_website = "https://json.nlohmann.me/";
drawAlignedText(ICON_FA_GLOBE " %s", json_website);
ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) {
ImGui::SetClipboardText(json_website);
}
ImGui::SameLine();
if(ImGui::Button("Open in browser")) {
openUri(json_website);
}
ImGui::TextUnformatted("Licence: MIT");
static const auto json_licence = _rs.get("LICENSE.json");
if(ImGui::BeginChild("##jsonLicence", {0.0f, windowSize().y() * 0.3f}, true)) {
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
ImGui::TextUnformatted(json_licence.c_str());
ImGui::PopFont(); ImGui::PopFont();
} }
ImGui::EndChild(); ImGui::EndChild();
@ -284,7 +296,7 @@ void SaveTool::drawAbout() {
if(ImGui::TreeNodeEx("Font Awesome", ImGuiTreeNodeFlags_SpanAvailWidth)) { if(ImGui::TreeNodeEx("Font Awesome", ImGuiTreeNodeFlags_SpanAvailWidth)) {
ImGui::TextUnformatted("Version used: 5.15.3"); ImGui::TextUnformatted("Version used: 5.15.3");
auto fa_website = "https://fontawesome.com/"; const char* fa_website = "https://fontawesome.com/";
drawAlignedText(ICON_FA_GLOBE " %s", fa_website); drawAlignedText(ICON_FA_GLOBE " %s", fa_website);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {
@ -301,7 +313,7 @@ void SaveTool::drawAbout() {
} }
if(ImGui::TreeNodeEx("IconFontCppHeaders", ImGuiTreeNodeFlags_SpanAvailWidth)) { if(ImGui::TreeNodeEx("IconFontCppHeaders", ImGuiTreeNodeFlags_SpanAvailWidth)) {
auto icon_repo = "https://github.com/juliettef/IconFontCppHeaders"; const char* icon_repo = "https://github.com/juliettef/IconFontCppHeaders";
drawAlignedText(ICON_FA_GITHUB " %s", icon_repo); drawAlignedText(ICON_FA_GITHUB " %s", icon_repo);
ImGui::SameLine(); ImGui::SameLine();
if(ImGui::Button("Copy to clipboard")) { if(ImGui::Button("Copy to clipboard")) {

View File

@ -14,39 +14,39 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Utility/Path.h> #include "SaveTool.h"
#include <Corrade/Utility/Directory.h>
#include "../FontAwesome/IconsFontAwesome5.h" #include "../FontAwesome/IconsFontAwesome5.h"
#include "../FontAwesome/IconsFontAwesome5Brands.h" #include "../FontAwesome/IconsFontAwesome5Brands.h"
#include "SaveTool.h"
void SaveTool::drawMainMenu() { void SaveTool::drawMainMenu() {
if(ImGui::BeginMainMenuBar()) { if(ImGui::BeginMainMenuBar()) {
if(ImGui::BeginMenu("Save Tool##SaveToolMenu")) { if(ImGui::BeginMenu("Save Tool##SaveToolMenu")) {
if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open game data directory", Utility::Path::exists(_gameDataDir))) { if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open game data directory", Utility::Directory::exists(_gameDataDir))) {
if(ImGui::MenuItem(ICON_FA_COG " Configuration", nullptr, false, Utility::Path::exists(_configDir))) { if(ImGui::MenuItem(ICON_FA_COG " Configuration", nullptr, false, Utility::Directory::exists(_configDir))) {
openUri(Utility::Path::toNativeSeparators(_configDir)); openUri(Utility::Directory::toNativeSeparators(_configDir));
} }
if(ImGui::MenuItem(ICON_FA_SAVE " Saves", nullptr, false, Utility::Path::exists(_saveDir))) { if(ImGui::MenuItem(ICON_FA_SAVE " Saves", nullptr, false, Utility::Directory::exists(_saveDir))) {
openUri(Utility::Path::toNativeSeparators(_saveDir)); openUri(Utility::Directory::toNativeSeparators(_saveDir));
} }
if(ImGui::MenuItem(ICON_FA_IMAGE " Screenshots", nullptr, false, Utility::Path::exists(_screenshotsDir))) { if(ImGui::MenuItem(ICON_FA_IMAGE " Screenshots", nullptr, false, Utility::Directory::exists(_screenshotsDir))) {
openUri(Utility::Path::toNativeSeparators(_screenshotsDir)); openUri(Utility::Directory::toNativeSeparators(_screenshotsDir));
} }
ImGui::EndMenu(); ImGui::EndMenu();
} }
if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open manager directory")) { if(ImGui::BeginMenu(ICON_FA_FOLDER_OPEN " Open manager directory")) {
if(ImGui::MenuItem(ICON_FA_FILE_ARCHIVE " Profile backups", nullptr, false, Utility::Path::exists(_backupsDir))) { if(ImGui::MenuItem(ICON_FA_FILE_ARCHIVE " Profile backups", nullptr, false, Utility::Directory::exists(_backupsDir))) {
openUri(Utility::Path::toNativeSeparators(_backupsDir)); openUri(Utility::Directory::toNativeSeparators(_backupsDir));
} }
if(ImGui::MenuItem(ICON_FA_EXCHANGE_ALT " Staging area", nullptr, false, Utility::Path::exists(_stagingDir))) { if(ImGui::MenuItem(ICON_FA_EXCHANGE_ALT " Staging area", nullptr, false, Utility::Directory::exists(_stagingDir))) {
openUri(Utility::Path::toNativeSeparators(_stagingDir)); openUri(Utility::Directory::toNativeSeparators(_stagingDir));
} }
ImGui::EndMenu(); ImGui::EndMenu();
@ -55,48 +55,47 @@ void SaveTool::drawMainMenu() {
ImGui::Separator(); ImGui::Separator();
if(ImGui::BeginMenu(ICON_FA_COG " Settings")) { if(ImGui::BeginMenu(ICON_FA_COG " Settings")) {
ImGui::BeginGroup(); drawAlignedText("Frame limiter:");
drawAlignedText("Vertical sync:");
if(_swapInterval == 0) {
drawAlignedText("FPS cap:");
}
ImGui::EndGroup();
ImGui::SameLine(); ImGui::SameLine();
ImGui::BeginGroup(); static UnsignedByte selection = static_cast<UnsignedByte>(_framelimit);
static const char* framelimit_labels[3] = {
static const char* framelimit_labels[] = { "V-sync",
"Off", "Half V-sync",
"Every VBLANK", "FPS cap, no V-sync"
"Every second VBLANK",
"Every third VBLANK",
}; };
ImGui::PushItemWidth(300.0f); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth());
if(ImGui::BeginCombo("##FrameLimit", framelimit_labels[selection])) {
if(ImGui::BeginCombo("##FrameLimit", framelimit_labels[_swapInterval])) { if(ImGui::Selectable(framelimit_labels[0], _framelimit == Framelimit::Vsync)) {
for(int i = 0; i <= 3; i++) { selection = 0;
if(ImGui::Selectable(framelimit_labels[i], _swapInterval == i)) { _framelimit = Framelimit::Vsync;
_swapInterval = i; setSwapInterval(1);
setSwapInterval(i);
if(i == 0) {
setMinimalLoopPeriod(0);
} }
if(ImGui::Selectable(framelimit_labels[1], _framelimit == Framelimit::HalfVsync)) {
selection = 1;
_framelimit = Framelimit::HalfVsync;
setSwapInterval(2);
} }
if(ImGui::Selectable(framelimit_labels[2], _framelimit == Framelimit::FpsCap)) {
selection = 2;
_framelimit = Framelimit::FpsCap;
setSwapInterval(0);
setMinimalLoopPeriod(1000 / _fpsCap);
} }
ImGui::EndCombo(); ImGui::EndCombo();
} }
if(_swapInterval == 0) { if(_framelimit == Framelimit::FpsCap) {
ImGui::SliderFloat("##FpsCapSlider", &_fpsCap, 15.0f, 301.0f, static constexpr UnsignedInt min_fps = 15;
_fpsCap != 301.0f ? "%.0f" : "Uncapped", ImGuiSliderFlags_AlwaysClamp); static constexpr UnsignedInt max_fps = 150;
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvailWidth());
if(ImGui::SliderScalar("##FpsSlider", ImGuiDataType_U32, &_fpsCap, &min_fps, &max_fps, "%u FPS", ImGuiSliderFlags_AlwaysClamp)) {
setMinimalLoopPeriod(1000 / _fpsCap);
}
} }
ImGui::PopItemWidth();
ImGui::EndGroup();
ImGui::Checkbox("Cheat mode", &_cheatMode); ImGui::Checkbox("Cheat mode", &_cheatMode);
ImGui::SameLine(); ImGui::SameLine();
@ -104,10 +103,10 @@ void SaveTool::drawMainMenu() {
drawHelpMarker("This gives access to save edition features that can be considered cheats.", drawHelpMarker("This gives access to save edition features that can be considered cheats.",
Float(windowSize().x()) * 0.4f); Float(windowSize().x()) * 0.4f);
ImGui::Checkbox("Advanced mode", &_advancedMode); ImGui::Checkbox("Unsafe mode", &_unsafeMode);
ImGui::SameLine(); ImGui::SameLine();
ImGui::AlignTextToFramePadding(); ImGui::AlignTextToFramePadding();
drawHelpMarker("This gives access to editing values that have unknown purposes or are undocumented.", drawHelpMarker("This allows changing the state of save files in the game's save folder even when the game is running.",
Float(windowSize().x()) * 0.4f); Float(windowSize().x()) * 0.4f);
ImGui::Checkbox("Check for updates on startup", &_checkUpdatesOnStartup); ImGui::Checkbox("Check for updates on startup", &_checkUpdatesOnStartup);
@ -118,7 +117,7 @@ void SaveTool::drawMainMenu() {
} }
if(_updateAvailable) { if(_updateAvailable) {
drawAlignedText("Version %s is available.", _latestVersion.data()); drawAlignedText("Version %s is available.", _latestVersion.c_str());
if(ImGui::Button(ICON_FA_FILE_SIGNATURE " Release notes")) { if(ImGui::Button(ICON_FA_FILE_SIGNATURE " Release notes")) {
openUri(_releaseLink); openUri(_releaseLink);
} }
@ -156,11 +155,11 @@ void SaveTool::drawMainMenu() {
if(ImGui::BeginMenu(ICON_FA_DISCORD " Discord communities")) { if(ImGui::BeginMenu(ICON_FA_DISCORD " Discord communities")) {
if(ImGui::MenuItem("Official server")) { if(ImGui::MenuItem("Official server")) {
openUri("https://discord.gg/sekai-project"); openUri("https://discord.gg/quS7E46");
} }
if(ImGui::MenuItem("Community server")) { if(ImGui::MenuItem("Community server")) {
openUri("https://discord.gg/massbuildercommunity"); openUri("https://discord.gg/YSSRTRB");
} }
ImGui::EndMenu(); ImGui::EndMenu();
@ -169,7 +168,7 @@ void SaveTool::drawMainMenu() {
ImGui::EndMenu(); ImGui::EndMenu();
} }
#ifdef SAVETOOL_DEBUG_BUILD #ifdef SAVETOOL_DEBUG_BUILD
if(ImGui::BeginMenu("Debug tools")) { if(ImGui::BeginMenu("Debug tools")) {
ImGui::MenuItem("ImGui demo window", nullptr, &_demoWindow); ImGui::MenuItem("ImGui demo window", nullptr, &_demoWindow);
ImGui::MenuItem("ImGui style editor", nullptr, &_styleEditor); ImGui::MenuItem("ImGui style editor", nullptr, &_styleEditor);
@ -177,10 +176,10 @@ void SaveTool::drawMainMenu() {
ImGui::EndMenu(); ImGui::EndMenu();
} }
#endif #endif
if(ImGui::BeginMenu("Help")) { if(ImGui::BeginMenu("Help")) {
if(ImGui::BeginMenu(ICON_FA_KEYBOARD " Keyboard shortcuts")) { if(ImGui::BeginMenu(ICON_FA_BOOK " ImGui user guide")) {
ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text."); 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("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
ImGui::BulletText("While inputing text:\n"); ImGui::BulletText("While inputing text:\n");

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Utility/Format.h> #include <Corrade/Utility/FormatStl.h>
#include <Magnum/Math/Functions.h> #include <Magnum/Math/Functions.h>
@ -24,7 +24,7 @@
#include "ToastQueue.h" #include "ToastQueue.h"
using namespace Containers::Literals; using namespace Corrade;
constexpr UnsignedInt success_colour = 0xff67d23bu; constexpr UnsignedInt success_colour = 0xff67d23bu;
constexpr UnsignedInt info_colour = 0xffcc832fu; constexpr UnsignedInt info_colour = 0xffcc832fu;
@ -36,7 +36,7 @@ constexpr Float base_opacity = 1.0f;
constexpr Vector2 padding{20.0f, 20.0f}; constexpr Vector2 padding{20.0f, 20.0f};
constexpr Float toast_spacing = 10.0f; constexpr Float toast_spacing = 10.0f;
Toast::Toast(Type type, Containers::StringView message, std::chrono::milliseconds timeout): Toast::Toast(Type type, const std::string& message, std::chrono::milliseconds timeout):
_type{type}, _message{message}, _timeout{timeout}, _creationTime{std::chrono::steady_clock::now()} _type{type}, _message{message}, _timeout{timeout}, _creationTime{std::chrono::steady_clock::now()}
{ {
_phaseTrack = Animation::Track<UnsignedInt, Phase>{{ _phaseTrack = Animation::Track<UnsignedInt, Phase>{{
@ -51,7 +51,7 @@ auto Toast::type() -> Type {
return _type; return _type;
} }
auto Toast::message() -> Containers::StringView { auto Toast::message() -> const std::string& {
return _message; return _message;
} }
@ -89,7 +89,7 @@ void ToastQueue::addToast(Toast&& toast) {
_toasts.push_back(std::move(toast)); _toasts.push_back(std::move(toast));
} }
void ToastQueue::addToast(Toast::Type type, Containers::StringView message, std::chrono::milliseconds timeout) { void ToastQueue::addToast(Toast::Type type, const std::string& message, std::chrono::milliseconds timeout) {
_toasts.emplace_back(type, message, timeout); _toasts.emplace_back(type, message, timeout);
} }
@ -104,14 +104,14 @@ void ToastQueue::draw(Vector2i viewport_size) {
continue; continue;
} }
Containers::String win_id = Utility::format("##Toast{}", i); std::string win_id = Utility::formatString("##Toast{}", i);
Float opacity = base_opacity * current->opacity(); Float opacity = base_opacity * current->opacity();
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, opacity); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, opacity);
ImGui::SetNextWindowPos({viewport_size.x() - padding.x(), viewport_size.y() - padding.y() - height}, ImGuiCond_Always, {1.0f, 1.0f}); ImGui::SetNextWindowPos({viewport_size.x() - padding.x(), viewport_size.y() - padding.y() - height}, ImGuiCond_Always, {1.0f, 1.0f});
if(ImGui::Begin(win_id.data(), nullptr, if(ImGui::Begin(win_id.c_str(), nullptr,
ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoDecoration| ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoDecoration|
ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoNav|ImGuiWindowFlags_NoFocusOnAppearing)) ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoNav|ImGuiWindowFlags_NoFocusOnAppearing))
{ {
@ -142,9 +142,12 @@ void ToastQueue::draw(Vector2i viewport_size) {
ImGui::SameLine(); ImGui::SameLine();
} }
ImGui::PushTextWrapPos(500.0f); if(current->message().length() > 127) {
ImGui::TextColored(colour, current->message().data()); ImGui::TextColored(colour, "%.*s...", 127, current->message().c_str());
ImGui::PopTextWrapPos(); }
else {
ImGui::TextColored(colour, current->message().c_str());
}
height += ImGui::GetWindowHeight() + toast_spacing; height += ImGui::GetWindowHeight() + toast_spacing;
} }

View File

@ -17,14 +17,12 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <chrono> #include <chrono>
#include <string>
#include <vector> #include <vector>
#include <Corrade/Containers/String.h>
#include <Magnum/Magnum.h> #include <Magnum/Magnum.h>
#include <Magnum/Animation/Track.h> #include <Magnum/Animation/Track.h>
using namespace Corrade;
using namespace Magnum; using namespace Magnum;
class Toast { class Toast {
@ -37,7 +35,7 @@ class Toast {
FadeIn, Wait, FadeOut, TimedOut FadeIn, Wait, FadeOut, TimedOut
}; };
explicit Toast(Type type, Containers::StringView message, explicit Toast(Type type, const std::string& message,
std::chrono::milliseconds timeout = std::chrono::milliseconds{3000}); std::chrono::milliseconds timeout = std::chrono::milliseconds{3000});
Toast(const Toast& other) = delete; Toast(const Toast& other) = delete;
@ -48,7 +46,7 @@ class Toast {
auto type() -> Type; auto type() -> Type;
auto message() -> Containers::StringView; auto message() -> std::string const&;
auto timeout() -> std::chrono::milliseconds; auto timeout() -> std::chrono::milliseconds;
@ -62,7 +60,7 @@ class Toast {
private: private:
Type _type{Type::Default}; Type _type{Type::Default};
Containers::String _message; std::string _message;
std::chrono::milliseconds _timeout; std::chrono::milliseconds _timeout;
std::chrono::steady_clock::time_point _creationTime; std::chrono::steady_clock::time_point _creationTime;
Animation::Track<UnsignedInt, Phase> _phaseTrack; Animation::Track<UnsignedInt, Phase> _phaseTrack;
@ -72,7 +70,7 @@ class ToastQueue {
public: public:
void addToast(Toast&& toast); void addToast(Toast&& toast);
void addToast(Toast::Type type, Containers::StringView message, void addToast(Toast::Type type, const std::string& message,
std::chrono::milliseconds timeout = std::chrono::milliseconds{3000}); std::chrono::milliseconds timeout = std::chrono::milliseconds{3000});
void draw(Vector2i viewport_size); void draw(Vector2i viewport_size);

View File

@ -16,18 +16,16 @@
#include <cstring> #include <cstring>
#include <Corrade/Containers/Array.h> #include <string>
#include <Corrade/Containers/String.h>
#include "../Logger/Logger.h"
#include "BinaryReader.h" #include "BinaryReader.h"
BinaryReader::BinaryReader(Containers::StringView filename) { BinaryReader::BinaryReader(const std::string& filename) {
_file = std::fopen(filename.data(), "rb"); _file = std::fopen(filename.c_str(), "rb");
if(!_file) { if(!_file) {
LOG_ERROR_FORMAT("Couldn't open {} for reading: {}", filename, std::strerror(errno)); Utility::Error{} << "Couldn't open" << filename.c_str() << "for reading:\n"
<< std::strerror(errno);
} }
} }
@ -108,15 +106,16 @@ auto BinaryReader::readArray(Containers::Array<char>& array, std::size_t count)
return std::fread(array.data(), sizeof(char), count, _file) == count; return std::fread(array.data(), sizeof(char), count, _file) == count;
} }
auto BinaryReader::readUEString(Containers::String& str) -> bool { auto BinaryReader::readUEString(std::string& str) -> bool {
UnsignedInt length = 0; UnsignedInt length = 0;
if(!readUnsignedInt(length) || length == 0) { if(!readUnsignedInt(length) || length == 0) {
return false; return false;
} }
str = Containers::String{ValueInit, length - 1}; str = std::string{};
str.resize(length - 1);
return std::fread(str.data(), sizeof(char), length, _file) == length; return std::fread(&str[0], sizeof(char), length, _file) == length;
} }
auto BinaryReader::peekChar() -> Int { auto BinaryReader::peekChar() -> Int {

View File

@ -18,9 +18,9 @@
#include <cstdio> #include <cstdio>
#include <Corrade/Containers/Containers.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/StaticArray.h> #include <Corrade/Containers/StaticArray.h>
#include <Corrade/Containers/StringView.h> #include <Corrade/Utility/StlForwardString.h>
#include <Magnum/Types.h> #include <Magnum/Types.h>
@ -29,7 +29,7 @@ using namespace Magnum;
class BinaryReader { class BinaryReader {
public: public:
explicit BinaryReader(Containers::StringView filename); explicit BinaryReader(const std::string& filename);
~BinaryReader(); ~BinaryReader();
auto open() -> bool; auto open() -> bool;
@ -63,7 +63,7 @@ class BinaryReader {
return std::fread(array.data(), sizeof(char), S, _file) == S; return std::fread(array.data(), sizeof(char), S, _file) == S;
} }
auto readUEString(Containers::String& str) -> bool; auto readUEString(std::string& str) -> bool;
auto peekChar() -> Int; auto peekChar() -> Int;

View File

@ -16,16 +16,15 @@
#include <cstring> #include <cstring>
#include "../Logger/Logger.h" #include <string>
#include "BinaryWriter.h" #include "BinaryWriter.h"
using namespace Containers::Literals; BinaryWriter::BinaryWriter(const std::string& filename) {
_file = std::fopen(filename.c_str(), "wb");
BinaryWriter::BinaryWriter(Containers::StringView filename) {
_file = std::fopen(filename.data(), "wb");
if(!_file) { if(!_file) {
LOG_ERROR_FORMAT("Couldn't open {} for reading: {}", filename, std::strerror(errno)); Utility::Error{} << "Couldn't open" << filename.c_str() << "for reading:\n"
<< std::strerror(errno);
} }
} }
@ -115,25 +114,24 @@ auto BinaryWriter::writeArray(Containers::ArrayView<const char> array) -> bool {
return std::fwrite(array.data(), sizeof(char), array.size(), _file) == array.size(); return std::fwrite(array.data(), sizeof(char), array.size(), _file) == array.size();
} }
auto BinaryWriter::writeUEString(Containers::StringView str) -> bool { auto BinaryWriter::writeUEString(const std::string& str) -> bool {
if(str.size() > UINT32_MAX) { if(str.length() > UINT32_MAX) {
LOG_ERROR_FORMAT("String is too big. Expected size() < UINT32_MAX, got {} instead.", str.size()); Utility::Error{} << "BinaryWriter::writeUEString(): string is too big.";
return false; return false;
} }
writeUnsignedInt(static_cast<UnsignedInt>(str.size()) + 1); writeUnsignedInt(static_cast<UnsignedInt>(str.length()) + 1);
if(str.size() > 0) { if(str.length() > 0) {
std::size_t count = std::fwrite(str.data(), sizeof(char), str.size(), _file); std::size_t count = std::fwrite(&str[0], sizeof(char), str.length(), _file);
if(count != str.size()) { if(count != str.length()) {
return false; return false;
} }
} }
return writeChar('\0'); return writeChar('\0');
} }
auto BinaryWriter::writeUEStringToArray(Containers::StringView value) -> UnsignedLong { auto BinaryWriter::writeUEStringToArray(const std::string& value) -> UnsignedLong {
return writeValueToArray<UnsignedInt>(UnsignedInt(value.size()) + 1u) + Containers::ArrayView<const char> view{value.c_str(), value.length()};
writeDataToArray(Containers::ArrayView<const char>{value}) + return writeValueToArray<UnsignedInt>(UnsignedInt(value.length()) + 1u) + writeDataToArray(view) + writeValueToArray<char>('\0');
writeValueToArray<char>('\0');
} }

View File

@ -21,7 +21,7 @@
#include <Corrade/Containers/ArrayView.h> #include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/GrowableArray.h> #include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/StaticArray.h> #include <Corrade/Containers/StaticArray.h>
#include <Corrade/Containers/StringView.h> #include <Corrade/Utility/StlForwardString.h>
#include <Magnum/Types.h> #include <Magnum/Types.h>
@ -30,7 +30,7 @@ using namespace Magnum;
class BinaryWriter { class BinaryWriter {
public: public:
explicit BinaryWriter(Containers::StringView filename); explicit BinaryWriter(const std::string& filename);
~BinaryWriter(); ~BinaryWriter();
BinaryWriter(const BinaryWriter& other) = delete; BinaryWriter(const BinaryWriter& other) = delete;
@ -71,7 +71,7 @@ class BinaryWriter {
return std::fwrite(array.data(), sizeof(char), S, _file) == S; return std::fwrite(array.data(), sizeof(char), S, _file) == S;
} }
auto writeUEString(Containers::StringView str) -> bool; auto writeUEString(const std::string& str) -> bool;
template<typename T, typename U = std::conditional_t<std::is_trivially_copyable<T>::value, T, T&>> template<typename T, typename U = std::conditional_t<std::is_trivially_copyable<T>::value, T, T&>>
auto writeValueToArray(U value) -> UnsignedLong { auto writeValueToArray(U value) -> UnsignedLong {
@ -79,7 +79,7 @@ class BinaryWriter {
return writeDataToArray(view); return writeDataToArray(view);
} }
auto writeUEStringToArray(Containers::StringView value) -> UnsignedLong; auto writeUEStringToArray(const std::string& value) -> UnsignedLong;
template<typename T> template<typename T>
void writeValueToArrayAt(T& value, UnsignedLong position) { void writeValueToArrayAt(T& value, UnsignedLong position) {

View File

@ -23,18 +23,18 @@
#include "Debug.h" #include "Debug.h"
Utility::Debug& operator<<(Utility::Debug& debug, const ArrayProperty* prop) { Utility::Debug& operator<<(Utility::Debug& debug, const ArrayProperty* prop) {
return debug << (*prop->name) << Utility::Debug::nospace << ":" << return debug << (*prop->name).c_str() << Utility::Debug::nospace << ":" <<
prop->propertyType << "of" << prop->items.size() << prop->itemType; prop->propertyType.c_str() << "of" << prop->items.size() << prop->itemType.c_str();
} }
Utility::Debug& operator<<(Utility::Debug& debug, const SetProperty* prop) { Utility::Debug& operator<<(Utility::Debug& debug, const SetProperty* prop) {
return debug << (*prop->name) << Utility::Debug::nospace << ":" << return debug << (*prop->name).c_str() << Utility::Debug::nospace << ":" <<
prop->propertyType << "of" << prop->items.size() << prop->itemType; prop->propertyType.c_str() << "of" << prop->items.size() << prop->itemType.c_str();
} }
Utility::Debug& operator<<(Utility::Debug& debug, const GenericStructProperty* prop) { Utility::Debug& operator<<(Utility::Debug& debug, const GenericStructProperty* prop) {
debug << (*prop->name) << Utility::Debug::nospace << ":" << debug << (*prop->name).c_str() << Utility::Debug::nospace << ":" <<
prop->structType << "(" << Utility::Debug::nospace << prop->propertyType << Utility::Debug::nospace << prop->structType.c_str() << "(" << Utility::Debug::nospace << prop->propertyType.c_str() << Utility::Debug::nospace <<
") Contents:"; ") Contents:";
for(const auto& item : prop->properties) { for(const auto& item : prop->properties) {
debug << "\n " << Utility::Debug::nospace << item.get(); debug << "\n " << Utility::Debug::nospace << item.get();
@ -48,8 +48,8 @@ Utility::Debug& operator<<(Utility::Debug& debug, const StructProperty* prop) {
return debug << cast; return debug << cast;
} }
return debug << (*prop->name) << Utility::Debug::nospace << ":" << return debug << (*prop->name).c_str() << Utility::Debug::nospace << ":" <<
prop->structType << "(" << Utility::Debug::nospace << prop->propertyType << Utility::Debug::nospace << ")"; prop->structType.c_str() << "(" << Utility::Debug::nospace << prop->propertyType.c_str() << Utility::Debug::nospace << ")";
} }
Utility::Debug& operator<<(Utility::Debug& debug, const UnrealPropertyBase* prop) { Utility::Debug& operator<<(Utility::Debug& debug, const UnrealPropertyBase* prop) {
@ -72,5 +72,5 @@ Utility::Debug& operator<<(Utility::Debug& debug, const UnrealPropertyBase* prop
} }
} }
return debug << (*prop->name) << Utility::Debug::nospace << ":" << prop->propertyType; return debug << (*prop->name).c_str() << Utility::Debug::nospace << ":" << prop->propertyType.c_str();
} }

View File

@ -40,10 +40,9 @@
#include "BinaryReader.h" #include "BinaryReader.h"
#include "BinaryWriter.h" #include "BinaryWriter.h"
#include "../Logger/Logger.h"
#include "PropertySerialiser.h" #include "PropertySerialiser.h"
PropertySerialiser::PropertySerialiser() { PropertySerialiser::PropertySerialiser() {
arrayAppend(_serialisers, Containers::pointer<ArrayPropertySerialiser>()); arrayAppend(_serialisers, Containers::pointer<ArrayPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<BoolPropertySerialiser>()); arrayAppend(_serialisers, Containers::pointer<BoolPropertySerialiser>());
@ -67,17 +66,12 @@ PropertySerialiser::PropertySerialiser() {
arrayAppend(_collectionSerialisers, Containers::pointer<StructSerialiser>()); arrayAppend(_collectionSerialisers, Containers::pointer<StructSerialiser>());
} }
auto PropertySerialiser::instance() -> PropertySerialiser& {
static PropertySerialiser serialiser;
return serialiser;
}
auto PropertySerialiser::read(BinaryReader& reader) -> UnrealPropertyBase::ptr { auto PropertySerialiser::read(BinaryReader& reader) -> UnrealPropertyBase::ptr {
if(reader.peekChar() < 0 || reader.eof()) { if(reader.peekChar() < 0 || reader.eof()) {
return nullptr; return nullptr;
} }
Containers::String name; std::string name;
if(!reader.readUEString(name)) { if(!reader.readUEString(name)) {
return nullptr; return nullptr;
} }
@ -86,7 +80,7 @@ auto PropertySerialiser::read(BinaryReader& reader) -> UnrealPropertyBase::ptr {
return Containers::pointer<NoneProperty>(); return Containers::pointer<NoneProperty>();
} }
Containers::String type; std::string type;
if(!reader.readUEString(type)) { if(!reader.readUEString(type)) {
return nullptr; return nullptr;
} }
@ -99,8 +93,7 @@ auto PropertySerialiser::read(BinaryReader& reader) -> UnrealPropertyBase::ptr {
return deserialise(std::move(name), std::move(type), value_length, reader); return deserialise(std::move(name), std::move(type), value_length, reader);
} }
auto PropertySerialiser::readItem(BinaryReader& reader, Containers::String type, UnsignedLong value_length, auto PropertySerialiser::readItem(BinaryReader& reader, std::string type, UnsignedLong value_length, std::string name) -> UnrealPropertyBase::ptr {
Containers::String name) -> UnrealPropertyBase::ptr {
if(reader.peekChar() < 0 || reader.eof()) { if(reader.peekChar() < 0 || reader.eof()) {
return nullptr; return nullptr;
} }
@ -108,9 +101,7 @@ auto PropertySerialiser::readItem(BinaryReader& reader, Containers::String type,
return deserialise(std::move(name), std::move(type), value_length, reader); return deserialise(std::move(name), std::move(type), value_length, reader);
} }
auto PropertySerialiser::readSet(BinaryReader& reader, Containers::StringView item_type, auto PropertySerialiser::readSet(BinaryReader& reader, const std::string& item_type, UnsignedInt count) -> Containers::Array<UnrealPropertyBase::ptr> {
UnsignedInt count) -> Containers::Array<UnrealPropertyBase::ptr>
{
if(reader.peekChar() < 0 || reader.eof()) { if(reader.peekChar() < 0 || reader.eof()) {
return nullptr; return nullptr;
} }
@ -120,12 +111,12 @@ auto PropertySerialiser::readSet(BinaryReader& reader, Containers::StringView it
Containers::Array<UnrealPropertyBase::ptr> array; Containers::Array<UnrealPropertyBase::ptr> array;
if(serialiser) { if(serialiser) {
Containers::String name; std::string name;
if(!reader.readUEString(name)) { if(!reader.readUEString(name)) {
return nullptr; return nullptr;
} }
Containers::String type; std::string type;
if(!reader.readUEString(type)) { if(!reader.readUEString(type)) {
return nullptr; return nullptr;
} }
@ -153,7 +144,7 @@ auto PropertySerialiser::readSet(BinaryReader& reader, Containers::StringView it
return array; return array;
} }
auto PropertySerialiser::deserialise(Containers::String name, Containers::String type, UnsignedLong value_length, auto PropertySerialiser::deserialise(std::string name, std::string type, UnsignedLong value_length,
BinaryReader& reader) -> UnrealPropertyBase::ptr BinaryReader& reader) -> UnrealPropertyBase::ptr
{ {
UnrealPropertyBase::ptr prop; UnrealPropertyBase::ptr prop;
@ -166,7 +157,7 @@ auto PropertySerialiser::deserialise(Containers::String name, Containers::String
prop = serialiser->deserialise(name, type, value_length, reader, *this); prop = serialiser->deserialise(name, type, value_length, reader, *this);
if(!prop) { if(!prop) {
LOG_ERROR("No property."); !Utility::Error{} << "No prop in" << __func__;
return nullptr; return nullptr;
} }
@ -176,8 +167,8 @@ auto PropertySerialiser::deserialise(Containers::String name, Containers::String
return prop; return prop;
} }
auto PropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, Containers::StringView item_type, auto PropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, const std::string& item_type, UnsignedLong& bytes_written,
UnsignedLong& bytes_written, BinaryWriter& writer) -> bool BinaryWriter& writer) -> bool
{ {
auto serialiser = getSerialiser(item_type); auto serialiser = getSerialiser(item_type);
if(!serialiser) { if(!serialiser) {
@ -209,7 +200,7 @@ auto PropertySerialiser::write(UnrealPropertyBase::ptr& prop, UnsignedLong& byte
return ret; return ret;
} }
auto PropertySerialiser::writeItem(UnrealPropertyBase::ptr& prop, Containers::StringView item_type, auto PropertySerialiser::writeItem(UnrealPropertyBase::ptr& prop, const std::string& item_type,
UnsignedLong& bytes_written, BinaryWriter& writer) -> bool UnsignedLong& bytes_written, BinaryWriter& writer) -> bool
{ {
if(prop->name == "None" && prop->propertyType == "NoneProperty" && dynamic_cast<NoneProperty*>(prop.get())) { if(prop->name == "None" && prop->propertyType == "NoneProperty" && dynamic_cast<NoneProperty*>(prop.get())) {
@ -220,9 +211,8 @@ auto PropertySerialiser::writeItem(UnrealPropertyBase::ptr& prop, Containers::St
return serialise(prop, item_type, bytes_written, writer); return serialise(prop, item_type, bytes_written, writer);
} }
auto PropertySerialiser::writeSet(Containers::ArrayView<UnrealPropertyBase::ptr> props, auto PropertySerialiser::writeSet(Containers::ArrayView<UnrealPropertyBase::ptr> props, const std::string& item_type,
Containers::StringView item_type, UnsignedLong& bytes_written, UnsignedLong& bytes_written, BinaryWriter& writer) -> bool
BinaryWriter& writer) -> bool
{ {
auto serialiser = getCollectionSerialiser(item_type); auto serialiser = getCollectionSerialiser(item_type);
if(serialiser) { if(serialiser) {
@ -239,9 +229,9 @@ auto PropertySerialiser::writeSet(Containers::ArrayView<UnrealPropertyBase::ptr>
} }
} }
auto PropertySerialiser::getSerialiser(Containers::StringView item_type) -> AbstractUnrealPropertySerialiser* { auto PropertySerialiser::getSerialiser(const std::string& item_type) -> AbstractUnrealPropertySerialiser* {
for(auto& item : _serialisers) { for(auto& item : _serialisers) {
for(auto serialiser_type : item->types()) { for(const std::string& serialiser_type : item->types()) {
if(item_type == serialiser_type) { if(item_type == serialiser_type) {
return item.get(); return item.get();
} }
@ -251,9 +241,9 @@ auto PropertySerialiser::getSerialiser(Containers::StringView item_type) -> Abst
return nullptr; return nullptr;
} }
auto PropertySerialiser::getCollectionSerialiser(Containers::StringView item_type) -> AbstractUnrealCollectionPropertySerialiser* { auto PropertySerialiser::getCollectionSerialiser(const std::string& item_type) -> AbstractUnrealCollectionPropertySerialiser* {
for(auto& item : _collectionSerialisers) { for(auto& item : _collectionSerialisers) {
for(Containers::StringView serialiser_type : item->types()) { for(const std::string& serialiser_type : item->types()) {
if(item_type == serialiser_type) { if(item_type == serialiser_type) {
return item.get(); return item.get();
} }

View File

@ -17,8 +17,6 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/GrowableArray.h> #include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/String.h>
#include <Corrade/Containers/StringView.h>
#include "Serialisers/AbstractUnrealPropertySerialiser.h" #include "Serialisers/AbstractUnrealPropertySerialiser.h"
#include "Serialisers/AbstractUnrealCollectionPropertySerialiser.h" #include "Serialisers/AbstractUnrealCollectionPropertySerialiser.h"
@ -32,28 +30,21 @@ class BinaryWriter;
class PropertySerialiser { class PropertySerialiser {
public: public:
static auto instance() -> PropertySerialiser&;
auto read(BinaryReader& reader) -> UnrealPropertyBase::ptr;
auto readItem(BinaryReader& reader, Containers::String type, UnsignedLong value_length,
Containers::String name) -> UnrealPropertyBase::ptr;
auto readSet(BinaryReader& reader, Containers::StringView item_type, UnsignedInt count) -> Containers::Array<UnrealPropertyBase::ptr>;
auto deserialise(Containers::String name, Containers::String type, UnsignedLong value_length,
BinaryReader& reader) -> UnrealPropertyBase::ptr;
auto serialise(UnrealPropertyBase::ptr& prop, Containers::StringView item_type, UnsignedLong& bytes_written,
BinaryWriter& writer) -> bool;
auto write(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer) -> bool;
auto writeItem(UnrealPropertyBase::ptr& prop, Containers::StringView item_type, UnsignedLong& bytes_written,
BinaryWriter& writer) -> bool;
auto writeSet(Containers::ArrayView<UnrealPropertyBase::ptr> props, Containers::StringView item_type,
UnsignedLong& bytes_written, BinaryWriter& writer) -> bool;
private:
PropertySerialiser(); PropertySerialiser();
auto getSerialiser(Containers::StringView item_type) -> AbstractUnrealPropertySerialiser*; auto read(BinaryReader& reader) -> UnrealPropertyBase::ptr;
auto getCollectionSerialiser(Containers::StringView item_type) -> AbstractUnrealCollectionPropertySerialiser*; auto readItem(BinaryReader& reader, std::string type, UnsignedLong value_length, std::string name) -> UnrealPropertyBase::ptr;
auto readSet(BinaryReader& reader, const std::string& item_type, UnsignedInt count) -> Containers::Array<UnrealPropertyBase::ptr>;
auto deserialise(std::string name, std::string type, UnsignedLong value_length, BinaryReader& reader) -> UnrealPropertyBase::ptr;
auto serialise(UnrealPropertyBase::ptr& prop, const std::string& item_type, UnsignedLong& bytes_written, BinaryWriter& writer) -> bool;
auto write(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer) -> bool;
auto writeItem(UnrealPropertyBase::ptr& prop, const std::string& item_type, UnsignedLong& bytes_written, BinaryWriter& writer) -> bool;
auto writeSet(Containers::ArrayView<UnrealPropertyBase::ptr> props, const std::string& item_type, UnsignedLong& bytes_written, BinaryWriter& writer) -> bool;
private:
auto getSerialiser(const std::string& item_type) -> AbstractUnrealPropertySerialiser*;
auto getCollectionSerialiser(const std::string& item_type) -> AbstractUnrealCollectionPropertySerialiser*;
Containers::Array<AbstractUnrealPropertySerialiser::ptr> _serialisers; Containers::Array<AbstractUnrealPropertySerialiser::ptr> _serialisers;
Containers::Array<AbstractUnrealCollectionPropertySerialiser::ptr> _collectionSerialisers; Containers::Array<AbstractUnrealCollectionPropertySerialiser::ptr> _collectionSerialisers;

View File

@ -16,10 +16,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ArrayView.h> #include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/Pointer.h> #include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Types.h> #include <Magnum/Types.h>
@ -38,12 +39,9 @@ class AbstractUnrealCollectionPropertySerialiser {
virtual ~AbstractUnrealCollectionPropertySerialiser() = default; virtual ~AbstractUnrealCollectionPropertySerialiser() = default;
virtual auto types() -> Containers::ArrayView<const Containers::String> = 0; virtual auto types() -> Containers::ArrayView<const std::string> = 0;
virtual auto deserialise(Containers::StringView name, Containers::StringView type, virtual auto deserialise(const std::string& name, const std::string& type, UnsignedLong value_length, UnsignedInt count, BinaryReader& reader, PropertySerialiser& serialiser) -> Containers::Array<UnrealPropertyBase::ptr> = 0;
UnsignedLong value_length, UnsignedInt count, BinaryReader& reader,
PropertySerialiser& serialiser) -> Containers::Array<UnrealPropertyBase::ptr> = 0;
virtual auto serialise(Containers::ArrayView<UnrealPropertyBase::ptr> props, Containers::StringView item_type, virtual auto serialise(Containers::ArrayView<UnrealPropertyBase::ptr> props, const std::string& item_type, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool = 0;
UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool = 0;
}; };

View File

@ -16,9 +16,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Pointer.h> #include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Types.h> #include <Magnum/Types.h>
@ -37,11 +38,9 @@ class AbstractUnrealPropertySerialiser {
virtual ~AbstractUnrealPropertySerialiser() = default; virtual ~AbstractUnrealPropertySerialiser() = default;
virtual auto types() -> Containers::ArrayView<const Containers::String> = 0; virtual auto types() -> Containers::ArrayView<const std::string> = 0;
virtual auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, virtual auto deserialise(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr = 0;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr = 0;
virtual auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, virtual auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool = 0;
PropertySerialiser& serialiser) -> bool = 0;
}; };

View File

@ -16,10 +16,11 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ArrayView.h> #include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/Pointer.h> #include <Corrade/Containers/Pointer.h>
#include <Corrade/Containers/StringView.h>
#include <Magnum/Types.h> #include <Magnum/Types.h>
@ -37,10 +38,9 @@ class AbstractUnrealStructSerialiser {
virtual ~AbstractUnrealStructSerialiser() = default; virtual ~AbstractUnrealStructSerialiser() = default;
virtual auto supportsType(Containers::StringView type) -> bool = 0; virtual auto supportsType(const std::string& type) -> bool = 0;
virtual auto deserialise(BinaryReader& reader) -> UnrealPropertyBase::ptr = 0; virtual auto deserialise(BinaryReader& reader) -> UnrealPropertyBase::ptr = 0;
virtual auto serialise(UnrealPropertyBase::ptr& structProp, BinaryWriter& writer, virtual auto serialise(UnrealPropertyBase::ptr& structProp, BinaryWriter& writer, UnsignedLong& bytes_written) -> bool = 0;
UnsignedLong& bytes_written) -> bool = 0;
}; };

View File

@ -14,34 +14,27 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/String.h>
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../PropertySerialiser.h" #include "../PropertySerialiser.h"
#include "../../Logger/Logger.h"
#include "ArrayPropertySerialiser.h" #include "ArrayPropertySerialiser.h"
auto ArrayPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type, auto ArrayPropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
Containers::String item_type; std::string item_type;
if(!reader.readUEString(item_type)) { if(!reader.readUEString(item_type)) {
LOG_ERROR_FORMAT("Couldn't read the item type of array property {}.", name);
return nullptr; return nullptr;
} }
char terminator; char terminator;
if(!reader.readChar(terminator) || terminator != '\0') { if(!reader.readChar(terminator) || terminator != '\0') {
LOG_ERROR_FORMAT("Couldn't read a null byte in array property {}.", name);
return nullptr; return nullptr;
} }
UnsignedInt item_count; UnsignedInt item_count;
if(!reader.readUnsignedInt(item_count)) { if(!reader.readUnsignedInt(item_count)) {
LOG_ERROR_FORMAT("Couldn't read array property {}'s item count.", name);
return nullptr; return nullptr;
} }
@ -57,7 +50,6 @@ auto ArrayPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, U
{ {
auto array_prop = dynamic_cast<ArrayProperty*>(prop.get()); auto array_prop = dynamic_cast<ArrayProperty*>(prop.get());
if(!array_prop) { if(!array_prop) {
LOG_ERROR("The property is not a valid array property.");
return false; return false;
} }

View File

@ -16,24 +16,15 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/StringView.h>
#include <Magnum/Types.h>
#include "UnrealPropertySerialiser.h" #include "UnrealPropertySerialiser.h"
#include "../Types/ArrayProperty.h" #include "../Types/ArrayProperty.h"
using namespace Corrade;
using namespace Magnum;
class ArrayPropertySerialiser : public UnrealPropertySerialiser<ArrayProperty> { class ArrayPropertySerialiser : public UnrealPropertySerialiser<ArrayProperty> {
public: public:
using ptr = Containers::Pointer<ArrayPropertySerialiser>; using ptr = Containers::Pointer<ArrayPropertySerialiser>;
private: private:
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override; auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -16,33 +16,27 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../../Logger/Logger.h"
#include "BoolPropertySerialiser.h" #include "BoolPropertySerialiser.h"
auto BoolPropertySerialiser::types() -> Containers::ArrayView<const Containers::String> { auto BoolPropertySerialiser::types() -> Containers::ArrayView<const std::string> {
using namespace Containers::Literals; static const Containers::Array<std::string> types{InPlaceInit, {"BoolProperty"}};
static const Containers::Array<Containers::String> types{InPlaceInit, {"BoolProperty"_s}};
return types; return types;
} }
auto BoolPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type, auto BoolPropertySerialiser::deserialise(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
if(value_length != 0) { if(value_length != 0) {
LOG_ERROR_FORMAT("Invalid value length for bool property {}. Expected 0, got {} instead.", name, value_length);
return nullptr; return nullptr;
} }
Short value; Short value;
if(!reader.readShort(value)) { if(!reader.readShort(value)) {
LOG_ERROR_FORMAT("Couldn't read bool property {}'s value.", name);
return nullptr; return nullptr;
} }
if(value > 1 || value < 0) { if(value > 1 || value < 0) {
LOG_ERROR_FORMAT("Bool property {}'s value is invalid. Expected 1 or 0, got {} instead.", name, value);
return nullptr; return nullptr;
} }
@ -56,8 +50,8 @@ auto BoolPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
{ {
auto bool_prop = dynamic_cast<BoolProperty*>(prop.get()); auto bool_prop = dynamic_cast<BoolProperty*>(prop.get());
if(!bool_prop) { if(!bool_prop) {
LOG_ERROR("The property is not a valid bool property.");
return false; return false;
} }

View File

@ -16,24 +16,17 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/StringView.h>
#include "AbstractUnrealPropertySerialiser.h" #include "AbstractUnrealPropertySerialiser.h"
#include "../Types/BoolProperty.h" #include "../Types/BoolProperty.h"
using namespace Corrade;
class BoolPropertySerialiser : public AbstractUnrealPropertySerialiser { class BoolPropertySerialiser : public AbstractUnrealPropertySerialiser {
public: public:
using ptr = Containers::Pointer<BoolPropertySerialiser>; using ptr = Containers::Pointer<BoolPropertySerialiser>;
auto types() -> Containers::ArrayView<const Containers::String> override; auto types() -> Containers::ArrayView<const std::string> override;
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialise(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -16,37 +16,31 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../../Logger/Logger.h"
#include "BytePropertySerialiser.h" #include "BytePropertySerialiser.h"
auto BytePropertySerialiser::types() -> Containers::ArrayView<const Containers::String> { auto BytePropertySerialiser::types() -> Containers::ArrayView<const std::string> {
using namespace Containers::Literals; static const Containers::Array<std::string> types{InPlaceInit, {"ByteProperty"}};
static const Containers::Array<Containers::String> types{InPlaceInit, {"ByteProperty"_s}};
return types; return types;
} }
auto BytePropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type, auto BytePropertySerialiser::deserialise(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<ByteProperty>(); auto prop = Containers::pointer<ByteProperty>();
if(value_length != UnsignedLong(-1)) { if(value_length != UnsignedLong(-1)) {
if(!reader.readUEString(prop->enumType)) { if(!reader.readUEString(prop->enumType)) {
LOG_ERROR_FORMAT("Couldn't read byte property {}'s enum type.", name);
return nullptr; return nullptr;
} }
char terminator; char terminator;
if(!reader.readChar(terminator) || terminator != '\0') { if(!reader.readChar(terminator) || terminator != '\0') {
LOG_ERROR_FORMAT("Couldn't read a null byte in byte property {}.", name);
return nullptr; return nullptr;
} }
} }
if(!reader.readUEString(prop->enumValue)) { if(!reader.readUEString(prop->enumValue)) {
LOG_ERROR("Couldn't read byte property's enum value.");
return nullptr; return nullptr;
} }
@ -68,8 +62,8 @@ auto BytePropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
{ {
auto byte_prop = dynamic_cast<ByteProperty*>(prop.get()); auto byte_prop = dynamic_cast<ByteProperty*>(prop.get());
if(!byte_prop) { if(!byte_prop) {
LOG_ERROR("The property is not a valid byte property.");
return false; return false;
} }

View File

@ -16,9 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/StringView.h>
#include "AbstractUnrealPropertySerialiser.h" #include "AbstractUnrealPropertySerialiser.h"
#include "../Types/ByteProperty.h" #include "../Types/ByteProperty.h"
@ -27,11 +24,9 @@ class BytePropertySerialiser : public AbstractUnrealPropertySerialiser {
public: public:
using ptr = Containers::Pointer<BytePropertySerialiser>; using ptr = Containers::Pointer<BytePropertySerialiser>;
auto types() -> Containers::ArrayView<const Containers::String> override; auto types() -> Containers::ArrayView<const std::string> override;
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialise(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -16,20 +16,17 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../../Logger/Logger.h"
#include "ColourPropertySerialiser.h" #include "ColourPropertySerialiser.h"
auto ColourPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type, auto ColourPropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<ColourStructProperty>(); auto prop = Containers::pointer<ColourStructProperty>();
if(!reader.readFloat(prop->r) || !reader.readFloat(prop->g) || if(!reader.readFloat(prop->r) || !reader.readFloat(prop->g) ||
!reader.readFloat(prop->b) || !reader.readFloat(prop->a)) !reader.readFloat(prop->b) || !reader.readFloat(prop->a))
{ {
LOG_ERROR_FORMAT("Couldn't read colour property {}'s value.", name);
return nullptr; return nullptr;
} }
@ -40,8 +37,8 @@ auto ColourPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop,
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
{ {
auto colour_prop = dynamic_cast<ColourStructProperty*>(prop.get()); auto colour_prop = dynamic_cast<ColourStructProperty*>(prop.get());
if(!colour_prop) { if(!colour_prop) {
LOG_ERROR("The property is not a valid colour property.");
return false; return false;
} }

View File

@ -16,21 +16,15 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/StringView.h>
#include "UnrealPropertySerialiser.h" #include "UnrealPropertySerialiser.h"
#include "../Types/ColourStructProperty.h" #include "../Types/ColourStructProperty.h"
using namespace Corrade;
class ColourPropertySerialiser : public UnrealPropertySerialiser<ColourStructProperty> { class ColourPropertySerialiser : public UnrealPropertySerialiser<ColourStructProperty> {
public: public:
using ptr = Containers::Pointer<ColourPropertySerialiser>; using ptr = Containers::Pointer<ColourPropertySerialiser>;
private: private:
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override; auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -16,18 +16,15 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../../Logger/Logger.h"
#include "DateTimePropertySerialiser.h" #include "DateTimePropertySerialiser.h"
auto DateTimePropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type, auto DateTimePropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<DateTimeStructProperty>(); auto prop = Containers::pointer<DateTimeStructProperty>();
if(!reader.readUnsignedLong(prop->timestamp)) { if(!reader.readUnsignedLong(prop->timestamp)) {
LOG_ERROR_FORMAT("Couldn't read date/time property {}'s value.", name);
return nullptr; return nullptr;
} }
@ -38,8 +35,8 @@ auto DateTimePropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
{ {
auto dt_prop = dynamic_cast<DateTimeStructProperty*>(prop.get()); auto dt_prop = dynamic_cast<DateTimeStructProperty*>(prop.get());
if(!dt_prop) { if(!dt_prop) {
LOG_ERROR("The property is not a valid date/time property.");
return false; return false;
} }

View File

@ -16,8 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/StringView.h>
#include "UnrealPropertySerialiser.h" #include "UnrealPropertySerialiser.h"
#include "../Types/DateTimeStructProperty.h" #include "../Types/DateTimeStructProperty.h"
@ -27,8 +25,6 @@ class DateTimePropertySerialiser : public UnrealPropertySerialiser<DateTimeStruc
using ptr = Containers::Pointer<DateTimePropertySerialiser>; using ptr = Containers::Pointer<DateTimePropertySerialiser>;
private: private:
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override; auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -16,35 +16,29 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../../Logger/Logger.h"
#include "EnumPropertySerialiser.h" #include "EnumPropertySerialiser.h"
auto EnumPropertySerialiser::types() -> Containers::ArrayView<const Containers::String> { auto EnumPropertySerialiser::types() -> Containers::ArrayView<const std::string> {
using namespace Containers::Literals; static const Containers::Array<std::string> types{InPlaceInit, {"EnumProperty"}};
static const Containers::Array<Containers::String> types{InPlaceInit, {"EnumProperty"_s}};
return types; return types;
} }
auto EnumPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type, auto EnumPropertySerialiser::deserialise(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<EnumProperty>(); auto prop = Containers::pointer<EnumProperty>();
if(!reader.readUEString(prop->enumType)) { if(!reader.readUEString(prop->enumType)) {
LOG_ERROR_FORMAT("Couldn't read enum property {}'s enum type.", name);
return nullptr; return nullptr;
} }
char terminator; char terminator;
if(!reader.readChar(terminator) || terminator != '\0') { if(!reader.readChar(terminator) || terminator != '\0') {
LOG_ERROR_FORMAT("Couldn't read a null byte in enum property {}.", name);
return nullptr; return nullptr;
} }
if(!reader.readUEString(prop->value)) { if(!reader.readUEString(prop->value)) {
LOG_ERROR_FORMAT("Couldn't read enum property {}'s enum value.", name);
return nullptr; return nullptr;
} }
@ -55,8 +49,8 @@ auto EnumPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLo
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
{ {
auto enum_prop = dynamic_cast<EnumProperty*>(prop.get()); auto enum_prop = dynamic_cast<EnumProperty*>(prop.get());
if(!enum_prop) { if(!enum_prop) {
LOG_ERROR("The property is not a valid enum property.");
return false; return false;
} }

View File

@ -16,9 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/StringView.h>
#include "AbstractUnrealPropertySerialiser.h" #include "AbstractUnrealPropertySerialiser.h"
#include "../Types/EnumProperty.h" #include "../Types/EnumProperty.h"
@ -27,11 +24,9 @@ class EnumPropertySerialiser : public AbstractUnrealPropertySerialiser {
public: public:
using ptr = Containers::Pointer<EnumPropertySerialiser>; using ptr = Containers::Pointer<EnumPropertySerialiser>;
auto types() -> Containers::ArrayView<const Containers::String> override; auto types() -> Containers::ArrayView<const std::string> override;
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialise(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -16,30 +16,25 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../../Logger/Logger.h"
#include "FloatPropertySerialiser.h" #include "FloatPropertySerialiser.h"
auto FloatPropertySerialiser::types() -> Containers::ArrayView<const Containers::String> { auto FloatPropertySerialiser::types() -> Containers::ArrayView<const std::string> {
using namespace Containers::Literals; static const Containers::Array<std::string> types{InPlaceInit, {"FloatProperty"}};
static const Containers::Array<Containers::String> types{InPlaceInit, {"FloatProperty"_s}};
return types; return types;
} }
auto FloatPropertySerialiser::deserialise(Containers::StringView name, Containers::StringView type, auto FloatPropertySerialiser::deserialise(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<FloatProperty>(); auto prop = Containers::pointer<FloatProperty>();
char terminator; char terminator;
if(!reader.readChar(terminator) || terminator != '\0') { if(!reader.readChar(terminator) || terminator != '\0') {
LOG_ERROR_FORMAT("Couldn't read a null byte in float property {}.", name);
return nullptr; return nullptr;
} }
if(!reader.readFloat(prop->value)) { if(!reader.readFloat(prop->value)) {
LOG_ERROR_FORMAT("Couldn't read float property {}'s value.", name);
return nullptr; return nullptr;
} }
@ -50,8 +45,8 @@ auto FloatPropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedL
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
{ {
auto float_prop = dynamic_cast<FloatProperty*>(prop.get()); auto float_prop = dynamic_cast<FloatProperty*>(prop.get());
if(!float_prop) { if(!float_prop) {
LOG_ERROR("The property is not a valid float property.");
return false; return false;
} }

View File

@ -16,9 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/ArrayView.h>
#include <Corrade/Containers/StringView.h>
#include "AbstractUnrealPropertySerialiser.h" #include "AbstractUnrealPropertySerialiser.h"
#include "../Types/FloatProperty.h" #include "../Types/FloatProperty.h"
@ -27,11 +24,9 @@ class FloatPropertySerialiser : public AbstractUnrealPropertySerialiser {
public: public:
using ptr = Containers::Pointer<FloatPropertySerialiser>; using ptr = Containers::Pointer<FloatPropertySerialiser>;
auto types() -> Containers::ArrayView<const Containers::String> override; auto types() -> Containers::ArrayView<const std::string> override;
auto deserialise(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialise(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, auto serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -16,20 +16,16 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../../Logger/Logger.h"
#include "GuidPropertySerialiser.h" #include "GuidPropertySerialiser.h"
using namespace Containers::Literals; auto GuidPropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
auto GuidPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
UnsignedLong value_length, BinaryReader& reader,
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<GuidStructProperty>(); auto prop = Containers::pointer<GuidStructProperty>();
if(!reader.readStaticArray(prop->guid)) { if(!reader.readStaticArray(prop->guid)) {
LOG_ERROR_FORMAT("Couldn't read GUID property {}'s value.", name); Utility::Error{} << "Couldn't read guid in" << __func__;
return nullptr; return nullptr;
} }
@ -40,8 +36,8 @@ auto GuidPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Un
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
{ {
auto guid_prop = dynamic_cast<GuidStructProperty*>(prop.get()); auto guid_prop = dynamic_cast<GuidStructProperty*>(prop.get());
if(!guid_prop) { if(!guid_prop) {
LOG_ERROR("The property is not a valid byte property.");
return false; return false;
} }

View File

@ -16,8 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/StringView.h>
#include "UnrealPropertySerialiser.h" #include "UnrealPropertySerialiser.h"
#include "../Types/GuidStructProperty.h" #include "../Types/GuidStructProperty.h"
@ -27,8 +25,7 @@ class GuidPropertySerialiser : public UnrealPropertySerialiser<GuidStructPropert
using ptr = Containers::Pointer<GuidPropertySerialiser>; using ptr = Containers::Pointer<GuidPropertySerialiser>;
private: private:
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override; BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -16,19 +16,16 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../../Logger/Logger.h"
#include "IntPropertySerialiser.h" #include "IntPropertySerialiser.h"
auto IntPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type, auto IntPropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<IntProperty>(); auto prop = Containers::pointer<IntProperty>();
if(value_length == UnsignedLong(-1)) { if(value_length == UnsignedLong(-1)) {
if(!reader.readInt(prop->value)) { if(!reader.readInt(prop->value)) {
LOG_ERROR("Couldn't read int property's value.");
return nullptr; return nullptr;
} }
@ -38,12 +35,10 @@ auto IntPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
char terminator; char terminator;
if(!reader.readChar(terminator) || terminator != '\0') { if(!reader.readChar(terminator) || terminator != '\0') {
LOG_ERROR_FORMAT("Couldn't read a null byte in int property {}.", name);
return nullptr; return nullptr;
} }
if(!reader.readInt(prop->value)) { if(!reader.readInt(prop->value)) {
LOG_ERROR_FORMAT("Couldn't read int property {}'s value.", name);
return nullptr; return nullptr;
} }
@ -56,8 +51,8 @@ auto IntPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
{ {
auto int_prop = dynamic_cast<IntProperty*>(prop.get()); auto int_prop = dynamic_cast<IntProperty*>(prop.get());
if(!int_prop) { if(!int_prop) {
LOG_ERROR("The property is not a valid int property.");
return false; return false;
} }

View File

@ -16,8 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/StringView.h>
#include "UnrealPropertySerialiser.h" #include "UnrealPropertySerialiser.h"
#include "../Types/IntProperty.h" #include "../Types/IntProperty.h"
@ -27,8 +25,6 @@ class IntPropertySerialiser : public UnrealPropertySerialiser<IntProperty> {
using ptr = Containers::Pointer<IntPropertySerialiser>; using ptr = Containers::Pointer<IntPropertySerialiser>;
private: private:
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override; auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -17,44 +17,36 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../PropertySerialiser.h" #include "../PropertySerialiser.h"
#include "../Types/NoneProperty.h" #include "../Types/NoneProperty.h"
#include "../../Logger/Logger.h"
#include "MapPropertySerialiser.h" #include "MapPropertySerialiser.h"
using namespace Containers::Literals; auto MapPropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
UnsignedLong value_length, BinaryReader& reader,
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<MapProperty>(); auto prop = Containers::pointer<MapProperty>();
if(!reader.readUEString(prop->keyType)) { if(!reader.readUEString(prop->keyType)) {
LOG_ERROR_FORMAT("Couldn't read map property {}'s key type.", name);
return nullptr; return nullptr;
} }
if(!reader.readUEString(prop->valueType)) { if(!reader.readUEString(prop->valueType)) {
LOG_ERROR_FORMAT("Couldn't read map property {}'s value type.", name);
return nullptr; return nullptr;
} }
char terminator; char terminator;
if(!reader.readChar(terminator) || terminator != '\0') { if(!reader.readChar(terminator) || terminator != '\0') {
LOG_ERROR_FORMAT("Couldn't read a null byte in map property {}.", name);
return nullptr; return nullptr;
} }
UnsignedInt null; UnsignedInt null;
if(!reader.readUnsignedInt(null) || null != 0u) { if(!reader.readUnsignedInt(null) || null != 0u) {
LOG_ERROR_FORMAT("Couldn't read a null int in map property {}.", name);
return nullptr; return nullptr;
} }
UnsignedInt count; UnsignedInt count;
if(!reader.readUnsignedInt(count)) { if(!reader.readUnsignedInt(count)) {
LOG_ERROR_FORMAT("Couldn't read map property {}'s item count.", name);
return nullptr; return nullptr;
} }
@ -66,32 +58,30 @@ auto MapPropertySerialiser::deserialiseProperty(Containers::StringView name, Con
for(UnsignedInt i = 0; i < count; i++) { for(UnsignedInt i = 0; i < count; i++) {
MapProperty::KeyValuePair pair; MapProperty::KeyValuePair pair;
if(prop->keyType == "IntProperty"_s || prop->keyType == "StrProperty"_s) { if(prop->keyType == "IntProperty" || prop->keyType == "StrProperty") {
pair.key = serialiser.readItem(reader, prop->keyType, -1, name); pair.key = serialiser.readItem(reader, prop->keyType, -1, name);
if(pair.key == nullptr) { if(pair.key == nullptr) {
LOG_ERROR_FORMAT("Couldn't read a valid key in map property {}.", name);
return nullptr; return nullptr;
} }
} }
else { // Add other branches depending on key type, should more maps appear in the future. else { // Add other branches depending on key type, should more maps appear in the future.
LOG_ERROR_FORMAT("Key type {} not implemented.", prop->keyType);
return nullptr; return nullptr;
} }
UnrealPropertyBase::ptr value_item; UnrealPropertyBase::ptr value_item;
if(prop->valueType == "StructProperty"_s) { if(prop->valueType == "StructProperty") {
while((value_item = serialiser.read(reader)) != nullptr) { while((value_item = serialiser.read(reader)) != nullptr) {
arrayAppend(pair.values, std::move(value_item)); arrayAppend(pair.values, std::move(value_item));
if(pair.values.back()->name == "None"_s && if(pair.values.back()->name == "None" &&
pair.values.back()->propertyType == "NoneProperty"_s && pair.values.back()->propertyType == "NoneProperty" &&
dynamic_cast<NoneProperty*>(pair.values.back().get()) != nullptr) dynamic_cast<NoneProperty*>(pair.values.back().get()) != nullptr)
{ {
break; break;
} }
} }
} }
else if(prop->valueType == "ByteProperty"_s) { else if(prop->valueType == "ByteProperty") {
if((value_item = serialiser.readItem(reader, prop->valueType, -1, name)) == nullptr) { if((value_item = serialiser.readItem(reader, prop->valueType, -1, name)) == nullptr) {
return nullptr; return nullptr;
} }
@ -112,7 +102,6 @@ auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
{ {
auto map_prop = dynamic_cast<MapProperty*>(prop.get()); auto map_prop = dynamic_cast<MapProperty*>(prop.get());
if(!map_prop) { if(!map_prop) {
LOG_ERROR("The property is not a valid map property.");
return false; return false;
} }
@ -128,20 +117,17 @@ auto MapPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
UnsignedLong dummy_bytes_written = 0; UnsignedLong dummy_bytes_written = 0;
for(auto& pair : map_prop->map) { for(auto& pair : map_prop->map) {
if(!serialiser.writeItem(pair.key, map_prop->keyType, dummy_bytes_written, writer)) { if(!serialiser.writeItem(pair.key, map_prop->keyType, dummy_bytes_written, writer)) {
LOG_ERROR("Couldn't write a key.");
return false; return false;
} }
for(auto& value : pair.values) { for(auto& value : pair.values) {
if(map_prop->valueType == "StructProperty"_s) { if(map_prop->valueType == "StructProperty") {
if(!serialiser.write(value, dummy_bytes_written, writer)) { if(!serialiser.write(value, dummy_bytes_written, writer)) {
LOG_ERROR("Couldn't write a value.");
return false; return false;
} }
} }
else { else {
if(!serialiser.writeItem(value, map_prop->valueType, dummy_bytes_written, writer)) { if(!serialiser.writeItem(value, map_prop->valueType, dummy_bytes_written, writer)) {
LOG_ERROR("Couldn't write a value.");
return false; return false;
} }
} }

View File

@ -16,8 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/StringView.h>
#include "UnrealPropertySerialiser.h" #include "UnrealPropertySerialiser.h"
#include "../Types/MapProperty.h" #include "../Types/MapProperty.h"
@ -27,8 +25,6 @@ class MapPropertySerialiser : public UnrealPropertySerialiser<MapProperty> {
using ptr = Containers::Pointer<MapPropertySerialiser>; using ptr = Containers::Pointer<MapPropertySerialiser>;
private: private:
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override; auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -17,60 +17,60 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../PropertySerialiser.h" #include "../PropertySerialiser.h"
#include "../Types/IntProperty.h" #include "../Types/IntProperty.h"
#include "../Types/NoneProperty.h" #include "../Types/NoneProperty.h"
#include "../../Logger/Logger.h"
#include "ResourcePropertySerialiser.h" #include "ResourcePropertySerialiser.h"
using namespace Containers::Literals; auto ResourcePropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
auto ResourcePropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type,
UnsignedLong value_length, BinaryReader& reader,
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<ResourceItemValue>(); auto prop = Containers::pointer<ResourceItemValue>();
auto id_prop = serialiser.read(reader); std::string str;
if(!id_prop) { if(!reader.readUEString(str) || str != "ID_4_AAE08F17428E229EC7A2209F51081A21") {
LOG_ERROR("Couldn't read the ID property."_s);
return nullptr; return nullptr;
} }
if((*id_prop->name) != "ID_4_AAE08F17428E229EC7A2209F51081A21"_s || if(!reader.readUEString(str) || str != "IntProperty") {
id_prop->propertyType != "IntProperty"_s ||
dynamic_cast<IntProperty*>(id_prop.get()) == nullptr)
{
LOG_ERROR("The ID property is invalid."_s);
return nullptr; return nullptr;
} }
prop->id = dynamic_cast<IntProperty*>(id_prop.get())->value; if(!reader.readUnsignedLong(value_length) || value_length != 4ull) {
auto value_prop = serialiser.read(reader);
if(!value_prop) {
LOG_ERROR("Couldn't read the value property."_s);
return nullptr; return nullptr;
} }
if((*value_prop->name) != "Quantity_3_560F09B5485C365D3041888910019CE3"_s || char terminator;
value_prop->propertyType != "IntProperty"_s || if(!reader.readChar(terminator) || terminator != '\0') {
dynamic_cast<IntProperty*>(value_prop.get()) == nullptr)
{
LOG_ERROR("The value property is invalid."_s);
return nullptr; return nullptr;
} }
prop->quantity = dynamic_cast<IntProperty*>(value_prop.get())->value; if(!reader.readInt(prop->id)) {
return nullptr;
}
auto none_prop = serialiser.read(reader); if(!reader.readUEString(str) || str != "Quantity_3_560F09B5485C365D3041888910019CE3") {
return nullptr;
}
if(!none_prop || if(!reader.readUEString(str) || str != "IntProperty") {
(*none_prop->name) != "None"_s || return nullptr;
none_prop->propertyType != "NoneProperty"_s || }
!dynamic_cast<NoneProperty*>(none_prop.get()))
{ if(!reader.readUnsignedLong(value_length) || value_length != 4ull) {
LOG_ERROR("Couldn't find a terminating NoneProperty."_s); return nullptr;
}
if(!reader.readChar(terminator) || terminator != '\0') {
return nullptr;
}
if(!reader.readInt(prop->quantity)) {
return nullptr;
}
if(!reader.readUEString(str) || str != "None") {
return nullptr; return nullptr;
} }
@ -82,23 +82,22 @@ auto ResourcePropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop
{ {
auto res_prop = dynamic_cast<ResourceItemValue*>(prop.get()); auto res_prop = dynamic_cast<ResourceItemValue*>(prop.get());
if(!res_prop) { if(!res_prop) {
LOG_ERROR("The property is not a valid ResourceItemValue property.");
return false; return false;
} }
bytes_written += writer.writeUEStringToArray("ID_4_AAE08F17428E229EC7A2209F51081A21"_s) + bytes_written += writer.writeUEStringToArray("ID_4_AAE08F17428E229EC7A2209F51081A21") +
writer.writeUEStringToArray("IntProperty"_s) + writer.writeUEStringToArray("IntProperty") +
writer.writeValueToArray<UnsignedLong>(4ull) + writer.writeValueToArray<UnsignedLong>(4ull) +
writer.writeValueToArray<char>('\0') + writer.writeValueToArray<char>('\0') +
writer.writeValueToArray<Int>(res_prop->id); writer.writeValueToArray<Int>(res_prop->id);
bytes_written += writer.writeUEStringToArray("Quantity_3_560F09B5485C365D3041888910019CE3"_s) + bytes_written += writer.writeUEStringToArray("Quantity_3_560F09B5485C365D3041888910019CE3") +
writer.writeUEStringToArray("IntProperty"_s) + writer.writeUEStringToArray("IntProperty") +
writer.writeValueToArray<UnsignedLong>(4ull) + writer.writeValueToArray<UnsignedLong>(4ull) +
writer.writeValueToArray<char>('\0') + writer.writeValueToArray<char>('\0') +
writer.writeValueToArray<Int>(res_prop->quantity); writer.writeValueToArray<Int>(res_prop->quantity);
bytes_written += writer.writeUEStringToArray("None"_s); bytes_written += writer.writeUEStringToArray("None");
return true; return true;
} }

View File

@ -16,8 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/StringView.h>
#include "UnrealPropertySerialiser.h" #include "UnrealPropertySerialiser.h"
#include "../Types/ResourceItemValue.h" #include "../Types/ResourceItemValue.h"
@ -27,8 +25,6 @@ class ResourcePropertySerialiser : public UnrealPropertySerialiser<ResourceItemV
using ptr = Containers::Pointer<ResourcePropertySerialiser>; using ptr = Containers::Pointer<ResourcePropertySerialiser>;
private: private:
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override; auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -16,18 +16,15 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../../Logger/Logger.h"
#include "RotatorPropertySerialiser.h" #include "RotatorPropertySerialiser.h"
auto RotatorPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type, auto RotatorPropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
auto prop = Containers::pointer<RotatorStructProperty>(); auto prop = Containers::pointer<RotatorStructProperty>();
if(!reader.readFloat(prop->x) || !reader.readFloat(prop->y) || !reader.readFloat(prop->z)) { if(!reader.readFloat(prop->x) || !reader.readFloat(prop->y) || !reader.readFloat(prop->z)) {
LOG_ERROR_FORMAT("Couldn't read rotator property {}'s value.", name);
return nullptr; return nullptr;
} }
@ -38,8 +35,8 @@ auto RotatorPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop,
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
{ {
auto rotator = dynamic_cast<RotatorStructProperty*>(prop.get()); auto rotator = dynamic_cast<RotatorStructProperty*>(prop.get());
if(!rotator) { if(!rotator) {
LOG_ERROR("The property is not a valid rotator property.");
return false; return false;
} }

View File

@ -16,8 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/StringView.h>
#include "UnrealPropertySerialiser.h" #include "UnrealPropertySerialiser.h"
#include "../Types/RotatorStructProperty.h" #include "../Types/RotatorStructProperty.h"
@ -27,8 +25,6 @@ class RotatorPropertySerialiser : public UnrealPropertySerialiser<RotatorStructP
using ptr = Containers::Pointer<RotatorPropertySerialiser>; using ptr = Containers::Pointer<RotatorPropertySerialiser>;
private: private:
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override; auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
PropertySerialiser& serialiser) -> bool override;
}; };

View File

@ -17,35 +17,29 @@
#include "../BinaryReader.h" #include "../BinaryReader.h"
#include "../BinaryWriter.h" #include "../BinaryWriter.h"
#include "../PropertySerialiser.h" #include "../PropertySerialiser.h"
#include "../../Logger/Logger.h"
#include "SetPropertySerialiser.h" #include "SetPropertySerialiser.h"
auto SetPropertySerialiser::deserialiseProperty(Containers::StringView name, Containers::StringView type, auto SetPropertySerialiser::deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length,
UnsignedLong value_length, BinaryReader& reader, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
{ {
Containers::String item_type; std::string item_type;
if(!reader.readUEString(item_type)) { if(!reader.readUEString(item_type)) {
LOG_ERROR_FORMAT("Couldn't read set property {}'s item type.", name);
return nullptr; return nullptr;
} }
char terminator; char terminator;
if(!reader.readChar(terminator) || terminator != '\0') { if(!reader.readChar(terminator) || terminator != '\0') {
LOG_ERROR_FORMAT("Couldn't read a null byte in set property {}.", name);
return nullptr; return nullptr;
} }
UnsignedInt four_bytes; UnsignedInt four_bytes;
if(!reader.readUnsignedInt(four_bytes) || four_bytes != 0u) { if(!reader.readUnsignedInt(four_bytes) || four_bytes != 0u) {
LOG_ERROR_FORMAT("Couldn't read four null bytes in set property {}.", name);
return nullptr; return nullptr;
} }
UnsignedInt item_count; UnsignedInt item_count;
if(!reader.readUnsignedInt(item_count)) { if(!reader.readUnsignedInt(item_count)) {
LOG_ERROR_FORMAT("Couldn't read set property {}'s item count.", name);
return nullptr; return nullptr;
} }
@ -61,7 +55,6 @@ auto SetPropertySerialiser::serialiseProperty(UnrealPropertyBase::ptr& prop, Uns
{ {
auto set_prop = dynamic_cast<SetProperty*>(prop.get()); auto set_prop = dynamic_cast<SetProperty*>(prop.get());
if(!set_prop) { if(!set_prop) {
LOG_ERROR("The property is not a valid set property.");
return false; return false;
} }

View File

@ -16,8 +16,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <Corrade/Containers/StringView.h>
#include "UnrealPropertySerialiser.h" #include "UnrealPropertySerialiser.h"
#include "../Types/SetProperty.h" #include "../Types/SetProperty.h"
@ -27,8 +25,6 @@ class SetPropertySerialiser : public UnrealPropertySerialiser<SetProperty> {
using ptr = Containers::Pointer<SetPropertySerialiser>; using ptr = Containers::Pointer<SetPropertySerialiser>;
private: private:
auto deserialiseProperty(Containers::StringView name, Containers::StringView type, UnsignedLong value_length, auto deserialiseProperty(const std::string& name, const std::string& type, UnsignedLong value_length, BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override;
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr override; auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool override;
auto serialiseProperty(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer,
PropertySerialiser& serialiser) -> bool override;
}; };

Some files were not shown because too many files have changed in this diff Show More