mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-05-11 03:31:39 +00:00
Compiling and running on Linux. (#49)
* Current work trying to get it to compile. * Update vcpkg.json baseline. * vcpkg, memory mapped file. * Bitscan forward. * Fix localtime_s. * FPS patches high res clock. * Rename Window to GameWindow. Fix guest pointers. * GetCurrentThreadID gone. * Code cache pointers, RenderWindow type. * Add Linux stubs. * Refactor Config. * Fix paths. * Add linux-release config. * FS fixes. * Fix Windows compilation errors & unicode converter crash. * Rename physical memory allocation functions to not clash with X11. * Fix NULL character being added on RtlMultiByteToUnicodeN. * Use std::exit. * Add protection to memory on Linux. * Convert majority of dependencies to submodules. (#48) * Convert majority of dependencies to submodules. * Don't compile header-only libraries. * Fix a few incorrect data types. * Fix config directory. * Unicode fixes & sizeof asserts. * Change the exit function to not call static destructors. * Fix files picker. * Add RelWithDebInfo preset for Linux. * Implement OS Restart on Linux. (#50) --------- Co-authored-by: Dario <dariosamo@gmail.com>
This commit is contained in:
parent
2bcaa61d42
commit
999fe3c4eb
78 changed files with 1723 additions and 1499 deletions
42
.gitmodules
vendored
42
.gitmodules
vendored
|
|
@ -22,3 +22,45 @@
|
|||
[submodule "thirdparty/vcpkg"]
|
||||
path = thirdparty/vcpkg
|
||||
url = https://github.com/microsoft/vcpkg
|
||||
[submodule "thirdparty/volk"]
|
||||
path = thirdparty/volk
|
||||
url = https://github.com/zeux/volk
|
||||
[submodule "thirdparty/SDL"]
|
||||
path = thirdparty/SDL
|
||||
url = https://github.com/libsdl-org/SDL.git
|
||||
[submodule "thirdparty/Vulkan-Headers"]
|
||||
path = thirdparty/Vulkan-Headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||
[submodule "thirdparty/VulkanMemoryAllocator"]
|
||||
path = thirdparty/VulkanMemoryAllocator
|
||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git
|
||||
[submodule "thirdparty/D3D12MemoryAllocator"]
|
||||
path = thirdparty/D3D12MemoryAllocator
|
||||
url = https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator.git
|
||||
[submodule "thirdparty/stb"]
|
||||
path = thirdparty/stb
|
||||
url = https://github.com/nothings/stb.git
|
||||
[submodule "thirdparty/concurrentqueue"]
|
||||
path = thirdparty/concurrentqueue
|
||||
url = https://github.com/cameron314/concurrentqueue.git
|
||||
[submodule "thirdparty/tiny-AES-c"]
|
||||
path = thirdparty/tiny-AES-c
|
||||
url = https://github.com/kokke/tiny-AES-c.git
|
||||
[submodule "thirdparty/magic_enum"]
|
||||
path = thirdparty/magic_enum
|
||||
url = https://github.com/Neargye/magic_enum.git
|
||||
[submodule "thirdparty/nativefiledialog-extended"]
|
||||
path = thirdparty/nativefiledialog-extended
|
||||
url = https://github.com/btzy/nativefiledialog-extended.git
|
||||
[submodule "thirdparty/imgui"]
|
||||
path = thirdparty/imgui
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
[submodule "thirdparty/unordered_dense"]
|
||||
path = thirdparty/unordered_dense
|
||||
url = https://github.com/martinus/unordered_dense.git
|
||||
[submodule "thirdparty/vorbis"]
|
||||
path = thirdparty/vorbis
|
||||
url = https://gitlab.xiph.org/xiph/vorbis.git
|
||||
[submodule "thirdparty/ogg"]
|
||||
path = thirdparty/ogg
|
||||
url = https://gitlab.xiph.org/xiph/ogg.git
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@
|
|||
"type": "FILEPATH"
|
||||
}
|
||||
},
|
||||
"environment": {
|
||||
"VCPKG_ROOT": "${sourceDir}/thirdparty/vcpkg"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
|
|
@ -57,14 +60,12 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-debug",
|
||||
"displayName": "Linux Debug",
|
||||
"description": "Target the Windows Subsystem for Linux (WSL) or a remote Linux system.",
|
||||
"name": "linux-base",
|
||||
"hidden": true,
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"installDir": "${sourceDir}/out/install/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_TOOLCHAIN_FILE": {
|
||||
"value": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
|
||||
"type": "FILEPATH"
|
||||
|
|
@ -88,6 +89,31 @@
|
|||
"remoteSourceRootDir": "$env{HOME}/.vs/$ms{projectDirName}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-debug",
|
||||
"displayName": "Linux-Debug",
|
||||
"inherits": "linux-base",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-relwithdebinfo",
|
||||
"displayName": "Linux-RelWithDebInfo",
|
||||
"inherits": "linux-base",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-release",
|
||||
"displayName": "Linux-Release",
|
||||
"inherits": "linux-base",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_INTERPROCEDURAL_OPTIMIZATION": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ function(BIN2C)
|
|||
endif()
|
||||
|
||||
add_custom_command(OUTPUT "${BIN2C_ARGS_DEST_FILE}.c"
|
||||
COMMAND file_to_c "${BIN2C_ARGS_SOURCE_FILE}" "${BIN2C_ARGS_ARRAY_NAME}" "${BIN2C_ARGS_COMPRESSION_TYPE}" "${BIN2C_ARGS_DEST_FILE}.c" "${BIN2C_ARGS_DEST_FILE}.h"
|
||||
DEPENDS "${BIN2C_ARGS_SOURCE_FILE}" file_to_c
|
||||
COMMAND $<TARGET_FILE:file_to_c> "${BIN2C_ARGS_SOURCE_FILE}" "${BIN2C_ARGS_ARRAY_NAME}" "${BIN2C_ARGS_COMPRESSION_TYPE}" "${BIN2C_ARGS_DEST_FILE}.c" "${BIN2C_ARGS_DEST_FILE}.h"
|
||||
DEPENDS "${BIN2C_ARGS_SOURCE_FILE}"
|
||||
BYPRODUCTS "${BIN2C_ARGS_DEST_FILE}.h"
|
||||
COMMENT "Generating binary header for ${BIN2C_ARGS_SOURCE_FILE}..."
|
||||
)
|
||||
|
|
@ -38,7 +38,6 @@ function(BIN2C)
|
|||
endfunction()
|
||||
|
||||
add_compile_options(
|
||||
/fp:strict
|
||||
-march=sandybridge
|
||||
-fno-strict-aliasing
|
||||
|
||||
|
|
@ -49,8 +48,17 @@ add_compile_options(
|
|||
-Wno-void-pointer-to-int-cast
|
||||
-Wno-int-to-void-pointer-cast
|
||||
-Wno-invalid-offsetof
|
||||
-Wno-null-arithmetic
|
||||
-Wno-null-conversion
|
||||
-Wno-tautological-undefined-compare
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
add_compile_options(/fp:strict)
|
||||
else()
|
||||
add_compile_options(-ffp-model=strict)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(
|
||||
SWA_IMPL
|
||||
SDL_MAIN_HANDLED
|
||||
|
|
@ -89,6 +97,13 @@ if (WIN32)
|
|||
"os/win32/process_win32.cpp"
|
||||
"os/win32/version_win32.cpp"
|
||||
)
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
list(APPEND SWA_OS_CXX_SOURCES
|
||||
"os/linux/logger_linux.cpp"
|
||||
"os/linux/media_linux.cpp"
|
||||
"os/linux/process_linux.cpp"
|
||||
"os/linux/version_linux.cpp"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(SWA_CPU_CXX_SOURCES
|
||||
|
|
@ -151,7 +166,7 @@ set(SWA_UI_CXX_SOURCES
|
|||
"ui/options_menu_thumbnails.cpp"
|
||||
"ui/options_menu.cpp"
|
||||
"ui/sdl_listener.cpp"
|
||||
"ui/window.cpp"
|
||||
"ui/game_window.cpp"
|
||||
)
|
||||
|
||||
set(SWA_INSTALL_CXX_SOURCES
|
||||
|
|
@ -170,25 +185,48 @@ set(SWA_INSTALL_CXX_SOURCES
|
|||
"install/hashes/update.cpp"
|
||||
)
|
||||
|
||||
set(LIBMSPACK_PATH ${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack)
|
||||
|
||||
set(LIBMSPACK_C_SOURCES
|
||||
${LIBMSPACK_PATH}/lzxd.c
|
||||
)
|
||||
|
||||
set_source_files_properties(${LIBMSPACK_C_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
|
||||
|
||||
set(SMOLV_SOURCE_DIR "${SWA_TOOLS_ROOT}/ShaderRecomp/thirdparty/smol-v/source")
|
||||
set(BC_DIFF_SOURCE_DIR "${SWA_TOOLS_ROOT}/bc_diff")
|
||||
|
||||
set(MINIAUDIO_INCLUDE_DIRS "${SWA_THIRDPARTY_ROOT}/miniaudio")
|
||||
|
||||
set(SWA_USER_CXX_SOURCES
|
||||
"user/achievement_data.cpp"
|
||||
"user/config.cpp"
|
||||
"user/config_detail.cpp"
|
||||
)
|
||||
|
||||
set(SWA_THIRDPARTY_SOURCES
|
||||
"${SWA_THIRDPARTY_ROOT}/imgui/backends/imgui_impl_sdl2.cpp"
|
||||
"${SWA_THIRDPARTY_ROOT}/imgui/imgui.cpp"
|
||||
"${SWA_THIRDPARTY_ROOT}/imgui/imgui_demo.cpp"
|
||||
"${SWA_THIRDPARTY_ROOT}/imgui/imgui_draw.cpp"
|
||||
"${SWA_THIRDPARTY_ROOT}/imgui/imgui_tables.cpp"
|
||||
"${SWA_THIRDPARTY_ROOT}/imgui/imgui_widgets.cpp"
|
||||
"${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack/lzxd.c"
|
||||
"${SWA_THIRDPARTY_ROOT}/tiny-AES-c/aes.c"
|
||||
"${SWA_TOOLS_ROOT}/ShaderRecomp/thirdparty/smol-v/source/smolv.cpp"
|
||||
)
|
||||
|
||||
set(SWA_THIRDPARTY_INCLUDES
|
||||
"${SWA_THIRDPARTY_ROOT}/concurrentqueue"
|
||||
"${SWA_THIRDPARTY_ROOT}/ddspp"
|
||||
"${SWA_THIRDPARTY_ROOT}/imgui"
|
||||
"${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack"
|
||||
"${SWA_THIRDPARTY_ROOT}/magic_enum/include"
|
||||
"${SWA_THIRDPARTY_ROOT}/miniaudio"
|
||||
"${SWA_THIRDPARTY_ROOT}/stb"
|
||||
"${SWA_THIRDPARTY_ROOT}/tiny-AES-c"
|
||||
"${SWA_THIRDPARTY_ROOT}/TinySHA1"
|
||||
"${SWA_THIRDPARTY_ROOT}/unordered_dense/include"
|
||||
"${SWA_THIRDPARTY_ROOT}/volk"
|
||||
"${SWA_THIRDPARTY_ROOT}/Vulkan-Headers/include"
|
||||
"${SWA_THIRDPARTY_ROOT}/VulkanMemoryAllocator/include"
|
||||
"${SWA_TOOLS_ROOT}/bc_diff"
|
||||
"${SWA_TOOLS_ROOT}/ShaderRecomp/thirdparty/smol-v/source"
|
||||
)
|
||||
|
||||
if (SWA_D3D12)
|
||||
list(APPEND SWA_THIRDPARTY_INCLUDES "${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/include")
|
||||
list(APPEND SWA_THIRDPARTY_SOURCES "${SWA_THIRDPARTY_ROOT}/D3D12MemoryAllocator/src/D3D12MemAlloc.cpp")
|
||||
endif()
|
||||
|
||||
set_source_files_properties(${SWA_THIRDPARTY_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
|
||||
|
||||
set(SWA_CXX_SOURCES
|
||||
"app.cpp"
|
||||
"exports.cpp"
|
||||
|
|
@ -206,9 +244,8 @@ set(SWA_CXX_SOURCES
|
|||
${SWA_PATCHES_CXX_SOURCES}
|
||||
${SWA_UI_CXX_SOURCES}
|
||||
${SWA_INSTALL_CXX_SOURCES}
|
||||
${LIBMSPACK_C_SOURCES}
|
||||
"${SMOLV_SOURCE_DIR}/smolv.cpp"
|
||||
${SWA_USER_CXX_SOURCES}
|
||||
${SWA_THIRDPARTY_SOURCES}
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
|
@ -225,28 +262,10 @@ set_target_properties(UnleashedRecomp PROPERTIES OUTPUT_NAME ${TARGET_NAME})
|
|||
if (SWA_D3D12)
|
||||
find_package(directx-headers CONFIG REQUIRED)
|
||||
find_package(directx12-agility CONFIG REQUIRED)
|
||||
find_package(d3d12-memory-allocator CONFIG REQUIRED)
|
||||
target_compile_definitions(UnleashedRecomp PRIVATE SWA_D3D12)
|
||||
endif()
|
||||
|
||||
find_package(SDL2 CONFIG REQUIRED)
|
||||
find_package(unordered_dense CONFIG REQUIRED)
|
||||
find_package(VulkanHeaders CONFIG)
|
||||
find_package(volk CONFIG REQUIRED)
|
||||
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
||||
find_package(xxHash CONFIG REQUIRED)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus)
|
||||
find_package(directx-dxc REQUIRED)
|
||||
find_package(zstd CONFIG REQUIRED)
|
||||
find_package(Stb REQUIRED)
|
||||
find_package(unofficial-concurrentqueue REQUIRED)
|
||||
find_package(imgui CONFIG REQUIRED)
|
||||
find_package(magic_enum CONFIG REQUIRED)
|
||||
find_package(unofficial-tiny-aes-c CONFIG REQUIRED)
|
||||
find_package(nfd CONFIG REQUIRED)
|
||||
find_package(Vorbis CONFIG REQUIRED)
|
||||
find_package(fmt CONFIG REQUIRED)
|
||||
|
||||
if (SWA_D3D12)
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
|
||||
|
|
@ -263,11 +282,13 @@ if (SWA_D3D12)
|
|||
Microsoft::DirectX-Guids
|
||||
Microsoft::DirectX12-Agility
|
||||
Microsoft::DirectXShaderCompiler
|
||||
unofficial::D3D12MemoryAllocator
|
||||
Microsoft::DXIL
|
||||
dxgi
|
||||
)
|
||||
endif()
|
||||
|
||||
file(CHMOD ${DIRECTX_DXC_TOOL} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(UnleashedRecomp PRIVATE
|
||||
comctl32
|
||||
|
|
@ -278,40 +299,30 @@ if (WIN32)
|
|||
endif()
|
||||
|
||||
target_link_libraries(UnleashedRecomp PRIVATE
|
||||
Vulkan::Headers
|
||||
volk::volk
|
||||
volk::volk_headers
|
||||
GPUOpen::VulkanMemoryAllocator
|
||||
fmt::fmt
|
||||
libzstd_static
|
||||
msdf-atlas-gen::msdf-atlas-gen
|
||||
nfd::nfd
|
||||
o1heap
|
||||
PowerUtils
|
||||
SDL2::SDL2-static
|
||||
tomlplusplus::tomlplusplus
|
||||
UnleashedRecompLib
|
||||
unordered_dense::unordered_dense
|
||||
xxHash::xxhash
|
||||
PkgConfig::tomlplusplus
|
||||
zstd::libzstd_static
|
||||
unofficial::concurrentqueue::concurrentqueue
|
||||
imgui::imgui
|
||||
magic_enum::magic_enum
|
||||
unofficial::tiny-aes-c::tiny-aes-c
|
||||
nfd::nfd
|
||||
msdf-atlas-gen::msdf-atlas-gen
|
||||
Vorbis::vorbisfile
|
||||
fmt::fmt
|
||||
)
|
||||
xxHash::xxhash
)
|
||||
|
||||
target_include_directories(UnleashedRecomp PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/api
|
||||
${SWA_THIRDPARTY_ROOT}/ddspp
|
||||
${SWA_THIRDPARTY_ROOT}/TinySHA1
|
||||
${LIBMSPACK_PATH}
|
||||
${Stb_INCLUDE_DIR}
|
||||
${SMOLV_SOURCE_DIR}
|
||||
${MINIAUDIO_INCLUDE_DIRS}
|
||||
${BC_DIFF_SOURCE_DIR}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/api"
|
||||
${SWA_THIRDPARTY_INCLUDES}
|
||||
)
|
||||
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
find_package(X11 REQUIRED)
|
||||
target_include_directories(UnleashedRecomp PRIVATE ${X11_INCLUDE_DIR})
|
||||
target_link_libraries(UnleashedRecomp PRIVATE ${X11_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_precompile_headers(UnleashedRecomp PUBLIC ${SWA_PRECOMPILED_HEADERS})
|
||||
|
||||
function(compile_shader FILE_PATH TARGET_NAME)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <app.h>
|
||||
#include <install/installer.h>
|
||||
#include <kernel/function.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <patches/audio_patches.h>
|
||||
#include <user/config.h>
|
||||
#include <os/process.h>
|
||||
|
|
@ -15,10 +15,7 @@ void App::Restart(std::vector<std::string> restartArgs)
|
|||
void App::Exit()
|
||||
{
|
||||
Config::Save();
|
||||
|
||||
#if _WIN32
|
||||
ExitProcess(0);
|
||||
#endif
|
||||
std::_Exit(0);
|
||||
}
|
||||
|
||||
// CApplication::Ctor
|
||||
|
|
@ -41,7 +38,7 @@ PPC_FUNC(sub_822C1130)
|
|||
SDL_PumpEvents();
|
||||
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
|
||||
|
||||
Window::Update();
|
||||
GameWindow::Update();
|
||||
AudioPatches::Update(App::s_deltaTime);
|
||||
|
||||
__imp__sub_822C1130(ctx, base);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <user/config_detail.h>
|
||||
#include <user/config.h>
|
||||
|
||||
class App
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
std::ofstream g_audioDumpStream;
|
||||
#endif
|
||||
|
||||
uint32_t XAudioRegisterRenderDriverClient(XLPDWORD callback, XLPDWORD driver)
|
||||
uint32_t XAudioRegisterRenderDriverClient(be<uint32_t>* callback, be<uint32_t>* driver)
|
||||
{
|
||||
#ifdef AUDIO_DUMP_SAMPLES_PATH
|
||||
g_audioDumpStream.open(AUDIO_DUMP_SAMPLES_PATH, std::ios::binary);
|
||||
|
|
@ -25,7 +25,7 @@ uint32_t XAudioRegisterRenderDriverClient(XLPDWORD callback, XLPDWORD driver)
|
|||
return 0;
|
||||
}
|
||||
|
||||
uint32_t XAudioUnregisterRenderDriverClient(DWORD driver)
|
||||
uint32_t XAudioUnregisterRenderDriverClient(uint32_t driver)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,6 @@ void XAudioRegisterClient(PPCFunc* callback, uint32_t param);
|
|||
void XAudioSubmitFrame(void* samples);
|
||||
#endif
|
||||
|
||||
uint32_t XAudioRegisterRenderDriverClient(XLPDWORD callback, XLPDWORD driver);
|
||||
uint32_t XAudioUnregisterRenderDriverClient(DWORD driver);
|
||||
uint32_t XAudioRegisterRenderDriverClient(be<uint32_t>* callback, be<uint32_t>* driver);
|
||||
uint32_t XAudioUnregisterRenderDriverClient(uint32_t driver);
|
||||
uint32_t XAudioSubmitRenderDriverFrame(uint32_t driver, void* samples);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include <kernel/heap.h>
|
||||
|
||||
static PPCFunc* g_clientCallback{};
|
||||
static DWORD g_clientCallbackParam{}; // pointer in guest memory
|
||||
static uint32_t g_clientCallbackParam{}; // pointer in guest memory
|
||||
static ma_device g_audioDevice{};
|
||||
static std::unique_ptr<GuestThreadContext> g_audioCtx;
|
||||
static uint32_t* g_audioOutput;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ CodeCache::CodeCache()
|
|||
assert(bucket != nullptr);
|
||||
#else
|
||||
bucket = (char*)mmap(NULL, 0x200000000, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
assert(bucket != (char *)MAP_FAILED)
|
||||
assert(bucket != (char*)MAP_FAILED);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -36,12 +36,12 @@ void CodeCache::Init()
|
|||
}
|
||||
}
|
||||
|
||||
void CodeCache::Insert(uint32_t guest, const void* host)
|
||||
void CodeCache::Insert(uint32_t guest, PPCFunc* host)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
VirtualAlloc(bucket + static_cast<uint64_t>(guest) * 2, sizeof(void*), MEM_COMMIT, PAGE_READWRITE);
|
||||
#endif
|
||||
*reinterpret_cast<const void**>(bucket + static_cast<uint64_t>(guest) * 2) = host;
|
||||
*reinterpret_cast<PPCFunc**>(bucket + static_cast<uint64_t>(guest) * 2) = host;
|
||||
}
|
||||
|
||||
void* CodeCache::Find(uint32_t guest) const
|
||||
|
|
@ -56,5 +56,5 @@ SWA_API PPCFunc* KeFindHostFunction(uint32_t guest)
|
|||
|
||||
SWA_API void KeInsertHostFunction(uint32_t guest, PPCFunc* function)
|
||||
{
|
||||
g_codeCache.Insert(guest, (const void*)function);
|
||||
g_codeCache.Insert(guest, function);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ struct CodeCache
|
|||
~CodeCache();
|
||||
|
||||
void Init();
|
||||
void Insert(uint32_t guest, const void* host);
|
||||
void Insert(uint32_t guest, PPCFunc* host);
|
||||
|
||||
void* Find(uint32_t guest) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include <kernel/memory.h>
|
||||
#include <cpu/guest_stack_var.h>
|
||||
#include <ui/installer_wizard.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <api/boost/smart_ptr/shared_ptr.h>
|
||||
|
||||
SWA_API void Game_PlaySound(const char* pName)
|
||||
|
|
@ -31,5 +31,5 @@ SWA_API void Game_PlaySound(const char* pName)
|
|||
|
||||
SWA_API void Window_SetFullscreen(bool isEnabled)
|
||||
{
|
||||
Window::SetFullscreen(isEnabled);
|
||||
GameWindow::SetFullscreen(isEnabled);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
#define SWA_DLLEXPORT __declspec(dllexport)
|
||||
#define SWA_DLLIMPORT __declspec(dllimport)
|
||||
#else
|
||||
#define SWA_DLLEXPORT __attribute__((dllexport))
|
||||
#define SWA_DLLIMPORT __attribute__((dllimport))
|
||||
// TODO
|
||||
#define SWA_DLLEXPORT
|
||||
#define SWA_DLLIMPORT
|
||||
#endif
|
||||
|
||||
#ifdef SWA_IMPL
|
||||
|
|
@ -33,19 +34,6 @@ inline T RoundDown(const T& in_rValue, uint32_t in_round)
|
|||
return in_rValue & ~(in_round - 1);
|
||||
}
|
||||
|
||||
inline bool FileExists(const char* path)
|
||||
{
|
||||
const auto attributes = GetFileAttributesA(path);
|
||||
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
|
||||
}
|
||||
|
||||
inline bool DirectoryExists(const char* path)
|
||||
{
|
||||
const auto attributes = GetFileAttributesA(path);
|
||||
return attributes != INVALID_FILE_ATTRIBUTES && !!(attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
inline size_t StringHash(const std::string_view& str)
|
||||
{
|
||||
return XXH3_64bits(str.data(), str.size());
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ void ImFontAtlasSnapshot::GenerateGlyphRanges()
|
|||
{
|
||||
std::vector<std::string_view> localeStrings;
|
||||
|
||||
for (auto& config : Config::Definitions)
|
||||
for (auto& config : g_configDefinitions)
|
||||
config->GetLocaleStrings(localeStrings);
|
||||
|
||||
std::set<ImWchar> glyphs;
|
||||
|
|
|
|||
|
|
@ -22,9 +22,18 @@
|
|||
#define VK_USE_PLATFORM_XLIB_KHR
|
||||
#endif
|
||||
|
||||
#include "volk.h"
|
||||
#include <volk.h>
|
||||
|
||||
#include "vk_mem_alloc.h"
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wnullability-completeness"
|
||||
#endif
|
||||
|
||||
#include <vk_mem_alloc.h>
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
namespace plume {
|
||||
struct VulkanCommandQueue;
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@
|
|||
#include <ui/message_window.h>
|
||||
#include <ui/options_menu.h>
|
||||
#include <ui/sdl_listener.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/config.h>
|
||||
#include <xxHashMap.h>
|
||||
|
||||
#if defined(ASYNC_PSO_DEBUG) || defined(PSO_CACHING)
|
||||
#include <magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#endif
|
||||
|
||||
#include "../../tools/ShaderRecomp/ShaderRecomp/shader_common.h"
|
||||
|
|
@ -70,11 +70,13 @@
|
|||
#include "shader/resolve_msaa_depth_4x.hlsl.spirv.h"
|
||||
#include "shader/resolve_msaa_depth_8x.hlsl.spirv.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace plume
|
||||
{
|
||||
|
|
@ -171,7 +173,7 @@ struct DirtyStates
|
|||
static DirtyStates g_dirtyStates(true);
|
||||
|
||||
template<typename T>
|
||||
static FORCEINLINE void SetDirtyValue(bool& dirtyState, T& dest, const T& src)
|
||||
static void SetDirtyValue(bool& dirtyState, T& dest, const T& src)
|
||||
{
|
||||
if (dest != src)
|
||||
{
|
||||
|
|
@ -556,7 +558,7 @@ static void DestructTempResources()
|
|||
g_tempBuffers[g_frame].clear();
|
||||
}
|
||||
|
||||
static uint32_t g_mainThreadId;
|
||||
static std::thread::id g_mainThreadId;
|
||||
|
||||
static ankerl::unordered_dense::map<RenderTexture*, RenderTextureLayout> g_barrierMap;
|
||||
|
||||
|
|
@ -1039,7 +1041,7 @@ static void ProcSetRenderState(const RenderCommand& cmd)
|
|||
}
|
||||
}
|
||||
|
||||
static const std::pair<GuestRenderState, void*> g_setRenderStateFunctions[] =
|
||||
static const std::pair<GuestRenderState, PPCFunc*> g_setRenderStateFunctions[] =
|
||||
{
|
||||
{ D3DRS_ZENABLE, HostToGuestFunction<SetRenderState<D3DRS_ZENABLE>> },
|
||||
{ D3DRS_ZWRITEENABLE, HostToGuestFunction<SetRenderState<D3DRS_ZWRITEENABLE>> },
|
||||
|
|
@ -1094,11 +1096,13 @@ static std::unique_ptr<GuestShader> g_enhancedMotionBlurShader;
|
|||
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static bool DetectWine()
|
||||
{
|
||||
HMODULE dllHandle = GetModuleHandle("ntdll.dll");
|
||||
return dllHandle != nullptr && GetProcAddress(dllHandle, "wine_get_version") != nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static constexpr size_t TEXTURE_DESCRIPTOR_SIZE = 65536;
|
||||
static constexpr size_t SAMPLER_DESCRIPTOR_SIZE = 1024;
|
||||
|
|
@ -1161,7 +1165,7 @@ static void CreateImGuiBackend()
|
|||
OptionsMenu::Init();
|
||||
InstallerWizard::Init();
|
||||
|
||||
ImGui_ImplSDL2_InitForOther(Window::s_pWindow);
|
||||
ImGui_ImplSDL2_InitForOther(GameWindow::s_pWindow);
|
||||
|
||||
#ifdef ENABLE_IM_FONT_ATLAS_SNAPSHOT
|
||||
g_imFontTexture = LoadTexture(
|
||||
|
|
@ -1311,7 +1315,7 @@ void Video::CreateHostDevice()
|
|||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
|
||||
Window::Init();
|
||||
GameWindow::Init();
|
||||
|
||||
#ifdef SWA_D3D12
|
||||
g_vulkan = DetectWine() || Config::GraphicsAPI == EGraphicsAPI::Vulkan;
|
||||
|
|
@ -1356,7 +1360,7 @@ void Video::CreateHostDevice()
|
|||
break;
|
||||
}
|
||||
|
||||
g_swapChain = g_queue->createSwapChain(Window::s_handle, bufferCount, BACKBUFFER_FORMAT);
|
||||
g_swapChain = g_queue->createSwapChain(GameWindow::s_renderWindow, bufferCount, BACKBUFFER_FORMAT);
|
||||
g_swapChain->setVsyncEnabled(Config::VSync);
|
||||
g_swapChainValid = !g_swapChain->needsResize();
|
||||
|
||||
|
|
@ -1366,7 +1370,7 @@ void Video::CreateHostDevice()
|
|||
for (auto& renderSemaphore : g_renderSemaphores)
|
||||
renderSemaphore = g_device->createCommandSemaphore();
|
||||
|
||||
g_mainThreadId = GetCurrentThreadId();
|
||||
g_mainThreadId = std::this_thread::get_id();
|
||||
|
||||
RenderPipelineLayoutBuilder pipelineLayoutBuilder;
|
||||
pipelineLayoutBuilder.begin(false, true);
|
||||
|
|
@ -1658,9 +1662,9 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
|
|||
memset(device, 0, sizeof(*device));
|
||||
|
||||
uint32_t functionOffset = 0x443344; // D3D
|
||||
g_codeCache.Insert(functionOffset, reinterpret_cast<void*>(HostToGuestFunction<SetRenderStateUnimplemented>));
|
||||
g_codeCache.Insert(functionOffset, HostToGuestFunction<SetRenderStateUnimplemented>);
|
||||
|
||||
for (size_t i = 0; i < _countof(device->setRenderStateFunctions); i++)
|
||||
for (size_t i = 0; i < std::size(device->setRenderStateFunctions); i++)
|
||||
device->setRenderStateFunctions[i] = functionOffset;
|
||||
|
||||
for (auto& [state, function] : g_setRenderStateFunctions)
|
||||
|
|
@ -1670,7 +1674,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4,
|
|||
device->setRenderStateFunctions[state / 4] = functionOffset;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _countof(device->setSamplerStateFunctions); i++)
|
||||
for (size_t i = 0; i < std::size(device->setSamplerStateFunctions); i++)
|
||||
device->setSamplerStateFunctions[i] = *reinterpret_cast<uint32_t*>(g_memory.Translate(0x8330F3DC + i * 0xC));
|
||||
|
||||
device->viewport.width = 1280.0f;
|
||||
|
|
@ -1795,7 +1799,7 @@ static void UnlockBuffer(GuestBuffer* buffer)
|
|||
{
|
||||
if (!buffer->lockedReadOnly)
|
||||
{
|
||||
if (GetCurrentThreadId() == g_mainThreadId)
|
||||
if (std::this_thread::get_id() == g_mainThreadId)
|
||||
{
|
||||
RenderCommand cmd;
|
||||
cmd.type = (sizeof(T) == 2) ? RenderCommandType::UnlockBuffer16 : RenderCommandType::UnlockBuffer32;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
#include <SDL.h>
|
||||
#include <user/config.h>
|
||||
#include <hid/hid_detail.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <kernel/xdm.h>
|
||||
|
||||
#define TRANSLATE_INPUT(S, X) SDL_GameControllerGetButton(controller, S) << FirstBitLow(X)
|
||||
#define VIBRATION_TIMEOUT_MS 5000
|
||||
|
|
@ -65,7 +66,7 @@ public:
|
|||
|
||||
bool CanPoll()
|
||||
{
|
||||
return controller && (Window::s_isFocused || Config::AllowBackgroundInput);
|
||||
return controller && (GameWindow::s_isFocused || Config::AllowBackgroundInput);
|
||||
}
|
||||
|
||||
void PollAxis()
|
||||
|
|
@ -128,7 +129,7 @@ public:
|
|||
std::array<Controller, 4> g_controllers;
|
||||
Controller* g_activeController;
|
||||
|
||||
inline Controller* EnsureController(DWORD dwUserIndex)
|
||||
inline Controller* EnsureController(uint32_t dwUserIndex)
|
||||
{
|
||||
if (!g_controllers[dwUserIndex].controller)
|
||||
return nullptr;
|
||||
|
|
@ -260,7 +261,7 @@ void hid::detail::Init()
|
|||
|
||||
uint32_t hid::detail::GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState)
|
||||
{
|
||||
static DWORD packet;
|
||||
static uint32_t packet;
|
||||
|
||||
if (!pState)
|
||||
return ERROR_BAD_ARGUMENTS;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ bool MemoryMappedFile::open(const std::filesystem::path &path)
|
|||
if (fileSize == (off_t)(-1))
|
||||
{
|
||||
fprintf(stderr, "lseek failed with error %s.\n", strerror(errno));
|
||||
close(fileHandle);
|
||||
::close(fileHandle);
|
||||
fileHandle = -1;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -106,7 +106,7 @@ bool MemoryMappedFile::open(const std::filesystem::path &path)
|
|||
if (fileView == MAP_FAILED)
|
||||
{
|
||||
fprintf(stderr, "mmap failed with error %s.\n", strerror(errno));
|
||||
close(fileHandle);
|
||||
::close(fileHandle);
|
||||
fileHandle = -1;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -140,7 +140,7 @@ void MemoryMappedFile::close()
|
|||
|
||||
if (fileHandle != -1)
|
||||
{
|
||||
close(fileHandle);
|
||||
::close(fileHandle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,14 +308,14 @@ inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex)
|
|||
inline bool bitScanForward(uint32_t v, uint32_t *outFirstSetIndex)
|
||||
{
|
||||
int i = ffs(v);
|
||||
*out_first_set_index = i - 1;
|
||||
*outFirstSetIndex = i - 1;
|
||||
return i != 0;
|
||||
}
|
||||
|
||||
inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex)
|
||||
{
|
||||
int i = __builtin_ffsll(v);
|
||||
*out_first_set_index = i - 1;
|
||||
*outFirstSetIndex = i - 1;
|
||||
return i != 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ std::enable_if_t<(I < sizeof...(TArgs)), void> _tuple_for(std::tuple<TArgs...>&
|
|||
|
||||
struct ArgTranslator
|
||||
{
|
||||
FORCEINLINE constexpr static uint64_t GetIntegerArgumentValue(const PPCContext& ctx, uint8_t* base, size_t arg) noexcept
|
||||
constexpr static uint64_t GetIntegerArgumentValue(const PPCContext& ctx, uint8_t* base, size_t arg) noexcept
|
||||
{
|
||||
if (arg <= 7)
|
||||
{
|
||||
|
|
@ -57,10 +57,10 @@ struct ArgTranslator
|
|||
}
|
||||
}
|
||||
|
||||
return *reinterpret_cast<XLPDWORD>(base + ctx.r1.u32 + 0x54 + ((arg - 8) * 8));
|
||||
return *reinterpret_cast<be<uint32_t>*>(base + ctx.r1.u32 + 0x54 + ((arg - 8) * 8));
|
||||
}
|
||||
|
||||
FORCEINLINE static double GetPrecisionArgumentValue(const PPCContext& ctx, uint8_t* base, size_t arg) noexcept
|
||||
static double GetPrecisionArgumentValue(const PPCContext& ctx, uint8_t* base, size_t arg) noexcept
|
||||
{
|
||||
switch (arg)
|
||||
{
|
||||
|
|
@ -84,7 +84,7 @@ struct ArgTranslator
|
|||
return 0;
|
||||
}
|
||||
|
||||
FORCEINLINE constexpr static void SetIntegerArgumentValue(PPCContext& ctx, uint8_t* base, size_t arg, uint64_t value) noexcept
|
||||
constexpr static void SetIntegerArgumentValue(PPCContext& ctx, uint8_t* base, size_t arg, uint64_t value) noexcept
|
||||
{
|
||||
if (arg <= 7)
|
||||
{
|
||||
|
|
@ -105,7 +105,7 @@ struct ArgTranslator
|
|||
assert(arg < 7 && "Pushing to stack memory is not yet supported.");
|
||||
}
|
||||
|
||||
FORCEINLINE static void SetPrecisionArgumentValue(PPCContext& ctx, uint8_t* base, size_t arg, double value) noexcept
|
||||
static void SetPrecisionArgumentValue(PPCContext& ctx, uint8_t* base, size_t arg, double value) noexcept
|
||||
{
|
||||
switch (arg)
|
||||
{
|
||||
|
|
@ -129,7 +129,7 @@ struct ArgTranslator
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE constexpr static std::enable_if_t<!std::is_pointer_v<T>, T> GetValue(PPCContext& ctx, uint8_t* base, size_t idx) noexcept
|
||||
constexpr static std::enable_if_t<!std::is_pointer_v<T>, T> GetValue(PPCContext& ctx, uint8_t* base, size_t idx) noexcept
|
||||
{
|
||||
if constexpr (is_precise_v<T>)
|
||||
{
|
||||
|
|
@ -142,7 +142,7 @@ struct ArgTranslator
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE constexpr static std::enable_if_t<std::is_pointer_v<T>, T> GetValue(PPCContext& ctx, uint8_t* base, size_t idx) noexcept
|
||||
constexpr static std::enable_if_t<std::is_pointer_v<T>, T> GetValue(PPCContext& ctx, uint8_t* base, size_t idx) noexcept
|
||||
{
|
||||
const auto v = GetIntegerArgumentValue(ctx, base, idx);
|
||||
if (!v)
|
||||
|
|
@ -154,7 +154,7 @@ struct ArgTranslator
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE constexpr static std::enable_if_t<!std::is_pointer_v<T>, void> SetValue(PPCContext& ctx, uint8_t* base, size_t idx, T value) noexcept
|
||||
constexpr static std::enable_if_t<!std::is_pointer_v<T>, void> SetValue(PPCContext& ctx, uint8_t* base, size_t idx, T value) noexcept
|
||||
{
|
||||
if constexpr (is_precise_v<T>)
|
||||
{
|
||||
|
|
@ -175,7 +175,7 @@ struct ArgTranslator
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
FORCEINLINE constexpr static std::enable_if_t<std::is_pointer_v<T>, void> SetValue(PPCContext& ctx, uint8_t* base, size_t idx, T value) noexcept
|
||||
constexpr static std::enable_if_t<std::is_pointer_v<T>, void> SetValue(PPCContext& ctx, uint8_t* base, size_t idx, T value) noexcept
|
||||
{
|
||||
const auto v = g_memory.MapVirtual((void*)value);
|
||||
if (!v)
|
||||
|
|
@ -240,13 +240,13 @@ struct arg_ordinal_t
|
|||
};
|
||||
|
||||
template<auto Func, int I = 0, typename ...TArgs>
|
||||
FORCEINLINE void _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>&) noexcept
|
||||
void _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>&) noexcept
|
||||
requires (I >= sizeof...(TArgs))
|
||||
{
|
||||
}
|
||||
|
||||
template <auto Func, int I = 0, typename ...TArgs>
|
||||
FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>& tpl) noexcept
|
||||
std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>& tpl) noexcept
|
||||
{
|
||||
using T = std::tuple_element_t<I, std::remove_reference_t<decltype(tpl)>>;
|
||||
std::get<I>(tpl) = ArgTranslator::GetValue<T>(ctx, base, arg_ordinal_t<Func, I>::value);
|
||||
|
|
@ -255,13 +255,13 @@ FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_ho
|
|||
}
|
||||
|
||||
template<int I = 0, typename ...TArgs>
|
||||
FORCEINLINE void _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>&) noexcept
|
||||
void _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>&) noexcept
|
||||
requires (I >= sizeof...(TArgs))
|
||||
{
|
||||
}
|
||||
|
||||
template <int I = 0, typename ...TArgs>
|
||||
FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>& tpl) noexcept
|
||||
std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple<TArgs...>& tpl) noexcept
|
||||
{
|
||||
using T = std::tuple_element_t<I, std::remove_reference_t<decltype(tpl)>>;
|
||||
ArgTranslator::SetValue<T>(ctx, base, GatherFunctionArguments(std::tuple<TArgs...>{})[I].ordinal, std::get<I>(tpl));
|
||||
|
|
@ -270,7 +270,7 @@ FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_gu
|
|||
}
|
||||
|
||||
template<auto Func>
|
||||
FORCEINLINE PPC_FUNC(HostToGuestFunction)
|
||||
PPC_FUNC(HostToGuestFunction)
|
||||
{
|
||||
using ret_t = decltype(std::apply(Func, function_args(Func)));
|
||||
|
||||
|
|
@ -293,7 +293,7 @@ FORCEINLINE PPC_FUNC(HostToGuestFunction)
|
|||
}
|
||||
else
|
||||
{
|
||||
ctx.r3.u64 = NULL;
|
||||
ctx.r3.u64 = 0;
|
||||
}
|
||||
}
|
||||
else if constexpr (is_precise_v<ret_t>)
|
||||
|
|
@ -308,7 +308,7 @@ FORCEINLINE PPC_FUNC(HostToGuestFunction)
|
|||
}
|
||||
|
||||
template<typename T, typename TFunction, typename... TArgs>
|
||||
FORCEINLINE T GuestToHostFunction(const TFunction& func, TArgs&&... argv)
|
||||
T GuestToHostFunction(const TFunction& func, TArgs&&... argv)
|
||||
{
|
||||
auto args = std::make_tuple(std::forward<TArgs>(argv)...);
|
||||
auto& currentCtx = *GetPPCContext();
|
||||
|
|
@ -331,11 +331,7 @@ FORCEINLINE T GuestToHostFunction(const TFunction& func, TArgs&&... argv)
|
|||
currentCtx.fpscr = newCtx.fpscr;
|
||||
SetPPCContext(currentCtx);
|
||||
|
||||
if constexpr (std::is_void_v<T>)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if constexpr (std::is_pointer_v<T>)
|
||||
if constexpr (std::is_pointer_v<T>)
|
||||
{
|
||||
return reinterpret_cast<T>((uint64_t)g_memory.Translate(newCtx.r3.u32));
|
||||
}
|
||||
|
|
@ -349,7 +345,7 @@ FORCEINLINE T GuestToHostFunction(const TFunction& func, TArgs&&... argv)
|
|||
}
|
||||
else
|
||||
{
|
||||
static_assert(false, "Unsupported return type.");
|
||||
static_assert(std::is_void_v<T>, "Unsupported return type.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ uint32_t RtlSizeHeap(uint32_t heapHandle, uint32_t flags, uint32_t memoryPointer
|
|||
return 0;
|
||||
}
|
||||
|
||||
SWA_API uint32_t XAlloc(uint32_t size, uint32_t flags)
|
||||
SWA_API uint32_t XAllocMem(uint32_t size, uint32_t flags)
|
||||
{
|
||||
void* ptr = (flags & 0x80000000) != 0 ?
|
||||
g_userHeap.AllocPhysical(size, (1ull << ((flags >> 24) & 0xF))) :
|
||||
|
|
@ -116,7 +116,7 @@ SWA_API uint32_t XAlloc(uint32_t size, uint32_t flags)
|
|||
return g_memory.MapVirtual(ptr);
|
||||
}
|
||||
|
||||
SWA_API void XFree(uint32_t baseAddress, uint32_t flags)
|
||||
SWA_API void XFreeMem(uint32_t baseAddress, uint32_t flags)
|
||||
{
|
||||
if (baseAddress != NULL)
|
||||
g_userHeap.Free(g_memory.Translate(baseAddress));
|
||||
|
|
@ -130,6 +130,5 @@ GUEST_FUNCTION_HOOK(sub_82BD8600, RtlFreeHeap);
|
|||
GUEST_FUNCTION_HOOK(sub_82BD88F0, RtlReAllocateHeap);
|
||||
GUEST_FUNCTION_HOOK(sub_82BD6FD0, RtlSizeHeap);
|
||||
|
||||
// Seems like these handle allocation of virtual and physical pages
|
||||
GUEST_FUNCTION_HOOK(sub_831CC9C8, XAlloc);
|
||||
GUEST_FUNCTION_HOOK(sub_831CCA60, XFree);
|
||||
GUEST_FUNCTION_HOOK(sub_831CC9C8, XAllocMem);
|
||||
GUEST_FUNCTION_HOOK(sub_831CCA60, XFreeMem);
|
||||
|
|
|
|||
|
|
@ -10,11 +10,12 @@
|
|||
#include <memory>
|
||||
#include "xam.h"
|
||||
#include "xdm.h"
|
||||
#include <timeapi.h>
|
||||
#include <user/config.h>
|
||||
#include <os/logger.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <ntstatus.h>
|
||||
#endif
|
||||
|
||||
struct Event final : KernelObject, HostObject<XKEVENT>
|
||||
{
|
||||
|
|
@ -149,7 +150,7 @@ inline void CloseKernelObject(XDISPATCHER_HEADER& header)
|
|||
DestroyKernelObject(header.WaitListHead.Blink);
|
||||
}
|
||||
|
||||
DWORD GuestTimeoutToMilliseconds(XLPQWORD timeout)
|
||||
uint32_t GuestTimeoutToMilliseconds(be<int64_t>* timeout)
|
||||
{
|
||||
return timeout ? (*timeout * -1) / 10000 : INFINITE;
|
||||
}
|
||||
|
|
@ -207,7 +208,7 @@ uint32_t XGetGameRegion()
|
|||
return 0x03FF;
|
||||
}
|
||||
|
||||
uint32_t XMsgStartIORequest(DWORD App, DWORD Message, XXOVERLAPPED* lpOverlapped, void* Buffer, DWORD szBuffer)
|
||||
uint32_t XMsgStartIORequest(uint32_t App, uint32_t Message, XXOVERLAPPED* lpOverlapped, void* Buffer, uint32_t szBuffer)
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -227,8 +228,7 @@ void XamContentDelete()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
|
||||
uint32_t XamContentGetCreator(DWORD userIndex, const XCONTENT_DATA* contentData, PBOOL isCreator, XLPQWORD xuid, XXOVERLAPPED* overlapped)
|
||||
uint32_t XamContentGetCreator(uint32_t userIndex, const XCONTENT_DATA* contentData, be<uint32_t>* isCreator, be<uint64_t>* xuid, XXOVERLAPPED* overlapped)
|
||||
{
|
||||
if (isCreator)
|
||||
*isCreator = true;
|
||||
|
|
@ -269,7 +269,7 @@ uint32_t XamShowDeviceSelectorUI
|
|||
uint32_t contentType,
|
||||
uint32_t contentFlags,
|
||||
uint64_t totalRequested,
|
||||
XDWORD* deviceId,
|
||||
be<uint32_t>* deviceId,
|
||||
XXOVERLAPPED* overlapped
|
||||
)
|
||||
{
|
||||
|
|
@ -337,10 +337,10 @@ void RtlInitAnsiString(XANSI_STRING* destination, char* source)
|
|||
destination->Buffer = source;
|
||||
}
|
||||
|
||||
DWORD NtCreateFile
|
||||
uint32_t NtCreateFile
|
||||
(
|
||||
XLPDWORD FileHandle,
|
||||
DWORD DesiredAccess,
|
||||
be<uint32_t>* FileHandle,
|
||||
uint32_t DesiredAccess,
|
||||
XOBJECT_ATTRIBUTES* Attributes,
|
||||
XIO_STATUS_BLOCK* IoStatusBlock,
|
||||
uint64_t* AllocationSize,
|
||||
|
|
@ -363,8 +363,11 @@ uint32_t NtClose(uint32_t handle)
|
|||
DestroyKernelObject(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return CloseHandle((HANDLE)handle) ? 0 : 0xFFFFFFFF;
|
||||
else
|
||||
{
|
||||
assert(false && "Unrecognized kernel object.");
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
void NtSetInformationFile()
|
||||
|
|
@ -377,7 +380,7 @@ uint32_t FscSetCacheElementCount()
|
|||
return 0;
|
||||
}
|
||||
|
||||
DWORD NtWaitForSingleObjectEx(DWORD Handle, DWORD WaitMode, DWORD Alertable, XLPQWORD Timeout)
|
||||
uint32_t NtWaitForSingleObjectEx(uint32_t Handle, uint32_t WaitMode, uint32_t Alertable, be<int64_t>* Timeout)
|
||||
{
|
||||
uint32_t timeout = GuestTimeoutToMilliseconds(Timeout);
|
||||
assert(timeout == 0 || timeout == INFINITE);
|
||||
|
|
@ -404,7 +407,7 @@ void vsprintf_x()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
uint32_t ExGetXConfigSetting(uint16_t Category, uint16_t Setting, void* Buffer, uint16_t SizeOfBuffer, XLPDWORD RequiredSize)
|
||||
uint32_t ExGetXConfigSetting(uint16_t Category, uint16_t Setting, void* Buffer, uint16_t SizeOfBuffer, be<uint32_t>* RequiredSize)
|
||||
{
|
||||
uint32_t data[4]{};
|
||||
|
||||
|
|
@ -517,9 +520,9 @@ void XexGetModuleSection()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
NTSTATUS RtlUnicodeToMultiByteN(PCHAR MultiByteString, DWORD MaxBytesInMultiByteString, XLPDWORD BytesInMultiByteString, PCWCH UnicodeString, ULONG BytesInUnicodeString)
|
||||
uint32_t RtlUnicodeToMultiByteN(char* MultiByteString, uint32_t MaxBytesInMultiByteString, be<uint32_t>* BytesInMultiByteString, const be<uint16_t>* UnicodeString, uint32_t BytesInUnicodeString)
|
||||
{
|
||||
const auto reqSize = BytesInUnicodeString / sizeof(wchar_t);
|
||||
const auto reqSize = BytesInUnicodeString / sizeof(uint16_t);
|
||||
|
||||
if (BytesInMultiByteString)
|
||||
*BytesInMultiByteString = reqSize;
|
||||
|
|
@ -529,7 +532,7 @@ NTSTATUS RtlUnicodeToMultiByteN(PCHAR MultiByteString, DWORD MaxBytesInMultiByte
|
|||
|
||||
for (size_t i = 0; i < reqSize; i++)
|
||||
{
|
||||
const auto c = ByteSwap(UnicodeString[i]);
|
||||
const auto c = UnicodeString[i].get();
|
||||
|
||||
MultiByteString[i] = c < 256 ? c : '?';
|
||||
}
|
||||
|
|
@ -537,7 +540,7 @@ NTSTATUS RtlUnicodeToMultiByteN(PCHAR MultiByteString, DWORD MaxBytesInMultiByte
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
DWORD KeDelayExecutionThread(DWORD WaitMode, bool Alertable, XLPQWORD Timeout)
|
||||
uint32_t KeDelayExecutionThread(uint32_t WaitMode, bool Alertable, be<int64_t>* Timeout)
|
||||
{
|
||||
// We don't do async file reads.
|
||||
if (Alertable)
|
||||
|
|
@ -614,7 +617,7 @@ void KeSetBasePriorityThread(GuestThreadHandle* hThread, int priority)
|
|||
#endif
|
||||
}
|
||||
|
||||
uint32_t ObReferenceObjectByHandle(uint32_t handle, uint32_t objectType, XLPDWORD object)
|
||||
uint32_t ObReferenceObjectByHandle(uint32_t handle, uint32_t objectType, be<uint32_t>* object)
|
||||
{
|
||||
*object = handle;
|
||||
return 0;
|
||||
|
|
@ -635,7 +638,7 @@ uint32_t NtSuspendThread(GuestThreadHandle* hThread, uint32_t* suspendCount)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
uint32_t KeSetAffinityThread(DWORD Thread, DWORD Affinity, XLPDWORD lpPreviousAffinity)
|
||||
uint32_t KeSetAffinityThread(uint32_t Thread, uint32_t Affinity, be<uint32_t>* lpPreviousAffinity)
|
||||
{
|
||||
if (lpPreviousAffinity)
|
||||
*lpPreviousAffinity = 2;
|
||||
|
|
@ -693,7 +696,7 @@ void RtlFillMemoryUlong()
|
|||
|
||||
void KeBugCheckEx()
|
||||
{
|
||||
__debugbreak();
|
||||
__builtin_debugtrap();
|
||||
}
|
||||
|
||||
uint32_t KeGetCurrentProcessType()
|
||||
|
|
@ -949,7 +952,7 @@ void VdEnableDisableClockGating()
|
|||
|
||||
void KeBugCheck()
|
||||
{
|
||||
__debugbreak();
|
||||
__builtin_debugtrap();
|
||||
}
|
||||
|
||||
void KeLockL2()
|
||||
|
|
@ -962,7 +965,7 @@ void KeUnlockL2()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
bool KeSetEvent(XKEVENT* pEvent, DWORD Increment, bool Wait)
|
||||
bool KeSetEvent(XKEVENT* pEvent, uint32_t Increment, bool Wait)
|
||||
{
|
||||
bool result = QueryKernelObject<Event>(*pEvent)->Set();
|
||||
|
||||
|
|
@ -977,7 +980,7 @@ bool KeResetEvent(XKEVENT* pEvent)
|
|||
return QueryKernelObject<Event>(*pEvent)->Reset();
|
||||
}
|
||||
|
||||
DWORD KeWaitForSingleObject(XDISPATCHER_HEADER* Object, DWORD WaitReason, DWORD WaitMode, bool Alertable, XLPQWORD Timeout)
|
||||
uint32_t KeWaitForSingleObject(XDISPATCHER_HEADER* Object, uint32_t WaitReason, uint32_t WaitMode, bool Alertable, be<int64_t>* Timeout)
|
||||
{
|
||||
const uint32_t timeout = GuestTimeoutToMilliseconds(Timeout);
|
||||
assert(timeout == INFINITE);
|
||||
|
|
@ -1019,18 +1022,18 @@ static uint32_t& KeTlsGetValueRef(size_t index)
|
|||
return s_tlsValues[index];
|
||||
}
|
||||
|
||||
uint32_t KeTlsGetValue(DWORD dwTlsIndex)
|
||||
uint32_t KeTlsGetValue(uint32_t dwTlsIndex)
|
||||
{
|
||||
return KeTlsGetValueRef(dwTlsIndex);
|
||||
}
|
||||
|
||||
BOOL KeTlsSetValue(DWORD dwTlsIndex, DWORD lpTlsValue)
|
||||
uint32_t KeTlsSetValue(uint32_t dwTlsIndex, uint32_t lpTlsValue)
|
||||
{
|
||||
KeTlsGetValueRef(dwTlsIndex) = lpTlsValue;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD KeTlsAlloc()
|
||||
uint32_t KeTlsAlloc()
|
||||
{
|
||||
std::lock_guard<Mutex> lock(g_tlsAllocationMutex);
|
||||
if (!g_tlsFreeIndices.empty())
|
||||
|
|
@ -1043,14 +1046,14 @@ DWORD KeTlsAlloc()
|
|||
return g_tlsNextIndex++;
|
||||
}
|
||||
|
||||
BOOL KeTlsFree(DWORD dwTlsIndex)
|
||||
uint32_t KeTlsFree(uint32_t dwTlsIndex)
|
||||
{
|
||||
std::lock_guard<Mutex> lock(g_tlsAllocationMutex);
|
||||
g_tlsFreeIndices.push_back(dwTlsIndex);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD XMsgInProcessCall(uint32_t app, uint32_t message, XDWORD* param1, XDWORD* param2)
|
||||
uint32_t XMsgInProcessCall(uint32_t app, uint32_t message, be<uint32_t>* param1, be<uint32_t>* param2)
|
||||
{
|
||||
if (message == 0x7001B)
|
||||
{
|
||||
|
|
@ -1070,7 +1073,7 @@ void XamUserReadProfileSettings
|
|||
uint64_t* xuids,
|
||||
uint32_t settingCount,
|
||||
uint32_t* settingIds,
|
||||
XDWORD* bufferSize,
|
||||
be<uint32_t>* bufferSize,
|
||||
void* buffer,
|
||||
void* overlapped
|
||||
)
|
||||
|
|
@ -1251,19 +1254,15 @@ void NtQueryFullAttributesFile()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
NTSTATUS RtlMultiByteToUnicodeN(PWCH UnicodeString, ULONG MaxBytesInUnicodeString, XLPDWORD BytesInUnicodeString, const CHAR* MultiByteString, ULONG BytesInMultiByteString)
|
||||
uint32_t RtlMultiByteToUnicodeN(be<uint16_t>* UnicodeString, uint32_t MaxBytesInUnicodeString, be<uint32_t>* BytesInUnicodeString, const char* MultiByteString, uint32_t BytesInMultiByteString)
|
||||
{
|
||||
// i am lazy
|
||||
const auto n = MultiByteToWideChar(CP_UTF8, 0, MultiByteString, BytesInMultiByteString, UnicodeString, MaxBytesInUnicodeString);
|
||||
uint32_t length = std::min(MaxBytesInUnicodeString / 2, BytesInMultiByteString);
|
||||
|
||||
if (BytesInUnicodeString)
|
||||
*BytesInUnicodeString = n * sizeof(wchar_t);
|
||||
for (size_t i = 0; i < length; i++)
|
||||
UnicodeString[i] = MultiByteString[i];
|
||||
|
||||
if (n)
|
||||
{
|
||||
for (size_t i = 0; i < n; i++)
|
||||
UnicodeString[i] = ByteSwap(UnicodeString[i]);
|
||||
}
|
||||
if (BytesInUnicodeString != nullptr)
|
||||
*BytesInUnicodeString = length * 2;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -1300,13 +1299,13 @@ uint32_t NtSetEvent(Event* handle, uint32_t* previousState)
|
|||
return 0;
|
||||
}
|
||||
|
||||
NTSTATUS NtCreateSemaphore(XLPDWORD Handle, XOBJECT_ATTRIBUTES* ObjectAttributes, DWORD InitialCount, DWORD MaximumCount)
|
||||
uint32_t NtCreateSemaphore(be<uint32_t>* Handle, XOBJECT_ATTRIBUTES* ObjectAttributes, uint32_t InitialCount, uint32_t MaximumCount)
|
||||
{
|
||||
*Handle = GetKernelHandle(CreateKernelObject<Semaphore>(InitialCount, MaximumCount));
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS NtReleaseSemaphore(Semaphore* Handle, DWORD ReleaseCount, LONG* PreviousCount)
|
||||
uint32_t NtReleaseSemaphore(Semaphore* Handle, uint32_t ReleaseCount, int32_t* PreviousCount)
|
||||
{
|
||||
uint32_t previousCount;
|
||||
Handle->Release(ReleaseCount, &previousCount);
|
||||
|
|
@ -1347,11 +1346,17 @@ void NtFlushBuffersFile()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
void KeQuerySystemTime(uint64_t* time)
|
||||
void KeQuerySystemTime(be<uint64_t>* time)
|
||||
{
|
||||
FILETIME t;
|
||||
GetSystemTimeAsFileTime(&t);
|
||||
*time = ByteSwap((uint64_t(t.dwHighDateTime) << 32) | t.dwLowDateTime);
|
||||
constexpr int64_t FILETIME_EPOCH_DIFFERENCE = 116444736000000000LL;
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto timeSinceEpoch = now.time_since_epoch();
|
||||
|
||||
int64_t currentTime100ns = std::chrono::duration_cast<std::chrono::duration<int64_t, std::ratio<1, 10000000>>>(timeSinceEpoch).count();
|
||||
currentTime100ns += FILETIME_EPOCH_DIFFERENCE;
|
||||
|
||||
*time = ((currentTime100ns & 0xFFFFFFFF) << 32) | (currentTime100ns & 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void RtlTimeToTimeFields()
|
||||
|
|
@ -1379,7 +1384,7 @@ void ExTerminateThread()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
uint32_t ExCreateThread(XLPDWORD handle, uint32_t stackSize, XLPDWORD threadId, uint32_t xApiThreadStartup, uint32_t startAddress, uint32_t startContext, uint32_t creationFlags)
|
||||
uint32_t ExCreateThread(be<uint32_t>* handle, uint32_t stackSize, be<uint32_t>* threadId, uint32_t xApiThreadStartup, uint32_t startAddress, uint32_t startContext, uint32_t creationFlags)
|
||||
{
|
||||
LOGF_UTILITY("0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}",
|
||||
(intptr_t)handle, stackSize, (intptr_t)threadId, xApiThreadStartup, startAddress, startContext, creationFlags);
|
||||
|
|
@ -1464,7 +1469,7 @@ void NetDll_XNetGetTitleXnAddr()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
DWORD KeWaitForMultipleObjects(DWORD Count, xpointer<XDISPATCHER_HEADER>* Objects, DWORD WaitType, DWORD WaitReason, DWORD WaitMode, DWORD Alertable, XLPQWORD Timeout)
|
||||
uint32_t KeWaitForMultipleObjects(uint32_t Count, xpointer<XDISPATCHER_HEADER>* Objects, uint32_t WaitType, uint32_t WaitReason, uint32_t WaitMode, uint32_t Alertable, be<int64_t>* Timeout)
|
||||
{
|
||||
// FIXME: This function is only accounting for events.
|
||||
|
||||
|
|
@ -1492,7 +1497,7 @@ DWORD KeWaitForMultipleObjects(DWORD Count, xpointer<XDISPATCHER_HEADER>* Object
|
|||
{
|
||||
if (s_events[i]->Wait(0) == STATUS_SUCCESS)
|
||||
{
|
||||
return WAIT_OBJECT_0 + i;
|
||||
return STATUS_WAIT_0 + i;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1522,7 +1527,7 @@ void XAudioGetVoiceCategoryVolume()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
DWORD XAudioGetVoiceCategoryVolumeChangeMask(DWORD Driver, XLPDWORD Mask)
|
||||
uint32_t XAudioGetVoiceCategoryVolumeChangeMask(uint32_t Driver, be<uint32_t>* Mask)
|
||||
{
|
||||
*Mask = 0;
|
||||
return 0;
|
||||
|
|
@ -1556,7 +1561,7 @@ void XMACreateContext()
|
|||
LOG_UTILITY("!!! STUB !!!");
|
||||
}
|
||||
|
||||
// uint32_t XAudioRegisterRenderDriverClient(XLPDWORD callback, XLPDWORD driver)
|
||||
// uint32_t XAudioRegisterRenderDriverClient(be<uint32_t>* callback, be<uint32_t>* driver)
|
||||
// {
|
||||
// //printf("XAudioRegisterRenderDriverClient(): %x %x\n");
|
||||
//
|
||||
|
|
|
|||
|
|
@ -14,10 +14,11 @@ struct FileHandle : KernelObject
|
|||
|
||||
struct FindHandle : KernelObject
|
||||
{
|
||||
std::error_code ec;
|
||||
std::filesystem::path searchPath;
|
||||
std::filesystem::directory_iterator iterator;
|
||||
|
||||
void fillFindData(LPWIN32_FIND_DATAA lpFindFileData)
|
||||
void fillFindData(WIN32_FIND_DATAA* lpFindFileData)
|
||||
{
|
||||
if (iterator->is_directory())
|
||||
lpFindFileData->dwFileAttributes = ByteSwap(FILE_ATTRIBUTE_DIRECTORY);
|
||||
|
|
@ -25,7 +26,7 @@ struct FindHandle : KernelObject
|
|||
lpFindFileData->dwFileAttributes = ByteSwap(FILE_ATTRIBUTE_NORMAL);
|
||||
|
||||
std::u8string pathU8Str = iterator->path().lexically_relative(searchPath).u8string();
|
||||
uint64_t fileSize = iterator->file_size();
|
||||
uint64_t fileSize = iterator->file_size(ec);
|
||||
strncpy(lpFindFileData->cFileName, (const char *)(pathU8Str.c_str()), sizeof(lpFindFileData->cFileName));
|
||||
lpFindFileData->nFileSizeLow = ByteSwap(uint32_t(fileSize >> 32U));
|
||||
lpFindFileData->nFileSizeHigh = ByteSwap(uint32_t(fileSize));
|
||||
|
|
@ -37,12 +38,12 @@ struct FindHandle : KernelObject
|
|||
|
||||
SWA_API FileHandle* XCreateFileA
|
||||
(
|
||||
LPCSTR lpFileName,
|
||||
DWORD dwDesiredAccess,
|
||||
DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
|
||||
DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes
|
||||
const char* lpFileName,
|
||||
uint32_t dwDesiredAccess,
|
||||
uint32_t dwShareMode,
|
||||
void* lpSecurityAttributes,
|
||||
uint32_t dwCreationDisposition,
|
||||
uint32_t dwFlagsAndAttributes
|
||||
)
|
||||
{
|
||||
assert(((dwDesiredAccess & ~(GENERIC_READ | GENERIC_WRITE | FILE_READ_DATA)) == 0) && "Unknown desired access bits.");
|
||||
|
|
@ -77,7 +78,7 @@ SWA_API FileHandle* XCreateFileA
|
|||
return fileHandle;
|
||||
}
|
||||
|
||||
static DWORD XGetFileSizeA(FileHandle* hFile, LPDWORD lpFileSizeHigh)
|
||||
static uint32_t XGetFileSizeA(FileHandle* hFile, be<uint32_t>* lpFileSizeHigh)
|
||||
{
|
||||
std::error_code ec;
|
||||
auto fileSize = std::filesystem::file_size(hFile->path, ec);
|
||||
|
|
@ -85,16 +86,16 @@ static DWORD XGetFileSizeA(FileHandle* hFile, LPDWORD lpFileSizeHigh)
|
|||
{
|
||||
if (lpFileSizeHigh != nullptr)
|
||||
{
|
||||
*lpFileSizeHigh = ByteSwap(DWORD(fileSize >> 32U));
|
||||
*lpFileSizeHigh = uint32_t(fileSize >> 32U);
|
||||
}
|
||||
|
||||
return (DWORD)(fileSize);
|
||||
return (uint32_t)(fileSize);
|
||||
}
|
||||
|
||||
return INVALID_FILE_SIZE;
|
||||
}
|
||||
|
||||
BOOL XGetFileSizeExA(FileHandle* hFile, PLARGE_INTEGER lpFileSize)
|
||||
uint32_t XGetFileSizeExA(FileHandle* hFile, LARGE_INTEGER* lpFileSize)
|
||||
{
|
||||
std::error_code ec;
|
||||
auto fileSize = std::filesystem::file_size(hFile->path, ec);
|
||||
|
|
@ -111,16 +112,16 @@ BOOL XGetFileSizeExA(FileHandle* hFile, PLARGE_INTEGER lpFileSize)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL XReadFile
|
||||
uint32_t XReadFile
|
||||
(
|
||||
FileHandle* hFile,
|
||||
LPVOID lpBuffer,
|
||||
DWORD nNumberOfBytesToRead,
|
||||
XLPDWORD lpNumberOfBytesRead,
|
||||
void* lpBuffer,
|
||||
uint32_t nNumberOfBytesToRead,
|
||||
be<uint32_t>* lpNumberOfBytesRead,
|
||||
XOVERLAPPED* lpOverlapped
|
||||
)
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
uint32_t result = FALSE;
|
||||
if (lpOverlapped != nullptr)
|
||||
{
|
||||
std::streamoff streamOffset = lpOverlapped->Offset + (std::streamoff(lpOverlapped->OffsetHigh.get()) << 32U);
|
||||
|
|
@ -132,11 +133,11 @@ BOOL XReadFile
|
|||
}
|
||||
}
|
||||
|
||||
DWORD numberOfBytesRead;
|
||||
uint32_t numberOfBytesRead;
|
||||
hFile->stream.read((char *)(lpBuffer), nNumberOfBytesToRead);
|
||||
if (!hFile->stream.bad())
|
||||
{
|
||||
numberOfBytesRead = DWORD(hFile->stream.gcount());
|
||||
numberOfBytesRead = uint32_t(hFile->stream.gcount());
|
||||
result = TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -146,9 +147,6 @@ BOOL XReadFile
|
|||
{
|
||||
lpOverlapped->Internal = 0;
|
||||
lpOverlapped->InternalHigh = numberOfBytesRead;
|
||||
|
||||
if (lpOverlapped->hEvent != NULL)
|
||||
SetEvent((HANDLE)lpOverlapped->hEvent.get());
|
||||
}
|
||||
else if (lpNumberOfBytesRead != nullptr)
|
||||
{
|
||||
|
|
@ -159,9 +157,9 @@ BOOL XReadFile
|
|||
return result;
|
||||
}
|
||||
|
||||
DWORD XSetFilePointer(FileHandle* hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
|
||||
uint32_t XSetFilePointer(FileHandle* hFile, int32_t lDistanceToMove, be<int32_t>* lpDistanceToMoveHigh, uint32_t dwMoveMethod)
|
||||
{
|
||||
LONG distanceToMoveHigh = lpDistanceToMoveHigh ? ByteSwap(*lpDistanceToMoveHigh) : 0;
|
||||
int32_t distanceToMoveHigh = lpDistanceToMoveHigh ? lpDistanceToMoveHigh->get() : 0;
|
||||
std::streamoff streamOffset = lDistanceToMove + (std::streamoff(distanceToMoveHigh) << 32U);
|
||||
std::fstream::seekdir streamSeekDir = {};
|
||||
switch (dwMoveMethod)
|
||||
|
|
@ -189,12 +187,12 @@ DWORD XSetFilePointer(FileHandle* hFile, LONG lDistanceToMove, PLONG lpDistanceT
|
|||
|
||||
std::streampos streamPos = hFile->stream.tellg();
|
||||
if (lpDistanceToMoveHigh != nullptr)
|
||||
*lpDistanceToMoveHigh = ByteSwap(LONG(streamPos >> 32U));
|
||||
*lpDistanceToMoveHigh = int32_t(streamPos >> 32U);
|
||||
|
||||
return DWORD(streamPos);
|
||||
return uint32_t(streamPos);
|
||||
}
|
||||
|
||||
BOOL XSetFilePointerEx(FileHandle* hFile, LONG lDistanceToMove, PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
|
||||
uint32_t XSetFilePointerEx(FileHandle* hFile, int32_t lDistanceToMove, LARGE_INTEGER* lpNewFilePointer, uint32_t dwMoveMethod)
|
||||
{
|
||||
std::fstream::seekdir streamSeekDir = {};
|
||||
switch (dwMoveMethod)
|
||||
|
|
@ -222,13 +220,13 @@ BOOL XSetFilePointerEx(FileHandle* hFile, LONG lDistanceToMove, PLARGE_INTEGER l
|
|||
|
||||
if (lpNewFilePointer != nullptr)
|
||||
{
|
||||
lpNewFilePointer->QuadPart = ByteSwap(LONGLONG(hFile->stream.tellg()));
|
||||
lpNewFilePointer->QuadPart = ByteSwap(int64_t(hFile->stream.tellg()));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FindHandle* XFindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
|
||||
FindHandle* XFindFirstFileA(const char* lpFileName, WIN32_FIND_DATAA* lpFindFileData)
|
||||
{
|
||||
const char *transformedPath = FileSystem::TransformPath(lpFileName);
|
||||
size_t transformedPathLength = strlen(transformedPath);
|
||||
|
|
@ -236,11 +234,11 @@ FindHandle* XFindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData
|
|||
return (FindHandle*)GUEST_INVALID_HANDLE_VALUE;
|
||||
|
||||
std::filesystem::path dirPath;
|
||||
if (strstr(transformedPath, "\\*") == (&transformedPath[transformedPathLength - 2]))
|
||||
if (strstr(transformedPath, "\\*") == (&transformedPath[transformedPathLength - 2]) || strstr(transformedPath, "/*") == (&transformedPath[transformedPathLength - 2]))
|
||||
{
|
||||
dirPath = std::u8string_view((const char8_t*)(transformedPath), transformedPathLength - 2);
|
||||
}
|
||||
else if (strstr(transformedPath, "\\*.*") == (&transformedPath[transformedPathLength - 4]))
|
||||
else if (strstr(transformedPath, "\\*.*") == (&transformedPath[transformedPathLength - 4]) || strstr(transformedPath, "/*.*") == (&transformedPath[transformedPathLength - 4]))
|
||||
{
|
||||
dirPath = std::u8string_view((const char8_t *)(transformedPath), transformedPathLength - 4);
|
||||
}
|
||||
|
|
@ -264,7 +262,7 @@ FindHandle* XFindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData
|
|||
return findHandle;
|
||||
}
|
||||
|
||||
BOOL XFindNextFileA(FindHandle* Handle, LPWIN32_FIND_DATAA lpFindFileData)
|
||||
uint32_t XFindNextFileA(FindHandle* Handle, WIN32_FIND_DATAA* lpFindFileData)
|
||||
{
|
||||
Handle->iterator++;
|
||||
|
||||
|
|
@ -279,10 +277,10 @@ BOOL XFindNextFileA(FindHandle* Handle, LPWIN32_FIND_DATAA lpFindFileData)
|
|||
}
|
||||
}
|
||||
|
||||
BOOL XReadFileEx(FileHandle* hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, XOVERLAPPED* lpOverlapped, uint32_t lpCompletionRoutine)
|
||||
uint32_t XReadFileEx(FileHandle* hFile, void* lpBuffer, uint32_t nNumberOfBytesToRead, XOVERLAPPED* lpOverlapped, uint32_t lpCompletionRoutine)
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
DWORD numberOfBytesRead;
|
||||
uint32_t result = FALSE;
|
||||
uint32_t numberOfBytesRead;
|
||||
std::streamoff streamOffset = lpOverlapped->Offset + (std::streamoff(lpOverlapped->OffsetHigh.get()) << 32U);
|
||||
hFile->stream.clear();
|
||||
hFile->stream.seekg(streamOffset, std::ios::beg);
|
||||
|
|
@ -292,7 +290,7 @@ BOOL XReadFileEx(FileHandle* hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
|||
hFile->stream.read((char *)(lpBuffer), nNumberOfBytesToRead);
|
||||
if (!hFile->stream.bad())
|
||||
{
|
||||
numberOfBytesRead = DWORD(hFile->stream.gcount());
|
||||
numberOfBytesRead = uint32_t(hFile->stream.gcount());
|
||||
result = TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -300,15 +298,12 @@ BOOL XReadFileEx(FileHandle* hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
|
|||
{
|
||||
lpOverlapped->Internal = 0;
|
||||
lpOverlapped->InternalHigh = numberOfBytesRead;
|
||||
|
||||
if (lpOverlapped->hEvent != NULL)
|
||||
SetEvent((HANDLE)lpOverlapped->hEvent.get());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DWORD XGetFileAttributesA(LPCSTR lpFileName)
|
||||
uint32_t XGetFileAttributesA(const char* lpFileName)
|
||||
{
|
||||
std::filesystem::path filePath(std::u8string_view((const char8_t*)(FileSystem::TransformPath(lpFileName))));
|
||||
if (std::filesystem::is_directory(filePath))
|
||||
|
|
@ -319,7 +314,7 @@ DWORD XGetFileAttributesA(LPCSTR lpFileName)
|
|||
return INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
|
||||
BOOL XWriteFile(FileHandle* hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
|
||||
uint32_t XWriteFile(FileHandle* hFile, const void* lpBuffer, uint32_t nNumberOfBytesToWrite, be<uint32_t>* lpNumberOfBytesWritten, void* lpOverlapped)
|
||||
{
|
||||
assert(lpOverlapped == nullptr && "Overlapped not implemented.");
|
||||
|
||||
|
|
@ -328,16 +323,28 @@ BOOL XWriteFile(FileHandle* hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite
|
|||
return FALSE;
|
||||
|
||||
if (lpNumberOfBytesWritten != nullptr)
|
||||
*lpNumberOfBytesWritten = DWORD(hFile->stream.gcount());
|
||||
*lpNumberOfBytesWritten = uint32_t(hFile->stream.gcount());
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void fixSlashes(char *path)
|
||||
{
|
||||
while (*path != 0)
|
||||
{
|
||||
if (*path == '\\')
|
||||
{
|
||||
*path = '/';
|
||||
}
|
||||
|
||||
path++;
|
||||
}
|
||||
}
|
||||
|
||||
const char* FileSystem::TransformPath(const char* path)
|
||||
{
|
||||
thread_local char builtPath[2048]{};
|
||||
const char* relativePath = strstr(path, ":\\");
|
||||
|
||||
if (relativePath != nullptr)
|
||||
{
|
||||
// rooted folder, handle direction
|
||||
|
|
@ -349,12 +356,19 @@ const char* FileSystem::TransformPath(const char* path)
|
|||
strncpy(builtPath, newRoot.data(), newRoot.size());
|
||||
builtPath[newRoot.size()] = '\\';
|
||||
strcpy(builtPath + newRoot.size() + 1, relativePath + 2);
|
||||
|
||||
return builtPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(builtPath, relativePath + 2, sizeof(builtPath));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(builtPath, path, sizeof(builtPath));
|
||||
}
|
||||
|
||||
return relativePath != nullptr ? relativePath + 2 : path;
|
||||
fixSlashes(builtPath);
|
||||
return builtPath;
|
||||
}
|
||||
|
||||
SWA_API const char* XExpandFilePathA(const char* path)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ Memory::Memory(void* address, size_t size) : size(size)
|
|||
|
||||
if (base == (char*)MAP_FAILED)
|
||||
base = (char*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
|
||||
mprotect(base, 4096, PROT_NONE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
#define MEM_COMMIT 0x00001000
|
||||
#define MEM_RESERVE 0x00002000
|
||||
#endif
|
||||
|
||||
class Memory
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -2,23 +2,25 @@
|
|||
#include "xam.h"
|
||||
#include "xdm.h"
|
||||
#include <hid/hid.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <cpu/guest_thread.h>
|
||||
#include <ranges>
|
||||
#include <unordered_set>
|
||||
#include <CommCtrl.h>
|
||||
#include "xxHashMap.h"
|
||||
#include <user/paths.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <CommCtrl.h>
|
||||
// Needed for commctrl
|
||||
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
|
||||
#endif
|
||||
|
||||
struct XamListener : KernelObject
|
||||
{
|
||||
uint32_t id{};
|
||||
uint64_t areas{};
|
||||
std::vector<std::tuple<DWORD, DWORD>> notifications;
|
||||
std::vector<std::tuple<uint32_t, uint32_t>> notifications;
|
||||
|
||||
XamListener(const XamListener&) = delete;
|
||||
XamListener& operator=(const XamListener&) = delete;
|
||||
|
|
@ -116,7 +118,7 @@ XamListener::~XamListener()
|
|||
gListeners.erase(this);
|
||||
}
|
||||
|
||||
XCONTENT_DATA XamMakeContent(DWORD type, const std::string_view& name)
|
||||
XCONTENT_DATA XamMakeContent(uint32_t type, const std::string_view& name)
|
||||
{
|
||||
XCONTENT_DATA data{ 1, type };
|
||||
|
||||
|
|
@ -132,7 +134,7 @@ void XamRegisterContent(const XCONTENT_DATA& data, const std::string_view& root)
|
|||
gContentRegistry[idx].emplace(StringHash(data.szFileName), XHOSTCONTENT_DATA{ data }).first->second.szRoot = root;
|
||||
}
|
||||
|
||||
void XamRegisterContent(DWORD type, const std::string_view name, const std::string_view& root)
|
||||
void XamRegisterContent(uint32_t type, const std::string_view name, const std::string_view& root)
|
||||
{
|
||||
XCONTENT_DATA data{ 1, type, {}, "" };
|
||||
|
||||
|
|
@ -141,7 +143,7 @@ void XamRegisterContent(DWORD type, const std::string_view name, const std::stri
|
|||
XamRegisterContent(data, root);
|
||||
}
|
||||
|
||||
SWA_API DWORD XamNotifyCreateListener(uint64_t qwAreas)
|
||||
SWA_API uint32_t XamNotifyCreateListener(uint64_t qwAreas)
|
||||
{
|
||||
auto* listener = CreateKernelObject<XamListener>();
|
||||
|
||||
|
|
@ -150,7 +152,7 @@ SWA_API DWORD XamNotifyCreateListener(uint64_t qwAreas)
|
|||
return GetKernelHandle(listener);
|
||||
}
|
||||
|
||||
SWA_API void XamNotifyEnqueueEvent(DWORD dwId, DWORD dwParam)
|
||||
SWA_API void XamNotifyEnqueueEvent(uint32_t dwId, uint32_t dwParam)
|
||||
{
|
||||
for (const auto& listener : gListeners)
|
||||
{
|
||||
|
|
@ -161,7 +163,7 @@ SWA_API void XamNotifyEnqueueEvent(DWORD dwId, DWORD dwParam)
|
|||
}
|
||||
}
|
||||
|
||||
SWA_API bool XNotifyGetNext(DWORD hNotification, DWORD dwMsgFilter, XDWORD* pdwId, XDWORD* pParam)
|
||||
SWA_API bool XNotifyGetNext(uint32_t hNotification, uint32_t dwMsgFilter, be<uint32_t>* pdwId, be<uint32_t>* pParam)
|
||||
{
|
||||
auto& listener = *GetKernelObject<XamListener>(hNotification);
|
||||
|
||||
|
|
@ -202,9 +204,12 @@ SWA_API bool XNotifyGetNext(DWORD hNotification, DWORD dwMsgFilter, XDWORD* pdwI
|
|||
return false;
|
||||
}
|
||||
|
||||
SWA_API uint32_t XamShowMessageBoxUI(DWORD dwUserIndex, XWORD* wszTitle, XWORD* wszText, DWORD cButtons,
|
||||
xpointer<XWORD>* pwszButtons, DWORD dwFocusButton, DWORD dwFlags, XLPDWORD pResult, XXOVERLAPPED* pOverlapped)
|
||||
SWA_API uint32_t XamShowMessageBoxUI(uint32_t dwUserIndex, be<uint16_t>* wszTitle, be<uint16_t>* wszText, uint32_t cButtons,
|
||||
xpointer<be<uint16_t>>* pwszButtons, uint32_t dwFocusButton, uint32_t dwFlags, be<uint32_t>* pResult, XXOVERLAPPED* pOverlapped)
|
||||
{
|
||||
int button{};
|
||||
|
||||
#ifdef _WIN32
|
||||
std::vector<std::wstring> texts{};
|
||||
std::vector<TASKDIALOG_BUTTON> buttons{};
|
||||
|
||||
|
|
@ -227,20 +232,19 @@ SWA_API uint32_t XamShowMessageBoxUI(DWORD dwUserIndex, XWORD* wszTitle, XWORD*
|
|||
|
||||
TASKDIALOGCONFIG config{};
|
||||
config.cbSize = sizeof(config);
|
||||
// config.hwndParent = Window::s_hWnd;
|
||||
config.pszWindowTitle = texts[0].c_str();
|
||||
config.pszContent = texts[1].c_str();
|
||||
config.cButtons = cButtons;
|
||||
config.pButtons = buttons.data();
|
||||
|
||||
int button{};
|
||||
TaskDialogIndirect(&config, &button, nullptr, nullptr);
|
||||
#endif
|
||||
|
||||
*pResult = button;
|
||||
|
||||
if (pOverlapped)
|
||||
{
|
||||
pOverlapped->dwCompletionContext = GetCurrentThreadId();
|
||||
pOverlapped->dwCompletionContext = GuestThread::GetCurrentThreadId();
|
||||
pOverlapped->Error = 0;
|
||||
pOverlapped->Length = -1;
|
||||
}
|
||||
|
|
@ -250,8 +254,8 @@ SWA_API uint32_t XamShowMessageBoxUI(DWORD dwUserIndex, XWORD* wszTitle, XWORD*
|
|||
return 0;
|
||||
}
|
||||
|
||||
SWA_API uint32_t XamContentCreateEnumerator(DWORD dwUserIndex, DWORD DeviceID, DWORD dwContentType,
|
||||
DWORD dwContentFlags, DWORD cItem, XLPDWORD pcbBuffer, XLPDWORD phEnum)
|
||||
SWA_API uint32_t XamContentCreateEnumerator(uint32_t dwUserIndex, uint32_t DeviceID, uint32_t dwContentType,
|
||||
uint32_t dwContentFlags, uint32_t cItem, be<uint32_t>* pcbBuffer, be<uint32_t>* phEnum)
|
||||
{
|
||||
if (dwUserIndex != 0)
|
||||
{
|
||||
|
|
@ -271,7 +275,7 @@ SWA_API uint32_t XamContentCreateEnumerator(DWORD dwUserIndex, DWORD DeviceID, D
|
|||
return 0;
|
||||
}
|
||||
|
||||
SWA_API uint32_t XamEnumerate(uint32_t hEnum, DWORD dwFlags, PVOID pvBuffer, DWORD cbBuffer, XLPDWORD pcItemsReturned, XXOVERLAPPED* pOverlapped)
|
||||
SWA_API uint32_t XamEnumerate(uint32_t hEnum, uint32_t dwFlags, void* pvBuffer, uint32_t cbBuffer, be<uint32_t>* pcItemsReturned, XXOVERLAPPED* pOverlapped)
|
||||
{
|
||||
auto* enumerator = GetKernelObject<XamEnumeratorBase>(hEnum);
|
||||
const auto count = enumerator->Next(pvBuffer);
|
||||
|
|
@ -285,9 +289,9 @@ SWA_API uint32_t XamEnumerate(uint32_t hEnum, DWORD dwFlags, PVOID pvBuffer, DWO
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
SWA_API uint32_t XamContentCreateEx(DWORD dwUserIndex, LPCSTR szRootName, const XCONTENT_DATA* pContentData,
|
||||
DWORD dwContentFlags, XLPDWORD pdwDisposition, XLPDWORD pdwLicenseMask,
|
||||
DWORD dwFileCacheSize, uint64_t uliContentSize, PXXOVERLAPPED pOverlapped)
|
||||
SWA_API uint32_t XamContentCreateEx(uint32_t dwUserIndex, const char* szRootName, const XCONTENT_DATA* pContentData,
|
||||
uint32_t dwContentFlags, be<uint32_t>* pdwDisposition, be<uint32_t>* pdwLicenseMask,
|
||||
uint32_t dwFileCacheSize, uint64_t uliContentSize, PXXOVERLAPPED pOverlapped)
|
||||
{
|
||||
const auto& registry = gContentRegistry[pContentData->dwContentType - 1];
|
||||
const auto exists = registry.contains(StringHash(pContentData->szFileName));
|
||||
|
|
@ -309,7 +313,7 @@ SWA_API uint32_t XamContentCreateEx(DWORD dwUserIndex, LPCSTR szRootName, const
|
|||
}
|
||||
else if (pContentData->dwContentType == XCONTENTTYPE_DLC)
|
||||
{
|
||||
root = ".\\dlc";
|
||||
root = "./dlc";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -354,13 +358,13 @@ SWA_API uint32_t XamContentCreateEx(DWORD dwUserIndex, LPCSTR szRootName, const
|
|||
return ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
SWA_API uint32_t XamContentClose(LPCSTR szRootName, XXOVERLAPPED* pOverlapped)
|
||||
SWA_API uint32_t XamContentClose(const char* szRootName, XXOVERLAPPED* pOverlapped)
|
||||
{
|
||||
gRootMap.erase(StringHash(szRootName));
|
||||
return 0;
|
||||
}
|
||||
|
||||
SWA_API uint32_t XamContentGetDeviceData(DWORD DeviceID, XDEVICE_DATA* pDeviceData)
|
||||
SWA_API uint32_t XamContentGetDeviceData(uint32_t DeviceID, XDEVICE_DATA* pDeviceData)
|
||||
{
|
||||
pDeviceData->DeviceID = DeviceID;
|
||||
pDeviceData->DeviceType = XCONTENTDEVICETYPE_HDD;
|
||||
|
|
@ -401,7 +405,7 @@ SWA_API uint32_t XamInputGetState(uint32_t userIndex, uint32_t flags, XAMINPUT_S
|
|||
|
||||
uint32_t result = hid::GetState(userIndex, state);
|
||||
|
||||
if (Window::s_isFocused)
|
||||
if (GameWindow::s_isFocused)
|
||||
{
|
||||
auto keyboardState = SDL_GetKeyboardState(NULL);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,32 +1,32 @@
|
|||
#pragma once
|
||||
#include <xbox.h>
|
||||
|
||||
#define MSGID(Area, Number) (DWORD)((WORD)(Area) << 16 | (WORD)(Number))
|
||||
#define MSGID(Area, Number) (uint32_t)((uint16_t)(Area) << 16 | (uint16_t)(Number))
|
||||
#define MSG_AREA(msgid) (((msgid) >> 16) & 0xFFFF)
|
||||
#define MSG_NUMBER(msgid) ((msgid) & 0xFFFF)
|
||||
|
||||
XCONTENT_DATA XamMakeContent(DWORD type, const std::string_view& name);
|
||||
XCONTENT_DATA XamMakeContent(uint32_t type, const std::string_view& name);
|
||||
void XamRegisterContent(const XCONTENT_DATA& data, const std::string_view& root);
|
||||
|
||||
std::string_view XamGetRootPath(const std::string_view& root);
|
||||
void XamRootCreate(const std::string_view& root, const std::string_view& path);
|
||||
|
||||
SWA_API DWORD XamNotifyCreateListener(uint64_t qwAreas);
|
||||
SWA_API void XamNotifyEnqueueEvent(DWORD dwId, DWORD dwParam); // i made it the fuck up
|
||||
SWA_API bool XNotifyGetNext(DWORD hNotification, DWORD dwMsgFilter, XDWORD* pdwId, XDWORD* pParam);
|
||||
SWA_API uint32_t XamNotifyCreateListener(uint64_t qwAreas);
|
||||
SWA_API void XamNotifyEnqueueEvent(uint32_t dwId, uint32_t dwParam); // i made it the fuck up
|
||||
SWA_API bool XNotifyGetNext(uint32_t hNotification, uint32_t dwMsgFilter, be<uint32_t>* pdwId, be<uint32_t>* pParam);
|
||||
|
||||
SWA_API uint32_t XamShowMessageBoxUI(DWORD dwUserIndex, XWORD* wszTitle, XWORD* wszText, DWORD cButtons,
|
||||
xpointer<XWORD>* pwszButtons, DWORD dwFocusButton, DWORD dwFlags, XLPDWORD pResult, XXOVERLAPPED* pOverlapped);
|
||||
SWA_API uint32_t XamShowMessageBoxUI(uint32_t dwUserIndex, be<uint16_t>* wszTitle, be<uint16_t>* wszText, uint32_t cButtons,
|
||||
xpointer<be<uint16_t>>* pwszButtons, uint32_t dwFocusButton, uint32_t dwFlags, be<uint32_t>* pResult, XXOVERLAPPED* pOverlapped);
|
||||
|
||||
SWA_API uint32_t XamContentCreateEnumerator(DWORD dwUserIndex, DWORD DeviceID, DWORD dwContentType,
|
||||
DWORD dwContentFlags, DWORD cItem, XLPDWORD pcbBuffer, XLPDWORD phEnum);
|
||||
SWA_API uint32_t XamEnumerate(uint32_t hEnum, DWORD dwFlags, PVOID pvBuffer, DWORD cbBuffer, XLPDWORD pcItemsReturned, XXOVERLAPPED* pOverlapped);
|
||||
SWA_API uint32_t XamContentCreateEnumerator(uint32_t dwUserIndex, uint32_t DeviceID, uint32_t dwContentType,
|
||||
uint32_t dwContentFlags, uint32_t cItem, be<uint32_t>* pcbBuffer, be<uint32_t>* phEnum);
|
||||
SWA_API uint32_t XamEnumerate(uint32_t hEnum, uint32_t dwFlags, void* pvBuffer, uint32_t cbBuffer, be<uint32_t>* pcItemsReturned, XXOVERLAPPED* pOverlapped);
|
||||
|
||||
SWA_API uint32_t XamContentCreateEx(DWORD dwUserIndex, LPCSTR szRootName, const XCONTENT_DATA* pContentData,
|
||||
DWORD dwContentFlags, XLPDWORD pdwDisposition, XLPDWORD pdwLicenseMask,
|
||||
DWORD dwFileCacheSize, uint64_t uliContentSize, PXXOVERLAPPED pOverlapped);
|
||||
SWA_API uint32_t XamContentGetDeviceData(DWORD DeviceID, XDEVICE_DATA* pDeviceData);
|
||||
SWA_API uint32_t XamContentClose(LPCSTR szRootName, XXOVERLAPPED* pOverlapped);
|
||||
SWA_API uint32_t XamContentCreateEx(uint32_t dwUserIndex, const char* szRootName, const XCONTENT_DATA* pContentData,
|
||||
uint32_t dwContentFlags, be<uint32_t>* pdwDisposition, be<uint32_t>* pdwLicenseMask,
|
||||
uint32_t dwFileCacheSize, uint64_t uliContentSize, PXXOVERLAPPED pOverlapped);
|
||||
SWA_API uint32_t XamContentGetDeviceData(uint32_t DeviceID, XDEVICE_DATA* pDeviceData);
|
||||
SWA_API uint32_t XamContentClose(const char* szRootName, XXOVERLAPPED* pOverlapped);
|
||||
|
||||
SWA_API uint32_t XamInputGetCapabilities(uint32_t unk, uint32_t userIndex, uint32_t flags, XAMINPUT_CAPABILITIES* caps);
|
||||
SWA_API uint32_t XamInputGetState(uint32_t userIndex, uint32_t flags, XAMINPUT_STATE* state);
|
||||
|
|
|
|||
|
|
@ -3,9 +3,84 @@
|
|||
#include "heap.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define OBJECT_SIGNATURE (DWORD)'XBOX'
|
||||
#define OBJECT_SIGNATURE (uint32_t)'XBOX'
|
||||
#define GUEST_INVALID_HANDLE_VALUE 0xFFFFFFFF
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#define S_OK 0x00000000
|
||||
#define FALSE 0x00000000
|
||||
#define TRUE 0x00000001
|
||||
#define STATUS_SUCCESS 0x00000000
|
||||
#define STATUS_WAIT_0 0x00000000
|
||||
#define STATUS_USER_APC 0x000000C0
|
||||
#define STATUS_TIMEOUT 0x00000102
|
||||
#define STATUS_FAIL_CHECK 0xC0000229
|
||||
#define INFINITE 0xFFFFFFFF
|
||||
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
||||
#define FILE_ATTRIBUTE_NORMAL 0x00000080
|
||||
#define GENERIC_READ 0x80000000
|
||||
#define GENERIC_WRITE 0x40000000
|
||||
#define FILE_READ_DATA 0x0001
|
||||
#define FILE_SHARE_READ 0x00000001
|
||||
#define FILE_SHARE_WRITE 0x00000002
|
||||
#define CREATE_NEW 1
|
||||
#define CREATE_ALWAYS 2
|
||||
#define OPEN_EXISTING 3
|
||||
#define INVALID_FILE_SIZE 0xFFFFFFFF
|
||||
#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
|
||||
#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
|
||||
#define FILE_BEGIN 0
|
||||
#define FILE_CURRENT 1
|
||||
#define FILE_END 2
|
||||
#define ERROR_NO_MORE_FILES 0x12
|
||||
#define ERROR_NO_SUCH_USER 0x525
|
||||
#define ERROR_SUCCESS 0x0
|
||||
#define ERROR_PATH_NOT_FOUND 0x3
|
||||
#define ERROR_BAD_ARGUMENTS 0xA0
|
||||
#define ERROR_DEVICE_NOT_CONNECTED 0x48F
|
||||
#define PAGE_READWRITE 0x04
|
||||
|
||||
typedef union _LARGE_INTEGER {
|
||||
struct {
|
||||
uint32_t LowPart;
|
||||
int32_t HighPart;
|
||||
};
|
||||
struct {
|
||||
uint32_t LowPart;
|
||||
int32_t HighPart;
|
||||
} u;
|
||||
int64_t QuadPart;
|
||||
} LARGE_INTEGER;
|
||||
|
||||
static_assert(sizeof(LARGE_INTEGER) == 8);
|
||||
|
||||
typedef struct _FILETIME
|
||||
{
|
||||
uint32_t dwLowDateTime;
|
||||
uint32_t dwHighDateTime;
|
||||
} FILETIME;
|
||||
|
||||
static_assert(sizeof(FILETIME) == 8);
|
||||
|
||||
typedef struct _WIN32_FIND_DATAA
|
||||
{
|
||||
uint32_t dwFileAttributes;
|
||||
FILETIME ftCreationTime;
|
||||
FILETIME ftLastAccessTime;
|
||||
FILETIME ftLastWriteTime;
|
||||
uint32_t nFileSizeHigh;
|
||||
uint32_t nFileSizeLow;
|
||||
uint32_t dwReserved0;
|
||||
uint32_t dwReserved1;
|
||||
char cFileName[260];
|
||||
char cAlternateFileName[14];
|
||||
} WIN32_FIND_DATAA;
|
||||
|
||||
static_assert(sizeof(WIN32_FIND_DATAA) == 320);
|
||||
|
||||
#endif
|
||||
|
||||
struct KernelObject
|
||||
{
|
||||
virtual ~KernelObject()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include <user/config.h>
|
||||
#include <user/config_detail.h>
|
||||
|
||||
#define CONFIG_DEFINE_LOCALE(name) \
|
||||
CONFIG_LOCALE Config::g_##name##_locale =
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include <user/config.h>
|
||||
#include <locale/locale.h>
|
||||
|
||||
std::unordered_map<std::string, std::unordered_map<ELanguage, std::string>> g_locale =
|
||||
|
|
|
|||
|
|
@ -1,6 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <user/config.h>
|
||||
enum class ELanguage : uint32_t
|
||||
{
|
||||
English = 1,
|
||||
Japanese,
|
||||
German,
|
||||
French,
|
||||
Spanish,
|
||||
Italian
|
||||
};
|
||||
|
||||
inline std::string g_localeMissing = "<missing string>";
|
||||
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ void KiSystemStartup()
|
|||
{
|
||||
const auto gameContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Game");
|
||||
const auto updateContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Update");
|
||||
XamRegisterContent(gameContent, DirectoryExists(".\\game") ? ".\\game" : ".");
|
||||
XamRegisterContent(updateContent, ".\\update");
|
||||
XamRegisterContent(gameContent, std::filesystem::exists("./game") ? "./game" : ".");
|
||||
XamRegisterContent(updateContent, "./update");
|
||||
|
||||
const auto savePath = GetSavePath();
|
||||
const auto saveName = "SYS-DATA";
|
||||
|
|
@ -69,27 +69,6 @@ void KiSystemStartup()
|
|||
// OS mounts game data to D:
|
||||
XamContentCreateEx(0, "D", &gameContent, OPEN_EXISTING, nullptr, nullptr, 0, 0, nullptr);
|
||||
|
||||
WIN32_FIND_DATAA fdata;
|
||||
const auto findHandle = FindFirstFileA(".\\dlc\\*.*", &fdata);
|
||||
if (findHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
char strBuf[256];
|
||||
do
|
||||
{
|
||||
if (strcmp(fdata.cFileName, ".") == 0 || strcmp(fdata.cFileName, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
snprintf(strBuf, sizeof(strBuf), ".\\dlc\\%s", fdata.cFileName);
|
||||
XamRegisterContent(XamMakeContent(XCONTENTTYPE_DLC, fdata.cFileName), strBuf);
|
||||
}
|
||||
} while (FindNextFileA(findHandle, &fdata));
|
||||
FindClose(findHandle);
|
||||
}
|
||||
|
||||
XAudioInitializeSystem();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,23 @@
|
|||
#include "stdafx.h"
|
||||
#include <kernel/function.h>
|
||||
#include <kernel/xdm.h>
|
||||
|
||||
BOOL QueryPerformanceCounterImpl(LARGE_INTEGER* lpPerformanceCount)
|
||||
uint32_t QueryPerformanceCounterImpl(LARGE_INTEGER* lpPerformanceCount)
|
||||
{
|
||||
lpPerformanceCount->QuadPart = ByteSwap(std::chrono::steady_clock::now().time_since_epoch().count());
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL QueryPerformanceFrequencyImpl(LARGE_INTEGER* lpFrequency)
|
||||
uint32_t QueryPerformanceFrequencyImpl(LARGE_INTEGER* lpFrequency)
|
||||
{
|
||||
constexpr auto Frequency = std::chrono::steady_clock::period::den / std::chrono::steady_clock::period::num;
|
||||
lpFrequency->QuadPart = ByteSwap(Frequency);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD GetTickCountImpl()
|
||||
uint32_t GetTickCountImpl()
|
||||
{
|
||||
return DWORD(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count());
|
||||
return uint32_t(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count());
|
||||
}
|
||||
|
||||
void GlobalMemoryStatusImpl(XLPMEMORYSTATUS lpMemoryStatus)
|
||||
|
|
@ -42,7 +43,11 @@ GUEST_FUNCTION_HOOK(sub_831B5E00, memmove);
|
|||
GUEST_FUNCTION_HOOK(sub_831B0BA0, memset);
|
||||
GUEST_FUNCTION_HOOK(sub_831CCAA0, memset);
|
||||
|
||||
#ifdef _WIN32
|
||||
GUEST_FUNCTION_HOOK(sub_82BD4CA8, OutputDebugStringA);
|
||||
#else
|
||||
GUEST_FUNCTION_STUB(sub_82BD4CA8);
|
||||
#endif
|
||||
|
||||
GUEST_FUNCTION_HOOK(sub_82BD4AC8, QueryPerformanceCounterImpl);
|
||||
GUEST_FUNCTION_HOOK(sub_831CD040, QueryPerformanceFrequencyImpl);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
struct Mutex : CRITICAL_SECTION
|
||||
{
|
||||
Mutex()
|
||||
|
|
@ -21,3 +23,9 @@ struct Mutex : CRITICAL_SECTION
|
|||
LeaveCriticalSection(this);
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
using Mutex = std::mutex;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
17
UnleashedRecomp/os/linux/logger_linux.cpp
Normal file
17
UnleashedRecomp/os/linux/logger_linux.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#include <os/logger_detail.h>
|
||||
|
||||
void os::logger::detail::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void os::logger::detail::Log(const std::string_view str, detail::ELogType type, const char* func)
|
||||
{
|
||||
if (func)
|
||||
{
|
||||
fmt::println("[{}] {}", func, str);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::println("{}", str);
|
||||
}
|
||||
}
|
||||
7
UnleashedRecomp/os/linux/media_linux.cpp
Normal file
7
UnleashedRecomp/os/linux/media_linux.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include <os/media_detail.h>
|
||||
|
||||
bool os::media::detail::IsExternalMediaPlaying()
|
||||
{
|
||||
// This functionality is not supported in Linux.
|
||||
return false;
|
||||
}
|
||||
57
UnleashedRecomp/os/linux/process_linux.cpp
Normal file
57
UnleashedRecomp/os/linux/process_linux.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include <os/process_detail.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
std::filesystem::path os::process::detail::GetExecutablePath()
|
||||
{
|
||||
char exePath[PATH_MAX] = {};
|
||||
if (readlink("/proc/self/exe", exePath, PATH_MAX) > 0)
|
||||
{
|
||||
return std::filesystem::path(std::u8string_view((const char8_t*)(exePath)));
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::filesystem::path();
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path os::process::detail::GetWorkingDirectory()
|
||||
{
|
||||
char cwd[PATH_MAX] = {};
|
||||
char *res = getcwd(cwd, sizeof(cwd));
|
||||
if (res != nullptr)
|
||||
{
|
||||
return std::filesystem::path(std::u8string_view((const char8_t*)(cwd)));
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::filesystem::path();
|
||||
}
|
||||
}
|
||||
|
||||
bool os::process::detail::StartProcess(const std::filesystem::path path, const std::vector<std::string> args, std::filesystem::path work)
|
||||
{
|
||||
pid_t pid = fork();
|
||||
if (pid < 0)
|
||||
return false;
|
||||
|
||||
if (pid == 0)
|
||||
{
|
||||
setsid();
|
||||
|
||||
std::u8string workU8 = work.u8string();
|
||||
chdir((const char*)(workU8.c_str()));
|
||||
|
||||
std::u8string pathU8 = path.u8string();
|
||||
std::vector<char*> argStrs;
|
||||
argStrs.push_back((char*)(pathU8.c_str()));
|
||||
for (const std::string& arg : args)
|
||||
argStrs.push_back((char *)(arg.c_str()));
|
||||
|
||||
argStrs.push_back(nullptr);
|
||||
execvp((const char*)(pathU8.c_str()), argStrs.data());
|
||||
raise(SIGKILL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
7
UnleashedRecomp/os/linux/version_linux.cpp
Normal file
7
UnleashedRecomp/os/linux/version_linux.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#include <os/version_detail.h>
|
||||
|
||||
os::version::detail::OSVersion os::version::detail::GetOSVersion()
|
||||
{
|
||||
assert(false && "Unimplemented.");
|
||||
return os::version::detail::OSVersion();
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/config.h>
|
||||
|
||||
constexpr float m_baseAspectRatio = 16.0f / 9.0f;
|
||||
|
|
@ -8,7 +8,7 @@ constexpr float m_baseAspectRatio = 16.0f / 9.0f;
|
|||
bool CameraAspectRatioMidAsmHook(PPCRegister& r31)
|
||||
{
|
||||
auto pCamera = (SWA::CCamera*)g_memory.Translate(r31.u32);
|
||||
auto newAspectRatio = (float)Window::s_width / (float)Window::s_height;
|
||||
auto newAspectRatio = (float)GameWindow::s_width / (float)GameWindow::s_height;
|
||||
|
||||
// Dynamically adjust horizontal aspect ratio to window dimensions.
|
||||
pCamera->m_HorzAspectRatio = newAspectRatio;
|
||||
|
|
@ -27,7 +27,7 @@ bool CameraBoostAspectRatioMidAsmHook(PPCRegister& r31, PPCRegister& f0, PPCRegi
|
|||
{
|
||||
auto pCamera = (SWA::CCamera*)g_memory.Translate(r31.u32);
|
||||
|
||||
if (Window::s_width < Window::s_height)
|
||||
if (GameWindow::s_width < GameWindow::s_height)
|
||||
{
|
||||
pCamera->m_VertFieldOfView = pCamera->m_HorzFieldOfView + f10.f64;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/config.h>
|
||||
#include <app.h>
|
||||
|
||||
float m_lastLoadingFrameDelta = 0.0f;
|
||||
std::chrono::steady_clock::time_point m_lastLoadingFrameTime;
|
||||
std::chrono::high_resolution_clock::time_point m_lastLoadingFrameTime;
|
||||
|
||||
void DownForceDeltaTimeFixMidAsmHook(PPCRegister& f0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/achievement_data.h>
|
||||
#include <user/config.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <ui/window_events.h>
|
||||
#include <user/config.h>
|
||||
#include <os/logger.h>
|
||||
|
|
@ -126,7 +126,7 @@ PPC_FUNC(sub_823B49D8)
|
|||
{
|
||||
__imp__sub_823B49D8(ctx, base);
|
||||
|
||||
SDL_User_EvilSonic(Window::s_pWindow, true);
|
||||
SDL_User_EvilSonic(GameWindow::s_pWindow, true);
|
||||
}
|
||||
|
||||
// SWA::Player::CEvilSonicContext::Dtor
|
||||
|
|
@ -135,5 +135,5 @@ PPC_FUNC(sub_823B4590)
|
|||
{
|
||||
__imp__sub_823B4590(ctx, base);
|
||||
|
||||
SDL_User_EvilSonic(Window::s_pWindow, false);
|
||||
SDL_User_EvilSonic(GameWindow::s_pWindow, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <cpu/guest_code.h>
|
||||
#include <user/config.h>
|
||||
#include <api/SWA.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
|
||||
// TODO: to be removed.
|
||||
constexpr float m_baseAspectRatio = 16.0f / 9.0f;
|
||||
|
|
@ -12,7 +12,7 @@ void CSDAspectRatioMidAsmHook(PPCRegister& f1, PPCRegister& f2)
|
|||
if (Config::UIScaleMode == EUIScaleMode::Stretch)
|
||||
return;
|
||||
|
||||
auto newAspectRatio = (float)Window::s_width / (float)Window::s_height;
|
||||
auto newAspectRatio = (float)GameWindow::s_width / (float)GameWindow::s_height;
|
||||
|
||||
if (newAspectRatio > m_baseAspectRatio)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,11 +34,11 @@ using Microsoft::WRL::ComPtr;
|
|||
#include <toml++/toml.hpp>
|
||||
#include <zstd.h>
|
||||
#include <stb_image.h>
|
||||
#include <concurrentqueue/blockingconcurrentqueue.h>
|
||||
#include <blockingconcurrentqueue.h>
|
||||
#include <SDL.h>
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <imgui_impl_sdl2.h>
|
||||
#include <backends/imgui_impl_sdl2.h>
|
||||
#include <o1heap.h>
|
||||
#include <cstddef>
|
||||
#include <smolv.h>
|
||||
|
|
@ -46,6 +46,7 @@ using Microsoft::WRL::ComPtr;
|
|||
#include <miniaudio.h>
|
||||
#include <extras/miniaudio_libvorbis.h>
|
||||
#include <fmt/core.h>
|
||||
#include <list>
|
||||
|
||||
#include "framework.h"
|
||||
#include "mutex.h"
|
||||
|
|
|
|||
|
|
@ -281,9 +281,14 @@ static void DrawAchievement(int rowIndex, float yOffset, Achievement& achievemen
|
|||
return;
|
||||
|
||||
char buffer[32];
|
||||
struct tm time;
|
||||
localtime_s(&time, ×tamp);
|
||||
strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M", &time);
|
||||
#ifdef _WIN32
|
||||
tm timeStruct;
|
||||
tm *timePtr = &timeStruct;
|
||||
localtime_s(timePtr, ×tamp);
|
||||
#else
|
||||
tm *timePtr = localtime(×tamp);
|
||||
#endif
|
||||
strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M", timePtr);
|
||||
|
||||
fontSize = Scale(12);
|
||||
textSize = g_fntNewRodinDB->CalcTextSizeA(fontSize, FLT_MAX, 0, buffer);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include "window.h"
|
||||
#include "game_window.h"
|
||||
#include "sdl_listener.h"
|
||||
#include <user/config.h>
|
||||
#include <SDL_syswm.h>
|
||||
|
|
@ -31,10 +31,10 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
|
|||
if (!(event->key.keysym.mod & KMOD_ALT) || !m_isFullscreenKeyReleased)
|
||||
break;
|
||||
|
||||
Config::Fullscreen = Window::SetFullscreen(!Window::IsFullscreen());
|
||||
Config::Fullscreen = GameWindow::SetFullscreen(!GameWindow::IsFullscreen());
|
||||
|
||||
if (!Config::Fullscreen)
|
||||
Config::WindowState = Window::SetMaximised(Config::WindowState == EWindowState::Maximised);
|
||||
Config::WindowState = GameWindow::SetMaximised(Config::WindowState == EWindowState::Maximised);
|
||||
|
||||
// Block holding ALT+ENTER spamming window changes.
|
||||
m_isFullscreenKeyReleased = false;
|
||||
|
|
@ -44,17 +44,17 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
|
|||
|
||||
// Restore original window dimensions on F2.
|
||||
case SDLK_F2:
|
||||
Config::Fullscreen = Window::SetFullscreen(false);
|
||||
Window::SetDimensions(DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
||||
Config::Fullscreen = GameWindow::SetFullscreen(false);
|
||||
GameWindow::SetDimensions(DEFAULT_WIDTH, DEFAULT_HEIGHT);
|
||||
break;
|
||||
|
||||
// Recentre window on F3.
|
||||
case SDLK_F3:
|
||||
{
|
||||
if (Window::IsFullscreen())
|
||||
if (GameWindow::IsFullscreen())
|
||||
break;
|
||||
|
||||
Window::SetDimensions(Window::s_width, Window::s_height);
|
||||
GameWindow::SetDimensions(GameWindow::s_width, GameWindow::s_height);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -79,16 +79,16 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
|
|||
switch (event->window.event)
|
||||
{
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST:
|
||||
Window::s_isFocused = false;
|
||||
GameWindow::s_isFocused = false;
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
{
|
||||
Window::s_isFocused = true;
|
||||
GameWindow::s_isFocused = true;
|
||||
|
||||
if (Window::IsFullscreen())
|
||||
SDL_ShowCursor(Window::s_isFullscreenCursorVisible ? SDL_ENABLE : SDL_DISABLE);
|
||||
if (GameWindow::IsFullscreen())
|
||||
SDL_ShowCursor(GameWindow::s_isFullscreenCursorVisible ? SDL_ENABLE : SDL_DISABLE);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -103,14 +103,14 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
|
|||
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
m_isResizing = true;
|
||||
Window::s_width = event->window.data1;
|
||||
Window::s_height = event->window.data2;
|
||||
Window::SetTitle(fmt::format("{} - [{}x{}]", Window::GetTitle(), Window::s_width, Window::s_height).c_str());
|
||||
GameWindow::s_width = event->window.data1;
|
||||
GameWindow::s_height = event->window.data2;
|
||||
GameWindow::SetTitle(fmt::format("{} - [{}x{}]", GameWindow::GetTitle(), GameWindow::s_width, GameWindow::s_height).c_str());
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_MOVED:
|
||||
Window::s_x = event->window.data1;
|
||||
Window::s_y = event->window.data2;
|
||||
GameWindow::s_x = event->window.data1;
|
||||
GameWindow::s_y = event->window.data2;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -119,13 +119,13 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
|
|||
|
||||
case SDL_USER_EVILSONIC:
|
||||
{
|
||||
Window::s_isIconNight = event->user.code;
|
||||
Window::SetIcon(Window::s_isIconNight);
|
||||
GameWindow::s_isIconNight = event->user.code;
|
||||
GameWindow::SetIcon(GameWindow::s_isIconNight);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Window::IsFullscreen())
|
||||
if (!GameWindow::IsFullscreen())
|
||||
{
|
||||
if (event->type == SDL_CONTROLLERBUTTONDOWN || event->type == SDL_CONTROLLERBUTTONUP || event->type == SDL_CONTROLLERAXISMOTION)
|
||||
{
|
||||
|
|
@ -142,12 +142,14 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Window::Init()
|
||||
void GameWindow::Init()
|
||||
{
|
||||
SDL_InitSubSystem(SDL_INIT_VIDEO);
|
||||
SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
|
||||
SDL_AddEventWatch(Window_OnSDLEvent, s_pWindow);
|
||||
#ifdef _WIN32
|
||||
SetProcessDPIAware();
|
||||
#endif
|
||||
|
||||
s_x = Config::WindowX;
|
||||
s_y = Config::WindowY;
|
||||
|
|
@ -183,21 +185,26 @@ void Window::Init()
|
|||
SDL_VERSION(&info.version);
|
||||
SDL_GetWindowWMInfo(s_pWindow, &info);
|
||||
|
||||
s_handle = info.info.win.window;
|
||||
|
||||
#if defined(_WIN32)
|
||||
s_renderWindow = info.info.win.window;
|
||||
SetDarkTitleBar(true);
|
||||
#elif defined(__linux__)
|
||||
s_renderWindow = { info.info.x11.display, info.info.x11.window };
|
||||
#else
|
||||
static_assert(false, "Unknown platform.");
|
||||
#endif
|
||||
|
||||
SDL_ShowWindow(s_pWindow);
|
||||
}
|
||||
|
||||
void Window::Update()
|
||||
void GameWindow::Update()
|
||||
{
|
||||
if (!Window::IsFullscreen() && !Window::IsMaximised())
|
||||
if (!GameWindow::IsFullscreen() && !GameWindow::IsMaximised())
|
||||
{
|
||||
Config::WindowX = Window::s_x;
|
||||
Config::WindowY = Window::s_y;
|
||||
Config::WindowWidth = Window::s_width;
|
||||
Config::WindowHeight = Window::s_height;
|
||||
Config::WindowX = GameWindow::s_x;
|
||||
Config::WindowY = GameWindow::s_y;
|
||||
Config::WindowWidth = GameWindow::s_width;
|
||||
Config::WindowHeight = GameWindow::s_height;
|
||||
}
|
||||
|
||||
if (m_isResizing)
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
#include <os/version.h>
|
||||
#include <ui/window_events.h>
|
||||
#include <user/config.h>
|
||||
#include <gpu/rhi/plume_render_interface_types.h>
|
||||
|
||||
#if _WIN32
|
||||
#include <dwmapi.h>
|
||||
|
|
@ -15,11 +16,11 @@
|
|||
#define DEFAULT_WIDTH 1280
|
||||
#define DEFAULT_HEIGHT 720
|
||||
|
||||
class Window
|
||||
class GameWindow
|
||||
{
|
||||
public:
|
||||
static inline SDL_Window* s_pWindow;
|
||||
static inline HWND s_handle;
|
||||
static inline plume::RenderWindow s_renderWindow;
|
||||
|
||||
static inline int s_x;
|
||||
static inline int s_y;
|
||||
|
|
@ -87,7 +88,7 @@ public:
|
|||
: 19; // DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1
|
||||
|
||||
const DWORD useImmersiveDarkMode = isEnabled;
|
||||
DwmSetWindowAttribute(s_handle, flag, &useImmersiveDarkMode, sizeof(useImmersiveDarkMode));
|
||||
DwmSetWindowAttribute(s_renderWindow, flag, &useImmersiveDarkMode, sizeof(useImmersiveDarkMode));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +108,7 @@ public:
|
|||
{
|
||||
SDL_SetWindowFullscreen(s_pWindow, 0);
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
SetIcon(Window::s_isIconNight);
|
||||
SetIcon(GameWindow::s_isIconNight);
|
||||
}
|
||||
|
||||
return isEnabled;
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
#include <ui/button_guide.h>
|
||||
#include <ui/message_window.h>
|
||||
#include <ui/sdl_listener.h>
|
||||
#include <ui/window.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <decompressor.h>
|
||||
|
||||
#include <res/images/installer/install_001.dds.h>
|
||||
|
|
@ -133,8 +133,12 @@ static WizardPage g_firstPage = WizardPage::SelectLanguage;
|
|||
static WizardPage g_currentPage = g_firstPage;
|
||||
static std::string g_currentMessagePrompt = "";
|
||||
static bool g_currentMessagePromptConfirmation = false;
|
||||
static std::list<std::filesystem::path> g_currentPickerResults;
|
||||
static std::atomic<bool> g_currentPickerResultsReady = false;
|
||||
static std::unique_ptr<std::thread> g_currentPickerThread;
|
||||
static bool g_currentPickerVisible = false;
|
||||
static bool g_currentPickerFolderMode = false;
|
||||
static int g_currentMessageResult = -1;
|
||||
static bool g_filesPickerSkipUpdate = false;
|
||||
static ImVec2 g_joypadAxis = {};
|
||||
static int g_currentCursorIndex = -1;
|
||||
static int g_currentCursorDefault = 0;
|
||||
|
|
@ -148,7 +152,7 @@ public:
|
|||
{
|
||||
constexpr float AxisValueRange = 32767.0f;
|
||||
constexpr float AxisTapRange = 0.5f;
|
||||
if (!InstallerWizard::s_isVisible || !g_currentMessagePrompt.empty())
|
||||
if (!InstallerWizard::s_isVisible || !g_currentMessagePrompt.empty() || g_currentPickerVisible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -217,7 +221,7 @@ public:
|
|||
case SDL_MOUSEBUTTONDOWN:
|
||||
case SDL_MOUSEMOTION:
|
||||
{
|
||||
for (size_t i = 0; i < g_currentCursorRects.size() && !g_filesPickerSkipUpdate; i++)
|
||||
for (size_t i = 0; i < g_currentCursorRects.size(); i++)
|
||||
{
|
||||
auto ¤tRect = g_currentCursorRects[i];
|
||||
if (ImGui::IsMouseHoveringRect(currentRect.first, currentRect.second, false))
|
||||
|
|
@ -734,7 +738,7 @@ static void DrawButton(ImVec2 min, ImVec2 max, const char *buttonText, bool sour
|
|||
|
||||
int baser = 0;
|
||||
int baseg = 0;
|
||||
if (g_currentMessagePrompt.empty() && !sourceButton && buttonEnabled && (alpha >= 1.0f))
|
||||
if (g_currentMessagePrompt.empty() && !g_currentPickerVisible && !sourceButton && buttonEnabled && (alpha >= 1.0f))
|
||||
{
|
||||
bool cursorOnButton = PushCursorRect(min, max, buttonPressed, makeDefault);
|
||||
if (cursorOnButton)
|
||||
|
|
@ -882,44 +886,44 @@ static bool ConvertPathSet(const nfdpathset_t *pathSet, std::list<std::filesyste
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool ShowFilesPicker(std::list<std::filesystem::path> &filePaths)
|
||||
static void PickerThreadProcess()
|
||||
{
|
||||
filePaths.clear();
|
||||
|
||||
const nfdpathset_t *pathSet;
|
||||
nfdresult_t result = NFD_OpenDialogMultipleU8(&pathSet, nullptr, 0, nullptr);
|
||||
g_filesPickerSkipUpdate = true;
|
||||
|
||||
if (result == NFD_OKAY)
|
||||
nfdresult_t result = NFD_ERROR;
|
||||
if (g_currentPickerFolderMode)
|
||||
{
|
||||
bool pathsConverted = ConvertPathSet(pathSet, filePaths);
|
||||
NFD_PathSet_Free(pathSet);
|
||||
return pathsConverted;
|
||||
nfdpickfolderu8args_t openArgs = {};
|
||||
result = NFD_PickFolderMultipleU8_With(&pathSet, &openArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
nfdopendialogu8args_t openArgs = {};
|
||||
result = NFD_OpenDialogMultipleU8_With(&pathSet, &openArgs);
|
||||
}
|
||||
|
||||
if (result == NFD_OKAY)
|
||||
{
|
||||
bool pathsConverted = ConvertPathSet(pathSet, g_currentPickerResults);
|
||||
NFD_PathSet_Free(pathSet);
|
||||
}
|
||||
|
||||
g_currentPickerResultsReady = true;
|
||||
g_currentPickerVisible = false;
|
||||
}
|
||||
|
||||
static bool ShowFoldersPicker(std::list<std::filesystem::path> &folderPaths)
|
||||
static void ShowPicker(bool folderMode)
|
||||
{
|
||||
folderPaths.clear();
|
||||
|
||||
const nfdpathset_t *pathSet;
|
||||
nfdresult_t result = NFD_PickFolderMultipleU8(&pathSet, nullptr);
|
||||
g_filesPickerSkipUpdate = true;
|
||||
|
||||
if (result == NFD_OKAY)
|
||||
if (g_currentPickerThread != nullptr)
|
||||
{
|
||||
bool pathsConverted = ConvertPathSet(pathSet, folderPaths);
|
||||
NFD_PathSet_Free(pathSet);
|
||||
return pathsConverted;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
g_currentPickerThread->join();
|
||||
g_currentPickerThread.reset();
|
||||
}
|
||||
|
||||
g_currentPickerResults.clear();
|
||||
g_currentPickerFolderMode = folderMode;
|
||||
g_currentPickerResultsReady = false;
|
||||
g_currentPickerVisible = true;
|
||||
g_currentPickerThread = std::make_unique<std::thread>(PickerThreadProcess);
|
||||
}
|
||||
|
||||
static void ParseSourcePaths(std::list<std::filesystem::path> &paths)
|
||||
|
|
@ -1013,8 +1017,6 @@ static void DrawLanguagePicker()
|
|||
|
||||
static void DrawSourcePickers()
|
||||
{
|
||||
g_filesPickerSkipUpdate = false;
|
||||
|
||||
bool buttonPressed = false;
|
||||
std::list<std::filesystem::path> paths;
|
||||
if (g_currentPage == WizardPage::SelectGameAndUpdate || g_currentPage == WizardPage::SelectDLC)
|
||||
|
|
@ -1028,9 +1030,9 @@ static void DrawSourcePickers()
|
|||
ImVec2 min = { Scale(AlignToNextGrid(CONTAINER_X) + BOTTOM_X_GAP), Scale(AlignToNextGrid(CONTAINER_Y + CONTAINER_HEIGHT) + BOTTOM_Y_GAP) };
|
||||
ImVec2 max = { Scale(AlignToNextGrid(CONTAINER_X) + BOTTOM_X_GAP + textSize.x * squashRatio), Scale(AlignToNextGrid(CONTAINER_Y + CONTAINER_HEIGHT) + BOTTOM_Y_GAP + BUTTON_HEIGHT) };
|
||||
DrawButton(min, max, addFilesText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
|
||||
if (buttonPressed && ShowFilesPicker(paths))
|
||||
if (buttonPressed)
|
||||
{
|
||||
ParseSourcePaths(paths);
|
||||
ShowPicker(false);
|
||||
}
|
||||
|
||||
min.x += Scale(BOTTOM_X_GAP + textSize.x * squashRatio);
|
||||
|
|
@ -1041,9 +1043,9 @@ static void DrawSourcePickers()
|
|||
|
||||
max.x = min.x + Scale(textSize.x * squashRatio);
|
||||
DrawButton(min, max, addFolderText.c_str(), false, true, buttonPressed, ADD_BUTTON_MAX_TEXT_WIDTH);
|
||||
if (buttonPressed && ShowFoldersPicker(paths))
|
||||
if (buttonPressed)
|
||||
{
|
||||
ParseSourcePaths(paths);
|
||||
ShowPicker(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1305,14 +1307,6 @@ static void DrawBorders()
|
|||
|
||||
static void DrawMessagePrompt()
|
||||
{
|
||||
if (g_filesPickerSkipUpdate)
|
||||
{
|
||||
// If a blocking function like the files picker is called, we must wait one update before actually showing
|
||||
// the message box, as a lot of time has passed since the last real update. Otherwise, animations will play
|
||||
// too quickly and input glitches might happen.
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_currentMessagePrompt.empty())
|
||||
{
|
||||
return;
|
||||
|
|
@ -1342,6 +1336,18 @@ static void DrawMessagePrompt()
|
|||
}
|
||||
}
|
||||
|
||||
static void CheckPickerResults()
|
||||
{
|
||||
if (!g_currentPickerResultsReady)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ParseSourcePaths(g_currentPickerResults);
|
||||
g_currentPickerResultsReady = false;
|
||||
g_currentPickerVisible = false;
|
||||
}
|
||||
|
||||
void InstallerWizard::Init()
|
||||
{
|
||||
auto &io = ImGui::GetIO();
|
||||
|
|
@ -1380,6 +1386,7 @@ void InstallerWizard::Draw()
|
|||
DrawNextButton();
|
||||
DrawBorders();
|
||||
DrawMessagePrompt();
|
||||
CheckPickerResults();
|
||||
|
||||
if (g_isDisappearing)
|
||||
{
|
||||
|
|
@ -1439,18 +1446,18 @@ bool InstallerWizard::Run(bool skipGame)
|
|||
g_currentPage = g_firstPage;
|
||||
}
|
||||
|
||||
Window::SetFullscreenCursorVisibility(true);
|
||||
GameWindow::SetFullscreenCursorVisibility(true);
|
||||
s_isVisible = true;
|
||||
|
||||
while (s_isVisible)
|
||||
{
|
||||
SDL_PumpEvents();
|
||||
SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
|
||||
Window::Update();
|
||||
GameWindow::Update();
|
||||
Video::HostPresent();
|
||||
}
|
||||
|
||||
Window::SetFullscreenCursorVisibility(false);
|
||||
GameWindow::SetFullscreenCursorVisibility(false);
|
||||
NFD_Quit();
|
||||
|
||||
InstallerWizard::Shutdown();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include "options_menu.h"
|
||||
#include "options_menu_thumbnails.h"
|
||||
#include "imgui_utils.h"
|
||||
#include "window.h"
|
||||
#include "game_window.h"
|
||||
#include "exports.h"
|
||||
|
||||
#include <api/SWA/System/InputState.h>
|
||||
|
|
@ -444,7 +444,7 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
|||
ImVec2 min = { clipRectMin.x, clipRectMin.y + (optionHeight + optionPadding) * rowIndex + yOffset };
|
||||
ImVec2 max = { min.x + optionWidth, min.y + optionHeight };
|
||||
|
||||
auto configName = config->GetNameLocalised();
|
||||
auto configName = config->GetNameLocalised(Config::Language);
|
||||
auto size = Scale(26.0f);
|
||||
auto textSize = g_seuratFont->CalcTextSizeA(size, FLT_MAX, 0.0f, configName.c_str());
|
||||
|
||||
|
|
@ -747,7 +747,7 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* conf
|
|||
}
|
||||
else
|
||||
{
|
||||
valueText = config->GetValueLocalised();
|
||||
valueText = config->GetValueLocalised(Config::Language);
|
||||
}
|
||||
|
||||
size = Scale(20.0f);
|
||||
|
|
@ -952,7 +952,7 @@ static void DrawInfoPanel()
|
|||
|
||||
if (g_selectedItem)
|
||||
{
|
||||
auto desc = g_selectedItem->GetDescription();
|
||||
auto desc = g_selectedItem->GetDescription(Config::Language);
|
||||
auto thumbnail = GetThumbnail(g_selectedItem);
|
||||
|
||||
if (thumbnail)
|
||||
|
|
@ -971,13 +971,13 @@ static void DrawInfoPanel()
|
|||
auto resScale = round(*(float*)g_selectedItem->GetValue() * 1000) / 1000;
|
||||
|
||||
std::snprintf(buf, sizeof(buf), desc.c_str(),
|
||||
(int)((float)Window::s_width * resScale),
|
||||
(int)((float)Window::s_height * resScale));
|
||||
(int)((float)GameWindow::s_width * resScale),
|
||||
(int)((float)GameWindow::s_height * resScale));
|
||||
|
||||
desc = buf;
|
||||
}
|
||||
|
||||
desc += "\n\n" + g_selectedItem->GetValueDescription();
|
||||
desc += "\n\n" + g_selectedItem->GetValueDescription(Config::Language);
|
||||
}
|
||||
|
||||
auto size = Scale(26.0f);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
#include "ui/window.h"
|
||||
#include "ui/game_window.h"
|
||||
|
||||
#define SDL_USER_EVILSONIC (SDL_USEREVENT + 1)
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ void Config::Load()
|
|||
toml = toml::parse(tomlStream);
|
||||
}
|
||||
|
||||
for (auto def : Config::Definitions)
|
||||
for (auto def : g_configDefinitions)
|
||||
{
|
||||
def->ReadValue(toml);
|
||||
#if _DEBUG
|
||||
|
|
@ -44,7 +44,7 @@ void Config::Save()
|
|||
std::string result;
|
||||
std::string section;
|
||||
|
||||
for (auto def : Config::Definitions)
|
||||
for (auto def : g_configDefinitions)
|
||||
{
|
||||
auto isFirstSection = section.empty();
|
||||
auto isDefWithSection = section != def->GetSection();
|
||||
|
|
|
|||
|
|
@ -1,14 +1,592 @@
|
|||
#pragma once
|
||||
|
||||
#include <user/config_detail.h>
|
||||
#include <locale/locale.h>
|
||||
#include <user/paths.h>
|
||||
#include <exports.h>
|
||||
|
||||
class IConfigDef
|
||||
{
|
||||
public:
|
||||
virtual ~IConfigDef() = default;
|
||||
virtual void ReadValue(toml::v3::ex::parse_result& toml) = 0;
|
||||
virtual void MakeDefault() = 0;
|
||||
virtual std::string_view GetSection() const = 0;
|
||||
virtual std::string_view GetName() const = 0;
|
||||
virtual std::string GetNameLocalised(ELanguage language) const = 0;
|
||||
virtual std::string GetDescription(ELanguage language) const = 0;
|
||||
virtual bool IsDefaultValue() const = 0;
|
||||
virtual const void* GetValue() const = 0;
|
||||
virtual std::string GetValueLocalised(ELanguage language) const = 0;
|
||||
virtual std::string GetValueDescription(ELanguage language) const = 0;
|
||||
virtual std::string GetDefinition(bool withSection = false) const = 0;
|
||||
virtual std::string ToString(bool strWithQuotes = true) const = 0;
|
||||
virtual void GetLocaleStrings(std::vector<std::string_view>& localeStrings) const = 0;
|
||||
};
|
||||
|
||||
#define CONFIG_LOCALE std::unordered_map<ELanguage, std::tuple<std::string, std::string>>
|
||||
#define CONFIG_ENUM_LOCALE(type) std::unordered_map<ELanguage, std::unordered_map<type, std::tuple<std::string, std::string>>>
|
||||
|
||||
#define CONFIG_DEFINE(section, type, name, defaultValue) \
|
||||
static inline ConfigDef<type> name{section, #name, defaultValue};
|
||||
|
||||
#define CONFIG_DEFINE_LOCALISED(section, type, name, defaultValue) \
|
||||
static CONFIG_LOCALE g_##name##_locale; \
|
||||
static inline ConfigDef<type> name{section, #name, &g_##name##_locale, defaultValue};
|
||||
|
||||
#define CONFIG_DEFINE_ENUM(section, type, name, defaultValue) \
|
||||
static inline ConfigDef<type> name{section, #name, defaultValue, &g_##type##_template};
|
||||
|
||||
#define CONFIG_DEFINE_ENUM_LOCALISED(section, type, name, defaultValue) \
|
||||
static CONFIG_LOCALE g_##name##_locale; \
|
||||
static CONFIG_ENUM_LOCALE(type) g_##type##_locale; \
|
||||
static inline ConfigDef<type> name{section, #name, &g_##name##_locale, defaultValue, &g_##type##_template, &g_##type##_locale};
|
||||
|
||||
#define CONFIG_DEFINE_CALLBACK(section, type, name, defaultValue, readCallback) \
|
||||
static CONFIG_LOCALE g_##name##_locale; \
|
||||
static inline ConfigDef<type> name{section, #name, defaultValue, [](ConfigDef<type>* def) readCallback};
|
||||
|
||||
#define CONFIG_DEFINE_ENUM_TEMPLATE(type) \
|
||||
inline std::unordered_map<std::string, type> g_##type##_template =
|
||||
|
||||
#define WINDOWPOS_CENTRED 0x2FFF0000
|
||||
|
||||
static inline std::vector<IConfigDef*> g_configDefinitions{};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(ELanguage)
|
||||
{
|
||||
{ "English", ELanguage::English },
|
||||
{ "Japanese", ELanguage::Japanese },
|
||||
{ "German", ELanguage::German },
|
||||
{ "French", ELanguage::French },
|
||||
{ "Spanish", ELanguage::Spanish },
|
||||
{ "Italian", ELanguage::Italian }
|
||||
};
|
||||
|
||||
enum class EUnleashGaugeBehaviour : uint32_t
|
||||
{
|
||||
Original,
|
||||
Revised
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EUnleashGaugeBehaviour)
|
||||
{
|
||||
{ "Original", EUnleashGaugeBehaviour::Original },
|
||||
{ "Revised", EUnleashGaugeBehaviour::Revised }
|
||||
};
|
||||
|
||||
enum class ETimeOfDayTransition : uint32_t
|
||||
{
|
||||
Xbox,
|
||||
PlayStation
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(ETimeOfDayTransition)
|
||||
{
|
||||
{ "Xbox", ETimeOfDayTransition::Xbox },
|
||||
{ "PlayStation", ETimeOfDayTransition::PlayStation }
|
||||
};
|
||||
|
||||
enum class EControllerIcons : uint32_t
|
||||
{
|
||||
Auto,
|
||||
Xbox,
|
||||
PlayStation
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EControllerIcons)
|
||||
{
|
||||
{ "Auto", EControllerIcons::Auto },
|
||||
{ "Xbox", EControllerIcons::Xbox },
|
||||
{ "PlayStation", EControllerIcons::PlayStation }
|
||||
};
|
||||
|
||||
enum class EVoiceLanguage : uint32_t
|
||||
{
|
||||
English,
|
||||
Japanese
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EVoiceLanguage)
|
||||
{
|
||||
{ "English", EVoiceLanguage::English },
|
||||
{ "Japanese", EVoiceLanguage::Japanese }
|
||||
};
|
||||
|
||||
enum class EGraphicsAPI : uint32_t
|
||||
{
|
||||
#ifdef SWA_D3D12
|
||||
D3D12,
|
||||
#endif
|
||||
Vulkan
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EGraphicsAPI)
|
||||
{
|
||||
#ifdef SWA_D3D12
|
||||
{ "D3D12", EGraphicsAPI::D3D12 },
|
||||
#endif
|
||||
{ "Vulkan", EGraphicsAPI::Vulkan }
|
||||
};
|
||||
|
||||
enum class EWindowState : uint32_t
|
||||
{
|
||||
Normal,
|
||||
Maximised
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EWindowState)
|
||||
{
|
||||
{ "Normal", EWindowState::Normal },
|
||||
{ "Maximised", EWindowState::Maximised },
|
||||
{ "Maximized", EWindowState::Maximised }
|
||||
};
|
||||
|
||||
enum class EAspectRatio : uint32_t
|
||||
{
|
||||
Auto,
|
||||
Square,
|
||||
Widescreen
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EAspectRatio)
|
||||
{
|
||||
{ "Auto", EAspectRatio::Auto },
|
||||
{ "4:3", EAspectRatio::Square },
|
||||
{ "16:9", EAspectRatio::Widescreen }
|
||||
};
|
||||
|
||||
enum class ETripleBuffering : uint32_t
|
||||
{
|
||||
Auto,
|
||||
On,
|
||||
Off
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(ETripleBuffering)
|
||||
{
|
||||
{ "Auto", ETripleBuffering::Auto },
|
||||
{ "On", ETripleBuffering::On },
|
||||
{ "Off", ETripleBuffering::Off }
|
||||
};
|
||||
|
||||
enum class EAntiAliasing : uint32_t
|
||||
{
|
||||
None = 0,
|
||||
MSAA2x = 2,
|
||||
MSAA4x = 4,
|
||||
MSAA8x = 8
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EAntiAliasing)
|
||||
{
|
||||
{ "None", EAntiAliasing::None },
|
||||
{ "2x MSAA", EAntiAliasing::MSAA2x },
|
||||
{ "4x MSAA", EAntiAliasing::MSAA4x },
|
||||
{ "8x MSAA", EAntiAliasing::MSAA8x }
|
||||
};
|
||||
|
||||
enum class EShadowResolution : int32_t
|
||||
{
|
||||
Original = -1,
|
||||
x512 = 512,
|
||||
x1024 = 1024,
|
||||
x2048 = 2048,
|
||||
x4096 = 4096,
|
||||
x8192 = 8192
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EShadowResolution)
|
||||
{
|
||||
{ "Original", EShadowResolution::Original },
|
||||
{ "512", EShadowResolution::x512 },
|
||||
{ "1024", EShadowResolution::x1024 },
|
||||
{ "2048", EShadowResolution::x2048 },
|
||||
{ "4096", EShadowResolution::x4096 },
|
||||
{ "8192", EShadowResolution::x8192 },
|
||||
};
|
||||
|
||||
enum class EGITextureFiltering : uint32_t
|
||||
{
|
||||
Bilinear,
|
||||
Bicubic
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EGITextureFiltering)
|
||||
{
|
||||
{ "Bilinear", EGITextureFiltering::Bilinear },
|
||||
{ "Bicubic", EGITextureFiltering::Bicubic }
|
||||
};
|
||||
|
||||
enum class EDepthOfFieldQuality : uint32_t
|
||||
{
|
||||
Auto,
|
||||
Low,
|
||||
Medium,
|
||||
High,
|
||||
Ultra
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EDepthOfFieldQuality)
|
||||
{
|
||||
{ "Auto", EDepthOfFieldQuality::Auto },
|
||||
{ "Low", EDepthOfFieldQuality::Low },
|
||||
{ "Medium", EDepthOfFieldQuality::Medium },
|
||||
{ "High", EDepthOfFieldQuality::High },
|
||||
{ "Ultra", EDepthOfFieldQuality::Ultra }
|
||||
};
|
||||
|
||||
enum class EMotionBlur : uint32_t
|
||||
{
|
||||
Off,
|
||||
Original,
|
||||
Enhanced
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EMotionBlur)
|
||||
{
|
||||
{ "Off", EMotionBlur::Off },
|
||||
{ "Original", EMotionBlur::Original },
|
||||
{ "Enhanced", EMotionBlur::Enhanced }
|
||||
};
|
||||
|
||||
enum class EMovieScaleMode : uint32_t
|
||||
{
|
||||
Stretch,
|
||||
Fit,
|
||||
Fill
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EMovieScaleMode)
|
||||
{
|
||||
{ "Stretch", EMovieScaleMode::Stretch },
|
||||
{ "Fit", EMovieScaleMode::Fit },
|
||||
{ "Fill", EMovieScaleMode::Fill }
|
||||
};
|
||||
|
||||
enum class EUIScaleMode : uint32_t
|
||||
{
|
||||
Stretch,
|
||||
Edge,
|
||||
Centre
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EUIScaleMode)
|
||||
{
|
||||
{ "Stretch", EUIScaleMode::Stretch },
|
||||
{ "Edge", EUIScaleMode::Edge },
|
||||
{ "Centre", EUIScaleMode::Centre },
|
||||
{ "Center", EUIScaleMode::Centre }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ConfigDef final : public IConfigDef
|
||||
{
|
||||
public:
|
||||
std::string Section{};
|
||||
std::string Name{};
|
||||
CONFIG_LOCALE* Locale{};
|
||||
T DefaultValue{};
|
||||
T Value{ DefaultValue };
|
||||
std::unordered_map<std::string, T>* EnumTemplate;
|
||||
std::map<T, std::string> EnumTemplateReverse{};
|
||||
CONFIG_ENUM_LOCALE(T)* EnumLocale{};
|
||||
std::function<void(ConfigDef<T>*)> Callback;
|
||||
|
||||
// CONFIG_DEFINE
|
||||
ConfigDef(std::string section, std::string name, T defaultValue) : Section(section), Name(name), DefaultValue(defaultValue)
|
||||
{
|
||||
g_configDefinitions.emplace_back(this);
|
||||
}
|
||||
|
||||
// CONFIG_DEFINE_LOCALISED
|
||||
ConfigDef(std::string section, std::string name, CONFIG_LOCALE* nameLocale, T defaultValue) : Section(section), Name(name), Locale(nameLocale), DefaultValue(defaultValue)
|
||||
{
|
||||
g_configDefinitions.emplace_back(this);
|
||||
}
|
||||
|
||||
// CONFIG_DEFINE_ENUM
|
||||
ConfigDef(std::string section, std::string name, T defaultValue, std::unordered_map<std::string, T>* enumTemplate) : Section(section), Name(name), DefaultValue(defaultValue), EnumTemplate(enumTemplate)
|
||||
{
|
||||
for (const auto& pair : *EnumTemplate)
|
||||
EnumTemplateReverse[pair.second] = pair.first;
|
||||
|
||||
g_configDefinitions.emplace_back(this);
|
||||
}
|
||||
|
||||
// CONFIG_DEFINE_ENUM_LOCALISED
|
||||
ConfigDef(std::string section, std::string name, CONFIG_LOCALE* nameLocale, T defaultValue, std::unordered_map<std::string, T>* enumTemplate, CONFIG_ENUM_LOCALE(T)* enumLocale) : Section(section), Name(name), Locale(nameLocale), DefaultValue(defaultValue), EnumTemplate(enumTemplate), EnumLocale(enumLocale)
|
||||
{
|
||||
for (const auto& pair : *EnumTemplate)
|
||||
EnumTemplateReverse[pair.second] = pair.first;
|
||||
|
||||
g_configDefinitions.emplace_back(this);
|
||||
}
|
||||
|
||||
// CONFIG_DEFINE_CALLBACK
|
||||
ConfigDef(std::string section, std::string name, T defaultValue, std::function<void(ConfigDef<T>*)> callback) : Section(section), Name(name), DefaultValue(defaultValue), Callback(callback)
|
||||
{
|
||||
g_configDefinitions.emplace_back(this);
|
||||
}
|
||||
|
||||
void ReadValue(toml::v3::ex::parse_result& toml) override
|
||||
{
|
||||
if (auto pSection = toml[Section].as_table())
|
||||
{
|
||||
const auto& section = *pSection;
|
||||
|
||||
if constexpr (std::is_same<T, std::string>::value)
|
||||
{
|
||||
Value = section[Name].value_or<std::string>(DefaultValue);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<T>)
|
||||
{
|
||||
std::string value = section[Name].value_or(std::string());
|
||||
auto it = EnumTemplate->find(value);
|
||||
if (it != EnumTemplate->end())
|
||||
{
|
||||
Value = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = DefaultValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = section[Name].value_or(DefaultValue);
|
||||
}
|
||||
|
||||
if (Callback)
|
||||
Callback(this);
|
||||
}
|
||||
}
|
||||
|
||||
void MakeDefault() override
|
||||
{
|
||||
Value = DefaultValue;
|
||||
}
|
||||
|
||||
std::string_view GetSection() const override
|
||||
{
|
||||
return Section;
|
||||
}
|
||||
|
||||
std::string_view GetName() const override
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
std::string GetNameLocalised(ELanguage language) const override
|
||||
{
|
||||
if (!Locale)
|
||||
return Name;
|
||||
|
||||
if (!Locale->count(language))
|
||||
{
|
||||
if (Locale->count(ELanguage::English))
|
||||
{
|
||||
return std::get<0>(Locale->at(ELanguage::English));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
return std::get<0>(Locale->at(language));
|
||||
}
|
||||
|
||||
std::string GetDescription(ELanguage language) const override
|
||||
{
|
||||
if (!Locale)
|
||||
return "";
|
||||
|
||||
if (!Locale->count(language))
|
||||
{
|
||||
if (Locale->count(ELanguage::English))
|
||||
{
|
||||
return std::get<1>(Locale->at(ELanguage::English));
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return std::get<1>(Locale->at(language));
|
||||
}
|
||||
|
||||
bool IsDefaultValue() const override
|
||||
{
|
||||
return Value == DefaultValue;
|
||||
}
|
||||
|
||||
const void* GetValue() const override
|
||||
{
|
||||
return &Value;
|
||||
}
|
||||
|
||||
std::string GetValueLocalised(ELanguage language) const override
|
||||
{
|
||||
CONFIG_ENUM_LOCALE(T)* locale = nullptr;
|
||||
|
||||
if constexpr (std::is_enum_v<T>)
|
||||
{
|
||||
locale = EnumLocale;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, bool>)
|
||||
{
|
||||
return Value
|
||||
? Localise("Common_On")
|
||||
: Localise("Common_Off");
|
||||
}
|
||||
|
||||
if (!locale)
|
||||
return ToString(false);
|
||||
|
||||
if (!locale->count(language))
|
||||
{
|
||||
if (locale->count(ELanguage::English))
|
||||
{
|
||||
language = ELanguage::English;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToString(false);
|
||||
}
|
||||
}
|
||||
|
||||
auto strings = locale->at(language);
|
||||
|
||||
if (!strings.count(Value))
|
||||
return ToString(false);
|
||||
|
||||
return std::get<0>(strings.at(Value));
|
||||
}
|
||||
|
||||
std::string GetValueDescription(ELanguage language) const override
|
||||
{
|
||||
CONFIG_ENUM_LOCALE(T)* locale = nullptr;
|
||||
|
||||
if constexpr (std::is_enum_v<T>)
|
||||
{
|
||||
locale = EnumLocale;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, bool>)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!locale)
|
||||
return "";
|
||||
|
||||
if (!locale->count(language))
|
||||
{
|
||||
if (locale->count(ELanguage::English))
|
||||
{
|
||||
language = ELanguage::English;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
auto strings = locale->at(language);
|
||||
|
||||
if (!strings.count(Value))
|
||||
return "";
|
||||
|
||||
return std::get<1>(strings.at(Value));
|
||||
}
|
||||
|
||||
std::string GetDefinition(bool withSection = false) const override
|
||||
{
|
||||
std::string result;
|
||||
|
||||
if (withSection)
|
||||
result += "[" + Section + "]\n";
|
||||
|
||||
result += Name + " = " + ToString();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ToString(bool strWithQuotes = true) const override
|
||||
{
|
||||
std::string result = "N/A";
|
||||
|
||||
if constexpr (std::is_same_v<T, std::string>)
|
||||
{
|
||||
result = fmt::format("{}", Value);
|
||||
|
||||
if (strWithQuotes)
|
||||
result = fmt::format("\"{}\"", result);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<T>)
|
||||
{
|
||||
auto it = EnumTemplateReverse.find(Value);
|
||||
|
||||
if (it != EnumTemplateReverse.end())
|
||||
result = fmt::format("{}", it->second);
|
||||
|
||||
if (strWithQuotes)
|
||||
result = fmt::format("\"{}\"", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = fmt::format("{}", Value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void GetLocaleStrings(std::vector<std::string_view>& localeStrings) const override
|
||||
{
|
||||
if (Locale != nullptr)
|
||||
{
|
||||
for (auto& [language, nameAndDesc] : *Locale)
|
||||
{
|
||||
localeStrings.push_back(std::get<0>(nameAndDesc));
|
||||
localeStrings.push_back(std::get<1>(nameAndDesc));
|
||||
}
|
||||
}
|
||||
|
||||
if (EnumLocale != nullptr)
|
||||
{
|
||||
for (auto& [language, locale] : *EnumLocale)
|
||||
{
|
||||
for (auto& [value, nameAndDesc] : locale)
|
||||
{
|
||||
localeStrings.push_back(std::get<0>(nameAndDesc));
|
||||
localeStrings.push_back(std::get<1>(nameAndDesc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigDef& operator=(const ConfigDef& other)
|
||||
{
|
||||
if (this != &other)
|
||||
Value = other.Value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
void operator=(const T& other)
|
||||
{
|
||||
Value = other;
|
||||
}
|
||||
};
|
||||
|
||||
class Config
|
||||
{
|
||||
public:
|
||||
static inline std::vector<IConfigDef*> Definitions{};
|
||||
|
||||
CONFIG_DEFINE_ENUM_LOCALISED("System", ELanguage, Language, ELanguage::English);
|
||||
CONFIG_DEFINE_LOCALISED("System", bool, Hints, true);
|
||||
CONFIG_DEFINE_LOCALISED("System", bool, ControlTutorial, true);
|
||||
|
|
|
|||
|
|
@ -1,193 +0,0 @@
|
|||
#include "config.h"
|
||||
#include "config_detail.h"
|
||||
#include <locale/locale.h>
|
||||
|
||||
// CONFIG_DEFINE
|
||||
template<typename T>
|
||||
ConfigDef<T>::ConfigDef(std::string section, std::string name, T defaultValue) : Section(section), Name(name), DefaultValue(defaultValue)
|
||||
{
|
||||
Config::Definitions.emplace_back(this);
|
||||
}
|
||||
|
||||
// CONFIG_DEFINE_LOCALISED
|
||||
template<typename T>
|
||||
ConfigDef<T>::ConfigDef(std::string section, std::string name, CONFIG_LOCALE* locale, T defaultValue)
|
||||
: Section(section), Name(name), Locale(locale), DefaultValue(defaultValue)
|
||||
{
|
||||
Config::Definitions.emplace_back(this);
|
||||
}
|
||||
|
||||
// CONFIG_DEFINE_ENUM
|
||||
template<typename T>
|
||||
ConfigDef<T>::ConfigDef(std::string section, std::string name, T defaultValue, std::unordered_map<std::string, T>* enumTemplate)
|
||||
: Section(section), Name(name), DefaultValue(defaultValue), EnumTemplate(enumTemplate)
|
||||
{
|
||||
for (const auto& pair : *EnumTemplate)
|
||||
EnumTemplateReverse[pair.second] = pair.first;
|
||||
|
||||
Config::Definitions.emplace_back(this);
|
||||
}
|
||||
|
||||
// CONFIG_DEFINE_ENUM_LOCALISED
|
||||
template<typename T>
|
||||
ConfigDef<T>::ConfigDef(std::string section, std::string name, CONFIG_LOCALE* locale, T defaultValue, std::unordered_map<std::string, T>* enumTemplate, CONFIG_ENUM_LOCALE(T)* enumLocale)
|
||||
: Section(section), Name(name), Locale(locale), DefaultValue(defaultValue), EnumTemplate(enumTemplate), EnumLocale(enumLocale)
|
||||
{
|
||||
for (const auto& pair : *EnumTemplate)
|
||||
EnumTemplateReverse[pair.second] = pair.first;
|
||||
|
||||
Config::Definitions.emplace_back(this);
|
||||
}
|
||||
|
||||
// CONFIG_DEFINE_CALLBACK
|
||||
template<typename T>
|
||||
ConfigDef<T>::ConfigDef(std::string section, std::string name, T defaultValue, std::function<void(ConfigDef<T>*)> callback)
|
||||
: Section(section), Name(name), DefaultValue(defaultValue), Callback(callback)
|
||||
{
|
||||
Config::Definitions.emplace_back(this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string ConfigDef<T>::GetNameLocalised() const
|
||||
{
|
||||
if (!Locale)
|
||||
return Name;
|
||||
|
||||
if (!Locale->count(Config::Language))
|
||||
{
|
||||
if (Locale->count(ELanguage::English))
|
||||
{
|
||||
return std::get<0>(Locale->at(ELanguage::English));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
return std::get<0>(Locale->at(Config::Language));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string ConfigDef<T>::GetDescription() const
|
||||
{
|
||||
if (!Locale)
|
||||
return "";
|
||||
|
||||
if (!Locale->count(Config::Language))
|
||||
{
|
||||
if (Locale->count(ELanguage::English))
|
||||
{
|
||||
return std::get<1>(Locale->at(ELanguage::English));
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
return std::get<1>(Locale->at(Config::Language));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string ConfigDef<T>::GetValueLocalised() const
|
||||
{
|
||||
auto language = Config::Language;
|
||||
CONFIG_ENUM_LOCALE(T)* locale = nullptr;
|
||||
|
||||
if constexpr (std::is_enum_v<T>)
|
||||
{
|
||||
locale = EnumLocale;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, bool>)
|
||||
{
|
||||
return Value
|
||||
? Localise("Common_On")
|
||||
: Localise("Common_Off");
|
||||
}
|
||||
|
||||
if (!locale)
|
||||
return ToString(false);
|
||||
|
||||
if (!locale->count(language))
|
||||
{
|
||||
if (locale->count(ELanguage::English))
|
||||
{
|
||||
language = ELanguage::English;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ToString(false);
|
||||
}
|
||||
}
|
||||
|
||||
auto strings = locale->at(language);
|
||||
|
||||
if (!strings.count(Value))
|
||||
return ToString(false);
|
||||
|
||||
return std::get<0>(strings.at(Value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string ConfigDef<T>::GetValueDescription() const
|
||||
{
|
||||
auto language = Config::Language;
|
||||
CONFIG_ENUM_LOCALE(T)* locale = nullptr;
|
||||
|
||||
if constexpr (std::is_enum_v<T>)
|
||||
{
|
||||
locale = EnumLocale;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, bool>)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!locale)
|
||||
return "";
|
||||
|
||||
if (!locale->count(language))
|
||||
{
|
||||
if (locale->count(ELanguage::English))
|
||||
{
|
||||
language = ELanguage::English;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
auto strings = locale->at(language);
|
||||
|
||||
if (!strings.count(Value))
|
||||
return "";
|
||||
|
||||
return std::get<1>(strings.at(Value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void ConfigDef<T>::GetLocaleStrings(std::vector<std::string_view>& localeStrings) const
|
||||
{
|
||||
if (Locale != nullptr)
|
||||
{
|
||||
for (auto& [language, nameAndDesc] : *Locale)
|
||||
{
|
||||
localeStrings.push_back(std::get<0>(nameAndDesc));
|
||||
localeStrings.push_back(std::get<1>(nameAndDesc));
|
||||
}
|
||||
}
|
||||
|
||||
if (EnumLocale != nullptr)
|
||||
{
|
||||
for (auto& [language, locale] : *EnumLocale)
|
||||
{
|
||||
for (auto& [value, nameAndDesc] : locale)
|
||||
{
|
||||
localeStrings.push_back(std::get<0>(nameAndDesc));
|
||||
localeStrings.push_back(std::get<1>(nameAndDesc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,440 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#define CONFIG_LOCALE std::unordered_map<ELanguage, std::tuple<std::string, std::string>>
|
||||
#define CONFIG_ENUM_LOCALE(type) std::unordered_map<ELanguage, std::unordered_map<type, std::tuple<std::string, std::string>>>
|
||||
|
||||
#define CONFIG_DEFINE(section, type, name, defaultValue) \
|
||||
static inline ConfigDef<type> name{section, #name, defaultValue};
|
||||
|
||||
#define CONFIG_DEFINE_LOCALISED(section, type, name, defaultValue) \
|
||||
static CONFIG_LOCALE g_##name##_locale; \
|
||||
static inline ConfigDef<type> name{section, #name, &g_##name##_locale, defaultValue};
|
||||
|
||||
#define CONFIG_DEFINE_ENUM(section, type, name, defaultValue) \
|
||||
static inline ConfigDef<type> name{section, #name, defaultValue, &g_##type##_template};
|
||||
|
||||
#define CONFIG_DEFINE_ENUM_LOCALISED(section, type, name, defaultValue) \
|
||||
static CONFIG_LOCALE g_##name##_locale; \
|
||||
static CONFIG_ENUM_LOCALE(type) g_##type##_locale; \
|
||||
static inline ConfigDef<type> name{section, #name, &g_##name##_locale, defaultValue, &g_##type##_template, &g_##type##_locale};
|
||||
|
||||
#define CONFIG_DEFINE_CALLBACK(section, type, name, defaultValue, readCallback) \
|
||||
static CONFIG_LOCALE g_##name##_locale; \
|
||||
static inline ConfigDef<type> name{section, #name, defaultValue, [](ConfigDef<type>* def) readCallback};
|
||||
|
||||
#define CONFIG_DEFINE_ENUM_TEMPLATE(type) \
|
||||
inline std::unordered_map<std::string, type> g_##type##_template =
|
||||
|
||||
#define WINDOWPOS_CENTRED 0x2FFF0000
|
||||
|
||||
enum class ELanguage : uint32_t
|
||||
{
|
||||
English = 1,
|
||||
Japanese,
|
||||
German,
|
||||
French,
|
||||
Spanish,
|
||||
Italian
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(ELanguage)
|
||||
{
|
||||
{ "English", ELanguage::English },
|
||||
{ "Japanese", ELanguage::Japanese },
|
||||
{ "German", ELanguage::German },
|
||||
{ "French", ELanguage::French },
|
||||
{ "Spanish", ELanguage::Spanish },
|
||||
{ "Italian", ELanguage::Italian }
|
||||
};
|
||||
|
||||
enum class EUnleashGaugeBehaviour : uint32_t
|
||||
{
|
||||
Original,
|
||||
Revised
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EUnleashGaugeBehaviour)
|
||||
{
|
||||
{ "Original", EUnleashGaugeBehaviour::Original },
|
||||
{ "Revised", EUnleashGaugeBehaviour::Revised }
|
||||
};
|
||||
|
||||
enum class ETimeOfDayTransition : uint32_t
|
||||
{
|
||||
Xbox,
|
||||
PlayStation
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(ETimeOfDayTransition)
|
||||
{
|
||||
{ "Xbox", ETimeOfDayTransition::Xbox },
|
||||
{ "PlayStation", ETimeOfDayTransition::PlayStation }
|
||||
};
|
||||
|
||||
enum class EControllerIcons : uint32_t
|
||||
{
|
||||
Auto,
|
||||
Xbox,
|
||||
PlayStation
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EControllerIcons)
|
||||
{
|
||||
{ "Auto", EControllerIcons::Auto },
|
||||
{ "Xbox", EControllerIcons::Xbox },
|
||||
{ "PlayStation", EControllerIcons::PlayStation }
|
||||
};
|
||||
|
||||
enum class EVoiceLanguage : uint32_t
|
||||
{
|
||||
English,
|
||||
Japanese
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EVoiceLanguage)
|
||||
{
|
||||
{ "English", EVoiceLanguage::English },
|
||||
{ "Japanese", EVoiceLanguage::Japanese }
|
||||
};
|
||||
|
||||
enum class EGraphicsAPI : uint32_t
|
||||
{
|
||||
#ifdef SWA_D3D12
|
||||
D3D12,
|
||||
#endif
|
||||
Vulkan
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EGraphicsAPI)
|
||||
{
|
||||
#ifdef SWA_D3D12
|
||||
{ "D3D12", EGraphicsAPI::D3D12 },
|
||||
#endif
|
||||
{ "Vulkan", EGraphicsAPI::Vulkan }
|
||||
};
|
||||
|
||||
enum class EWindowState : uint32_t
|
||||
{
|
||||
Normal,
|
||||
Maximised
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EWindowState)
|
||||
{
|
||||
{ "Normal", EWindowState::Normal },
|
||||
{ "Maximised", EWindowState::Maximised },
|
||||
{ "Maximized", EWindowState::Maximised }
|
||||
};
|
||||
|
||||
enum class EAspectRatio : uint32_t
|
||||
{
|
||||
Auto,
|
||||
Square,
|
||||
Widescreen
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EAspectRatio)
|
||||
{
|
||||
{ "Auto", EAspectRatio::Auto },
|
||||
{ "4:3", EAspectRatio::Square },
|
||||
{ "16:9", EAspectRatio::Widescreen }
|
||||
};
|
||||
|
||||
enum class ETripleBuffering : uint32_t
|
||||
{
|
||||
Auto,
|
||||
On,
|
||||
Off
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(ETripleBuffering)
|
||||
{
|
||||
{ "Auto", ETripleBuffering::Auto },
|
||||
{ "On", ETripleBuffering::On },
|
||||
{ "Off", ETripleBuffering::Off }
|
||||
};
|
||||
|
||||
enum class EAntiAliasing : uint32_t
|
||||
{
|
||||
None = 0,
|
||||
MSAA2x = 2,
|
||||
MSAA4x = 4,
|
||||
MSAA8x = 8
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EAntiAliasing)
|
||||
{
|
||||
{ "None", EAntiAliasing::None },
|
||||
{ "2x MSAA", EAntiAliasing::MSAA2x },
|
||||
{ "4x MSAA", EAntiAliasing::MSAA4x },
|
||||
{ "8x MSAA", EAntiAliasing::MSAA8x }
|
||||
};
|
||||
|
||||
enum class EShadowResolution : int32_t
|
||||
{
|
||||
Original = -1,
|
||||
x512 = 512,
|
||||
x1024 = 1024,
|
||||
x2048 = 2048,
|
||||
x4096 = 4096,
|
||||
x8192 = 8192
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EShadowResolution)
|
||||
{
|
||||
{ "Original", EShadowResolution::Original },
|
||||
{ "512", EShadowResolution::x512 },
|
||||
{ "1024", EShadowResolution::x1024 },
|
||||
{ "2048", EShadowResolution::x2048 },
|
||||
{ "4096", EShadowResolution::x4096 },
|
||||
{ "8192", EShadowResolution::x8192 },
|
||||
};
|
||||
|
||||
enum class EGITextureFiltering : uint32_t
|
||||
{
|
||||
Bilinear,
|
||||
Bicubic
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EGITextureFiltering)
|
||||
{
|
||||
{ "Bilinear", EGITextureFiltering::Bilinear },
|
||||
{ "Bicubic", EGITextureFiltering::Bicubic }
|
||||
};
|
||||
|
||||
enum class EDepthOfFieldQuality : uint32_t
|
||||
{
|
||||
Auto,
|
||||
Low,
|
||||
Medium,
|
||||
High,
|
||||
Ultra
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EDepthOfFieldQuality)
|
||||
{
|
||||
{ "Auto", EDepthOfFieldQuality::Auto },
|
||||
{ "Low", EDepthOfFieldQuality::Low },
|
||||
{ "Medium", EDepthOfFieldQuality::Medium },
|
||||
{ "High", EDepthOfFieldQuality::High },
|
||||
{ "Ultra", EDepthOfFieldQuality::Ultra }
|
||||
};
|
||||
|
||||
enum class EMotionBlur : uint32_t
|
||||
{
|
||||
Off,
|
||||
Original,
|
||||
Enhanced
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EMotionBlur)
|
||||
{
|
||||
{ "Off", EMotionBlur::Off },
|
||||
{ "Original", EMotionBlur::Original },
|
||||
{ "Enhanced", EMotionBlur::Enhanced }
|
||||
};
|
||||
|
||||
enum class EMovieScaleMode : uint32_t
|
||||
{
|
||||
Stretch,
|
||||
Fit,
|
||||
Fill
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EMovieScaleMode)
|
||||
{
|
||||
{ "Stretch", EMovieScaleMode::Stretch },
|
||||
{ "Fit", EMovieScaleMode::Fit },
|
||||
{ "Fill", EMovieScaleMode::Fill }
|
||||
};
|
||||
|
||||
enum class EUIScaleMode : uint32_t
|
||||
{
|
||||
Stretch,
|
||||
Edge,
|
||||
Centre
|
||||
};
|
||||
|
||||
CONFIG_DEFINE_ENUM_TEMPLATE(EUIScaleMode)
|
||||
{
|
||||
{ "Stretch", EUIScaleMode::Stretch },
|
||||
{ "Edge", EUIScaleMode::Edge },
|
||||
{ "Centre", EUIScaleMode::Centre },
|
||||
{ "Center", EUIScaleMode::Centre }
|
||||
};
|
||||
|
||||
class IConfigDef
|
||||
{
|
||||
public:
|
||||
virtual ~IConfigDef() = default;
|
||||
virtual void ReadValue(toml::v3::ex::parse_result& toml) = 0;
|
||||
virtual void MakeDefault() = 0;
|
||||
virtual std::string_view GetSection() const = 0;
|
||||
virtual std::string_view GetName() const = 0;
|
||||
virtual std::string GetNameLocalised() const = 0;
|
||||
virtual std::string GetDescription() const = 0;
|
||||
virtual bool IsDefaultValue() const = 0;
|
||||
virtual const void* GetValue() const = 0;
|
||||
virtual std::string GetValueLocalised() const = 0;
|
||||
virtual std::string GetValueDescription() const = 0;
|
||||
virtual std::string GetDefinition(bool withSection = false) const = 0;
|
||||
virtual std::string ToString(bool strWithQuotes = true) const = 0;
|
||||
virtual void GetLocaleStrings(std::vector<std::string_view>& localeStrings) const = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class ConfigDef final : public IConfigDef
|
||||
{
|
||||
public:
|
||||
std::string Section{};
|
||||
std::string Name{};
|
||||
CONFIG_LOCALE* Locale{};
|
||||
T DefaultValue{};
|
||||
T Value{ DefaultValue };
|
||||
std::unordered_map<std::string, T>* EnumTemplate;
|
||||
std::map<T, std::string> EnumTemplateReverse{};
|
||||
CONFIG_ENUM_LOCALE(T)* EnumLocale{};
|
||||
std::function<void(ConfigDef<T>*)> Callback;
|
||||
|
||||
// CONFIG_DEFINE
|
||||
ConfigDef(std::string section, std::string name, T defaultValue);
|
||||
|
||||
// CONFIG_DEFINE_LOCALISED
|
||||
ConfigDef(std::string section, std::string name, CONFIG_LOCALE* nameLocale, T defaultValue);
|
||||
|
||||
// CONFIG_DEFINE_ENUM
|
||||
ConfigDef(std::string section, std::string name, T defaultValue, std::unordered_map<std::string, T>* enumTemplate);
|
||||
|
||||
// CONFIG_DEFINE_ENUM_LOCALISED
|
||||
ConfigDef(std::string section, std::string name, CONFIG_LOCALE* nameLocale, T defaultValue, std::unordered_map<std::string, T>* enumTemplate, CONFIG_ENUM_LOCALE(T)* enumLocale);
|
||||
|
||||
// CONFIG_DEFINE_CALLBACK
|
||||
ConfigDef(std::string section, std::string name, T defaultValue, std::function<void(ConfigDef<T>*)> callback);
|
||||
|
||||
void ReadValue(toml::v3::ex::parse_result& toml) override
|
||||
{
|
||||
if (auto pSection = toml[Section].as_table())
|
||||
{
|
||||
const auto& section = *pSection;
|
||||
|
||||
if constexpr (std::is_same<T, std::string>::value)
|
||||
{
|
||||
Value = section[Name].value_or<std::string>(DefaultValue);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<T>)
|
||||
{
|
||||
std::string value = section[Name].value_or(std::string());
|
||||
auto it = EnumTemplate->find(value);
|
||||
if (it != EnumTemplate->end())
|
||||
{
|
||||
Value = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = DefaultValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Value = section[Name].value_or(DefaultValue);
|
||||
}
|
||||
|
||||
if (Callback)
|
||||
Callback(this);
|
||||
}
|
||||
}
|
||||
|
||||
void MakeDefault() override
|
||||
{
|
||||
Value = DefaultValue;
|
||||
}
|
||||
|
||||
std::string_view GetSection() const override
|
||||
{
|
||||
return Section;
|
||||
}
|
||||
|
||||
std::string_view GetName() const override
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
std::string GetNameLocalised() const override;
|
||||
|
||||
std::string GetDescription() const override;
|
||||
|
||||
bool IsDefaultValue() const override
|
||||
{
|
||||
return Value == DefaultValue;
|
||||
}
|
||||
|
||||
const void* GetValue() const override
|
||||
{
|
||||
return &Value;
|
||||
}
|
||||
|
||||
std::string GetValueLocalised() const override;
|
||||
|
||||
std::string GetValueDescription() const override;
|
||||
|
||||
std::string GetDefinition(bool withSection = false) const override
|
||||
{
|
||||
std::string result;
|
||||
|
||||
if (withSection)
|
||||
result += "[" + Section + "]\n";
|
||||
|
||||
result += Name + " = " + ToString();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ToString(bool strWithQuotes = true) const override
|
||||
{
|
||||
std::string result = "N/A";
|
||||
|
||||
if constexpr (std::is_same_v<T, std::string>)
|
||||
{
|
||||
result = fmt::format("{}", Value);
|
||||
|
||||
if (strWithQuotes)
|
||||
result = fmt::format("\"{}\"", result);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<T>)
|
||||
{
|
||||
auto it = EnumTemplateReverse.find(Value);
|
||||
|
||||
if (it != EnumTemplateReverse.end())
|
||||
result = fmt::format("{}", it->second);
|
||||
|
||||
if (strWithQuotes)
|
||||
result = fmt::format("\"{}\"", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = fmt::format("{}", Value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void GetLocaleStrings(std::vector<std::string_view>& localeStrings) const override;
|
||||
|
||||
ConfigDef& operator=(const ConfigDef& other)
|
||||
{
|
||||
if (this != &other)
|
||||
Value = other.Value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
void operator=(const T& other)
|
||||
{
|
||||
Value = other;
|
||||
}
|
||||
};
|
||||
|
|
@ -30,13 +30,12 @@ inline std::filesystem::path GetUserPath()
|
|||
if (homeDir != nullptr)
|
||||
{
|
||||
// Prefer to store in the .config directory if it exists. Use the home directory otherwise.
|
||||
const std::string dirName = "." USER_DIRECTORY;
|
||||
std::filesystem::path homePath = homeDir;
|
||||
std::filesystem::path configPath = homePath / ".config";
|
||||
if (std::filesystem::exists(configPath))
|
||||
userPath = configPath / dirName;
|
||||
userPath = configPath / USER_DIRECTORY;
|
||||
else
|
||||
userPath = homePath / dirName;
|
||||
userPath = homePath / ("." USER_DIRECTORY);
|
||||
}
|
||||
#else
|
||||
static_assert(false, "GetUserPath() not implemented for this platform.");
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
project("UnleashedRecompLib")
|
||||
|
||||
add_compile_options(
|
||||
"/fp:strict"
|
||||
"-march=sandybridge"
|
||||
"-fno-strict-aliasing"
|
||||
-march=sandybridge
|
||||
-mlzcnt
|
||||
-fno-strict-aliasing
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
add_compile_options(/fp:strict)
|
||||
else()
|
||||
add_compile_options(-ffp-model=strict)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(PowerRecomp PRIVATE CONFIG_FILE_PATH=\"${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml\")
|
||||
|
||||
set(SWA_PPC_RECOMPILED_SOURCES
|
||||
|
|
@ -21,7 +27,7 @@ endforeach()
|
|||
|
||||
add_custom_command(
|
||||
OUTPUT ${SWA_PPC_RECOMPILED_SOURCES}
|
||||
COMMAND PowerRecomp
|
||||
COMMAND $<TARGET_FILE:PowerRecomp>
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex" "${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml"
|
||||
)
|
||||
|
||||
|
|
@ -41,7 +47,7 @@ file(GLOB SHADER_RECOMP_SOURCES
|
|||
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/shader/shader_cache.cpp"
|
||||
COMMAND ShaderRecomp
|
||||
COMMAND $<TARGET_FILE:ShaderRecomp>
|
||||
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/private/shader.ar" ${SHADER_RECOMP_SOURCES} ${SHADER_RECOMP_INCLUDE}
|
||||
)
|
||||
|
||||
|
|
|
|||
8
thirdparty/CMakeLists.txt
vendored
8
thirdparty/CMakeLists.txt
vendored
|
|
@ -3,5 +3,9 @@ set(MSDF_ATLAS_USE_SKIA OFF)
|
|||
set(MSDF_ATLAS_NO_ARTERY_FONT ON)
|
||||
set(MSDFGEN_DISABLE_PNG ON)
|
||||
|
||||
add_subdirectory(${SWA_THIRDPARTY_ROOT}/o1heap)
|
||||
add_subdirectory(${SWA_THIRDPARTY_ROOT}/msdf-atlas-gen)
|
||||
add_subdirectory("${SWA_THIRDPARTY_ROOT}/msdf-atlas-gen")
|
||||
add_subdirectory("${SWA_THIRDPARTY_ROOT}/nativefiledialog-extended")
|
||||
add_subdirectory("${SWA_THIRDPARTY_ROOT}/ogg")
|
||||
add_subdirectory("${SWA_THIRDPARTY_ROOT}/o1heap")
|
||||
add_subdirectory("${SWA_THIRDPARTY_ROOT}/SDL")
|
||||
add_subdirectory("${SWA_THIRDPARTY_ROOT}/vorbis")
|
||||
|
|
|
|||
1
thirdparty/D3D12MemoryAllocator
vendored
Submodule
1
thirdparty/D3D12MemoryAllocator
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit e00c4a7c85cf9c28c6f4a6cc75032736f416410f
|
||||
1
thirdparty/SDL
vendored
Submodule
1
thirdparty/SDL
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 1edaad17218d67b567c149badce9ef0fc67f65fa
|
||||
1
thirdparty/Vulkan-Headers
vendored
Submodule
1
thirdparty/Vulkan-Headers
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 14345dab231912ee9601136e96ca67a6e1f632e7
|
||||
1
thirdparty/VulkanMemoryAllocator
vendored
Submodule
1
thirdparty/VulkanMemoryAllocator
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 1c35ba99ce775f8342d87a83a3f0f696f99c2a39
|
||||
1
thirdparty/concurrentqueue
vendored
Submodule
1
thirdparty/concurrentqueue
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 6dd38b8a1dbaa7863aa907045f32308a56a6ff5d
|
||||
1
thirdparty/imgui
vendored
Submodule
1
thirdparty/imgui
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 8199457a7d9e453f8d3d9cadc14683fb54a858b5
|
||||
1
thirdparty/magic_enum
vendored
Submodule
1
thirdparty/magic_enum
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 1a1824df7ac798177a521eed952720681b0bf482
|
||||
1
thirdparty/nativefiledialog-extended
vendored
Submodule
1
thirdparty/nativefiledialog-extended
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 388549a5badaa7cbd138f5f189f50c67d5bf060c
|
||||
1
thirdparty/ogg
vendored
Submodule
1
thirdparty/ogg
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7cf42ea17aef7bc1b7b21af70724840a96c2e7d0
|
||||
1
thirdparty/stb
vendored
Submodule
1
thirdparty/stb
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 5c205738c191bcb0abc65c4febfa9bd25ff35234
|
||||
1
thirdparty/tiny-AES-c
vendored
Submodule
1
thirdparty/tiny-AES-c
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 23856752fbd139da0b8ca6e471a13d5bcc99a08d
|
||||
1
thirdparty/unordered_dense
vendored
Submodule
1
thirdparty/unordered_dense
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit d911053e390816ecc5dedd5a9d6b4bb5ed92b4c9
|
||||
2
thirdparty/vcpkg
vendored
2
thirdparty/vcpkg
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit 19847ac3d8cad7599e96bd531f9bc1f0ebae6131
|
||||
Subproject commit b322364f06308bdd24823f9d8f03fe0cc86fd46f
|
||||
1
thirdparty/volk
vendored
Submodule
1
thirdparty/volk
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 447e21b5d92ed8d5271b0d39b071f938fcfa875f
|
||||
1
thirdparty/vorbis
vendored
Submodule
1
thirdparty/vorbis
vendored
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 84c023699cdf023a32fa4ded32019f194afcdad0
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 45c00cfec6c2ad141ebf8fce1f5dbcdde2816e94
|
||||
Subproject commit 14b7fd3445857a44ad91b832592cffb069451e4f
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 4b69741e196e0a8aed9d51bbe0cf24019afab08e
|
||||
Subproject commit cf44a5e6fb7c9931888ee4e6506109787141f87e
|
||||
|
|
@ -6,5 +6,4 @@ set(CMAKE_CXX_STANDARD 17)
|
|||
add_executable(bc_diff "bc_diff.cpp")
|
||||
add_compile_definitions(bc_diff PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||
|
||||
find_package(xxHash CONFIG REQUIRED)
|
||||
target_link_libraries(bc_diff PRIVATE xxHash::xxhash)
|
||||
|
|
|
|||
|
|
@ -7,5 +7,4 @@ set(CMAKE_CXX_STANDARD 17)
|
|||
|
||||
add_executable(file_to_c "file_to_c.cpp")
|
||||
|
||||
find_package(zstd CONFIG REQUIRED)
|
||||
target_link_libraries(file_to_c PRIVATE $<IF:$<TARGET_EXISTS:zstd::libzstd_static>,zstd::libzstd_static,zstd::libzstd>)
|
||||
target_link_libraries(file_to_c PRIVATE $<IF:$<TARGET_EXISTS:libzstd_static>,libzstd_static,libzstd_shared>)
|
||||
|
|
|
|||
|
|
@ -110,8 +110,8 @@ int main(int argc, const char** argv) {
|
|||
|
||||
// Write decompressed size.
|
||||
if (!compressed_contents.empty()) {
|
||||
output_c_file << "extern size_t " << array_name << "_uncompressed_size;\n";
|
||||
output_c_file << "size_t " << array_name << "_uncompressed_size = " << contents.size() << ";\n";
|
||||
output_c_file << "extern unsigned long long " << array_name << "_uncompressed_size;\n";
|
||||
output_c_file << "unsigned long long " << array_name << "_uncompressed_size = " << contents.size() << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ int main(int argc, const char** argv) {
|
|||
|
||||
// Write decompressed size.
|
||||
if (!compressed_contents.empty()) {
|
||||
output_h_file << "extern size_t " << array_name << "_uncompressed_size;\n";
|
||||
output_h_file << "extern unsigned long long " << array_name << "_uncompressed_size;\n";
|
||||
}
|
||||
|
||||
output_h_file <<
|
||||
|
|
|
|||
|
|
@ -2,6 +2,4 @@ project("fshasher")
|
|||
|
||||
add_executable(fshasher "fshasher.cpp")
|
||||
|
||||
find_package(xxHash CONFIG REQUIRED)
|
||||
|
||||
target_link_libraries(fshasher PRIVATE xxHash::xxhash)
|
||||
|
|
|
|||
31
vcpkg.json
31
vcpkg.json
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"builtin-baseline": "e63bd09dc0b7204467705c1c7c71d0e2a3f8860b",
|
||||
"builtin-baseline": "b322364f06308bdd24823f9d8f03fe0cc86fd46f",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "directx-headers",
|
||||
|
|
@ -9,34 +9,7 @@
|
|||
"name": "directx12-agility",
|
||||
"platform": "windows"
|
||||
},
|
||||
{
|
||||
"name": "d3d12-memory-allocator",
|
||||
"platform": "windows"
|
||||
},
|
||||
{
|
||||
"name": "pkgconf",
|
||||
"platform": "windows"
|
||||
},
|
||||
{
|
||||
"name": "imgui",
|
||||
"features": [ "sdl2-binding" ]
|
||||
},
|
||||
"directx-dxc",
|
||||
"sdl2",
|
||||
"unordered-dense",
|
||||
"volk",
|
||||
"vulkan-headers",
|
||||
"vulkan-memory-allocator",
|
||||
"xxhash",
|
||||
"tomlplusplus",
|
||||
"zstd",
|
||||
"stb",
|
||||
"concurrentqueue",
|
||||
"tiny-aes-c",
|
||||
"magic-enum",
|
||||
"nativefiledialog-extended",
|
||||
"freetype",
|
||||
"libvorbis",
|
||||
"fmt"
|
||||
"freetype"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue