Merge branch 'shadps4-emu:main' into fontlib

This commit is contained in:
georgemoralis 2025-03-31 15:15:51 +03:00 committed by GitHub
commit f893ab1bc4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
149 changed files with 7318 additions and 9346 deletions

12
.gitmodules vendored
View file

@ -1,15 +1,3 @@
[submodule "externals/cryptopp-cmake"]
path = externals/cryptopp-cmake
url = https://github.com/shadps4-emu/ext-cryptopp-cmake.git
shallow = true
[submodule "externals/cryptopp"]
path = externals/cryptopp
url = https://github.com/shadps4-emu/ext-cryptopp.git
shallow = true
[submodule "externals/cryptoppwin"]
path = externals/cryptoppwin
url = https://github.com/shadps4-emu/ext-cryptoppwin.git
shallow = true
[submodule "externals/zlib-ng"] [submodule "externals/zlib-ng"]
path = externals/zlib-ng path = externals/zlib-ng
url = https://github.com/shadps4-emu/ext-zlib-ng.git url = https://github.com/shadps4-emu/ext-zlib-ng.git

View file

@ -37,8 +37,10 @@ option(ENABLE_UPDATER "Enables the options to updater" ON)
# First, determine whether to use CMAKE_OSX_ARCHITECTURES or CMAKE_SYSTEM_PROCESSOR. # First, determine whether to use CMAKE_OSX_ARCHITECTURES or CMAKE_SYSTEM_PROCESSOR.
if (APPLE AND CMAKE_OSX_ARCHITECTURES) if (APPLE AND CMAKE_OSX_ARCHITECTURES)
set(BASE_ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}") set(BASE_ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
else() elseif (CMAKE_SYSTEM_PROCESSOR)
set(BASE_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}") set(BASE_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
else()
set(BASE_ARCHITECTURE "${CMAKE_HOST_SYSTEM_PROCESSOR}")
endif() endif()
# Next, match common architecture strings down to a known common value. # Next, match common architecture strings down to a known common value.
@ -50,7 +52,12 @@ else()
message(FATAL_ERROR "Unsupported CPU architecture: ${BASE_ARCHITECTURE}") message(FATAL_ERROR "Unsupported CPU architecture: ${BASE_ARCHITECTURE}")
endif() endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64") if (ARCHITECTURE STREQUAL "x86_64")
# Set x86_64 target level to Sandy Bridge to generally match what is supported for PS4 guest code with CPU patches.
add_compile_options(-march=sandybridge)
endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
# Exclude ARM homebrew path to avoid conflicts when cross compiling. # Exclude ARM homebrew path to avoid conflicts when cross compiling.
list(APPEND CMAKE_IGNORE_PREFIX_PATH "/opt/homebrew") list(APPEND CMAKE_IGNORE_PREFIX_PATH "/opt/homebrew")
@ -106,28 +113,74 @@ git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH) git_branch_name(GIT_BRANCH)
string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S") string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S")
message("start git things")
# Try to get the upstream remote and branch # Try to get the upstream remote and branch
message("check for remote and branch")
execute_process( execute_process(
COMMAND git rev-parse --abbrev-ref --symbolic-full-name @{u} COMMAND git rev-parse --abbrev-ref --symbolic-full-name @{u}
OUTPUT_VARIABLE GIT_REMOTE_NAME OUTPUT_VARIABLE GIT_REMOTE_NAME
RESULT_VARIABLE GIT_BRANCH_RESULT RESULT_VARIABLE GIT_REMOTE_RESULT
ERROR_QUIET ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
# If there's no upstream set or the command failed, check remote.pushDefault # If there's no upstream set or the command failed, check remote.pushDefault
if (GIT_BRANCH_RESULT OR GIT_REMOTE_NAME STREQUAL "") if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check default push")
execute_process( execute_process(
COMMAND git config --get remote.pushDefault COMMAND git config --get remote.pushDefault
OUTPUT_VARIABLE GIT_REMOTE_NAME OUTPUT_VARIABLE GIT_REMOTE_NAME
RESULT_VARIABLE GIT_PUSH_DEFAULT_RESULT RESULT_VARIABLE GIT_REMOTE_RESULT
ERROR_QUIET ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
) )
endif()
# If remote.pushDefault is not set or fails, default to origin
if (GIT_PUSH_DEFAULT_RESULT OR GIT_REMOTE_NAME STREQUAL "") # If running in GitHub Actions and the above fails
set(GIT_REMOTE_NAME "origin") if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check github")
set(GIT_REMOTE_NAME "origin")
# Retrieve environment variables
if (DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "")
message("github head ref: $ENV{GITHUB_HEAD_REF}")
set(GITHUB_HEAD_REF "$ENV{GITHUB_HEAD_REF}")
else()
set(GITHUB_HEAD_REF "")
endif()
if (DEFINED ENV{GITHUB_REF} AND NOT "$ENV{GITHUB_REF}" STREQUAL "")
message("github ref: $ENV{GITHUB_REF}")
string(REGEX REPLACE "^refs/[^/]*/" "" GITHUB_BRANCH "$ENV{GITHUB_REF}")
string(REGEX MATCH "refs/pull/([0-9]+)/merge" MATCHED_REF "$ENV{GITHUB_REF}")
if (MATCHED_REF)
set(PR_NUMBER "${CMAKE_MATCH_1}")
set(GITHUB_BRANCH "")
message("PR number: ${PR_NUMBER}")
else()
set(PR_NUMBER "")
endif()
else()
set(GITHUB_BRANCH "")
set(PR_NUMBER "")
endif()
if (NOT "${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_HEAD_REF}" STREQUAL "")
set(GIT_BRANCH "pr-${PR_NUMBER}-${GITHUB_HEAD_REF}")
elseif (NOT "${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_BRANCH}" STREQUAL "")
set(GIT_BRANCH "pr-${PR_NUMBER}-${GITHUB_BRANCH}")
elseif (NOT "${PR_NUMBER}" STREQUAL "")
set(GIT_BRANCH "pr-${PR_NUMBER}")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_HEAD_REF}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_HEAD_REF}")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_BRANCH}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_BRANCH}")
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "")
set(GIT_BRANCH "${GITHUB_REF}")
else()
message("couldn't find branch")
set(GIT_BRANCH "detached-head")
endif() endif()
else() else()
# Extract remote name if the output contains a remote/branch format # Extract remote name if the output contains a remote/branch format
@ -141,6 +194,7 @@ else()
endif() endif()
# Get remote link # Get remote link
message("getting remote link")
execute_process( execute_process(
COMMAND git config --get remote.${GIT_REMOTE_NAME}.url COMMAND git config --get remote.${GIT_REMOTE_NAME}.url
OUTPUT_VARIABLE GIT_REMOTE_URL OUTPUT_VARIABLE GIT_REMOTE_URL
@ -149,6 +203,8 @@ execute_process(
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY)
message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}")
find_package(Boost 1.84.0 CONFIG) find_package(Boost 1.84.0 CONFIG)
find_package(FFmpeg 5.1.2 MODULE) find_package(FFmpeg 5.1.2 MODULE)
find_package(fmt 10.2.0 CONFIG) find_package(fmt 10.2.0 CONFIG)
@ -278,6 +334,8 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp
src/core/libraries/kernel/threads/thread_state.h src/core/libraries/kernel/threads/thread_state.h
src/core/libraries/kernel/process.cpp src/core/libraries/kernel/process.cpp
src/core/libraries/kernel/process.h src/core/libraries/kernel/process.h
src/core/libraries/kernel/debug.cpp
src/core/libraries/kernel/debug.h
src/core/libraries/kernel/equeue.cpp src/core/libraries/kernel/equeue.cpp
src/core/libraries/kernel/equeue.h src/core/libraries/kernel/equeue.h
src/core/libraries/kernel/file_system.cpp src/core/libraries/kernel/file_system.cpp
@ -371,6 +429,24 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/ngs2/ngs2_error.h src/core/libraries/ngs2/ngs2_error.h
src/core/libraries/ngs2/ngs2_impl.cpp src/core/libraries/ngs2/ngs2_impl.cpp
src/core/libraries/ngs2/ngs2_impl.h src/core/libraries/ngs2/ngs2_impl.h
src/core/libraries/ngs2/ngs2_custom.cpp
src/core/libraries/ngs2/ngs2_custom.h
src/core/libraries/ngs2/ngs2_reverb.cpp
src/core/libraries/ngs2/ngs2_reverb.h
src/core/libraries/ngs2/ngs2_geom.cpp
src/core/libraries/ngs2/ngs2_geom.h
src/core/libraries/ngs2/ngs2_pan.cpp
src/core/libraries/ngs2/ngs2_pan.h
src/core/libraries/ngs2/ngs2_report.cpp
src/core/libraries/ngs2/ngs2_report.h
src/core/libraries/ngs2/ngs2_eq.cpp
src/core/libraries/ngs2/ngs2_eq.h
src/core/libraries/ngs2/ngs2_mastering.cpp
src/core/libraries/ngs2/ngs2_mastering.h
src/core/libraries/ngs2/ngs2_sampler.cpp
src/core/libraries/ngs2/ngs2_sampler.h
src/core/libraries/ngs2/ngs2_submixer.cpp
src/core/libraries/ngs2/ngs2_submixer.h
src/core/libraries/ajm/ajm_error.h src/core/libraries/ajm/ajm_error.h
src/core/libraries/audio3d/audio3d.cpp src/core/libraries/audio3d/audio3d.cpp
src/core/libraries/audio3d/audio3d.h src/core/libraries/audio3d/audio3d.h
@ -550,6 +626,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/logging/text_formatter.cpp src/common/logging/text_formatter.cpp
src/common/logging/text_formatter.h src/common/logging/text_formatter.h
src/common/logging/types.h src/common/logging/types.h
src/common/aes.h
src/common/alignment.h src/common/alignment.h
src/common/arch.h src/common/arch.h
src/common/assert.cpp src/common/assert.cpp
@ -581,6 +658,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/polyfill_thread.h src/common/polyfill_thread.h
src/common/rdtsc.cpp src/common/rdtsc.cpp
src/common/rdtsc.h src/common/rdtsc.h
src/common/sha1.h
src/common/signal_context.h src/common/signal_context.h
src/common/signal_context.cpp src/common/signal_context.cpp
src/common/singleton.h src/common/singleton.h
@ -620,9 +698,6 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/aerolib/aerolib.h src/core/aerolib/aerolib.h
src/core/address_space.cpp src/core/address_space.cpp
src/core/address_space.h src/core/address_space.h
src/core/crypto/crypto.cpp
src/core/crypto/crypto.h
src/core/crypto/keys.h
src/core/devices/base_device.cpp src/core/devices/base_device.cpp
src/core/devices/base_device.h src/core/devices/base_device.h
src/core/devices/ioccom.h src/core/devices/ioccom.h
@ -640,10 +715,6 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/devices/srandom_device.cpp src/core/devices/srandom_device.cpp
src/core/devices/srandom_device.h src/core/devices/srandom_device.h
src/core/file_format/pfs.h src/core/file_format/pfs.h
src/core/file_format/pkg.cpp
src/core/file_format/pkg.h
src/core/file_format/pkg_type.cpp
src/core/file_format/pkg_type.h
src/core/file_format/psf.cpp src/core/file_format/psf.cpp
src/core/file_format/psf.h src/core/file_format/psf.h
src/core/file_format/playgo_chunk.cpp src/core/file_format/playgo_chunk.cpp
@ -652,8 +723,6 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/file_format/trp.h src/core/file_format/trp.h
src/core/file_sys/fs.cpp src/core/file_sys/fs.cpp
src/core/file_sys/fs.h src/core/file_sys/fs.h
src/core/loader.cpp
src/core/loader.h
src/core/loader/dwarf.cpp src/core/loader/dwarf.cpp
src/core/loader/dwarf.h src/core/loader/dwarf.h
src/core/loader/elf.cpp src/core/loader/elf.cpp
@ -770,6 +839,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/ir/passes/identity_removal_pass.cpp src/shader_recompiler/ir/passes/identity_removal_pass.cpp
src/shader_recompiler/ir/passes/ir_passes.h src/shader_recompiler/ir/passes/ir_passes.h
src/shader_recompiler/ir/passes/lower_buffer_format_to_raw.cpp src/shader_recompiler/ir/passes/lower_buffer_format_to_raw.cpp
src/shader_recompiler/ir/passes/readlane_elimination_pass.cpp
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
src/shader_recompiler/ir/passes/ring_access_elimination.cpp src/shader_recompiler/ir/passes/ring_access_elimination.cpp
src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp
@ -942,10 +1012,6 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/game_grid_frame.h src/qt_gui/game_grid_frame.h
src/qt_gui/game_install_dialog.cpp src/qt_gui/game_install_dialog.cpp
src/qt_gui/game_install_dialog.h src/qt_gui/game_install_dialog.h
src/qt_gui/install_dir_select.cpp
src/qt_gui/install_dir_select.h
src/qt_gui/pkg_viewer.cpp
src/qt_gui/pkg_viewer.h
src/qt_gui/trophy_viewer.cpp src/qt_gui/trophy_viewer.cpp
src/qt_gui/trophy_viewer.h src/qt_gui/trophy_viewer.h
src/qt_gui/elf_viewer.cpp src/qt_gui/elf_viewer.cpp
@ -1050,12 +1116,6 @@ if (NOT ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE SDL3::SDL3) target_link_libraries(shadps4 PRIVATE SDL3::SDL3)
endif() endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
target_link_libraries(shadps4 PRIVATE cryptoppwin)
else()
target_link_libraries(shadps4 PRIVATE cryptopp::cryptopp)
endif()
if (ENABLE_QT_GUI) if (ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia) target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
add_definitions(-DENABLE_QT_GUI) add_definitions(-DENABLE_QT_GUI)
@ -1126,7 +1186,6 @@ cmrc_add_resource_library(embedded-resources
src/images/gold.png src/images/gold.png
src/images/platinum.png src/images/platinum.png
src/images/silver.png) src/images/silver.png)
target_link_libraries(shadps4 PRIVATE res::embedded) target_link_libraries(shadps4 PRIVATE res::embedded)
# ImGui resources # ImGui resources

View file

@ -30,6 +30,7 @@ path = [
"src/images/dump_icon.png", "src/images/dump_icon.png",
"src/images/exit_icon.png", "src/images/exit_icon.png",
"src/images/file_icon.png", "src/images/file_icon.png",
"src/images/trophy_icon.png",
"src/images/flag_china.png", "src/images/flag_china.png",
"src/images/flag_eu.png", "src/images/flag_eu.png",
"src/images/flag_jp.png", "src/images/flag_jp.png",
@ -48,8 +49,10 @@ path = [
"src/images/pause_icon.png", "src/images/pause_icon.png",
"src/images/play_icon.png", "src/images/play_icon.png",
"src/images/ps4_controller.png", "src/images/ps4_controller.png",
"src/images/refresh_icon.png", "src/images/restart_game_icon.png",
"src/images/refreshlist_icon.png",
"src/images/settings_icon.png", "src/images/settings_icon.png",
"src/images/fullscreen_icon.png",
"src/images/stop_icon.png", "src/images/stop_icon.png",
"src/images/utils_icon.png", "src/images/utils_icon.png",
"src/images/shadPS4.icns", "src/images/shadPS4.icns",

View file

@ -37,6 +37,9 @@
<category translate="no">Game</category> <category translate="no">Game</category>
</categories> </categories>
<releases> <releases>
<release version="0.7.0" date="2025-03-23">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.7.0</url>
</release>
<release version="0.6.0" date="2025-01-31"> <release version="0.6.0" date="2025-01-31">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.6.0</url> <url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.6.0</url>
</release> </release>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 KiB

View file

@ -13,7 +13,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
- [**RAM**](#ram) - [**RAM**](#ram)
- [**OS**](#os) - [**OS**](#os)
- [**Have the latest WIP version**](#how-to-run-the-latest-work-in-progress-builds-of-shadps4) - [**Have the latest WIP version**](#how-to-run-the-latest-work-in-progress-builds-of-shadps4)
- [**Install PKG files (Games and Updates)**](#install-pkg-files)
- [**Configure the emulator**](#configure-the-emulator) - [**Configure the emulator**](#configure-the-emulator)
## Minimum PC requirements ## Minimum PC requirements
@ -48,13 +47,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
2. Once downloaded, extract to its own folder, and run shadPS4's executable from the extracted folder. 2. Once downloaded, extract to its own folder, and run shadPS4's executable from the extracted folder.
3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that shadPS4 can use to install your PKG files to. 3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that contains your dumped games.
## Install PKG files
To install PKG files (game and updates), you will need the Qt application (with UI). You will have to go to "File" then to "Install Packages (PKG)", a window will open then you will have to select the files. You can install multiple PKG files at once. Once finished, the game should appear in the application.
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/2.png" width="800">
## Configure the emulator ## Configure the emulator

View file

@ -108,7 +108,7 @@ Now run the emulator. If Qt was enabled at configure time:
./build/shadps4 ./build/shadps4
``` ```
Otherwise, specify the path to your PKG's boot file: Otherwise, specify the path to your game's boot file:
```bash ```bash
./build/shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin ./build/shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin

View file

@ -26,24 +26,7 @@ if (NOT TARGET fmt::fmt)
add_subdirectory(fmt) add_subdirectory(fmt)
endif() endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC) # FFmpeg
# If it is clang and MSVC we will add a static lib
# CryptoPP
add_subdirectory(cryptoppwin)
target_include_directories(cryptoppwin INTERFACE cryptoppwin/include)
else()
# CryptoPP
if (NOT TARGET cryptopp::cryptopp)
set(CRYPTOPP_INSTALL OFF)
set(CRYPTOPP_BUILD_TESTING OFF)
set(CRYPTOPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp)
add_subdirectory(cryptopp-cmake)
file(COPY cryptopp DESTINATION cryptopp FILES_MATCHING PATTERN "*.h")
# remove externals/cryptopp from include directories because it contains a conflicting zlib.h file
set_target_properties(cryptopp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/cryptopp")
endif()
endif()
if (NOT TARGET FFmpeg::ffmpeg) if (NOT TARGET FFmpeg::ffmpeg)
add_subdirectory(ffmpeg-core) add_subdirectory(ffmpeg-core)
add_library(FFmpeg::ffmpeg ALIAS ffmpeg) add_library(FFmpeg::ffmpeg ALIAS ffmpeg)

1
externals/cryptopp vendored

@ -1 +0,0 @@
Subproject commit 60f81a77e0c9a0e7ffc1ca1bc438ddfa2e43b78e

@ -1 +0,0 @@
Subproject commit 2c384c28265a93358a2455e610e76393358794df

@ -1 +0,0 @@
Subproject commit bc3441dd2d6a9728e747dc0180bc8b9065a2923c

1195
src/common/aes.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,7 @@ std::filesystem::path find_fs_path_or(const basic_value<TC>& v, const K& ky,
namespace Config { namespace Config {
static bool isNeo = false; static bool isNeo = false;
static bool isDevKit = false;
static bool playBGM = false; static bool playBGM = false;
static bool isTrophyPopupDisabled = false; static bool isTrophyPopupDisabled = false;
static int BGMvolume = 50; static int BGMvolume = 50;
@ -40,7 +41,7 @@ static u32 screenWidth = 1280;
static u32 screenHeight = 720; static u32 screenHeight = 720;
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
static std::string logFilter; static std::string logFilter;
static std::string logType = "async"; static std::string logType = "sync";
static std::string userName = "shadPS4"; static std::string userName = "shadPS4";
static std::string updateChannel; static std::string updateChannel;
static std::string chooseHomeTab; static std::string chooseHomeTab;
@ -74,14 +75,14 @@ static double trophyNotificationDuration = 6.0;
static bool useUnifiedInputConfig = true; static bool useUnifiedInputConfig = true;
static bool overrideControllerColor = false; static bool overrideControllerColor = false;
static int controllerCustomColorRGB[3] = {0, 0, 255}; static int controllerCustomColorRGB[3] = {0, 0, 255};
static bool separateupdatefolder = false;
static bool compatibilityData = false; static bool compatibilityData = false;
static bool checkCompatibilityOnStartup = false; static bool checkCompatibilityOnStartup = false;
static std::string trophyKey; static std::string trophyKey;
// Gui // Gui
static bool load_game_size = true; static bool load_game_size = true;
std::vector<std::filesystem::path> settings_install_dirs = {}; static std::vector<GameInstallDir> settings_install_dirs = {};
std::vector<bool> install_dirs_enabled = {};
std::filesystem::path settings_addon_install_dir = {}; std::filesystem::path settings_addon_install_dir = {};
std::filesystem::path save_data_path = {}; std::filesystem::path save_data_path = {};
u32 main_window_geometry_x = 400; u32 main_window_geometry_x = 400;
@ -96,7 +97,6 @@ u32 m_slider_pos_grid = 0;
u32 m_table_mode = 0; u32 m_table_mode = 0;
u32 m_window_size_W = 1280; u32 m_window_size_W = 1280;
u32 m_window_size_H = 720; u32 m_window_size_H = 720;
std::vector<std::string> m_pkg_viewer;
std::vector<std::string> m_elf_viewer; std::vector<std::string> m_elf_viewer;
std::vector<std::string> m_recent_files; std::vector<std::string> m_recent_files;
std::string emulator_language = "en_US"; std::string emulator_language = "en_US";
@ -105,6 +105,7 @@ static bool showBackgroundImage = true;
static bool isFullscreen = false; static bool isFullscreen = false;
static std::string fullscreenMode = "Windowed"; static std::string fullscreenMode = "Windowed";
static bool isHDRAllowed = false; static bool isHDRAllowed = false;
static bool showLabelsUnderIcons = true;
// Language // Language
u32 m_language = 1; // english u32 m_language = 1; // english
@ -166,10 +167,22 @@ bool isNeoModeConsole() {
return isNeo; return isNeo;
} }
bool isDevKitConsole() {
return isDevKit;
}
bool getIsFullscreen() { bool getIsFullscreen() {
return isFullscreen; return isFullscreen;
} }
bool getShowLabelsUnderIcons() {
return showLabelsUnderIcons;
}
bool setShowLabelsUnderIcons() {
return false;
}
std::string getFullscreenMode() { std::string getFullscreenMode() {
return fullscreenMode; return fullscreenMode;
} }
@ -338,10 +351,6 @@ void setVkGuestMarkersEnabled(bool enable) {
vkGuestMarkers = enable; vkGuestMarkers = enable;
} }
bool getSeparateUpdateEnabled() {
return separateupdatefolder;
}
bool getCompatibilityEnabled() { bool getCompatibilityEnabled() {
return compatibilityData; return compatibilityData;
} }
@ -421,6 +430,9 @@ void setVblankDiv(u32 value) {
void setIsFullscreen(bool enable) { void setIsFullscreen(bool enable) {
isFullscreen = enable; isFullscreen = enable;
} }
static void setShowLabelsUnderIcons(bool enable) {
showLabelsUnderIcons = enable;
}
void setFullscreenMode(std::string mode) { void setFullscreenMode(std::string mode) {
fullscreenMode = mode; fullscreenMode = mode;
@ -500,10 +512,6 @@ void setIsMotionControlsEnabled(bool use) {
isMotionControlsEnabled = use; isMotionControlsEnabled = use;
} }
void setSeparateUpdateEnabled(bool use) {
separateupdatefolder = use;
}
void setCompatibilityEnabled(bool use) { void setCompatibilityEnabled(bool use) {
compatibilityData = use; compatibilityData = use;
} }
@ -519,22 +527,34 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
main_window_geometry_h = h; main_window_geometry_h = h;
} }
bool addGameInstallDir(const std::filesystem::path& dir) { bool addGameInstallDir(const std::filesystem::path& dir, bool enabled) {
if (std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir) == for (const auto& install_dir : settings_install_dirs) {
settings_install_dirs.end()) { if (install_dir.path == dir) {
settings_install_dirs.push_back(dir); return false;
return true; }
} }
return false; settings_install_dirs.push_back({dir, enabled});
return true;
} }
void removeGameInstallDir(const std::filesystem::path& dir) { void removeGameInstallDir(const std::filesystem::path& dir) {
auto iterator = std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir); auto iterator =
std::find_if(settings_install_dirs.begin(), settings_install_dirs.end(),
[&dir](const GameInstallDir& install_dir) { return install_dir.path == dir; });
if (iterator != settings_install_dirs.end()) { if (iterator != settings_install_dirs.end()) {
settings_install_dirs.erase(iterator); settings_install_dirs.erase(iterator);
} }
} }
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled) {
auto iterator =
std::find_if(settings_install_dirs.begin(), settings_install_dirs.end(),
[&dir](const GameInstallDir& install_dir) { return install_dir.path == dir; });
if (iterator != settings_install_dirs.end()) {
iterator->enabled = enabled;
}
}
void setAddonInstallDir(const std::filesystem::path& dir) { void setAddonInstallDir(const std::filesystem::path& dir) {
settings_addon_install_dir = dir; settings_addon_install_dir = dir;
} }
@ -571,11 +591,6 @@ void setMainWindowHeight(u32 height) {
m_window_size_H = height; m_window_size_H = height;
} }
void setPkgViewer(const std::vector<std::string>& pkgList) {
m_pkg_viewer.resize(pkgList.size());
m_pkg_viewer = pkgList;
}
void setElfViewer(const std::vector<std::string>& elfList) { void setElfViewer(const std::vector<std::string>& elfList) {
m_elf_viewer.resize(elfList.size()); m_elf_viewer.resize(elfList.size());
m_elf_viewer = elfList; m_elf_viewer = elfList;
@ -590,8 +605,15 @@ void setEmulatorLanguage(std::string language) {
emulator_language = language; emulator_language = language;
} }
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config) { void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config) {
settings_install_dirs = settings_install_dirs_config; settings_install_dirs.clear();
for (const auto& dir : dirs_config) {
settings_install_dirs.push_back({dir, true});
}
}
void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config) {
settings_install_dirs = dirs_config;
} }
void setSaveDataPath(const std::filesystem::path& path) { void setSaveDataPath(const std::filesystem::path& path) {
@ -614,8 +636,22 @@ u32 getMainWindowGeometryH() {
return main_window_geometry_h; return main_window_geometry_h;
} }
const std::vector<std::filesystem::path>& getGameInstallDirs() { const std::vector<std::filesystem::path> getGameInstallDirs() {
return settings_install_dirs; std::vector<std::filesystem::path> enabled_dirs;
for (const auto& dir : settings_install_dirs) {
if (dir.enabled) {
enabled_dirs.push_back(dir.path);
}
}
return enabled_dirs;
}
const std::vector<bool> getGameInstallDirsEnabled() {
std::vector<bool> enabled_dirs;
for (const auto& dir : settings_install_dirs) {
enabled_dirs.push_back(dir.enabled);
}
return enabled_dirs;
} }
std::filesystem::path getAddonInstallDir() { std::filesystem::path getAddonInstallDir() {
@ -658,10 +694,6 @@ u32 getMainWindowHeight() {
return m_window_size_H; return m_window_size_H;
} }
std::vector<std::string> getPkgViewer() {
return m_pkg_viewer;
}
std::vector<std::string> getElfViewer() { std::vector<std::string> getElfViewer() {
return m_elf_viewer; return m_elf_viewer;
} }
@ -721,6 +753,7 @@ void load(const std::filesystem::path& path) {
const toml::value& general = data.at("General"); const toml::value& general = data.at("General");
isNeo = toml::find_or<bool>(general, "isPS4Pro", false); isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
isDevKit = toml::find_or<bool>(general, "isDevKit", false);
playBGM = toml::find_or<bool>(general, "playBGM", false); playBGM = toml::find_or<bool>(general, "playBGM", false);
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false); isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false);
trophyNotificationDuration = trophyNotificationDuration =
@ -739,7 +772,6 @@ void load(const std::filesystem::path& path) {
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false); isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false);
isAlwaysShowChangelog = toml::find_or<bool>(general, "alwaysShowChangelog", false); isAlwaysShowChangelog = toml::find_or<bool>(general, "alwaysShowChangelog", false);
isSideTrophy = toml::find_or<std::string>(general, "sideTrophy", "right"); isSideTrophy = toml::find_or<std::string>(general, "sideTrophy", "right");
separateupdatefolder = toml::find_or<bool>(general, "separateUpdateEnabled", false);
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false); compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false);
checkCompatibilityOnStartup = checkCompatibilityOnStartup =
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false); toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
@ -808,9 +840,23 @@ void load(const std::filesystem::path& path) {
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0); m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
const auto install_dir_array = const auto install_dir_array =
toml::find_or<std::vector<std::string>>(gui, "installDirs", {}); toml::find_or<std::vector<std::u8string>>(gui, "installDirs", {});
for (const auto& dir : install_dir_array) {
addGameInstallDir(std::filesystem::path{dir}); try {
install_dirs_enabled = toml::find<std::vector<bool>>(gui, "installDirsEnabled");
} catch (...) {
// If it does not exist, assume that all are enabled.
install_dirs_enabled.resize(install_dir_array.size(), true);
}
if (install_dirs_enabled.size() < install_dir_array.size()) {
install_dirs_enabled.resize(install_dir_array.size(), true);
}
settings_install_dirs.clear();
for (size_t i = 0; i < install_dir_array.size(); i++) {
settings_install_dirs.push_back(
{std::filesystem::path{install_dir_array[i]}, install_dirs_enabled[i]});
} }
save_data_path = toml::find_fs_path_or(gui, "saveDataPath", {}); save_data_path = toml::find_fs_path_or(gui, "saveDataPath", {});
@ -820,7 +866,6 @@ void load(const std::filesystem::path& path) {
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0); main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
main_window_geometry_w = toml::find_or<int>(gui, "geometry_w", 0); main_window_geometry_w = toml::find_or<int>(gui, "geometry_w", 0);
main_window_geometry_h = toml::find_or<int>(gui, "geometry_h", 0); main_window_geometry_h = toml::find_or<int>(gui, "geometry_h", 0);
m_pkg_viewer = toml::find_or<std::vector<std::string>>(gui, "pkgDirs", {});
m_elf_viewer = toml::find_or<std::vector<std::string>>(gui, "elfDirs", {}); m_elf_viewer = toml::find_or<std::vector<std::string>>(gui, "elfDirs", {});
m_recent_files = toml::find_or<std::vector<std::string>>(gui, "recentFiles", {}); m_recent_files = toml::find_or<std::vector<std::string>>(gui, "recentFiles", {});
m_table_mode = toml::find_or<int>(gui, "gameTableMode", 0); m_table_mode = toml::find_or<int>(gui, "gameTableMode", 0);
@ -853,6 +898,37 @@ void load(const std::filesystem::path& path) {
} }
} }
void sortTomlSections(toml::ordered_value& data) {
toml::ordered_value ordered_data;
std::vector<std::string> section_order = {"General", "Input", "GPU", "Vulkan",
"Debug", "Keys", "GUI", "Settings"};
for (const auto& section : section_order) {
if (data.contains(section)) {
std::vector<std::string> keys;
for (const auto& item : data.at(section).as_table()) {
keys.push_back(item.first);
}
std::sort(keys.begin(), keys.end(), [](const std::string& a, const std::string& b) {
return std::lexicographical_compare(
a.begin(), a.end(), b.begin(), b.end(), [](char a_char, char b_char) {
return std::tolower(a_char) < std::tolower(b_char);
});
});
toml::ordered_value ordered_section;
for (const auto& key : keys) {
ordered_section[key] = data.at(section).at(key);
}
ordered_data[section] = ordered_section;
}
}
data = ordered_data;
}
void save(const std::filesystem::path& path) { void save(const std::filesystem::path& path) {
toml::ordered_value data; toml::ordered_value data;
@ -876,6 +952,7 @@ void save(const std::filesystem::path& path) {
} }
data["General"]["isPS4Pro"] = isNeo; data["General"]["isPS4Pro"] = isNeo;
data["General"]["isDevKit"] = isDevKit;
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled; data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
data["General"]["trophyNotificationDuration"] = trophyNotificationDuration; data["General"]["trophyNotificationDuration"] = trophyNotificationDuration;
data["General"]["playBGM"] = playBGM; data["General"]["playBGM"] = playBGM;
@ -890,7 +967,6 @@ void save(const std::filesystem::path& path) {
data["General"]["autoUpdate"] = isAutoUpdate; data["General"]["autoUpdate"] = isAutoUpdate;
data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog; data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog;
data["General"]["sideTrophy"] = isSideTrophy; data["General"]["sideTrophy"] = isSideTrophy;
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
data["General"]["compatibilityEnabled"] = compatibilityData; data["General"]["compatibilityEnabled"] = compatibilityData;
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup; data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
data["Input"]["cursorState"] = cursorState; data["Input"]["cursorState"] = cursorState;
@ -922,14 +998,37 @@ void save(const std::filesystem::path& path) {
data["Debug"]["CollectShader"] = isShaderDebug; data["Debug"]["CollectShader"] = isShaderDebug;
data["Debug"]["isSeparateLogFilesEnabled"] = isSeparateLogFilesEnabled; data["Debug"]["isSeparateLogFilesEnabled"] = isSeparateLogFilesEnabled;
data["Debug"]["FPSColor"] = isFpsColor; data["Debug"]["FPSColor"] = isFpsColor;
data["Keys"]["TrophyKey"] = trophyKey; data["Keys"]["TrophyKey"] = trophyKey;
std::vector<std::string> install_dirs; std::vector<std::string> install_dirs;
for (const auto& dirString : settings_install_dirs) { std::vector<bool> install_dirs_enabled;
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
// temporary structure for ordering
struct DirEntry {
std::string path_str;
bool enabled;
};
std::vector<DirEntry> sorted_dirs;
for (const auto& dirInfo : settings_install_dirs) {
sorted_dirs.push_back(
{std::string{fmt::UTF(dirInfo.path.u8string()).data}, dirInfo.enabled});
} }
// Sort directories alphabetically
std::sort(sorted_dirs.begin(), sorted_dirs.end(), [](const DirEntry& a, const DirEntry& b) {
return std::lexicographical_compare(
a.path_str.begin(), a.path_str.end(), b.path_str.begin(), b.path_str.end(),
[](char a_char, char b_char) { return std::tolower(a_char) < std::tolower(b_char); });
});
for (const auto& entry : sorted_dirs) {
install_dirs.push_back(entry.path_str);
install_dirs_enabled.push_back(entry.enabled);
}
data["GUI"]["installDirs"] = install_dirs; data["GUI"]["installDirs"] = install_dirs;
data["GUI"]["installDirsEnabled"] = install_dirs_enabled;
data["GUI"]["saveDataPath"] = std::string{fmt::UTF(save_data_path.u8string()).data}; data["GUI"]["saveDataPath"] = std::string{fmt::UTF(save_data_path.u8string()).data};
data["GUI"]["loadGameSizeEnabled"] = load_game_size; data["GUI"]["loadGameSizeEnabled"] = load_game_size;
@ -940,9 +1039,13 @@ void save(const std::filesystem::path& path) {
data["GUI"]["showBackgroundImage"] = showBackgroundImage; data["GUI"]["showBackgroundImage"] = showBackgroundImage;
data["Settings"]["consoleLanguage"] = m_language; data["Settings"]["consoleLanguage"] = m_language;
// Sorting of TOML sections
sortTomlSections(data);
std::ofstream file(path, std::ios::binary); std::ofstream file(path, std::ios::binary);
file << data; file << data;
file.close(); file.close();
saveMainWindow(path); saveMainWindow(path);
} }
@ -980,10 +1083,12 @@ void saveMainWindow(const std::filesystem::path& path) {
data["GUI"]["geometry_y"] = main_window_geometry_y; data["GUI"]["geometry_y"] = main_window_geometry_y;
data["GUI"]["geometry_w"] = main_window_geometry_w; data["GUI"]["geometry_w"] = main_window_geometry_w;
data["GUI"]["geometry_h"] = main_window_geometry_h; data["GUI"]["geometry_h"] = main_window_geometry_h;
data["GUI"]["pkgDirs"] = m_pkg_viewer;
data["GUI"]["elfDirs"] = m_elf_viewer; data["GUI"]["elfDirs"] = m_elf_viewer;
data["GUI"]["recentFiles"] = m_recent_files; data["GUI"]["recentFiles"] = m_recent_files;
// Sorting of TOML sections
sortTomlSections(data);
std::ofstream file(path, std::ios::binary); std::ofstream file(path, std::ios::binary);
file << data; file << data;
file.close(); file.close();
@ -992,6 +1097,7 @@ void saveMainWindow(const std::filesystem::path& path) {
void setDefaultValues() { void setDefaultValues() {
isHDRAllowed = false; isHDRAllowed = false;
isNeo = false; isNeo = false;
isDevKit = false;
isFullscreen = false; isFullscreen = false;
isTrophyPopupDisabled = false; isTrophyPopupDisabled = false;
playBGM = false; playBGM = false;
@ -1000,7 +1106,7 @@ void setDefaultValues() {
screenWidth = 1280; screenWidth = 1280;
screenHeight = 720; screenHeight = 720;
logFilter = ""; logFilter = "";
logType = "async"; logType = "sync";
userName = "shadPS4"; userName = "shadPS4";
if (Common::isRelease) { if (Common::isRelease) {
updateChannel = "Release"; updateChannel = "Release";
@ -1033,7 +1139,6 @@ void setDefaultValues() {
emulator_language = "en_US"; emulator_language = "en_US";
m_language = 1; m_language = 1;
gpuId = -1; gpuId = -1;
separateupdatefolder = false;
compatibilityData = false; compatibilityData = false;
checkCompatibilityOnStartup = false; checkCompatibilityOnStartup = false;
backgroundImageOpacity = 50; backgroundImageOpacity = 50;

View file

@ -9,6 +9,11 @@
namespace Config { namespace Config {
struct GameInstallDir {
std::filesystem::path path;
bool enabled;
};
enum HideCursorState : s16 { Never, Idle, Always }; enum HideCursorState : s16 { Never, Idle, Always };
void load(const std::filesystem::path& path); void load(const std::filesystem::path& path);
@ -21,13 +26,15 @@ bool GetLoadGameSizeEnabled();
std::filesystem::path GetSaveDataPath(); std::filesystem::path GetSaveDataPath();
void setLoadGameSizeEnabled(bool enable); void setLoadGameSizeEnabled(bool enable);
bool getIsFullscreen(); bool getIsFullscreen();
bool getShowLabelsUnderIcons();
bool setShowLabelsUnderIcons();
std::string getFullscreenMode(); std::string getFullscreenMode();
bool isNeoModeConsole(); bool isNeoModeConsole();
bool isDevKitConsole();
bool getPlayBGM(); bool getPlayBGM();
int getBGMvolume(); int getBGMvolume();
bool getisTrophyPopupDisabled(); bool getisTrophyPopupDisabled();
bool getEnableDiscordRPC(); bool getEnableDiscordRPC();
bool getSeparateUpdateEnabled();
bool getCompatibilityEnabled(); bool getCompatibilityEnabled();
bool getCheckCompatibilityOnStartup(); bool getCheckCompatibilityOnStartup();
int getBackgroundImageOpacity(); int getBackgroundImageOpacity();
@ -97,8 +104,8 @@ void setNeoMode(bool enable);
void setUserName(const std::string& type); void setUserName(const std::string& type);
void setUpdateChannel(const std::string& type); void setUpdateChannel(const std::string& type);
void setChooseHomeTab(const std::string& type); void setChooseHomeTab(const std::string& type);
void setSeparateUpdateEnabled(bool use); void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config);
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config); void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config);
void setSaveDataPath(const std::filesystem::path& path); void setSaveDataPath(const std::filesystem::path& path);
void setCompatibilityEnabled(bool use); void setCompatibilityEnabled(bool use);
void setCheckCompatibilityOnStartup(bool use); void setCheckCompatibilityOnStartup(bool use);
@ -133,8 +140,9 @@ void setVkGuestMarkersEnabled(bool enable);
// Gui // Gui
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h); void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
bool addGameInstallDir(const std::filesystem::path& dir); bool addGameInstallDir(const std::filesystem::path& dir, bool enabled = true);
void removeGameInstallDir(const std::filesystem::path& dir); void removeGameInstallDir(const std::filesystem::path& dir);
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled);
void setAddonInstallDir(const std::filesystem::path& dir); void setAddonInstallDir(const std::filesystem::path& dir);
void setMainWindowTheme(u32 theme); void setMainWindowTheme(u32 theme);
void setIconSize(u32 size); void setIconSize(u32 size);
@ -144,7 +152,6 @@ void setSliderPositionGrid(u32 pos);
void setTableMode(u32 mode); void setTableMode(u32 mode);
void setMainWindowWidth(u32 width); void setMainWindowWidth(u32 width);
void setMainWindowHeight(u32 height); void setMainWindowHeight(u32 height);
void setPkgViewer(const std::vector<std::string>& pkgList);
void setElfViewer(const std::vector<std::string>& elfList); void setElfViewer(const std::vector<std::string>& elfList);
void setRecentFiles(const std::vector<std::string>& recentFiles); void setRecentFiles(const std::vector<std::string>& recentFiles);
void setEmulatorLanguage(std::string language); void setEmulatorLanguage(std::string language);
@ -153,7 +160,8 @@ u32 getMainWindowGeometryX();
u32 getMainWindowGeometryY(); u32 getMainWindowGeometryY();
u32 getMainWindowGeometryW(); u32 getMainWindowGeometryW();
u32 getMainWindowGeometryH(); u32 getMainWindowGeometryH();
const std::vector<std::filesystem::path>& getGameInstallDirs(); const std::vector<std::filesystem::path> getGameInstallDirs();
const std::vector<bool> getGameInstallDirsEnabled();
std::filesystem::path getAddonInstallDir(); std::filesystem::path getAddonInstallDir();
u32 getMainWindowTheme(); u32 getMainWindowTheme();
u32 getIconSize(); u32 getIconSize();
@ -163,7 +171,6 @@ u32 getSliderPositionGrid();
u32 getTableMode(); u32 getTableMode();
u32 getMainWindowWidth(); u32 getMainWindowWidth();
u32 getMainWindowHeight(); u32 getMainWindowHeight();
std::vector<std::string> getPkgViewer();
std::vector<std::string> getElfViewer(); std::vector<std::string> getElfViewer();
std::vector<std::string> getRecentFiles(); std::vector<std::string> getRecentFiles();
std::string getEmulatorLanguage(); std::string getEmulatorLanguage();

View file

@ -125,12 +125,15 @@ namespace {
[[nodiscard]] constexpr int ToSeekOrigin(SeekOrigin origin) { [[nodiscard]] constexpr int ToSeekOrigin(SeekOrigin origin) {
switch (origin) { switch (origin) {
case SeekOrigin::SetOrigin: case SeekOrigin::SetOrigin:
default:
return SEEK_SET; return SEEK_SET;
case SeekOrigin::CurrentPosition: case SeekOrigin::CurrentPosition:
return SEEK_CUR; return SEEK_CUR;
case SeekOrigin::End: case SeekOrigin::End:
return SEEK_END; return SEEK_END;
default:
LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET",
static_cast<u32>(origin));
return SEEK_SET;
} }
} }
@ -377,20 +380,6 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const {
return false; return false;
} }
if (False(file_access_mode & (FileAccessMode::Write | FileAccessMode::Append))) {
u64 size = GetSize();
if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::End && offset > 0) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
}
}
errno = 0; errno = 0;
const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0; const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0;

View file

@ -61,6 +61,8 @@ enum class SeekOrigin : u32 {
SetOrigin, // Seeks from the start of the file. SetOrigin, // Seeks from the start of the file.
CurrentPosition, // Seeks from the current file pointer position. CurrentPosition, // Seeks from the current file pointer position.
End, // Seeks from the end of the file. End, // Seeks from the end of the file.
SeekHole, // Seeks from the start of the next hole in the file.
SeekData, // Seeks from the start of the next non-hole region in the file.
}; };
class IOFile final { class IOFile final {

180
src/common/sha1.h Normal file
View file

@ -0,0 +1,180 @@
// SPDX-FileCopyrightText: 2012 SAURAV MOHAPATRA <mohaps@gmail.com>
// SPDX-License-Identifier: MIT
#pragma once
#include <cstdint>
#include <cstdlib>
#include <cstring>
namespace sha1 {
class SHA1 {
public:
typedef uint32_t digest32_t[5];
typedef uint8_t digest8_t[20];
inline static uint32_t LeftRotate(uint32_t value, size_t count) {
return (value << count) ^ (value >> (32 - count));
}
SHA1() {
reset();
}
virtual ~SHA1() {}
SHA1(const SHA1& s) {
*this = s;
}
const SHA1& operator=(const SHA1& s) {
memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
memcpy(m_block, s.m_block, 64);
m_blockByteIndex = s.m_blockByteIndex;
m_byteCount = s.m_byteCount;
return *this;
}
SHA1& reset() {
m_digest[0] = 0x67452301;
m_digest[1] = 0xEFCDAB89;
m_digest[2] = 0x98BADCFE;
m_digest[3] = 0x10325476;
m_digest[4] = 0xC3D2E1F0;
m_blockByteIndex = 0;
m_byteCount = 0;
return *this;
}
SHA1& processByte(uint8_t octet) {
this->m_block[this->m_blockByteIndex++] = octet;
++this->m_byteCount;
if (m_blockByteIndex == 64) {
this->m_blockByteIndex = 0;
processBlock();
}
return *this;
}
SHA1& processBlock(const void* const start, const void* const end) {
const uint8_t* begin = static_cast<const uint8_t*>(start);
const uint8_t* finish = static_cast<const uint8_t*>(end);
while (begin != finish) {
processByte(*begin);
begin++;
}
return *this;
}
SHA1& processBytes(const void* const data, size_t len) {
const uint8_t* block = static_cast<const uint8_t*>(data);
processBlock(block, block + len);
return *this;
}
const uint32_t* getDigest(digest32_t digest) {
size_t bitCount = this->m_byteCount * 8;
processByte(0x80);
if (this->m_blockByteIndex > 56) {
while (m_blockByteIndex != 0) {
processByte(0);
}
while (m_blockByteIndex < 56) {
processByte(0);
}
} else {
while (m_blockByteIndex < 56) {
processByte(0);
}
}
processByte(0);
processByte(0);
processByte(0);
processByte(0);
processByte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
processByte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
processByte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
processByte(static_cast<unsigned char>((bitCount) & 0xFF));
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
return digest;
}
const uint8_t* getDigestBytes(digest8_t digest) {
digest32_t d32;
getDigest(d32);
size_t di = 0;
digest[di++] = ((d32[0] >> 24) & 0xFF);
digest[di++] = ((d32[0] >> 16) & 0xFF);
digest[di++] = ((d32[0] >> 8) & 0xFF);
digest[di++] = ((d32[0]) & 0xFF);
digest[di++] = ((d32[1] >> 24) & 0xFF);
digest[di++] = ((d32[1] >> 16) & 0xFF);
digest[di++] = ((d32[1] >> 8) & 0xFF);
digest[di++] = ((d32[1]) & 0xFF);
digest[di++] = ((d32[2] >> 24) & 0xFF);
digest[di++] = ((d32[2] >> 16) & 0xFF);
digest[di++] = ((d32[2] >> 8) & 0xFF);
digest[di++] = ((d32[2]) & 0xFF);
digest[di++] = ((d32[3] >> 24) & 0xFF);
digest[di++] = ((d32[3] >> 16) & 0xFF);
digest[di++] = ((d32[3] >> 8) & 0xFF);
digest[di++] = ((d32[3]) & 0xFF);
digest[di++] = ((d32[4] >> 24) & 0xFF);
digest[di++] = ((d32[4] >> 16) & 0xFF);
digest[di++] = ((d32[4] >> 8) & 0xFF);
digest[di++] = ((d32[4]) & 0xFF);
return digest;
}
protected:
void processBlock() {
uint32_t w[80];
for (size_t i = 0; i < 16; i++) {
w[i] = (m_block[i * 4 + 0] << 24);
w[i] |= (m_block[i * 4 + 1] << 16);
w[i] |= (m_block[i * 4 + 2] << 8);
w[i] |= (m_block[i * 4 + 3]);
}
for (size_t i = 16; i < 80; i++) {
w[i] = LeftRotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
}
uint32_t a = m_digest[0];
uint32_t b = m_digest[1];
uint32_t c = m_digest[2];
uint32_t d = m_digest[3];
uint32_t e = m_digest[4];
for (std::size_t i = 0; i < 80; ++i) {
uint32_t f = 0;
uint32_t k = 0;
if (i < 20) {
f = (b & c) | (~b & d);
k = 0x5A827999;
} else if (i < 40) {
f = b ^ c ^ d;
k = 0x6ED9EBA1;
} else if (i < 60) {
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
} else {
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
e = d;
d = c;
c = LeftRotate(b, 30);
b = a;
a = temp;
}
m_digest[0] += a;
m_digest[1] += b;
m_digest[2] += c;
m_digest[3] += d;
m_digest[4] += e;
}
private:
digest32_t m_digest;
uint8_t m_block[64];
size_t m_blockByteIndex;
size_t m_byteCount;
};
} // namespace sha1

View file

@ -8,7 +8,7 @@
namespace Common { namespace Common {
constexpr char VERSION[] = "0.6.1 WIP"; constexpr char VERSION[] = "0.7.1 WIP";
constexpr bool isRelease = false; constexpr bool isRelease = false;
} // namespace Common } // namespace Common

View file

@ -1,215 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include "crypto.h"
CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() {
CryptoPP::InvertibleRSAFunction params;
params.SetPrime1(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime1, 0x80));
params.SetPrime2(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime2, 0x80));
params.SetPublicExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PublicExponent, 4));
params.SetPrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PrivateExponent, 0x100));
params.SetModPrime1PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent1, 0x80));
params.SetModPrime2PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent2, 0x80));
params.SetModulus(CryptoPP::Integer(PkgDerivedKey3Keyset::Modulus, 0x100));
params.SetMultiplicativeInverseOfPrime2ModPrime1(
CryptoPP::Integer(PkgDerivedKey3Keyset::Coefficient, 0x80));
CryptoPP::RSA::PrivateKey privateKey(params);
return privateKey;
}
CryptoPP::RSA::PrivateKey Crypto::FakeKeyset_keyset_init() {
CryptoPP::InvertibleRSAFunction params;
params.SetPrime1(CryptoPP::Integer(FakeKeyset::Prime1, 0x80));
params.SetPrime2(CryptoPP::Integer(FakeKeyset::Prime2, 0x80));
params.SetPublicExponent(CryptoPP::Integer(FakeKeyset::PublicExponent, 4));
params.SetPrivateExponent(CryptoPP::Integer(FakeKeyset::PrivateExponent, 0x100));
params.SetModPrime1PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent1, 0x80));
params.SetModPrime2PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent2, 0x80));
params.SetModulus(CryptoPP::Integer(FakeKeyset::Modulus, 0x100));
params.SetMultiplicativeInverseOfPrime2ModPrime1(
CryptoPP::Integer(FakeKeyset::Coefficient, 0x80));
CryptoPP::RSA::PrivateKey privateKey(params);
return privateKey;
}
CryptoPP::RSA::PrivateKey Crypto::DebugRifKeyset_init() {
CryptoPP::InvertibleRSAFunction params;
params.SetPrime1(CryptoPP::Integer(DebugRifKeyset::Prime1, sizeof(DebugRifKeyset::Prime1)));
params.SetPrime2(CryptoPP::Integer(DebugRifKeyset::Prime2, sizeof(DebugRifKeyset::Prime2)));
params.SetPublicExponent(
CryptoPP::Integer(DebugRifKeyset::PublicExponent, sizeof(DebugRifKeyset::PublicExponent)));
params.SetPrivateExponent(CryptoPP::Integer(DebugRifKeyset::PrivateExponent,
sizeof(DebugRifKeyset::PrivateExponent)));
params.SetModPrime1PrivateExponent(
CryptoPP::Integer(DebugRifKeyset::Exponent1, sizeof(DebugRifKeyset::Exponent1)));
params.SetModPrime2PrivateExponent(
CryptoPP::Integer(DebugRifKeyset::Exponent2, sizeof(DebugRifKeyset::Exponent2)));
params.SetModulus(CryptoPP::Integer(DebugRifKeyset::Modulus, sizeof(DebugRifKeyset::Modulus)));
params.SetMultiplicativeInverseOfPrime2ModPrime1(
CryptoPP::Integer(DebugRifKeyset::Coefficient, sizeof(DebugRifKeyset::Coefficient)));
CryptoPP::RSA::PrivateKey privateKey(params);
return privateKey;
}
void Crypto::RSA2048Decrypt(std::span<CryptoPP::byte, 32> dec_key,
std::span<const CryptoPP::byte, 256> ciphertext,
bool is_dk3) { // RSAES_PKCS1v15_
// Create an RSA decryptor
CryptoPP::RSA::PrivateKey privateKey;
if (is_dk3) {
privateKey = key_pkg_derived_key3_keyset_init();
} else {
privateKey = FakeKeyset_keyset_init();
}
CryptoPP::RSAES_PKCS1v15_Decryptor rsaDecryptor(privateKey);
// Allocate memory for the decrypted data
std::array<CryptoPP::byte, 256> decrypted;
// Perform the decryption
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::DecodingResult result =
rsaDecryptor.Decrypt(rng, ciphertext.data(), decrypted.size(), decrypted.data());
std::copy(decrypted.begin(), decrypted.begin() + dec_key.size(), dec_key.begin());
}
void Crypto::ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
std::span<CryptoPP::byte, 32> ivkey_result) {
CryptoPP::SHA256 sha256;
std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> hashResult;
auto array_sink = new CryptoPP::ArraySink(hashResult.data(), CryptoPP::SHA256::DIGESTSIZE);
auto filter = new CryptoPP::HashFilter(sha256, array_sink);
CryptoPP::ArraySource r(cipher_input.data(), cipher_input.size(), true, filter);
std::copy(hashResult.begin(), hashResult.begin() + ivkey_result.size(), ivkey_result.begin());
}
void Crypto::aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
std::span<const CryptoPP::byte, 256> ciphertext,
std::span<CryptoPP::byte, 256> decrypted) {
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
CryptoPP::AES::BLOCKSIZE);
}
}
void Crypto::aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted) {
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
CryptoPP::AES::BLOCKSIZE);
}
}
void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
std::span<CryptoPP::byte, 16> NPcommID,
std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted) {
// step 1: Encrypt NPcommID
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
std::vector<CryptoPP::byte> trophyIv(16, 0);
std::vector<CryptoPP::byte> trpKey(16);
encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
// step 2: decrypt efsm.
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
decrypt.ProcessData(decrypted.data() + i, ciphertext.data() + i, CryptoPP::AES::BLOCKSIZE);
}
}
void Crypto::PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
std::span<const CryptoPP::byte, 16> seed,
std::span<CryptoPP::byte, 16> dataKey,
std::span<CryptoPP::byte, 16> tweakKey) {
CryptoPP::HMAC<CryptoPP::SHA256> hmac(ekpfs.data(), ekpfs.size());
CryptoPP::SecByteBlock d(20); // Use Crypto++ SecByteBlock for better memory management
// Copy the bytes of 'index' to the 'd' array
uint32_t index = 1;
std::memcpy(d, &index, sizeof(uint32_t));
// Copy the bytes of 'seed' to the 'd' array starting from index 4
std::memcpy(d + sizeof(uint32_t), seed.data(), seed.size());
// Allocate memory for 'u64' using new
std::vector<CryptoPP::byte> data_tweak_key(hmac.DigestSize());
// Calculate the HMAC
hmac.CalculateDigest(data_tweak_key.data(), d, d.size());
std::copy(data_tweak_key.begin(), data_tweak_key.begin() + dataKey.size(), tweakKey.begin());
std::copy(data_tweak_key.begin() + tweakKey.size(),
data_tweak_key.begin() + tweakKey.size() + dataKey.size(), dataKey.begin());
}
void Crypto::decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
std::span<CryptoPP::byte> dst_image, u64 sector) {
// Start at 0x10000 to keep the header when decrypting the whole pfs_image.
for (int i = 0; i < src_image.size(); i += 0x1000) {
const u64 current_sector = sector + (i / 0x1000);
CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption encrypt(tweakKey.data(), tweakKey.size());
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption decrypt(dataKey.data(), dataKey.size());
std::array<CryptoPP::byte, 16> tweak{};
std::array<CryptoPP::byte, 16> encryptedTweak;
std::array<CryptoPP::byte, 16> xorBuffer;
std::memcpy(tweak.data(), &current_sector, sizeof(u64));
// Encrypt the tweak for each sector.
encrypt.ProcessData(encryptedTweak.data(), tweak.data(), 16);
for (int plaintextOffset = 0; plaintextOffset < 0x1000; plaintextOffset += 16) {
xtsXorBlock(xorBuffer.data(), src_image.data() + i + plaintextOffset,
encryptedTweak.data()); // x, c, t
decrypt.ProcessData(xorBuffer.data(), xorBuffer.data(), 16); // x, x
xtsXorBlock(dst_image.data() + i + plaintextOffset, xorBuffer.data(),
encryptedTweak.data()); //(p) c, x , t
xtsMult(encryptedTweak);
}
}
}

View file

@ -1,63 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <span>
#include <cryptopp/aes.h>
#include <cryptopp/filters.h>
#include <cryptopp/modes.h>
#include <cryptopp/oaep.h>
#include <cryptopp/osrng.h>
#include <cryptopp/rsa.h>
#include <cryptopp/sha.h>
#include "common/types.h"
#include "keys.h"
class Crypto {
public:
CryptoPP::RSA::PrivateKey key_pkg_derived_key3_keyset_init();
CryptoPP::RSA::PrivateKey FakeKeyset_keyset_init();
CryptoPP::RSA::PrivateKey DebugRifKeyset_init();
void RSA2048Decrypt(std::span<CryptoPP::byte, 32> dk3,
std::span<const CryptoPP::byte, 256> ciphertext,
bool is_dk3); // RSAES_PKCS1v15_
void ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
std::span<CryptoPP::byte, 32> ivkey_result);
void aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
std::span<const CryptoPP::byte, 256> ciphertext,
std::span<CryptoPP::byte, 256> decrypted);
void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted);
void decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
std::span<CryptoPP::byte, 16> NPcommID, std::span<CryptoPP::byte, 16> efsmIv,
std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte> decrypted);
void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
std::span<const CryptoPP::byte, 16> seed,
std::span<CryptoPP::byte, 16> dataKey,
std::span<CryptoPP::byte, 16> tweakKey);
void decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
std::span<CryptoPP::byte> dst_image, u64 sector);
void xtsXorBlock(CryptoPP::byte* x, const CryptoPP::byte* a, const CryptoPP::byte* b) {
for (int i = 0; i < 16; i++) {
x[i] = a[i] ^ b[i];
}
}
void xtsMult(std::span<CryptoPP::byte, 16> encryptedTweak) {
int feedback = 0;
for (int k = 0; k < encryptedTweak.size(); k++) {
const auto tmp = (encryptedTweak[k] >> 7) & 1;
encryptedTweak[k] = ((encryptedTweak[k] << 1) + feedback) & 0xFF;
feedback = tmp;
}
if (feedback != 0) {
encryptedTweak[0] ^= 0x87;
}
}
};

View file

@ -1,305 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <cryptopp/rsa.h>
class FakeKeyset {
public:
// Constructor
static constexpr CryptoPP::byte Exponent1[] = {
0x6D, 0x48, 0xE0, 0x54, 0x40, 0x25, 0xC8, 0x41, 0x29, 0x52, 0x42, 0x27, 0xEB, 0xD2, 0xC7,
0xAB, 0x6B, 0x9C, 0x27, 0x0A, 0xB4, 0x1F, 0x94, 0x4E, 0xFA, 0x42, 0x1D, 0xB7, 0xBC, 0xB9,
0xAE, 0xBC, 0x04, 0x6F, 0x75, 0x8F, 0x10, 0x5F, 0x89, 0xAC, 0xAB, 0x9C, 0xD2, 0xFA, 0xE6,
0xA4, 0x13, 0x83, 0x68, 0xD4, 0x56, 0x38, 0xFE, 0xE5, 0x2B, 0x78, 0x44, 0x9C, 0x34, 0xE6,
0x5A, 0xA0, 0xBE, 0x05, 0x70, 0xAD, 0x15, 0xC3, 0x2D, 0x31, 0xAC, 0x97, 0x5D, 0x88, 0xFC,
0xC1, 0x62, 0x3D, 0xE2, 0xED, 0x11, 0xDB, 0xB6, 0x9E, 0xFC, 0x5A, 0x5A, 0x03, 0xF6, 0xCF,
0x08, 0xD4, 0x5D, 0x90, 0xC9, 0x2A, 0xB9, 0x9B, 0xCF, 0xC8, 0x1A, 0x65, 0xF3, 0x5B, 0xE8,
0x7F, 0xCF, 0xA5, 0xA6, 0x4C, 0x5C, 0x2A, 0x12, 0x0F, 0x92, 0xA5, 0xE3, 0xF0, 0x17, 0x1E,
0x9A, 0x97, 0x45, 0x86, 0xFD, 0xDB, 0x54, 0x25};
// exponent2 = d mod (q - 1)
static constexpr CryptoPP::byte Exponent2[] = {
0x2A, 0x51, 0xCE, 0x02, 0x44, 0x28, 0x50, 0xE8, 0x30, 0x20, 0x7C, 0x9C, 0x55, 0xBF, 0x60,
0x39, 0xBC, 0xD1, 0xF0, 0xE7, 0x68, 0xF8, 0x08, 0x5B, 0x61, 0x1F, 0xA7, 0xBF, 0xD0, 0xE8,
0x8B, 0xB5, 0xB1, 0xD5, 0xD9, 0x16, 0xAC, 0x75, 0x0C, 0x6D, 0xF2, 0xE0, 0xB5, 0x97, 0x75,
0xD2, 0x68, 0x16, 0x1F, 0x00, 0x7D, 0x8B, 0x17, 0xE8, 0x78, 0x48, 0x41, 0x71, 0x2B, 0x18,
0x96, 0x80, 0x11, 0xDB, 0x68, 0x39, 0x9C, 0xD6, 0xE0, 0x72, 0x42, 0x86, 0xF0, 0x1B, 0x16,
0x0D, 0x3E, 0x12, 0x94, 0x3D, 0x25, 0xA8, 0xA9, 0x30, 0x9E, 0x54, 0x5A, 0xD6, 0x36, 0x6C,
0xD6, 0x8C, 0x20, 0x62, 0x8F, 0xA1, 0x6B, 0x1F, 0x7C, 0x6D, 0xB2, 0xB1, 0xC1, 0x2E, 0xAD,
0x36, 0x02, 0x9C, 0x3A, 0xCA, 0x2F, 0x09, 0xD2, 0x45, 0x9E, 0xEB, 0xF2, 0xBC, 0x6C, 0xAA,
0x3B, 0x3E, 0x90, 0xBC, 0x38, 0x67, 0x35, 0x4D};
// e
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
// (InverseQ)(q) = 1 mod p
static constexpr CryptoPP::byte Coefficient[] = {
0x0B, 0x67, 0x1C, 0x0D, 0x6C, 0x57, 0xD3, 0xE7, 0x05, 0x65, 0x94, 0x31, 0x56, 0x55, 0xFD,
0x28, 0x08, 0xFA, 0x05, 0x8A, 0xCC, 0x55, 0x39, 0x61, 0x97, 0x63, 0xA0, 0x16, 0x27, 0x3D,
0xED, 0xC1, 0x16, 0x40, 0x2A, 0x12, 0xEA, 0x6F, 0xD9, 0xD8, 0x58, 0x56, 0xA8, 0x56, 0x8B,
0x0D, 0x38, 0x5E, 0x1E, 0x80, 0x3B, 0x5F, 0x40, 0x80, 0x6F, 0x62, 0x4F, 0x28, 0xA2, 0x69,
0xF3, 0xD3, 0xF7, 0xFD, 0xB2, 0xC3, 0x52, 0x43, 0x20, 0x92, 0x9D, 0x97, 0x8D, 0xA0, 0x15,
0x07, 0x15, 0x6E, 0xA4, 0x0D, 0x56, 0xD3, 0x37, 0x1A, 0xC4, 0x9E, 0xDF, 0x02, 0x49, 0xB8,
0x0A, 0x84, 0x62, 0xF5, 0xFA, 0xB9, 0x3F, 0xA4, 0x09, 0x76, 0xCC, 0xAA, 0xB9, 0x9B, 0xA6,
0x4F, 0xC1, 0x6A, 0x64, 0xCE, 0xD8, 0x77, 0xAB, 0x4B, 0xF9, 0xA0, 0xAE, 0xDA, 0xF1, 0x67,
0x87, 0x7C, 0x98, 0x5C, 0x7E, 0xB8, 0x73, 0xF5};
// n = p * q
static constexpr CryptoPP::byte Modulus[] = {
0xC6, 0xCF, 0x71, 0xE7, 0xE5, 0x9A, 0xF0, 0xD1, 0x2A, 0x2C, 0x45, 0x8B, 0xF9, 0x2A, 0x0E,
0xC1, 0x43, 0x05, 0x8B, 0xC3, 0x71, 0x17, 0x80, 0x1D, 0xCD, 0x49, 0x7D, 0xDE, 0x35, 0x9D,
0x25, 0x9B, 0xA0, 0xD7, 0xA0, 0xF2, 0x7D, 0x6C, 0x08, 0x7E, 0xAA, 0x55, 0x02, 0x68, 0x2B,
0x23, 0xC6, 0x44, 0xB8, 0x44, 0x18, 0xEB, 0x56, 0xCF, 0x16, 0xA2, 0x48, 0x03, 0xC9, 0xE7,
0x4F, 0x87, 0xEB, 0x3D, 0x30, 0xC3, 0x15, 0x88, 0xBF, 0x20, 0xE7, 0x9D, 0xFF, 0x77, 0x0C,
0xDE, 0x1D, 0x24, 0x1E, 0x63, 0xA9, 0x4F, 0x8A, 0xBF, 0x5B, 0xBE, 0x60, 0x19, 0x68, 0x33,
0x3B, 0xFC, 0xED, 0x9F, 0x47, 0x4E, 0x5F, 0xF8, 0xEA, 0xCB, 0x3D, 0x00, 0xBD, 0x67, 0x01,
0xF9, 0x2C, 0x6D, 0xC6, 0xAC, 0x13, 0x64, 0xE7, 0x67, 0x14, 0xF3, 0xDC, 0x52, 0x69, 0x6A,
0xB9, 0x83, 0x2C, 0x42, 0x30, 0x13, 0x1B, 0xB2, 0xD8, 0xA5, 0x02, 0x0D, 0x79, 0xED, 0x96,
0xB1, 0x0D, 0xF8, 0xCC, 0x0C, 0xDF, 0x81, 0x95, 0x4F, 0x03, 0x58, 0x09, 0x57, 0x0E, 0x80,
0x69, 0x2E, 0xFE, 0xFF, 0x52, 0x77, 0xEA, 0x75, 0x28, 0xA8, 0xFB, 0xC9, 0xBE, 0xBF, 0x9F,
0xBB, 0xB7, 0x79, 0x8E, 0x18, 0x05, 0xE1, 0x80, 0xBD, 0x50, 0x34, 0x94, 0x81, 0xD3, 0x53,
0xC2, 0x69, 0xA2, 0xD2, 0x4C, 0xCF, 0x6C, 0xF4, 0x57, 0x2C, 0x10, 0x4A, 0x3F, 0xFB, 0x22,
0xFD, 0x8B, 0x97, 0xE2, 0xC9, 0x5B, 0xA6, 0x2B, 0xCD, 0xD6, 0x1B, 0x6B, 0xDB, 0x68, 0x7F,
0x4B, 0xC2, 0xA0, 0x50, 0x34, 0xC0, 0x05, 0xE5, 0x8D, 0xEF, 0x24, 0x67, 0xFF, 0x93, 0x40,
0xCF, 0x2D, 0x62, 0xA2, 0xA0, 0x50, 0xB1, 0xF1, 0x3A, 0xA8, 0x3D, 0xFD, 0x80, 0xD1, 0xF9,
0xB8, 0x05, 0x22, 0xAF, 0xC8, 0x35, 0x45, 0x90, 0x58, 0x8E, 0xE3, 0x3A, 0x7C, 0xBD, 0x3E,
0x27};
// p
static constexpr CryptoPP::byte Prime1[] = {
0xFE, 0xF6, 0xBF, 0x1D, 0x69, 0xAB, 0x16, 0x25, 0x08, 0x47, 0x55, 0x6B, 0x86, 0xE4, 0x35,
0x88, 0x72, 0x2A, 0xB1, 0x3D, 0xF8, 0xB6, 0x44, 0xCA, 0xB3, 0xAB, 0x19, 0xD1, 0x04, 0x24,
0x28, 0x0A, 0x74, 0x55, 0xB8, 0x15, 0x45, 0x09, 0xCC, 0x13, 0x1C, 0xF2, 0xBA, 0x37, 0xA9,
0x03, 0x90, 0x8F, 0x02, 0x10, 0xFF, 0x25, 0x79, 0x86, 0xCC, 0x18, 0x50, 0x9A, 0x10, 0x5F,
0x5B, 0x4C, 0x1C, 0x4E, 0xB0, 0xA7, 0xE3, 0x59, 0xB1, 0x2D, 0xA0, 0xC6, 0xB0, 0x20, 0x2C,
0x21, 0x33, 0x12, 0xB3, 0xAF, 0x72, 0x34, 0x83, 0xCD, 0x52, 0x2F, 0xAF, 0x0F, 0x20, 0x5A,
0x1B, 0xC0, 0xE2, 0xA3, 0x76, 0x34, 0x0F, 0xD7, 0xFC, 0xC1, 0x41, 0xC9, 0xF9, 0x79, 0x40,
0x17, 0x42, 0x21, 0x3E, 0x9D, 0xFD, 0xC7, 0xC1, 0x50, 0xDE, 0x44, 0x5A, 0xC9, 0x31, 0x89,
0x6A, 0x78, 0x05, 0xBE, 0x65, 0xB4, 0xE8, 0x2D};
// q
static constexpr CryptoPP::byte Prime2[] = {
0xC7, 0x9E, 0x47, 0x58, 0x00, 0x7D, 0x62, 0x82, 0xB0, 0xD2, 0x22, 0x81, 0xD4, 0xA8, 0x97,
0x1B, 0x79, 0x0C, 0x3A, 0xB0, 0xD7, 0xC9, 0x30, 0xE3, 0xC3, 0x53, 0x8E, 0x57, 0xEF, 0xF0,
0x9B, 0x9F, 0xB3, 0x90, 0x52, 0xC6, 0x94, 0x22, 0x36, 0xAA, 0xE6, 0x4A, 0x5F, 0x72, 0x1D,
0x70, 0xE8, 0x76, 0x58, 0xC8, 0xB2, 0x91, 0xCE, 0x9C, 0xC3, 0xE9, 0x09, 0x7F, 0x2E, 0x47,
0x97, 0xCC, 0x90, 0x39, 0x15, 0x35, 0x31, 0xDE, 0x1F, 0x0C, 0x8C, 0x0D, 0xC1, 0xC2, 0x92,
0xBE, 0x97, 0xBF, 0x2F, 0x91, 0xA1, 0x8C, 0x7D, 0x50, 0xA8, 0x21, 0x2F, 0xD7, 0xA2, 0x9A,
0x7E, 0xB5, 0xA7, 0x2A, 0x90, 0x02, 0xD9, 0xF3, 0x3D, 0xD1, 0xEB, 0xB8, 0xE0, 0x5A, 0x79,
0x9E, 0x7D, 0x8D, 0xCA, 0x18, 0x6D, 0xBD, 0x9E, 0xA1, 0x80, 0x28, 0x6B, 0x2A, 0xFE, 0x51,
0x24, 0x9B, 0x6F, 0x4D, 0x84, 0x77, 0x80, 0x23};
static constexpr CryptoPP::byte PrivateExponent[] = {
0x7F, 0x76, 0xCD, 0x0E, 0xE2, 0xD4, 0xDE, 0x05, 0x1C, 0xC6, 0xD9, 0xA8, 0x0E, 0x8D, 0xFA,
0x7B, 0xCA, 0x1E, 0xAA, 0x27, 0x1A, 0x40, 0xF8, 0xF1, 0x22, 0x87, 0x35, 0xDD, 0xDB, 0xFD,
0xEE, 0xF8, 0xC2, 0xBC, 0xBD, 0x01, 0xFB, 0x8B, 0xE2, 0x3E, 0x63, 0xB2, 0xB1, 0x22, 0x5C,
0x56, 0x49, 0x6E, 0x11, 0xBE, 0x07, 0x44, 0x0B, 0x9A, 0x26, 0x66, 0xD1, 0x49, 0x2C, 0x8F,
0xD3, 0x1B, 0xCF, 0xA4, 0xA1, 0xB8, 0xD1, 0xFB, 0xA4, 0x9E, 0xD2, 0x21, 0x28, 0x83, 0x09,
0x8A, 0xF6, 0xA0, 0x0B, 0xA3, 0xD6, 0x0F, 0x9B, 0x63, 0x68, 0xCC, 0xBC, 0x0C, 0x4E, 0x14,
0x5B, 0x27, 0xA4, 0xA9, 0xF4, 0x2B, 0xB9, 0xB8, 0x7B, 0xC0, 0xE6, 0x51, 0xAD, 0x1D, 0x77,
0xD4, 0x6B, 0xB9, 0xCE, 0x20, 0xD1, 0x26, 0x66, 0x7E, 0x5E, 0x9E, 0xA2, 0xE9, 0x6B, 0x90,
0xF3, 0x73, 0xB8, 0x52, 0x8F, 0x44, 0x11, 0x03, 0x0C, 0x13, 0x97, 0x39, 0x3D, 0x13, 0x22,
0x58, 0xD5, 0x43, 0x82, 0x49, 0xDA, 0x6E, 0x7C, 0xA1, 0xC5, 0x8C, 0xA5, 0xB0, 0x09, 0xE0,
0xCE, 0x3D, 0xDF, 0xF4, 0x9D, 0x3C, 0x97, 0x15, 0xE2, 0x6A, 0xC7, 0x2B, 0x3C, 0x50, 0x93,
0x23, 0xDB, 0xBA, 0x4A, 0x22, 0x66, 0x44, 0xAC, 0x78, 0xBB, 0x0E, 0x1A, 0x27, 0x43, 0xB5,
0x71, 0x67, 0xAF, 0xF4, 0xAB, 0x48, 0x46, 0x93, 0x73, 0xD0, 0x42, 0xAB, 0x93, 0x63, 0xE5,
0x6C, 0x9A, 0xDE, 0x50, 0x24, 0xC0, 0x23, 0x7D, 0x99, 0x79, 0x3F, 0x22, 0x07, 0xE0, 0xC1,
0x48, 0x56, 0x1B, 0xDF, 0x83, 0x09, 0x12, 0xB4, 0x2D, 0x45, 0x6B, 0xC9, 0xC0, 0x68, 0x85,
0x99, 0x90, 0x79, 0x96, 0x1A, 0xD7, 0xF5, 0x4D, 0x1F, 0x37, 0x83, 0x40, 0x4A, 0xEC, 0x39,
0x37, 0xA6, 0x80, 0x92, 0x7D, 0xC5, 0x80, 0xC7, 0xD6, 0x6F, 0xFE, 0x8A, 0x79, 0x89, 0xC6,
0xB1};
};
class DebugRifKeyset {
public:
// std::uint8_t* PrivateExponent;
static constexpr CryptoPP::byte Exponent1[] = {
0xCD, 0x9A, 0x61, 0xB0, 0xB8, 0xD5, 0xB4, 0xE4, 0xE4, 0xF6, 0xAB, 0xF7, 0x27, 0xB7, 0x56,
0x59, 0x6B, 0xB9, 0x11, 0xE7, 0xF4, 0x83, 0xAF, 0xB9, 0x73, 0x99, 0x7F, 0x49, 0xA2, 0x9C,
0xF0, 0xB5, 0x6D, 0x37, 0x82, 0x14, 0x15, 0xF1, 0x04, 0x8A, 0xD4, 0x8E, 0xEB, 0x2E, 0x1F,
0xE2, 0x81, 0xA9, 0x62, 0x6E, 0xB1, 0x68, 0x75, 0x62, 0xF3, 0x0F, 0xFE, 0xD4, 0x91, 0x87,
0x98, 0x78, 0xBF, 0x26, 0xB5, 0x07, 0x58, 0xD0, 0xEE, 0x3F, 0x21, 0xE8, 0xC8, 0x0F, 0x5F,
0xFA, 0x1C, 0x64, 0x74, 0x49, 0x52, 0xEB, 0xE7, 0xEE, 0xDE, 0xBA, 0x23, 0x26, 0x4A, 0xF6,
0x9C, 0x1A, 0x09, 0x3F, 0xB9, 0x0B, 0x36, 0x26, 0x1A, 0xBE, 0xA9, 0x76, 0xE6, 0xF2, 0x69,
0xDE, 0xFF, 0xAF, 0xCC, 0x0C, 0x9A, 0x66, 0x03, 0x86, 0x0A, 0x1F, 0x49, 0xA4, 0x10, 0xB6,
0xBC, 0xC3, 0x7C, 0x88, 0xE8, 0xCE, 0x4B, 0xD9};
// exponent2 = d mod (q - 1)
static constexpr CryptoPP::byte Exponent2[] = {
0xB3, 0x73, 0xA3, 0x59, 0xE6, 0x97, 0xC0, 0xAB, 0x3B, 0x68, 0xFC, 0x39, 0xAC, 0xDB, 0x44,
0xB1, 0xB4, 0x9E, 0x35, 0x4D, 0xBE, 0xC5, 0x36, 0x69, 0x6C, 0x3D, 0xC5, 0xFC, 0xFE, 0x4B,
0x2F, 0xDC, 0x86, 0x80, 0x46, 0x96, 0x40, 0x1A, 0x0D, 0x6E, 0xFA, 0x8C, 0xE0, 0x47, 0x91,
0xAC, 0xAD, 0x95, 0x2B, 0x8E, 0x1F, 0xF2, 0x0A, 0x45, 0xF8, 0x29, 0x95, 0x70, 0xC6, 0x88,
0x5F, 0x71, 0x03, 0x99, 0x79, 0xBC, 0x84, 0x71, 0xBD, 0xE8, 0x84, 0x8C, 0x0E, 0xD4, 0x7B,
0x30, 0x74, 0x57, 0x1A, 0x95, 0xE7, 0x90, 0x19, 0x8D, 0xAD, 0x8B, 0x4C, 0x4E, 0xC3, 0xE7,
0x6B, 0x23, 0x86, 0x01, 0xEE, 0x9B, 0xE0, 0x2F, 0x15, 0xA2, 0x2C, 0x4C, 0x39, 0xD3, 0xDF,
0x9C, 0x39, 0x01, 0xF1, 0x8C, 0x44, 0x4A, 0x15, 0x44, 0xDC, 0x51, 0xF7, 0x22, 0xD7, 0x7F,
0x41, 0x7F, 0x68, 0xFA, 0xEE, 0x56, 0xE8, 0x05};
// e
static constexpr CryptoPP::byte PublicExponent[] = {0x00, 0x01, 0x00, 0x01};
// (InverseQ)(q) = 1 mod p
static constexpr CryptoPP::byte Coefficient[] = {
0xC0, 0x32, 0x43, 0xD3, 0x8C, 0x3D, 0xB4, 0xD2, 0x48, 0x8C, 0x42, 0x41, 0x24, 0x94, 0x6C,
0x80, 0xC9, 0xC1, 0x79, 0x36, 0x7F, 0xAC, 0xC3, 0xFF, 0x6A, 0x25, 0xEB, 0x2C, 0xFB, 0xD4,
0x2B, 0xA0, 0xEB, 0xFE, 0x25, 0xE9, 0xC6, 0x77, 0xCE, 0xFE, 0x2D, 0x23, 0xFE, 0xD0, 0xF4,
0x0F, 0xD9, 0x7E, 0xD5, 0xA5, 0x7D, 0x1F, 0xC0, 0xE8, 0xE8, 0xEC, 0x80, 0x5B, 0xC7, 0xFD,
0xE2, 0xBD, 0x94, 0xA6, 0x2B, 0xDD, 0x6A, 0x60, 0x45, 0x54, 0xAB, 0xCA, 0x42, 0x9C, 0x6A,
0x6C, 0xBF, 0x3C, 0x84, 0xF9, 0xA5, 0x0E, 0x63, 0x0C, 0x51, 0x58, 0x62, 0x6D, 0x5A, 0xB7,
0x3C, 0x3F, 0x49, 0x1A, 0xD0, 0x93, 0xB8, 0x4F, 0x1A, 0x6C, 0x5F, 0xC5, 0xE5, 0xA9, 0x75,
0xD4, 0x86, 0x9E, 0xDF, 0x87, 0x0F, 0x27, 0xB0, 0x26, 0x78, 0x4E, 0xFB, 0xC1, 0x8A, 0x4A,
0x24, 0x3F, 0x7F, 0x8F, 0x9A, 0x12, 0x51, 0xCB};
// n = p * q
static constexpr CryptoPP::byte Modulus[] = {
0xC2, 0xD2, 0x44, 0xBC, 0xDD, 0x84, 0x3F, 0xD9, 0xC5, 0x22, 0xAF, 0xF7, 0xFC, 0x88, 0x8A,
0x33, 0x80, 0xED, 0x8E, 0xE2, 0xCC, 0x81, 0xF7, 0xEC, 0xF8, 0x1C, 0x79, 0xBF, 0x02, 0xBB,
0x12, 0x8E, 0x61, 0x68, 0x29, 0x1B, 0x15, 0xB6, 0x5E, 0xC6, 0xF8, 0xBF, 0x5A, 0xE0, 0x3B,
0x6A, 0x6C, 0xD9, 0xD6, 0xF5, 0x75, 0xAB, 0xA0, 0x6F, 0x34, 0x81, 0x34, 0x9A, 0x5B, 0xAD,
0xED, 0x31, 0xE3, 0xC6, 0xEA, 0x1A, 0xD1, 0x13, 0x22, 0xBB, 0xB3, 0xDA, 0xB3, 0xB2, 0x53,
0xBD, 0x45, 0x79, 0x87, 0xAD, 0x0A, 0x01, 0x72, 0x18, 0x10, 0x29, 0x49, 0xF4, 0x41, 0x7F,
0xD6, 0x47, 0x0C, 0x72, 0x92, 0x9E, 0xE9, 0xBB, 0x95, 0xA9, 0x5D, 0x79, 0xEB, 0xE4, 0x30,
0x76, 0x90, 0x45, 0x4B, 0x9D, 0x9C, 0xCF, 0x92, 0x03, 0x60, 0x8C, 0x4B, 0x6C, 0xB3, 0x7A,
0x3A, 0x05, 0x39, 0xA0, 0x66, 0xA9, 0x35, 0xCF, 0xB9, 0xFA, 0xAD, 0x9C, 0xAB, 0xEB, 0xE4,
0x6A, 0x8C, 0xE9, 0x3B, 0xCC, 0x72, 0x12, 0x62, 0x63, 0xBD, 0x80, 0xC4, 0xEE, 0x37, 0x2B,
0x32, 0x03, 0xA3, 0x09, 0xF7, 0xA0, 0x61, 0x57, 0xAD, 0x0D, 0xCF, 0x15, 0x98, 0x9E, 0x4E,
0x49, 0xF8, 0xB5, 0xA3, 0x5C, 0x27, 0xEE, 0x45, 0x04, 0xEA, 0xE4, 0x4B, 0xBC, 0x8F, 0x87,
0xED, 0x19, 0x1E, 0x46, 0x75, 0x63, 0xC4, 0x5B, 0xD5, 0xBC, 0x09, 0x2F, 0x02, 0x73, 0x19,
0x3C, 0x58, 0x55, 0x49, 0x66, 0x4C, 0x11, 0xEC, 0x0F, 0x09, 0xFA, 0xA5, 0x56, 0x0A, 0x5A,
0x63, 0x56, 0xAD, 0xA0, 0x0D, 0x86, 0x08, 0xC1, 0xE6, 0xB6, 0x13, 0x22, 0x49, 0x2F, 0x7C,
0xDB, 0x4C, 0x56, 0x97, 0x0E, 0xC2, 0xD9, 0x2E, 0x87, 0xBC, 0x0E, 0x67, 0xC0, 0x1B, 0x58,
0xBC, 0x64, 0x2B, 0xC2, 0x6E, 0xE2, 0x93, 0x2E, 0xB5, 0x6B, 0x70, 0xA4, 0x42, 0x9F, 0x64,
0xC1};
// p
static constexpr CryptoPP::byte Prime1[] = {
0xE5, 0x62, 0xE1, 0x7F, 0x9F, 0x86, 0x08, 0xE2, 0x61, 0xD3, 0xD0, 0x42, 0xE2, 0xC4, 0xB6,
0xA8, 0x51, 0x09, 0x19, 0x14, 0xA4, 0x3A, 0x11, 0x4C, 0x33, 0xA5, 0x9C, 0x01, 0x5E, 0x34,
0xB6, 0x3F, 0x02, 0x1A, 0xCA, 0x47, 0xF1, 0x4F, 0x3B, 0x35, 0x2A, 0x07, 0x20, 0xEC, 0xD8,
0xC1, 0x15, 0xD9, 0xCA, 0x03, 0x4F, 0xB8, 0xE8, 0x09, 0x73, 0x3F, 0x85, 0xB7, 0x41, 0xD5,
0x51, 0x3E, 0x7B, 0xE3, 0x53, 0x2B, 0x48, 0x8B, 0x8E, 0xCB, 0xBA, 0xF7, 0xE0, 0x60, 0xF5,
0x35, 0x0E, 0x6F, 0xB0, 0xD9, 0x2A, 0x99, 0xD0, 0xFF, 0x60, 0x14, 0xED, 0x40, 0xEA, 0xF8,
0xD7, 0x0B, 0xC3, 0x8D, 0x8C, 0xE8, 0x81, 0xB3, 0x75, 0x93, 0x15, 0xB3, 0x7D, 0xF6, 0x39,
0x60, 0x1A, 0x00, 0xE7, 0xC3, 0x27, 0xAD, 0xA4, 0x33, 0xD5, 0x3E, 0xA4, 0x35, 0x48, 0x6F,
0x22, 0xEF, 0x5D, 0xDD, 0x7D, 0x7B, 0x61, 0x05};
// q
static constexpr CryptoPP::byte Prime2[] = {
0xD9, 0x6C, 0xC2, 0x0C, 0xF7, 0xAE, 0xD1, 0xF3, 0x3B, 0x3B, 0x49, 0x1E, 0x9F, 0x12, 0x9C,
0xA1, 0x78, 0x1F, 0x35, 0x1D, 0x98, 0x26, 0x13, 0x71, 0xF9, 0x09, 0xFD, 0xF0, 0xAD, 0x38,
0x55, 0xB7, 0xEE, 0x61, 0x04, 0x72, 0x51, 0x87, 0x2E, 0x05, 0x84, 0xB1, 0x1D, 0x0C, 0x0D,
0xDB, 0xD4, 0x25, 0x3E, 0x26, 0xED, 0xEA, 0xB8, 0xF7, 0x49, 0xFE, 0xA2, 0x94, 0xE6, 0xF2,
0x08, 0x92, 0xA7, 0x85, 0xF5, 0x30, 0xB9, 0x84, 0x22, 0xBF, 0xCA, 0xF0, 0x5F, 0xCB, 0x31,
0x20, 0x34, 0x49, 0x16, 0x76, 0x34, 0xCC, 0x7A, 0xCB, 0x96, 0xFE, 0x78, 0x7A, 0x41, 0xFE,
0x9A, 0xA2, 0x23, 0xF7, 0x68, 0x80, 0xD6, 0xCE, 0x4A, 0x78, 0xA5, 0xB7, 0x05, 0x77, 0x81,
0x1F, 0xDE, 0x5E, 0xA8, 0x6E, 0x3E, 0x87, 0xEC, 0x44, 0xD2, 0x69, 0xC6, 0x54, 0x91, 0x6B,
0x5E, 0x13, 0x8A, 0x03, 0x87, 0x05, 0x31, 0x8D};
static constexpr CryptoPP::byte PrivateExponent[] = {
0x01, 0x61, 0xAD, 0xD8, 0x9C, 0x06, 0x89, 0xD0, 0x60, 0xC8, 0x41, 0xF0, 0xB3, 0x83, 0x01,
0x5D, 0xE3, 0xA2, 0x6B, 0xA2, 0xBA, 0x9A, 0x0A, 0x58, 0xCD, 0x1A, 0xA0, 0x97, 0x64, 0xEC,
0xD0, 0x31, 0x1F, 0xCA, 0x36, 0x0E, 0x69, 0xDD, 0x40, 0xF7, 0x4E, 0xC0, 0xC6, 0xA3, 0x73,
0xF0, 0x69, 0x84, 0xB2, 0xF4, 0x4B, 0x29, 0x14, 0x2A, 0x6D, 0xB8, 0x23, 0xD8, 0x1B, 0x61,
0xD4, 0x9E, 0x87, 0xB3, 0xBB, 0xA9, 0xC4, 0x85, 0x4A, 0xF8, 0x03, 0x4A, 0xBF, 0xFE, 0xF9,
0xFE, 0x8B, 0xDD, 0x54, 0x83, 0xBA, 0xE0, 0x2F, 0x3F, 0xB1, 0xEF, 0xA5, 0x05, 0x5D, 0x28,
0x8B, 0xAB, 0xB5, 0xD0, 0x23, 0x2F, 0x8A, 0xCF, 0x48, 0x7C, 0xAA, 0xBB, 0xC8, 0x5B, 0x36,
0x27, 0xC5, 0x16, 0xA4, 0xB6, 0x61, 0xAC, 0x0C, 0x28, 0x47, 0x79, 0x3F, 0x38, 0xAE, 0x5E,
0x25, 0xC6, 0xAF, 0x35, 0xAE, 0xBC, 0xB0, 0xF3, 0xBC, 0xBD, 0xFD, 0xA4, 0x87, 0x0D, 0x14,
0x3D, 0x90, 0xE4, 0xDE, 0x5D, 0x1D, 0x46, 0x81, 0xF1, 0x28, 0x6D, 0x2F, 0x2C, 0x5E, 0x97,
0x2D, 0x89, 0x2A, 0x51, 0x72, 0x3C, 0x20, 0x02, 0x59, 0xB1, 0x98, 0x93, 0x05, 0x1E, 0x3F,
0xA1, 0x8A, 0x69, 0x30, 0x0E, 0x70, 0x84, 0x8B, 0xAE, 0x97, 0xA1, 0x08, 0x95, 0x63, 0x4C,
0xC7, 0xE8, 0x5D, 0x59, 0xCA, 0x78, 0x2A, 0x23, 0x87, 0xAC, 0x6F, 0x04, 0x33, 0xB1, 0x61,
0xB9, 0xF0, 0x95, 0xDA, 0x33, 0xCC, 0xE0, 0x4C, 0x82, 0x68, 0x82, 0x14, 0x51, 0xBE, 0x49,
0x1C, 0x58, 0xA2, 0x8B, 0x05, 0x4E, 0x98, 0x37, 0xEB, 0x94, 0x0B, 0x01, 0x22, 0xDC, 0xB3,
0x19, 0xCA, 0x77, 0xA6, 0x6E, 0x97, 0xFF, 0x8A, 0x53, 0x5A, 0xC5, 0x24, 0xE4, 0xAF, 0x6E,
0xA8, 0x2B, 0x53, 0xA4, 0xBE, 0x96, 0xA5, 0x7B, 0xCE, 0x22, 0x56, 0xA3, 0xF1, 0xCF, 0x14,
0xA5};
};
class PkgDerivedKey3Keyset {
public:
// std::uint8_t* PrivateExponent;
static constexpr CryptoPP::byte Exponent1[] = {
0x52, 0xCC, 0x2D, 0xA0, 0x9C, 0x9E, 0x75, 0xE7, 0x28, 0xEE, 0x3D, 0xDE, 0xE3, 0x45, 0xD1,
0x4F, 0x94, 0x1C, 0xCC, 0xC8, 0x87, 0x29, 0x45, 0x3B, 0x8D, 0x6E, 0xAB, 0x6E, 0x2A, 0xA7,
0xC7, 0x15, 0x43, 0xA3, 0x04, 0x8F, 0x90, 0x5F, 0xEB, 0xF3, 0x38, 0x4A, 0x77, 0xFA, 0x36,
0xB7, 0x15, 0x76, 0xB6, 0x01, 0x1A, 0x8E, 0x25, 0x87, 0x82, 0xF1, 0x55, 0xD8, 0xC6, 0x43,
0x2A, 0xC0, 0xE5, 0x98, 0xC9, 0x32, 0xD1, 0x94, 0x6F, 0xD9, 0x01, 0xBA, 0x06, 0x81, 0xE0,
0x6D, 0x88, 0xF2, 0x24, 0x2A, 0x25, 0x01, 0x64, 0x5C, 0xBF, 0xF2, 0xD9, 0x99, 0x67, 0x3E,
0xF6, 0x72, 0xEE, 0xE4, 0xE2, 0x33, 0x5C, 0xF8, 0x00, 0x40, 0xE3, 0x2A, 0x9A, 0xF4, 0x3D,
0x22, 0x86, 0x44, 0x3C, 0xFB, 0x0A, 0xA5, 0x7C, 0x3F, 0xCC, 0xF5, 0xF1, 0x16, 0xC4, 0xAC,
0x88, 0xB4, 0xDE, 0x62, 0x94, 0x92, 0x6A, 0x13};
// exponent2 = d mod (q - 1)
static constexpr CryptoPP::byte Exponent2[] = {
0x7C, 0x9D, 0xAD, 0x39, 0xE0, 0xD5, 0x60, 0x14, 0x94, 0x48, 0x19, 0x7F, 0x88, 0x95, 0xD5,
0x8B, 0x80, 0xAD, 0x85, 0x8A, 0x4B, 0x77, 0x37, 0x85, 0xD0, 0x77, 0xBB, 0xBF, 0x89, 0x71,
0x4A, 0x72, 0xCB, 0x72, 0x68, 0x38, 0xEC, 0x02, 0xC6, 0x7D, 0xC6, 0x44, 0x06, 0x33, 0x51,
0x1C, 0xC0, 0xFF, 0x95, 0x8F, 0x0D, 0x75, 0xDC, 0x25, 0xBB, 0x0B, 0x73, 0x91, 0xA9, 0x6D,
0x42, 0xD8, 0x03, 0xB7, 0x68, 0xD4, 0x1E, 0x75, 0x62, 0xA3, 0x70, 0x35, 0x79, 0x78, 0x00,
0xC8, 0xF5, 0xEF, 0x15, 0xB9, 0xFC, 0x4E, 0x47, 0x5A, 0xC8, 0x70, 0x70, 0x5B, 0x52, 0x98,
0xC0, 0xC2, 0x58, 0x4A, 0x70, 0x96, 0xCC, 0xB8, 0x10, 0xE1, 0x2F, 0x78, 0x8B, 0x2B, 0xA1,
0x7F, 0xF9, 0xAC, 0xDE, 0xF0, 0xBB, 0x2B, 0xE2, 0x66, 0xE3, 0x22, 0x92, 0x31, 0x21, 0x57,
0x92, 0xC4, 0xB8, 0xF2, 0x3E, 0x76, 0x20, 0x37};
// e
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
// (InverseQ)(q) = 1 mod p
static constexpr CryptoPP::byte Coefficient[] = {
0x45, 0x97, 0x55, 0xD4, 0x22, 0x08, 0x5E, 0xF3, 0x5C, 0xB4, 0x05, 0x7A, 0xFD, 0xAA, 0x42,
0x42, 0xAD, 0x9A, 0x8C, 0xA0, 0x6C, 0xBB, 0x1D, 0x68, 0x54, 0x54, 0x6E, 0x3E, 0x32, 0xE3,
0x53, 0x73, 0x76, 0xF1, 0x3E, 0x01, 0xEA, 0xD3, 0xCF, 0xEB, 0xEB, 0x23, 0x3E, 0xC0, 0xBE,
0xCE, 0xEC, 0x2C, 0x89, 0x5F, 0xA8, 0x27, 0x3A, 0x4C, 0xB7, 0xE6, 0x74, 0xBC, 0x45, 0x4C,
0x26, 0xC8, 0x25, 0xFF, 0x34, 0x63, 0x25, 0x37, 0xE1, 0x48, 0x10, 0xC1, 0x93, 0xA6, 0xAF,
0xEB, 0xBA, 0xE3, 0xA2, 0xF1, 0x3D, 0xEF, 0x63, 0xD8, 0xF4, 0xFD, 0xD3, 0xEE, 0xE2, 0x5D,
0xE9, 0x33, 0xCC, 0xAD, 0xBA, 0x75, 0x5C, 0x85, 0xAF, 0xCE, 0xA9, 0x3D, 0xD1, 0xA2, 0x17,
0xF3, 0xF6, 0x98, 0xB3, 0x50, 0x8E, 0x5E, 0xF6, 0xEB, 0x02, 0x8E, 0xA1, 0x62, 0xA7, 0xD6,
0x2C, 0xEC, 0x91, 0xFF, 0x15, 0x40, 0xD2, 0xE3};
// n = p * q
static constexpr CryptoPP::byte Modulus[] = {
0xd2, 0x12, 0xfc, 0x33, 0x5f, 0x6d, 0xdb, 0x83, 0x16, 0x09, 0x62, 0x8b, 0x03, 0x56, 0x27,
0x37, 0x82, 0xd4, 0x77, 0x85, 0x35, 0x29, 0x39, 0x2d, 0x52, 0x6b, 0x8c, 0x4c, 0x8c, 0xfb,
0x06, 0xc1, 0x84, 0x5b, 0xe7, 0xd4, 0xf7, 0xbc, 0xd2, 0x4e, 0x62, 0x45, 0xcd, 0x2a, 0xbb,
0xd7, 0x77, 0x76, 0x45, 0x36, 0x55, 0x27, 0x3f, 0xb3, 0xf5, 0xf9, 0x8e, 0xda, 0x4b, 0xef,
0xaa, 0x59, 0xae, 0xb3, 0x9b, 0xea, 0x54, 0x98, 0xd2, 0x06, 0x32, 0x6a, 0x58, 0x31, 0x2a,
0xe0, 0xd4, 0x4f, 0x90, 0xb5, 0x0a, 0x7d, 0xec, 0xf4, 0x3a, 0x9c, 0x52, 0x67, 0x2d, 0x99,
0x31, 0x8e, 0x0c, 0x43, 0xe6, 0x82, 0xfe, 0x07, 0x46, 0xe1, 0x2e, 0x50, 0xd4, 0x1f, 0x2d,
0x2f, 0x7e, 0xd9, 0x08, 0xba, 0x06, 0xb3, 0xbf, 0x2e, 0x20, 0x3f, 0x4e, 0x3f, 0xfe, 0x44,
0xff, 0xaa, 0x50, 0x43, 0x57, 0x91, 0x69, 0x94, 0x49, 0x15, 0x82, 0x82, 0xe4, 0x0f, 0x4c,
0x8d, 0x9d, 0x2c, 0xc9, 0x5b, 0x1d, 0x64, 0xbf, 0x88, 0x8b, 0xd4, 0xc5, 0x94, 0xe7, 0x65,
0x47, 0x84, 0x1e, 0xe5, 0x79, 0x10, 0xfb, 0x98, 0x93, 0x47, 0xb9, 0x7d, 0x85, 0x12, 0xa6,
0x40, 0x98, 0x2c, 0xf7, 0x92, 0xbc, 0x95, 0x19, 0x32, 0xed, 0xe8, 0x90, 0x56, 0x0d, 0x65,
0xc1, 0xaa, 0x78, 0xc6, 0x2e, 0x54, 0xfd, 0x5f, 0x54, 0xa1, 0xf6, 0x7e, 0xe5, 0xe0, 0x5f,
0x61, 0xc1, 0x20, 0xb4, 0xb9, 0xb4, 0x33, 0x08, 0x70, 0xe4, 0xdf, 0x89, 0x56, 0xed, 0x01,
0x29, 0x46, 0x77, 0x5f, 0x8c, 0xb8, 0xa9, 0xf5, 0x1e, 0x2e, 0xb3, 0xb9, 0xbf, 0xe0, 0x09,
0xb7, 0x8d, 0x28, 0xd4, 0xa6, 0xc3, 0xb8, 0x1e, 0x1f, 0x07, 0xeb, 0xb4, 0x12, 0x0b, 0x95,
0xb8, 0x85, 0x30, 0xfd, 0xdc, 0x39, 0x13, 0xd0, 0x7c, 0xdc, 0x8f, 0xed, 0xf9, 0xc9, 0xa3,
0xc1};
// p
static constexpr CryptoPP::byte Prime1[] = {
0xF9, 0x67, 0xAD, 0x99, 0x12, 0x31, 0x0C, 0x56, 0xA2, 0x2E, 0x16, 0x1C, 0x46, 0xB3, 0x4D,
0x5B, 0x43, 0xBE, 0x42, 0xA2, 0xF6, 0x86, 0x96, 0x80, 0x42, 0xC3, 0xC7, 0x3F, 0xC3, 0x42,
0xF5, 0x87, 0x49, 0x33, 0x9F, 0x07, 0x5D, 0x6E, 0x2C, 0x04, 0xFD, 0xE3, 0xE1, 0xB2, 0xAE,
0x0A, 0x0C, 0xF0, 0xC7, 0xA6, 0x1C, 0xA1, 0x63, 0x50, 0xC8, 0x09, 0x9C, 0x51, 0x24, 0x52,
0x6C, 0x5E, 0x5E, 0xBD, 0x1E, 0x27, 0x06, 0xBB, 0xBC, 0x9E, 0x94, 0xE1, 0x35, 0xD4, 0x6D,
0xB3, 0xCB, 0x3C, 0x68, 0xDD, 0x68, 0xB3, 0xFE, 0x6C, 0xCB, 0x8D, 0x82, 0x20, 0x76, 0x23,
0x63, 0xB7, 0xE9, 0x68, 0x10, 0x01, 0x4E, 0xDC, 0xBA, 0x27, 0x5D, 0x01, 0xC1, 0x2D, 0x80,
0x5E, 0x2B, 0xAF, 0x82, 0x6B, 0xD8, 0x84, 0xB6, 0x10, 0x52, 0x86, 0xA7, 0x89, 0x8E, 0xAE,
0x9A, 0xE2, 0x89, 0xC6, 0xF7, 0xD5, 0x87, 0xFB};
// q
static constexpr CryptoPP::byte Prime2[] = {
0xD7, 0xA1, 0x0F, 0x9A, 0x8B, 0xF2, 0xC9, 0x11, 0x95, 0x32, 0x9A, 0x8C, 0xF0, 0xD9, 0x40,
0x47, 0xF5, 0x68, 0xA0, 0x0D, 0xBD, 0xC1, 0xFC, 0x43, 0x2F, 0x65, 0xF9, 0xC3, 0x61, 0x0F,
0x25, 0x77, 0x54, 0xAD, 0xD7, 0x58, 0xAC, 0x84, 0x40, 0x60, 0x8D, 0x3F, 0xF3, 0x65, 0x89,
0x75, 0xB5, 0xC6, 0x2C, 0x51, 0x1A, 0x2F, 0x1F, 0x22, 0xE4, 0x43, 0x11, 0x54, 0xBE, 0xC9,
0xB4, 0xC7, 0xB5, 0x1B, 0x05, 0x0B, 0xBC, 0x56, 0x9A, 0xCD, 0x4A, 0xD9, 0x73, 0x68, 0x5E,
0x5C, 0xFB, 0x92, 0xB7, 0x8B, 0x0D, 0xFF, 0xF5, 0x07, 0xCA, 0xB4, 0xC8, 0x9B, 0x96, 0x3C,
0x07, 0x9E, 0x3E, 0x6B, 0x2A, 0x11, 0xF2, 0x8A, 0xB1, 0x8A, 0xD7, 0x2E, 0x1B, 0xA5, 0x53,
0x24, 0x06, 0xED, 0x50, 0xB8, 0x90, 0x67, 0xB1, 0xE2, 0x41, 0xC6, 0x92, 0x01, 0xEE, 0x10,
0xF0, 0x61, 0xBB, 0xFB, 0xB2, 0x7D, 0x4A, 0x73};
static constexpr CryptoPP::byte PrivateExponent[] = {
0x32, 0xD9, 0x03, 0x90, 0x8F, 0xBD, 0xB0, 0x8F, 0x57, 0x2B, 0x28, 0x5E, 0x0B, 0x8D, 0xB3,
0xEA, 0x5C, 0xD1, 0x7E, 0xA8, 0x90, 0x88, 0x8C, 0xDD, 0x6A, 0x80, 0xBB, 0xB1, 0xDF, 0xC1,
0xF7, 0x0D, 0xAA, 0x32, 0xF0, 0xB7, 0x7C, 0xCB, 0x88, 0x80, 0x0E, 0x8B, 0x64, 0xB0, 0xBE,
0x4C, 0xD6, 0x0E, 0x9B, 0x8C, 0x1E, 0x2A, 0x64, 0xE1, 0xF3, 0x5C, 0xD7, 0x76, 0x01, 0x41,
0x5E, 0x93, 0x5C, 0x94, 0xFE, 0xDD, 0x46, 0x62, 0xC3, 0x1B, 0x5A, 0xE2, 0xA0, 0xBC, 0x2D,
0xEB, 0xC3, 0x98, 0x0A, 0xA7, 0xB7, 0x85, 0x69, 0x70, 0x68, 0x2B, 0x64, 0x4A, 0xB3, 0x1F,
0xCC, 0x7D, 0xDC, 0x7C, 0x26, 0xF4, 0x77, 0xF6, 0x5C, 0xF2, 0xAE, 0x5A, 0x44, 0x2D, 0xD3,
0xAB, 0x16, 0x62, 0x04, 0x19, 0xBA, 0xFB, 0x90, 0xFF, 0xE2, 0x30, 0x50, 0x89, 0x6E, 0xCB,
0x56, 0xB2, 0xEB, 0xC0, 0x91, 0x16, 0x92, 0x5E, 0x30, 0x8E, 0xAE, 0xC7, 0x94, 0x5D, 0xFD,
0x35, 0xE1, 0x20, 0xF8, 0xAD, 0x3E, 0xBC, 0x08, 0xBF, 0xC0, 0x36, 0x74, 0x9F, 0xD5, 0xBB,
0x52, 0x08, 0xFD, 0x06, 0x66, 0xF3, 0x7A, 0xB3, 0x04, 0xF4, 0x75, 0x29, 0x5D, 0xE9, 0x5F,
0xAA, 0x10, 0x30, 0xB2, 0x0F, 0x5A, 0x1A, 0xC1, 0x2A, 0xB3, 0xFE, 0xCB, 0x21, 0xAD, 0x80,
0xEC, 0x8F, 0x20, 0x09, 0x1C, 0xDB, 0xC5, 0x58, 0x94, 0xC2, 0x9C, 0xC6, 0xCE, 0x82, 0x65,
0x3E, 0x57, 0x90, 0xBC, 0xA9, 0x8B, 0x06, 0xB4, 0xF0, 0x72, 0xF6, 0x77, 0xDF, 0x98, 0x64,
0xF1, 0xEC, 0xFE, 0x37, 0x2D, 0xBC, 0xAE, 0x8C, 0x08, 0x81, 0x1F, 0xC3, 0xC9, 0x89, 0x1A,
0xC7, 0x42, 0x82, 0x4B, 0x2E, 0xDC, 0x8E, 0x8D, 0x73, 0xCE, 0xB1, 0xCC, 0x01, 0xD9, 0x08,
0x70, 0x87, 0x3C, 0x44, 0x08, 0xEC, 0x49, 0x8F, 0x81, 0x5A, 0xE2, 0x40, 0xFF, 0x77, 0xFC,
0x0D};
};

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "SDL3/SDL_log.h"
#include "layer.h" #include "layer.h"
#include <imgui.h> #include <imgui.h>
@ -117,22 +118,6 @@ void L::DrawMenuBar() {
EndMainMenuBar(); EndMainMenuBar();
} }
if (IsKeyPressed(ImGuiKey_F9, false)) {
if (io.KeyCtrl && io.KeyAlt) {
if (!DebugState.ShouldPauseInSubmit()) {
DebugState.RequestFrameDump(dump_frame_count);
}
}
if (!io.KeyCtrl && !io.KeyAlt) {
if (isSystemPaused) {
DebugState.ResumeGuestThreads();
} else {
DebugState.PauseGuestThreads();
}
}
}
if (open_popup_options) { if (open_popup_options) {
OpenPopup("GPU Tools Options"); OpenPopup("GPU Tools Options");
just_opened_options = true; just_opened_options = true;
@ -381,6 +366,32 @@ void L::Draw() {
visibility_toggled = true; visibility_toggled = true;
} }
if (IsKeyPressed(ImGuiKey_F9, false)) {
if (io.KeyCtrl && io.KeyAlt) {
if (!DebugState.ShouldPauseInSubmit()) {
DebugState.RequestFrameDump(dump_frame_count);
}
} else {
if (DebugState.IsGuestThreadsPaused()) {
DebugState.ResumeGuestThreads();
SDL_Log("Game resumed from Keyboard");
show_pause_status = false;
} else {
DebugState.PauseGuestThreads();
SDL_Log("Game paused from Keyboard");
show_pause_status = true;
}
visibility_toggled = true;
}
}
if (show_pause_status) {
ImVec2 pos = ImVec2(10, 10);
ImU32 color = IM_COL32(255, 255, 255, 255);
ImGui::GetForegroundDrawList()->AddText(pos, color, "Game Paused Press F9 to Resume");
}
if (show_simple_fps) { if (show_simple_fps) {
if (Begin("Video Info", nullptr, if (Begin("Video Info", nullptr,
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration |

View file

@ -19,6 +19,7 @@ public:
static void SetupSettings(); static void SetupSettings();
void Draw() override; void Draw() override;
bool show_pause_status = false;
}; };
} // namespace Core::Devtools } // namespace Core::Devtools

View file

@ -1,473 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <zlib.h>
#include "common/io_file.h"
#include "common/logging/formatter.h"
#include "core/file_format/pkg.h"
#include "core/file_format/pkg_type.h"
static void DecompressPFSC(std::span<char> compressed_data, std::span<char> decompressed_data) {
z_stream decompressStream;
decompressStream.zalloc = Z_NULL;
decompressStream.zfree = Z_NULL;
decompressStream.opaque = Z_NULL;
if (inflateInit(&decompressStream) != Z_OK) {
// std::cerr << "Error initializing zlib for deflation." << std::endl;
}
decompressStream.avail_in = compressed_data.size();
decompressStream.next_in = reinterpret_cast<unsigned char*>(compressed_data.data());
decompressStream.avail_out = decompressed_data.size();
decompressStream.next_out = reinterpret_cast<unsigned char*>(decompressed_data.data());
if (inflate(&decompressStream, Z_FINISH)) {
}
if (inflateEnd(&decompressStream) != Z_OK) {
// std::cerr << "Error ending zlib inflate" << std::endl;
}
}
u32 GetPFSCOffset(std::span<const u8> pfs_image) {
static constexpr u32 PfscMagic = 0x43534650;
u32 value;
for (u32 i = 0x20000; i < pfs_image.size(); i += 0x10000) {
std::memcpy(&value, &pfs_image[i], sizeof(u32));
if (value == PfscMagic)
return i;
}
return -1;
}
PKG::PKG() = default;
PKG::~PKG() = default;
bool PKG::Open(const std::filesystem::path& filepath, std::string& failreason) {
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) {
return false;
}
pkgSize = file.GetSize();
file.Read(pkgheader);
if (pkgheader.magic != 0x7F434E54)
return false;
for (const auto& flag : flagNames) {
if (isFlagSet(pkgheader.pkg_content_flags, flag.first)) {
if (!pkgFlags.empty())
pkgFlags += (", ");
pkgFlags += (flag.second);
}
}
// Find title id it is part of pkg_content_id starting at offset 0x40
file.Seek(0x47); // skip first 7 characters of content_id
file.Read(pkgTitleID);
u32 offset = pkgheader.pkg_table_entry_offset;
u32 n_files = pkgheader.pkg_table_entry_count;
if (!file.Seek(offset)) {
failreason = "Failed to seek to PKG table entry offset";
return false;
}
for (int i = 0; i < n_files; i++) {
PKGEntry entry{};
file.Read(entry.id);
file.Read(entry.filename_offset);
file.Read(entry.flags1);
file.Read(entry.flags2);
file.Read(entry.offset);
file.Read(entry.size);
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
// Try to figure out the name
const auto name = GetEntryNameByType(entry.id);
if (name == "param.sfo") {
sfo.clear();
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to param.sfo offset";
return false;
}
sfo.resize(entry.size);
file.ReadRaw<u8>(sfo.data(), entry.size);
}
}
file.Close();
return true;
}
bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
std::string& failreason) {
extract_path = extract;
pkgpath = filepath;
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) {
return false;
}
pkgSize = file.GetSize();
file.ReadRaw<u8>(&pkgheader, sizeof(PKGHeader));
if (pkgheader.magic != 0x7F434E54)
return false;
if (pkgheader.pkg_size > pkgSize) {
failreason = "PKG file size is different";
return false;
}
if ((pkgheader.pkg_content_size + pkgheader.pkg_content_offset) > pkgheader.pkg_size) {
failreason = "Content size is bigger than pkg size";
return false;
}
u32 offset = pkgheader.pkg_table_entry_offset;
u32 n_files = pkgheader.pkg_table_entry_count;
std::array<u8, 64> concatenated_ivkey_dk3;
std::array<u8, 32> seed_digest;
std::array<std::array<u8, 32>, 7> digest1;
std::array<std::array<u8, 256>, 7> key1;
std::array<u8, 256> imgkeydata;
if (!file.Seek(offset)) {
failreason = "Failed to seek to PKG table entry offset";
return false;
}
for (int i = 0; i < n_files; i++) {
PKGEntry entry{};
file.Read(entry.id);
file.Read(entry.filename_offset);
file.Read(entry.flags1);
file.Read(entry.flags2);
file.Read(entry.offset);
file.Read(entry.size);
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
auto currentPos = file.Tell();
// Try to figure out the name
const auto name = GetEntryNameByType(entry.id);
const auto filepath = extract_path / "sce_sys" / name;
std::filesystem::create_directories(filepath.parent_path());
if (name.empty()) {
// Just print with id
Common::FS::IOFile out(extract_path / "sce_sys" / std::to_string(entry.id),
Common::FS::FileAccessMode::Write);
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to PKG entry offset";
return false;
}
std::vector<u8> data;
data.resize(entry.size);
file.ReadRaw<u8>(data.data(), entry.size);
out.WriteRaw<u8>(data.data(), entry.size);
out.Close();
file.Seek(currentPos);
continue;
}
if (entry.id == 0x1) { // DIGESTS, seek;
// file.Seek(entry.offset, fsSeekSet);
} else if (entry.id == 0x10) { // ENTRY_KEYS, seek;
file.Seek(entry.offset);
file.Read(seed_digest);
for (int i = 0; i < 7; i++) {
file.Read(digest1[i]);
}
for (int i = 0; i < 7; i++) {
file.Read(key1[i]);
}
PKG::crypto.RSA2048Decrypt(dk3_, key1[3], true); // decrypt DK3
} else if (entry.id == 0x20) { // IMAGE_KEY, seek; IV_KEY
file.Seek(entry.offset);
file.Read(imgkeydata);
// The Concatenated iv + dk3 imagekey for HASH256
std::memcpy(concatenated_ivkey_dk3.data(), &entry, sizeof(entry));
std::memcpy(concatenated_ivkey_dk3.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3, ivKey); // ivkey_
// imgkey_ to use for last step to get ekpfs
PKG::crypto.aesCbcCfb128Decrypt(ivKey, imgkeydata, imgKey);
// ekpfs key to get data and tweak keys.
PKG::crypto.RSA2048Decrypt(ekpfsKey, imgKey, false);
} else if (entry.id == 0x80) {
// GENERAL_DIGESTS, seek;
// file.Seek(entry.offset, fsSeekSet);
}
Common::FS::IOFile out(extract_path / "sce_sys" / name, Common::FS::FileAccessMode::Write);
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to PKG entry offset";
return false;
}
std::vector<u8> data;
data.resize(entry.size);
file.ReadRaw<u8>(data.data(), entry.size);
out.WriteRaw<u8>(data.data(), entry.size);
out.Close();
// Decrypt Np stuff and overwrite.
if (entry.id == 0x400 || entry.id == 0x401 || entry.id == 0x402 ||
entry.id == 0x403) { // somehow 0x401 is not decrypting
decNp.resize(entry.size);
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to PKG entry offset";
return false;
}
std::vector<u8> data;
data.resize(entry.size);
file.ReadRaw<u8>(data.data(), entry.size);
std::span<u8> cipherNp(data.data(), entry.size);
std::array<u8, 64> concatenated_ivkey_dk3_;
std::memcpy(concatenated_ivkey_dk3_.data(), &entry, sizeof(entry));
std::memcpy(concatenated_ivkey_dk3_.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3_, ivKey);
PKG::crypto.aesCbcCfb128DecryptEntry(ivKey, cipherNp, decNp);
Common::FS::IOFile out(extract_path / "sce_sys" / name,
Common::FS::FileAccessMode::Write);
out.Write(decNp);
out.Close();
}
file.Seek(currentPos);
}
// Read the seed
std::array<u8, 16> seed;
if (!file.Seek(pkgheader.pfs_image_offset + 0x370)) {
failreason = "Failed to seek to PFS image offset";
return false;
}
file.Read(seed);
// Get data and tweak keys.
PKG::crypto.PfsGenCryptoKey(ekpfsKey, seed, dataKey, tweakKey);
const u32 length = pkgheader.pfs_cache_size * 0x2; // Seems to be ok.
int num_blocks = 0;
std::vector<u8> pfsc(length);
if (length != 0) {
// Read encrypted pfs_image
std::vector<u8> pfs_encrypted(length);
file.Seek(pkgheader.pfs_image_offset);
file.Read(pfs_encrypted);
file.Close();
// Decrypt the pfs_image.
std::vector<u8> pfs_decrypted(length);
PKG::crypto.decryptPFS(dataKey, tweakKey, pfs_encrypted, pfs_decrypted, 0);
// Retrieve PFSC from decrypted pfs_image.
pfsc_offset = GetPFSCOffset(pfs_decrypted);
std::memcpy(pfsc.data(), pfs_decrypted.data() + pfsc_offset, length - pfsc_offset);
PFSCHdr pfsChdr;
std::memcpy(&pfsChdr, pfsc.data(), sizeof(pfsChdr));
num_blocks = (int)(pfsChdr.data_length / pfsChdr.block_sz2);
sectorMap.resize(num_blocks + 1); // 8 bytes, need extra 1 to get the last offset.
for (int i = 0; i < num_blocks + 1; i++) {
std::memcpy(&sectorMap[i], pfsc.data() + pfsChdr.block_offsets + i * 8, 8);
}
}
u32 ent_size = 0;
u32 ndinode = 0;
int ndinode_counter = 0;
bool dinode_reached = false;
bool uroot_reached = false;
std::vector<char> compressedData;
std::vector<char> decompressedData(0x10000);
// Get iNdoes and Dirents.
for (int i = 0; i < num_blocks; i++) {
const u64 sectorOffset = sectorMap[i];
const u64 sectorSize = sectorMap[i + 1] - sectorOffset;
compressedData.resize(sectorSize);
std::memcpy(compressedData.data(), pfsc.data() + sectorOffset, sectorSize);
if (sectorSize == 0x10000) // Uncompressed data
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
else if (sectorSize < 0x10000) // Compressed data
DecompressPFSC(compressedData, decompressedData);
if (i == 0) {
std::memcpy(&ndinode, decompressedData.data() + 0x30, 4); // number of folders and files
}
int occupied_blocks =
(ndinode * 0xA8) / 0x10000; // how many blocks(0x10000) are taken by iNodes.
if (((ndinode * 0xA8) % 0x10000) != 0)
occupied_blocks += 1;
if (i >= 1 && i <= occupied_blocks) { // Get all iNodes, gives type, file size and location.
for (int p = 0; p < 0x10000; p += 0xA8) {
Inode node;
std::memcpy(&node, &decompressedData[p], sizeof(node));
if (node.Mode == 0) {
break;
}
iNodeBuf.push_back(node);
}
}
// let's deal with the root/uroot entries here.
// Sometimes it's more than 2 entries (Tomb Raider Remastered)
const std::string_view flat_path_table(&decompressedData[0x10], 15);
if (flat_path_table == "flat_path_table") {
uroot_reached = true;
}
if (uroot_reached) {
for (int i = 0; i < 0x10000; i += ent_size) {
Dirent dirent;
std::memcpy(&dirent, &decompressedData[i], sizeof(dirent));
ent_size = dirent.entsize;
if (dirent.ino != 0) {
ndinode_counter++;
} else {
// Set the the folder according to the current inode.
// Can be 2 or more (rarely)
auto parent_path = extract_path.parent_path();
auto title_id = GetTitleID();
if (parent_path.filename() != title_id &&
!fmt::UTF(extract_path.u8string()).data.ends_with("-UPDATE")) {
extractPaths[ndinode_counter] = parent_path / title_id;
} else {
// DLCs path has different structure
extractPaths[ndinode_counter] = extract_path;
}
uroot_reached = false;
break;
}
}
}
const char dot = decompressedData[0x10];
const std::string_view dotdot(&decompressedData[0x28], 2);
if (dot == '.' && dotdot == "..") {
dinode_reached = true;
}
// Get folder and file names.
bool end_reached = false;
if (dinode_reached) {
for (int j = 0; j < 0x10000; j += ent_size) { // Skip the first parent and child.
Dirent dirent;
std::memcpy(&dirent, &decompressedData[j], sizeof(dirent));
// Stop here and continue the main loop
if (dirent.ino == 0) {
break;
}
ent_size = dirent.entsize;
auto& table = fsTable.emplace_back();
table.name = std::string(dirent.name, dirent.namelen);
table.inode = dirent.ino;
table.type = dirent.type;
if (table.type == PFS_CURRENT_DIR) {
current_dir = extractPaths[table.inode];
}
extractPaths[table.inode] = current_dir / std::filesystem::path(table.name);
if (table.type == PFS_FILE || table.type == PFS_DIR) {
if (table.type == PFS_DIR) { // Create dirs.
std::filesystem::create_directory(extractPaths[table.inode]);
}
ndinode_counter++;
if ((ndinode_counter + 1) == ndinode) // 1 for the image itself (root).
end_reached = true;
}
}
if (end_reached) {
break;
}
}
}
return true;
}
void PKG::ExtractFiles(const int index) {
int inode_number = fsTable[index].inode;
int inode_type = fsTable[index].type;
std::string inode_name = fsTable[index].name;
if (inode_type == PFS_FILE) {
int sector_loc = iNodeBuf[inode_number].loc;
int nblocks = iNodeBuf[inode_number].Blocks;
int bsize = iNodeBuf[inode_number].Size;
Common::FS::IOFile inflated;
inflated.Open(extractPaths[inode_number], Common::FS::FileAccessMode::Write);
Common::FS::IOFile pkgFile; // Open the file for each iteration to avoid conflict.
pkgFile.Open(pkgpath, Common::FS::FileAccessMode::Read);
int size_decompressed = 0;
std::vector<char> compressedData;
std::vector<char> decompressedData(0x10000);
u64 pfsc_buf_size = 0x11000; // extra 0x1000
std::vector<u8> pfsc(pfsc_buf_size);
std::vector<u8> pfs_decrypted(pfsc_buf_size);
for (int j = 0; j < nblocks; j++) {
u64 sectorOffset =
sectorMap[sector_loc + j]; // offset into PFSC_image and not pfs_image.
u64 sectorSize = sectorMap[sector_loc + j + 1] -
sectorOffset; // indicates if data is compressed or not.
u64 fileOffset = (pkgheader.pfs_image_offset + pfsc_offset + sectorOffset);
u64 currentSector1 =
(pfsc_offset + sectorOffset) / 0x1000; // block size is 0x1000 for xts decryption.
int sectorOffsetMask = (sectorOffset + pfsc_offset) & 0xFFFFF000;
int previousData = (sectorOffset + pfsc_offset) - sectorOffsetMask;
pkgFile.Seek(fileOffset - previousData);
pkgFile.Read(pfsc);
PKG::crypto.decryptPFS(dataKey, tweakKey, pfsc, pfs_decrypted, currentSector1);
compressedData.resize(sectorSize);
std::memcpy(compressedData.data(), pfs_decrypted.data() + previousData, sectorSize);
if (sectorSize == 0x10000) // Uncompressed data
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
else if (sectorSize < 0x10000) // Compressed data
DecompressPFSC(compressedData, decompressedData);
size_decompressed += 0x10000;
if (j < nblocks - 1) {
inflated.WriteRaw<u8>(decompressedData.data(), decompressedData.size());
} else {
// This is to remove the zeros at the end of the file.
const u32 write_size = decompressedData.size() - (size_decompressed - bsize);
inflated.WriteRaw<u8>(decompressedData.data(), write_size);
}
}
pkgFile.Close();
inflated.Close();
}
}

View file

@ -1,174 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <filesystem>
#include <string>
#include <unordered_map>
#include <vector>
#include "common/endian.h"
#include "core/crypto/crypto.h"
#include "pfs.h"
#include "trp.h"
struct PKGHeader {
u32_be magic; // Magic
u32_be pkg_type;
u32_be pkg_0x8; // unknown field
u32_be pkg_file_count;
u32_be pkg_table_entry_count;
u16_be pkg_sc_entry_count;
u16_be pkg_table_entry_count_2; // same as pkg_entry_count
u32_be pkg_table_entry_offset; // file table offset
u32_be pkg_sc_entry_data_size;
u64_be pkg_body_offset; // offset of PKG entries
u64_be pkg_body_size; // length of all PKG entries
u64_be pkg_content_offset;
u64_be pkg_content_size;
u8 pkg_content_id[0x24]; // packages' content ID as a 36-byte string
u8 pkg_padding[0xC]; // padding
u32_be pkg_drm_type; // DRM type
u32_be pkg_content_type; // Content type
u32_be pkg_content_flags; // Content flags
u32_be pkg_promote_size;
u32_be pkg_version_date;
u32_be pkg_version_hash;
u32_be pkg_0x088;
u32_be pkg_0x08C;
u32_be pkg_0x090;
u32_be pkg_0x094;
u32_be pkg_iro_tag;
u32_be pkg_drm_type_version;
u8 pkg_zeroes_1[0x60];
/* Digest table */
u8 digest_entries1[0x20]; // sha256 digest for main entry 1
u8 digest_entries2[0x20]; // sha256 digest for main entry 2
u8 digest_table_digest[0x20]; // sha256 digest for digest table
u8 digest_body_digest[0x20]; // sha256 digest for main table
u8 pkg_zeroes_2[0x280];
u32_be pkg_0x400;
u32_be pfs_image_count; // count of PFS images
u64_be pfs_image_flags; // PFS flags
u64_be pfs_image_offset; // offset to start of external PFS image
u64_be pfs_image_size; // size of external PFS image
u64_be mount_image_offset;
u64_be mount_image_size;
u64_be pkg_size;
u32_be pfs_signed_size;
u32_be pfs_cache_size;
u8 pfs_image_digest[0x20];
u8 pfs_signed_digest[0x20];
u64_be pfs_split_size_nth_0;
u64_be pfs_split_size_nth_1;
u8 pkg_zeroes_3[0xB50];
u8 pkg_digest[0x20];
};
enum class PKGContentFlag {
FIRST_PATCH = 0x100000,
PATCHGO = 0x200000,
REMASTER = 0x400000,
PS_CLOUD = 0x800000,
GD_AC = 0x2000000,
NON_GAME = 0x4000000,
UNKNOWN_0x8000000 = 0x8000000,
SUBSEQUENT_PATCH = 0x40000000,
DELTA_PATCH = 0x41000000,
CUMULATIVE_PATCH = 0x60000000
};
struct PKGEntry {
u32_be id; // File ID, useful for files without a filename entry
u32_be filename_offset; // Offset into the filenames table (ID 0x200) where this file's name is
// located
u32_be flags1; // Flags including encrypted flag, etc
u32_be flags2; // Flags including encryption key index, etc
u32_be offset; // Offset into PKG to find the file
u32_be size; // Size of the file
u64_be padding; // blank padding
};
static_assert(sizeof(PKGEntry) == 32);
class PKG {
public:
PKG();
~PKG();
bool Open(const std::filesystem::path& filepath, std::string& failreason);
void ExtractFiles(const int index);
bool Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
std::string& failreason);
std::vector<u8> sfo;
u32 GetNumberOfFiles() {
return fsTable.size();
}
u64 GetPkgSize() {
return pkgSize;
}
std::string GetPkgFlags() {
return pkgFlags;
}
std::string_view GetTitleID() {
return std::string_view(pkgTitleID, 9);
}
PKGHeader GetPkgHeader() {
return pkgheader;
}
static bool isFlagSet(u32_be variable, PKGContentFlag flag) {
return (variable) & static_cast<u32>(flag);
}
static constexpr std::array<std::pair<PKGContentFlag, std::string_view>, 10> flagNames = {
{{PKGContentFlag::FIRST_PATCH, "FIRST_PATCH"},
{PKGContentFlag::PATCHGO, "PATCHGO"},
{PKGContentFlag::REMASTER, "REMASTER"},
{PKGContentFlag::PS_CLOUD, "PS_CLOUD"},
{PKGContentFlag::GD_AC, "GD_AC"},
{PKGContentFlag::NON_GAME, "NON_GAME"},
{PKGContentFlag::UNKNOWN_0x8000000, "UNKNOWN_0x8000000"},
{PKGContentFlag::SUBSEQUENT_PATCH, "SUBSEQUENT_PATCH"},
{PKGContentFlag::DELTA_PATCH, "DELTA_PATCH"},
{PKGContentFlag::CUMULATIVE_PATCH, "CUMULATIVE_PATCH"}}};
private:
Crypto crypto;
TRP trp;
u64 pkgSize = 0;
char pkgTitleID[9];
PKGHeader pkgheader;
std::string pkgFlags;
std::unordered_map<int, std::filesystem::path> extractPaths;
std::vector<pfs_fs_table> fsTable;
std::vector<Inode> iNodeBuf;
std::vector<u64> sectorMap;
u64 pfsc_offset;
std::array<u8, 32> dk3_;
std::array<u8, 32> ivKey;
std::array<u8, 256> imgKey;
std::array<u8, 32> ekpfsKey;
std::array<u8, 16> dataKey;
std::array<u8, 16> tweakKey;
std::vector<u8> decNp;
std::filesystem::path pkgpath;
std::filesystem::path current_dir;
std::filesystem::path extract_path;
};

View file

@ -1,638 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include "pkg_type.h"
struct PkgEntryValue {
u32 type;
std::string_view name;
operator u32() const noexcept {
return type;
}
};
constexpr static std::array<PkgEntryValue, 611> PkgEntries = {{
{0x0001, "digests"},
{0x0010, "entry_keys"},
{0x0020, "image_key"},
{0x0080, "general_digests"},
{0x0100, "metas"},
{0x0200, "entry_names"},
{0x0400, "license.dat"},
{0x0401, "license.info"},
{0x0402, "nptitle.dat"},
{0x0403, "npbind.dat"},
{0x0404, "selfinfo.dat"},
{0x0406, "imageinfo.dat"},
{0x0407, "target-deltainfo.dat"},
{0x0408, "origin-deltainfo.dat"},
{0x0409, "psreserved.dat"},
{0x1000, "param.sfo"},
{0x1001, "playgo-chunk.dat"},
{0x1002, "playgo-chunk.sha"},
{0x1003, "playgo-manifest.xml"},
{0x1004, "pronunciation.xml"},
{0x1005, "pronunciation.sig"},
{0x1006, "pic1.png"},
{0x1007, "pubtoolinfo.dat"},
{0x1008, "app/playgo-chunk.dat"},
{0x1009, "app/playgo-chunk.sha"},
{0x100A, "app/playgo-manifest.xml"},
{0x100B, "shareparam.json"},
{0x100C, "shareoverlayimage.png"},
{0x100D, "save_data.png"},
{0x100E, "shareprivacyguardimage.png"},
{0x1200, "icon0.png"},
{0x1201, "icon0_00.png"},
{0x1202, "icon0_01.png"},
{0x1203, "icon0_02.png"},
{0x1204, "icon0_03.png"},
{0x1205, "icon0_04.png"},
{0x1206, "icon0_05.png"},
{0x1207, "icon0_06.png"},
{0x1208, "icon0_07.png"},
{0x1209, "icon0_08.png"},
{0x120A, "icon0_09.png"},
{0x120B, "icon0_10.png"},
{0x120C, "icon0_11.png"},
{0x120D, "icon0_12.png"},
{0x120E, "icon0_13.png"},
{0x120F, "icon0_14.png"},
{0x1210, "icon0_15.png"},
{0x1211, "icon0_16.png"},
{0x1212, "icon0_17.png"},
{0x1213, "icon0_18.png"},
{0x1214, "icon0_19.png"},
{0x1215, "icon0_20.png"},
{0x1216, "icon0_21.png"},
{0x1217, "icon0_22.png"},
{0x1218, "icon0_23.png"},
{0x1219, "icon0_24.png"},
{0x121A, "icon0_25.png"},
{0x121B, "icon0_26.png"},
{0x121C, "icon0_27.png"},
{0x121D, "icon0_28.png"},
{0x121E, "icon0_29.png"},
{0x121F, "icon0_30.png"},
{0x1220, "pic0.png"},
{0x1240, "snd0.at9"},
{0x1241, "pic1_00.png"},
{0x1242, "pic1_01.png"},
{0x1243, "pic1_02.png"},
{0x1244, "pic1_03.png"},
{0x1245, "pic1_04.png"},
{0x1246, "pic1_05.png"},
{0x1247, "pic1_06.png"},
{0x1248, "pic1_07.png"},
{0x1249, "pic1_08.png"},
{0x124A, "pic1_09.png"},
{0x124B, "pic1_10.png"},
{0x124C, "pic1_11.png"},
{0x124D, "pic1_12.png"},
{0x124E, "pic1_13.png"},
{0x124F, "pic1_14.png"},
{0x1250, "pic1_15.png"},
{0x1251, "pic1_16.png"},
{0x1252, "pic1_17.png"},
{0x1253, "pic1_18.png"},
{0x1254, "pic1_19.png"},
{0x1255, "pic1_20.png"},
{0x1256, "pic1_21.png"},
{0x1257, "pic1_22.png"},
{0x1258, "pic1_23.png"},
{0x1259, "pic1_24.png"},
{0x125A, "pic1_25.png"},
{0x125B, "pic1_26.png"},
{0x125C, "pic1_27.png"},
{0x125D, "pic1_28.png"},
{0x125E, "pic1_29.png"},
{0x125F, "pic1_30.png"},
{0x1260, "changeinfo/changeinfo.xml"},
{0x1261, "changeinfo/changeinfo_00.xml"},
{0x1262, "changeinfo/changeinfo_01.xml"},
{0x1263, "changeinfo/changeinfo_02.xml"},
{0x1264, "changeinfo/changeinfo_03.xml"},
{0x1265, "changeinfo/changeinfo_04.xml"},
{0x1266, "changeinfo/changeinfo_05.xml"},
{0x1267, "changeinfo/changeinfo_06.xml"},
{0x1268, "changeinfo/changeinfo_07.xml"},
{0x1269, "changeinfo/changeinfo_08.xml"},
{0x126A, "changeinfo/changeinfo_09.xml"},
{0x126B, "changeinfo/changeinfo_10.xml"},
{0x126C, "changeinfo/changeinfo_11.xml"},
{0x126D, "changeinfo/changeinfo_12.xml"},
{0x126E, "changeinfo/changeinfo_13.xml"},
{0x126F, "changeinfo/changeinfo_14.xml"},
{0x1270, "changeinfo/changeinfo_15.xml"},
{0x1271, "changeinfo/changeinfo_16.xml"},
{0x1272, "changeinfo/changeinfo_17.xml"},
{0x1273, "changeinfo/changeinfo_18.xml"},
{0x1274, "changeinfo/changeinfo_19.xml"},
{0x1275, "changeinfo/changeinfo_20.xml"},
{0x1276, "changeinfo/changeinfo_21.xml"},
{0x1277, "changeinfo/changeinfo_22.xml"},
{0x1278, "changeinfo/changeinfo_23.xml"},
{0x1279, "changeinfo/changeinfo_24.xml"},
{0x127A, "changeinfo/changeinfo_25.xml"},
{0x127B, "changeinfo/changeinfo_26.xml"},
{0x127C, "changeinfo/changeinfo_27.xml"},
{0x127D, "changeinfo/changeinfo_28.xml"},
{0x127E, "changeinfo/changeinfo_29.xml"},
{0x127F, "changeinfo/changeinfo_30.xml"},
{0x1280, "icon0.dds"},
{0x1281, "icon0_00.dds"},
{0x1282, "icon0_01.dds"},
{0x1283, "icon0_02.dds"},
{0x1284, "icon0_03.dds"},
{0x1285, "icon0_04.dds"},
{0x1286, "icon0_05.dds"},
{0x1287, "icon0_06.dds"},
{0x1288, "icon0_07.dds"},
{0x1289, "icon0_08.dds"},
{0x128A, "icon0_09.dds"},
{0x128B, "icon0_10.dds"},
{0x128C, "icon0_11.dds"},
{0x128D, "icon0_12.dds"},
{0x128E, "icon0_13.dds"},
{0x128F, "icon0_14.dds"},
{0x1290, "icon0_15.dds"},
{0x1291, "icon0_16.dds"},
{0x1292, "icon0_17.dds"},
{0x1293, "icon0_18.dds"},
{0x1294, "icon0_19.dds"},
{0x1295, "icon0_20.dds"},
{0x1296, "icon0_21.dds"},
{0x1297, "icon0_22.dds"},
{0x1298, "icon0_23.dds"},
{0x1299, "icon0_24.dds"},
{0x129A, "icon0_25.dds"},
{0x129B, "icon0_26.dds"},
{0x129C, "icon0_27.dds"},
{0x129D, "icon0_28.dds"},
{0x129E, "icon0_29.dds"},
{0x129F, "icon0_30.dds"},
{0x12A0, "pic0.dds"},
{0x12C0, "pic1.dds"},
{0x12C1, "pic1_00.dds"},
{0x12C2, "pic1_01.dds"},
{0x12C3, "pic1_02.dds"},
{0x12C4, "pic1_03.dds"},
{0x12C5, "pic1_04.dds"},
{0x12C6, "pic1_05.dds"},
{0x12C7, "pic1_06.dds"},
{0x12C8, "pic1_07.dds"},
{0x12C9, "pic1_08.dds"},
{0x12CA, "pic1_09.dds"},
{0x12CB, "pic1_10.dds"},
{0x12CC, "pic1_11.dds"},
{0x12CD, "pic1_12.dds"},
{0x12CE, "pic1_13.dds"},
{0x12CF, "pic1_14.dds"},
{0x12D0, "pic1_15.dds"},
{0x12D1, "pic1_16.dds"},
{0x12D2, "pic1_17.dds"},
{0x12D3, "pic1_18.dds"},
{0x12D4, "pic1_19.dds"},
{0x12D5, "pic1_20.dds"},
{0x12D6, "pic1_21.dds"},
{0x12D7, "pic1_22.dds"},
{0x12D8, "pic1_23.dds"},
{0x12D9, "pic1_24.dds"},
{0x12DA, "pic1_25.dds"},
{0x12DB, "pic1_26.dds"},
{0x12DC, "pic1_27.dds"},
{0x12DD, "pic1_28.dds"},
{0x12DE, "pic1_29.dds"},
{0x12DF, "pic1_30.dds"},
{0x1400, "trophy/trophy00.trp"},
{0x1401, "trophy/trophy01.trp"},
{0x1402, "trophy/trophy02.trp"},
{0x1403, "trophy/trophy03.trp"},
{0x1404, "trophy/trophy04.trp"},
{0x1405, "trophy/trophy05.trp"},
{0x1406, "trophy/trophy06.trp"},
{0x1407, "trophy/trophy07.trp"},
{0x1408, "trophy/trophy08.trp"},
{0x1409, "trophy/trophy09.trp"},
{0x140A, "trophy/trophy10.trp"},
{0x140B, "trophy/trophy11.trp"},
{0x140C, "trophy/trophy12.trp"},
{0x140D, "trophy/trophy13.trp"},
{0x140E, "trophy/trophy14.trp"},
{0x140F, "trophy/trophy15.trp"},
{0x1410, "trophy/trophy16.trp"},
{0x1411, "trophy/trophy17.trp"},
{0x1412, "trophy/trophy18.trp"},
{0x1413, "trophy/trophy19.trp"},
{0x1414, "trophy/trophy20.trp"},
{0x1415, "trophy/trophy21.trp"},
{0x1416, "trophy/trophy22.trp"},
{0x1417, "trophy/trophy23.trp"},
{0x1418, "trophy/trophy24.trp"},
{0x1419, "trophy/trophy25.trp"},
{0x141A, "trophy/trophy26.trp"},
{0x141B, "trophy/trophy27.trp"},
{0x141C, "trophy/trophy28.trp"},
{0x141D, "trophy/trophy29.trp"},
{0x141E, "trophy/trophy30.trp"},
{0x141F, "trophy/trophy31.trp"},
{0x1420, "trophy/trophy32.trp"},
{0x1421, "trophy/trophy33.trp"},
{0x1422, "trophy/trophy34.trp"},
{0x1423, "trophy/trophy35.trp"},
{0x1424, "trophy/trophy36.trp"},
{0x1425, "trophy/trophy37.trp"},
{0x1426, "trophy/trophy38.trp"},
{0x1427, "trophy/trophy39.trp"},
{0x1428, "trophy/trophy40.trp"},
{0x1429, "trophy/trophy41.trp"},
{0x142A, "trophy/trophy42.trp"},
{0x142B, "trophy/trophy43.trp"},
{0x142C, "trophy/trophy44.trp"},
{0x142D, "trophy/trophy45.trp"},
{0x142E, "trophy/trophy46.trp"},
{0x142F, "trophy/trophy47.trp"},
{0x1430, "trophy/trophy48.trp"},
{0x1431, "trophy/trophy49.trp"},
{0x1432, "trophy/trophy50.trp"},
{0x1433, "trophy/trophy51.trp"},
{0x1434, "trophy/trophy52.trp"},
{0x1435, "trophy/trophy53.trp"},
{0x1436, "trophy/trophy54.trp"},
{0x1437, "trophy/trophy55.trp"},
{0x1438, "trophy/trophy56.trp"},
{0x1439, "trophy/trophy57.trp"},
{0x143A, "trophy/trophy58.trp"},
{0x143B, "trophy/trophy59.trp"},
{0x143C, "trophy/trophy60.trp"},
{0x143D, "trophy/trophy61.trp"},
{0x143E, "trophy/trophy62.trp"},
{0x143F, "trophy/trophy63.trp"},
{0x1440, "trophy/trophy64.trp"},
{0x1441, "trophy/trophy65.trp"},
{0x1442, "trophy/trophy66.trp"},
{0x1443, "trophy/trophy67.trp"},
{0x1444, "trophy/trophy68.trp"},
{0x1445, "trophy/trophy69.trp"},
{0x1446, "trophy/trophy70.trp"},
{0x1447, "trophy/trophy71.trp"},
{0x1448, "trophy/trophy72.trp"},
{0x1449, "trophy/trophy73.trp"},
{0x144A, "trophy/trophy74.trp"},
{0x144B, "trophy/trophy75.trp"},
{0x144C, "trophy/trophy76.trp"},
{0x144D, "trophy/trophy77.trp"},
{0x144E, "trophy/trophy78.trp"},
{0x144F, "trophy/trophy79.trp"},
{0x1450, "trophy/trophy80.trp"},
{0x1451, "trophy/trophy81.trp"},
{0x1452, "trophy/trophy82.trp"},
{0x1453, "trophy/trophy83.trp"},
{0x1454, "trophy/trophy84.trp"},
{0x1455, "trophy/trophy85.trp"},
{0x1456, "trophy/trophy86.trp"},
{0x1457, "trophy/trophy87.trp"},
{0x1458, "trophy/trophy88.trp"},
{0x1459, "trophy/trophy89.trp"},
{0x145A, "trophy/trophy90.trp"},
{0x145B, "trophy/trophy91.trp"},
{0x145C, "trophy/trophy92.trp"},
{0x145D, "trophy/trophy93.trp"},
{0x145E, "trophy/trophy94.trp"},
{0x145F, "trophy/trophy95.trp"},
{0x1460, "trophy/trophy96.trp"},
{0x1461, "trophy/trophy97.trp"},
{0x1462, "trophy/trophy98.trp"},
{0x1463, "trophy/trophy99.trp"},
{0x1600, "keymap_rp/001.png"},
{0x1601, "keymap_rp/002.png"},
{0x1602, "keymap_rp/003.png"},
{0x1603, "keymap_rp/004.png"},
{0x1604, "keymap_rp/005.png"},
{0x1605, "keymap_rp/006.png"},
{0x1606, "keymap_rp/007.png"},
{0x1607, "keymap_rp/008.png"},
{0x1608, "keymap_rp/009.png"},
{0x1609, "keymap_rp/010.png"},
{0x1610, "keymap_rp/00/001.png"},
{0x1611, "keymap_rp/00/002.png"},
{0x1612, "keymap_rp/00/003.png"},
{0x1613, "keymap_rp/00/004.png"},
{0x1614, "keymap_rp/00/005.png"},
{0x1615, "keymap_rp/00/006.png"},
{0x1616, "keymap_rp/00/007.png"},
{0x1617, "keymap_rp/00/008.png"},
{0x1618, "keymap_rp/00/009.png"},
{0x1619, "keymap_rp/00/010.png"},
{0x1620, "keymap_rp/01/001.png"},
{0x1621, "keymap_rp/01/002.png"},
{0x1622, "keymap_rp/01/003.png"},
{0x1623, "keymap_rp/01/004.png"},
{0x1624, "keymap_rp/01/005.png"},
{0x1625, "keymap_rp/01/006.png"},
{0x1626, "keymap_rp/01/007.png"},
{0x1627, "keymap_rp/01/008.png"},
{0x1628, "keymap_rp/01/009.png"},
{0x1629, "keymap_rp/01/010.png"},
{0x1630, "keymap_rp/02/001.png"},
{0x1631, "keymap_rp/02/002.png"},
{0x1632, "keymap_rp/02/003.png"},
{0x1633, "keymap_rp/02/004.png"},
{0x1634, "keymap_rp/02/005.png"},
{0x1635, "keymap_rp/02/006.png"},
{0x1636, "keymap_rp/02/007.png"},
{0x1637, "keymap_rp/02/008.png"},
{0x1638, "keymap_rp/02/009.png"},
{0x1639, "keymap_rp/02/010.png"},
{0x1640, "keymap_rp/03/001.png"},
{0x1641, "keymap_rp/03/002.png"},
{0x1642, "keymap_rp/03/003.png"},
{0x1643, "keymap_rp/03/004.png"},
{0x1644, "keymap_rp/03/005.png"},
{0x1645, "keymap_rp/03/006.png"},
{0x1646, "keymap_rp/03/007.png"},
{0x1647, "keymap_rp/03/008.png"},
{0x1648, "keymap_rp/03/0010.png"},
{0x1650, "keymap_rp/04/001.png"},
{0x1651, "keymap_rp/04/002.png"},
{0x1652, "keymap_rp/04/003.png"},
{0x1653, "keymap_rp/04/004.png"},
{0x1654, "keymap_rp/04/005.png"},
{0x1655, "keymap_rp/04/006.png"},
{0x1656, "keymap_rp/04/007.png"},
{0x1657, "keymap_rp/04/008.png"},
{0x1658, "keymap_rp/04/009.png"},
{0x1659, "keymap_rp/04/010.png"},
{0x1660, "keymap_rp/05/001.png"},
{0x1661, "keymap_rp/05/002.png"},
{0x1662, "keymap_rp/05/003.png"},
{0x1663, "keymap_rp/05/004.png"},
{0x1664, "keymap_rp/05/005.png"},
{0x1665, "keymap_rp/05/006.png"},
{0x1666, "keymap_rp/05/007.png"},
{0x1667, "keymap_rp/05/008.png"},
{0x1668, "keymap_rp/05/009.png"},
{0x1669, "keymap_rp/05/010.png"},
{0x1670, "keymap_rp/06/001.png"},
{0x1671, "keymap_rp/06/002.png"},
{0x1672, "keymap_rp/06/003.png"},
{0x1673, "keymap_rp/06/004.png"},
{0x1674, "keymap_rp/06/005.png"},
{0x1675, "keymap_rp/06/006.png"},
{0x1676, "keymap_rp/06/007.png"},
{0x1677, "keymap_rp/06/008.png"},
{0x1678, "keymap_rp/06/009.png"},
{0x1679, "keymap_rp/06/010.png"},
{0x1680, "keymap_rp/07/001.png"},
{0x1681, "keymap_rp/07/002.png"},
{0x1682, "keymap_rp/07/003.png"},
{0x1683, "keymap_rp/07/004.png"},
{0x1684, "keymap_rp/07/005.png"},
{0x1685, "keymap_rp/07/006.png"},
{0x1686, "keymap_rp/07/007.png"},
{0x1687, "keymap_rp/07/008.png"},
{0x1688, "keymap_rp/07/009.png"},
{0x1689, "keymap_rp/07/010.png"},
{0x1690, "keymap_rp/08/001.png"},
{0x1691, "keymap_rp/08/002.png"},
{0x1692, "keymap_rp/08/003.png"},
{0x1693, "keymap_rp/08/004.png"},
{0x1694, "keymap_rp/08/005.png"},
{0x1695, "keymap_rp/08/006.png"},
{0x1696, "keymap_rp/08/007.png"},
{0x1697, "keymap_rp/08/008.png"},
{0x1698, "keymap_rp/08/009.png"},
{0x1699, "keymap_rp/08/010.png"},
{0x16A0, "keymap_rp/09/001.png"},
{0x16A1, "keymap_rp/09/002.png"},
{0x16A2, "keymap_rp/09/003.png"},
{0x16A3, "keymap_rp/09/004.png"},
{0x16A4, "keymap_rp/09/005.png"},
{0x16A5, "keymap_rp/09/006.png"},
{0x16A6, "keymap_rp/09/007.png"},
{0x16A7, "keymap_rp/09/008.png"},
{0x16A8, "keymap_rp/09/009.png"},
{0x16A9, "keymap_rp/09/010.png"},
{0x16B0, "keymap_rp/10/001.png"},
{0x16B1, "keymap_rp/10/002.png"},
{0x16B2, "keymap_rp/10/003.png"},
{0x16B3, "keymap_rp/10/004.png"},
{0x16B4, "keymap_rp/10/005.png"},
{0x16B5, "keymap_rp/10/006.png"},
{0x16B6, "keymap_rp/10/007.png"},
{0x16B7, "keymap_rp/10/008.png"},
{0x16B8, "keymap_rp/10/009.png"},
{0x16B9, "keymap_rp/10/010.png"},
{0x16C0, "keymap_rp/11/001.png"},
{0x16C1, "keymap_rp/11/002.png"},
{0x16C2, "keymap_rp/11/003.png"},
{0x16C3, "keymap_rp/11/004.png"},
{0x16C4, "keymap_rp/11/005.png"},
{0x16C5, "keymap_rp/11/006.png"},
{0x16C6, "keymap_rp/11/007.png"},
{0x16C7, "keymap_rp/11/008.png"},
{0x16C8, "keymap_rp/11/009.png"},
{0x16C9, "keymap_rp/11/010.png"},
{0x16D0, "keymap_rp/12/001.png"},
{0x16D1, "keymap_rp/12/002.png"},
{0x16D2, "keymap_rp/12/003.png"},
{0x16D3, "keymap_rp/12/004.png"},
{0x16D4, "keymap_rp/12/005.png"},
{0x16D5, "keymap_rp/12/006.png"},
{0x16D6, "keymap_rp/12/007.png"},
{0x16D7, "keymap_rp/12/008.png"},
{0x16D8, "keymap_rp/12/009.png"},
{0x16D9, "keymap_rp/12/010.png"},
{0x16E0, "keymap_rp/13/001.png"},
{0x16E1, "keymap_rp/13/002.png"},
{0x16E2, "keymap_rp/13/003.png"},
{0x16E3, "keymap_rp/13/004.png"},
{0x16E4, "keymap_rp/13/005.png"},
{0x16E5, "keymap_rp/13/006.png"},
{0x16E6, "keymap_rp/13/007.png"},
{0x16E7, "keymap_rp/13/008.png"},
{0x16E8, "keymap_rp/13/009.png"},
{0x16E9, "keymap_rp/13/010.png"},
{0x16F0, "keymap_rp/14/001.png"},
{0x16F1, "keymap_rp/14/002.png"},
{0x16F2, "keymap_rp/14/003.png"},
{0x16F3, "keymap_rp/14/004.png"},
{0x16F4, "keymap_rp/14/005.png"},
{0x16F5, "keymap_rp/14/006.png"},
{0x16F6, "keymap_rp/14/007.png"},
{0x16F7, "keymap_rp/14/008.png"},
{0x16F8, "keymap_rp/14/009.png"},
{0x16F9, "keymap_rp/14/010.png"},
{0x1700, "keymap_rp/15/001.png"},
{0x1701, "keymap_rp/15/002.png"},
{0x1702, "keymap_rp/15/003.png"},
{0x1703, "keymap_rp/15/004.png"},
{0x1704, "keymap_rp/15/005.png"},
{0x1705, "keymap_rp/15/006.png"},
{0x1706, "keymap_rp/15/007.png"},
{0x1707, "keymap_rp/15/008.png"},
{0x1708, "keymap_rp/15/009.png"},
{0x1709, "keymap_rp/15/010.png"},
{0x1710, "keymap_rp/16/001.png"},
{0x1711, "keymap_rp/16/002.png"},
{0x1712, "keymap_rp/16/003.png"},
{0x1713, "keymap_rp/16/004.png"},
{0x1714, "keymap_rp/16/005.png"},
{0x1715, "keymap_rp/16/006.png"},
{0x1716, "keymap_rp/16/007.png"},
{0x1717, "keymap_rp/16/008.png"},
{0x1718, "keymap_rp/16/009.png"},
{0x1719, "keymap_rp/16/010.png"},
{0x1720, "keymap_rp/17/001.png"},
{0x1721, "keymap_rp/17/002.png"},
{0x1722, "keymap_rp/17/003.png"},
{0x1723, "keymap_rp/17/004.png"},
{0x1724, "keymap_rp/17/005.png"},
{0x1725, "keymap_rp/17/006.png"},
{0x1726, "keymap_rp/17/007.png"},
{0x1727, "keymap_rp/17/008.png"},
{0x1728, "keymap_rp/17/009.png"},
{0x1729, "keymap_rp/17/010.png"},
{0x1730, "keymap_rp/18/001.png"},
{0x1731, "keymap_rp/18/002.png"},
{0x1732, "keymap_rp/18/003.png"},
{0x1733, "keymap_rp/18/004.png"},
{0x1734, "keymap_rp/18/005.png"},
{0x1735, "keymap_rp/18/006.png"},
{0x1736, "keymap_rp/18/007.png"},
{0x1737, "keymap_rp/18/008.png"},
{0x1738, "keymap_rp/18/009.png"},
{0x1739, "keymap_rp/18/010.png"},
{0x1740, "keymap_rp/19/001.png"},
{0x1741, "keymap_rp/19/002.png"},
{0x1742, "keymap_rp/19/003.png"},
{0x1743, "keymap_rp/19/004.png"},
{0x1744, "keymap_rp/19/005.png"},
{0x1745, "keymap_rp/19/006.png"},
{0x1746, "keymap_rp/19/007.png"},
{0x1747, "keymap_rp/19/008.png"},
{0x1748, "keymap_rp/19/009.png"},
{0x1749, "keymap_rp/19/010.png"},
{0x1750, "keymap_rp/20/001.png"},
{0x1751, "keymap_rp/20/002.png"},
{0x1752, "keymap_rp/20/003.png"},
{0x1753, "keymap_rp/20/004.png"},
{0x1754, "keymap_rp/20/005.png"},
{0x1755, "keymap_rp/20/006.png"},
{0x1756, "keymap_rp/20/007.png"},
{0x1757, "keymap_rp/20/008.png"},
{0x1758, "keymap_rp/20/009.png"},
{0x1759, "keymap_rp/20/010.png"},
{0x1760, "keymap_rp/21/001.png"},
{0x1761, "keymap_rp/21/002.png"},
{0x1762, "keymap_rp/21/003.png"},
{0x1763, "keymap_rp/21/004.png"},
{0x1764, "keymap_rp/21/005.png"},
{0x1765, "keymap_rp/21/006.png"},
{0x1766, "keymap_rp/21/007.png"},
{0x1767, "keymap_rp/21/008.png"},
{0x1768, "keymap_rp/21/009.png"},
{0x1769, "keymap_rp/21/010.png"},
{0x1770, "keymap_rp/22/001.png"},
{0x1771, "keymap_rp/22/002.png"},
{0x1772, "keymap_rp/22/003.png"},
{0x1773, "keymap_rp/22/004.png"},
{0x1774, "keymap_rp/22/005.png"},
{0x1775, "keymap_rp/22/006.png"},
{0x1776, "keymap_rp/22/007.png"},
{0x1777, "keymap_rp/22/008.png"},
{0x1778, "keymap_rp/22/009.png"},
{0x1779, "keymap_rp/22/010.png"},
{0x1780, "keymap_rp/23/001.png"},
{0x1781, "keymap_rp/23/002.png"},
{0x1782, "keymap_rp/23/003.png"},
{0x1783, "keymap_rp/23/004.png"},
{0x1784, "keymap_rp/23/005.png"},
{0x1785, "keymap_rp/23/006.png"},
{0x1786, "keymap_rp/23/007.png"},
{0x1787, "keymap_rp/23/008.png"},
{0x1788, "keymap_rp/23/009.png"},
{0x1789, "keymap_rp/23/010.png"},
{0x1790, "keymap_rp/24/001.png"},
{0x1791, "keymap_rp/24/002.png"},
{0x1792, "keymap_rp/24/003.png"},
{0x1793, "keymap_rp/24/004.png"},
{0x1794, "keymap_rp/24/005.png"},
{0x1795, "keymap_rp/24/006.png"},
{0x1796, "keymap_rp/24/007.png"},
{0x1797, "keymap_rp/24/008.png"},
{0x1798, "keymap_rp/24/009.png"},
{0x1799, "keymap_rp/24/010.png"},
{0x17A0, "keymap_rp/25/001.png"},
{0x17A1, "keymap_rp/25/002.png"},
{0x17A2, "keymap_rp/25/003.png"},
{0x17A3, "keymap_rp/25/004.png"},
{0x17A4, "keymap_rp/25/005.png"},
{0x17A5, "keymap_rp/25/006.png"},
{0x17A6, "keymap_rp/25/007.png"},
{0x17A7, "keymap_rp/25/008.png"},
{0x17A8, "keymap_rp/25/009.png"},
{0x17A9, "keymap_rp/25/010.png"},
{0x17B0, "keymap_rp/26/001.png"},
{0x17B1, "keymap_rp/26/002.png"},
{0x17B2, "keymap_rp/26/003.png"},
{0x17B3, "keymap_rp/26/004.png"},
{0x17B4, "keymap_rp/26/005.png"},
{0x17B5, "keymap_rp/26/006.png"},
{0x17B6, "keymap_rp/26/007.png"},
{0x17B7, "keymap_rp/26/008.png"},
{0x17B8, "keymap_rp/26/009.png"},
{0x17B9, "keymap_rp/26/010.png"},
{0x17C0, "keymap_rp/27/001.png"},
{0x17C1, "keymap_rp/27/002.png"},
{0x17C2, "keymap_rp/27/003.png"},
{0x17C3, "keymap_rp/27/004.png"},
{0x17C4, "keymap_rp/27/005.png"},
{0x17C5, "keymap_rp/27/006.png"},
{0x17C6, "keymap_rp/27/007.png"},
{0x17C7, "keymap_rp/27/008.png"},
{0x17C8, "keymap_rp/27/009.png"},
{0x17C9, "keymap_rp/27/010.png"},
{0x17D0, "keymap_rp/28/001.png"},
{0x17D1, "keymap_rp/28/002.png"},
{0x17D2, "keymap_rp/28/003.png"},
{0x17D3, "keymap_rp/28/004.png"},
{0x17D4, "keymap_rp/28/005.png"},
{0x17D5, "keymap_rp/28/006.png"},
{0x17D6, "keymap_rp/28/007.png"},
{0x17D7, "keymap_rp/28/008.png"},
{0x17D8, "keymap_rp/28/009.png"},
{0x17D9, "keymap_rp/28/010.png"},
{0x17E0, "keymap_rp/29/001.png"},
{0x17E1, "keymap_rp/29/002.png"},
{0x17E2, "keymap_rp/29/003.png"},
{0x17E3, "keymap_rp/29/004.png"},
{0x17E4, "keymap_rp/29/005.png"},
{0x17E5, "keymap_rp/29/006.png"},
{0x17E6, "keymap_rp/29/007.png"},
{0x17E7, "keymap_rp/29/008.png"},
{0x17E8, "keymap_rp/29/009.png"},
{0x17E9, "keymap_rp/29/010.png"},
{0x17F0, "keymap_rp/30/001.png"},
{0x17F1, "keymap_rp/30/002.png"},
{0x17F2, "keymap_rp/30/003.png"},
{0x17F3, "keymap_rp/30/004.png"},
{0x17F4, "keymap_rp/30/005.png"},
{0x17F5, "keymap_rp/30/006.png"},
{0x17F6, "keymap_rp/30/007.png"},
{0x17F7, "keymap_rp/30/008.png"},
{0x17F8, "keymap_rp/30/009.png"},
{0x17F9, "keymap_rp/30/010.png"},
}};
std::string_view GetEntryNameByType(u32 type) {
const auto key = PkgEntryValue{type};
const auto it = std::ranges::lower_bound(PkgEntries, key);
if (it != PkgEntries.end() && it->type == type) {
return it->name;
}
return "";
}

View file

@ -1,10 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string_view>
#include "common/types.h"
/// Retrieves the PKG entry name from its type identifier.
std::string_view GetEntryNameByType(u32 type);

View file

@ -1,10 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/aes.h"
#include "common/config.h" #include "common/config.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "trp.h" #include "core/file_format/trp.h"
static void DecryptEFSM(std::span<u8, 16> trophyKey, std::span<u8, 16> NPcommID,
std::span<u8, 16> efsmIv, std::span<u8> ciphertext,
std::span<u8> decrypted) {
// Step 1: Encrypt NPcommID
std::array<u8, 16> trophyIv{};
std::array<u8, 16> trpKey;
aes::encrypt_cbc(NPcommID.data(), NPcommID.size(), trophyKey.data(), trophyKey.size(),
trophyIv.data(), trpKey.data(), trpKey.size(), false);
// Step 2: Decrypt EFSM
aes::decrypt_cbc(ciphertext.data(), ciphertext.size(), trpKey.data(), trpKey.size(),
efsmIv.data(), decrypted.data(), decrypted.size(), nullptr);
}
TRP::TRP() = default; TRP::TRP() = default;
TRP::~TRP() = default; TRP::~TRP() = default;
@ -54,7 +69,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
return false; return false;
} }
std::array<CryptoPP::byte, 16> user_key{}; std::array<u8, 16> user_key{};
hexToBytes(user_key_str.c_str(), user_key.data()); hexToBytes(user_key_str.c_str(), user_key.data());
for (int index = 0; const auto& it : std::filesystem::directory_iterator(gameSysDir)) { for (int index = 0; const auto& it : std::filesystem::directory_iterator(gameSysDir)) {
@ -115,7 +130,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
return false; return false;
} }
file.Read(ESFM); file.Read(ESFM);
crypto.decryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt DecryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt
removePadding(XML); removePadding(XML);
std::string xml_name = entry.entry_name; std::string xml_name = entry.entry_name;
size_t pos = xml_name.find("ESFM"); size_t pos = xml_name.find("ESFM");

View file

@ -7,7 +7,6 @@
#include "common/endian.h" #include "common/endian.h"
#include "common/io_file.h" #include "common/io_file.h"
#include "common/types.h" #include "common/types.h"
#include "core/crypto/crypto.h"
struct TrpHeader { struct TrpHeader {
u32_be magic; // (0xDCA24D00) u32_be magic; // (0xDCA24D00)
@ -37,10 +36,9 @@ public:
void GetNPcommID(const std::filesystem::path& trophyPath, int index); void GetNPcommID(const std::filesystem::path& trophyPath, int index);
private: private:
Crypto crypto;
std::vector<u8> NPcommID = std::vector<u8>(12); std::vector<u8> NPcommID = std::vector<u8>(12);
std::array<u8, 16> np_comm_id{}; std::array<u8, 16> np_comm_id{};
std::array<u8, 16> esfmIv{}; std::array<u8, 16> esfmIv{};
std::filesystem::path trpFilesPath; std::filesystem::path trpFilesPath;
static constexpr int iv_len = 16; static constexpr int iv_len = 16;
}; };

View file

@ -70,6 +70,10 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
std::filesystem::path host_path = mount->host_path / rel_path; std::filesystem::path host_path = mount->host_path / rel_path;
std::filesystem::path patch_path = mount->host_path; std::filesystem::path patch_path = mount->host_path;
patch_path += "-UPDATE"; patch_path += "-UPDATE";
if (!std::filesystem::exists(patch_path)) {
patch_path = mount->host_path;
patch_path += "-patch";
}
patch_path /= rel_path; patch_path /= rel_path;
if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) && if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) &&

View file

@ -9,29 +9,29 @@
namespace Libraries::DiscMap { namespace Libraries::DiscMap {
int PS4_SYSV_ABI sceDiscMapGetPackageSize() { int PS4_SYSV_ABI sceDiscMapGetPackageSize(s64 fflags, int* ret1, int* ret2) {
LOG_WARNING(Lib_DiscMap, "(DUMMY) called");
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO; return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
} }
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD() { int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD(char* path, s64 offset, s64 nbytes, int* ret) {
LOG_WARNING(Lib_DiscMap, "(DUMMY) called");
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO; return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
} }
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A() { int PS4_SYSV_ABI Func_7C980FFB0AA27E7A(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
LOG_ERROR(Lib_DiscMap, "(STUBBED) called"); int* ret2) {
*flags = 0;
*ret1 = 0;
*ret2 = 0;
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9() { int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
LOG_ERROR(Lib_DiscMap, "(STUBBED) called"); int* ret2) {
return ORBIS_OK; return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
} }
int PS4_SYSV_ABI Func_E7EBCE96E92F91F8() { int PS4_SYSV_ABI Func_E7EBCE96E92F91F8() {
LOG_ERROR(Lib_DiscMap, "(STUBBED) called"); return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
return ORBIS_OK;
} }
void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym) { void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym) {

View file

@ -10,10 +10,12 @@ class SymbolsResolver;
} }
namespace Libraries::DiscMap { namespace Libraries::DiscMap {
int PS4_SYSV_ABI sceDiscMapGetPackageSize(); int PS4_SYSV_ABI sceDiscMapGetPackageSize(s64 fflags, int* ret1, int* ret2);
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD(); int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD(char* path, s64 offset, s64 nbytes, int* ret);
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A(); int PS4_SYSV_ABI Func_7C980FFB0AA27E7A(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9(); int* ret2);
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int* ret2);
int PS4_SYSV_ABI Func_E7EBCE96E92F91F8(); int PS4_SYSV_ABI Func_E7EBCE96E92F91F8();
void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym); void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym);

View file

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "core/libraries/kernel/file_system.h"
#include "core/libraries/kernel/orbis_error.h"
#include "core/libraries/libs.h"
namespace Libraries::Kernel {
void PS4_SYSV_ABI sceKernelDebugOutText(void* unk, char* text) {
sceKernelWrite(1, text, strlen(text));
return;
}
void RegisterDebug(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("9JYNqN6jAKI", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugOutText);
}
} // namespace Libraries::Kernel

View file

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Kernel {
void RegisterDebug(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

File diff suppressed because it is too large Load diff

View file

@ -65,10 +65,10 @@ constexpr int ORBIS_KERNEL_O_DSYNC = 0x1000;
constexpr int ORBIS_KERNEL_O_DIRECT = 0x00010000; constexpr int ORBIS_KERNEL_O_DIRECT = 0x00010000;
constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000; constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000;
s64 PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes); s64 PS4_SYSV_ABI sceKernelWrite(s32 fd, const void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes); s64 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelPread(int d, void* buf, size_t nbytes, s64 offset); s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, size_t nbytes, s64 offset);
s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset); s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset);
void RegisterFileSystem(Core::Loader::SymbolsResolver* sym); void RegisterFileSystem(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View file

@ -12,6 +12,7 @@
#include "common/va_ctx.h" #include "common/va_ctx.h"
#include "core/file_sys/fs.h" #include "core/file_sys/fs.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/kernel/debug.h"
#include "core/libraries/kernel/equeue.h" #include "core/libraries/kernel/equeue.h"
#include "core/libraries/kernel/file_system.h" #include "core/libraries/kernel/file_system.h"
#include "core/libraries/kernel/kernel.h" #include "core/libraries/kernel/kernel.h"
@ -85,17 +86,23 @@ int ErrnoToSceKernelError(int error) {
} }
void SetPosixErrno(int e) { void SetPosixErrno(int e) {
// Some error numbers are different between supported OSes or the PS4 // Some error numbers are different between supported OSes
switch (e) { switch (e) {
case EPERM: case EPERM:
g_posix_errno = POSIX_EPERM; g_posix_errno = POSIX_EPERM;
break; break;
case EAGAIN: case ENOENT:
g_posix_errno = POSIX_EAGAIN; g_posix_errno = POSIX_ENOENT;
break;
case EDEADLK:
g_posix_errno = POSIX_EDEADLK;
break; break;
case ENOMEM: case ENOMEM:
g_posix_errno = POSIX_ENOMEM; g_posix_errno = POSIX_ENOMEM;
break; break;
case EACCES:
g_posix_errno = POSIX_EACCES;
break;
case EINVAL: case EINVAL:
g_posix_errno = POSIX_EINVAL; g_posix_errno = POSIX_EINVAL;
break; break;
@ -105,13 +112,14 @@ void SetPosixErrno(int e) {
case ERANGE: case ERANGE:
g_posix_errno = POSIX_ERANGE; g_posix_errno = POSIX_ERANGE;
break; break;
case EDEADLK: case EAGAIN:
g_posix_errno = POSIX_EDEADLK; g_posix_errno = POSIX_EAGAIN;
break; break;
case ETIMEDOUT: case ETIMEDOUT:
g_posix_errno = POSIX_ETIMEDOUT; g_posix_errno = POSIX_ETIMEDOUT;
break; break;
default: default:
LOG_WARNING(Kernel, "Unhandled errno {}", e);
g_posix_errno = e; g_posix_errno = e;
} }
} }
@ -133,14 +141,6 @@ void PS4_SYSV_ABI sceLibcHeapGetTraceInfo(HeapInfoInfo* info) {
info->getSegmentInfo = 0; info->getSegmentInfo = 0;
} }
s64 PS4_SYSV_ABI ps4__write(int d, const char* buf, std::size_t nbytes) {
return sceKernelWrite(d, buf, nbytes);
}
s64 PS4_SYSV_ABI ps4__read(int d, void* buf, u64 nbytes) {
return sceKernelRead(d, buf, nbytes);
}
struct OrbisKernelUuid { struct OrbisKernelUuid {
u32 timeLow; u32 timeLow;
u16 timeMid; u16 timeMid;
@ -220,6 +220,7 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
Libraries::Kernel::RegisterProcess(sym); Libraries::Kernel::RegisterProcess(sym);
Libraries::Kernel::RegisterException(sym); Libraries::Kernel::RegisterException(sym);
Libraries::Kernel::RegisterAio(sym); Libraries::Kernel::RegisterAio(sym);
Libraries::Kernel::RegisterDebug(sym);
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl); LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", 1, 1, kernel_ioctl);
@ -229,13 +230,10 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate); LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate);
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail); LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
LIB_FUNCTION("9BcDykPmo1I", "libkernel", 1, "libkernel", 1, 1, __Error); LIB_FUNCTION("9BcDykPmo1I", "libkernel", 1, "libkernel", 1, 1, __Error);
LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read);
LIB_FUNCTION("k+AXqu2-eBc", "libkernel", 1, "libkernel", 1, 1, posix_getpagesize); LIB_FUNCTION("k+AXqu2-eBc", "libkernel", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize); LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1, LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
sceLibcHeapGetTraceInfo); sceLibcHeapGetTraceInfo);
LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write);
LIB_FUNCTION("FN4gaPmuFV8", "libScePosix", 1, "libkernel", 1, 1, ps4__write);
} }
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View file

@ -127,6 +127,11 @@ int PS4_SYSV_ABI sceKernelGetModuleInfoFromAddr(VAddr addr, int flags,
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI exit(s32 status) {
UNREACHABLE_MSG("Exiting with status code {}", status);
return 0;
}
void RegisterProcess(Core::Loader::SymbolsResolver* sym) { void RegisterProcess(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("WB66evu8bsU", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCompiledSdkVersion); LIB_FUNCTION("WB66evu8bsU", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCompiledSdkVersion);
LIB_FUNCTION("WslcK1FQcGI", "libkernel", 1, "libkernel", 1, 1, sceKernelIsNeoMode); LIB_FUNCTION("WslcK1FQcGI", "libkernel", 1, "libkernel", 1, 1, sceKernelIsNeoMode);
@ -136,6 +141,7 @@ void RegisterProcess(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym); LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym);
LIB_FUNCTION("RpQJJVKTiFM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoForUnwind); LIB_FUNCTION("RpQJJVKTiFM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoForUnwind);
LIB_FUNCTION("f7KBOafysXo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoFromAddr); LIB_FUNCTION("f7KBOafysXo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoFromAddr);
LIB_FUNCTION("6Z83sYWFlA8", "libkernel", 1, "libkernel", 1, 1, exit);
} }
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h" #include "common/assert.h"
#include "core/libraries/kernel/orbis_error.h"
#include "core/libraries/kernel/threads/exception.h" #include "core/libraries/kernel/threads/exception.h"
#include "core/libraries/kernel/threads/pthread.h" #include "core/libraries/kernel/threads/pthread.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
@ -148,13 +149,19 @@ int PS4_SYSV_ABI sceKernelRaiseException(PthreadT thread, int signum) {
return 0; return 0;
} }
int PS4_SYSV_ABI sceKernelDebugRaiseException() { s32 PS4_SYSV_ABI sceKernelDebugRaiseException(s32 error, s64 unk) {
UNREACHABLE(); if (unk != 0) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
UNREACHABLE_MSG("error {:#x}", error);
return 0; return 0;
} }
int PS4_SYSV_ABI sceKernelDebugRaiseExceptionOnReleaseMode() { s32 PS4_SYSV_ABI sceKernelDebugRaiseExceptionOnReleaseMode(s32 error, s64 unk) {
UNREACHABLE(); if (unk != 0) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
UNREACHABLE_MSG("error {:#x}", error);
return 0; return 0;
} }
@ -163,7 +170,7 @@ void RegisterException(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("WkwEd3N7w0Y", "libkernel_unity", 1, "libkernel", 1, 1, LIB_FUNCTION("WkwEd3N7w0Y", "libkernel_unity", 1, "libkernel", 1, 1,
sceKernelInstallExceptionHandler); sceKernelInstallExceptionHandler);
LIB_FUNCTION("Qhv5ARAoOEc", "libkernel_unity", 1, "libkernel", 1, 1, LIB_FUNCTION("Qhv5ARAoOEc", "libkernel_unity", 1, "libkernel", 1, 1,
sceKernelRemoveExceptionHandler) sceKernelRemoveExceptionHandler);
LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException); LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException);
LIB_FUNCTION("zE-wXIZjLoM", "libkernel", 1, "libkernel", 1, 1, LIB_FUNCTION("zE-wXIZjLoM", "libkernel", 1, "libkernel", 1, 1,
sceKernelDebugRaiseExceptionOnReleaseMode); sceKernelDebugRaiseExceptionOnReleaseMode);

View file

@ -147,6 +147,11 @@ void RegisterSpec(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("0-KXaS70xy4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_getspecific); LIB_FUNCTION("0-KXaS70xy4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_getspecific);
LIB_FUNCTION("WrOLvHU0yQM", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setspecific); LIB_FUNCTION("WrOLvHU0yQM", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setspecific);
// Posix-Kernel
LIB_FUNCTION("mqULNdimTn0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_key_create);
LIB_FUNCTION("0-KXaS70xy4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_getspecific);
LIB_FUNCTION("WrOLvHU0yQM", "libkernel", 1, "libkernel", 1, 1, posix_pthread_setspecific);
// Orbis // Orbis
LIB_FUNCTION("geDaqgH9lTg", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_key_create)); LIB_FUNCTION("geDaqgH9lTg", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_key_create));
LIB_FUNCTION("PrdHuuDekhY", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_key_delete)); LIB_FUNCTION("PrdHuuDekhY", "libkernel", 1, "libkernel", 1, 1, ORBIS(posix_pthread_key_delete));

View file

@ -172,7 +172,7 @@ static s32 clock_gettime(u32 clock_id, struct timespec* ts) {
} }
#endif #endif
int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct timespec* ts) { int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* ts) {
if (ts == nullptr) { if (ts == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT; return ORBIS_KERNEL_ERROR_EFAULT;
} }
@ -265,17 +265,18 @@ int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct timespec* ts) {
return EINVAL; return EINVAL;
} }
return clock_gettime(pclock_id, ts); timespec t{};
int result = clock_gettime(pclock_id, &t);
ts->tv_sec = t.tv_sec;
ts->tv_nsec = t.tv_nsec;
return result;
} }
int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) { int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) {
struct timespec ts; const auto res = orbis_clock_gettime(clock_id, tp);
const auto res = orbis_clock_gettime(clock_id, &ts);
if (res < 0) { if (res < 0) {
return ErrnoToSceKernelError(res); return ErrnoToSceKernelError(res);
} }
tp->tv_sec = ts.tv_sec;
tp->tv_nsec = ts.tv_nsec;
return ORBIS_OK; return ORBIS_OK;
} }
@ -469,4 +470,4 @@ void RegisterTime(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime); LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime);
} }
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View file

@ -115,6 +115,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::NpParty::RegisterlibSceNpParty(sym); Libraries::NpParty::RegisterlibSceNpParty(sym);
Libraries::Zlib::RegisterlibSceZlib(sym); Libraries::Zlib::RegisterlibSceZlib(sym);
Libraries::Hmd::RegisterlibSceHmd(sym); Libraries::Hmd::RegisterlibSceHmd(sym);
Libraries::DiscMap::RegisterlibSceDiscMap(sym);
} }
} // namespace Libraries } // namespace Libraries

View file

@ -5,21 +5,480 @@
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/ngs2/ngs2.h" #include "core/libraries/ngs2/ngs2.h"
#include "core/libraries/ngs2/ngs2_custom.h"
#include "core/libraries/ngs2/ngs2_error.h" #include "core/libraries/ngs2/ngs2_error.h"
#include "core/libraries/ngs2/ngs2_geom.h"
#include "core/libraries/ngs2/ngs2_impl.h" #include "core/libraries/ngs2/ngs2_impl.h"
#include "core/libraries/ngs2/ngs2_pan.h"
#include "core/libraries/ngs2/ngs2_report.h"
namespace Libraries::Ngs2 { namespace Libraries::Ngs2 {
int PS4_SYSV_ABI sceNgs2CalcWaveformBlock() { // Ngs2
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
s32 PS4_SYSV_ABI sceNgs2CalcWaveformBlock(const OrbisNgs2WaveformFormat* format, u32 samplePos,
u32 numSamples, OrbisNgs2WaveformBlock* outBlock) {
LOG_INFO(Lib_Ngs2, "samplePos = {}, numSamples = {}", samplePos, numSamples);
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNgs2CustomRackGetModuleInfo() { s32 PS4_SYSV_ABI sceNgs2GetWaveformFrameInfo(const OrbisNgs2WaveformFormat* format,
LOG_ERROR(Lib_Ngs2, "(STUBBED) called"); u32* outFrameSize, u32* outNumFrameSamples,
u32* outUnitsPerFrame, u32* outNumDelaySamples) {
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK; return ORBIS_OK;
} }
s32 PS4_SYSV_ABI sceNgs2ParseWaveformData(const void* data, size_t dataSize,
OrbisNgs2WaveformInfo* outInfo) {
LOG_INFO(Lib_Ngs2, "dataSize = {}", dataSize);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ParseWaveformFile(const char* path, u64 offset,
OrbisNgs2WaveformInfo* outInfo) {
LOG_INFO(Lib_Ngs2, "path = {}, offset = {}", path, offset);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ParseWaveformUser(OrbisNgs2ParseReadHandler handler, uintptr_t userData,
OrbisNgs2WaveformInfo* outInfo) {
LOG_INFO(Lib_Ngs2, "userData = {}", userData);
if (!handler) {
LOG_ERROR(Lib_Ngs2, "handler is nullptr");
return ORBIS_NGS2_ERROR_INVALID_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackCreate(OrbisNgs2Handle systemHandle, u32 rackId,
const OrbisNgs2RackOption* option,
const OrbisNgs2ContextBufferInfo* bufferInfo,
OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "rackId = {}", rackId);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackCreateWithAllocator(OrbisNgs2Handle systemHandle, u32 rackId,
const OrbisNgs2RackOption* option,
const OrbisNgs2BufferAllocator* allocator,
OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "rackId = {}", rackId);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackDestroy(OrbisNgs2Handle rackHandle,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackGetInfo(OrbisNgs2Handle rackHandle, OrbisNgs2RackInfo* outInfo,
size_t infoSize) {
LOG_INFO(Lib_Ngs2, "infoSize = {}", infoSize);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackGetUserData(OrbisNgs2Handle rackHandle, uintptr_t* outUserData) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackGetVoiceHandle(OrbisNgs2Handle rackHandle, u32 voiceIndex,
OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "voiceIndex = {}", voiceIndex);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackLock(OrbisNgs2Handle rackHandle) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackQueryBufferSize(u32 rackId, const OrbisNgs2RackOption* option,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
LOG_INFO(Lib_Ngs2, "rackId = {}", rackId);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackSetUserData(OrbisNgs2Handle rackHandle, uintptr_t userData) {
LOG_INFO(Lib_Ngs2, "userData = {}", userData);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackUnlock(OrbisNgs2Handle rackHandle) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemCreate(const OrbisNgs2SystemOption* option,
const OrbisNgs2ContextBufferInfo* bufferInfo,
OrbisNgs2Handle* outHandle) {
s32 result;
OrbisNgs2ContextBufferInfo localInfo;
if (!bufferInfo || !outHandle) {
if (!bufferInfo) {
result = ORBIS_NGS2_ERROR_INVALID_BUFFER_INFO;
LOG_ERROR(Lib_Ngs2, "Invalid system buffer info {}", (void*)bufferInfo);
} else {
result = ORBIS_NGS2_ERROR_INVALID_OUT_ADDRESS;
LOG_ERROR(Lib_Ngs2, "Invalid system handle address {}", (void*)outHandle);
}
// TODO: Report errors?
} else {
// Make bufferInfo copy
localInfo.hostBuffer = bufferInfo->hostBuffer;
localInfo.hostBufferSize = bufferInfo->hostBufferSize;
for (int i = 0; i < 5; i++) {
localInfo.reserved[i] = bufferInfo->reserved[i];
}
localInfo.userData = bufferInfo->userData;
result = SystemSetup(option, &localInfo, 0, outHandle);
}
// TODO: API reporting?
LOG_INFO(Lib_Ngs2, "called");
return result;
}
s32 PS4_SYSV_ABI sceNgs2SystemCreateWithAllocator(const OrbisNgs2SystemOption* option,
const OrbisNgs2BufferAllocator* allocator,
OrbisNgs2Handle* outHandle) {
s32 result;
if (allocator && allocator->allocHandler != 0) {
OrbisNgs2BufferAllocHandler hostAlloc = allocator->allocHandler;
if (outHandle) {
OrbisNgs2BufferFreeHandler hostFree = allocator->freeHandler;
OrbisNgs2ContextBufferInfo* bufferInfo = 0;
result = SystemSetup(option, bufferInfo, 0, 0);
if (result >= 0) {
uintptr_t sysUserData = allocator->userData;
result = hostAlloc(bufferInfo);
if (result >= 0) {
OrbisNgs2Handle* handleCopy = outHandle;
result = SystemSetup(option, bufferInfo, hostFree, handleCopy);
if (result < 0) {
if (hostFree) {
hostFree(bufferInfo);
}
}
}
}
} else {
result = ORBIS_NGS2_ERROR_INVALID_OUT_ADDRESS;
LOG_ERROR(Lib_Ngs2, "Invalid system handle address {}", (void*)outHandle);
}
} else {
result = ORBIS_NGS2_ERROR_INVALID_BUFFER_ALLOCATOR;
LOG_ERROR(Lib_Ngs2, "Invalid system buffer allocator {}", (void*)allocator);
}
LOG_INFO(Lib_Ngs2, "called");
return result;
}
s32 PS4_SYSV_ABI sceNgs2SystemDestroy(OrbisNgs2Handle systemHandle,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemEnumHandles(OrbisNgs2Handle* aOutHandle, u32 maxHandles) {
LOG_INFO(Lib_Ngs2, "maxHandles = {}", maxHandles);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemEnumRackHandles(OrbisNgs2Handle systemHandle,
OrbisNgs2Handle* aOutHandle, u32 maxHandles) {
LOG_INFO(Lib_Ngs2, "maxHandles = {}", maxHandles);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemGetInfo(OrbisNgs2Handle rackHandle, OrbisNgs2SystemInfo* outInfo,
size_t infoSize) {
LOG_INFO(Lib_Ngs2, "infoSize = {}", infoSize);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemGetUserData(OrbisNgs2Handle systemHandle, uintptr_t* outUserData) {
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemLock(OrbisNgs2Handle systemHandle) {
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemQueryBufferSize(const OrbisNgs2SystemOption* option,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
s32 result;
if (outBufferInfo) {
result = SystemSetup(option, outBufferInfo, 0, 0);
LOG_INFO(Lib_Ngs2, "called");
} else {
result = ORBIS_NGS2_ERROR_INVALID_OUT_ADDRESS;
LOG_ERROR(Lib_Ngs2, "Invalid system buffer info {}", (void*)outBufferInfo);
}
return result;
}
s32 PS4_SYSV_ABI sceNgs2SystemRender(OrbisNgs2Handle systemHandle,
const OrbisNgs2RenderBufferInfo* aBufferInfo,
u32 numBufferInfo) {
LOG_INFO(Lib_Ngs2, "numBufferInfo = {}", numBufferInfo);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
static s32 PS4_SYSV_ABI sceNgs2SystemResetOption(OrbisNgs2SystemOption* outOption) {
static const OrbisNgs2SystemOption option = {
sizeof(OrbisNgs2SystemOption), "", 0, 512, 256, 48000, {0}};
if (!outOption) {
LOG_ERROR(Lib_Ngs2, "Invalid system option address {}", (void*)outOption);
return ORBIS_NGS2_ERROR_INVALID_OPTION_ADDRESS;
}
*outOption = option;
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemSetGrainSamples(OrbisNgs2Handle systemHandle, u32 numSamples) {
LOG_INFO(Lib_Ngs2, "numSamples = {}", numSamples);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemSetSampleRate(OrbisNgs2Handle systemHandle, u32 sampleRate) {
LOG_INFO(Lib_Ngs2, "sampleRate = {}", sampleRate);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemSetUserData(OrbisNgs2Handle systemHandle, uintptr_t userData) {
LOG_INFO(Lib_Ngs2, "userData = {}", userData);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemUnlock(OrbisNgs2Handle systemHandle) {
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceControl(OrbisNgs2Handle voiceHandle,
const OrbisNgs2VoiceParamHeader* paramList) {
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetMatrixInfo(OrbisNgs2Handle voiceHandle, u32 matrixId,
OrbisNgs2VoiceMatrixInfo* outInfo, size_t outInfoSize) {
LOG_INFO(Lib_Ngs2, "matrixId = {}, outInfoSize = {}", matrixId, outInfoSize);
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetOwner(OrbisNgs2Handle voiceHandle, OrbisNgs2Handle* outRackHandle,
u32* outVoiceId) {
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetPortInfo(OrbisNgs2Handle voiceHandle, u32 port,
OrbisNgs2VoicePortInfo* outInfo, size_t outInfoSize) {
LOG_INFO(Lib_Ngs2, "port = {}, outInfoSize = {}", port, outInfoSize);
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetState(OrbisNgs2Handle voiceHandle, OrbisNgs2VoiceState* outState,
size_t stateSize) {
LOG_INFO(Lib_Ngs2, "stateSize = {}", stateSize);
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetStateFlags(OrbisNgs2Handle voiceHandle, u32* outStateFlags) {
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
// Ngs2Custom
s32 PS4_SYSV_ABI sceNgs2CustomRackGetModuleInfo(OrbisNgs2Handle rackHandle, u32 moduleIndex,
OrbisNgs2CustomModuleInfo* outInfo,
size_t infoSize) {
LOG_INFO(Lib_Ngs2, "moduleIndex = {}, infoSize = {}", moduleIndex, infoSize);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
// Ngs2Geom
s32 PS4_SYSV_ABI sceNgs2GeomResetListenerParam(OrbisNgs2GeomListenerParam* outListenerParam) {
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GeomResetSourceParam(OrbisNgs2GeomSourceParam* outSourceParam) {
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GeomCalcListener(const OrbisNgs2GeomListenerParam* param,
OrbisNgs2GeomListenerWork* outWork, u32 flags) {
LOG_INFO(Lib_Ngs2, "flags = {}", flags);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GeomApply(const OrbisNgs2GeomListenerWork* listener,
const OrbisNgs2GeomSourceParam* source,
OrbisNgs2GeomAttribute* outAttrib, u32 flags) {
LOG_INFO(Lib_Ngs2, "flags = {}", flags);
return ORBIS_OK;
}
// Ngs2Pan
s32 PS4_SYSV_ABI sceNgs2PanInit(OrbisNgs2PanWork* work, const float* aSpeakerAngle, float unitAngle,
u32 numSpeakers) {
LOG_INFO(Lib_Ngs2, "aSpeakerAngle = {}, unitAngle = {}, numSpeakers = {}", *aSpeakerAngle,
unitAngle, numSpeakers);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2PanGetVolumeMatrix(OrbisNgs2PanWork* work, const OrbisNgs2PanParam* aParam,
u32 numParams, u32 matrixFormat,
float* outVolumeMatrix) {
LOG_INFO(Lib_Ngs2, "numParams = {}, matrixFormat = {}", numParams, matrixFormat);
return ORBIS_OK;
}
// Ngs2Report
s32 PS4_SYSV_ABI sceNgs2ReportRegisterHandler(u32 reportType, OrbisNgs2ReportHandler handler,
uintptr_t userData, OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "reportType = {}, userData = {}", reportType, userData);
if (!handler) {
LOG_ERROR(Lib_Ngs2, "handler is nullptr");
return ORBIS_NGS2_ERROR_INVALID_REPORT_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ReportUnregisterHandler(OrbisNgs2Handle reportHandle) {
if (!reportHandle) {
LOG_ERROR(Lib_Ngs2, "reportHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_REPORT_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
// Unknown
int PS4_SYSV_ABI sceNgs2FftInit() { int PS4_SYSV_ABI sceNgs2FftInit() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called"); LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
@ -35,31 +494,6 @@ int PS4_SYSV_ABI sceNgs2FftQuerySize() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNgs2GeomApply() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2GeomCalcListener() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2GeomResetListenerParam() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2GeomResetSourceParam() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2GetWaveformFrameInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2JobSchedulerResetOption() { int PS4_SYSV_ABI sceNgs2JobSchedulerResetOption() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called"); LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
@ -80,71 +514,6 @@ int PS4_SYSV_ABI sceNgs2ModuleQueueEnumItems() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNgs2PanGetVolumeMatrix() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2PanInit() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ParseWaveformData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ParseWaveformFile() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ParseWaveformUser() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackCreate() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackCreateWithAllocator() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackDestroy() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackGetInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackGetUserData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackGetVoiceHandle() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackLock() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackQueryBufferSize() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackQueryInfo() { int PS4_SYSV_ABI sceNgs2RackQueryInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called"); LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
@ -155,116 +524,21 @@ int PS4_SYSV_ABI sceNgs2RackRunCommands() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNgs2RackSetUserData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackUnlock() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ReportRegisterHandler() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ReportUnregisterHandler() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemCreate() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemCreateWithAllocator() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemDestroy() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemEnumHandles() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemEnumRackHandles() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemGetInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemGetUserData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemLock() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemQueryBufferSize() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemQueryInfo() { int PS4_SYSV_ABI sceNgs2SystemQueryInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called"); LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNgs2SystemRender() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemResetOption() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemRunCommands() { int PS4_SYSV_ABI sceNgs2SystemRunCommands() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called"); LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNgs2SystemSetGrainSamples() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemSetLoudThreshold() { int PS4_SYSV_ABI sceNgs2SystemSetLoudThreshold() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called"); LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNgs2SystemSetSampleRate() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemSetUserData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemUnlock() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2StreamCreate() { int PS4_SYSV_ABI sceNgs2StreamCreate() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called"); LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
@ -300,36 +574,6 @@ int PS4_SYSV_ABI sceNgs2StreamRunCommands() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNgs2VoiceControl() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetMatrixInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetOwner() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetPortInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetState() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetStateFlags() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceQueryInfo() { int PS4_SYSV_ABI sceNgs2VoiceQueryInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called"); LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;

View file

@ -3,7 +3,11 @@
#pragma once #pragma once
#include "core/libraries/ngs2/ngs2_impl.h"
#include <atomic> #include <atomic>
#include <mutex>
#include <vector>
#include "common/types.h" #include "common/types.h"
namespace Core::Loader { namespace Core::Loader {
@ -12,60 +16,253 @@ class SymbolsResolver;
namespace Libraries::Ngs2 { namespace Libraries::Ngs2 {
class Ngs2; typedef s32 (*OrbisNgs2ParseReadHandler)(uintptr_t userData, u32 offset, void* data, size_t size);
using SceNgs2Handle = Ngs2*; enum class OrbisNgs2HandleType : u32 {
Invalid = 0,
enum class SceNgs2HandleType : u32 { System = 1,
System = 0, Rack = 2,
Voice = 3,
VoiceControl = 6
}; };
struct Ngs2Handle { static const int ORBIS_NGS2_MAX_VOICE_CHANNELS = 8;
void* selfPointer; static const int ORBIS_NGS2_WAVEFORM_INFO_MAX_BLOCKS = 4;
void* dataPointer; static const int ORBIS_NGS2_MAX_MATRIX_LEVELS =
std::atomic<u32>* atomicPtr; (ORBIS_NGS2_MAX_VOICE_CHANNELS * ORBIS_NGS2_MAX_VOICE_CHANNELS);
u32 handleType;
u32 flags_unk;
u32 uid; struct OrbisNgs2WaveformFormat {
u16 maxGrainSamples; u32 waveformType;
u16 minGrainSamples; u32 numChannels;
u16 currentGrainSamples;
u16 numGrainSamples;
u16 unknown2;
u32 sampleRate; u32 sampleRate;
u32 unknown3; u32 configData;
u32 frameOffset;
void* flushMutex; u32 frameMargin;
u32 flushMutexInitialized;
void* processMutex;
u32 processMutexInitialized;
// Linked list pointers for system list
Ngs2Handle* prev;
Ngs2Handle* next;
}; };
struct SystemOptions { struct OrbisNgs2WaveformBlock {
char padding[6]; u32 dataOffset;
s32 maxGrainSamples; u32 dataSize;
s32 numGrainSamples; u32 numRepeats;
s32 sampleRate; u32 numSkipSamples;
u32 numSamples;
u32 reserved;
uintptr_t userData;
}; };
struct SystemState { struct OrbisNgs2WaveformInfo {
// TODO OrbisNgs2WaveformFormat format;
u32 dataOffset;
u32 dataSize;
u32 loopBeginPosition;
u32 loopEndPosition;
u32 numSamples;
u32 audioUnitSize;
u32 numAudioUnitSamples;
u32 numAudioUnitPerFrame;
u32 audioFrameSize;
u32 numAudioFrameSamples;
u32 numDelaySamples;
u32 numBlocks;
OrbisNgs2WaveformBlock aBlock[ORBIS_NGS2_WAVEFORM_INFO_MAX_BLOCKS];
}; };
struct StackBuffer { struct OrbisNgs2EnvelopePoint {
void** top; u32 curve;
void* base; u32 duration;
void* curr; float height;
size_t usedSize; };
size_t totalSize;
size_t alignment; struct OrbisNgs2UserFxProcessContext {
char isVerifyEnabled; float** aChannelData;
char padding[7]; uintptr_t userData0;
uintptr_t userData1;
uintptr_t userData2;
u32 flags;
u32 numChannels;
u32 numGrainSamples;
u32 sampleRate;
};
typedef s32 (*OrbisNgs2UserFxProcessHandler)(OrbisNgs2UserFxProcessContext* context);
struct OrbisNgs2UserFx2SetupContext {
void* common;
void* param;
void* work;
uintptr_t userData;
u32 maxVoices;
u32 voiceIndex;
u64 reserved[4];
};
typedef s32 (*OrbisNgs2UserFx2SetupHandler)(OrbisNgs2UserFx2SetupContext* context);
struct OrbisNgs2UserFx2CleanupContext {
void* common;
void* param;
void* work;
uintptr_t userData;
u32 maxVoices;
u32 voiceIndex;
u64 reserved[4];
};
typedef s32 (*OrbisNgs2UserFx2CleanupHandler)(OrbisNgs2UserFx2CleanupContext* context);
struct OrbisNgs2UserFx2ControlContext {
const void* data;
size_t dataSize;
void* common;
void* param;
uintptr_t userData;
u64 reserved[4];
};
typedef s32 (*OrbisNgs2UserFx2ControlHandler)(OrbisNgs2UserFx2ControlContext* context);
struct OrbisNgs2UserFx2ProcessContext {
float** aChannelData;
void* common;
const void* param;
void* work;
void* state;
uintptr_t userData;
u32 flags;
u32 numInputChannels;
u32 numOutputChannels;
u32 numGrainSamples;
u32 sampleRate;
u32 reserved;
u64 reserved2[4];
};
typedef s32 (*OrbisNgs2UserFx2ProcessHandler)(OrbisNgs2UserFx2ProcessContext* context);
struct OrbisNgs2BufferAllocator {
OrbisNgs2BufferAllocHandler allocHandler;
OrbisNgs2BufferFreeHandler freeHandler;
uintptr_t userData;
};
struct OrbisNgs2RenderBufferInfo {
void* buffer;
size_t bufferSize;
u32 waveformType;
u32 numChannels;
};
struct OrbisNgs2RackOption {
size_t size;
char name[ORBIS_NGS2_RACK_NAME_LENGTH];
u32 flags;
u32 maxGrainSamples;
u32 maxVoices;
u32 maxInputDelayBlocks;
u32 maxMatrices;
u32 maxPorts;
u32 aReserved[20];
};
struct OrbisNgs2VoiceParamHeader {
u16 size;
s16 next;
u32 id;
};
struct OrbisNgs2VoiceMatrixLevelsParam {
OrbisNgs2VoiceParamHeader header;
u32 matrixId;
u32 numLevels;
const float* aLevel;
};
struct OrbisNgs2VoicePortMatrixParam {
OrbisNgs2VoiceParamHeader header;
u32 port;
s32 matrixId;
};
struct OrbisNgs2VoicePortVolumeParam {
OrbisNgs2VoiceParamHeader header;
u32 port;
float level;
};
struct OrbisNgs2VoicePortDelayParam {
OrbisNgs2VoiceParamHeader header;
u32 port;
u32 numSamples;
};
struct OrbisNgs2VoicePatchParam {
OrbisNgs2VoiceParamHeader header;
u32 port;
u32 destInputId;
OrbisNgs2Handle destHandle;
};
struct OrbisNgs2VoiceEventParam {
OrbisNgs2VoiceParamHeader header;
u32 eventId;
};
struct OrbisNgs2VoiceCallbackInfo {
uintptr_t callbackData;
OrbisNgs2Handle voiceHandle;
u32 flag;
u32 reserved;
union {
struct {
uintptr_t userData;
const void* data;
u32 dataSize;
u32 repeatedCount;
u32 attributeFlags;
u32 reserved2;
} waveformBlock;
} param;
};
typedef void (*OrbisNgs2VoiceCallbackHandler)(const OrbisNgs2VoiceCallbackInfo* info);
struct OrbisNgs2VoiceCallbackParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2VoiceCallbackHandler callbackHandler;
uintptr_t callbackData;
u32 flags;
u32 reserved;
};
struct OrbisNgs2VoicePortInfo {
s32 matrixId;
float volume;
u32 numDelaySamples;
u32 destInputId;
OrbisNgs2Handle destHandle;
};
struct OrbisNgs2VoiceMatrixInfo {
u32 numLevels;
float aLevel[ORBIS_NGS2_MAX_MATRIX_LEVELS];
};
struct OrbisNgs2VoiceState {
u32 stateFlags;
}; };
void RegisterlibSceNgs2(Core::Loader::SymbolsResolver* sym); void RegisterlibSceNgs2(Core::Loader::SymbolsResolver* sym);

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View file

@ -0,0 +1,444 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
#include "ngs2_reverb.h"
namespace Libraries::Ngs2 {
class Ngs2Custom;
static const int ORBIS_NGS2_CUSTOM_MAX_MODULES = 24;
static const int ORBIS_NGS2_CUSTOM_MAX_PORTS = 16;
static const int ORBIS_NGS2_CUSTOM_DELAY_MAX_TAPS = 8;
struct OrbisNgs2CustomModuleOption {
u32 size;
};
struct OrbisNgs2CustomEnvelopeModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 maxPoints;
u32 reserved;
};
struct OrbisNgs2CustomReverbModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 reverbSize;
u32 reserved;
};
struct OrbisNgs2CustomChorusModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 maxPhases;
u32 reserved;
} OrbisNgs2CustomChorusModuleOption;
struct OrbisNgs2CustomPeakMeterModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 numBlocks;
u32 reserved;
};
struct OrbisNgs2CustomDelayModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 type;
u32 maxTaps;
float maxLength;
u32 reserved;
};
struct OrbisNgs2CustomPitchShiftModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 quality;
};
struct OrbisNgs2CustomUserFx2ModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
OrbisNgs2UserFx2SetupHandler setupHandler;
OrbisNgs2UserFx2CleanupHandler cleanupHandler;
OrbisNgs2UserFx2ControlHandler controlHandler;
OrbisNgs2UserFx2ProcessHandler processHandler;
size_t commonSize;
size_t paramSize;
size_t workSize;
uintptr_t userData;
};
struct OrbisNgs2CustomRackModuleInfo {
const OrbisNgs2CustomModuleOption* option;
u32 moduleId;
u32 sourceBufferId;
u32 extraBufferId;
u32 destBufferId;
u32 stateOffset;
u32 stateSize;
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomRackPortInfo {
u32 sourceBufferId;
u32 reserved;
};
struct OrbisNgs2CustomRackOption {
OrbisNgs2RackOption rackOption;
u32 stateSize;
u32 numBuffers;
u32 numModules;
u32 reserved;
OrbisNgs2CustomRackModuleInfo aModule[ORBIS_NGS2_CUSTOM_MAX_MODULES];
OrbisNgs2CustomRackPortInfo aPort[ORBIS_NGS2_CUSTOM_MAX_PORTS];
};
struct OrbisNgs2CustomSamplerRackOption {
OrbisNgs2CustomRackOption customRackOption;
u32 maxChannelWorks;
u32 maxWaveformBlocks;
u32 maxAtrac9Decoders;
u32 maxAtrac9ChannelWorks;
u32 maxAjmAtrac9Decoders;
u32 maxCodecCaches;
};
struct OrbisNgs2CustomSubmixerRackOption {
OrbisNgs2CustomRackOption customRackOption;
u32 maxChannels;
u32 maxInputs;
};
struct OrbisNgs2CustomMasteringRackOption {
OrbisNgs2CustomRackOption customRackOption;
u32 maxChannels;
u32 maxInputs;
};
struct OrbisNgs2CustomSamplerVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2WaveformFormat format;
u32 flags;
u32 reserved;
};
struct OrbisNgs2CustomSamplerVoiceWaveformBlocksParam {
OrbisNgs2VoiceParamHeader header;
const void* data;
u32 flags;
u32 numBlocks;
const OrbisNgs2WaveformBlock* aBlock;
};
struct OrbisNgs2CustomSamplerVoiceWaveformAddressParam {
OrbisNgs2VoiceParamHeader header;
const void* from;
const void* to;
};
struct OrbisNgs2CustomSamplerVoiceWaveformFrameOffsetParam {
OrbisNgs2VoiceParamHeader header;
u32 frameOffset;
u32 reserved;
};
struct OrbisNgs2CustomSamplerVoiceExitLoopParam {
OrbisNgs2VoiceParamHeader header;
};
struct OrbisNgs2CustomSamplerVoicePitchParam {
OrbisNgs2VoiceParamHeader header;
float ratio;
u32 reserved;
};
struct OrbisNgs2CustomSamplerVoiceState {
OrbisNgs2VoiceState voiceState;
char padding[32];
const void* waveformData;
u64 numDecodedSamples;
u64 decodedDataSize;
u64 userData;
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomSubmixerVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numInputChannels;
u32 numOutputChannels;
u32 flags;
u32 reserved;
};
struct OrbisNgs2CustomSubmixerVoiceState {
OrbisNgs2VoiceState voiceState; // Voice state
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomMasteringVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numInputChannels;
u32 flags;
};
struct OrbisNgs2CustomMasteringVoiceOutputParam {
OrbisNgs2VoiceParamHeader header;
u32 outputId;
u32 reserved;
};
struct OrbisNgs2CustomMasteringVoiceState {
OrbisNgs2VoiceState voiceState;
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomVoiceEnvelopeParam {
OrbisNgs2VoiceParamHeader header;
u32 numForwardPoints;
u32 numReleasePoints;
const OrbisNgs2EnvelopePoint* aPoint;
};
struct OrbisNgs2CustomVoiceDistortionParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float a;
float b;
float clip;
float gate;
float wetLevel;
float dryLevel;
u32 reserved;
};
struct OrbisNgs2CustomVoiceCompressorParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float threshold;
float ratio;
float knee;
float attackTime;
float releaseTime;
float level;
u32 reserved;
};
struct OrbisNgs2CustomVoiceFilterParam {
OrbisNgs2VoiceParamHeader header;
u32 type;
u32 channelMask;
union {
struct {
float i0;
float i1;
float i2;
float o1;
float o2;
} direct;
struct {
float fc;
float q;
float level;
u32 reserved;
u32 reserved2;
} fcq;
} param;
u32 reserved3;
};
struct OrbisNgs2CustomVoiceLfeFilterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 fc;
};
struct OrbisNgs2CustomVoiceGainParam {
OrbisNgs2VoiceParamHeader header;
float aLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS];
};
struct OrbisNgs2CustomVoiceMixerParam {
OrbisNgs2VoiceParamHeader header;
float aSourceLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS];
float aDestLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS];
};
struct OrbisNgs2CustomVoiceChannelMixerParam {
OrbisNgs2VoiceParamHeader header;
float aLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS][ORBIS_NGS2_MAX_VOICE_CHANNELS];
};
struct OrbisNgs2CustomVoiceUserFxParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2UserFxProcessHandler handler;
uintptr_t userData0;
uintptr_t userData1;
uintptr_t userData2;
};
struct OrbisNgs2CustomVoiceUserFx2Param {
OrbisNgs2VoiceParamHeader header;
const void* data;
size_t dataSize;
};
struct OrbisNgs2CustomVoiceOutputParam {
OrbisNgs2VoiceParamHeader header;
u32 outputId;
u32 reserved;
};
struct OrbisNgs2CustomVoicePeakMeterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 reserved;
} OrbisNgs2CustomVoicePeakMeterParam;
struct OrbisNgs2CustomVoiceReverbParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2ReverbI3DL2Param i3dl2;
};
struct OrbisNgs2CustomVoiceChorusParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
u32 numPhases;
u32 channelMask;
float inputLevel;
float delayTime;
float modulationRatio;
float modulationDepth;
float feedbackLevel;
float wetLevel;
float dryLevel;
};
struct OrbisNgs2DelayTapInfo {
float tapLevel;
float delayTime;
};
struct OrbisNgs2CustomVoiceDelayParam {
OrbisNgs2VoiceParamHeader header;
float dryLevel;
float wetLevel;
float inputLevel;
float feedbackLevel;
float lowpassFc;
u32 numTaps;
OrbisNgs2DelayTapInfo aTap[ORBIS_NGS2_CUSTOM_DELAY_MAX_TAPS];
float aInputMixLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS];
u32 channelMask;
u32 flags;
};
struct OrbisNgs2CustomVoiceNoiseGateParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float threshold;
float attackTime;
float releaseTime;
};
struct OrbisNgs2CustomVoicePitchShiftParam {
OrbisNgs2VoiceParamHeader header;
s32 cent;
};
struct OrbisNgs2CustomEnvelopeModuleState {
float height;
u32 reserved;
};
struct OrbisNgs2CustomCompressorModuleState {
float peakHeight;
float compressorHeight;
};
struct OrbisNgs2CustomPeakMeterModuleState {
float peak;
float aChannelPeak[ORBIS_NGS2_MAX_VOICE_CHANNELS];
u32 reserved;
};
struct OrbisNgs2CustomNoiseGateModuleState {
float gateHeight;
};
struct OrbisNgs2CustomRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 stateSize;
u32 numBuffers;
u32 numModules;
u32 reserved;
OrbisNgs2CustomRackModuleInfo aModule[ORBIS_NGS2_CUSTOM_MAX_MODULES];
OrbisNgs2CustomRackPortInfo aPort[ORBIS_NGS2_CUSTOM_MAX_PORTS];
};
struct OrbisNgs2CustomSamplerRackInfo {
OrbisNgs2CustomRackInfo customRackInfo;
u32 maxChannelWorks;
u32 maxWaveformBlocks;
u32 maxAtrac9Decoders;
u32 maxAtrac9ChannelWorks;
u32 maxAjmAtrac9Decoders;
u32 maxCodecCaches;
};
struct OrbisNgs2CustomSubmixerRackInfo {
OrbisNgs2CustomRackInfo customRackInfo;
u32 maxChannels;
u32 maxInputs;
};
struct OrbisNgs2CustomMasteringRackInfo {
OrbisNgs2CustomRackInfo customRackInfo;
u32 maxChannels;
u32 maxInputs;
};
struct OrbisNgs2CustomModuleInfo {
u32 moduleId;
u32 sourceBufferId;
u32 extraBufferId;
u32 destBufferId;
u32 stateOffset;
u32 stateSize;
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomEnvelopeModuleInfo {
OrbisNgs2CustomModuleInfo moduleInfo;
u32 maxPoints;
u32 reserved;
};
struct OrbisNgs2CustomReverbModuleInfo {
OrbisNgs2CustomModuleInfo moduleInfo;
u32 reverbSize;
u32 reserved;
};
} // namespace Libraries::Ngs2

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View file

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Eq;
struct OrbisNgs2EqVoiceSetupParam {
u32 numChannels;
};
struct OrbisNgs2EqVoiceFilterParam {
u32 type;
u32 channelMask;
union {
struct {
float i0;
float i1;
float i2;
float o1;
float o2;
} direct;
struct {
float fc;
float q;
float level;
u32 reserved;
u32 reserved2;
} fcq;
} param;
};
struct OrbisNgs2EqVoiceState {
u32 stateFlags;
};
} // namespace Libraries::Ngs2

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View file

@ -0,0 +1,80 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Geom;
struct OrbisNgs2GeomVector {
float x;
float y;
float z;
};
struct OrbisNgs2GeomCone {
float innerLevel;
float innerAngle;
float outerLevel;
float outerAngle;
};
struct OrbisNgs2GeomRolloff {
u32 model;
float maxDistance;
float rolloffFactor;
float referenceDistance;
};
struct OrbisNgs2GeomListenerParam {
OrbisNgs2GeomVector position;
OrbisNgs2GeomVector orientFront;
OrbisNgs2GeomVector orientUp;
OrbisNgs2GeomVector velocity;
float soundSpeed;
u32 reserved[2];
};
struct OrbisNgs2GeomListenerWork {
float matrix[4][4];
OrbisNgs2GeomVector velocity;
float soundSpeed;
u32 coordinate;
u32 reserved[3];
};
struct OrbisNgs2GeomSourceParam {
OrbisNgs2GeomVector position;
OrbisNgs2GeomVector velocity;
OrbisNgs2GeomVector direction;
OrbisNgs2GeomCone cone;
OrbisNgs2GeomRolloff rolloff;
float dopplerFactor;
float fbwLevel;
float lfeLevel;
float maxLevel;
float minLevel;
float radius;
u32 numSpeakers;
u32 matrixFormat;
u32 reserved[2];
};
struct OrbisNgs2GeomA3dAttribute {
OrbisNgs2GeomVector position;
float volume;
u32 reserved[4];
};
struct OrbisNgs2GeomAttribute {
float pitchRatio;
float aLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS * ORBIS_NGS2_MAX_VOICE_CHANNELS];
OrbisNgs2GeomA3dAttribute a3dAttrib;
u32 reserved[4];
};
} // namespace Libraries::Ngs2

View file

@ -12,153 +12,171 @@ using namespace Libraries::Kernel;
namespace Libraries::Ngs2 { namespace Libraries::Ngs2 {
s32 Ngs2::ReportInvalid(Ngs2Handle* handle, u32 handle_type) const { s32 HandleReportInvalid(OrbisNgs2Handle handle, u32 handleType) {
uintptr_t hAddress = reinterpret_cast<uintptr_t>(handle); switch (handleType) {
switch (handle_type) {
case 1: case 1:
LOG_ERROR(Lib_Ngs2, "Invalid system handle {}", hAddress); LOG_ERROR(Lib_Ngs2, "Invalid system handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE; return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
case 2: case 2:
LOG_ERROR(Lib_Ngs2, "Invalid rack handle {}", hAddress); LOG_ERROR(Lib_Ngs2, "Invalid rack handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE; return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
case 4: case 4:
LOG_ERROR(Lib_Ngs2, "Invalid voice handle {}", hAddress); LOG_ERROR(Lib_Ngs2, "Invalid voice handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE; return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
case 8: case 8:
LOG_ERROR(Lib_Ngs2, "Invalid report handle {}", hAddress); LOG_ERROR(Lib_Ngs2, "Invalid report handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_REPORT_HANDLE; return ORBIS_NGS2_ERROR_INVALID_REPORT_HANDLE;
default: default:
LOG_ERROR(Lib_Ngs2, "Invalid handle {}", hAddress); LOG_ERROR(Lib_Ngs2, "Invalid handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_HANDLE; return ORBIS_NGS2_ERROR_INVALID_HANDLE;
} }
} }
s32 Ngs2::HandleSetup(Ngs2Handle* handle, void* data, std::atomic<u32>* atomic, u32 type, void* MemoryClear(void* buffer, size_t size) {
u32 flags) { return memset(buffer, 0, size);
handle->dataPointer = data;
handle->atomicPtr = atomic;
handle->handleType = type;
handle->flags_unk = flags;
return ORBIS_OK;
} }
s32 Ngs2::HandleCleanup(Ngs2Handle* handle, u32 hType, void* dataOut) { s32 StackBufferClose(StackBuffer* stackBuffer, size_t* outTotalSize) {
if (handle && handle->selfPointer == handle) { if (outTotalSize) {
std::atomic<u32>* tmp_atomic = handle->atomicPtr; *outTotalSize = stackBuffer->usedSize + stackBuffer->alignment;
if (tmp_atomic && handle->handleType == hType) {
while (tmp_atomic->load() != 0) {
u32 expected = 1;
if (tmp_atomic->compare_exchange_strong(expected, 0)) {
if (dataOut) {
dataOut = handle->dataPointer;
}
// sceNgs2MemoryClear(handle, 32);
return ORBIS_OK;
}
tmp_atomic = handle->atomicPtr;
}
}
}
return this->ReportInvalid(handle, hType);
}
s32 Ngs2::HandleEnter(Ngs2Handle* handle, u32 hType, Ngs2Handle* handleOut) {
if (!handle) {
return this->ReportInvalid(handle, 0);
}
if (handle->selfPointer != handle || !handle->atomicPtr || !handle->dataPointer ||
(~hType & handle->handleType)) {
return this->ReportInvalid(handle, handle->handleType);
}
std::atomic<u32>* atomic = handle->atomicPtr;
while (true) {
u32 i = atomic->load();
if (i == 0) {
return this->ReportInvalid(handle, handle->handleType);
}
if (atomic->compare_exchange_strong(i, i + 1)) {
break;
}
}
if (handleOut) {
handleOut = handle;
} }
return ORBIS_OK; return ORBIS_OK;
} }
s32 Ngs2::HandleLeave(Ngs2Handle* handle) { s32 StackBufferOpen(StackBuffer* stackBuffer, void* bufferStart, size_t bufferSize,
std::atomic<u32>* tmp_atomic; void** outBuffer, u8 flags) {
u32 i; stackBuffer->top = outBuffer;
do { stackBuffer->base = bufferStart;
tmp_atomic = handle->atomicPtr; stackBuffer->size = (size_t)bufferStart;
i = tmp_atomic->load(); stackBuffer->currentOffset = (size_t)bufferStart;
} while (!tmp_atomic->compare_exchange_strong(i, i - 1)); stackBuffer->usedSize = 0;
return ORBIS_OK; stackBuffer->totalSize = bufferSize;
} stackBuffer->alignment = 8; // this is a fixed value
stackBuffer->flags = flags;
s32 Ngs2::StackBufferOpen(StackBuffer* buf, void* base_addr, size_t size, void** stackTop, if (outBuffer != NULL) {
bool verify) { *outBuffer = NULL;
buf->top = stackTop;
buf->base = base_addr;
buf->curr = base_addr;
buf->usedSize = 0;
buf->totalSize = size;
buf->alignment = 8;
buf->isVerifyEnabled = verify;
if (stackTop) {
*stackTop = nullptr;
} }
return ORBIS_OK; return ORBIS_OK;
} }
s32 Ngs2::StackBufferClose(StackBuffer* buf, size_t* usedSize) { s32 SystemCleanup(OrbisNgs2Handle systemHandle, OrbisNgs2ContextBufferInfo* outInfo) {
if (usedSize) { if (!systemHandle) {
*usedSize = buf->usedSize + buf->alignment; return ORBIS_NGS2_ERROR_INVALID_HANDLE;
} }
// TODO
return ORBIS_OK; return ORBIS_OK;
} }
s32 Ngs2::SystemSetupCore(StackBuffer* buf, SystemOptions* options, Ngs2Handle** sysOut) { s32 SystemSetupCore(StackBuffer* stackBuffer, const OrbisNgs2SystemOption* option,
SystemInternal* outSystem) {
u32 maxGrainSamples = 512; u32 maxGrainSamples = 512;
u32 numGrainSamples = 256; u32 numGrainSamples = 256;
u32 sampleRate = 48000; u32 sampleRate = 48000;
if (options) { if (option) {
maxGrainSamples = options->maxGrainSamples; sampleRate = option->sampleRate;
numGrainSamples = options->numGrainSamples; maxGrainSamples = option->maxGrainSamples;
sampleRate = options->sampleRate; numGrainSamples = option->numGrainSamples;
} }
// Validate maxGrainSamples if (maxGrainSamples < 64 || maxGrainSamples > 1024 || (maxGrainSamples & 63) != 0) {
if (maxGrainSamples < 64 || maxGrainSamples > 1024 || (maxGrainSamples & 0x3F) != 0) {
LOG_ERROR(Lib_Ngs2, "Invalid system option (maxGrainSamples={},x64)", maxGrainSamples); LOG_ERROR(Lib_Ngs2, "Invalid system option (maxGrainSamples={},x64)", maxGrainSamples);
return ORBIS_NGS2_ERROR_INVALID_MAX_GRAIN_SAMPLES; return ORBIS_NGS2_ERROR_INVALID_MAX_GRAIN_SAMPLES;
} }
// Validate numGrainSamples if (numGrainSamples < 64 || numGrainSamples > 1024 || (numGrainSamples & 63) != 0) {
if (numGrainSamples < 64 || numGrainSamples > 1024 || (numGrainSamples & 0x3F) != 0) {
LOG_ERROR(Lib_Ngs2, "Invalid system option (numGrainSamples={},x64)", numGrainSamples); LOG_ERROR(Lib_Ngs2, "Invalid system option (numGrainSamples={},x64)", numGrainSamples);
return ORBIS_NGS2_ERROR_INVALID_NUM_GRAIN_SAMPLES; return ORBIS_NGS2_ERROR_INVALID_NUM_GRAIN_SAMPLES;
} }
// Validate sampleRate
if (sampleRate != 11025 && sampleRate != 12000 && sampleRate != 22050 && sampleRate != 24000 && if (sampleRate != 11025 && sampleRate != 12000 && sampleRate != 22050 && sampleRate != 24000 &&
sampleRate != 44100 && sampleRate != 48000 && sampleRate != 88200 && sampleRate != 96000) { sampleRate != 44100 && sampleRate != 48000 && sampleRate != 88200 && sampleRate != 96000 &&
sampleRate != 176400 && sampleRate != 192000) {
LOG_ERROR(Lib_Ngs2, "Invalid system option(sampleRate={}:44.1/48kHz series)", sampleRate); LOG_ERROR(Lib_Ngs2, "Invalid system option(sampleRate={}:44.1/48kHz series)", sampleRate);
return ORBIS_NGS2_ERROR_INVALID_SAMPLE_RATE; return ORBIS_NGS2_ERROR_INVALID_SAMPLE_RATE;
} }
int result = ORBIS_OK; return ORBIS_OK;
}
s32 SystemSetup(const OrbisNgs2SystemOption* option, OrbisNgs2ContextBufferInfo* hostBufferInfo,
OrbisNgs2BufferFreeHandler hostFree, OrbisNgs2Handle* outHandle) {
u8 optionFlags = 0;
StackBuffer stackBuffer;
SystemInternal setupResult;
void* systemList = NULL;
size_t requiredBufferSize = 0;
u32 result = ORBIS_NGS2_ERROR_INVALID_BUFFER_SIZE;
if (option) {
if (option->size != 64) {
LOG_ERROR(Lib_Ngs2, "Invalid system option size ({})", option->size);
return ORBIS_NGS2_ERROR_INVALID_OPTION_SIZE;
}
optionFlags = option->flags >> 31;
}
// Init
StackBufferOpen(&stackBuffer, NULL, 0, NULL, optionFlags);
result = SystemSetupCore(&stackBuffer, option, 0);
if (result < 0) {
return result;
}
StackBufferClose(&stackBuffer, &requiredBufferSize);
// outHandle unprovided
if (!outHandle) {
hostBufferInfo->hostBuffer = NULL;
hostBufferInfo->hostBufferSize = requiredBufferSize;
MemoryClear(&hostBufferInfo->reserved, sizeof(hostBufferInfo->reserved));
return ORBIS_OK;
}
if (!hostBufferInfo->hostBuffer) {
LOG_ERROR(Lib_Ngs2, "Invalid system buffer address ({})", hostBufferInfo->hostBuffer);
return ORBIS_NGS2_ERROR_INVALID_BUFFER_ADDRESS;
}
if (hostBufferInfo->hostBufferSize < requiredBufferSize) {
LOG_ERROR(Lib_Ngs2, "Invalid system buffer size ({}<{}[byte])",
hostBufferInfo->hostBufferSize, requiredBufferSize);
return ORBIS_NGS2_ERROR_INVALID_BUFFER_SIZE;
}
// Setup
StackBufferOpen(&stackBuffer, hostBufferInfo->hostBuffer, hostBufferInfo->hostBufferSize,
&systemList, optionFlags);
result = SystemSetupCore(&stackBuffer, option, &setupResult);
if (result < 0) {
return result;
}
StackBufferClose(&stackBuffer, &requiredBufferSize);
// Copy buffer results
setupResult.bufferInfo = *hostBufferInfo;
setupResult.hostFree = hostFree;
// TODO // TODO
// setupResult.systemList = systemList;
return result; // Success OrbisNgs2Handle systemHandle = setupResult.systemHandle;
if (hostBufferInfo->hostBufferSize >= requiredBufferSize) {
*outHandle = systemHandle;
return ORBIS_OK;
}
SystemCleanup(systemHandle, 0);
LOG_ERROR(Lib_Ngs2, "Invalid system buffer size ({}<{}[byte])", hostBufferInfo->hostBufferSize,
requiredBufferSize);
return ORBIS_NGS2_ERROR_INVALID_BUFFER_SIZE;
} }
} // namespace Libraries::Ngs2 } // namespace Libraries::Ngs2

View file

@ -3,23 +3,176 @@
#pragma once #pragma once
#include "ngs2.h" #include "core/libraries/kernel/threads/pthread.h"
namespace Libraries::Ngs2 { namespace Libraries::Ngs2 {
class Ngs2 { static const int ORBIS_NGS2_SYSTEM_NAME_LENGTH = 16;
public: static const int ORBIS_NGS2_RACK_NAME_LENGTH = 16;
s32 ReportInvalid(Ngs2Handle* handle, u32 handle_type) const;
s32 HandleSetup(Ngs2Handle* handle, void* data, std::atomic<u32>* atomic, u32 type, u32 flags);
s32 HandleCleanup(Ngs2Handle* handle, u32 hType, void* dataOut);
s32 HandleEnter(Ngs2Handle* handle, u32 hType, Ngs2Handle* handleOut);
s32 HandleLeave(Ngs2Handle* handle);
s32 StackBufferOpen(StackBuffer* buf, void* base_addr, size_t size, void** stackTop,
bool verify);
s32 StackBufferClose(StackBuffer* buf, size_t* usedSize);
s32 SystemSetupCore(StackBuffer* buf, SystemOptions* options, Ngs2Handle** sysOut);
private: typedef uintptr_t OrbisNgs2Handle;
struct OrbisNgs2ContextBufferInfo {
void* hostBuffer;
size_t hostBufferSize;
uintptr_t reserved[5];
uintptr_t userData;
}; };
struct OrbisNgs2SystemOption {
size_t size;
char name[ORBIS_NGS2_SYSTEM_NAME_LENGTH];
u32 flags;
u32 maxGrainSamples;
u32 numGrainSamples;
u32 sampleRate;
u32 aReserved[6];
};
typedef s32 (*OrbisNgs2BufferAllocHandler)(OrbisNgs2ContextBufferInfo* ioBufferInfo);
typedef s32 (*OrbisNgs2BufferFreeHandler)(OrbisNgs2ContextBufferInfo* ioBufferInfo);
struct OrbisNgs2SystemInfo {
char name[ORBIS_NGS2_SYSTEM_NAME_LENGTH]; // 0
OrbisNgs2Handle systemHandle; // 16
OrbisNgs2ContextBufferInfo bufferInfo; // 24
u32 uid; // 88
u32 minGrainSamples; // 92
u32 maxGrainSamples; // 96
u32 stateFlags; // 100
u32 rackCount; // 104
float lastRenderRatio; // 108
s64 lastRenderTick; // 112
s64 renderCount; // 120
u32 sampleRate; // 128
u32 numGrainSamples; // 132
};
struct OrbisNgs2RackInfo {
char name[ORBIS_NGS2_RACK_NAME_LENGTH]; // 0
OrbisNgs2Handle rackHandle; // 16
OrbisNgs2ContextBufferInfo bufferInfo; // 24
OrbisNgs2Handle ownerSystemHandle; // 88
u32 type; // 96
u32 rackId; // 100
u32 uid; // 104
u32 minGrainSamples; // 108
u32 maxGrainSamples; // 112
u32 maxVoices; // 116
u32 maxChannelWorks; // 120
u32 maxInputs; // 124
u32 maxMatrices; // 128
u32 maxPorts; // 132
u32 stateFlags; // 136
float lastProcessRatio; // 140
u64 lastProcessTick; // 144
u64 renderCount; // 152
u32 activeVoiceCount; // 160
u32 activeChannelWorkCount; // 164
};
struct StackBuffer {
void** top;
void* base;
size_t size;
size_t currentOffset;
size_t usedSize;
size_t totalSize;
size_t alignment;
u8 flags;
char padding[7];
};
struct SystemInternal {
// setup init
char name[ORBIS_NGS2_SYSTEM_NAME_LENGTH]; // 0
OrbisNgs2ContextBufferInfo bufferInfo; // 16
OrbisNgs2BufferFreeHandler hostFree; // 80
OrbisNgs2Handle systemHandle; // 88
void* unknown1; // 96
void* unknown2; // 104
OrbisNgs2Handle rackHandle; // 112
uintptr_t* userData; // 120
SystemInternal* systemList; // 128
StackBuffer* stackBuffer; // 136
OrbisNgs2SystemInfo ownerSystemInfo; // 144
struct rackList {
void* prev;
void* next;
void* unknown;
};
rackList rackListPreset; // 152
rackList rackListNormal; // 176
rackList rackListMaster; // 200
void* unknown3; // 208
void* systemListPrev; // 216
void* unknown4; // 224
void* systemListNext; // 232
void* rackFunction; // 240
Kernel::PthreadMutex processLock; // 248
u32 hasProcessMutex; // 256
u32 unknown5; // 260
Kernel::PthreadMutex flushLock; // 264
u32 hasFlushMutex; // 272
u32 unknown6; // 276
// info
u64 lastRenderTick; // 280
u64 renderCount; // 288
u32 isActive; // 296
std::atomic<int> lockCount; // 300
u32 uid; // 304
u32 systemType; // 308
struct {
u8 isBufferValid : 1;
u8 isRendering : 1;
u8 isSorted : 1;
u8 isFlushReady : 1;
} flags; // 312
u16 currentMaxGrainSamples; // 316
u16 minGrainSamples; // 318
u16 maxGrainSamples; // 320
u16 numGrainSamples; // 322
u32 currentNumGrainSamples; // 324
u32 sampleRate; // 328
u32 currentSampleRate; // 332
u32 rackCount; // 336
float lastRenderRatio; // 340
float cpuLoad; // 344
};
struct HandleInternal {
HandleInternal* selfPtr; // 0
SystemInternal* systemData; // 8
std::atomic<int> refCount; // 16
u32 handleType; // 24
u32 handleID; // 28
};
s32 StackBufferClose(StackBuffer* stackBuffer, size_t* outTotalSize);
s32 StackBufferOpen(StackBuffer* stackBuffer, void* buffer, size_t bufferSize, void** outBuffer,
u8 flags);
s32 SystemSetupCore(StackBuffer* stackBuffer, const OrbisNgs2SystemOption* option,
SystemInternal* outSystem);
s32 HandleReportInvalid(OrbisNgs2Handle handle, u32 handleType);
void* MemoryClear(void* buffer, size_t size);
s32 SystemCleanup(OrbisNgs2Handle systemHandle, OrbisNgs2ContextBufferInfo* outInfo);
s32 SystemSetup(const OrbisNgs2SystemOption* option, OrbisNgs2ContextBufferInfo* hostBufferInfo,
OrbisNgs2BufferFreeHandler hostFree, OrbisNgs2Handle* outHandle);
} // namespace Libraries::Ngs2 } // namespace Libraries::Ngs2

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View file

@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Mastering;
struct OrbisNgs2MasteringRackOption {
OrbisNgs2RackOption rackOption;
u32 maxChannels;
u32 numPeakMeterBlocks;
};
struct OrbisNgs2MasteringVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numInputChannels;
u32 flags;
};
struct OrbisNgs2MasteringVoiceMatrixParam {
OrbisNgs2VoiceParamHeader header;
u32 type;
u32 numLevels;
const float* aLevel;
};
struct OrbisNgs2MasteringVoiceLfeParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 fc;
};
struct OrbisNgs2MasteringVoiceLimiterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
float threshold;
};
struct OrbisNgs2MasteringVoiceGainParam {
OrbisNgs2VoiceParamHeader header;
float fbwLevel;
float lfeLevel;
};
struct OrbisNgs2MasteringVoiceOutputParam {
OrbisNgs2VoiceParamHeader header;
u32 outputId;
u32 reserved;
};
struct OrbisNgs2MasteringVoicePeakMeterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 reserved;
};
struct OrbisNgs2MasteringVoiceState {
OrbisNgs2VoiceState voiceState;
float limiterPeakLevel;
float limiterPressLevel;
float aInputPeakHeight[ORBIS_NGS2_MAX_VOICE_CHANNELS];
float aOutputPeakHeight[ORBIS_NGS2_MAX_VOICE_CHANNELS];
};
struct OrbisNgs2MasteringRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 maxChannels;
u32 reserved;
};
} // namespace Libraries::Ngs2

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View file

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Pan;
struct OrbisNgs2PanParam {
float angle;
float distance;
float fbwLevel;
float lfeLevel;
};
struct OrbisNgs2PanWork {
float aSpeakerAngle[ORBIS_NGS2_MAX_VOICE_CHANNELS];
float unitAngle;
u32 numSpeakers;
};
} // namespace Libraries::Ngs2

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View file

@ -0,0 +1,78 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
#include <stdarg.h> // va_list
namespace Libraries::Ngs2 {
class Ngs2Report;
struct OrbisNgs2ReportDataHeader {
size_t size;
OrbisNgs2Handle handle;
u32 type;
s32 result;
};
typedef void (*OrbisNgs2ReportHandler)(const OrbisNgs2ReportDataHeader* data, uintptr_t userData);
struct OrbisNgs2ReportMessageData {
OrbisNgs2ReportDataHeader header;
const char* message;
};
struct OrbisNgs2ReportApiData {
OrbisNgs2ReportDataHeader header;
const char* functionName;
const char* format;
va_list argument;
};
struct OrbisNgs2ReportControlData {
OrbisNgs2ReportDataHeader header;
const OrbisNgs2VoiceParamHeader* param;
};
struct OrbisNgs2ReportOutputData {
OrbisNgs2ReportDataHeader header;
const OrbisNgs2RenderBufferInfo* bufferInfo;
u32 bufferIndex;
u32 sampleRate;
u32 numGrainSamples;
u32 reserved;
};
struct OrbisNgs2ReportCpuLoadData {
OrbisNgs2ReportDataHeader header;
float totalRatio;
float flushRatio;
float processRatio;
float feedbackRatio;
};
struct OrbisNgs2ReportRenderStateData {
OrbisNgs2ReportDataHeader header;
u32 state;
u32 reserved;
};
struct OrbisNgs2ReportVoiceWaveformData {
OrbisNgs2ReportDataHeader header;
u32 location;
u32 waveformType;
u32 numChannels;
u32 sampleRate;
u32 numGrainSamples;
u32 reserved;
void* const* aData;
};
s32 PS4_SYSV_ABI sceNgs2ReportRegisterHandler(u32 reportType, OrbisNgs2ReportHandler handler,
uintptr_t userData, OrbisNgs2Handle* outHandle);
} // namespace Libraries::Ngs2

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View file

@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Reverb;
struct OrbisNgs2ReverbRackOption {
OrbisNgs2RackOption rackOption;
u32 maxChannels;
u32 reverbSize;
};
struct OrbisNgs2ReverbI3DL2Param {
float wet;
float dry;
s32 room;
s32 roomHF;
u32 reflectionPattern;
float decayTime;
float decayHFRatio;
s32 reflections;
float reflectionsDelay;
s32 reverb;
float reverbDelay;
float diffusion;
float density;
float HFReference;
u32 reserve[8];
};
struct OrbisNgs2ReverbVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numInputChannels;
u32 numOutputChannels;
u32 flags;
u32 reserved;
};
struct OrbisNgs2ReverbVoiceI3DL2Param {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2ReverbI3DL2Param i3dl2;
};
struct OrbisNgs2ReverbVoiceState {
OrbisNgs2VoiceState voiceState;
};
struct OrbisNgs2ReverbRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 maxChannels;
u32 reverbSize;
};
} // namespace Libraries::Ngs2

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View file

@ -0,0 +1,162 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Sampler;
struct OrbisNgs2SamplerRackOption {
OrbisNgs2RackOption rackOption;
u32 maxChannelWorks;
u32 maxCodecCaches;
u32 maxWaveformBlocks;
u32 maxEnvelopePoints;
u32 maxFilters;
u32 maxAtrac9Decoders;
u32 maxAtrac9ChannelWorks;
u32 maxAjmAtrac9Decoders;
u32 numPeakMeterBlocks;
};
struct OrbisNgs2SamplerVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2WaveformFormat format;
u32 flags;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceWaveformBlocksParam {
OrbisNgs2VoiceParamHeader header;
const void* data;
u32 flags;
u32 numBlocks;
const OrbisNgs2WaveformBlock* aBlock;
// Blocks
};
struct OrbisNgs2SamplerVoiceWaveformAddressParam {
OrbisNgs2VoiceParamHeader header;
const void* from;
const void* to;
};
struct OrbisNgs2SamplerVoiceWaveformFrameOffsetParam {
OrbisNgs2VoiceParamHeader header;
u32 frameOffset;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceExitLoopParam {
OrbisNgs2VoiceParamHeader header;
};
struct OrbisNgs2SamplerVoicePitchParam {
OrbisNgs2VoiceParamHeader header;
float ratio;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceEnvelopeParam {
OrbisNgs2VoiceParamHeader header;
u32 numForwardPoints;
u32 numReleasePoints;
const OrbisNgs2EnvelopePoint* aPoint;
};
struct OrbisNgs2SamplerVoiceDistortionParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float a;
float b;
float clip;
float gate;
float wetLevel;
float dryLevel;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceUserFxParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2UserFxProcessHandler handler;
uintptr_t userData0;
uintptr_t userData1;
uintptr_t userData2;
};
struct OrbisNgs2SamplerVoicePeakMeterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceFilterParam {
OrbisNgs2VoiceParamHeader header;
u32 index;
u32 location;
u32 type;
u32 channelMask;
union {
struct {
float i0;
float i1;
float i2;
float o1;
float o2;
} direct;
struct {
float fc;
float q;
float level;
u32 reserved;
u32 reserved2;
} fcq;
} param;
u32 reserved3;
};
struct OrbisNgs2SamplerVoiceNumFilters {
OrbisNgs2VoiceParamHeader header;
u32 numFilters;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceState {
OrbisNgs2VoiceState voiceState;
float envelopeHeight;
float peakHeight;
u32 reserved;
u64 numDecodedSamples;
u64 decodedDataSize;
u64 userData;
const void* waveformData;
};
struct OrbisNgs2SamplerRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 maxChannelWorks;
u32 maxCodecCaches;
u32 maxWaveformBlocks;
u32 maxEnvelopePoints;
u32 maxFilters;
u32 maxAtrac9Decoders;
u32 maxAtrac9ChannelWorks;
u32 maxAjmAtrac9Decoders;
};
} // namespace Libraries::Ngs2

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View file

@ -0,0 +1,126 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Submixer;
struct OrbisNgs2SubmixerRackOption {
OrbisNgs2RackOption rackOption;
u32 maxChannels;
u32 maxEnvelopePoints;
u32 maxFilters;
u32 maxInputs;
u32 numPeakMeterBlocks;
};
struct OrbisNgs2SubmixerVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numIoChannels;
u32 flags;
};
struct OrbisNgs2SubmixerVoiceEnvelopeParam {
OrbisNgs2VoiceParamHeader header;
u32 numForwardPoints;
u32 numReleasePoints;
const OrbisNgs2EnvelopePoint* aPoint;
};
struct OrbisNgs2SubmixerVoiceCompressorParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float threshold;
float ratio;
float knee;
float attackTime;
float releaseTime;
float level;
u32 reserved;
};
struct OrbisNgs2SubmixerVoiceDistortionParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float a;
float b;
float clip;
float gate;
float wetLevel;
float dryLevel;
u32 reserved;
};
struct OrbisNgs2SubmixerVoiceUserFxParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2UserFxProcessHandler handler;
uintptr_t userData0;
uintptr_t userData1;
uintptr_t userData2;
};
struct OrbisNgs2SubmixerVoicePeakMeterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 reserved;
};
struct OrbisNgs2SubmixerVoiceFilterParam {
OrbisNgs2VoiceParamHeader header;
u32 index;
u32 location;
u32 type;
u32 channelMask;
union {
struct {
float i0;
float i1;
float i2;
float o1;
float o2;
} direct;
struct {
float fc;
float q;
float level;
u32 reserved;
u32 reserved2;
} fcq;
} param;
u32 reserved3;
};
struct OrbisNgs2SubmixerVoiceNumFilters {
OrbisNgs2VoiceParamHeader header;
u32 numFilters;
u32 reserved;
};
struct OrbisNgs2SubmixerVoiceState {
OrbisNgs2VoiceState voiceState;
float envelopeHeight;
float peakHeight;
float compressorHeight;
};
struct OrbisNgs2SubmixerRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 maxChannels;
u32 maxEnvelopePoints;
u32 maxFilters;
u32 maxInputs;
};
} // namespace Libraries::Ngs2

View file

@ -63,6 +63,7 @@ void VideoOutDriver::Close(s32 handle) {
main_port.is_open = false; main_port.is_open = false;
main_port.flip_rate = 0; main_port.flip_rate = 0;
main_port.prev_index = -1;
ASSERT(main_port.flip_events.empty()); ASSERT(main_port.flip_events.empty());
} }
@ -133,6 +134,10 @@ int VideoOutDriver::RegisterBuffers(VideoOutPort* port, s32 startIndex, void* co
.address_right = 0, .address_right = 0,
}; };
// Reset flip label also when registering buffer
port->buffer_labels[startIndex + i] = 0;
port->SignalVoLabel();
presenter->RegisterVideoOutSurface(group, address); presenter->RegisterVideoOutSurface(group, address);
LOG_INFO(Lib_VideoOut, "buffers[{}] = {:#x}", i + startIndex, address); LOG_INFO(Lib_VideoOut, "buffers[{}] = {:#x}", i + startIndex, address);
} }
@ -190,11 +195,13 @@ void VideoOutDriver::Flip(const Request& req) {
} }
} }
// Reset flip label // Reset prev flip label
if (req.index != -1) { if (port->prev_index != -1) {
port->buffer_labels[req.index] = 0; port->buffer_labels[port->prev_index] = 0;
port->SignalVoLabel(); port->SignalVoLabel();
} }
// save to prev buf index
port->prev_index = req.index;
} }
void VideoOutDriver::DrawBlankFrame() { void VideoOutDriver::DrawBlankFrame() {

View file

@ -32,6 +32,7 @@ struct VideoOutPort {
std::condition_variable vo_cv; std::condition_variable vo_cv;
std::condition_variable vblank_cv; std::condition_variable vblank_cv;
int flip_rate = 0; int flip_rate = 0;
int prev_index = -1;
bool is_open = false; bool is_open = false;
bool is_mode_changing = false; // Used to prevent flip during mode change bool is_mode_changing = false; // Used to prevent flip during mode change

View file

@ -101,6 +101,17 @@ void Linker::Execute(const std::vector<std::string> args) {
memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2); memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2);
// Simulate sceKernelInternalMemory mapping, a mapping usually performed during libkernel init.
// Due to the large size of this mapping, failing to emulate it causes issues in some titles.
// This mapping belongs in the system reserved area, which starts at address 0x880000000.
static constexpr VAddr KernelAllocBase = 0x880000000ULL;
static constexpr s64 InternalMemorySize = 0x1000000;
void* addr_out{reinterpret_cast<void*>(KernelAllocBase)};
const s32 ret = Libraries::Kernel::sceKernelMapNamedFlexibleMemory(
&addr_out, InternalMemorySize, 3, 0, "SceKernelInternalMemory");
ASSERT_MSG(ret == 0, "Unable to perform sceKernelInternalMemory mapping");
main_thread.Run([this, module, args](std::stop_token) { main_thread.Run([this, module, args](std::stop_token) {
Common::SetCurrentThreadName("GAME_MainThread"); Common::SetCurrentThreadName("GAME_MainThread");
LoadSharedLibraries(); LoadSharedLibraries();
@ -372,7 +383,8 @@ void* Linker::AllocateTlsForThread(bool is_primary) {
// If sceKernelMapNamedFlexibleMemory is being called from libkernel and addr = 0 // If sceKernelMapNamedFlexibleMemory is being called from libkernel and addr = 0
// it automatically places mappings in system reserved area instead of managed. // it automatically places mappings in system reserved area instead of managed.
static constexpr VAddr KernelAllocBase = 0x880000000ULL; // Since the system reserved area already has a mapping in it, this address is slightly higher.
static constexpr VAddr KernelAllocBase = 0x881000000ULL;
// The kernel module has a few different paths for TLS allocation. // The kernel module has a few different paths for TLS allocation.
// For SDK < 1.7 it allocates both main and secondary thread blocks using libc mspace/malloc. // For SDK < 1.7 it allocates both main and secondary thread blocks using libc mspace/malloc.

View file

@ -1,28 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/io_file.h"
#include "common/types.h"
#include "loader.h"
namespace Loader {
FileTypes DetectFileType(const std::filesystem::path& filepath) {
// No file loaded
if (filepath.empty()) {
return FileTypes::Unknown;
}
Common::FS::IOFile file;
file.Open(filepath, Common::FS::FileAccessMode::Read);
file.Seek(0);
u32 magic;
file.Read(magic);
file.Close();
switch (magic) {
case PkgMagic:
return FileTypes::Pkg;
}
return FileTypes::Unknown;
}
} // namespace Loader

View file

@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
namespace Loader {
constexpr static u32 PkgMagic = 0x544e437f;
enum class FileTypes {
Unknown,
Pkg,
};
FileTypes DetectFileType(const std::filesystem::path& filepath);
} // namespace Loader

View file

@ -38,6 +38,16 @@ void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1
bool use_extended_mem2) { bool use_extended_mem2) {
const bool is_neo = ::Libraries::Kernel::sceKernelIsNeoMode(); const bool is_neo = ::Libraries::Kernel::sceKernelIsNeoMode();
auto total_size = is_neo ? SCE_KERNEL_TOTAL_MEM_PRO : SCE_KERNEL_TOTAL_MEM; auto total_size = is_neo ? SCE_KERNEL_TOTAL_MEM_PRO : SCE_KERNEL_TOTAL_MEM;
if (Config::isDevKitConsole()) {
const auto old_size = total_size;
// Assuming 2gb is neo for now, will need to link it with sceKernelIsDevKit
total_size += is_neo ? 2_GB : 768_MB;
LOG_WARNING(Kernel_Vmm,
"Config::isDevKitConsole is enabled! Added additional {:s} of direct memory.",
is_neo ? "2 GB" : "768 MB");
LOG_WARNING(Kernel_Vmm, "Old Direct Size: {:#x} -> New Direct Size: {:#x}", old_size,
total_size);
}
if (!use_extended_mem1 && is_neo) { if (!use_extended_mem1 && is_neo) {
total_size -= 256_MB; total_size -= 256_MB;
} }

View file

@ -1,13 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <cryptopp/sha.h>
#include "common/alignment.h" #include "common/alignment.h"
#include "common/arch.h" #include "common/arch.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/memory_patcher.h" #include "common/memory_patcher.h"
#include "common/sha1.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/aerolib/aerolib.h" #include "core/aerolib/aerolib.h"
#include "core/cpu_patches.h" #include "core/cpu_patches.h"
@ -65,11 +64,13 @@ static std::string StringToNid(std::string_view symbol) {
std::memcpy(input.data(), symbol.data(), symbol.size()); std::memcpy(input.data(), symbol.data(), symbol.size());
std::memcpy(input.data() + symbol.size(), Salt.data(), Salt.size()); std::memcpy(input.data() + symbol.size(), Salt.data(), Salt.size());
std::array<u8, CryptoPP::SHA1::DIGESTSIZE> hash; sha1::SHA1::digest8_t hash;
CryptoPP::SHA1().CalculateDigest(hash.data(), input.data(), input.size()); sha1::SHA1 sha;
sha.processBytes(input.data(), input.size());
sha.getDigestBytes(hash);
u64 digest; u64 digest;
std::memcpy(&digest, hash.data(), sizeof(digest)); std::memcpy(&digest, hash, sizeof(digest));
static constexpr std::string_view codes = static constexpr std::string_view codes =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";

View file

@ -82,7 +82,7 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
const auto eboot_name = file.filename().string(); const auto eboot_name = file.filename().string();
auto game_folder = file.parent_path(); auto game_folder = file.parent_path();
if (const auto game_folder_name = game_folder.filename().string(); if (const auto game_folder_name = game_folder.filename().string();
game_folder_name.ends_with("-UPDATE")) { game_folder_name.ends_with("-UPDATE") || game_folder_name.ends_with("-patch")) {
// If an executable was launched from a separate update directory, // If an executable was launched from a separate update directory,
// use the base game directory as the game folder. // use the base game directory as the game folder.
const auto base_name = game_folder_name.substr(0, game_folder_name.size() - 7); const auto base_name = game_folder_name.substr(0, game_folder_name.size() - 7);
@ -291,13 +291,12 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
} }
void Emulator::LoadSystemModules(const std::string& game_serial) { void Emulator::LoadSystemModules(const std::string& game_serial) {
constexpr std::array<SysModules, 11> ModulesToLoad{ constexpr std::array<SysModules, 10> ModulesToLoad{
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2}, {{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
{"libSceUlt.sprx", nullptr}, {"libSceUlt.sprx", nullptr},
{"libSceJson.sprx", nullptr}, {"libSceJson.sprx", nullptr},
{"libSceJson2.sprx", nullptr}, {"libSceJson2.sprx", nullptr},
{"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal}, {"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal},
{"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap},
{"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc}, {"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc},
{"libSceCesCs.sprx", nullptr}, {"libSceCesCs.sprx", nullptr},
{"libSceFont.sprx", &Libraries::Font::RegisterlibSceFont}, {"libSceFont.sprx", &Libraries::Font::RegisterlibSceFont},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 965 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Before After
Before After

BIN
src/images/trophy_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View file

@ -20,7 +20,7 @@ void ScanDirectoryRecursively(const QString& dir, QStringList& filePaths, int cu
QFileInfoList entries = directory.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); QFileInfoList entries = directory.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const auto& entry : entries) { for (const auto& entry : entries) {
if (entry.fileName().endsWith("-UPDATE")) { if (entry.fileName().endsWith("-UPDATE") || entry.fileName().endsWith("-patch")) {
continue; continue;
} }

View file

@ -34,6 +34,12 @@ public:
game_update_path += "-UPDATE"; game_update_path += "-UPDATE";
if (std::filesystem::exists(game_update_path / "sce_sys" / "param.sfo")) { if (std::filesystem::exists(game_update_path / "sce_sys" / "param.sfo")) {
sce_folder_path = game_update_path / "sce_sys" / "param.sfo"; sce_folder_path = game_update_path / "sce_sys" / "param.sfo";
} else {
game_update_path = filePath;
game_update_path += "-patch";
if (std::filesystem::exists(game_update_path / "sce_sys" / "param.sfo")) {
sce_folder_path = game_update_path / "sce_sys" / "param.sfo";
}
} }
PSF psf; PSF psf;

View file

@ -185,7 +185,8 @@ void GameListFrame::SetListBackgroundImage(QTableWidgetItem* item) {
// Recompute if opacity changed or we switched to a different game // Recompute if opacity changed or we switched to a different game
if (opacity != m_last_opacity || game.pic_path != m_current_game_path) { if (opacity != m_last_opacity || game.pic_path != m_current_game_path) {
QImage original_image(QString::fromStdString(game.pic_path.string())); auto image_path = game.pic_path.u8string();
QImage original_image(QString::fromStdString({image_path.begin(), image_path.end()}));
if (!original_image.isNull()) { if (!original_image.isNull()) {
backgroundImage = m_game_list_utils.ChangeImageOpacity( backgroundImage = m_game_list_utils.ChangeImageOpacity(
original_image, original_image.rect(), opacity / 100.0f); original_image, original_image.rect(), opacity / 100.0f);

View file

@ -7,7 +7,6 @@
#include <QDesktopServices> #include <QDesktopServices>
#include <QMenu> #include <QMenu>
#include <QMessageBox> #include <QMessageBox>
#include <QTreeWidget>
#include <QTreeWidgetItem> #include <QTreeWidgetItem>
#include <qt_gui/background_music_player.h> #include <qt_gui/background_music_player.h>
@ -116,7 +115,9 @@ public:
compatibilityMenu->addAction(updateCompatibility); compatibilityMenu->addAction(updateCompatibility);
compatibilityMenu->addAction(viewCompatibilityReport); compatibilityMenu->addAction(viewCompatibilityReport);
compatibilityMenu->addAction(submitCompatibilityReport); if (Common::isRelease) {
compatibilityMenu->addAction(submitCompatibilityReport);
}
menu.addMenu(compatibilityMenu); menu.addMenu(compatibilityMenu);
@ -139,11 +140,17 @@ public:
QString open_update_path; QString open_update_path;
Common::FS::PathToQString(open_update_path, m_games[itemID].path); Common::FS::PathToQString(open_update_path, m_games[itemID].path);
open_update_path += "-UPDATE"; open_update_path += "-UPDATE";
if (!std::filesystem::exists(Common::FS::PathFromQString(open_update_path))) { if (std::filesystem::exists(Common::FS::PathFromQString(open_update_path))) {
QMessageBox::critical(nullptr, tr("Error"),
QString(tr("This game has no update folder to open!")));
} else {
QDesktopServices::openUrl(QUrl::fromLocalFile(open_update_path)); QDesktopServices::openUrl(QUrl::fromLocalFile(open_update_path));
} else {
Common::FS::PathToQString(open_update_path, m_games[itemID].path);
open_update_path += "-patch";
if (std::filesystem::exists(Common::FS::PathFromQString(open_update_path))) {
QDesktopServices::openUrl(QUrl::fromLocalFile(open_update_path));
} else {
QMessageBox::critical(nullptr, tr("Error"),
QString(tr("This game has no update folder to open!")));
}
} }
} }
@ -216,6 +223,12 @@ public:
game_update_path += "-UPDATE"; game_update_path += "-UPDATE";
if (std::filesystem::exists(game_update_path)) { if (std::filesystem::exists(game_update_path)) {
game_folder_path = game_update_path; game_folder_path = game_update_path;
} else {
game_update_path = game_folder_path;
game_update_path += "-patch";
if (std::filesystem::exists(game_update_path)) {
game_folder_path = game_update_path;
}
} }
if (psf.Open(game_folder_path / "sce_sys" / "param.sfo")) { if (psf.Open(game_folder_path / "sce_sys" / "param.sfo")) {
int rows = psf.GetEntries().size(); int rows = psf.GetEntries().size();
@ -312,8 +325,40 @@ public:
game_update_path += "-UPDATE"; game_update_path += "-UPDATE";
if (std::filesystem::exists(game_update_path)) { if (std::filesystem::exists(game_update_path)) {
Common::FS::PathToQString(gameTrpPath, game_update_path); Common::FS::PathToQString(gameTrpPath, game_update_path);
} else {
game_update_path = Common::FS::PathFromQString(gameTrpPath);
game_update_path += "-patch";
if (std::filesystem::exists(game_update_path)) {
Common::FS::PathToQString(gameTrpPath, game_update_path);
}
} }
TrophyViewer* trophyViewer = new TrophyViewer(trophyPath, gameTrpPath);
// Array with all games and their trophy information
QVector<TrophyGameInfo> allTrophyGames;
for (const auto& game : m_games) {
TrophyGameInfo gameInfo;
gameInfo.name = QString::fromStdString(game.name);
Common::FS::PathToQString(gameInfo.trophyPath, game.serial);
Common::FS::PathToQString(gameInfo.gameTrpPath, game.path);
auto update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath);
update_path += "-UPDATE";
if (std::filesystem::exists(update_path)) {
Common::FS::PathToQString(gameInfo.gameTrpPath, update_path);
} else {
update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath);
update_path += "-patch";
if (std::filesystem::exists(update_path)) {
Common::FS::PathToQString(gameInfo.gameTrpPath, update_path);
}
}
allTrophyGames.append(gameInfo);
}
QString gameName = QString::fromStdString(m_games[itemID].name);
TrophyViewer* trophyViewer =
new TrophyViewer(trophyPath, gameTrpPath, gameName, allTrophyGames);
trophyViewer->show(); trophyViewer->show();
connect(widget->parent(), &QWidget::destroyed, trophyViewer, connect(widget->parent(), &QWidget::destroyed, trophyViewer,
[trophyViewer]() { trophyViewer->deleteLater(); }); [trophyViewer]() { trophyViewer->deleteLater(); });
@ -432,6 +477,9 @@ public:
QString folder_path, game_update_path, dlc_path, save_data_path, trophy_data_path; QString folder_path, game_update_path, dlc_path, save_data_path, trophy_data_path;
Common::FS::PathToQString(folder_path, m_games[itemID].path); Common::FS::PathToQString(folder_path, m_games[itemID].path);
game_update_path = folder_path + "-UPDATE"; game_update_path = folder_path + "-UPDATE";
if (!std::filesystem::exists(Common::FS::PathFromQString(game_update_path))) {
game_update_path = folder_path + "-patch";
}
Common::FS::PathToQString( Common::FS::PathToQString(
dlc_path, Config::getAddonInstallDir() / dlc_path, Config::getAddonInstallDir() /
Common::FS::PathFromQString(folder_path).parent_path().filename()); Common::FS::PathFromQString(folder_path).parent_path().filename());
@ -521,7 +569,7 @@ public:
"title", QString("%1 - %2").arg(QString::fromStdString(m_games[itemID].serial), "title", QString("%1 - %2").arg(QString::fromStdString(m_games[itemID].serial),
QString::fromStdString(m_games[itemID].name))); QString::fromStdString(m_games[itemID].name)));
query.addQueryItem("game-name", QString::fromStdString(m_games[itemID].name)); query.addQueryItem("game-name", QString::fromStdString(m_games[itemID].name));
query.addQueryItem("game-code", QString::fromStdString(m_games[itemID].serial)); query.addQueryItem("game-serial", QString::fromStdString(m_games[itemID].serial));
query.addQueryItem("game-version", QString::fromStdString(m_games[itemID].version)); query.addQueryItem("game-version", QString::fromStdString(m_games[itemID].version));
query.addQueryItem("emulator-version", QString(Common::VERSION)); query.addQueryItem("emulator-version", QString(Common::VERSION));
url.setQuery(query); url.setQuery(query);
@ -552,30 +600,6 @@ public:
return -1; return -1;
} }
void RequestGameMenuPKGViewer(
const QPoint& pos, QStringList m_pkg_app_list, QTreeWidget* treeWidget,
std::function<void(std::filesystem::path, int, int)> InstallDragDropPkg) {
QPoint global_pos = treeWidget->viewport()->mapToGlobal(pos); // context menu position
QTreeWidgetItem* currentItem = treeWidget->currentItem(); // current clicked item
int itemIndex = GetRowIndex(treeWidget, currentItem); // row
QMenu menu(treeWidget);
QAction installPackage(tr("Install PKG"), treeWidget);
menu.addAction(&installPackage);
auto selected = menu.exec(global_pos);
if (!selected) {
return;
}
if (selected == &installPackage) {
QStringList pkg_app_ = m_pkg_app_list[itemIndex].split(";;");
std::filesystem::path path = Common::FS::PathFromQString(pkg_app_[9]);
InstallDragDropPkg(path, 1, 1);
}
}
private: private:
bool convertPngToIco(const QString& pngFilePath, const QString& icoFilePath) { bool convertPngToIco(const QString& pngFilePath, const QString& icoFilePath) {
// Load the PNG image // Load the PNG image

View file

@ -1,94 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QDir>
#include <QFileDialog>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QMessageBox>
#include <QPushButton>
#include <QVBoxLayout>
#include "install_dir_select.h"
InstallDirSelect::InstallDirSelect() : selected_dir() {
auto install_dirs = Config::getGameInstallDirs();
selected_dir = install_dirs.empty() ? "" : install_dirs.front();
if (!install_dirs.empty() && install_dirs.size() == 1) {
accept();
}
auto layout = new QVBoxLayout(this);
layout->addWidget(SetupInstallDirList());
layout->addStretch();
layout->addWidget(SetupDialogActions());
setWindowTitle(tr("shadPS4 - Choose directory"));
setWindowIcon(QIcon(":images/shadps4.ico"));
}
InstallDirSelect::~InstallDirSelect() {}
QWidget* InstallDirSelect::SetupInstallDirList() {
auto group = new QGroupBox(tr("Select which directory you want to install to."));
auto vlayout = new QVBoxLayout();
auto m_path_list = new QListWidget();
QList<QString> qt_list;
for (const auto& str : Config::getGameInstallDirs()) {
QString installDirPath;
Common::FS::PathToQString(installDirPath, str);
qt_list.append(installDirPath);
}
m_path_list->insertItems(0, qt_list);
m_path_list->setSpacing(1);
connect(m_path_list, &QListWidget::itemClicked, this, &InstallDirSelect::setSelectedDirectory);
connect(m_path_list, &QListWidget::itemActivated, this,
&InstallDirSelect::setSelectedDirectory);
vlayout->addWidget(m_path_list);
auto checkbox = new QCheckBox(tr("Install All Queued to Selected Folder"));
connect(checkbox, &QCheckBox::toggled, this, &InstallDirSelect::setUseForAllQueued);
vlayout->addWidget(checkbox);
auto checkbox2 = new QCheckBox(tr("Delete PKG File on Install"));
connect(checkbox2, &QCheckBox::toggled, this, &InstallDirSelect::setDeleteFileOnInstall);
vlayout->addWidget(checkbox2);
group->setLayout(vlayout);
return group;
}
void InstallDirSelect::setSelectedDirectory(QListWidgetItem* item) {
if (item) {
const auto highlighted_path = Common::FS::PathFromQString(item->text());
if (!highlighted_path.empty()) {
selected_dir = highlighted_path;
}
}
}
void InstallDirSelect::setUseForAllQueued(bool enabled) {
use_for_all_queued = enabled;
}
void InstallDirSelect::setDeleteFileOnInstall(bool enabled) {
delete_file_on_install = enabled;
}
QWidget* InstallDirSelect::SetupDialogActions() {
auto actions = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(actions, &QDialogButtonBox::accepted, this, &InstallDirSelect::accept);
connect(actions, &QDialogButtonBox::rejected, this, &InstallDirSelect::reject);
return actions;
}

View file

@ -1,42 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QDialog>
#include <QListWidget>
#include "common/config.h"
#include "common/path_util.h"
class QLineEdit;
class InstallDirSelect final : public QDialog {
Q_OBJECT
public:
InstallDirSelect();
~InstallDirSelect();
std::filesystem::path getSelectedDirectory() {
return selected_dir;
}
bool useForAllQueued() {
return use_for_all_queued;
}
bool deleteFileOnInstall() {
return delete_file_on_install;
}
private:
QWidget* SetupInstallDirList();
QWidget* SetupDialogActions();
void setSelectedDirectory(QListWidgetItem* item);
void setDeleteFileOnInstall(bool enabled);
void setUseForAllQueued(bool enabled);
std::filesystem::path selected_dir;
bool delete_file_on_install = false;
bool use_for_all_queued = false;
};

View file

@ -225,7 +225,8 @@ void EditorDialog::loadInstalledGames() {
QDir parentFolder(installDir); QDir parentFolder(installDir);
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const auto& fileInfo : fileList) { for (const auto& fileInfo : fileList) {
if (fileInfo.isDir() && !fileInfo.filePath().endsWith("-UPDATE")) { if (fileInfo.isDir() && (!fileInfo.filePath().endsWith("-UPDATE") ||
!fileInfo.filePath().endsWith("-patch"))) {
gameComboBox->addItem(fileInfo.fileName()); // Add game name to combo box gameComboBox->addItem(fileInfo.fileName()); // Add game name to combo box
} }
} }

View file

@ -15,7 +15,6 @@
#include "ui_kbm_gui.h" #include "ui_kbm_gui.h"
HelpDialog* HelpWindow; HelpDialog* HelpWindow;
KBMSettings::KBMSettings(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent) KBMSettings::KBMSettings(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent)
: QDialog(parent), m_game_info(game_info_get), ui(new Ui::KBMSettings) { : QDialog(parent), m_game_info(game_info_get), ui(new Ui::KBMSettings) {
@ -48,6 +47,7 @@ KBMSettings::KBMSettings(std::shared_ptr<GameInfoClass> game_info_get, QWidget*
ui->ProfileComboBox->setCurrentText("Common Config"); ui->ProfileComboBox->setCurrentText("Common Config");
ui->TitleLabel->setText("Common Config"); ui->TitleLabel->setText("Common Config");
config_id = "default";
connect(ui->buttonBox, &QDialogButtonBox::clicked, this, [this](QAbstractButton* button) { connect(ui->buttonBox, &QDialogButtonBox::clicked, this, [this](QAbstractButton* button) {
if (button == ui->buttonBox->button(QDialogButtonBox::Save)) { if (button == ui->buttonBox->button(QDialogButtonBox::Save)) {
@ -72,6 +72,7 @@ KBMSettings::KBMSettings(std::shared_ptr<GameInfoClass> game_info_get, QWidget*
connect(ui->TextEditorButton, &QPushButton::clicked, this, [this]() { connect(ui->TextEditorButton, &QPushButton::clicked, this, [this]() {
auto kbmWindow = new EditorDialog(this); auto kbmWindow = new EditorDialog(this);
kbmWindow->exec(); kbmWindow->exec();
SetUIValuestoMappings(config_id);
}); });
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] { connect(ui->buttonBox, &QDialogButtonBox::rejected, this, [this] {
@ -84,9 +85,6 @@ KBMSettings::KBMSettings(std::shared_ptr<GameInfoClass> game_info_get, QWidget*
connect(ui->ProfileComboBox, &QComboBox::currentTextChanged, this, [this] { connect(ui->ProfileComboBox, &QComboBox::currentTextChanged, this, [this] {
GetGameTitle(); GetGameTitle();
std::string config_id = (ui->ProfileComboBox->currentText() == "Common Config")
? "default"
: ui->ProfileComboBox->currentText().toStdString();
SetUIValuestoMappings(config_id); SetUIValuestoMappings(config_id);
}); });
@ -385,10 +383,6 @@ void KBMSettings::SaveKBMConfig(bool CloseOnSave) {
lines.push_back(output_string + " = " + input_string); lines.push_back(output_string + " = " + input_string);
lines.push_back(""); lines.push_back("");
std::string config_id = (ui->ProfileComboBox->currentText() == "Common Config")
? "default"
: ui->ProfileComboBox->currentText().toStdString();
const auto config_file = Config::GetFoolproofKbmConfigFile(config_id); const auto config_file = Config::GetFoolproofKbmConfigFile(config_id);
std::fstream file(config_file); std::fstream file(config_file);
int lineCount = 0; int lineCount = 0;
@ -626,6 +620,9 @@ void KBMSettings::GetGameTitle() {
} }
} }
} }
config_id = (ui->ProfileComboBox->currentText() == "Common Config")
? "default"
: ui->ProfileComboBox->currentText().toStdString();
} }
void KBMSettings::onHelpClicked() { void KBMSettings::onHelpClicked() {

View file

@ -42,7 +42,7 @@ private:
QTimer* timer; QTimer* timer;
QPushButton* MappingButton; QPushButton* MappingButton;
QList<QPushButton*> ButtonsList; QList<QPushButton*> ButtonsList;
std::string config_id;
const std::vector<std::string> ControllerInputs = { const std::vector<std::string> ControllerInputs = {
"cross", "circle", "square", "triangle", "l1", "cross", "circle", "square", "triangle", "l1",
"r1", "l2", "r2", "l3", "r1", "l2", "r2", "l3",

View file

@ -11,10 +11,16 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1193</width> <width>1234</width>
<height>754</height> <height>796</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::StrongFocus</enum> <enum>Qt::FocusPolicy::StrongFocus</enum>
</property> </property>
@ -38,8 +44,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1173</width> <width>1214</width>
<height>704</height> <height>746</height>
</rect> </rect>
</property> </property>
<widget class="QWidget" name="layoutWidget"> <widget class="QWidget" name="layoutWidget">
@ -47,8 +53,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1171</width> <width>1211</width>
<height>703</height> <height>741</height>
</rect> </rect>
</property> </property>
<layout class="QHBoxLayout" name="RemapLayout"> <layout class="QHBoxLayout" name="RemapLayout">
@ -63,7 +69,7 @@
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -149,6 +155,12 @@
<layout class="QHBoxLayout" name="layout_dpad_left_right"> <layout class="QHBoxLayout" name="layout_dpad_left_right">
<item> <item>
<widget class="QGroupBox" name="gb_dpad_left"> <widget class="QGroupBox" name="gb_dpad_left">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Left</string> <string>Left</string>
</property> </property>
@ -180,6 +192,12 @@
</item> </item>
<item> <item>
<widget class="QGroupBox" name="gb_dpad_right"> <widget class="QGroupBox" name="gb_dpad_right">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Right</string> <string>Right</string>
</property> </property>
@ -282,11 +300,17 @@
<item> <item>
<widget class="QGroupBox" name="LeftStickDeadZoneGB"> <widget class="QGroupBox" name="LeftStickDeadZoneGB">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="maximumSize">
<size>
<width>344</width>
<height>16777215</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Left Analog Halfmode</string> <string>Left Analog Halfmode</string>
</property> </property>
@ -319,7 +343,7 @@
<item> <item>
<widget class="QGroupBox" name="gb_left_stick"> <widget class="QGroupBox" name="gb_left_stick">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -405,6 +429,12 @@
<layout class="QHBoxLayout" name="layout_left_stick_left_right"> <layout class="QHBoxLayout" name="layout_left_stick_left_right">
<item> <item>
<widget class="QGroupBox" name="gb_left_stick_left"> <widget class="QGroupBox" name="gb_left_stick_left">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Left</string> <string>Left</string>
</property> </property>
@ -436,6 +466,12 @@
</item> </item>
<item> <item>
<widget class="QGroupBox" name="gb_left_stick_right"> <widget class="QGroupBox" name="gb_left_stick_right">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>179</width> <width>179</width>
@ -528,18 +564,24 @@
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="verticalLayout_middle" stretch="0,0,0,0,0,0"> <layout class="QVBoxLayout" name="verticalLayout_middle" stretch="0,0,0,0,0">
<property name="spacing"> <property name="spacing">
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QGroupBox" name="ProfileGroupBox"> <widget class="QGroupBox" name="ProfileGroupBox">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font"> <property name="font">
<font> <font>
<pointsize>12</pointsize> <pointsize>12</pointsize>
@ -652,6 +694,18 @@
<layout class="QVBoxLayout" name="layout_l1_l2"> <layout class="QVBoxLayout" name="layout_l1_l2">
<item> <item>
<widget class="QGroupBox" name="gb_l1"> <widget class="QGroupBox" name="gb_l1">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>L1</string> <string>L1</string>
</property> </property>
@ -670,6 +724,12 @@
</property> </property>
<item> <item>
<widget class="QPushButton" name="L1Button"> <widget class="QPushButton" name="L1Button">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -683,6 +743,12 @@
</item> </item>
<item> <item>
<widget class="QGroupBox" name="gb_l2"> <widget class="QGroupBox" name="gb_l2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>160</width> <width>160</width>
@ -707,6 +773,12 @@
</property> </property>
<item> <item>
<widget class="QPushButton" name="L2Button"> <widget class="QPushButton" name="L2Button">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -724,6 +796,18 @@
<layout class="QVBoxLayout" name="layout_system_buttons" stretch="0"> <layout class="QVBoxLayout" name="layout_system_buttons" stretch="0">
<item> <item>
<widget class="QGroupBox" name="groupBox_4"> <widget class="QGroupBox" name="groupBox_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="font"> <property name="font">
<font> <font>
<bold>true</bold> <bold>true</bold>
@ -735,6 +819,12 @@
<layout class="QVBoxLayout" name="verticalLayout_20"> <layout class="QVBoxLayout" name="verticalLayout_20">
<item> <item>
<widget class="QPushButton" name="TextEditorButton"> <widget class="QPushButton" name="TextEditorButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -745,6 +835,12 @@
</item> </item>
<item> <item>
<widget class="QPushButton" name="HelpButton"> <widget class="QPushButton" name="HelpButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -762,6 +858,12 @@
<layout class="QVBoxLayout" name="layout_r1_r2"> <layout class="QVBoxLayout" name="layout_r1_r2">
<item> <item>
<widget class="QGroupBox" name="gb_r1"> <widget class="QGroupBox" name="gb_r1">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>160</width> <width>160</width>
@ -786,6 +888,12 @@
</property> </property>
<item> <item>
<widget class="QPushButton" name="R1Button"> <widget class="QPushButton" name="R1Button">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -799,6 +907,18 @@
</item> </item>
<item> <item>
<widget class="QGroupBox" name="gb_r2"> <widget class="QGroupBox" name="gb_r2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>R2</string> <string>R2</string>
</property> </property>
@ -817,6 +937,12 @@
</property> </property>
<item> <item>
<widget class="QPushButton" name="R2Button"> <widget class="QPushButton" name="R2Button">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -857,7 +983,7 @@
<widget class="QLabel" name="l_controller"> <widget class="QLabel" name="l_controller">
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>420</width> <width>500</width>
<height>200</height> <height>200</height>
</size> </size>
</property> </property>
@ -887,6 +1013,12 @@
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<item> <item>
<widget class="QGroupBox" name="gb_l3"> <widget class="QGroupBox" name="gb_l3">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>160</width> <width>160</width>
@ -911,6 +1043,12 @@
</property> </property>
<item> <item>
<widget class="QPushButton" name="L3Button"> <widget class="QPushButton" name="L3Button">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -924,12 +1062,30 @@
</item> </item>
<item> <item>
<widget class="QGroupBox" name="gb_touchpad"> <widget class="QGroupBox" name="gb_touchpad">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Touchpad Click</string> <string>Touchpad Click</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_9"> <layout class="QVBoxLayout" name="verticalLayout_9">
<item> <item>
<widget class="QPushButton" name="TouchpadButton"> <widget class="QPushButton" name="TouchpadButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -947,6 +1103,18 @@
<layout class="QVBoxLayout" name="verticalLayout_21"> <layout class="QVBoxLayout" name="verticalLayout_21">
<item> <item>
<widget class="QGroupBox" name="groupBox_5"> <widget class="QGroupBox" name="groupBox_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Mouse to Joystick</string> <string>Mouse to Joystick</string>
</property> </property>
@ -982,6 +1150,12 @@
<layout class="QVBoxLayout" name="verticalLayout_12"> <layout class="QVBoxLayout" name="verticalLayout_12">
<item> <item>
<widget class="QGroupBox" name="gb_r3"> <widget class="QGroupBox" name="gb_r3">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>160</width> <width>160</width>
@ -1006,6 +1180,12 @@
</property> </property>
<item> <item>
<widget class="QPushButton" name="R3Button"> <widget class="QPushButton" name="R3Button">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -1019,9 +1199,15 @@
</item> </item>
<item> <item>
<widget class="QGroupBox" name="gb_options"> <widget class="QGroupBox" name="gb_options">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>145</width> <width>160</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
@ -1043,6 +1229,12 @@
</property> </property>
<item> <item>
<widget class="QPushButton" name="OptionsButton"> <widget class="QPushButton" name="OptionsButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="focusPolicy"> <property name="focusPolicy">
<enum>Qt::FocusPolicy::NoFocus</enum> <enum>Qt::FocusPolicy::NoFocus</enum>
</property> </property>
@ -1064,6 +1256,12 @@
<layout class="QVBoxLayout" name="verticalLayout_14"> <layout class="QVBoxLayout" name="verticalLayout_14">
<item> <item>
<widget class="QGroupBox" name="MouseParamsBox"> <widget class="QGroupBox" name="MouseParamsBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font"> <property name="font">
<font> <font>
<bold>false</bold> <bold>false</bold>
@ -1196,6 +1394,25 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QLabel" name="MoreInfoLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<italic>true</italic>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>note: click Help Button/Special Keybindings for more information</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -1203,19 +1420,6 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<widget class="QLabel" name="MoreInfoLabel">
<property name="font">
<font>
<italic>true</italic>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>note: click Help Button/Special Keybindings for more information</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
@ -1226,7 +1430,7 @@
<item> <item>
<widget class="QGroupBox" name="gb_face_buttons"> <widget class="QGroupBox" name="gb_face_buttons">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -1306,6 +1510,12 @@
<layout class="QHBoxLayout" name="layout_square_circle"> <layout class="QHBoxLayout" name="layout_square_circle">
<item> <item>
<widget class="QGroupBox" name="gb_square"> <widget class="QGroupBox" name="gb_square">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Square</string> <string>Square</string>
</property> </property>
@ -1337,6 +1547,12 @@
</item> </item>
<item> <item>
<widget class="QGroupBox" name="gb_circle"> <widget class="QGroupBox" name="gb_circle">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Circle</string> <string>Circle</string>
</property> </property>
@ -1444,6 +1660,12 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="maximumSize">
<size>
<width>344</width>
<height>16777215</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Right Analog Halfmode</string> <string>Right Analog Halfmode</string>
</property> </property>
@ -1476,7 +1698,7 @@
<item> <item>
<widget class="QGroupBox" name="gb_right_stick"> <widget class="QGroupBox" name="gb_right_stick">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
@ -1568,6 +1790,12 @@
<layout class="QHBoxLayout" name="layout_right_stick_left_right"> <layout class="QHBoxLayout" name="layout_right_stick_left_right">
<item> <item>
<widget class="QGroupBox" name="gb_right_stick_left"> <widget class="QGroupBox" name="gb_right_stick_left">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Left</string> <string>Left</string>
</property> </property>
@ -1599,6 +1827,12 @@
</item> </item>
<item> <item>
<widget class="QGroupBox" name="gb_right_stick_right"> <widget class="QGroupBox" name="gb_right_stick_right">
<property name="minimumSize">
<size>
<width>160</width>
<height>0</height>
</size>
</property>
<property name="title"> <property name="title">
<string>Right</string> <string>Right</string>
</property> </property>

View file

@ -157,8 +157,8 @@ int main(int argc, char* argv[]) {
} }
} }
// If no game directory is set and no command line argument, prompt for it // If no game directories are set and no command line argument, prompt for it
if (Config::getGameInstallDirs().empty() && !has_command_line_argument) { if (Config::getGameInstallDirsEnabled().empty() && !has_command_line_argument) {
GameInstallDialog dlg; GameInstallDialog dlg;
dlg.exec(); dlg.exec();
} }

View file

@ -1,10 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "SDL3/SDL_events.h"
#include <QDockWidget> #include <QDockWidget>
#include <QKeyEvent> #include <QKeyEvent>
#include <QPlainTextEdit> #include <QPlainTextEdit>
#include <QProgressDialog> #include <QProgressDialog>
#include <QStatusBar>
#include "about_dialog.h" #include "about_dialog.h"
#include "cheats_patches.h" #include "cheats_patches.h"
@ -17,10 +20,7 @@
#include "common/string_util.h" #include "common/string_util.h"
#include "common/version.h" #include "common/version.h"
#include "control_settings.h" #include "control_settings.h"
#include "core/file_format/pkg.h"
#include "core/loader.h"
#include "game_install_dialog.h" #include "game_install_dialog.h"
#include "install_dir_select.h"
#include "kbm_gui.h" #include "kbm_gui.h"
#include "main_window.h" #include "main_window.h"
#include "settings_dialog.h" #include "settings_dialog.h"
@ -45,11 +45,11 @@ MainWindow::~MainWindow() {
bool MainWindow::Init() { bool MainWindow::Init() {
auto start = std::chrono::steady_clock::now(); auto start = std::chrono::steady_clock::now();
// setup ui // setup ui
LoadTranslation();
AddUiWidgets(); AddUiWidgets();
CreateActions(); CreateActions();
CreateRecentGameActions(); CreateRecentGameActions();
ConfigureGuiFromSettings(); ConfigureGuiFromSettings();
LoadTranslation();
CreateDockWindows(); CreateDockWindows();
CreateConnects(); CreateConnects();
SetLastUsedTheme(); SetLastUsedTheme();
@ -132,23 +132,160 @@ void MainWindow::CreateActions() {
m_theme_act_group->addAction(ui->setThemeOled); m_theme_act_group->addAction(ui->setThemeOled);
} }
void MainWindow::PauseGame() {
SDL_Event event;
SDL_memset(&event, 0, sizeof(event));
event.type = SDL_EVENT_TOGGLE_PAUSE;
is_paused = !is_paused;
UpdateToolbarButtons();
SDL_PushEvent(&event);
}
void MainWindow::toggleLabelsUnderIcons() {
bool showLabels = ui->toggleLabelsAct->isChecked();
Config::setShowLabelsUnderIcons();
UpdateToolbarLabels();
if (isGameRunning) {
UpdateToolbarButtons();
}
}
void MainWindow::toggleFullscreen() {
SDL_Event event;
SDL_memset(&event, 0, sizeof(event));
event.type = SDL_EVENT_TOGGLE_FULLSCREEN;
SDL_PushEvent(&event);
}
QWidget* MainWindow::createButtonWithLabel(QPushButton* button, const QString& labelText,
bool showLabel) {
QWidget* container = new QWidget(this);
QVBoxLayout* layout = new QVBoxLayout(container);
layout->setAlignment(Qt::AlignCenter | Qt::AlignBottom);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(button);
QLabel* label = nullptr;
if (showLabel && ui->toggleLabelsAct->isChecked()) {
label = new QLabel(labelText, this);
label->setAlignment(Qt::AlignCenter | Qt::AlignBottom);
layout->addWidget(label);
button->setToolTip("");
} else {
button->setToolTip(labelText);
}
container->setLayout(layout);
container->setProperty("buttonLabel", QVariant::fromValue(label));
return container;
}
QWidget* createSpacer(QWidget* parent) {
QWidget* spacer = new QWidget(parent);
spacer->setFixedWidth(15);
spacer->setFixedHeight(15);
return spacer;
}
void MainWindow::AddUiWidgets() { void MainWindow::AddUiWidgets() {
// add toolbar widgets // add toolbar widgets
QApplication::setStyle("Fusion"); QApplication::setStyle("Fusion");
ui->toolBar->setObjectName("mw_toolbar");
ui->toolBar->addWidget(ui->playButton); bool showLabels = ui->toggleLabelsAct->isChecked();
ui->toolBar->addWidget(ui->pauseButton); ui->toolBar->clear();
ui->toolBar->addWidget(ui->stopButton);
ui->toolBar->addWidget(ui->refreshButton); ui->toolBar->addWidget(createSpacer(this));
ui->toolBar->addWidget(ui->settingsButton); ui->toolBar->addWidget(createButtonWithLabel(ui->playButton, tr("Play"), showLabels));
ui->toolBar->addWidget(ui->controllerButton); ui->toolBar->addWidget(createButtonWithLabel(ui->pauseButton, tr("Pause"), showLabels));
ui->toolBar->addWidget(ui->keyboardButton); ui->toolBar->addWidget(createButtonWithLabel(ui->stopButton, tr("Stop"), showLabels));
ui->toolBar->addWidget(createButtonWithLabel(ui->restartButton, tr("Restart"), showLabels));
ui->toolBar->addWidget(createSpacer(this));
ui->toolBar->addWidget(createButtonWithLabel(ui->settingsButton, tr("Settings"), showLabels));
ui->toolBar->addWidget(
createButtonWithLabel(ui->fullscreenButton, tr("Full Screen"), showLabels));
ui->toolBar->addWidget(createSpacer(this));
ui->toolBar->addWidget(
createButtonWithLabel(ui->controllerButton, tr("Controllers"), showLabels));
ui->toolBar->addWidget(createButtonWithLabel(ui->keyboardButton, tr("Keyboard"), showLabels));
ui->toolBar->addWidget(createSpacer(this));
QFrame* line = new QFrame(this); QFrame* line = new QFrame(this);
line->setFrameShape(QFrame::StyledPanel); line->setFrameShape(QFrame::VLine);
line->setFrameShadow(QFrame::Sunken); line->setFrameShadow(QFrame::Sunken);
line->setMinimumWidth(2);
ui->toolBar->addWidget(line); ui->toolBar->addWidget(line);
ui->toolBar->addWidget(ui->sizeSliderContainer); ui->toolBar->addWidget(createSpacer(this));
ui->toolBar->addWidget(ui->mw_searchbar); if (showLabels) {
QLabel* pauseButtonLabel = ui->pauseButton->parentWidget()->findChild<QLabel*>();
if (pauseButtonLabel) {
pauseButtonLabel->setVisible(false);
}
}
ui->toolBar->addWidget(
createButtonWithLabel(ui->refreshButton, tr("Refresh List"), showLabels));
ui->toolBar->addWidget(createSpacer(this));
QBoxLayout* toolbarLayout = new QBoxLayout(QBoxLayout::TopToBottom);
toolbarLayout->setSpacing(2);
toolbarLayout->setContentsMargins(2, 2, 2, 2);
ui->sizeSliderContainer->setFixedWidth(150);
QWidget* searchSliderContainer = new QWidget(this);
QBoxLayout* searchSliderLayout = new QBoxLayout(QBoxLayout::TopToBottom);
searchSliderLayout->setContentsMargins(0, 0, 6, 6);
searchSliderLayout->setSpacing(2);
ui->mw_searchbar->setFixedWidth(150);
searchSliderLayout->addWidget(ui->sizeSliderContainer);
searchSliderLayout->addWidget(ui->mw_searchbar);
searchSliderContainer->setLayout(searchSliderLayout);
ui->toolBar->addWidget(searchSliderContainer);
if (!showLabels) {
toolbarLayout->addWidget(searchSliderContainer);
}
ui->playButton->setVisible(true);
ui->pauseButton->setVisible(false);
}
void MainWindow::UpdateToolbarButtons() {
// add toolbar widgets when game is running
bool showLabels = ui->toggleLabelsAct->isChecked();
ui->playButton->setVisible(false);
ui->pauseButton->setVisible(true);
if (showLabels) {
QLabel* playButtonLabel = ui->playButton->parentWidget()->findChild<QLabel*>();
if (playButtonLabel)
playButtonLabel->setVisible(false);
}
if (is_paused) {
ui->pauseButton->setIcon(ui->playButton->icon());
ui->pauseButton->setToolTip(tr("Resume"));
} else {
if (isIconBlack) {
ui->pauseButton->setIcon(QIcon(":images/pause_icon.png"));
} else {
ui->pauseButton->setIcon(RecolorIcon(QIcon(":images/pause_icon.png"), isWhite));
}
ui->pauseButton->setToolTip(tr("Pause"));
}
if (showLabels) {
QLabel* pauseButtonLabel = ui->pauseButton->parentWidget()->findChild<QLabel*>();
if (pauseButtonLabel) {
pauseButtonLabel->setText(is_paused ? tr("Resume") : tr("Pause"));
pauseButtonLabel->setVisible(true);
}
}
}
void MainWindow::UpdateToolbarLabels() {
AddUiWidgets();
} }
void MainWindow::CreateDockWindows() { void MainWindow::CreateDockWindows() {
@ -253,6 +390,8 @@ void MainWindow::CreateConnects() {
connect(ui->refreshButton, &QPushButton::clicked, this, &MainWindow::RefreshGameTable); connect(ui->refreshButton, &QPushButton::clicked, this, &MainWindow::RefreshGameTable);
connect(ui->showGameListAct, &QAction::triggered, this, &MainWindow::ShowGameList); connect(ui->showGameListAct, &QAction::triggered, this, &MainWindow::ShowGameList);
connect(this, &MainWindow::ExtractionFinished, this, &MainWindow::RefreshGameTable); connect(this, &MainWindow::ExtractionFinished, this, &MainWindow::RefreshGameTable);
connect(ui->toggleLabelsAct, &QAction::toggled, this, &MainWindow::toggleLabelsUnderIcons);
connect(ui->fullscreenButton, &QPushButton::clicked, this, &MainWindow::toggleFullscreen);
connect(ui->sizeSlider, &QSlider::valueChanged, this, [this](int value) { connect(ui->sizeSlider, &QSlider::valueChanged, this, [this](int value) {
if (isTableList) { if (isTableList) {
@ -276,6 +415,7 @@ void MainWindow::CreateConnects() {
}); });
connect(ui->playButton, &QPushButton::clicked, this, &MainWindow::StartGame); connect(ui->playButton, &QPushButton::clicked, this, &MainWindow::StartGame);
connect(ui->pauseButton, &QPushButton::clicked, this, &MainWindow::PauseGame);
connect(m_game_grid_frame.get(), &QTableWidget::cellDoubleClicked, this, connect(m_game_grid_frame.get(), &QTableWidget::cellDoubleClicked, this,
&MainWindow::StartGame); &MainWindow::StartGame);
connect(m_game_list_frame.get(), &QTableWidget::cellDoubleClicked, this, connect(m_game_list_frame.get(), &QTableWidget::cellDoubleClicked, this,
@ -576,7 +716,6 @@ void MainWindow::CreateConnects() {
}); });
// Package install. // Package install.
connect(ui->bootInstallPkgAct, &QAction::triggered, this, &MainWindow::InstallPkg);
connect(ui->bootGameAct, &QAction::triggered, this, &MainWindow::BootGame); connect(ui->bootGameAct, &QAction::triggered, this, &MainWindow::BootGame);
connect(ui->gameInstallPathAct, &QAction::triggered, this, &MainWindow::InstallDirectory); connect(ui->gameInstallPathAct, &QAction::triggered, this, &MainWindow::InstallDirectory);
@ -584,13 +723,58 @@ void MainWindow::CreateConnects() {
connect(ui->addElfFolderAct, &QAction::triggered, m_elf_viewer.data(), connect(ui->addElfFolderAct, &QAction::triggered, m_elf_viewer.data(),
&ElfViewer::OpenElfFolder); &ElfViewer::OpenElfFolder);
// Package Viewer. // Trophy Viewer
connect(ui->pkgViewerAct, &QAction::triggered, this, [this]() { connect(ui->trophyViewerAct, &QAction::triggered, this, [this]() {
PKGViewer* pkgViewer = new PKGViewer( if (m_game_info->m_games.empty()) {
m_game_info, this, [this](std::filesystem::path file, int pkgNum, int nPkg) { QMessageBox::information(
this->InstallDragDropPkg(file, pkgNum, nPkg); this, tr("Trophy Viewer"),
}); tr("No games found. Please add your games to your library first."));
pkgViewer->show(); return;
}
const auto& firstGame = m_game_info->m_games[0];
QString trophyPath, gameTrpPath;
Common::FS::PathToQString(trophyPath, firstGame.serial);
Common::FS::PathToQString(gameTrpPath, firstGame.path);
auto game_update_path = Common::FS::PathFromQString(gameTrpPath);
game_update_path += "-UPDATE";
if (std::filesystem::exists(game_update_path)) {
Common::FS::PathToQString(gameTrpPath, game_update_path);
} else {
game_update_path = Common::FS::PathFromQString(gameTrpPath);
game_update_path += "-patch";
if (std::filesystem::exists(game_update_path)) {
Common::FS::PathToQString(gameTrpPath, game_update_path);
}
}
QVector<TrophyGameInfo> allTrophyGames;
for (const auto& game : m_game_info->m_games) {
TrophyGameInfo gameInfo;
gameInfo.name = QString::fromStdString(game.name);
Common::FS::PathToQString(gameInfo.trophyPath, game.serial);
Common::FS::PathToQString(gameInfo.gameTrpPath, game.path);
auto update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath);
update_path += "-UPDATE";
if (std::filesystem::exists(update_path)) {
Common::FS::PathToQString(gameInfo.gameTrpPath, update_path);
} else {
update_path = Common::FS::PathFromQString(gameInfo.gameTrpPath);
update_path += "-patch";
if (std::filesystem::exists(update_path)) {
Common::FS::PathToQString(gameInfo.gameTrpPath, update_path);
}
}
allTrophyGames.append(gameInfo);
}
QString gameName = QString::fromStdString(firstGame.name);
TrophyViewer* trophyViewer =
new TrophyViewer(trophyPath, gameTrpPath, gameName, allTrophyGames);
trophyViewer->show();
}); });
// Themes // Themes
@ -689,6 +873,8 @@ void MainWindow::StartGame() {
return; return;
} }
StartEmulator(path); StartEmulator(path);
UpdateToolbarButtons();
} }
} }
@ -767,22 +953,6 @@ void MainWindow::SaveWindowState() const {
this->geometry().width(), this->geometry().height()); this->geometry().width(), this->geometry().height());
} }
void MainWindow::InstallPkg() {
QFileDialog dialog;
dialog.setFileMode(QFileDialog::ExistingFiles);
dialog.setNameFilter(tr("PKG File (*.PKG *.pkg)"));
if (dialog.exec()) {
QStringList fileNames = dialog.selectedFiles();
int nPkg = fileNames.size();
int pkgNum = 0;
for (const QString& file : fileNames) {
++pkgNum;
std::filesystem::path path = Common::FS::PathFromQString(file);
MainWindow::InstallDragDropPkg(path, pkgNum, nPkg);
}
}
}
void MainWindow::BootGame() { void MainWindow::BootGame() {
QFileDialog dialog; QFileDialog dialog;
dialog.setFileMode(QFileDialog::ExistingFile); dialog.setFileMode(QFileDialog::ExistingFile);
@ -806,260 +976,6 @@ void MainWindow::BootGame() {
} }
} }
void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int nPkg) {
if (Loader::DetectFileType(file) == Loader::FileTypes::Pkg) {
std::string failreason;
pkg = PKG();
if (!pkg.Open(file, failreason)) {
QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason));
return;
}
if (!psf.Open(pkg.sfo)) {
QMessageBox::critical(this, tr("PKG ERROR"),
"Could not read SFO. Check log for details");
return;
}
auto category = psf.GetString("CATEGORY");
if (!use_for_all_queued || pkgNum == 1) {
InstallDirSelect ids;
const auto selected = ids.exec();
if (selected == QDialog::Rejected) {
return;
}
last_install_dir = ids.getSelectedDirectory();
delete_file_on_install = ids.deleteFileOnInstall();
use_for_all_queued = ids.useForAllQueued();
}
std::filesystem::path game_install_dir = last_install_dir;
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
bool use_game_update = pkgType.contains("PATCH") && Config::getSeparateUpdateEnabled();
// Default paths
auto game_folder_path = game_install_dir / pkg.GetTitleID();
auto game_update_path = use_game_update ? game_folder_path.parent_path() /
(std::string{pkg.GetTitleID()} + "-UPDATE")
: game_folder_path;
const int max_depth = 5;
if (pkgType.contains("PATCH")) {
// For patches, try to find the game recursively
auto found_game = Common::FS::FindGameByID(game_install_dir,
std::string{pkg.GetTitleID()}, max_depth);
if (found_game.has_value()) {
game_folder_path = found_game.value().parent_path();
game_update_path = use_game_update ? game_folder_path.parent_path() /
(std::string{pkg.GetTitleID()} + "-UPDATE")
: game_folder_path;
}
} else {
// For base games, we check if the game is already installed
auto found_game = Common::FS::FindGameByID(game_install_dir,
std::string{pkg.GetTitleID()}, max_depth);
if (found_game.has_value()) {
game_folder_path = found_game.value().parent_path();
}
// If the game is not found, we install it in the game install directory
else {
game_folder_path = game_install_dir / pkg.GetTitleID();
}
game_update_path = use_game_update ? game_folder_path.parent_path() /
(std::string{pkg.GetTitleID()} + "-UPDATE")
: game_folder_path;
}
QString gameDirPath;
Common::FS::PathToQString(gameDirPath, game_folder_path);
QDir game_dir(gameDirPath);
if (game_dir.exists()) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("PKG Extraction"));
std::string content_id;
if (auto value = psf.GetString("CONTENT_ID"); value.has_value()) {
content_id = std::string{*value};
} else {
QMessageBox::critical(this, tr("PKG ERROR"), "PSF file there is no CONTENT_ID");
return;
}
std::string entitlement_label = Common::SplitString(content_id, '-')[2];
auto addon_extract_path =
Config::getAddonInstallDir() / pkg.GetTitleID() / entitlement_label;
QString addonDirPath;
Common::FS::PathToQString(addonDirPath, addon_extract_path);
QDir addon_dir(addonDirPath);
if (pkgType.contains("PATCH")) {
QString pkg_app_version;
if (auto app_ver = psf.GetString("APP_VER"); app_ver.has_value()) {
pkg_app_version = QString::fromStdString(std::string{*app_ver});
} else {
QMessageBox::critical(this, tr("PKG ERROR"), "PSF file there is no APP_VER");
return;
}
std::filesystem::path sce_folder_path =
std::filesystem::exists(game_update_path / "sce_sys" / "param.sfo")
? game_update_path / "sce_sys" / "param.sfo"
: game_folder_path / "sce_sys" / "param.sfo";
psf.Open(sce_folder_path);
QString game_app_version;
if (auto app_ver = psf.GetString("APP_VER"); app_ver.has_value()) {
game_app_version = QString::fromStdString(std::string{*app_ver});
} else {
QMessageBox::critical(this, tr("PKG ERROR"), "PSF file there is no APP_VER");
return;
}
double appD = game_app_version.toDouble();
double pkgD = pkg_app_version.toDouble();
if (pkgD == appD) {
msgBox.setText(QString(tr("Patch detected!") + "\n" +
tr("PKG and Game versions match: ") + pkg_app_version +
"\n" + tr("Would you like to overwrite?")));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
} else if (pkgD < appD) {
msgBox.setText(QString(tr("Patch detected!") + "\n" +
tr("PKG Version %1 is older than installed version: ")
.arg(pkg_app_version) +
game_app_version + "\n" +
tr("Would you like to overwrite?")));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
} else {
msgBox.setText(QString(tr("Patch detected!") + "\n" +
tr("Game is installed: ") + game_app_version + "\n" +
tr("Would you like to install Patch: ") +
pkg_app_version + " ?"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
}
int result = msgBox.exec();
if (result == QMessageBox::Yes) {
// Do nothing.
} else {
return;
}
} else if (category == "ac") {
if (!addon_dir.exists()) {
QMessageBox addonMsgBox;
addonMsgBox.setWindowTitle(tr("DLC Installation"));
addonMsgBox.setText(QString(tr("Would you like to install DLC: %1?"))
.arg(QString::fromStdString(entitlement_label)));
addonMsgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
addonMsgBox.setDefaultButton(QMessageBox::No);
int result = addonMsgBox.exec();
if (result == QMessageBox::Yes) {
game_update_path = addon_extract_path;
} else {
return;
}
} else {
msgBox.setText(QString(tr("DLC already installed:") + "\n" + addonDirPath +
"\n\n" + tr("Would you like to overwrite?")));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
int result = msgBox.exec();
if (result == QMessageBox::Yes) {
game_update_path = addon_extract_path;
} else {
return;
}
}
} else {
msgBox.setText(QString(tr("Game already installed") + "\n" + gameDirPath + "\n" +
tr("Would you like to overwrite?")));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::No);
int result = msgBox.exec();
if (result == QMessageBox::Yes) {
// Do nothing.
} else {
return;
}
}
} else {
// Do nothing;
if (pkgType.contains("PATCH") || category == "ac") {
QMessageBox::information(
this, tr("PKG Extraction"),
tr("PKG is a patch or DLC, please install the game first!"));
return;
}
// what else?
}
if (!pkg.Extract(file, game_update_path, failreason)) {
QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason));
} else {
int nfiles = pkg.GetNumberOfFiles();
if (nfiles > 0) {
QVector<int> indices;
for (int i = 0; i < nfiles; i++) {
indices.append(i);
}
QProgressDialog dialog;
dialog.setWindowTitle(tr("PKG Extraction"));
dialog.setWindowModality(Qt::WindowModal);
QString extractmsg = QString(tr("Extracting PKG %1/%2")).arg(pkgNum).arg(nPkg);
dialog.setLabelText(extractmsg);
dialog.setAutoClose(true);
dialog.setRange(0, nfiles);
dialog.setGeometry(QStyle::alignedRect(Qt::LeftToRight, Qt::AlignCenter,
dialog.size(), this->geometry()));
QFutureWatcher<void> futureWatcher;
connect(&futureWatcher, &QFutureWatcher<void>::finished, this, [=, this]() {
if (pkgNum == nPkg) {
QString path;
// We want to show the parent path instead of the full path
Common::FS::PathToQString(path, game_folder_path.parent_path());
QIcon windowIcon(
Common::FS::PathToUTF8String(game_folder_path / "sce_sys/icon0.png")
.c_str());
QMessageBox extractMsgBox(this);
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
if (!windowIcon.isNull()) {
extractMsgBox.setWindowIcon(windowIcon);
}
extractMsgBox.setText(
QString(tr("Game successfully installed at %1")).arg(path));
extractMsgBox.addButton(QMessageBox::Ok);
extractMsgBox.setDefaultButton(QMessageBox::Ok);
connect(&extractMsgBox, &QMessageBox::buttonClicked, this,
[&](QAbstractButton* button) {
if (extractMsgBox.button(QMessageBox::Ok) == button) {
extractMsgBox.close();
emit ExtractionFinished();
}
});
extractMsgBox.exec();
}
if (delete_file_on_install) {
std::filesystem::remove(file);
}
});
connect(&dialog, &QProgressDialog::canceled, [&]() { futureWatcher.cancel(); });
connect(&futureWatcher, &QFutureWatcher<void>::progressValueChanged, &dialog,
&QProgressDialog::setValue);
futureWatcher.setFuture(
QtConcurrent::map(indices, [&](int index) { pkg.ExtractFiles(index); }));
dialog.exec();
}
}
} else {
QMessageBox::critical(this, tr("PKG ERROR"),
tr("File doesn't appear to be a valid PKG file"));
}
}
void MainWindow::InstallDirectory() { void MainWindow::InstallDirectory() {
GameInstallDialog dlg; GameInstallDialog dlg;
dlg.exec(); dlg.exec();
@ -1142,7 +1058,6 @@ QIcon MainWindow::RecolorIcon(const QIcon& icon, bool isWhite) {
} }
void MainWindow::SetUiIcons(bool isWhite) { void MainWindow::SetUiIcons(bool isWhite) {
ui->bootInstallPkgAct->setIcon(RecolorIcon(ui->bootInstallPkgAct->icon(), isWhite));
ui->bootGameAct->setIcon(RecolorIcon(ui->bootGameAct->icon(), isWhite)); ui->bootGameAct->setIcon(RecolorIcon(ui->bootGameAct->icon(), isWhite));
ui->shadFolderAct->setIcon(RecolorIcon(ui->shadFolderAct->icon(), isWhite)); ui->shadFolderAct->setIcon(RecolorIcon(ui->shadFolderAct->icon(), isWhite));
ui->exitAct->setIcon(RecolorIcon(ui->exitAct->icon(), isWhite)); ui->exitAct->setIcon(RecolorIcon(ui->exitAct->icon(), isWhite));
@ -1163,12 +1078,14 @@ void MainWindow::SetUiIcons(bool isWhite) {
ui->pauseButton->setIcon(RecolorIcon(ui->pauseButton->icon(), isWhite)); ui->pauseButton->setIcon(RecolorIcon(ui->pauseButton->icon(), isWhite));
ui->stopButton->setIcon(RecolorIcon(ui->stopButton->icon(), isWhite)); ui->stopButton->setIcon(RecolorIcon(ui->stopButton->icon(), isWhite));
ui->refreshButton->setIcon(RecolorIcon(ui->refreshButton->icon(), isWhite)); ui->refreshButton->setIcon(RecolorIcon(ui->refreshButton->icon(), isWhite));
ui->restartButton->setIcon(RecolorIcon(ui->restartButton->icon(), isWhite));
ui->settingsButton->setIcon(RecolorIcon(ui->settingsButton->icon(), isWhite)); ui->settingsButton->setIcon(RecolorIcon(ui->settingsButton->icon(), isWhite));
ui->fullscreenButton->setIcon(RecolorIcon(ui->fullscreenButton->icon(), isWhite));
ui->controllerButton->setIcon(RecolorIcon(ui->controllerButton->icon(), isWhite)); ui->controllerButton->setIcon(RecolorIcon(ui->controllerButton->icon(), isWhite));
ui->keyboardButton->setIcon(RecolorIcon(ui->keyboardButton->icon(), isWhite)); ui->keyboardButton->setIcon(RecolorIcon(ui->keyboardButton->icon(), isWhite));
ui->refreshGameListAct->setIcon(RecolorIcon(ui->refreshGameListAct->icon(), isWhite)); ui->refreshGameListAct->setIcon(RecolorIcon(ui->refreshGameListAct->icon(), isWhite));
ui->menuGame_List_Mode->setIcon(RecolorIcon(ui->menuGame_List_Mode->icon(), isWhite)); ui->menuGame_List_Mode->setIcon(RecolorIcon(ui->menuGame_List_Mode->icon(), isWhite));
ui->pkgViewerAct->setIcon(RecolorIcon(ui->pkgViewerAct->icon(), isWhite)); ui->trophyViewerAct->setIcon(RecolorIcon(ui->trophyViewerAct->icon(), isWhite));
ui->configureAct->setIcon(RecolorIcon(ui->configureAct->icon(), isWhite)); ui->configureAct->setIcon(RecolorIcon(ui->configureAct->icon(), isWhite));
ui->addElfFolderAct->setIcon(RecolorIcon(ui->addElfFolderAct->icon(), isWhite)); ui->addElfFolderAct->setIcon(RecolorIcon(ui->addElfFolderAct->icon(), isWhite));
} }

View file

@ -5,6 +5,7 @@
#include <QActionGroup> #include <QActionGroup>
#include <QDragEnterEvent> #include <QDragEnterEvent>
#include <QProcess>
#include <QTranslator> #include <QTranslator>
#include "background_music_player.h" #include "background_music_player.h"
@ -21,7 +22,6 @@
#include "game_list_utils.h" #include "game_list_utils.h"
#include "main_window_themes.h" #include "main_window_themes.h"
#include "main_window_ui.h" #include "main_window_ui.h"
#include "pkg_viewer.h"
class GameListFrame; class GameListFrame;
@ -35,9 +35,10 @@ public:
explicit MainWindow(QWidget* parent = nullptr); explicit MainWindow(QWidget* parent = nullptr);
~MainWindow(); ~MainWindow();
bool Init(); bool Init();
void InstallDragDropPkg(std::filesystem::path file, int pkgNum, int nPkg);
void InstallDirectory(); void InstallDirectory();
void StartGame(); void StartGame();
void PauseGame();
bool showLabels;
private Q_SLOTS: private Q_SLOTS:
void ConfigureGuiFromSettings(); void ConfigureGuiFromSettings();
@ -47,15 +48,21 @@ private Q_SLOTS:
void RefreshGameTable(); void RefreshGameTable();
void HandleResize(QResizeEvent* event); void HandleResize(QResizeEvent* event);
void OnLanguageChanged(const std::string& locale); void OnLanguageChanged(const std::string& locale);
void toggleLabelsUnderIcons();
private: private:
Ui_MainWindow* ui; Ui_MainWindow* ui;
void AddUiWidgets(); void AddUiWidgets();
void UpdateToolbarLabels();
void UpdateToolbarButtons();
QWidget* createButtonWithLabel(QPushButton* button, const QString& labelText, bool showLabel);
void CreateActions(); void CreateActions();
void toggleFullscreen();
void CreateRecentGameActions(); void CreateRecentGameActions();
void CreateDockWindows(); void CreateDockWindows();
void GetPhysicalDevices(); void GetPhysicalDevices();
void LoadGameLists(); void LoadGameLists();
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
void CheckUpdateMain(bool checkSave); void CheckUpdateMain(bool checkSave);
#endif #endif
@ -63,7 +70,6 @@ private:
void SetLastUsedTheme(); void SetLastUsedTheme();
void SetLastIconSizeBullet(); void SetLastIconSizeBullet();
void SetUiIcons(bool isWhite); void SetUiIcons(bool isWhite);
void InstallPkg();
void BootGame(); void BootGame();
void AddRecentFiles(QString filePath); void AddRecentFiles(QString filePath);
void LoadTranslation(); void LoadTranslation();
@ -73,11 +79,13 @@ private:
bool isIconBlack = false; bool isIconBlack = false;
bool isTableList = true; bool isTableList = true;
bool isGameRunning = false; bool isGameRunning = false;
bool isWhite = false;
bool is_paused = false;
QActionGroup* m_icon_size_act_group = nullptr; QActionGroup* m_icon_size_act_group = nullptr;
QActionGroup* m_list_mode_act_group = nullptr; QActionGroup* m_list_mode_act_group = nullptr;
QActionGroup* m_theme_act_group = nullptr; QActionGroup* m_theme_act_group = nullptr;
QActionGroup* m_recent_files_group = nullptr; QActionGroup* m_recent_files_group = nullptr;
PKG pkg;
// Dockable widget frames // Dockable widget frames
WindowThemes m_window_themes; WindowThemes m_window_themes;
GameListUtils m_game_list_utils; GameListUtils m_game_list_utils;
@ -108,20 +116,6 @@ protected:
} }
} }
void dropEvent(QDropEvent* event1) override {
const QMimeData* mimeData = event1->mimeData();
if (mimeData->hasUrls()) {
QList<QUrl> urlList = mimeData->urls();
int pkgNum = 0;
int nPkg = urlList.size();
for (const QUrl& url : urlList) {
pkgNum++;
std::filesystem::path path = Common::FS::PathFromQString(url.toLocalFile());
InstallDragDropPkg(path, pkgNum, nPkg);
}
}
}
void resizeEvent(QResizeEvent* event) override; void resizeEvent(QResizeEvent* event) override;
std::filesystem::path last_install_dir = ""; std::filesystem::path last_install_dir = "";

View file

@ -19,7 +19,7 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
themePalette.setColor(QPalette::WindowText, Qt::white); themePalette.setColor(QPalette::WindowText, Qt::white);
themePalette.setColor(QPalette::Base, QColor(20, 20, 20)); themePalette.setColor(QPalette::Base, QColor(20, 20, 20));
themePalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53)); themePalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
themePalette.setColor(QPalette::ToolTipBase, Qt::white); themePalette.setColor(QPalette::ToolTipBase, QColor(20, 20, 20));
themePalette.setColor(QPalette::ToolTipText, Qt::white); themePalette.setColor(QPalette::ToolTipText, Qt::white);
themePalette.setColor(QPalette::Text, Qt::white); themePalette.setColor(QPalette::Text, Qt::white);
themePalette.setColor(QPalette::Button, QColor(53, 53, 53)); themePalette.setColor(QPalette::Button, QColor(53, 53, 53));
@ -37,18 +37,18 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
"border-radius: 4px; padding: 5px; }" "border-radius: 4px; padding: 5px; }"
"QLineEdit:focus {" "QLineEdit:focus {"
"border: 1px solid #2A82DA; }"); "border: 1px solid #2A82DA; }");
themePalette.setColor(QPalette::Window, QColor(240, 240, 240)); // Light gray themePalette.setColor(QPalette::Window, QColor(240, 240, 240)); // Light gray
themePalette.setColor(QPalette::WindowText, Qt::black); // Black themePalette.setColor(QPalette::WindowText, Qt::black); // Black
themePalette.setColor(QPalette::Base, QColor(230, 230, 230, 80)); // Grayish themePalette.setColor(QPalette::Base, QColor(230, 230, 230, 80)); // Grayish
themePalette.setColor(QPalette::ToolTipBase, Qt::black); // Black themePalette.setColor(QPalette::ToolTipBase, QColor(230, 230, 230, 80)); // Grayish
themePalette.setColor(QPalette::ToolTipText, Qt::black); // Black themePalette.setColor(QPalette::ToolTipText, Qt::black); // Black
themePalette.setColor(QPalette::Text, Qt::black); // Black themePalette.setColor(QPalette::Text, Qt::black); // Black
themePalette.setColor(QPalette::Button, QColor(240, 240, 240)); // Light gray themePalette.setColor(QPalette::Button, QColor(240, 240, 240)); // Light gray
themePalette.setColor(QPalette::ButtonText, Qt::black); // Black themePalette.setColor(QPalette::ButtonText, Qt::black); // Black
themePalette.setColor(QPalette::BrightText, Qt::red); // Red themePalette.setColor(QPalette::BrightText, Qt::red); // Red
themePalette.setColor(QPalette::Link, QColor(42, 130, 218)); // Blue themePalette.setColor(QPalette::Link, QColor(42, 130, 218)); // Blue
themePalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); // Blue themePalette.setColor(QPalette::Highlight, QColor(42, 130, 218)); // Blue
themePalette.setColor(QPalette::HighlightedText, Qt::white); // White themePalette.setColor(QPalette::HighlightedText, Qt::white); // White
qApp->setPalette(themePalette); qApp->setPalette(themePalette);
break; break;
case Theme::Green: case Theme::Green:
@ -62,8 +62,9 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
themePalette.setColor(QPalette::WindowText, Qt::white); // White text themePalette.setColor(QPalette::WindowText, Qt::white); // White text
themePalette.setColor(QPalette::Base, QColor(25, 40, 25)); // Darker green base themePalette.setColor(QPalette::Base, QColor(25, 40, 25)); // Darker green base
themePalette.setColor(QPalette::AlternateBase, themePalette.setColor(QPalette::AlternateBase,
QColor(53, 69, 53)); // Dark green alternate base QColor(53, 69, 53)); // Dark green alternate base
themePalette.setColor(QPalette::ToolTipBase, Qt::white); // White tooltip background themePalette.setColor(QPalette::ToolTipBase,
QColor(25, 40, 25)); // White tooltip background
themePalette.setColor(QPalette::ToolTipText, Qt::white); // White tooltip text themePalette.setColor(QPalette::ToolTipText, Qt::white); // White tooltip text
themePalette.setColor(QPalette::Text, Qt::white); // White text themePalette.setColor(QPalette::Text, Qt::white); // White text
themePalette.setColor(QPalette::Button, QColor(53, 69, 53)); // Dark green button themePalette.setColor(QPalette::Button, QColor(53, 69, 53)); // Dark green button
@ -85,8 +86,9 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
themePalette.setColor(QPalette::WindowText, Qt::white); // White text themePalette.setColor(QPalette::WindowText, Qt::white); // White text
themePalette.setColor(QPalette::Base, QColor(20, 40, 60)); // Darker blue base themePalette.setColor(QPalette::Base, QColor(20, 40, 60)); // Darker blue base
themePalette.setColor(QPalette::AlternateBase, themePalette.setColor(QPalette::AlternateBase,
QColor(40, 60, 90)); // Dark blue alternate base QColor(40, 60, 90)); // Dark blue alternate base
themePalette.setColor(QPalette::ToolTipBase, Qt::white); // White tooltip background themePalette.setColor(QPalette::ToolTipBase,
QColor(20, 40, 60)); // White tooltip background
themePalette.setColor(QPalette::ToolTipText, Qt::white); // White tooltip text themePalette.setColor(QPalette::ToolTipText, Qt::white); // White tooltip text
themePalette.setColor(QPalette::Text, Qt::white); // White text themePalette.setColor(QPalette::Text, Qt::white); // White text
themePalette.setColor(QPalette::Button, QColor(40, 60, 90)); // Dark blue button themePalette.setColor(QPalette::Button, QColor(40, 60, 90)); // Dark blue button
@ -109,8 +111,9 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
themePalette.setColor(QPalette::WindowText, Qt::white); // White text themePalette.setColor(QPalette::WindowText, Qt::white); // White text
themePalette.setColor(QPalette::Base, QColor(80, 30, 90)); // Darker violet base themePalette.setColor(QPalette::Base, QColor(80, 30, 90)); // Darker violet base
themePalette.setColor(QPalette::AlternateBase, themePalette.setColor(QPalette::AlternateBase,
QColor(100, 50, 120)); // Violet alternate base QColor(100, 50, 120)); // Violet alternate base
themePalette.setColor(QPalette::ToolTipBase, Qt::white); // White tooltip background themePalette.setColor(QPalette::ToolTipBase,
QColor(80, 30, 90)); // White tooltip background
themePalette.setColor(QPalette::ToolTipText, Qt::white); // White tooltip text themePalette.setColor(QPalette::ToolTipText, Qt::white); // White tooltip text
themePalette.setColor(QPalette::Text, Qt::white); // White text themePalette.setColor(QPalette::Text, Qt::white); // White text
themePalette.setColor(QPalette::Button, QColor(100, 50, 120)); // Violet button themePalette.setColor(QPalette::Button, QColor(100, 50, 120)); // Violet button
@ -133,7 +136,7 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
themePalette.setColor(QPalette::WindowText, QColor(249, 245, 215)); themePalette.setColor(QPalette::WindowText, QColor(249, 245, 215));
themePalette.setColor(QPalette::Base, QColor(29, 32, 33)); themePalette.setColor(QPalette::Base, QColor(29, 32, 33));
themePalette.setColor(QPalette::AlternateBase, QColor(50, 48, 47)); themePalette.setColor(QPalette::AlternateBase, QColor(50, 48, 47));
themePalette.setColor(QPalette::ToolTipBase, QColor(249, 245, 215)); themePalette.setColor(QPalette::ToolTipBase, QColor(29, 32, 33));
themePalette.setColor(QPalette::ToolTipText, QColor(249, 245, 215)); themePalette.setColor(QPalette::ToolTipText, QColor(249, 245, 215));
themePalette.setColor(QPalette::Text, QColor(249, 245, 215)); themePalette.setColor(QPalette::Text, QColor(249, 245, 215));
themePalette.setColor(QPalette::Button, QColor(40, 40, 40)); themePalette.setColor(QPalette::Button, QColor(40, 40, 40));
@ -155,7 +158,7 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
themePalette.setColor(QPalette::WindowText, QColor(192, 202, 245)); themePalette.setColor(QPalette::WindowText, QColor(192, 202, 245));
themePalette.setColor(QPalette::Base, QColor(25, 28, 39)); themePalette.setColor(QPalette::Base, QColor(25, 28, 39));
themePalette.setColor(QPalette::AlternateBase, QColor(36, 40, 59)); themePalette.setColor(QPalette::AlternateBase, QColor(36, 40, 59));
themePalette.setColor(QPalette::ToolTipBase, QColor(192, 202, 245)); themePalette.setColor(QPalette::ToolTipBase, QColor(25, 28, 39));
themePalette.setColor(QPalette::ToolTipText, QColor(192, 202, 245)); themePalette.setColor(QPalette::ToolTipText, QColor(192, 202, 245));
themePalette.setColor(QPalette::Text, QColor(192, 202, 245)); themePalette.setColor(QPalette::Text, QColor(192, 202, 245));
themePalette.setColor(QPalette::Button, QColor(30, 30, 41)); themePalette.setColor(QPalette::Button, QColor(30, 30, 41));

View file

@ -9,7 +9,6 @@
class Ui_MainWindow { class Ui_MainWindow {
public: public:
QAction* bootInstallPkgAct;
QAction* bootGameAct; QAction* bootGameAct;
QAction* addElfFolderAct; QAction* addElfFolderAct;
QAction* shadFolderAct; QAction* shadFolderAct;
@ -20,13 +19,14 @@ public:
QAction* setIconSizeSmallAct; QAction* setIconSizeSmallAct;
QAction* setIconSizeMediumAct; QAction* setIconSizeMediumAct;
QAction* setIconSizeLargeAct; QAction* setIconSizeLargeAct;
QAction* toggleLabelsAct;
QAction* setlistModeListAct; QAction* setlistModeListAct;
QAction* setlistModeGridAct; QAction* setlistModeGridAct;
QAction* setlistElfAct; QAction* setlistElfAct;
QAction* gameInstallPathAct; QAction* gameInstallPathAct;
QAction* downloadCheatsPatchesAct; QAction* downloadCheatsPatchesAct;
QAction* dumpGameListAct; QAction* dumpGameListAct;
QAction* pkgViewerAct; QAction* trophyViewerAct;
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
QAction* updaterAct; QAction* updaterAct;
#endif #endif
@ -49,6 +49,8 @@ public:
QPushButton* settingsButton; QPushButton* settingsButton;
QPushButton* controllerButton; QPushButton* controllerButton;
QPushButton* keyboardButton; QPushButton* keyboardButton;
QPushButton* fullscreenButton;
QPushButton* restartButton;
QWidget* sizeSliderContainer; QWidget* sizeSliderContainer;
QHBoxLayout* sizeSliderContainer_layout; QHBoxLayout* sizeSliderContainer_layout;
@ -83,9 +85,6 @@ public:
MainWindow->setDockNestingEnabled(true); MainWindow->setDockNestingEnabled(true);
MainWindow->setDockOptions(QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks | MainWindow->setDockOptions(QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks |
QMainWindow::AnimatedDocks | QMainWindow::GroupedDragging); QMainWindow::AnimatedDocks | QMainWindow::GroupedDragging);
bootInstallPkgAct = new QAction(MainWindow);
bootInstallPkgAct->setObjectName("bootInstallPkgAct");
bootInstallPkgAct->setIcon(QIcon(":images/file_icon.png"));
bootGameAct = new QAction(MainWindow); bootGameAct = new QAction(MainWindow);
bootGameAct->setObjectName("bootGameAct"); bootGameAct->setObjectName("bootGameAct");
bootGameAct->setIcon(QIcon(":images/play_icon.png")); bootGameAct->setIcon(QIcon(":images/play_icon.png"));
@ -103,7 +102,15 @@ public:
showGameListAct->setCheckable(true); showGameListAct->setCheckable(true);
refreshGameListAct = new QAction(MainWindow); refreshGameListAct = new QAction(MainWindow);
refreshGameListAct->setObjectName("refreshGameListAct"); refreshGameListAct->setObjectName("refreshGameListAct");
refreshGameListAct->setIcon(QIcon(":images/refresh_icon.png")); refreshGameListAct->setIcon(QIcon(":images/refreshlist_icon.png"));
toggleLabelsAct = new QAction(MainWindow);
toggleLabelsAct->setObjectName("toggleLabelsAct");
toggleLabelsAct->setText(
QCoreApplication::translate("MainWindow", "Show Labels Under Icons"));
toggleLabelsAct->setCheckable(true);
toggleLabelsAct->setChecked(Config::getShowLabelsUnderIcons());
setIconSizeTinyAct = new QAction(MainWindow); setIconSizeTinyAct = new QAction(MainWindow);
setIconSizeTinyAct->setObjectName("setIconSizeTinyAct"); setIconSizeTinyAct->setObjectName("setIconSizeTinyAct");
setIconSizeTinyAct->setCheckable(true); setIconSizeTinyAct->setCheckable(true);
@ -136,9 +143,10 @@ public:
dumpGameListAct = new QAction(MainWindow); dumpGameListAct = new QAction(MainWindow);
dumpGameListAct->setObjectName("dumpGameList"); dumpGameListAct->setObjectName("dumpGameList");
dumpGameListAct->setIcon(QIcon(":images/dump_icon.png")); dumpGameListAct->setIcon(QIcon(":images/dump_icon.png"));
pkgViewerAct = new QAction(MainWindow); trophyViewerAct = new QAction(MainWindow);
pkgViewerAct->setObjectName("pkgViewer"); trophyViewerAct->setObjectName("trophyViewer");
pkgViewerAct->setIcon(QIcon(":images/file_icon.png")); trophyViewerAct->setIcon(QIcon(":images/trophy_icon.png"));
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
updaterAct = new QAction(MainWindow); updaterAct = new QAction(MainWindow);
updaterAct->setObjectName("updaterAct"); updaterAct->setObjectName("updaterAct");
@ -205,20 +213,28 @@ public:
stopButton->setIconSize(QSize(40, 40)); stopButton->setIconSize(QSize(40, 40));
refreshButton = new QPushButton(centralWidget); refreshButton = new QPushButton(centralWidget);
refreshButton->setFlat(true); refreshButton->setFlat(true);
refreshButton->setIcon(QIcon(":images/refresh_icon.png")); refreshButton->setIcon(QIcon(":images/refreshlist_icon.png"));
refreshButton->setIconSize(QSize(32, 32)); refreshButton->setIconSize(QSize(40, 40));
fullscreenButton = new QPushButton(centralWidget);
fullscreenButton->setFlat(true);
fullscreenButton->setIcon(QIcon(":images/fullscreen_icon.png"));
fullscreenButton->setIconSize(QSize(38, 38));
settingsButton = new QPushButton(centralWidget); settingsButton = new QPushButton(centralWidget);
settingsButton->setFlat(true); settingsButton->setFlat(true);
settingsButton->setIcon(QIcon(":images/settings_icon.png")); settingsButton->setIcon(QIcon(":images/settings_icon.png"));
settingsButton->setIconSize(QSize(44, 44)); settingsButton->setIconSize(QSize(40, 40));
controllerButton = new QPushButton(centralWidget); controllerButton = new QPushButton(centralWidget);
controllerButton->setFlat(true); controllerButton->setFlat(true);
controllerButton->setIcon(QIcon(":images/controller_icon.png")); controllerButton->setIcon(QIcon(":images/controller_icon.png"));
controllerButton->setIconSize(QSize(40, 40)); controllerButton->setIconSize(QSize(55, 48));
keyboardButton = new QPushButton(centralWidget); keyboardButton = new QPushButton(centralWidget);
keyboardButton->setFlat(true); keyboardButton->setFlat(true);
keyboardButton->setIcon(QIcon(":images/keyboard_icon.png")); keyboardButton->setIcon(QIcon(":images/keyboard_icon.png"));
keyboardButton->setIconSize(QSize(48, 44)); keyboardButton->setIconSize(QSize(50, 50));
restartButton = new QPushButton(centralWidget);
restartButton->setFlat(true);
restartButton->setIcon(QIcon(":images/restart_game_icon.png"));
restartButton->setIconSize(QSize(40, 40));
sizeSliderContainer = new QWidget(centralWidget); sizeSliderContainer = new QWidget(centralWidget);
sizeSliderContainer->setObjectName("sizeSliderContainer"); sizeSliderContainer->setObjectName("sizeSliderContainer");
@ -285,7 +301,6 @@ public:
menuBar->addAction(menuView->menuAction()); menuBar->addAction(menuView->menuAction());
menuBar->addAction(menuSettings->menuAction()); menuBar->addAction(menuSettings->menuAction());
menuBar->addAction(menuHelp->menuAction()); menuBar->addAction(menuHelp->menuAction());
menuFile->addAction(bootInstallPkgAct);
menuFile->addAction(bootGameAct); menuFile->addAction(bootGameAct);
menuFile->addSeparator(); menuFile->addSeparator();
menuFile->addAction(addElfFolderAct); menuFile->addAction(addElfFolderAct);
@ -299,6 +314,7 @@ public:
menuView->addAction(refreshGameListAct); menuView->addAction(refreshGameListAct);
menuView->addAction(menuGame_List_Mode->menuAction()); menuView->addAction(menuGame_List_Mode->menuAction());
menuView->addAction(menuGame_List_Icons->menuAction()); menuView->addAction(menuGame_List_Icons->menuAction());
menuView->addAction(toggleLabelsAct);
menuView->addAction(menuThemes->menuAction()); menuView->addAction(menuThemes->menuAction());
menuThemes->addAction(setThemeDark); menuThemes->addAction(setThemeDark);
menuThemes->addAction(setThemeLight); menuThemes->addAction(setThemeLight);
@ -320,7 +336,7 @@ public:
menuSettings->addAction(menuUtils->menuAction()); menuSettings->addAction(menuUtils->menuAction());
menuUtils->addAction(downloadCheatsPatchesAct); menuUtils->addAction(downloadCheatsPatchesAct);
menuUtils->addAction(dumpGameListAct); menuUtils->addAction(dumpGameListAct);
menuUtils->addAction(pkgViewerAct); menuUtils->addAction(trophyViewerAct);
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
menuHelp->addAction(updaterAct); menuHelp->addAction(updaterAct);
#endif #endif
@ -335,8 +351,6 @@ public:
MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "shadPS4", nullptr)); MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "shadPS4", nullptr));
addElfFolderAct->setText( addElfFolderAct->setText(
QCoreApplication::translate("MainWindow", "Open/Add Elf Folder", nullptr)); QCoreApplication::translate("MainWindow", "Open/Add Elf Folder", nullptr));
bootInstallPkgAct->setText(
QCoreApplication::translate("MainWindow", "Install Packages (PKG)", nullptr));
bootGameAct->setText(QCoreApplication::translate("MainWindow", "Boot Game", nullptr)); bootGameAct->setText(QCoreApplication::translate("MainWindow", "Boot Game", nullptr));
#ifdef ENABLE_UPDATER #ifdef ENABLE_UPDATER
updaterAct->setText( updaterAct->setText(
@ -345,8 +359,6 @@ public:
aboutAct->setText(QCoreApplication::translate("MainWindow", "About shadPS4", nullptr)); aboutAct->setText(QCoreApplication::translate("MainWindow", "About shadPS4", nullptr));
configureAct->setText(QCoreApplication::translate("MainWindow", "Configure...", nullptr)); configureAct->setText(QCoreApplication::translate("MainWindow", "Configure...", nullptr));
#if QT_CONFIG(tooltip) #if QT_CONFIG(tooltip)
bootInstallPkgAct->setToolTip(QCoreApplication::translate(
"MainWindow", "Install application from a .pkg file", nullptr));
#endif // QT_CONFIG(tooltip) #endif // QT_CONFIG(tooltip)
menuRecent->setTitle(QCoreApplication::translate("MainWindow", "Recent Games", nullptr)); menuRecent->setTitle(QCoreApplication::translate("MainWindow", "Recent Games", nullptr));
shadFolderAct->setText( shadFolderAct->setText(
@ -378,7 +390,8 @@ public:
QCoreApplication::translate("MainWindow", "Download Cheats/Patches", nullptr)); QCoreApplication::translate("MainWindow", "Download Cheats/Patches", nullptr));
dumpGameListAct->setText( dumpGameListAct->setText(
QCoreApplication::translate("MainWindow", "Dump Game List", nullptr)); QCoreApplication::translate("MainWindow", "Dump Game List", nullptr));
pkgViewerAct->setText(QCoreApplication::translate("MainWindow", "PKG Viewer", nullptr)); trophyViewerAct->setText(
QCoreApplication::translate("MainWindow", "Trophy Viewer", nullptr));
mw_searchbar->setPlaceholderText( mw_searchbar->setPlaceholderText(
QCoreApplication::translate("MainWindow", "Search...", nullptr)); QCoreApplication::translate("MainWindow", "Search...", nullptr));
menuFile->setTitle(QCoreApplication::translate("MainWindow", "File", nullptr)); menuFile->setTitle(QCoreApplication::translate("MainWindow", "File", nullptr));
@ -405,4 +418,4 @@ public:
namespace Ui { namespace Ui {
class MainWindow : public Ui_MainWindow {}; class MainWindow : public Ui_MainWindow {};
} // namespace Ui } // namespace Ui

View file

@ -1,217 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "pkg_viewer.h"
PKGViewer::PKGViewer(std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent,
std::function<void(std::filesystem::path, int, int)> InstallDragDropPkg)
: QMainWindow(), m_game_info(game_info_get) {
this->resize(1280, 720);
this->setAttribute(Qt::WA_DeleteOnClose);
dir_list_std = Config::getPkgViewer();
dir_list.clear();
for (const auto& str : dir_list_std) {
dir_list.append(QString::fromStdString(str));
}
statusBar = new QStatusBar(treeWidget);
this->setStatusBar(statusBar);
treeWidget = new QTreeWidget(this);
treeWidget->setColumnCount(9);
QStringList headers;
headers << tr("Name") << tr("Serial") << tr("Installed") << tr("Size") << tr("Category")
<< tr("Type") << tr("App Ver") << tr("FW") << tr("Region") << tr("Flags") << tr("Path");
treeWidget->setHeaderLabels(headers);
treeWidget->header()->setDefaultAlignment(Qt::AlignCenter);
treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
treeWidget->setColumnWidth(8, 170);
this->setCentralWidget(treeWidget);
QMenuBar* menuBar = new QMenuBar(this);
menuBar->setContextMenuPolicy(Qt::PreventContextMenu);
QMenu* fileMenu = menuBar->addMenu(tr("File"));
QAction* openFolderAct = new QAction(tr("Open Folder"), this);
fileMenu->addAction(openFolderAct);
this->setMenuBar(menuBar);
CheckPKGFolders(); // Check for new PKG files in existing folders.
ProcessPKGInfo();
connect(openFolderAct, &QAction::triggered, this, &PKGViewer::OpenPKGFolder);
connect(treeWidget, &QTreeWidget::customContextMenuRequested, this,
[=, this](const QPoint& pos) {
if (treeWidget->selectedItems().isEmpty()) {
return;
}
m_gui_context_menus.RequestGameMenuPKGViewer(pos, m_full_pkg_list, treeWidget,
InstallDragDropPkg);
});
connect(parent, &QWidget::destroyed, this, [this]() { this->deleteLater(); });
}
PKGViewer::~PKGViewer() {}
void PKGViewer::OpenPKGFolder() {
QString folderPath =
QFileDialog::getExistingDirectory(this, tr("Open Folder"), QDir::homePath());
if (!dir_list.contains(folderPath)) {
dir_list.append(folderPath);
QDir directory(folderPath);
QFileInfoList fileInfoList = directory.entryInfoList(QDir::Files);
for (const QFileInfo& fileInfo : fileInfoList) {
QString file_ext = fileInfo.suffix();
if (fileInfo.isFile() && file_ext == "pkg") {
m_pkg_list.append(fileInfo.absoluteFilePath());
}
}
std::sort(m_pkg_list.begin(), m_pkg_list.end());
ProcessPKGInfo();
dir_list_std.clear();
for (auto dir : dir_list) {
dir_list_std.push_back(dir.toStdString());
}
Config::setPkgViewer(dir_list_std);
} else {
// qDebug() << "Folder selection canceled.";
}
}
void PKGViewer::CheckPKGFolders() { // Check for new PKG file additions.
m_pkg_list.clear();
for (const QString& dir : dir_list) {
QDir directory(dir);
QFileInfoList fileInfoList = directory.entryInfoList(QDir::Files);
for (const QFileInfo& fileInfo : fileInfoList) {
QString file_ext = fileInfo.suffix();
if (fileInfo.isFile() && file_ext == "pkg") {
m_pkg_list.append(fileInfo.absoluteFilePath());
}
}
}
std::sort(m_pkg_list.begin(), m_pkg_list.end());
}
void PKGViewer::ProcessPKGInfo() {
treeWidget->clear();
map_strings.clear();
map_integers.clear();
m_pkg_app_list.clear();
m_pkg_patch_list.clear();
m_full_pkg_list.clear();
for (int i = 0; i < m_pkg_list.size(); i++) {
std::filesystem::path path = Common::FS::PathFromQString(m_pkg_list[i]);
std::string failreason;
if (!package.Open(path, failreason)) {
QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason));
return;
}
psf.Open(package.sfo);
QString title_name = QString::fromStdString(
std::string{psf.GetString("TITLE").value_or(std::string{tr("Unknown").toStdString()})});
QString title_id = QString::fromStdString(std::string{
psf.GetString("TITLE_ID").value_or(std::string{tr("Unknown").toStdString()})});
QString app_type = GameListUtils::GetAppType(psf.GetInteger("APP_TYPE").value_or(0));
QString app_version = QString::fromStdString(std::string{
psf.GetString("APP_VER").value_or(std::string{tr("Unknown").toStdString()})});
QString title_category = QString::fromStdString(std::string{
psf.GetString("CATEGORY").value_or(std::string{tr("Unknown").toStdString()})});
QString pkg_size = GameListUtils::FormatSize(package.GetPkgHeader().pkg_size);
pkg_content_flag = package.GetPkgHeader().pkg_content_flags;
QString flagss = "";
for (const auto& flag : package.flagNames) {
if (package.isFlagSet(pkg_content_flag, flag.first)) {
if (!flagss.isEmpty())
flagss += (", ");
flagss += QString::fromStdString(flag.second.data());
}
}
QString fw_ = tr("Unknown");
if (const auto fw_int_opt = psf.GetInteger("SYSTEM_VER"); fw_int_opt.has_value()) {
const u32 fw_int = *fw_int_opt;
if (fw_int == 0) {
fw_ = "0.00";
} else {
QString fw = QString::number(fw_int, 16);
fw_ = fw.length() > 7 ? QString::number(fw_int, 16).left(3).insert(2, '.')
: fw.left(3).insert(1, '.');
}
}
char region = package.GetPkgHeader().pkg_content_id[0];
QString pkg_info = "";
if (title_category == "gd" && !flagss.contains("PATCH")) {
title_category = "App";
pkg_info = title_name + ";;" + title_id + ";;" + pkg_size + ";;" + title_category +
";;" + app_type + ";;" + app_version + ";;" + fw_ + ";;" +
game_list_util.GetRegion(region) + ";;" + flagss + ";;" + m_pkg_list[i];
m_pkg_app_list.append(pkg_info);
} else {
title_category = "Patch";
pkg_info = title_name + ";;" + title_id + ";;" + pkg_size + ";;" + title_category +
";;" + app_type + ";;" + app_version + ";;" + fw_ + ";;" +
game_list_util.GetRegion(region) + ";;" + flagss + ";;" + m_pkg_list[i];
m_pkg_patch_list.append(pkg_info);
}
}
std::sort(m_pkg_app_list.begin(), m_pkg_app_list.end());
for (int i = 0; i < m_pkg_app_list.size(); i++) {
QTreeWidgetItem* treeItem = new QTreeWidgetItem(treeWidget);
QStringList pkg_app_ = m_pkg_app_list[i].split(";;");
m_full_pkg_list.append(m_pkg_app_list[i]);
treeItem->setExpanded(true);
treeItem->setText(0, pkg_app_[0]);
treeItem->setText(1, pkg_app_[1]);
treeItem->setText(3, pkg_app_[2]);
treeItem->setTextAlignment(3, Qt::AlignCenter);
treeItem->setText(4, pkg_app_[3]);
treeItem->setTextAlignment(4, Qt::AlignCenter);
treeItem->setText(5, pkg_app_[4]);
treeItem->setTextAlignment(5, Qt::AlignCenter);
treeItem->setText(6, pkg_app_[5]);
treeItem->setTextAlignment(6, Qt::AlignCenter);
treeItem->setText(7, pkg_app_[6]);
treeItem->setTextAlignment(7, Qt::AlignCenter);
treeItem->setText(8, pkg_app_[7]);
treeItem->setTextAlignment(8, Qt::AlignCenter);
treeItem->setText(9, pkg_app_[8]);
treeItem->setText(10, pkg_app_[9]);
for (const GameInfo& info : m_game_info->m_games) { // Check if game is installed.
if (info.serial == pkg_app_[1].toStdString()) {
treeItem->setText(2, QChar(0x2713));
treeItem->setTextAlignment(2, Qt::AlignCenter);
}
}
for (const QString& item : m_pkg_patch_list) {
QStringList pkg_patch_ = item.split(";;");
if (pkg_patch_[1] == pkg_app_[1]) { // check patches with serial.
m_full_pkg_list.append(item);
QTreeWidgetItem* childItem = new QTreeWidgetItem(treeItem);
childItem->setText(0, pkg_patch_[0]);
childItem->setText(1, pkg_patch_[1]);
childItem->setText(3, pkg_patch_[2]);
childItem->setTextAlignment(3, Qt::AlignCenter);
childItem->setText(4, pkg_patch_[3]);
childItem->setTextAlignment(4, Qt::AlignCenter);
childItem->setText(5, pkg_patch_[4]);
childItem->setTextAlignment(5, Qt::AlignCenter);
childItem->setText(6, pkg_patch_[5]);
childItem->setTextAlignment(6, Qt::AlignCenter);
childItem->setText(7, pkg_patch_[6]);
childItem->setTextAlignment(7, Qt::AlignCenter);
childItem->setText(8, pkg_patch_[7]);
childItem->setTextAlignment(8, Qt::AlignCenter);
childItem->setText(9, pkg_patch_[8]);
childItem->setText(10, pkg_patch_[9]);
}
}
}
for (int column = 0; column < treeWidget->columnCount() - 2; ++column) {
// Resize the column to fit its contents
treeWidget->resizeColumnToContents(column);
}
// Update status bar.
statusBar->clearMessage();
int numPkgs = m_pkg_list.size();
QString statusMessage = QString::number(numPkgs) + " " + tr("Package");
statusBar->showMessage(statusMessage);
}

View file

@ -1,62 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <QFileDialog>
#include <QMenuBar>
#include <QStatusBar>
#include "common/io_file.h"
#include "core/file_format/pkg.h"
#include "core/file_format/pkg_type.h"
#include "core/file_format/psf.h"
#include "game_info.h"
#include "game_list_utils.h"
#include "gui_context_menus.h"
class PKGViewer : public QMainWindow {
Q_OBJECT
public:
explicit PKGViewer(
std::shared_ptr<GameInfoClass> game_info_get, QWidget* parent,
std::function<void(std::filesystem::path, int, int)> InstallDragDropPkg = nullptr);
~PKGViewer();
void OpenPKGFolder();
void CheckPKGFolders();
void ProcessPKGInfo();
private:
GuiContextMenus m_gui_context_menus;
PKG package;
PSF psf;
PKGHeader pkgheader;
PKGEntry entry;
PSFHeader header;
char pkgTitleID[9];
std::vector<u8> pkg;
u64 pkgSize = 0;
std::unordered_map<std::string, std::string> map_strings;
std::unordered_map<std::string, u32> map_integers;
u32_be pkg_content_flag;
std::shared_ptr<GameInfoClass> m_game_info;
GameListUtils game_list_util;
// Status bar
QStatusBar* statusBar;
std::vector<std::pair<int, QString>> appTypes = {
{0, "FULL APP"},
{1, "UPGRADABLE"},
{2, "DEMO"},
{3, "FREEMIUM"},
};
QStringList m_full_pkg_list;
QStringList m_pkg_app_list;
QStringList m_pkg_patch_list;
QStringList m_pkg_list;
QStringList dir_list;
std::vector<std::string> dir_list_std;
QTreeWidget* treeWidget = nullptr;
};

View file

@ -246,12 +246,13 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
// PATH TAB // PATH TAB
{ {
connect(ui->addFolderButton, &QPushButton::clicked, this, [this]() { connect(ui->addFolderButton, &QPushButton::clicked, this, [this]() {
const auto config_dir = Config::getGameInstallDirs();
QString file_path_string = QString file_path_string =
QFileDialog::getExistingDirectory(this, tr("Directory to install games")); QFileDialog::getExistingDirectory(this, tr("Directory to install games"));
auto file_path = Common::FS::PathFromQString(file_path_string); auto file_path = Common::FS::PathFromQString(file_path_string);
if (!file_path.empty() && Config::addGameInstallDir(file_path)) { if (!file_path.empty() && Config::addGameInstallDir(file_path, true)) {
QListWidgetItem* item = new QListWidgetItem(file_path_string); QListWidgetItem* item = new QListWidgetItem(file_path_string);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(Qt::Checked);
ui->gameFoldersListWidget->addItem(item); ui->gameFoldersListWidget->addItem(item);
} }
}); });
@ -317,7 +318,6 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
// General // General
ui->consoleLanguageGroupBox->installEventFilter(this); ui->consoleLanguageGroupBox->installEventFilter(this);
ui->emulatorLanguageGroupBox->installEventFilter(this); ui->emulatorLanguageGroupBox->installEventFilter(this);
ui->separateUpdatesCheckBox->installEventFilter(this);
ui->showSplashCheckBox->installEventFilter(this); ui->showSplashCheckBox->installEventFilter(this);
ui->discordRPCCheckbox->installEventFilter(this); ui->discordRPCCheckbox->installEventFilter(this);
ui->userName->installEventFilter(this); ui->userName->installEventFilter(this);
@ -449,8 +449,6 @@ void SettingsDialog::LoadValuesFromConfig() {
QString translatedText_FullscreenMode = QString translatedText_FullscreenMode =
screenModeMap.key(QString::fromStdString(Config::getFullscreenMode())); screenModeMap.key(QString::fromStdString(Config::getFullscreenMode()));
ui->displayModeComboBox->setCurrentText(translatedText_FullscreenMode); ui->displayModeComboBox->setCurrentText(translatedText_FullscreenMode);
ui->separateUpdatesCheckBox->setChecked(
toml::find_or<bool>(data, "General", "separateUpdateEnabled", false));
ui->gameSizeCheckBox->setChecked(toml::find_or<bool>(data, "GUI", "loadGameSizeEnabled", true)); ui->gameSizeCheckBox->setChecked(toml::find_or<bool>(data, "GUI", "loadGameSizeEnabled", true));
ui->showSplashCheckBox->setChecked(toml::find_or<bool>(data, "General", "showSplash", false)); ui->showSplashCheckBox->setChecked(toml::find_or<bool>(data, "General", "showSplash", false));
QString translatedText_logType = logTypeMap.key(QString::fromStdString(Config::getLogType())); QString translatedText_logType = logTypeMap.key(QString::fromStdString(Config::getLogType()));
@ -599,8 +597,6 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
text = tr("Console Language:\\nSets the language that the PS4 game uses.\\nIt's recommended to set this to a language the game supports, which will vary by region."); text = tr("Console Language:\\nSets the language that the PS4 game uses.\\nIt's recommended to set this to a language the game supports, which will vary by region.");
} else if (elementName == "emulatorLanguageGroupBox") { } else if (elementName == "emulatorLanguageGroupBox") {
text = tr("Emulator Language:\\nSets the language of the emulator's user interface."); text = tr("Emulator Language:\\nSets the language of the emulator's user interface.");
} else if (elementName == "separateUpdatesCheckBox") {
text = tr("Enable Separate Update Folder:\\nEnables installing game updates into a separate folder for easy management.\\nThis can be manually created by adding the extracted update to the game folder with the name \"CUSA00000-UPDATE\" where the CUSA ID matches the game's ID.");
} else if (elementName == "showSplashCheckBox") { } else if (elementName == "showSplashCheckBox") {
text = tr("Show Splash Screen:\\nShows the game's splash screen (a special image) while the game is starting."); text = tr("Show Splash Screen:\\nShows the game's splash screen (a special image) while the game is starting.");
} else if (elementName == "discordRPCCheckbox") { } else if (elementName == "discordRPCCheckbox") {
@ -759,7 +755,6 @@ void SettingsDialog::UpdateSettings() {
Config::setVblankDiv(ui->vblankSpinBox->value()); Config::setVblankDiv(ui->vblankSpinBox->value());
Config::setDumpShaders(ui->dumpShadersCheckBox->isChecked()); Config::setDumpShaders(ui->dumpShadersCheckBox->isChecked());
Config::setNullGpu(ui->nullGpuCheckBox->isChecked()); Config::setNullGpu(ui->nullGpuCheckBox->isChecked());
Config::setSeparateUpdateEnabled(ui->separateUpdatesCheckBox->isChecked());
Config::setLoadGameSizeEnabled(ui->gameSizeCheckBox->isChecked()); Config::setLoadGameSizeEnabled(ui->gameSizeCheckBox->isChecked());
Config::setShowSplash(ui->showSplashCheckBox->isChecked()); Config::setShowSplash(ui->showSplashCheckBox->isChecked());
Config::setDebugDump(ui->debugDump->isChecked()); Config::setDebugDump(ui->debugDump->isChecked());
@ -783,6 +778,17 @@ void SettingsDialog::UpdateSettings() {
emit BackgroundOpacityChanged(ui->backgroundImageOpacitySlider->value()); emit BackgroundOpacityChanged(ui->backgroundImageOpacitySlider->value());
Config::setShowBackgroundImage(ui->showBackgroundImageCheckBox->isChecked()); Config::setShowBackgroundImage(ui->showBackgroundImageCheckBox->isChecked());
std::vector<Config::GameInstallDir> dirs_with_states;
for (int i = 0; i < ui->gameFoldersListWidget->count(); i++) {
QListWidgetItem* item = ui->gameFoldersListWidget->item(i);
QString path_string = item->text();
auto path = Common::FS::PathFromQString(path_string);
bool enabled = (item->checkState() == Qt::Checked);
dirs_with_states.push_back({path, enabled});
}
Config::setAllGameInstallDirs(dirs_with_states);
#ifdef ENABLE_DISCORD_RPC #ifdef ENABLE_DISCORD_RPC
auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance(); auto* rpc = Common::Singleton<DiscordRPCHandler::RPC>::Instance();
if (Config::getEnableDiscordRPC()) { if (Config::getEnableDiscordRPC()) {
@ -797,6 +803,7 @@ void SettingsDialog::UpdateSettings() {
} }
void SettingsDialog::ResetInstallFolders() { void SettingsDialog::ResetInstallFolders() {
ui->gameFoldersListWidget->clear();
std::filesystem::path userdir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); std::filesystem::path userdir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
const toml::value data = toml::parse(userdir / "config.toml"); const toml::value data = toml::parse(userdir / "config.toml");
@ -804,22 +811,37 @@ void SettingsDialog::ResetInstallFolders() {
if (data.contains("GUI")) { if (data.contains("GUI")) {
const toml::value& gui = data.at("GUI"); const toml::value& gui = data.at("GUI");
const auto install_dir_array = const auto install_dir_array =
toml::find_or<std::vector<std::string>>(gui, "installDirs", {}); toml::find_or<std::vector<std::u8string>>(gui, "installDirs", {});
std::vector<std::filesystem::path> settings_install_dirs_config = {};
for (const auto& dir : install_dir_array) { std::vector<bool> install_dirs_enabled;
if (std::find(settings_install_dirs_config.begin(), settings_install_dirs_config.end(), try {
dir) == settings_install_dirs_config.end()) { install_dirs_enabled = Config::getGameInstallDirsEnabled();
settings_install_dirs_config.push_back(dir); } catch (...) {
} // If it does not exist, assume that all are enabled.
install_dirs_enabled.resize(install_dir_array.size(), true);
} }
for (const auto& dir : settings_install_dirs_config) { if (install_dirs_enabled.size() < install_dir_array.size()) {
install_dirs_enabled.resize(install_dir_array.size(), true);
}
std::vector<Config::GameInstallDir> settings_install_dirs_config;
for (size_t i = 0; i < install_dir_array.size(); i++) {
std::filesystem::path dir = install_dir_array[i];
bool enabled = install_dirs_enabled[i];
settings_install_dirs_config.push_back({dir, enabled});
QString path_string; QString path_string;
Common::FS::PathToQString(path_string, dir); Common::FS::PathToQString(path_string, dir);
QListWidgetItem* item = new QListWidgetItem(path_string); QListWidgetItem* item = new QListWidgetItem(path_string);
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(enabled ? Qt::Checked : Qt::Unchecked);
ui->gameFoldersListWidget->addItem(item); ui->gameFoldersListWidget->addItem(item);
} }
Config::setGameInstallDirs(settings_install_dirs_config);
Config::setAllGameInstallDirs(settings_install_dirs_config);
} }
} }

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