mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-20 11:35:45 +00:00
Merge branch 'shadps4-emu:main' into allocate-fixes
This commit is contained in:
commit
46e467878a
141 changed files with 5929 additions and 1392 deletions
|
@ -106,6 +106,36 @@ git_describe(GIT_DESC --always --long --dirty)
|
|||
git_branch_name(GIT_BRANCH)
|
||||
string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Try to get the upstream remote and branch
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref --symbolic-full-name @{u}
|
||||
OUTPUT_VARIABLE GIT_REMOTE_NAME
|
||||
RESULT_VARIABLE GIT_BRANCH_RESULT
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Default to origin if there's no upstream set or if the command failed
|
||||
if (GIT_BRANCH_RESULT OR GIT_REMOTE_NAME STREQUAL "")
|
||||
set(GIT_REMOTE_NAME "origin")
|
||||
else()
|
||||
# Extract remote name if the output contains a remote/branch format
|
||||
string(FIND "${GIT_REMOTE_NAME}" "/" INDEX)
|
||||
if (INDEX GREATER -1)
|
||||
string(SUBSTRING "${GIT_REMOTE_NAME}" 0 "${INDEX}" GIT_REMOTE_NAME)
|
||||
else()
|
||||
# If no remote is present (only a branch name), default to origin
|
||||
set(GIT_REMOTE_NAME "origin")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Get remote link
|
||||
execute_process(
|
||||
COMMAND git config --get remote.${GIT_REMOTE_NAME}.url
|
||||
OUTPUT_VARIABLE GIT_REMOTE_URL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY)
|
||||
|
||||
find_package(Boost 1.84.0 CONFIG)
|
||||
|
@ -344,6 +374,8 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
|
|||
src/core/libraries/razor_cpu/razor_cpu.h
|
||||
src/core/libraries/mouse/mouse.cpp
|
||||
src/core/libraries/mouse/mouse.h
|
||||
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
|
||||
src/core/libraries/web_browser_dialog/webbrowserdialog.h
|
||||
)
|
||||
|
||||
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
|
||||
|
@ -434,6 +466,13 @@ set(NP_LIBS src/core/libraries/np_common/np_common.cpp
|
|||
src/core/libraries/np_trophy/np_trophy_error.h
|
||||
src/core/libraries/np_web_api/np_web_api.cpp
|
||||
src/core/libraries/np_web_api/np_web_api.h
|
||||
src/core/libraries/np_party/np_party.cpp
|
||||
src/core/libraries/np_party/np_party.h
|
||||
)
|
||||
|
||||
set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp
|
||||
src/core/libraries/zlib/zlib_sce.h
|
||||
src/core/libraries/zlib/zlib_error.h
|
||||
)
|
||||
|
||||
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
||||
|
@ -608,6 +647,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||
${PLAYGO_LIB}
|
||||
${RANDOM_LIB}
|
||||
${USBD_LIB}
|
||||
${ZLIB_LIB}
|
||||
${MISC_LIBS}
|
||||
${IME_LIB}
|
||||
${FIBER_LIB}
|
||||
|
@ -751,8 +791,6 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
|
|||
src/video_core/renderer_vulkan/vk_common.h
|
||||
src/video_core/renderer_vulkan/vk_compute_pipeline.cpp
|
||||
src/video_core/renderer_vulkan/vk_compute_pipeline.h
|
||||
src/video_core/renderer_vulkan/vk_descriptor_update_queue.cpp
|
||||
src/video_core/renderer_vulkan/vk_descriptor_update_queue.h
|
||||
src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
|
||||
src/video_core/renderer_vulkan/vk_graphics_pipeline.h
|
||||
src/video_core/renderer_vulkan/vk_instance.cpp
|
||||
|
@ -816,6 +854,10 @@ set(IMGUI src/imgui/imgui_config.h
|
|||
|
||||
set(INPUT src/input/controller.cpp
|
||||
src/input/controller.h
|
||||
src/input/input_handler.cpp
|
||||
src/input/input_handler.h
|
||||
src/input/input_mouse.cpp
|
||||
src/input/input_mouse.h
|
||||
)
|
||||
|
||||
set(EMULATOR src/emulator.cpp
|
||||
|
@ -865,6 +907,10 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
|
|||
src/qt_gui/trophy_viewer.h
|
||||
src/qt_gui/elf_viewer.cpp
|
||||
src/qt_gui/elf_viewer.h
|
||||
src/qt_gui/kbm_config_dialog.cpp
|
||||
src/qt_gui/kbm_config_dialog.h
|
||||
src/qt_gui/kbm_help_dialog.cpp
|
||||
src/qt_gui/kbm_help_dialog.h
|
||||
src/qt_gui/main_window_themes.cpp
|
||||
src/qt_gui/main_window_themes.h
|
||||
src/qt_gui/settings_dialog.cpp
|
||||
|
|
63
README.md
63
README.md
|
@ -55,6 +55,9 @@ This project began as a fun project. Given our limited free time, it may take so
|
|||
|
||||
# Building
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you want to use shadPS4 to play your games, you don't have to follow the build instructions, you can simply download the emulator from either the [**release tab**](https://github.com/shadps4-emu/shadPS4/releases) or the [**action tab**](https://github.com/shadps4-emu/shadPS4/actions).
|
||||
|
||||
## Windows
|
||||
|
||||
Check the build instructions for [**Windows**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-windows.md).
|
||||
|
@ -74,7 +77,10 @@ Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shad
|
|||
|
||||
For more information on how to test, debug and report issues with the emulator or games, read the [**Debugging documentation**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md).
|
||||
|
||||
# Keyboard mapping
|
||||
# Keyboard and Mouse Mappings
|
||||
|
||||
> [!NOTE]
|
||||
> Some keyboards may also require you to hold the Fn key to use the F\* keys. Mac users should use the Command key instead of Control, and need to use Command+F11 for full screen to avoid conflicting with system key bindings.
|
||||
|
||||
| Button | Function |
|
||||
|-------------|-------------|
|
||||
|
@ -86,32 +92,35 @@ F12 | Trigger RenderDoc Capture
|
|||
> [!NOTE]
|
||||
> Xbox and DualShock controllers work out of the box.
|
||||
|
||||
| Controller button | Keyboard equivelant | Mac alternative |
|
||||
|-------------|-------------|--------------|
|
||||
LEFT AXIS UP | W | |
|
||||
LEFT AXIS DOWN | S | |
|
||||
LEFT AXIS LEFT | A | |
|
||||
LEFT AXIS RIGHT | D | |
|
||||
RIGHT AXIS UP | I | |
|
||||
RIGHT AXIS DOWN | K | |
|
||||
RIGHT AXIS LEFT | J | |
|
||||
RIGHT AXIS RIGHT | L | |
|
||||
TRIANGLE | Numpad 8 | C |
|
||||
CIRCLE | Numpad 6 | B |
|
||||
CROSS | Numpad 2 | N |
|
||||
SQUARE | Numpad 4 | V |
|
||||
PAD UP | UP | |
|
||||
PAD DOWN | DOWN | |
|
||||
PAD LEFT | LEFT | |
|
||||
PAD RIGHT | RIGHT | |
|
||||
OPTIONS | RETURN | |
|
||||
BACK BUTTON / TOUCH PAD | SPACE | |
|
||||
L1 | Q | |
|
||||
R1 | U | |
|
||||
L2 | E | |
|
||||
R2 | O | |
|
||||
L3 | X | |
|
||||
R3 | M | |
|
||||
| Controller button | Keyboard equivalent |
|
||||
|-------------|-------------|
|
||||
LEFT AXIS UP | W |
|
||||
LEFT AXIS DOWN | S |
|
||||
LEFT AXIS LEFT | A |
|
||||
LEFT AXIS RIGHT | D |
|
||||
RIGHT AXIS UP | I |
|
||||
RIGHT AXIS DOWN | K |
|
||||
RIGHT AXIS LEFT | J |
|
||||
RIGHT AXIS RIGHT | L |
|
||||
TRIANGLE | Numpad 8 or C |
|
||||
CIRCLE | Numpad 6 or B |
|
||||
CROSS | Numpad 2 or N |
|
||||
SQUARE | Numpad 4 or V |
|
||||
PAD UP | UP |
|
||||
PAD DOWN | DOWN |
|
||||
PAD LEFT | LEFT |
|
||||
PAD RIGHT | RIGHT |
|
||||
OPTIONS | RETURN |
|
||||
BACK BUTTON / TOUCH PAD | SPACE |
|
||||
L1 | Q |
|
||||
R1 | U |
|
||||
L2 | E |
|
||||
R2 | O |
|
||||
L3 | X |
|
||||
R3 | M |
|
||||
|
||||
Keyboard and mouse inputs can be customized in the settings menu by clicking the Controller button, and further details and help on controls are also found there. Custom bindings are saved per-game. Inputs support up to three keys per binding, mouse buttons, mouse movement mapped to joystick input, and more.
|
||||
|
||||
|
||||
# Main team
|
||||
|
||||
|
|
3
dist/net.shadps4.shadPS4.metainfo.xml
vendored
3
dist/net.shadps4.shadPS4.metainfo.xml
vendored
|
@ -37,6 +37,9 @@
|
|||
<category translate="no">Game</category>
|
||||
</categories>
|
||||
<releases>
|
||||
<release version="0.6.0" date="2025-01-31">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.6.0</url>
|
||||
</release>
|
||||
<release version="0.5.0" date="2024-12-25">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.5.0</url>
|
||||
</release>
|
||||
|
|
|
@ -22,7 +22,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
||||
- A processor with at least 4 cores and 6 threads
|
||||
- Above 2.5 GHz frequency
|
||||
- required support AVX2 extension or Rosetta 2 on ARM
|
||||
- A CPU supporting the following instruction sets: MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, F16C, CLMUL, AES, BMI1, MOVBE, XSAVE, ABM
|
||||
- **Intel**: Haswell generation or newer
|
||||
- **AMD**: Jaguar generation or newer
|
||||
- **Apple**: Rosetta 2 on macOS 15 or newer
|
||||
|
||||
### GPU
|
||||
|
||||
|
|
|
@ -29,7 +29,9 @@ sudo dnf install clang git cmake libatomic alsa-lib-devel pipewire-jack-audio-co
|
|||
sudo pacman -S base-devel clang git cmake sndio jack2 openal qt6-base qt6-declarative qt6-multimedia sdl2 vulkan-validation-layers
|
||||
```
|
||||
|
||||
**Note** : The `shadps4-git` AUR package is not maintained by any of the developers, and it uses the default compiler, which is often set to GCC. Use at your own discretion.#### OpenSUSE
|
||||
**Note**: The `shadps4-git` AUR package is not maintained by any of the developers, and it uses the default compiler, which is often set to GCC. Use at your own discretion.
|
||||
|
||||
#### OpenSUSE
|
||||
|
||||
```
|
||||
sudo zypper install clang git cmake libasound2 libpulse-devel libsndio7 libjack-devel openal-soft-devel libopenssl-devel zlib-devel libedit-devel systemd-devel libevdev-devel qt6-base-devel qt6-multimedia-devel qt6-svg-devel qt6-linguist-devel qt6-gui-private-devel vulkan-devel vulkan-validationlayers
|
||||
|
@ -48,6 +50,7 @@ distrobox create --name archlinux --init --image archlinux:latest
|
|||
|
||||
and install the dependencies on that container as cited above.
|
||||
This option is **highly recommended** for NixOS and distributions with immutable/atomic filesystems (example: Fedora Kinoite, SteamOS).
|
||||
|
||||
### Cloning
|
||||
|
||||
```
|
||||
|
|
2
externals/MoltenVK/MoltenVK
vendored
2
externals/MoltenVK/MoltenVK
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 2473ce6f0ab7d5d8a49aa91b2e37f3447a939f18
|
||||
Subproject commit 0c090001cb42997031cfe43914340e2639944972
|
2
externals/MoltenVK/SPIRV-Cross
vendored
2
externals/MoltenVK/SPIRV-Cross
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 6173e24b31f09a0c3217103a130e74c4ddec14a6
|
||||
Subproject commit 1a7b7ef6de02cf6767e42b10ddad217c45e90d47
|
2
externals/sirit
vendored
2
externals/sirit
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 26ad5a9d0fe13260b0d7d6c64419d01a196b2e32
|
||||
Subproject commit d6f3c0d99862ab2ff8f95e9ac221560f1f97e29a
|
|
@ -46,8 +46,6 @@ static std::string logType = "async";
|
|||
static std::string userName = "shadPS4";
|
||||
static std::string updateChannel;
|
||||
static std::string chooseHomeTab;
|
||||
static u16 deadZoneLeft = 2.0;
|
||||
static u16 deadZoneRight = 2.0;
|
||||
static std::string backButtonBehavior = "left";
|
||||
static bool useSpecialPad = false;
|
||||
static int specialPadClass = 1;
|
||||
|
@ -70,6 +68,7 @@ static bool vkGuestMarkers = false;
|
|||
static bool rdocEnable = false;
|
||||
static s16 cursorState = HideCursorState::Idle;
|
||||
static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||
static bool useUnifiedInputConfig = true;
|
||||
static bool separateupdatefolder = false;
|
||||
static bool compatibilityData = false;
|
||||
static bool checkCompatibilityOnStartup = false;
|
||||
|
@ -100,6 +99,14 @@ std::string emulator_language = "en";
|
|||
// Language
|
||||
u32 m_language = 1; // english
|
||||
|
||||
bool GetUseUnifiedInputConfig() {
|
||||
return useUnifiedInputConfig;
|
||||
}
|
||||
|
||||
void SetUseUnifiedInputConfig(bool use) {
|
||||
useUnifiedInputConfig = use;
|
||||
}
|
||||
|
||||
std::string getTrophyKey() {
|
||||
return trophyKey;
|
||||
}
|
||||
|
@ -151,14 +158,6 @@ bool getEnableDiscordRPC() {
|
|||
return enableDiscordRPC;
|
||||
}
|
||||
|
||||
u16 leftDeadZone() {
|
||||
return deadZoneLeft;
|
||||
}
|
||||
|
||||
u16 rightDeadZone() {
|
||||
return deadZoneRight;
|
||||
}
|
||||
|
||||
s16 getCursorState() {
|
||||
return cursorState;
|
||||
}
|
||||
|
@ -267,18 +266,28 @@ bool vkValidationGpuEnabled() {
|
|||
return vkValidationGpu;
|
||||
}
|
||||
|
||||
bool vkCrashDiagnosticEnabled() {
|
||||
bool getVkCrashDiagnosticEnabled() {
|
||||
return vkCrashDiagnostic;
|
||||
}
|
||||
|
||||
bool vkHostMarkersEnabled() {
|
||||
// Forced on when crash diagnostic enabled.
|
||||
return vkHostMarkers || vkCrashDiagnostic;
|
||||
bool getVkHostMarkersEnabled() {
|
||||
return vkHostMarkers;
|
||||
}
|
||||
|
||||
bool vkGuestMarkersEnabled() {
|
||||
// Forced on when crash diagnostic enabled.
|
||||
return vkGuestMarkers || vkCrashDiagnostic;
|
||||
bool getVkGuestMarkersEnabled() {
|
||||
return vkGuestMarkers;
|
||||
}
|
||||
|
||||
void setVkCrashDiagnosticEnabled(bool enable) {
|
||||
vkCrashDiagnostic = enable;
|
||||
}
|
||||
|
||||
void setVkHostMarkersEnabled(bool enable) {
|
||||
vkHostMarkers = enable;
|
||||
}
|
||||
|
||||
void setVkGuestMarkersEnabled(bool enable) {
|
||||
vkGuestMarkers = enable;
|
||||
}
|
||||
|
||||
bool getSeparateUpdateEnabled() {
|
||||
|
@ -651,14 +660,13 @@ void load(const std::filesystem::path& path) {
|
|||
if (data.contains("Input")) {
|
||||
const toml::value& input = data.at("Input");
|
||||
|
||||
deadZoneLeft = toml::find_or<float>(input, "deadZoneLeft", 2.0);
|
||||
deadZoneRight = toml::find_or<float>(input, "deadZoneRight", 2.0);
|
||||
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle);
|
||||
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5);
|
||||
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
|
||||
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
|
||||
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
|
||||
isMotionControlsEnabled = toml::find_or<bool>(input, "isMotionControlsEnabled", true);
|
||||
useUnifiedInputConfig = toml::find_or<bool>(input, "useUnifiedInputConfig", true);
|
||||
}
|
||||
|
||||
if (data.contains("GPU")) {
|
||||
|
@ -775,14 +783,13 @@ void save(const std::filesystem::path& path) {
|
|||
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
|
||||
data["General"]["compatibilityEnabled"] = compatibilityData;
|
||||
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
|
||||
data["Input"]["deadZoneLeft"] = deadZoneLeft;
|
||||
data["Input"]["deadZoneRight"] = deadZoneRight;
|
||||
data["Input"]["cursorState"] = cursorState;
|
||||
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
||||
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
||||
data["Input"]["useSpecialPad"] = useSpecialPad;
|
||||
data["Input"]["specialPadClass"] = specialPadClass;
|
||||
data["Input"]["isMotionControlsEnabled"] = isMotionControlsEnabled;
|
||||
data["Input"]["useUnifiedInputConfig"] = useUnifiedInputConfig;
|
||||
data["GPU"]["screenWidth"] = screenWidth;
|
||||
data["GPU"]["screenHeight"] = screenHeight;
|
||||
data["GPU"]["nullGpu"] = isNullGpu;
|
||||
|
@ -909,4 +916,112 @@ void setDefaultValues() {
|
|||
checkCompatibilityOnStartup = false;
|
||||
}
|
||||
|
||||
} // namespace Config
|
||||
constexpr std::string_view GetDefaultKeyboardConfig() {
|
||||
return R"(#Feeling lost? Check out the Help section!
|
||||
|
||||
# Keyboard bindings
|
||||
|
||||
triangle = kp8
|
||||
circle = kp6
|
||||
cross = kp2
|
||||
square = kp4
|
||||
# Alternatives for users without a keypad
|
||||
triangle = c
|
||||
circle = b
|
||||
cross = n
|
||||
square = v
|
||||
|
||||
l1 = q
|
||||
r1 = u
|
||||
l2 = e
|
||||
r2 = o
|
||||
l3 = x
|
||||
r3 = m
|
||||
|
||||
options = enter
|
||||
touchpad = space
|
||||
|
||||
pad_up = up
|
||||
pad_down = down
|
||||
pad_left = left
|
||||
pad_right = right
|
||||
|
||||
axis_left_x_minus = a
|
||||
axis_left_x_plus = d
|
||||
axis_left_y_minus = w
|
||||
axis_left_y_plus = s
|
||||
|
||||
axis_right_x_minus = j
|
||||
axis_right_x_plus = l
|
||||
axis_right_y_minus = i
|
||||
axis_right_y_plus = k
|
||||
|
||||
# Controller bindings
|
||||
|
||||
triangle = triangle
|
||||
cross = cross
|
||||
square = square
|
||||
circle = circle
|
||||
|
||||
l1 = l1
|
||||
l2 = l2
|
||||
l3 = l3
|
||||
r1 = r1
|
||||
r2 = r2
|
||||
r3 = r3
|
||||
|
||||
options = options
|
||||
touchpad = back
|
||||
|
||||
pad_up = pad_up
|
||||
pad_down = pad_down
|
||||
pad_left = pad_left
|
||||
pad_right = pad_right
|
||||
|
||||
axis_left_x = axis_left_x
|
||||
axis_left_y = axis_left_y
|
||||
axis_right_x = axis_right_x
|
||||
axis_right_y = axis_right_y
|
||||
|
||||
# Range of deadzones: 1 (almost none) to 127 (max)
|
||||
analog_deadzone = leftjoystick, 2
|
||||
analog_deadzone = rightjoystick, 2
|
||||
)";
|
||||
}
|
||||
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) {
|
||||
// Read configuration file of the game, and if it doesn't exist, generate it from default
|
||||
// If that doesn't exist either, generate that from getDefaultConfig() and try again
|
||||
// If even the folder is missing, we start with that.
|
||||
|
||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "input_config";
|
||||
const auto config_file = config_dir / (game_id + ".ini");
|
||||
const auto default_config_file = config_dir / "default.ini";
|
||||
|
||||
// Ensure the config directory exists
|
||||
if (!std::filesystem::exists(config_dir)) {
|
||||
std::filesystem::create_directories(config_dir);
|
||||
}
|
||||
|
||||
// Check if the default config exists
|
||||
if (!std::filesystem::exists(default_config_file)) {
|
||||
// If the default config is also missing, create it from getDefaultConfig()
|
||||
const auto default_config = GetDefaultKeyboardConfig();
|
||||
std::ofstream default_config_stream(default_config_file);
|
||||
if (default_config_stream) {
|
||||
default_config_stream << default_config;
|
||||
}
|
||||
}
|
||||
|
||||
// if empty, we only need to execute the function up until this point
|
||||
if (game_id.empty()) {
|
||||
return default_config_file;
|
||||
}
|
||||
|
||||
// If game-specific config doesn't exist, create it from the default config
|
||||
if (!std::filesystem::exists(config_file)) {
|
||||
std::filesystem::copy(default_config_file, config_file);
|
||||
}
|
||||
return config_file;
|
||||
}
|
||||
|
||||
} // namespace Config
|
||||
|
|
|
@ -37,14 +37,14 @@ std::string getUserName();
|
|||
std::string getUpdateChannel();
|
||||
std::string getChooseHomeTab();
|
||||
|
||||
u16 leftDeadZone();
|
||||
u16 rightDeadZone();
|
||||
s16 getCursorState();
|
||||
int getCursorHideTimeout();
|
||||
std::string getBackButtonBehavior();
|
||||
bool getUseSpecialPad();
|
||||
int getSpecialPadClass();
|
||||
bool getIsMotionControlsEnabled();
|
||||
bool GetUseUnifiedInputConfig();
|
||||
void SetUseUnifiedInputConfig(bool use);
|
||||
|
||||
u32 getScreenWidth();
|
||||
u32 getScreenHeight();
|
||||
|
@ -106,9 +106,12 @@ void setRdocEnabled(bool enable);
|
|||
bool vkValidationEnabled();
|
||||
bool vkValidationSyncEnabled();
|
||||
bool vkValidationGpuEnabled();
|
||||
bool vkCrashDiagnosticEnabled();
|
||||
bool vkHostMarkersEnabled();
|
||||
bool vkGuestMarkersEnabled();
|
||||
bool getVkCrashDiagnosticEnabled();
|
||||
bool getVkHostMarkersEnabled();
|
||||
bool getVkGuestMarkersEnabled();
|
||||
void setVkCrashDiagnosticEnabled(bool enable);
|
||||
void setVkHostMarkersEnabled(bool enable);
|
||||
void setVkGuestMarkersEnabled(bool enable);
|
||||
|
||||
// Gui
|
||||
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
||||
|
@ -149,6 +152,9 @@ std::string getEmulatorLanguage();
|
|||
|
||||
void setDefaultValues();
|
||||
|
||||
// todo: name and function location pending
|
||||
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id = "");
|
||||
|
||||
// settings
|
||||
u32 GetLanguage();
|
||||
}; // namespace Config
|
||||
|
|
|
@ -80,6 +80,7 @@ public:
|
|||
static constexpr u32 FW_40 = 0x4000000;
|
||||
static constexpr u32 FW_45 = 0x4500000;
|
||||
static constexpr u32 FW_50 = 0x5000000;
|
||||
static constexpr u32 FW_55 = 0x5500000;
|
||||
static constexpr u32 FW_80 = 0x8000000;
|
||||
|
||||
static ElfInfo& Instance() {
|
||||
|
|
|
@ -131,6 +131,9 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||
SUB(Lib, Videodec) \
|
||||
SUB(Lib, RazorCpu) \
|
||||
SUB(Lib, Mouse) \
|
||||
SUB(Lib, WebBrowserDialog) \
|
||||
SUB(Lib, NpParty) \
|
||||
SUB(Lib, Zlib) \
|
||||
CLS(Frontend) \
|
||||
CLS(Render) \
|
||||
SUB(Render, Vulkan) \
|
||||
|
|
|
@ -98,6 +98,9 @@ enum class Class : u8 {
|
|||
Lib_Videodec, ///< The LibSceVideodec implementation.
|
||||
Lib_RazorCpu, ///< The LibRazorCpu implementation.
|
||||
Lib_Mouse, ///< The LibSceMouse implementation
|
||||
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
|
||||
Lib_NpParty, ///< The LibSceNpParty implementation
|
||||
Lib_Zlib, ///< The LibSceZlib implementation.
|
||||
Frontend, ///< Emulator UI
|
||||
Render, ///< Video Core
|
||||
Render_Vulkan, ///< Vulkan backend
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <string>
|
||||
#include <pugixml.hpp>
|
||||
#ifdef ENABLE_QT_GUI
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
|
@ -189,14 +190,16 @@ void OnGameLoaded() {
|
|||
// We use the QT headers for the xml and json parsing, this define is only true on QT builds
|
||||
QString patchDir;
|
||||
Common::FS::PathToQString(patchDir, Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
|
||||
QString repositories[] = {"GoldHEN", "shadPS4"};
|
||||
QDir dir(patchDir);
|
||||
QStringList folders = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
|
||||
for (const QString& repository : repositories) {
|
||||
QString filesJsonPath = patchDir + "/" + repository + "/files.json";
|
||||
for (const QString& folder : folders) {
|
||||
QString filesJsonPath = patchDir + "/" + folder + "/files.json";
|
||||
|
||||
QFile jsonFile(filesJsonPath);
|
||||
if (!jsonFile.open(QIODevice::ReadOnly)) {
|
||||
LOG_ERROR(Loader, "Unable to open files.json for reading.");
|
||||
LOG_ERROR(Loader, "Unable to open files.json for reading in repository {}",
|
||||
folder.toStdString());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -220,11 +223,12 @@ void OnGameLoaded() {
|
|||
}
|
||||
|
||||
if (selectedFileName.isEmpty()) {
|
||||
LOG_ERROR(Loader, "No patch file found for the current serial.");
|
||||
LOG_ERROR(Loader, "No patch file found for the current serial in repository {}",
|
||||
folder.toStdString());
|
||||
continue;
|
||||
}
|
||||
|
||||
QString filePath = patchDir + "/" + repository + "/" + selectedFileName;
|
||||
QString filePath = patchDir + "/" + folder + "/" + selectedFileName;
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
LOG_ERROR(Loader, "Unable to open the file for reading.");
|
||||
|
|
|
@ -176,6 +176,34 @@ void SetUserPath(PathType shad_path, const fs::path& new_path) {
|
|||
UserPaths.insert_or_assign(shad_path, new_path);
|
||||
}
|
||||
|
||||
std::optional<fs::path> FindGameByID(const fs::path& dir, const std::string& game_id,
|
||||
int max_depth) {
|
||||
if (max_depth < 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Check if this is the game we're looking for
|
||||
if (dir.filename() == game_id && fs::exists(dir / "sce_sys" / "param.sfo")) {
|
||||
auto eboot_path = dir / "eboot.bin";
|
||||
if (fs::exists(eboot_path)) {
|
||||
return eboot_path;
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively search subdirectories
|
||||
std::error_code ec;
|
||||
for (const auto& entry : fs::directory_iterator(dir, ec)) {
|
||||
if (!entry.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
if (auto found = FindGameByID(entry.path(), game_id, max_depth - 1)) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_QT_GUI
|
||||
void PathToQString(QString& result, const std::filesystem::path& path) {
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#ifdef ENABLE_QT_GUI
|
||||
|
@ -115,4 +116,18 @@ void PathToQString(QString& result, const std::filesystem::path& path);
|
|||
[[nodiscard]] std::filesystem::path PathFromQString(const QString& path);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Recursively searches for a game directory by its ID.
|
||||
* Limits search depth to prevent excessive filesystem traversal.
|
||||
*
|
||||
* @param dir Base directory to start the search from
|
||||
* @param game_id The game ID to search for
|
||||
* @param max_depth Maximum directory depth to search
|
||||
*
|
||||
* @returns Path to eboot.bin if found, std::nullopt otherwise
|
||||
*/
|
||||
[[nodiscard]] std::optional<std::filesystem::path> FindGameByID(const std::filesystem::path& dir,
|
||||
const std::string& game_id,
|
||||
int max_depth);
|
||||
|
||||
} // namespace Common::FS
|
||||
|
|
|
@ -6,14 +6,18 @@
|
|||
#define GIT_REV "@GIT_REV@"
|
||||
#define GIT_BRANCH "@GIT_BRANCH@"
|
||||
#define GIT_DESC "@GIT_DESC@"
|
||||
#define GIT_REMOTE_NAME "@GIT_REMOTE_NAME@"
|
||||
#define GIT_REMOTE_URL "@GIT_REMOTE_URL@"
|
||||
#define BUILD_DATE "@BUILD_DATE@"
|
||||
|
||||
namespace Common {
|
||||
|
||||
const char g_scm_rev[] = GIT_REV;
|
||||
const char g_scm_branch[] = GIT_BRANCH;
|
||||
const char g_scm_desc[] = GIT_DESC;
|
||||
const char g_scm_date[] = BUILD_DATE;
|
||||
const char g_scm_rev[] = GIT_REV;
|
||||
const char g_scm_branch[] = GIT_BRANCH;
|
||||
const char g_scm_desc[] = GIT_DESC;
|
||||
const char g_scm_remote_name[] = GIT_REMOTE_NAME;
|
||||
const char g_scm_remote_url[] = GIT_REMOTE_URL;
|
||||
const char g_scm_date[] = BUILD_DATE;
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace Common {
|
|||
extern const char g_scm_rev[];
|
||||
extern const char g_scm_branch[];
|
||||
extern const char g_scm_desc[];
|
||||
extern const char g_scm_remote_name[];
|
||||
extern const char g_scm_remote_url[];
|
||||
extern const char g_scm_date[];
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
namespace Common {
|
||||
|
||||
constexpr char VERSION[] = "0.5.1 WIP";
|
||||
constexpr char VERSION[] = "0.6.1 WIP";
|
||||
constexpr bool isRelease = false;
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -30,16 +30,6 @@
|
|||
|
||||
using namespace Xbyak::util;
|
||||
|
||||
#define MAYBE_AVX(OPCODE, ...) \
|
||||
[&] { \
|
||||
Cpu cpu; \
|
||||
if (cpu.has(Cpu::tAVX)) { \
|
||||
c.v##OPCODE(__VA_ARGS__); \
|
||||
} else { \
|
||||
c.OPCODE(__VA_ARGS__); \
|
||||
} \
|
||||
}()
|
||||
|
||||
namespace Core {
|
||||
|
||||
static Xbyak::Reg ZydisToXbyakRegister(const ZydisRegister reg) {
|
||||
|
@ -643,7 +633,7 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
|
|||
ASSERT_MSG(length + index <= 64, "length + index must be less than or equal to 64.");
|
||||
|
||||
// Get lower qword from xmm register
|
||||
MAYBE_AVX(movq, scratch1, xmm_dst);
|
||||
c.vmovq(scratch1, xmm_dst);
|
||||
|
||||
if (index != 0) {
|
||||
c.shr(scratch1, index);
|
||||
|
@ -656,7 +646,7 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
|
|||
|
||||
// Writeback to xmm register, extrq instruction says top 64-bits are undefined so we don't
|
||||
// care to preserve them
|
||||
MAYBE_AVX(movq, xmm_dst, scratch1);
|
||||
c.vmovq(xmm_dst, scratch1);
|
||||
|
||||
c.pop(scratch2);
|
||||
c.pop(scratch1);
|
||||
|
@ -690,7 +680,7 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
|
|||
c.push(mask);
|
||||
|
||||
// Construct the mask out of the length that resides in bottom 6 bits of source xmm
|
||||
MAYBE_AVX(movq, scratch1, xmm_src);
|
||||
c.vmovq(scratch1, xmm_src);
|
||||
c.mov(scratch2, scratch1);
|
||||
c.and_(scratch2, 0x3F);
|
||||
c.jz(length_zero);
|
||||
|
@ -711,10 +701,10 @@ static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
|
|||
c.and_(scratch1, 0x3F);
|
||||
c.mov(scratch2, scratch1); // cl now contains the shift amount
|
||||
|
||||
MAYBE_AVX(movq, scratch1, xmm_dst);
|
||||
c.vmovq(scratch1, xmm_dst);
|
||||
c.shr(scratch1, cl);
|
||||
c.and_(scratch1, mask);
|
||||
MAYBE_AVX(movq, xmm_dst, scratch1);
|
||||
c.vmovq(xmm_dst, scratch1);
|
||||
|
||||
c.pop(mask);
|
||||
c.pop(scratch2);
|
||||
|
@ -765,8 +755,8 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||
|
||||
ASSERT_MSG(length + index <= 64, "length + index must be less than or equal to 64.");
|
||||
|
||||
MAYBE_AVX(movq, scratch1, xmm_src);
|
||||
MAYBE_AVX(movq, scratch2, xmm_dst);
|
||||
c.vmovq(scratch1, xmm_src);
|
||||
c.vmovq(scratch2, xmm_dst);
|
||||
c.mov(mask, mask_value);
|
||||
|
||||
// src &= mask
|
||||
|
@ -784,12 +774,7 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||
c.or_(scratch2, scratch1);
|
||||
|
||||
// Insert scratch2 into low 64 bits of dst, upper 64 bits are unaffected
|
||||
Cpu cpu;
|
||||
if (cpu.has(Cpu::tAVX)) {
|
||||
c.vpinsrq(xmm_dst, xmm_dst, scratch2, 0);
|
||||
} else {
|
||||
c.pinsrq(xmm_dst, scratch2, 0);
|
||||
}
|
||||
c.vpinsrq(xmm_dst, xmm_dst, scratch2, 0);
|
||||
|
||||
c.pop(mask);
|
||||
c.pop(scratch2);
|
||||
|
@ -816,7 +801,7 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||
c.push(mask);
|
||||
|
||||
// Get upper 64 bits of src and copy it to mask and index
|
||||
MAYBE_AVX(pextrq, index, xmm_src, 1);
|
||||
c.vpextrq(index, xmm_src, 1);
|
||||
c.mov(mask, index);
|
||||
|
||||
// When length is 0, set it to 64
|
||||
|
@ -839,7 +824,7 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||
c.and_(index, 0x3F);
|
||||
|
||||
// src &= mask
|
||||
MAYBE_AVX(movq, scratch1, xmm_src);
|
||||
c.vmovq(scratch1, xmm_src);
|
||||
c.and_(scratch1, mask);
|
||||
|
||||
// mask = ~(mask << index)
|
||||
|
@ -851,12 +836,12 @@ static void GenerateINSERTQ(const ZydisDecodedOperand* operands, Xbyak::CodeGene
|
|||
c.shl(scratch1, cl);
|
||||
|
||||
// dst = (dst & mask) | src
|
||||
MAYBE_AVX(movq, scratch2, xmm_dst);
|
||||
c.vmovq(scratch2, xmm_dst);
|
||||
c.and_(scratch2, mask);
|
||||
c.or_(scratch2, scratch1);
|
||||
|
||||
// Upper 64 bits are undefined in insertq
|
||||
MAYBE_AVX(movq, xmm_dst, scratch2);
|
||||
c.vmovq(xmm_dst, scratch2);
|
||||
|
||||
c.pop(mask);
|
||||
c.pop(index);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "core/file_sys/fs.h"
|
||||
#include "core/libraries/app_content/app_content_error.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/system/systemservice.h"
|
||||
|
||||
namespace Libraries::AppContent {
|
||||
|
||||
|
@ -262,6 +263,15 @@ int PS4_SYSV_ABI sceAppContentInitialize(const OrbisAppContentInitParam* initPar
|
|||
entitlement_label.copy(info.entitlement_label, sizeof(info.entitlement_label));
|
||||
}
|
||||
}
|
||||
|
||||
if (addcont_count > 0) {
|
||||
SystemService::OrbisSystemServiceEvent event{};
|
||||
event.event_type = SystemService::OrbisSystemServiceEventType::EntitlementUpdate;
|
||||
event.service_entitlement_update.user_id = 0;
|
||||
event.service_entitlement_update.np_service_label = 0;
|
||||
SystemService::PushSystemServiceEvent(event);
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -89,6 +89,9 @@ int PS4_SYSV_ABI sceAudioOutChangeAppModuleState() {
|
|||
|
||||
int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
|
||||
LOG_INFO(Lib_AudioOut, "handle = {}", handle);
|
||||
if (audio == nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
@ -171,6 +174,9 @@ int PS4_SYSV_ABI sceAudioOutGetLastOutputTime() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state) {
|
||||
if (audio == nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
@ -305,6 +311,10 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
|||
user_id, magic_enum::enum_name(port_type), index, length, sample_rate,
|
||||
magic_enum::enum_name(param_type.data_format.Value()),
|
||||
magic_enum::enum_name(param_type.attributes.Value()));
|
||||
if (audio == nullptr) {
|
||||
LOG_ERROR(Lib_AudioOut, "Audio out not initialized");
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if ((port_type < OrbisAudioOutPort::Main || port_type > OrbisAudioOutPort::Padspk) &&
|
||||
(port_type != OrbisAudioOutPort::Aux)) {
|
||||
LOG_ERROR(Lib_AudioOut, "Invalid port type");
|
||||
|
@ -368,6 +378,9 @@ int PS4_SYSV_ABI sceAudioOutOpenEx() {
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
|
||||
if (audio == nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
@ -489,6 +502,9 @@ int PS4_SYSV_ABI sceAudioOutSetUsbVolume() {
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
|
||||
if (audio == nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
|
|
@ -37,8 +37,9 @@ extern "C" void PS4_SYSV_ABI _sceFiberForceQuit(u64 ret) {
|
|||
|
||||
void PS4_SYSV_ABI _sceFiberCheckStackOverflow(OrbisFiberContext* ctx) {
|
||||
u64* stack_base = reinterpret_cast<u64*>(ctx->current_fiber->addr_context);
|
||||
u64 stack_size = ctx->current_fiber->size_context;
|
||||
if (stack_base && *stack_base != kFiberStackSignature) {
|
||||
UNREACHABLE_MSG("Stack overflow detected in fiber.");
|
||||
UNREACHABLE_MSG("Stack overflow detected in fiber with size = 0x{:x}", stack_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1366,7 +1366,7 @@ s32 PS4_SYSV_ABI sceGnmSetEmbeddedPsShader(u32* cmdbuf, u32 size, u32 shader_id,
|
|||
// pointer to a stack memory, so the check will likely fail. To workaround it we will
|
||||
// repeat set shader functionality here as it is trivial.
|
||||
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 8u, ps_regs[0],
|
||||
0u); // SPI_SHADER_PGM_LO_PS/SPI_SHADER_PGM_HI_PS
|
||||
ps_regs[1]); // SPI_SHADER_PGM_LO_PS/SPI_SHADER_PGM_HI_PS
|
||||
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 10u, ps_regs[2],
|
||||
ps_regs[3]); // SPI_SHADER_PGM_RSRC1_PS/SPI_SHADER_PGM_RSRC2_PS
|
||||
cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x1c4u, ps_regs[4],
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "core/libraries/network/ssl2.h"
|
||||
#include "core/libraries/np_common/np_common.h"
|
||||
#include "core/libraries/np_manager/np_manager.h"
|
||||
#include "core/libraries/np_party/np_party.h"
|
||||
#include "core/libraries/np_score/np_score.h"
|
||||
#include "core/libraries/np_trophy/np_trophy.h"
|
||||
#include "core/libraries/np_web_api/np_web_api.h"
|
||||
|
@ -52,6 +53,8 @@
|
|||
#include "core/libraries/videodec/videodec.h"
|
||||
#include "core/libraries/videodec/videodec2.h"
|
||||
#include "core/libraries/videoout/video_out.h"
|
||||
#include "core/libraries/web_browser_dialog/webbrowserdialog.h"
|
||||
#include "core/libraries/zlib/zlib_sce.h"
|
||||
#include "fiber/fiber.h"
|
||||
#include "jpeg/jpegenc.h"
|
||||
|
||||
|
@ -107,6 +110,9 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
|||
Libraries::Fiber::RegisterlibSceFiber(sym);
|
||||
Libraries::JpegEnc::RegisterlibSceJpegEnc(sym);
|
||||
Libraries::Mouse::RegisterlibSceMouse(sym);
|
||||
Libraries::WebBrowserDialog::RegisterlibSceWebBrowserDialog(sym);
|
||||
Libraries::NpParty::RegisterlibSceNpParty(sym);
|
||||
Libraries::Zlib::RegisterlibSceZlib(sym);
|
||||
}
|
||||
|
||||
} // namespace Libraries
|
||||
|
|
195
src/core/libraries/np_party/np_party.cpp
Normal file
195
src/core/libraries/np_party/np_party.cpp
Normal file
|
@ -0,0 +1,195 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/np_party/np_party.h"
|
||||
|
||||
namespace Libraries::NpParty {
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyCheckCallback() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyCreate() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyCreateA() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetId() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfo() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfoA() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMembers() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMembersA() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMemberSessionInfo() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMemberVoiceInfo() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetState() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUser() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUserA() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetVoiceChatPriority() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyInitialize() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyJoin() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyLeave() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyRegisterHandler() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyRegisterHandlerA() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyRegisterPrivateHandler() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartySendBinaryMessage() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartySetVoiceChatPriority() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyShowInvitationList() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyShowInvitationListA() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyTerminate() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyUnregisterPrivateHandler() {
|
||||
LOG_ERROR(Lib_NpParty, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceNpParty(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("3e4k2mzLkmc", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyCheckCallback);
|
||||
LIB_FUNCTION("nOZRy-slBoA", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyCreate);
|
||||
LIB_FUNCTION("XQSUbbnpPBA", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyCreateA);
|
||||
LIB_FUNCTION("DRA3ay-1DFQ", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetId);
|
||||
LIB_FUNCTION("F1P+-wpxQow", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetMemberInfo);
|
||||
LIB_FUNCTION("v2RYVGrJDkM", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyGetMemberInfoA);
|
||||
LIB_FUNCTION("T2UOKf00ZN0", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetMembers);
|
||||
LIB_FUNCTION("TaNw7W25QJw", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetMembersA);
|
||||
LIB_FUNCTION("4gOMfNYzllw", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyGetMemberSessionInfo);
|
||||
LIB_FUNCTION("EKi1jx59SP4", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyGetMemberVoiceInfo);
|
||||
LIB_FUNCTION("aEzKdJzATZ0", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyGetState);
|
||||
LIB_FUNCTION("o7grRhiGHYI", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyGetStateAsUser);
|
||||
LIB_FUNCTION("EjyAI+QNgFw", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyGetStateAsUserA);
|
||||
LIB_FUNCTION("-lc6XZnQXvM", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyGetVoiceChatPriority);
|
||||
LIB_FUNCTION("lhYCTQmBkds", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyInitialize);
|
||||
LIB_FUNCTION("RXNCDw2GDEg", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyJoin);
|
||||
LIB_FUNCTION("J8jAi-tfJHc", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyLeave);
|
||||
LIB_FUNCTION("kA88gbv71ao", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyRegisterHandler);
|
||||
LIB_FUNCTION("+v4fVHMwFWc", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyRegisterHandlerA);
|
||||
LIB_FUNCTION("zo4G5WWYpKg", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyRegisterPrivateHandler);
|
||||
LIB_FUNCTION("U6VdUe-PNAY", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartySendBinaryMessage);
|
||||
LIB_FUNCTION("nazKyHygHhY", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartySetVoiceChatPriority);
|
||||
LIB_FUNCTION("-MFiL7hEnPE", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyShowInvitationList);
|
||||
LIB_FUNCTION("yARHEYLajs0", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyShowInvitationListA);
|
||||
LIB_FUNCTION("oLYkibiHqRA", "libSceNpParty", 1, "libSceNpParty", 1, 1, sceNpPartyTerminate);
|
||||
LIB_FUNCTION("zQ7gIvt11Pc", "libSceNpParty", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyUnregisterPrivateHandler);
|
||||
LIB_FUNCTION("nOZRy-slBoA", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1, sceNpPartyCreate);
|
||||
LIB_FUNCTION("F1P+-wpxQow", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyGetMemberInfo);
|
||||
LIB_FUNCTION("T2UOKf00ZN0", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyGetMembers);
|
||||
LIB_FUNCTION("o7grRhiGHYI", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyGetStateAsUser);
|
||||
LIB_FUNCTION("kA88gbv71ao", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyRegisterHandler);
|
||||
LIB_FUNCTION("-MFiL7hEnPE", "libSceNpPartyCompat", 1, "libSceNpParty", 1, 1,
|
||||
sceNpPartyShowInvitationList);
|
||||
};
|
||||
|
||||
} // namespace Libraries::NpParty
|
44
src/core/libraries/np_party/np_party.h
Normal file
44
src/core/libraries/np_party/np_party.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::NpParty {
|
||||
|
||||
s32 PS4_SYSV_ABI sceNpPartyCheckCallback();
|
||||
s32 PS4_SYSV_ABI sceNpPartyCreate();
|
||||
s32 PS4_SYSV_ABI sceNpPartyCreateA();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetId();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfo();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMemberInfoA();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMembers();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMembersA();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMemberSessionInfo();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetMemberVoiceInfo();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetState();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUser();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetStateAsUserA();
|
||||
s32 PS4_SYSV_ABI sceNpPartyGetVoiceChatPriority();
|
||||
s32 PS4_SYSV_ABI sceNpPartyInitialize();
|
||||
s32 PS4_SYSV_ABI sceNpPartyJoin();
|
||||
s32 PS4_SYSV_ABI sceNpPartyLeave();
|
||||
s32 PS4_SYSV_ABI sceNpPartyRegisterHandler();
|
||||
s32 PS4_SYSV_ABI sceNpPartyRegisterHandlerA();
|
||||
s32 PS4_SYSV_ABI sceNpPartyRegisterPrivateHandler();
|
||||
s32 PS4_SYSV_ABI sceNpPartySendBinaryMessage();
|
||||
s32 PS4_SYSV_ABI sceNpPartySetVoiceChatPriority();
|
||||
s32 PS4_SYSV_ABI sceNpPartyShowInvitationList();
|
||||
s32 PS4_SYSV_ABI sceNpPartyShowInvitationListA();
|
||||
s32 PS4_SYSV_ABI sceNpPartyTerminate();
|
||||
s32 PS4_SYSV_ABI sceNpPartyUnregisterPrivateHandler();
|
||||
s32 PS4_SYSV_ABI module_start();
|
||||
s32 PS4_SYSV_ABI module_stop();
|
||||
|
||||
void RegisterlibSceNpParty(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::NpParty
|
|
@ -95,8 +95,8 @@ int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerIn
|
|||
pInfo->touchPadInfo.pixelDensity = 1;
|
||||
pInfo->touchPadInfo.resolution.x = 1920;
|
||||
pInfo->touchPadInfo.resolution.y = 950;
|
||||
pInfo->stickInfo.deadZoneLeft = Config::leftDeadZone();
|
||||
pInfo->stickInfo.deadZoneRight = Config::rightDeadZone();
|
||||
pInfo->stickInfo.deadZoneLeft = 1;
|
||||
pInfo->stickInfo.deadZoneRight = 1;
|
||||
pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD;
|
||||
pInfo->connectedCount = 1;
|
||||
pInfo->connected = false;
|
||||
|
@ -106,8 +106,8 @@ int PS4_SYSV_ABI scePadGetControllerInformation(s32 handle, OrbisPadControllerIn
|
|||
pInfo->touchPadInfo.pixelDensity = 1;
|
||||
pInfo->touchPadInfo.resolution.x = 1920;
|
||||
pInfo->touchPadInfo.resolution.y = 950;
|
||||
pInfo->stickInfo.deadZoneLeft = Config::leftDeadZone();
|
||||
pInfo->stickInfo.deadZoneRight = Config::rightDeadZone();
|
||||
pInfo->stickInfo.deadZoneLeft = 1;
|
||||
pInfo->stickInfo.deadZoneRight = 1;
|
||||
pInfo->connectionType = ORBIS_PAD_PORT_TYPE_STANDARD;
|
||||
pInfo->connectedCount = 1;
|
||||
pInfo->connected = true;
|
||||
|
@ -473,8 +473,8 @@ int PS4_SYSV_ABI scePadSetForceIntercepted() {
|
|||
|
||||
int PS4_SYSV_ABI scePadSetLightBar(s32 handle, const OrbisPadLightBarParam* pParam) {
|
||||
if (pParam != nullptr) {
|
||||
LOG_INFO(Lib_Pad, "scePadSetLightBar called handle = {} rgb = {} {} {}", handle, pParam->r,
|
||||
pParam->g, pParam->b);
|
||||
LOG_DEBUG(Lib_Pad, "called handle = {} rgb = {} {} {}", handle, pParam->r, pParam->g,
|
||||
pParam->b);
|
||||
|
||||
if (pParam->r < 0xD && pParam->g < 0xD && pParam->b < 0xD) {
|
||||
LOG_INFO(Lib_Pad, "Invalid lightbar setting");
|
||||
|
|
|
@ -121,15 +121,17 @@ static void BackupThreadBody() {
|
|||
std::scoped_lock lk{g_backup_queue_mutex};
|
||||
g_backup_queue.front().done = true;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5)); // Don't backup too often
|
||||
{
|
||||
std::scoped_lock lk{g_backup_queue_mutex};
|
||||
g_backup_queue.pop_front();
|
||||
g_result_queue.push_back(std::move(req));
|
||||
if (g_result_queue.size() > 20) {
|
||||
g_result_queue.pop_front();
|
||||
if (req.origin != OrbisSaveDataEventType::__DO_NOT_SAVE) {
|
||||
g_result_queue.push_back(std::move(req));
|
||||
if (g_result_queue.size() > 20) {
|
||||
g_result_queue.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5)); // Don't backup too often
|
||||
}
|
||||
g_backup_status = WorkerStatus::NotStarted;
|
||||
}
|
||||
|
@ -141,6 +143,15 @@ void StartThread() {
|
|||
LOG_DEBUG(Lib_SaveData, "Starting backup thread");
|
||||
g_backup_status = WorkerStatus::Waiting;
|
||||
g_backup_thread = std::jthread{BackupThreadBody};
|
||||
static std::once_flag flag;
|
||||
std::call_once(flag, [] {
|
||||
std::at_quick_exit([] {
|
||||
StopThread();
|
||||
while (GetWorkerStatus() != WorkerStatus::NotStarted) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void StopThread() {
|
||||
|
@ -148,12 +159,12 @@ void StopThread() {
|
|||
return;
|
||||
}
|
||||
LOG_DEBUG(Lib_SaveData, "Stopping backup thread");
|
||||
g_backup_status = WorkerStatus::Stopping;
|
||||
{
|
||||
std::scoped_lock lk{g_backup_queue_mutex};
|
||||
g_backup_queue.emplace_back(BackupRequest{});
|
||||
}
|
||||
g_backup_thread_semaphore.release();
|
||||
g_backup_status = WorkerStatus::Stopping;
|
||||
}
|
||||
|
||||
bool NewRequest(OrbisUserServiceUserId user_id, std::string_view title_id,
|
||||
|
|
|
@ -25,6 +25,8 @@ enum class OrbisSaveDataEventType : u32 {
|
|||
UMOUNT_BACKUP = 1,
|
||||
BACKUP = 2,
|
||||
SAVE_DATA_MEMORY_SYNC = 3,
|
||||
|
||||
__DO_NOT_SAVE = 1000000, // This value is only for the backup thread
|
||||
};
|
||||
|
||||
struct BackupRequest {
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "common/path_util.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
#include "save_backup.h"
|
||||
#include "save_instance.h"
|
||||
|
||||
constexpr auto OrbisSaveDataBlocksMin2 = 96; // 3MiB
|
||||
|
@ -45,14 +46,13 @@ static const std::unordered_map<std::string, std::string> default_title = {
|
|||
|
||||
namespace Libraries::SaveData {
|
||||
|
||||
std::filesystem::path SaveInstance::MakeTitleSavePath(OrbisUserServiceUserId user_id,
|
||||
std::string_view game_serial) {
|
||||
fs::path SaveInstance::MakeTitleSavePath(OrbisUserServiceUserId user_id,
|
||||
std::string_view game_serial) {
|
||||
return Config::GetSaveDataPath() / std::to_string(user_id) / game_serial;
|
||||
}
|
||||
|
||||
std::filesystem::path SaveInstance::MakeDirSavePath(OrbisUserServiceUserId user_id,
|
||||
std::string_view game_serial,
|
||||
std::string_view dir_name) {
|
||||
fs::path SaveInstance::MakeDirSavePath(OrbisUserServiceUserId user_id, std::string_view game_serial,
|
||||
std::string_view dir_name) {
|
||||
return Config::GetSaveDataPath() / std::to_string(user_id) / game_serial / dir_name;
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ uint64_t SaveInstance::GetMaxBlockFromSFO(const PSF& psf) {
|
|||
return *(uint64_t*)value.data();
|
||||
}
|
||||
|
||||
std::filesystem::path SaveInstance::GetParamSFOPath(const std::filesystem::path& dir_path) {
|
||||
fs::path SaveInstance::GetParamSFOPath(const fs::path& dir_path) {
|
||||
return dir_path / sce_sys / "param.sfo";
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,6 @@ SaveInstance& SaveInstance::operator=(SaveInstance&& other) noexcept {
|
|||
save_path = std::move(other.save_path);
|
||||
param_sfo_path = std::move(other.param_sfo_path);
|
||||
corrupt_file_path = std::move(other.corrupt_file_path);
|
||||
corrupt_file = std::move(other.corrupt_file);
|
||||
param_sfo = std::move(other.param_sfo);
|
||||
mount_point = std::move(other.mount_point);
|
||||
max_blocks = other.max_blocks;
|
||||
|
@ -142,7 +141,8 @@ SaveInstance& SaveInstance::operator=(SaveInstance&& other) noexcept {
|
|||
return *this;
|
||||
}
|
||||
|
||||
void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_corrupt) {
|
||||
void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_corrupt,
|
||||
bool dont_restore_backup) {
|
||||
if (mounted) {
|
||||
UNREACHABLE_MSG("Save instance is already mounted");
|
||||
}
|
||||
|
@ -161,25 +161,27 @@ void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_cor
|
|||
}
|
||||
exists = true;
|
||||
} else {
|
||||
std::optional<fs::filesystem_error> err;
|
||||
if (!ignore_corrupt && fs::exists(corrupt_file_path)) {
|
||||
throw std::filesystem::filesystem_error(
|
||||
"Corrupted save data", corrupt_file_path,
|
||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
||||
err = fs::filesystem_error("Corrupted save data", corrupt_file_path,
|
||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
||||
} else if (!param_sfo.Open(param_sfo_path)) {
|
||||
err = fs::filesystem_error("Failed to read param.sfo", param_sfo_path,
|
||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
||||
}
|
||||
if (!param_sfo.Open(param_sfo_path)) {
|
||||
throw std::filesystem::filesystem_error(
|
||||
"Failed to read param.sfo", param_sfo_path,
|
||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
||||
if (err.has_value()) {
|
||||
if (dont_restore_backup) {
|
||||
throw err.value();
|
||||
}
|
||||
if (Backup::Restore(save_path)) {
|
||||
return SetupAndMount(read_only, copy_icon, ignore_corrupt, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignore_corrupt && !read_only) {
|
||||
int err = corrupt_file.Open(corrupt_file_path, Common::FS::FileAccessMode::Write);
|
||||
if (err != 0) {
|
||||
throw std::filesystem::filesystem_error(
|
||||
"Failed to open corrupted file", corrupt_file_path,
|
||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
||||
}
|
||||
Common::FS::IOFile f(corrupt_file_path, Common::FS::FileAccessMode::Write);
|
||||
f.Close();
|
||||
}
|
||||
|
||||
max_blocks = static_cast<int>(GetMaxBlockFromSFO(param_sfo));
|
||||
|
@ -197,12 +199,11 @@ void SaveInstance::Umount() {
|
|||
mounted = false;
|
||||
const bool ok = param_sfo.Encode(param_sfo_path);
|
||||
if (!ok) {
|
||||
throw std::filesystem::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
||||
std::make_error_code(std::errc::permission_denied));
|
||||
throw fs::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
||||
std::make_error_code(std::errc::permission_denied));
|
||||
}
|
||||
param_sfo = PSF();
|
||||
|
||||
corrupt_file.Close();
|
||||
fs::remove(corrupt_file_path);
|
||||
g_mnt->Unmount(save_path, mount_point);
|
||||
}
|
||||
|
@ -216,8 +217,8 @@ void SaveInstance::CreateFiles() {
|
|||
|
||||
const bool ok = param_sfo.Encode(param_sfo_path);
|
||||
if (!ok) {
|
||||
throw std::filesystem::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
||||
std::make_error_code(std::errc::permission_denied));
|
||||
throw fs::filesystem_error("Failed to write param.sfo", param_sfo_path,
|
||||
std::make_error_code(std::errc::permission_denied));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,6 @@ class SaveInstance {
|
|||
std::filesystem::path param_sfo_path;
|
||||
std::filesystem::path corrupt_file_path;
|
||||
|
||||
Common::FS::IOFile corrupt_file;
|
||||
|
||||
PSF param_sfo;
|
||||
std::string mount_point;
|
||||
|
||||
|
@ -80,7 +78,8 @@ public:
|
|||
SaveInstance& operator=(const SaveInstance& other) = delete;
|
||||
SaveInstance& operator=(SaveInstance&& other) noexcept;
|
||||
|
||||
void SetupAndMount(bool read_only = false, bool copy_icon = false, bool ignore_corrupt = false);
|
||||
void SetupAndMount(bool read_only = false, bool copy_icon = false, bool ignore_corrupt = false,
|
||||
bool dont_restore_backup = false);
|
||||
|
||||
void Umount();
|
||||
|
||||
|
|
|
@ -6,14 +6,16 @@
|
|||
#include <condition_variable>
|
||||
#include <filesystem>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <core/libraries/system/msgdialog_ui.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/elf_info.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/path_util.h"
|
||||
#include "common/singleton.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/file_sys/fs.h"
|
||||
|
@ -23,265 +25,202 @@ using Common::FS::IOFile;
|
|||
namespace fs = std::filesystem;
|
||||
|
||||
constexpr std::string_view sce_sys = "sce_sys"; // system folder inside save
|
||||
constexpr std::string_view DirnameSaveDataMemory = "sce_sdmemory";
|
||||
constexpr std::string_view StandardDirnameSaveDataMemory = "sce_sdmemory";
|
||||
constexpr std::string_view FilenameSaveDataMemory = "memory.dat";
|
||||
constexpr std::string_view IconName = "icon0.png";
|
||||
constexpr std::string_view CorruptFileName = "corrupted";
|
||||
|
||||
namespace Libraries::SaveData::SaveMemory {
|
||||
|
||||
static Core::FileSys::MntPoints* g_mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
|
||||
static OrbisUserServiceUserId g_user_id{};
|
||||
static std::string g_game_serial{};
|
||||
static std::filesystem::path g_save_path{};
|
||||
static std::filesystem::path g_param_sfo_path{};
|
||||
static PSF g_param_sfo;
|
||||
struct SlotData {
|
||||
OrbisUserServiceUserId user_id;
|
||||
std::string game_serial;
|
||||
std::filesystem::path folder_path;
|
||||
PSF sfo;
|
||||
std::vector<u8> memory_cache;
|
||||
};
|
||||
|
||||
static bool g_save_memory_initialized = false;
|
||||
static std::mutex g_saving_memory_mutex;
|
||||
static std::vector<u8> g_save_memory;
|
||||
static std::mutex g_slot_mtx;
|
||||
static std::unordered_map<u32, SlotData> g_attached_slots;
|
||||
|
||||
static std::filesystem::path g_icon_path;
|
||||
static std::vector<u8> g_icon_memory;
|
||||
void PersistMemory(u32 slot_id, bool lock) {
|
||||
std::unique_lock lck{g_slot_mtx, std::defer_lock};
|
||||
if (lock) {
|
||||
lck.lock();
|
||||
}
|
||||
auto& data = g_attached_slots[slot_id];
|
||||
auto memoryPath = data.folder_path / FilenameSaveDataMemory;
|
||||
fs::create_directories(memoryPath.parent_path());
|
||||
|
||||
static std::condition_variable g_trigger_save_memory;
|
||||
static std::atomic_bool g_saving_memory = false;
|
||||
static std::atomic_bool g_save_event = false;
|
||||
static std::jthread g_save_memory_thread;
|
||||
|
||||
static std::atomic_bool g_memory_dirty = false;
|
||||
static std::atomic_bool g_param_dirty = false;
|
||||
static std::atomic_bool g_icon_dirty = false;
|
||||
|
||||
static void SaveFileSafe(void* buf, size_t count, const std::filesystem::path& path) {
|
||||
const auto& dir = path.parent_path();
|
||||
const auto& name = path.filename();
|
||||
const auto tmp_path = dir / (name.string() + ".tmp");
|
||||
|
||||
IOFile file(tmp_path, Common::FS::FileAccessMode::Write);
|
||||
file.WriteRaw<u8>(buf, count);
|
||||
file.Close();
|
||||
|
||||
fs::remove(path);
|
||||
fs::rename(tmp_path, path);
|
||||
}
|
||||
|
||||
[[noreturn]] void SaveThreadLoop() {
|
||||
Common::SetCurrentThreadName("shadPS4:SaveData:SaveDataMemoryThread");
|
||||
std::mutex mtx;
|
||||
while (true) {
|
||||
{
|
||||
std::unique_lock lk{mtx};
|
||||
g_trigger_save_memory.wait(lk);
|
||||
}
|
||||
// Save the memory
|
||||
g_saving_memory = true;
|
||||
std::scoped_lock lk{g_saving_memory_mutex};
|
||||
int n = 0;
|
||||
std::string errMsg;
|
||||
while (n++ < 10) {
|
||||
try {
|
||||
LOG_DEBUG(Lib_SaveData, "Saving save data memory {}", fmt::UTF(g_save_path.u8string()));
|
||||
|
||||
if (g_memory_dirty) {
|
||||
g_memory_dirty = false;
|
||||
SaveFileSafe(g_save_memory.data(), g_save_memory.size(),
|
||||
g_save_path / FilenameSaveDataMemory);
|
||||
IOFile f;
|
||||
int r = f.Open(memoryPath, Common::FS::FileAccessMode::Write);
|
||||
if (f.IsOpen()) {
|
||||
f.WriteRaw<u8>(data.memory_cache.data(), data.memory_cache.size());
|
||||
f.Close();
|
||||
return;
|
||||
}
|
||||
if (g_param_dirty) {
|
||||
g_param_dirty = false;
|
||||
static std::vector<u8> buf;
|
||||
g_param_sfo.Encode(buf);
|
||||
SaveFileSafe(buf.data(), buf.size(), g_param_sfo_path);
|
||||
}
|
||||
if (g_icon_dirty) {
|
||||
g_icon_dirty = false;
|
||||
SaveFileSafe(g_icon_memory.data(), g_icon_memory.size(), g_icon_path);
|
||||
}
|
||||
|
||||
if (g_save_event) {
|
||||
Backup::PushBackupEvent(Backup::BackupRequest{
|
||||
.user_id = g_user_id,
|
||||
.title_id = g_game_serial,
|
||||
.dir_name = std::string{DirnameSaveDataMemory},
|
||||
.origin = Backup::OrbisSaveDataEventType::SAVE_DATA_MEMORY_SYNC,
|
||||
.save_path = g_save_path,
|
||||
});
|
||||
g_save_event = false;
|
||||
}
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
LOG_ERROR(Lib_SaveData, "Failed to save save data memory: {}", e.what());
|
||||
MsgDialog::ShowMsgDialog(MsgDialog::MsgDialogState{
|
||||
MsgDialog::MsgDialogState::UserState{
|
||||
.type = MsgDialog::ButtonType::OK,
|
||||
.msg = fmt::format("Failed to save save data memory.\nCode: <{}>\n{}",
|
||||
e.code().message(), e.what()),
|
||||
},
|
||||
});
|
||||
const auto err = std::error_code{r, std::iostream_category()};
|
||||
throw std::filesystem::filesystem_error{err.message(), err};
|
||||
} catch (const std::filesystem::filesystem_error& e) {
|
||||
errMsg = std::string{e.what()};
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
g_saving_memory = false;
|
||||
}
|
||||
const MsgDialog::MsgDialogState dialog{MsgDialog::MsgDialogState::UserState{
|
||||
.type = MsgDialog::ButtonType::OK,
|
||||
.msg = "Failed to persist save memory:\n" + errMsg + "\nat " +
|
||||
Common::FS::PathToUTF8String(memoryPath),
|
||||
}};
|
||||
MsgDialog::ShowMsgDialog(dialog);
|
||||
}
|
||||
|
||||
void SetDirectories(OrbisUserServiceUserId user_id, std::string _game_serial) {
|
||||
g_user_id = user_id;
|
||||
g_game_serial = std::move(_game_serial);
|
||||
g_save_path = SaveInstance::MakeDirSavePath(user_id, g_game_serial, DirnameSaveDataMemory);
|
||||
g_param_sfo_path = SaveInstance::GetParamSFOPath(g_save_path);
|
||||
g_param_sfo = PSF();
|
||||
g_icon_path = g_save_path / sce_sys / "icon0.png";
|
||||
std::string GetSaveDir(u32 slot_id) {
|
||||
std::string dir(StandardDirnameSaveDataMemory);
|
||||
if (slot_id > 0) {
|
||||
dir += std::to_string(slot_id);
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
||||
const std::filesystem::path& GetSavePath() {
|
||||
return g_save_path;
|
||||
std::filesystem::path GetSavePath(OrbisUserServiceUserId user_id, u32 slot_id,
|
||||
std::string_view game_serial) {
|
||||
std::string dir(StandardDirnameSaveDataMemory);
|
||||
if (slot_id > 0) {
|
||||
dir += std::to_string(slot_id);
|
||||
}
|
||||
return SaveInstance::MakeDirSavePath(user_id, Common::ElfInfo::Instance().GameSerial(), dir);
|
||||
}
|
||||
|
||||
size_t CreateSaveMemory(size_t memory_size) {
|
||||
size_t existed_size = 0;
|
||||
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial) {
|
||||
std::lock_guard lck{g_slot_mtx};
|
||||
|
||||
static std::once_flag init_save_thread_flag;
|
||||
std::call_once(init_save_thread_flag,
|
||||
[] { g_save_memory_thread = std::jthread{SaveThreadLoop}; });
|
||||
const auto save_dir = GetSavePath(user_id, slot_id, game_serial);
|
||||
|
||||
g_save_memory.resize(memory_size);
|
||||
SaveInstance::SetupDefaultParamSFO(g_param_sfo, std::string{DirnameSaveDataMemory},
|
||||
g_game_serial);
|
||||
auto& data = g_attached_slots[slot_id];
|
||||
data = SlotData{
|
||||
.user_id = user_id,
|
||||
.game_serial = std::string{game_serial},
|
||||
.folder_path = save_dir,
|
||||
.sfo = {},
|
||||
.memory_cache = {},
|
||||
};
|
||||
|
||||
g_save_memory_initialized = true;
|
||||
SaveInstance::SetupDefaultParamSFO(data.sfo, GetSaveDir(slot_id), std::string{game_serial});
|
||||
|
||||
if (!fs::exists(g_param_sfo_path)) {
|
||||
// Create save memory
|
||||
fs::create_directories(g_save_path / sce_sys);
|
||||
|
||||
IOFile memory_file{g_save_path / FilenameSaveDataMemory, Common::FS::FileAccessMode::Write};
|
||||
bool ok = memory_file.SetSize(memory_size);
|
||||
if (!ok) {
|
||||
LOG_ERROR(Lib_SaveData, "Failed to set memory size");
|
||||
throw std::filesystem::filesystem_error(
|
||||
"Failed to set save memory size", g_save_path / FilenameSaveDataMemory,
|
||||
std::make_error_code(std::errc::no_space_on_device));
|
||||
}
|
||||
memory_file.Close();
|
||||
} else {
|
||||
// Load save memory
|
||||
|
||||
bool ok = g_param_sfo.Open(g_param_sfo_path);
|
||||
if (!ok) {
|
||||
LOG_ERROR(Lib_SaveData, "Failed to open SFO at {}",
|
||||
fmt::UTF(g_param_sfo_path.u8string()));
|
||||
throw std::filesystem::filesystem_error(
|
||||
"failed to open SFO", g_param_sfo_path,
|
||||
std::make_error_code(std::errc::illegal_byte_sequence));
|
||||
}
|
||||
|
||||
IOFile memory_file{g_save_path / FilenameSaveDataMemory, Common::FS::FileAccessMode::Read};
|
||||
if (!memory_file.IsOpen()) {
|
||||
LOG_ERROR(Lib_SaveData, "Failed to open save memory");
|
||||
throw std::filesystem::filesystem_error(
|
||||
"failed to open save memory", g_save_path / FilenameSaveDataMemory,
|
||||
std::make_error_code(std::errc::permission_denied));
|
||||
}
|
||||
size_t save_size = memory_file.GetSize();
|
||||
existed_size = save_size;
|
||||
memory_file.Seek(0);
|
||||
memory_file.ReadRaw<u8>(g_save_memory.data(), std::min(save_size, memory_size));
|
||||
memory_file.Close();
|
||||
auto param_sfo_path = SaveInstance::GetParamSFOPath(save_dir);
|
||||
if (!fs::exists(param_sfo_path)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return existed_size;
|
||||
if (!data.sfo.Open(param_sfo_path) || fs::exists(save_dir / CorruptFileName)) {
|
||||
if (!Backup::Restore(save_dir)) { // Could not restore the backup
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const auto memory = save_dir / FilenameSaveDataMemory;
|
||||
if (fs::exists(memory)) {
|
||||
return fs::file_size(memory);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetIcon(void* buf, size_t buf_size) {
|
||||
void SetIcon(u32 slot_id, void* buf, size_t buf_size) {
|
||||
std::lock_guard lck{g_slot_mtx};
|
||||
const auto& data = g_attached_slots[slot_id];
|
||||
const auto icon_path = data.folder_path / sce_sys / "icon0.png";
|
||||
if (buf == nullptr) {
|
||||
const auto& src_icon = g_mnt->GetHostPath("/app0/sce_sys/save_data.png");
|
||||
if (fs::exists(src_icon)) {
|
||||
if (fs::exists(g_icon_path)) {
|
||||
fs::remove(g_icon_path);
|
||||
}
|
||||
fs::copy_file(src_icon, g_icon_path);
|
||||
if (fs::exists(icon_path)) {
|
||||
fs::remove(icon_path);
|
||||
}
|
||||
if (fs::exists(g_icon_path)) {
|
||||
IOFile file(g_icon_path, Common::FS::FileAccessMode::Read);
|
||||
size_t size = file.GetSize();
|
||||
file.Seek(0);
|
||||
g_icon_memory.resize(size);
|
||||
file.ReadRaw<u8>(g_icon_memory.data(), size);
|
||||
file.Close();
|
||||
if (fs::exists(src_icon)) {
|
||||
fs::create_directories(icon_path.parent_path());
|
||||
fs::copy_file(src_icon, icon_path);
|
||||
}
|
||||
} else {
|
||||
g_icon_memory.resize(buf_size);
|
||||
std::memcpy(g_icon_memory.data(), buf, buf_size);
|
||||
IOFile file(g_icon_path, Common::FS::FileAccessMode::Write);
|
||||
file.Seek(0);
|
||||
file.WriteRaw<u8>(g_icon_memory.data(), buf_size);
|
||||
IOFile file(icon_path, Common::FS::FileAccessMode::Write);
|
||||
file.WriteRaw<u8>(buf, buf_size);
|
||||
file.Close();
|
||||
}
|
||||
}
|
||||
|
||||
void WriteIcon(void* buf, size_t buf_size) {
|
||||
if (buf_size != g_icon_memory.size()) {
|
||||
g_icon_memory.resize(buf_size);
|
||||
bool IsSaveMemoryInitialized(u32 slot_id) {
|
||||
std::lock_guard lck{g_slot_mtx};
|
||||
return g_attached_slots.contains(slot_id);
|
||||
}
|
||||
|
||||
PSF& GetParamSFO(u32 slot_id) {
|
||||
std::lock_guard lck{g_slot_mtx};
|
||||
auto& data = g_attached_slots[slot_id];
|
||||
return data.sfo;
|
||||
}
|
||||
|
||||
std::vector<u8> GetIcon(u32 slot_id) {
|
||||
std::lock_guard lck{g_slot_mtx};
|
||||
auto& data = g_attached_slots[slot_id];
|
||||
const auto icon_path = data.folder_path / sce_sys / "icon0.png";
|
||||
IOFile f{icon_path, Common::FS::FileAccessMode::Read};
|
||||
if (!f.IsOpen()) {
|
||||
return {};
|
||||
}
|
||||
std::memcpy(g_icon_memory.data(), buf, buf_size);
|
||||
g_icon_dirty = true;
|
||||
const u64 size = f.GetSize();
|
||||
std::vector<u8> ret;
|
||||
ret.resize(size);
|
||||
f.ReadSpan(std::span{ret});
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool IsSaveMemoryInitialized() {
|
||||
return g_save_memory_initialized;
|
||||
}
|
||||
|
||||
PSF& GetParamSFO() {
|
||||
return g_param_sfo;
|
||||
}
|
||||
|
||||
std::span<u8> GetIcon() {
|
||||
return {g_icon_memory};
|
||||
}
|
||||
|
||||
void SaveSFO(bool sync) {
|
||||
if (!sync) {
|
||||
g_param_dirty = true;
|
||||
return;
|
||||
}
|
||||
const bool ok = g_param_sfo.Encode(g_param_sfo_path);
|
||||
void SaveSFO(u32 slot_id) {
|
||||
std::lock_guard lck{g_slot_mtx};
|
||||
const auto& data = g_attached_slots[slot_id];
|
||||
const auto sfo_path = SaveInstance::GetParamSFOPath(data.folder_path);
|
||||
fs::create_directories(sfo_path.parent_path());
|
||||
const bool ok = data.sfo.Encode(sfo_path);
|
||||
if (!ok) {
|
||||
LOG_ERROR(Lib_SaveData, "Failed to encode param.sfo");
|
||||
throw std::filesystem::filesystem_error("Failed to write param.sfo", g_param_sfo_path,
|
||||
throw std::filesystem::filesystem_error("Failed to write param.sfo", sfo_path,
|
||||
std::make_error_code(std::errc::permission_denied));
|
||||
}
|
||||
}
|
||||
bool IsSaving() {
|
||||
return g_saving_memory;
|
||||
|
||||
void ReadMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset) {
|
||||
std::lock_guard lk{g_slot_mtx};
|
||||
auto& data = g_attached_slots[slot_id];
|
||||
auto& memory = data.memory_cache;
|
||||
if (memory.empty()) { // Load file
|
||||
IOFile f{data.folder_path / FilenameSaveDataMemory, Common::FS::FileAccessMode::Read};
|
||||
if (f.IsOpen()) {
|
||||
memory.resize(f.GetSize());
|
||||
f.Seek(0);
|
||||
f.ReadSpan(std::span{memory});
|
||||
}
|
||||
}
|
||||
s64 read_size = buf_size;
|
||||
if (read_size + offset > memory.size()) {
|
||||
read_size = memory.size() - offset;
|
||||
}
|
||||
std::memcpy(buf, memory.data() + offset, read_size);
|
||||
}
|
||||
|
||||
bool TriggerSaveWithoutEvent() {
|
||||
if (g_saving_memory) {
|
||||
return false;
|
||||
void WriteMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset) {
|
||||
std::lock_guard lk{g_slot_mtx};
|
||||
auto& data = g_attached_slots[slot_id];
|
||||
auto& memory = data.memory_cache;
|
||||
if (offset + buf_size > memory.size()) {
|
||||
memory.resize(offset + buf_size);
|
||||
}
|
||||
g_trigger_save_memory.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TriggerSave() {
|
||||
if (g_saving_memory) {
|
||||
return false;
|
||||
}
|
||||
g_save_event = true;
|
||||
g_trigger_save_memory.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReadMemory(void* buf, size_t buf_size, int64_t offset) {
|
||||
std::scoped_lock lk{g_saving_memory_mutex};
|
||||
if (offset + buf_size > g_save_memory.size()) {
|
||||
UNREACHABLE_MSG("ReadMemory out of bounds");
|
||||
}
|
||||
std::memcpy(buf, g_save_memory.data() + offset, buf_size);
|
||||
}
|
||||
|
||||
void WriteMemory(void* buf, size_t buf_size, int64_t offset) {
|
||||
std::scoped_lock lk{g_saving_memory_mutex};
|
||||
if (offset + buf_size > g_save_memory.size()) {
|
||||
g_save_memory.resize(offset + buf_size);
|
||||
}
|
||||
std::memcpy(g_save_memory.data() + offset, buf, buf_size);
|
||||
g_memory_dirty = true;
|
||||
std::memcpy(memory.data() + offset, buf, buf_size);
|
||||
PersistMemory(slot_id, false);
|
||||
Backup::NewRequest(data.user_id, data.game_serial, GetSaveDir(slot_id),
|
||||
Backup::OrbisSaveDataEventType::__DO_NOT_SAVE);
|
||||
}
|
||||
|
||||
} // namespace Libraries::SaveData::SaveMemory
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
#include "save_backup.h"
|
||||
|
||||
class PSF;
|
||||
|
@ -14,36 +14,30 @@ using OrbisUserServiceUserId = s32;
|
|||
|
||||
namespace Libraries::SaveData::SaveMemory {
|
||||
|
||||
void SetDirectories(OrbisUserServiceUserId user_id, std::string game_serial);
|
||||
void PersistMemory(u32 slot_id, bool lock = true);
|
||||
|
||||
[[nodiscard]] const std::filesystem::path& GetSavePath();
|
||||
[[nodiscard]] std::string GetSaveDir(u32 slot_id);
|
||||
|
||||
// returns the size of the existed save memory
|
||||
size_t CreateSaveMemory(size_t memory_size);
|
||||
[[nodiscard]] std::filesystem::path GetSavePath(OrbisUserServiceUserId user_id, u32 slot_id,
|
||||
std::string_view game_serial);
|
||||
|
||||
// Initialize the icon. Set buf to null to read the standard icon.
|
||||
void SetIcon(void* buf, size_t buf_size);
|
||||
// returns the size of the save memory if exists
|
||||
size_t SetupSaveMemory(OrbisUserServiceUserId user_id, u32 slot_id, std::string_view game_serial);
|
||||
|
||||
// Update the icon
|
||||
void WriteIcon(void* buf, size_t buf_size);
|
||||
// Write the icon. Set buf to null to read the standard icon.
|
||||
void SetIcon(u32 slot_id, void* buf = nullptr, size_t buf_size = 0);
|
||||
|
||||
[[nodiscard]] bool IsSaveMemoryInitialized();
|
||||
[[nodiscard]] bool IsSaveMemoryInitialized(u32 slot_id);
|
||||
|
||||
[[nodiscard]] PSF& GetParamSFO();
|
||||
[[nodiscard]] PSF& GetParamSFO(u32 slot_id);
|
||||
|
||||
[[nodiscard]] std::span<u8> GetIcon();
|
||||
[[nodiscard]] std::vector<u8> GetIcon(u32 slot_id);
|
||||
|
||||
// Save now or wait for the background thread to save
|
||||
void SaveSFO(bool sync = false);
|
||||
void SaveSFO(u32 slot_id);
|
||||
|
||||
[[nodiscard]] bool IsSaving();
|
||||
void ReadMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset);
|
||||
|
||||
bool TriggerSaveWithoutEvent();
|
||||
|
||||
bool TriggerSave();
|
||||
|
||||
void ReadMemory(void* buf, size_t buf_size, int64_t offset);
|
||||
|
||||
void WriteMemory(void* buf, size_t buf_size, int64_t offset);
|
||||
void WriteMemory(u32 slot_id, void* buf, size_t buf_size, int64_t offset);
|
||||
|
||||
} // namespace Libraries::SaveData::SaveMemory
|
|
@ -177,7 +177,8 @@ struct OrbisSaveDataMemoryGet2 {
|
|||
OrbisSaveDataMemoryData* data;
|
||||
OrbisSaveDataParam* param;
|
||||
OrbisSaveDataIcon* icon;
|
||||
std::array<u8, 32> _reserved;
|
||||
u32 slotId;
|
||||
std::array<u8, 28> _reserved;
|
||||
};
|
||||
|
||||
struct OrbisSaveDataMemorySet2 {
|
||||
|
@ -186,6 +187,8 @@ struct OrbisSaveDataMemorySet2 {
|
|||
const OrbisSaveDataMemoryData* data;
|
||||
const OrbisSaveDataParam* param;
|
||||
const OrbisSaveDataIcon* icon;
|
||||
u32 dataNum;
|
||||
u32 slotId;
|
||||
std::array<u8, 32> _reserved;
|
||||
};
|
||||
|
||||
|
@ -198,7 +201,8 @@ struct OrbisSaveDataMemorySetup2 {
|
|||
const OrbisSaveDataParam* initParam;
|
||||
// +4.5
|
||||
const OrbisSaveDataIcon* initIcon;
|
||||
std::array<u8, 24> _reserved;
|
||||
u32 slotId;
|
||||
std::array<u8, 20> _reserved;
|
||||
};
|
||||
|
||||
struct OrbisSaveDataMemorySetupResult {
|
||||
|
@ -206,9 +210,16 @@ struct OrbisSaveDataMemorySetupResult {
|
|||
std::array<u8, 16> _reserved;
|
||||
};
|
||||
|
||||
enum OrbisSaveDataMemorySyncOption : u32 {
|
||||
NONE = 0,
|
||||
BLOCKING = 1,
|
||||
};
|
||||
|
||||
struct OrbisSaveDataMemorySync {
|
||||
OrbisUserServiceUserId userId;
|
||||
std::array<u8, 36> _reserved;
|
||||
u32 slotId;
|
||||
OrbisSaveDataMemorySyncOption option;
|
||||
std::array<u8, 28> _reserved;
|
||||
};
|
||||
|
||||
struct OrbisSaveDataMount2 {
|
||||
|
@ -327,6 +338,7 @@ static void initialize() {
|
|||
g_initialized = true;
|
||||
g_game_serial = ElfInfo::Instance().GameSerial();
|
||||
g_fw_ver = ElfInfo::Instance().FirmwareVer();
|
||||
Backup::StartThread();
|
||||
}
|
||||
|
||||
// game_00other | game*other
|
||||
|
@ -558,7 +570,6 @@ Error PS4_SYSV_ABI sceSaveDataBackup(const OrbisSaveDataBackup* backup) {
|
|||
}
|
||||
}
|
||||
|
||||
Backup::StartThread();
|
||||
Backup::NewRequest(backup->userId, title, dir_name, OrbisSaveDataEventType::BACKUP);
|
||||
|
||||
return Error::OK;
|
||||
|
@ -1136,22 +1147,27 @@ Error PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getPar
|
|||
LOG_INFO(Lib_SaveData, "called with invalid parameter");
|
||||
return Error::PARAMETER;
|
||||
}
|
||||
if (!SaveMemory::IsSaveMemoryInitialized()) {
|
||||
|
||||
u32 slot_id = 0;
|
||||
if (g_fw_ver > ElfInfo::FW_50) {
|
||||
slot_id = getParam->slotId;
|
||||
}
|
||||
if (!SaveMemory::IsSaveMemoryInitialized(slot_id)) {
|
||||
LOG_INFO(Lib_SaveData, "called without save memory initialized");
|
||||
return Error::MEMORY_NOT_READY;
|
||||
}
|
||||
LOG_DEBUG(Lib_SaveData, "called");
|
||||
auto data = getParam->data;
|
||||
if (data != nullptr) {
|
||||
SaveMemory::ReadMemory(data->buf, data->bufSize, data->offset);
|
||||
SaveMemory::ReadMemory(slot_id, data->buf, data->bufSize, data->offset);
|
||||
}
|
||||
auto param = getParam->param;
|
||||
if (param != nullptr) {
|
||||
param->FromSFO(SaveMemory::GetParamSFO());
|
||||
param->FromSFO(SaveMemory::GetParamSFO(slot_id));
|
||||
}
|
||||
auto icon = getParam->icon;
|
||||
if (icon != nullptr) {
|
||||
auto icon_mem = SaveMemory::GetIcon();
|
||||
auto icon_mem = SaveMemory::GetIcon(slot_id);
|
||||
size_t total = std::min(icon->bufSize, icon_mem.size());
|
||||
std::memcpy(icon->buf, icon_mem.data(), total);
|
||||
icon->dataSize = total;
|
||||
|
@ -1494,36 +1510,37 @@ Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2*
|
|||
LOG_INFO(Lib_SaveData, "called with invalid parameter");
|
||||
return Error::PARAMETER;
|
||||
}
|
||||
if (!SaveMemory::IsSaveMemoryInitialized()) {
|
||||
u32 slot_id = 0;
|
||||
u32 data_num = 1;
|
||||
if (g_fw_ver > ElfInfo::FW_50) {
|
||||
slot_id = setParam->slotId;
|
||||
if (setParam->dataNum > 1) {
|
||||
data_num = setParam->dataNum;
|
||||
}
|
||||
}
|
||||
if (!SaveMemory::IsSaveMemoryInitialized(slot_id)) {
|
||||
LOG_INFO(Lib_SaveData, "called without save memory initialized");
|
||||
return Error::MEMORY_NOT_READY;
|
||||
}
|
||||
if (SaveMemory::IsSaving()) {
|
||||
int count = 0;
|
||||
while (++count < 100 && SaveMemory::IsSaving()) { // try for more 10 seconds
|
||||
std::this_thread::sleep_for(chrono::milliseconds(100));
|
||||
}
|
||||
if (SaveMemory::IsSaving()) {
|
||||
LOG_TRACE(Lib_SaveData, "called while saving");
|
||||
return Error::BUSY_FOR_SAVING;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG(Lib_SaveData, "called");
|
||||
auto data = setParam->data;
|
||||
if (data != nullptr) {
|
||||
SaveMemory::WriteMemory(data->buf, data->bufSize, data->offset);
|
||||
for (int i = 0; i < data_num; i++) {
|
||||
SaveMemory::WriteMemory(slot_id, data[i].buf, data[i].bufSize, data[i].offset);
|
||||
}
|
||||
}
|
||||
auto param = setParam->param;
|
||||
if (param != nullptr) {
|
||||
param->ToSFO(SaveMemory::GetParamSFO());
|
||||
SaveMemory::SaveSFO();
|
||||
}
|
||||
auto icon = setParam->icon;
|
||||
if (icon != nullptr) {
|
||||
SaveMemory::WriteIcon(icon->buf, icon->bufSize);
|
||||
param->ToSFO(SaveMemory::GetParamSFO(slot_id));
|
||||
SaveMemory::SaveSFO(slot_id);
|
||||
}
|
||||
|
||||
auto icon = setParam->icon;
|
||||
if (icon != nullptr) {
|
||||
SaveMemory::SetIcon(slot_id, icon->buf, icon->bufSize);
|
||||
}
|
||||
|
||||
SaveMemory::TriggerSaveWithoutEvent();
|
||||
return Error::OK;
|
||||
}
|
||||
|
||||
|
@ -1563,9 +1580,12 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
|
|||
}
|
||||
LOG_DEBUG(Lib_SaveData, "called");
|
||||
|
||||
SaveMemory::SetDirectories(setupParam->userId, g_game_serial);
|
||||
u32 slot_id = 0;
|
||||
if (g_fw_ver > ElfInfo::FW_50) {
|
||||
slot_id = setupParam->slotId;
|
||||
}
|
||||
|
||||
const auto& save_path = SaveMemory::GetSavePath();
|
||||
const auto& save_path = SaveMemory::GetSavePath(setupParam->userId, slot_id, g_game_serial);
|
||||
for (const auto& instance : g_mount_slots) {
|
||||
if (instance.has_value() && instance->GetSavePath() == save_path) {
|
||||
return Error::BUSY;
|
||||
|
@ -1573,21 +1593,21 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
|
|||
}
|
||||
|
||||
try {
|
||||
size_t existed_size = SaveMemory::CreateSaveMemory(setupParam->memorySize);
|
||||
size_t existed_size =
|
||||
SaveMemory::SetupSaveMemory(setupParam->userId, slot_id, g_game_serial);
|
||||
if (existed_size == 0) { // Just created
|
||||
if (g_fw_ver >= ElfInfo::FW_45 && setupParam->initParam != nullptr) {
|
||||
auto& sfo = SaveMemory::GetParamSFO();
|
||||
auto& sfo = SaveMemory::GetParamSFO(slot_id);
|
||||
setupParam->initParam->ToSFO(sfo);
|
||||
}
|
||||
SaveMemory::SaveSFO();
|
||||
SaveMemory::SaveSFO(slot_id);
|
||||
|
||||
auto init_icon = setupParam->initIcon;
|
||||
if (g_fw_ver >= ElfInfo::FW_45 && init_icon != nullptr) {
|
||||
SaveMemory::SetIcon(init_icon->buf, init_icon->bufSize);
|
||||
SaveMemory::SetIcon(slot_id, init_icon->buf, init_icon->bufSize);
|
||||
} else {
|
||||
SaveMemory::SetIcon(nullptr, 0);
|
||||
SaveMemory::SetIcon(slot_id);
|
||||
}
|
||||
SaveMemory::TriggerSaveWithoutEvent();
|
||||
}
|
||||
if (g_fw_ver >= ElfInfo::FW_45 && result != nullptr) {
|
||||
result->existedMemorySize = existed_size;
|
||||
|
@ -1631,15 +1651,23 @@ Error PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(OrbisSaveDataMemorySync* syncPa
|
|||
LOG_INFO(Lib_SaveData, "called with invalid parameter");
|
||||
return Error::PARAMETER;
|
||||
}
|
||||
if (!SaveMemory::IsSaveMemoryInitialized()) {
|
||||
|
||||
u32 slot_id = 0;
|
||||
if (g_fw_ver > ElfInfo::FW_50) {
|
||||
slot_id = syncParam->slotId;
|
||||
}
|
||||
|
||||
if (!SaveMemory::IsSaveMemoryInitialized(slot_id)) {
|
||||
LOG_INFO(Lib_SaveData, "called without save memory initialized");
|
||||
return Error::MEMORY_NOT_READY;
|
||||
}
|
||||
LOG_DEBUG(Lib_SaveData, "called");
|
||||
bool ok = SaveMemory::TriggerSave();
|
||||
if (!ok) {
|
||||
return Error::BUSY_FOR_SAVING;
|
||||
}
|
||||
|
||||
SaveMemory::PersistMemory(slot_id);
|
||||
const auto& save_path = SaveMemory::GetSaveDir(slot_id);
|
||||
Backup::NewRequest(syncParam->userId, g_game_serial, save_path,
|
||||
OrbisSaveDataEventType::SAVE_DATA_MEMORY_SYNC);
|
||||
|
||||
return Error::OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
namespace Libraries::SystemService {
|
||||
|
||||
bool g_splash_status{true};
|
||||
std::queue<OrbisSystemServiceEvent> g_event_queue;
|
||||
std::mutex g_event_queue_mutex;
|
||||
|
||||
bool IsSplashVisible() {
|
||||
return Config::showSplash() && g_splash_status;
|
||||
|
@ -1772,7 +1774,9 @@ s32 PS4_SYSV_ABI sceSystemServiceGetStatus(OrbisSystemServiceStatus* status) {
|
|||
LOG_ERROR(Lib_SystemService, "OrbisSystemServiceStatus is null");
|
||||
return ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER;
|
||||
}
|
||||
status->event_num = 0;
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_event_queue_mutex);
|
||||
status->event_num = static_cast<s32>(g_event_queue.size());
|
||||
status->is_system_ui_overlaid = false;
|
||||
status->is_in_background_execution = false;
|
||||
status->is_cpu_mode7_cpu_normal = true;
|
||||
|
@ -1940,11 +1944,19 @@ int PS4_SYSV_ABI sceSystemServiceRaiseExceptionLocalProcess() {
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceSystemServiceReceiveEvent(OrbisSystemServiceEvent* event) {
|
||||
LOG_ERROR(Lib_SystemService, "(STUBBED) called");
|
||||
LOG_TRACE(Lib_SystemService, "called");
|
||||
if (event == nullptr) {
|
||||
return ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER;
|
||||
}
|
||||
return ORBIS_SYSTEM_SERVICE_ERROR_NO_EVENT;
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_event_queue_mutex);
|
||||
if (g_event_queue.empty()) {
|
||||
return ORBIS_SYSTEM_SERVICE_ERROR_NO_EVENT;
|
||||
}
|
||||
|
||||
*event = g_event_queue.front();
|
||||
g_event_queue.pop();
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceSystemServiceReenableMusicPlayer() {
|
||||
|
@ -2412,6 +2424,11 @@ int PS4_SYSV_ABI Func_CB5E885E225F69F0() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void PushSystemServiceEvent(const OrbisSystemServiceEvent& event) {
|
||||
std::lock_guard<std::mutex> lock(g_event_queue_mutex);
|
||||
g_event_queue.push(event);
|
||||
}
|
||||
|
||||
void RegisterlibSceSystemService(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("alZfRdr2RP8", "libSceAppMessaging", 1, "libSceSystemService", 1, 1,
|
||||
sceAppMessagingClearEventFlag);
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
// https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain/blob/master/include/orbis/_types/sys_service.h
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
|
@ -603,5 +605,7 @@ int PS4_SYSV_ABI sceSystemServiceReenableVoiceRecognition();
|
|||
int PS4_SYSV_ABI Func_6B1CDB955F0EBD65();
|
||||
int PS4_SYSV_ABI Func_CB5E885E225F69F0();
|
||||
|
||||
void PushSystemServiceEvent(const OrbisSystemServiceEvent& event);
|
||||
|
||||
void RegisterlibSceSystemService(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::SystemService
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace Libraries::Videodec {
|
||||
|
||||
static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying
|
||||
static constexpr u64 kMinimumMemorySize = 16_MB; ///> Fake minimum memory size for querying
|
||||
|
||||
int PS4_SYSV_ABI sceVideodecCreateDecoder(const OrbisVideodecConfigInfo* pCfgInfoIn,
|
||||
const OrbisVideodecResourceInfo* pRsrcInfoIn,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
namespace Libraries::Vdec2 {
|
||||
|
||||
static constexpr u64 kMinimumMemorySize = 32_MB; ///> Fake minimum memory size for querying
|
||||
static constexpr u64 kMinimumMemorySize = 16_MB; ///> Fake minimum memory size for querying
|
||||
|
||||
s32 PS4_SYSV_ABI
|
||||
sceVideodec2QueryComputeMemoryInfo(OrbisVideodec2ComputeMemoryInfo* computeMemInfo) {
|
||||
|
|
112
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
Normal file
112
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/web_browser_dialog/webbrowserdialog.h"
|
||||
|
||||
namespace Libraries::WebBrowserDialog {
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogClose() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogGetEvent() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogGetStatus() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogInitialize() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogNavigate() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogOpen() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogOpenForPredeterminedContent() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogResetCookie() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogSetCookie() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogSetZoom() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogTerminate() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogUpdateStatus() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI Func_F2BE042771625F8C() {
|
||||
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceWebBrowserDialog(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("PSK+Eik919Q", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogClose);
|
||||
LIB_FUNCTION("Wit4LjeoeX4", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogGetEvent);
|
||||
LIB_FUNCTION("vCaW0fgVQmc", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogGetResult);
|
||||
LIB_FUNCTION("CFTG6a8TjOU", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogGetStatus);
|
||||
LIB_FUNCTION("jqb7HntFQFc", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogInitialize);
|
||||
LIB_FUNCTION("uYELOMVnmNQ", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogNavigate);
|
||||
LIB_FUNCTION("FraP7debcdg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogOpen);
|
||||
LIB_FUNCTION("O7dIZQrwVFY", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogOpenForPredeterminedContent);
|
||||
LIB_FUNCTION("Cya+jvTtPqg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogResetCookie);
|
||||
LIB_FUNCTION("TZnDVkP91Rg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogSetCookie);
|
||||
LIB_FUNCTION("RLhKBOoNyXY", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogSetZoom);
|
||||
LIB_FUNCTION("ocHtyBwHfys", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogTerminate);
|
||||
LIB_FUNCTION("h1dR-t5ISgg", "libSceWebBrowserDialog", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
sceWebBrowserDialogUpdateStatus);
|
||||
LIB_FUNCTION("8r4EJ3FiX4w", "libSceWebBrowserDialogLimited", 1, "libSceWebBrowserDialog", 1, 1,
|
||||
Func_F2BE042771625F8C);
|
||||
};
|
||||
|
||||
} // namespace Libraries::WebBrowserDialog
|
30
src/core/libraries/web_browser_dialog/webbrowserdialog.h
Normal file
30
src/core/libraries/web_browser_dialog/webbrowserdialog.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::WebBrowserDialog {
|
||||
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogClose();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogGetEvent();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogGetStatus();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogInitialize();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogNavigate();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogOpen();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogOpenForPredeterminedContent();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogResetCookie();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogSetCookie();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogSetZoom();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogTerminate();
|
||||
s32 PS4_SYSV_ABI sceWebBrowserDialogUpdateStatus();
|
||||
s32 PS4_SYSV_ABI Func_F2BE042771625F8C();
|
||||
|
||||
void RegisterlibSceWebBrowserDialog(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::WebBrowserDialog
|
183
src/core/libraries/zlib/zlib.cpp
Normal file
183
src/core/libraries/zlib/zlib.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <stop_token>
|
||||
#include <unordered_map>
|
||||
#include <queue>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/libraries/kernel/threads.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "core/libraries/zlib/zlib_error.h"
|
||||
#include "core/libraries/zlib/zlib_sce.h"
|
||||
|
||||
namespace Libraries::Zlib {
|
||||
|
||||
struct InflateTask {
|
||||
u64 request_id;
|
||||
const void* src;
|
||||
u32 src_length;
|
||||
void* dst;
|
||||
u32 dst_length;
|
||||
};
|
||||
|
||||
struct InflateResult {
|
||||
u32 length;
|
||||
s32 status;
|
||||
};
|
||||
|
||||
static Kernel::Thread task_thread;
|
||||
|
||||
static std::mutex mutex;
|
||||
static std::queue<InflateTask> task_queue;
|
||||
static std::condition_variable_any task_queue_cv;
|
||||
static std::queue<u64> done_queue;
|
||||
static std::condition_variable_any done_queue_cv;
|
||||
static std::unordered_map<u64, InflateResult> results;
|
||||
static u64 next_request_id;
|
||||
|
||||
void ZlibTaskThread(const std::stop_token& stop) {
|
||||
Common::SetCurrentThreadName("shadPS4:ZlibTaskThread");
|
||||
|
||||
while (!stop.stop_requested()) {
|
||||
InflateTask task;
|
||||
{
|
||||
// Lock and pop from the task queue, unless stop has been requested.
|
||||
std::unique_lock lock(mutex);
|
||||
if (!task_queue_cv.wait(lock, stop, [&] { return !task_queue.empty(); })) {
|
||||
break;
|
||||
}
|
||||
task = task_queue.back();
|
||||
task_queue.pop();
|
||||
}
|
||||
|
||||
uLongf decompressed_length = task.dst_length;
|
||||
const auto ret = uncompress(static_cast<Bytef*>(task.dst), &decompressed_length,
|
||||
static_cast<const Bytef*>(task.src), task.src_length);
|
||||
|
||||
{
|
||||
// Lock, insert the new result, and push the finished request ID to the done queue.
|
||||
std::unique_lock lock(mutex);
|
||||
results[task.request_id] = InflateResult{
|
||||
.length = static_cast<u32>(decompressed_length),
|
||||
.status = ret == Z_BUF_ERROR ? ORBIS_ZLIB_ERROR_NOSPACE
|
||||
: ret == Z_OK ? ORBIS_OK
|
||||
: ORBIS_ZLIB_ERROR_FATAL,
|
||||
};
|
||||
done_queue.push(task.request_id);
|
||||
}
|
||||
done_queue_cv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceZlibInitialize(const void* buffer, u32 length) {
|
||||
LOG_INFO(Lib_Zlib, "called");
|
||||
if (task_thread.Joinable()) {
|
||||
return ORBIS_ZLIB_ERROR_ALREADY_INITIALIZED;
|
||||
}
|
||||
|
||||
// Initialize with empty task data
|
||||
task_queue = std::queue<InflateTask>();
|
||||
done_queue = std::queue<u64>();
|
||||
results.clear();
|
||||
next_request_id = 1;
|
||||
|
||||
task_thread.Run([](const std::stop_token& stop) { ZlibTaskThread(stop); });
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceZlibInflate(const void* src, u32 src_len, void* dst, u32 dst_len,
|
||||
u64* request_id) {
|
||||
LOG_DEBUG(Lib_Zlib, "(STUBBED) called");
|
||||
if (!task_thread.Joinable()) {
|
||||
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!src || !src_len || !dst || !dst_len || !request_id || dst_len > 64_KB ||
|
||||
dst_len % 2_KB != 0) {
|
||||
return ORBIS_ZLIB_ERROR_INVALID;
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
*request_id = next_request_id++;
|
||||
task_queue.emplace(InflateTask{
|
||||
.request_id = *request_id,
|
||||
.src = src,
|
||||
.src_length = src_len,
|
||||
.dst = dst,
|
||||
.dst_length = dst_len,
|
||||
});
|
||||
task_queue_cv.notify_one();
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceZlibWaitForDone(u64* request_id, const u32* timeout) {
|
||||
LOG_DEBUG(Lib_Zlib, "(STUBBED) called");
|
||||
if (!task_thread.Joinable()) {
|
||||
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!request_id) {
|
||||
return ORBIS_ZLIB_ERROR_INVALID;
|
||||
}
|
||||
|
||||
{
|
||||
// Pop from the done queue, unless the timeout is reached.
|
||||
std::unique_lock lock(mutex);
|
||||
const auto pred = [] { return !done_queue.empty(); };
|
||||
if (timeout) {
|
||||
if (!done_queue_cv.wait_for(lock, std::chrono::milliseconds(*timeout), pred)) {
|
||||
return ORBIS_ZLIB_ERROR_TIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
done_queue_cv.wait(lock, pred);
|
||||
}
|
||||
*request_id = done_queue.back();
|
||||
done_queue.pop();
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceZlibGetResult(const u64 request_id, u32* dst_length, s32* status) {
|
||||
LOG_DEBUG(Lib_Zlib, "(STUBBED) called");
|
||||
if (!task_thread.Joinable()) {
|
||||
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (!dst_length || !status) {
|
||||
return ORBIS_ZLIB_ERROR_INVALID;
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock lock(mutex);
|
||||
if (!results.contains(request_id)) {
|
||||
return ORBIS_ZLIB_ERROR_NOT_FOUND;
|
||||
}
|
||||
const auto result = results[request_id];
|
||||
*dst_length = result.length;
|
||||
*status = result.status;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceZlibFinalize() {
|
||||
LOG_INFO(Lib_Zlib, "called");
|
||||
if (!task_thread.Joinable()) {
|
||||
return ORBIS_ZLIB_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
task_thread.Stop();
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceZlib(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("m1YErdIXCp4", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibInitialize);
|
||||
LIB_FUNCTION("6na+Sa-B83w", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibFinalize);
|
||||
LIB_FUNCTION("TLar1HULv1Q", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibInflate);
|
||||
LIB_FUNCTION("uB8VlDD4e0s", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibWaitForDone);
|
||||
LIB_FUNCTION("2eDcGHC0YaM", "libSceZlib", 1, "libSceZlib", 1, 1, sceZlibGetResult);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Zlib
|
18
src/core/libraries/zlib/zlib_error.h
Normal file
18
src/core/libraries/zlib/zlib_error.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
||||
// Zlib library
|
||||
constexpr int ORBIS_ZLIB_ERROR_NOT_FOUND = 0x81120002;
|
||||
constexpr int ORBIS_ZLIB_ERROR_BUSY = 0x8112000B;
|
||||
constexpr int ORBIS_ZLIB_ERROR_FAULT = 0x8112000E;
|
||||
constexpr int ORBIS_ZLIB_ERROR_INVALID = 0x81120016;
|
||||
constexpr int ORBIS_ZLIB_ERROR_NOSPACE = 0x8112001C;
|
||||
constexpr int ORBIS_ZLIB_ERROR_NOT_SUPPORTED = 0x81120025;
|
||||
constexpr int ORBIS_ZLIB_ERROR_TIMEDOUT = 0x81120027;
|
||||
constexpr int ORBIS_ZLIB_ERROR_NOT_INITIALIZED = 0x81120032;
|
||||
constexpr int ORBIS_ZLIB_ERROR_ALREADY_INITIALIZED = 0x81120033;
|
||||
constexpr int ORBIS_ZLIB_ERROR_FATAL = 0x811200FF;
|
21
src/core/libraries/zlib/zlib_sce.h
Normal file
21
src/core/libraries/zlib/zlib_sce.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
namespace Libraries::Zlib {
|
||||
|
||||
s32 PS4_SYSV_ABI sceZlibInitialize(const void* buffer, u32 length);
|
||||
s32 PS4_SYSV_ABI sceZlibInflate(const void* src, u32 src_len, void* dst, u32 dst_len,
|
||||
u64* request_id);
|
||||
s32 PS4_SYSV_ABI sceZlibWaitForDone(u64* request_id, const u32* timeout);
|
||||
s32 PS4_SYSV_ABI sceZlibGetResult(u64 request_id, u32* dst_length, s32* status);
|
||||
s32 PS4_SYSV_ABI sceZlibFinalize();
|
||||
|
||||
void RegisterlibSceZlib(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Zlib
|
|
@ -109,10 +109,13 @@ public:
|
|||
|
||||
void RelocateAnyImports(Module* m) {
|
||||
Relocate(m);
|
||||
for (auto& module : m_modules) {
|
||||
const auto imports = module->GetImportModules();
|
||||
if (std::ranges::contains(imports, m->name, &ModuleInfo::name)) {
|
||||
Relocate(module.get());
|
||||
const auto exports = m->GetExportModules();
|
||||
for (auto& export_mod : exports) {
|
||||
for (auto& module : m_modules) {
|
||||
const auto imports = module->GetImportModules();
|
||||
if (std::ranges::contains(imports, export_mod.name, &ModuleInfo::name)) {
|
||||
Relocate(module.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -392,47 +392,57 @@ s32 MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
|
|||
return UnmapMemoryImpl(virtual_addr, size);
|
||||
}
|
||||
|
||||
s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, size_t size) {
|
||||
const auto it = FindVMA(virtual_addr);
|
||||
const auto& vma_base = it->second;
|
||||
ASSERT_MSG(vma_base.Contains(virtual_addr, size),
|
||||
"Existing mapping does not contain requested unmap range");
|
||||
|
||||
const auto type = vma_base.type;
|
||||
if (type == VMAType::Free) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
u64 MemoryManager::UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma_base, u64 size) {
|
||||
const auto vma_base_addr = vma_base.base;
|
||||
const auto vma_base_size = vma_base.size;
|
||||
const auto type = vma_base.type;
|
||||
const auto phys_base = vma_base.phys_base;
|
||||
const bool is_exec = vma_base.is_exec;
|
||||
const auto start_in_vma = virtual_addr - vma_base_addr;
|
||||
const auto adjusted_size =
|
||||
vma_base_size - start_in_vma < size ? vma_base_size - start_in_vma : size;
|
||||
const bool has_backing = type == VMAType::Direct || type == VMAType::File;
|
||||
|
||||
if (type == VMAType::Free) {
|
||||
return adjusted_size;
|
||||
}
|
||||
if (type == VMAType::Direct || type == VMAType::Pooled) {
|
||||
rasterizer->UnmapMemory(virtual_addr, size);
|
||||
rasterizer->UnmapMemory(virtual_addr, adjusted_size);
|
||||
}
|
||||
if (type == VMAType::Flexible) {
|
||||
flexible_usage -= size;
|
||||
flexible_usage -= adjusted_size;
|
||||
}
|
||||
|
||||
// Mark region as free and attempt to coalesce it with neighbours.
|
||||
const auto new_it = CarveVMA(virtual_addr, size);
|
||||
const auto new_it = CarveVMA(virtual_addr, adjusted_size);
|
||||
auto& vma = new_it->second;
|
||||
vma.type = VMAType::Free;
|
||||
vma.prot = MemoryProt::NoAccess;
|
||||
vma.phys_base = 0;
|
||||
vma.disallow_merge = false;
|
||||
vma.name = "";
|
||||
MergeAdjacent(vma_map, new_it);
|
||||
bool readonly_file = vma.prot == MemoryProt::CpuRead && type == VMAType::File;
|
||||
|
||||
const auto post_merge_it = MergeAdjacent(vma_map, new_it);
|
||||
auto& post_merge_vma = post_merge_it->second;
|
||||
bool readonly_file = post_merge_vma.prot == MemoryProt::CpuRead && type == VMAType::File;
|
||||
if (type != VMAType::Reserved && type != VMAType::PoolReserved) {
|
||||
// Unmap the memory region.
|
||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + size, phys_base,
|
||||
is_exec, has_backing, readonly_file);
|
||||
impl.Unmap(vma_base_addr, vma_base_size, start_in_vma, start_in_vma + adjusted_size,
|
||||
phys_base, is_exec, has_backing, readonly_file);
|
||||
TRACK_FREE(virtual_addr, "VMEM");
|
||||
}
|
||||
return adjusted_size;
|
||||
}
|
||||
|
||||
s32 MemoryManager::UnmapMemoryImpl(VAddr virtual_addr, u64 size) {
|
||||
u64 unmapped_bytes = 0;
|
||||
do {
|
||||
auto it = FindVMA(virtual_addr + unmapped_bytes);
|
||||
auto& vma_base = it->second;
|
||||
auto unmapped =
|
||||
UnmapBytesFromEntry(virtual_addr + unmapped_bytes, vma_base, size - unmapped_bytes);
|
||||
ASSERT_MSG(unmapped > 0, "Failed to unmap memory, progress is impossible");
|
||||
unmapped_bytes += unmapped;
|
||||
} while (unmapped_bytes < size);
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -654,6 +664,12 @@ MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size
|
|||
|
||||
const VAddr start_in_vma = virtual_addr - vma.base;
|
||||
const VAddr end_in_vma = start_in_vma + size;
|
||||
|
||||
if (start_in_vma == 0 && size == vma.size) {
|
||||
// if requsting the whole VMA, return it
|
||||
return vma_handle;
|
||||
}
|
||||
|
||||
ASSERT_MSG(end_in_vma <= vma.size, "Mapping cannot fit inside free region");
|
||||
|
||||
if (end_in_vma != vma.size) {
|
||||
|
|
|
@ -252,7 +252,9 @@ private:
|
|||
|
||||
DMemHandle Split(DMemHandle dmem_handle, size_t offset_in_area);
|
||||
|
||||
s32 UnmapMemoryImpl(VAddr virtual_addr, size_t size);
|
||||
u64 UnmapBytesFromEntry(VAddr virtual_addr, VirtualMemoryArea vma_base, u64 size);
|
||||
|
||||
s32 UnmapMemoryImpl(VAddr virtual_addr, u64 size);
|
||||
|
||||
private:
|
||||
AddressSpace impl;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "core/libraries/ngs2/ngs2.h"
|
||||
#include "core/libraries/np_trophy/np_trophy.h"
|
||||
#include "core/libraries/rtc/rtc.h"
|
||||
#include "core/libraries/save_data/save_backup.h"
|
||||
#include "core/linker.h"
|
||||
#include "core/memory.h"
|
||||
#include "emulator.h"
|
||||
|
@ -56,6 +57,7 @@ Emulator::Emulator() {
|
|||
LOG_INFO(Loader, "Revision {}", Common::g_scm_rev);
|
||||
LOG_INFO(Loader, "Branch {}", Common::g_scm_branch);
|
||||
LOG_INFO(Loader, "Description {}", Common::g_scm_desc);
|
||||
LOG_INFO(Loader, "Remote {}", Common::g_scm_remote_url);
|
||||
|
||||
LOG_INFO(Config, "General LogType: {}", Config::getLogType());
|
||||
LOG_INFO(Config, "General isNeo: {}", Config::isNeoModeConsole());
|
||||
|
@ -66,9 +68,9 @@ Emulator::Emulator() {
|
|||
LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled());
|
||||
LOG_INFO(Config, "Vulkan vkValidationSync: {}", Config::vkValidationSyncEnabled());
|
||||
LOG_INFO(Config, "Vulkan vkValidationGpu: {}", Config::vkValidationGpuEnabled());
|
||||
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::vkCrashDiagnosticEnabled());
|
||||
LOG_INFO(Config, "Vulkan hostMarkers: {}", Config::vkHostMarkersEnabled());
|
||||
LOG_INFO(Config, "Vulkan guestMarkers: {}", Config::vkGuestMarkersEnabled());
|
||||
LOG_INFO(Config, "Vulkan crashDiagnostics: {}", Config::getVkCrashDiagnosticEnabled());
|
||||
LOG_INFO(Config, "Vulkan hostMarkers: {}", Config::getVkHostMarkersEnabled());
|
||||
LOG_INFO(Config, "Vulkan guestMarkers: {}", Config::getVkGuestMarkersEnabled());
|
||||
LOG_INFO(Config, "Vulkan rdocEnable: {}", Config::isRdocEnabled());
|
||||
|
||||
// Create stdin/stdout/stderr
|
||||
|
@ -100,9 +102,21 @@ Emulator::~Emulator() {
|
|||
}
|
||||
|
||||
void Emulator::Run(const std::filesystem::path& file, const std::vector<std::string> args) {
|
||||
const auto eboot_name = file.filename().string();
|
||||
auto game_folder = file.parent_path();
|
||||
if (const auto game_folder_name = game_folder.filename().string();
|
||||
game_folder_name.ends_with("-UPDATE")) {
|
||||
// If an executable was launched from a separate update directory,
|
||||
// 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_path = game_folder.parent_path() / base_name;
|
||||
if (std::filesystem::is_directory(base_path)) {
|
||||
game_folder = base_path;
|
||||
}
|
||||
}
|
||||
|
||||
// Applications expect to be run from /app0 so mount the file's parent path as app0.
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
const auto game_folder = file.parent_path();
|
||||
mnt->Mount(game_folder, "/app0");
|
||||
// Certain games may use /hostapp as well such as CUSA001100
|
||||
mnt->Mount(game_folder, "/hostapp");
|
||||
|
@ -186,8 +200,16 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
if (Common::isRelease) {
|
||||
window_title = fmt::format("shadPS4 v{} | {}", Common::VERSION, game_title);
|
||||
} else {
|
||||
window_title = fmt::format("shadPS4 v{} {} {} | {}", Common::VERSION, Common::g_scm_branch,
|
||||
Common::g_scm_desc, game_title);
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
if (remote_url == "https://github.com/shadps4-emu/shadPS4.git" ||
|
||||
remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{} {} {} | {}", Common::VERSION,
|
||||
Common::g_scm_branch, Common::g_scm_desc, game_title);
|
||||
} else {
|
||||
std::string remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
window_title = fmt::format("shadPS4 v{} {}/{} {} | {}", Common::VERSION, remote_host,
|
||||
Common::g_scm_branch, Common::g_scm_desc, game_title);
|
||||
}
|
||||
}
|
||||
window = std::make_unique<Frontend::WindowSDL>(
|
||||
Config::getScreenWidth(), Config::getScreenHeight(), controller, window_title);
|
||||
|
@ -223,7 +245,7 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
Libraries::InitHLELibs(&linker->GetHLESymbols());
|
||||
|
||||
// Load the module with the linker
|
||||
const auto eboot_path = mnt->GetHostPath("/app0/" + file.filename().string());
|
||||
const auto eboot_path = mnt->GetHostPath("/app0/" + eboot_name);
|
||||
linker->LoadModule(eboot_path);
|
||||
|
||||
// check if we have system modules to load
|
||||
|
@ -259,7 +281,7 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
|
|||
UpdatePlayTime(id);
|
||||
#endif
|
||||
|
||||
std::exit(0);
|
||||
std::quick_exit(0);
|
||||
}
|
||||
|
||||
void Emulator::LoadSystemModules(const std::string& game_serial) {
|
||||
|
|
|
@ -148,7 +148,7 @@ bool ProcessEvent(SDL_Event* event) {
|
|||
case SDL_EVENT_MOUSE_BUTTON_DOWN: {
|
||||
const auto& io = GetIO();
|
||||
return io.WantCaptureMouse && io.Ctx->NavWindow != nullptr &&
|
||||
io.Ctx->NavWindow->ID != dock_id;
|
||||
(io.Ctx->NavWindow->Flags & ImGuiWindowFlags_NoNav) == 0;
|
||||
}
|
||||
case SDL_EVENT_TEXT_INPUT:
|
||||
case SDL_EVENT_KEY_DOWN: {
|
||||
|
@ -208,7 +208,7 @@ void Render(const vk::CommandBuffer& cmdbuf, const vk::ImageView& image_view,
|
|||
return;
|
||||
}
|
||||
|
||||
if (Config::vkHostMarkersEnabled()) {
|
||||
if (Config::getVkHostMarkersEnabled()) {
|
||||
cmdbuf.beginDebugUtilsLabelEXT(vk::DebugUtilsLabelEXT{
|
||||
.pLabelName = "ImGui Render",
|
||||
});
|
||||
|
@ -233,7 +233,7 @@ void Render(const vk::CommandBuffer& cmdbuf, const vk::ImageView& image_view,
|
|||
cmdbuf.beginRendering(render_info);
|
||||
Vulkan::RenderDrawData(*draw_data, cmdbuf);
|
||||
cmdbuf.endRendering();
|
||||
if (Config::vkHostMarkersEnabled()) {
|
||||
if (Config::getVkHostMarkersEnabled()) {
|
||||
cmdbuf.endDebugUtilsLabelEXT();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ void WorkerLoop() {
|
|||
g_job_list.pop_front();
|
||||
g_job_list_mtx.unlock();
|
||||
|
||||
if (Config::vkCrashDiagnosticEnabled()) {
|
||||
if (Config::getVkCrashDiagnosticEnabled()) {
|
||||
// FIXME: Crash diagnostic hangs when building the command buffer here
|
||||
continue;
|
||||
}
|
||||
|
|
673
src/input/input_handler.cpp
Normal file
673
src/input/input_handler.cpp
Normal file
|
@ -0,0 +1,673 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "input_handler.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_timer.h"
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/elf_info.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/path_util.h"
|
||||
#include "common/version.h"
|
||||
#include "input/controller.h"
|
||||
#include "input/input_mouse.h"
|
||||
|
||||
namespace Input {
|
||||
/*
|
||||
Project structure:
|
||||
n to m connection between inputs and outputs
|
||||
Keyup and keydown events update a dynamic list* of u32 'flags' (what is currently in the list is
|
||||
'pressed') On every event, after flag updates, we check for every input binding -> controller output
|
||||
pair if all their flags are 'on' If not, disable; if so, enable them. For axes, we gather their data
|
||||
into a struct cumulatively from all inputs, then after we checked all of those, we update them all
|
||||
at once. Wheel inputs generate a timer that doesn't turn off their outputs automatically, but push a
|
||||
userevent to do so.
|
||||
|
||||
What structs are needed?
|
||||
InputBinding(key1, key2, key3)
|
||||
ControllerOutput(button, axis) - we only need a const array of these, and one of the attr-s is
|
||||
always 0 BindingConnection(inputBinding (member), controllerOutput (ref to the array element))
|
||||
|
||||
Things to always test before pushing like a dumbass:
|
||||
Button outputs
|
||||
Axis outputs
|
||||
Input hierarchy
|
||||
Multi key inputs
|
||||
Mouse to joystick
|
||||
Key toggle
|
||||
Joystick halfmode
|
||||
|
||||
Don't be an idiot and test only the changed part expecting everything else to not be broken
|
||||
*/
|
||||
|
||||
bool leftjoystick_halfmode = false, rightjoystick_halfmode = false;
|
||||
int leftjoystick_deadzone, rightjoystick_deadzone, lefttrigger_deadzone, righttrigger_deadzone;
|
||||
|
||||
std::list<std::pair<InputEvent, bool>> pressed_keys;
|
||||
std::list<InputID> toggled_keys;
|
||||
static std::vector<BindingConnection> connections;
|
||||
|
||||
auto output_array = std::array{
|
||||
// Important: these have to be the first, or else they will update in the wrong order
|
||||
ControllerOutput(LEFTJOYSTICK_HALFMODE),
|
||||
ControllerOutput(RIGHTJOYSTICK_HALFMODE),
|
||||
ControllerOutput(KEY_TOGGLE),
|
||||
|
||||
// Button mappings
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_NORTH), // Triangle
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_EAST), // Circle
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_SOUTH), // Cross
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_WEST), // Square
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_LEFT_SHOULDER), // L1
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_LEFT_STICK), // L3
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER), // R1
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_RIGHT_STICK), // R3
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_START), // Options
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_TOUCHPAD), // TouchPad
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_DPAD_UP), // Up
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_DPAD_DOWN), // Down
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_DPAD_LEFT), // Left
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_DPAD_RIGHT), // Right
|
||||
|
||||
// Axis mappings
|
||||
// ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_LEFTX, false),
|
||||
// ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_LEFTY, false),
|
||||
// ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_RIGHTX, false),
|
||||
// ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_RIGHTY, false),
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_LEFTX),
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_LEFTY),
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_RIGHTX),
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_RIGHTY),
|
||||
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_LEFT_TRIGGER),
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER),
|
||||
|
||||
ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID, SDL_GAMEPAD_AXIS_INVALID),
|
||||
};
|
||||
|
||||
void ControllerOutput::LinkJoystickAxes() {
|
||||
// for (int i = 17; i < 23; i += 2) {
|
||||
// delete output_array[i].new_param;
|
||||
// output_array[i].new_param = output_array[i + 1].new_param;
|
||||
// }
|
||||
}
|
||||
|
||||
static OrbisPadButtonDataOffset SDLGamepadToOrbisButton(u8 button) {
|
||||
using OPBDO = OrbisPadButtonDataOffset;
|
||||
|
||||
switch (button) {
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_DOWN:
|
||||
return OPBDO::Down;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_UP:
|
||||
return OPBDO::Up;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_LEFT:
|
||||
return OPBDO::Left;
|
||||
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT:
|
||||
return OPBDO::Right;
|
||||
case SDL_GAMEPAD_BUTTON_SOUTH:
|
||||
return OPBDO::Cross;
|
||||
case SDL_GAMEPAD_BUTTON_NORTH:
|
||||
return OPBDO::Triangle;
|
||||
case SDL_GAMEPAD_BUTTON_WEST:
|
||||
return OPBDO::Square;
|
||||
case SDL_GAMEPAD_BUTTON_EAST:
|
||||
return OPBDO::Circle;
|
||||
case SDL_GAMEPAD_BUTTON_START:
|
||||
return OPBDO::Options;
|
||||
case SDL_GAMEPAD_BUTTON_TOUCHPAD:
|
||||
return OPBDO::TouchPad;
|
||||
case SDL_GAMEPAD_BUTTON_BACK:
|
||||
return OPBDO::TouchPad;
|
||||
case SDL_GAMEPAD_BUTTON_LEFT_SHOULDER:
|
||||
return OPBDO::L1;
|
||||
case SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER:
|
||||
return OPBDO::R1;
|
||||
case SDL_GAMEPAD_BUTTON_LEFT_STICK:
|
||||
return OPBDO::L3;
|
||||
case SDL_GAMEPAD_BUTTON_RIGHT_STICK:
|
||||
return OPBDO::R3;
|
||||
default:
|
||||
return OPBDO::None;
|
||||
}
|
||||
}
|
||||
|
||||
Axis GetAxisFromSDLAxis(u8 sdl_axis) {
|
||||
switch (sdl_axis) {
|
||||
case SDL_GAMEPAD_AXIS_LEFTX:
|
||||
return Axis::LeftX;
|
||||
case SDL_GAMEPAD_AXIS_LEFTY:
|
||||
return Axis::LeftY;
|
||||
case SDL_GAMEPAD_AXIS_RIGHTX:
|
||||
return Axis::RightX;
|
||||
case SDL_GAMEPAD_AXIS_RIGHTY:
|
||||
return Axis::RightY;
|
||||
case SDL_GAMEPAD_AXIS_LEFT_TRIGGER:
|
||||
return Axis::TriggerLeft;
|
||||
case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER:
|
||||
return Axis::TriggerRight;
|
||||
default:
|
||||
return Axis::AxisMax;
|
||||
}
|
||||
}
|
||||
|
||||
// syntax: 'name, name,name' or 'name,name' or 'name'
|
||||
InputBinding GetBindingFromString(std::string& line) {
|
||||
std::array<InputID, 3> keys = {InputID(), InputID(), InputID()};
|
||||
|
||||
// Check and process tokens
|
||||
for (const auto token : std::views::split(line, ',')) { // Split by comma
|
||||
const std::string t(token.begin(), token.end());
|
||||
InputID input;
|
||||
|
||||
if (string_to_keyboard_key_map.find(t) != string_to_keyboard_key_map.end()) {
|
||||
input = InputID(InputType::KeyboardMouse, string_to_keyboard_key_map.at(t));
|
||||
} else if (string_to_axis_map.find(t) != string_to_axis_map.end()) {
|
||||
input = InputID(InputType::Axis, (u32)string_to_axis_map.at(t).axis);
|
||||
} else if (string_to_cbutton_map.find(t) != string_to_cbutton_map.end()) {
|
||||
input = InputID(InputType::Controller, string_to_cbutton_map.at(t));
|
||||
} else {
|
||||
// Invalid token found; return default binding
|
||||
LOG_DEBUG(Input, "Invalid token found: {}", t);
|
||||
return InputBinding();
|
||||
}
|
||||
|
||||
// Assign to the first available slot
|
||||
for (auto& key : keys) {
|
||||
if (!key.IsValid()) {
|
||||
key = input;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(Input, "Parsed line: {}", InputBinding(keys[0], keys[1], keys[2]).ToString());
|
||||
return InputBinding(keys[0], keys[1], keys[2]);
|
||||
}
|
||||
|
||||
void ParseInputConfig(const std::string game_id = "") {
|
||||
std::string config_type = Config::GetUseUnifiedInputConfig() ? "default" : game_id;
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile(config_type);
|
||||
|
||||
// we reset these here so in case the user fucks up or doesn't include some of these,
|
||||
// we can fall back to default
|
||||
connections.clear();
|
||||
float mouse_deadzone_offset = 0.5;
|
||||
float mouse_speed = 1;
|
||||
float mouse_speed_offset = 0.125;
|
||||
|
||||
leftjoystick_deadzone = 1;
|
||||
rightjoystick_deadzone = 1;
|
||||
lefttrigger_deadzone = 1;
|
||||
righttrigger_deadzone = 1;
|
||||
|
||||
int lineCount = 0;
|
||||
|
||||
std::ifstream file(config_file);
|
||||
std::string line = "";
|
||||
while (std::getline(file, line)) {
|
||||
lineCount++;
|
||||
|
||||
// Strip the ; and whitespace
|
||||
line.erase(std::remove_if(line.begin(), line.end(),
|
||||
[](unsigned char c) { return std::isspace(c); }),
|
||||
line.end());
|
||||
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
// Truncate lines starting at #
|
||||
std::size_t comment_pos = line.find('#');
|
||||
if (comment_pos != std::string::npos) {
|
||||
line = line.substr(0, comment_pos);
|
||||
}
|
||||
// Remove trailing semicolon
|
||||
if (!line.empty() && line[line.length() - 1] == ';') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Split the line by '='
|
||||
std::size_t equal_pos = line.find('=');
|
||||
if (equal_pos == std::string::npos) {
|
||||
LOG_WARNING(Input, "Invalid format at line: {}, data: \"{}\", skipping line.",
|
||||
lineCount, line);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string output_string = line.substr(0, equal_pos);
|
||||
std::string input_string = line.substr(equal_pos + 1);
|
||||
std::size_t comma_pos = input_string.find(',');
|
||||
|
||||
if (output_string == "mouse_to_joystick") {
|
||||
if (input_string == "left") {
|
||||
SetMouseToJoystick(1);
|
||||
} else if (input_string == "right") {
|
||||
SetMouseToJoystick(2);
|
||||
} else {
|
||||
LOG_WARNING(Input, "Invalid argument for mouse-to-joystick binding");
|
||||
SetMouseToJoystick(0);
|
||||
}
|
||||
continue;
|
||||
} else if (output_string == "key_toggle") {
|
||||
if (comma_pos != std::string::npos) {
|
||||
// handle key-to-key toggling (separate list?)
|
||||
InputBinding toggle_keys = GetBindingFromString(input_string);
|
||||
if (toggle_keys.KeyCount() != 2) {
|
||||
LOG_WARNING(Input,
|
||||
"Syntax error: Please provide exactly 2 keys: "
|
||||
"first is the toggler, the second is the key to toggle: {}",
|
||||
line);
|
||||
continue;
|
||||
}
|
||||
ControllerOutput* toggle_out =
|
||||
&*std::ranges::find(output_array, ControllerOutput(KEY_TOGGLE));
|
||||
BindingConnection toggle_connection = BindingConnection(
|
||||
InputBinding(toggle_keys.keys[0]), toggle_out, 0, toggle_keys.keys[1]);
|
||||
connections.insert(connections.end(), toggle_connection);
|
||||
continue;
|
||||
}
|
||||
LOG_WARNING(Input, "Invalid format at line: {}, data: \"{}\", skipping line.",
|
||||
lineCount, line);
|
||||
continue;
|
||||
} else if (output_string == "mouse_movement_params") {
|
||||
std::stringstream ss(input_string);
|
||||
char comma; // To hold the comma separators between the floats
|
||||
ss >> mouse_deadzone_offset >> comma >> mouse_speed >> comma >> mouse_speed_offset;
|
||||
|
||||
// Check for invalid input (in case there's an unexpected format)
|
||||
if (ss.fail()) {
|
||||
LOG_WARNING(Input, "Failed to parse mouse movement parameters from line: {}", line);
|
||||
continue;
|
||||
}
|
||||
SetMouseParams(mouse_deadzone_offset, mouse_speed, mouse_speed_offset);
|
||||
continue;
|
||||
} else if (output_string == "analog_deadzone") {
|
||||
std::stringstream ss(input_string);
|
||||
std::string device;
|
||||
int deadzone;
|
||||
std::getline(ss, device, ',');
|
||||
ss >> deadzone;
|
||||
if (ss.fail()) {
|
||||
LOG_WARNING(Input, "Failed to parse deadzone config from line: {}", line);
|
||||
continue;
|
||||
} else {
|
||||
LOG_DEBUG(Input, "Parsed deadzone: {} {}", device, deadzone);
|
||||
}
|
||||
if (device == "leftjoystick") {
|
||||
leftjoystick_deadzone = deadzone;
|
||||
} else if (device == "rightjoystick") {
|
||||
rightjoystick_deadzone = deadzone;
|
||||
} else if (device == "l2") {
|
||||
lefttrigger_deadzone = deadzone;
|
||||
} else if (device == "r2") {
|
||||
righttrigger_deadzone = deadzone;
|
||||
} else {
|
||||
LOG_WARNING(Input, "Invalid axis name at line: {}, data: \"{}\", skipping line.",
|
||||
lineCount, line);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// normal cases
|
||||
InputBinding binding = GetBindingFromString(input_string);
|
||||
BindingConnection connection(InputID(), nullptr);
|
||||
auto button_it = string_to_cbutton_map.find(output_string);
|
||||
auto axis_it = string_to_axis_map.find(output_string);
|
||||
|
||||
if (binding.IsEmpty()) {
|
||||
LOG_WARNING(Input, "Invalid format at line: {}, data: \"{}\", skipping line.",
|
||||
lineCount, line);
|
||||
continue;
|
||||
}
|
||||
if (button_it != string_to_cbutton_map.end()) {
|
||||
connection = BindingConnection(
|
||||
binding, &*std::ranges::find(output_array, ControllerOutput(button_it->second)));
|
||||
connections.insert(connections.end(), connection);
|
||||
|
||||
} else if (axis_it != string_to_axis_map.end()) {
|
||||
int value_to_set = binding.keys[2].type == InputType::Axis ? 0 : axis_it->second.value;
|
||||
connection = BindingConnection(
|
||||
binding,
|
||||
&*std::ranges::find(output_array, ControllerOutput(SDL_GAMEPAD_BUTTON_INVALID,
|
||||
axis_it->second.axis,
|
||||
axis_it->second.value >= 0)),
|
||||
value_to_set);
|
||||
connections.insert(connections.end(), connection);
|
||||
} else {
|
||||
LOG_WARNING(Input, "Invalid format at line: {}, data: \"{}\", skipping line.",
|
||||
lineCount, line);
|
||||
continue;
|
||||
}
|
||||
LOG_DEBUG(Input, "Succesfully parsed line {}", lineCount);
|
||||
}
|
||||
file.close();
|
||||
std::sort(connections.begin(), connections.end());
|
||||
for (auto& c : connections) {
|
||||
LOG_DEBUG(Input, "Binding: {} : {}", c.output->ToString(), c.binding.ToString());
|
||||
}
|
||||
LOG_DEBUG(Input, "Done parsing the input config!");
|
||||
}
|
||||
|
||||
u32 GetMouseWheelEvent(const SDL_Event& event) {
|
||||
if (event.type != SDL_EVENT_MOUSE_WHEEL && event.type != SDL_EVENT_MOUSE_WHEEL_OFF) {
|
||||
LOG_WARNING(Input, "Something went wrong with wheel input parsing!");
|
||||
return (u32)-1;
|
||||
}
|
||||
if (event.wheel.y > 0) {
|
||||
return SDL_MOUSE_WHEEL_UP;
|
||||
} else if (event.wheel.y < 0) {
|
||||
return SDL_MOUSE_WHEEL_DOWN;
|
||||
} else if (event.wheel.x > 0) {
|
||||
return SDL_MOUSE_WHEEL_RIGHT;
|
||||
} else if (event.wheel.x < 0) {
|
||||
return SDL_MOUSE_WHEEL_LEFT;
|
||||
}
|
||||
return (u32)-1;
|
||||
}
|
||||
|
||||
InputEvent InputBinding::GetInputEventFromSDLEvent(const SDL_Event& e) {
|
||||
switch (e.type) {
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
return InputEvent(InputType::KeyboardMouse, e.key.key, e.key.down, 0);
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
return InputEvent(InputType::KeyboardMouse, (u32)e.button.button, e.button.down, 0);
|
||||
case SDL_EVENT_MOUSE_WHEEL:
|
||||
case SDL_EVENT_MOUSE_WHEEL_OFF:
|
||||
return InputEvent(InputType::KeyboardMouse, GetMouseWheelEvent(e),
|
||||
e.type == SDL_EVENT_MOUSE_WHEEL, 0);
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||
return InputEvent(InputType::Controller, (u32)e.gbutton.button, e.gbutton.down, 0);
|
||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||
return InputEvent(InputType::Axis, (u32)e.gaxis.axis, true, e.gaxis.value / 256);
|
||||
default:
|
||||
return InputEvent();
|
||||
}
|
||||
}
|
||||
|
||||
GameController* ControllerOutput::controller = nullptr;
|
||||
void ControllerOutput::SetControllerOutputController(GameController* c) {
|
||||
ControllerOutput::controller = c;
|
||||
}
|
||||
|
||||
void ToggleKeyInList(InputID input) {
|
||||
if (input.type == InputType::Axis) {
|
||||
LOG_ERROR(Input, "Toggling analog inputs is not supported!");
|
||||
return;
|
||||
}
|
||||
auto it = std::find(toggled_keys.begin(), toggled_keys.end(), input);
|
||||
if (it == toggled_keys.end()) {
|
||||
toggled_keys.insert(toggled_keys.end(), input);
|
||||
LOG_DEBUG(Input, "Added {} to toggled keys", input.ToString());
|
||||
} else {
|
||||
toggled_keys.erase(it);
|
||||
LOG_DEBUG(Input, "Removed {} from toggled keys", input.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerOutput::ResetUpdate() {
|
||||
state_changed = false;
|
||||
new_button_state = false;
|
||||
*new_param = 0; // bruh
|
||||
}
|
||||
void ControllerOutput::AddUpdate(InputEvent event) {
|
||||
state_changed = true;
|
||||
if (button == KEY_TOGGLE) {
|
||||
if (event.active) {
|
||||
ToggleKeyInList(event.input);
|
||||
}
|
||||
} else if (button != SDL_GAMEPAD_BUTTON_INVALID) {
|
||||
if (event.input.type == InputType::Axis) {
|
||||
bool temp = event.axis_value * (positive_axis ? 1 : -1) > 0x40;
|
||||
new_button_state |= event.active && event.axis_value * (positive_axis ? 1 : -1) > 0x40;
|
||||
if (temp) {
|
||||
LOG_DEBUG(Input, "Toggled a button from an axis");
|
||||
}
|
||||
} else {
|
||||
new_button_state |= event.active;
|
||||
}
|
||||
|
||||
} else if (axis != SDL_GAMEPAD_AXIS_INVALID) {
|
||||
switch (axis) {
|
||||
case SDL_GAMEPAD_AXIS_LEFT_TRIGGER:
|
||||
case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER:
|
||||
// if it's a button input, then we know the value to set, so the param is 0.
|
||||
// if it's an analog input, then the param isn't 0
|
||||
*new_param = (event.active ? event.axis_value : 0) + *new_param;
|
||||
break;
|
||||
default:
|
||||
*new_param = (event.active ? event.axis_value : 0) + *new_param;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ControllerOutput::FinalizeUpdate() {
|
||||
if (!state_changed) {
|
||||
// return;
|
||||
}
|
||||
|
||||
old_button_state = new_button_state;
|
||||
old_param = *new_param;
|
||||
float touchpad_x = 0;
|
||||
if (button != SDL_GAMEPAD_BUTTON_INVALID) {
|
||||
switch (button) {
|
||||
case SDL_GAMEPAD_BUTTON_TOUCHPAD:
|
||||
touchpad_x = Config::getBackButtonBehavior() == "left" ? 0.25f
|
||||
: Config::getBackButtonBehavior() == "right" ? 0.75f
|
||||
: 0.5f;
|
||||
controller->SetTouchpadState(0, new_button_state, touchpad_x, 0.5f);
|
||||
controller->CheckButton(0, SDLGamepadToOrbisButton(button), new_button_state);
|
||||
break;
|
||||
case LEFTJOYSTICK_HALFMODE:
|
||||
leftjoystick_halfmode = new_button_state;
|
||||
break;
|
||||
case RIGHTJOYSTICK_HALFMODE:
|
||||
rightjoystick_halfmode = new_button_state;
|
||||
break;
|
||||
// KEY_TOGGLE isn't handled here anymore, as this function doesn't have the necessary data
|
||||
// to do it, and it would be inconvenient to force it here, when AddUpdate does the job just
|
||||
// fine, and a toggle doesn't have to checked against every input that's bound to it, it's
|
||||
// enough that one is pressed
|
||||
default: // is a normal key (hopefully)
|
||||
controller->CheckButton(0, SDLGamepadToOrbisButton(button), new_button_state);
|
||||
break;
|
||||
}
|
||||
} else if (axis != SDL_GAMEPAD_AXIS_INVALID && positive_axis) {
|
||||
// avoid double-updating axes, but don't skip directional button bindings
|
||||
float multiplier = 1.0;
|
||||
int deadzone = 0;
|
||||
auto ApplyDeadzone = [](s16* value, int deadzone) {
|
||||
if (std::abs(*value) <= deadzone) {
|
||||
*value = 0;
|
||||
}
|
||||
};
|
||||
Axis c_axis = GetAxisFromSDLAxis(axis);
|
||||
switch (c_axis) {
|
||||
case Axis::LeftX:
|
||||
case Axis::LeftY:
|
||||
ApplyDeadzone(new_param, leftjoystick_deadzone);
|
||||
multiplier = leftjoystick_halfmode ? 0.5 : 1.0;
|
||||
break;
|
||||
case Axis::RightX:
|
||||
case Axis::RightY:
|
||||
ApplyDeadzone(new_param, rightjoystick_deadzone);
|
||||
multiplier = rightjoystick_halfmode ? 0.5 : 1.0;
|
||||
break;
|
||||
case Axis::TriggerLeft:
|
||||
ApplyDeadzone(new_param, lefttrigger_deadzone);
|
||||
controller->Axis(0, c_axis, GetAxis(0x0, 0x80, *new_param));
|
||||
controller->CheckButton(0, OrbisPadButtonDataOffset::L2, *new_param > 0x20);
|
||||
return;
|
||||
case Axis::TriggerRight:
|
||||
ApplyDeadzone(new_param, righttrigger_deadzone);
|
||||
controller->Axis(0, c_axis, GetAxis(0x0, 0x80, *new_param));
|
||||
controller->CheckButton(0, OrbisPadButtonDataOffset::R2, *new_param > 0x20);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
controller->Axis(0, c_axis, GetAxis(-0x80, 0x80, *new_param * multiplier));
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the list of pressed keys with the given input.
|
||||
// Returns whether the list was updated or not.
|
||||
bool UpdatePressedKeys(InputEvent event) {
|
||||
// Skip invalid inputs
|
||||
InputID input = event.input;
|
||||
if (input.sdl_id == (u32)-1) {
|
||||
return false;
|
||||
}
|
||||
if (input.type == InputType::Axis) {
|
||||
// analog input, it gets added when it first sends an event,
|
||||
// and from there, it only changes the parameter
|
||||
auto it = std::lower_bound(pressed_keys.begin(), pressed_keys.end(), input,
|
||||
[](const std::pair<InputEvent, bool>& e, InputID i) {
|
||||
return std::tie(e.first.input.type, e.first.input.sdl_id) <
|
||||
std::tie(i.type, i.sdl_id);
|
||||
});
|
||||
if (it == pressed_keys.end() || it->first.input != input) {
|
||||
pressed_keys.insert(it, {event, false});
|
||||
LOG_DEBUG(Input, "Added axis {} to the input list", event.input.sdl_id);
|
||||
} else {
|
||||
it->first.axis_value = event.axis_value;
|
||||
}
|
||||
return true;
|
||||
} else if (event.active) {
|
||||
// Find the correct position for insertion to maintain order
|
||||
auto it = std::lower_bound(pressed_keys.begin(), pressed_keys.end(), input,
|
||||
[](const std::pair<InputEvent, bool>& e, InputID i) {
|
||||
return std::tie(e.first.input.type, e.first.input.sdl_id) <
|
||||
std::tie(i.type, i.sdl_id);
|
||||
});
|
||||
|
||||
// Insert only if 'value' is not already in the list
|
||||
if (it == pressed_keys.end() || it->first.input != input) {
|
||||
pressed_keys.insert(it, {event, false});
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Remove 'value' from the list if it's not pressed
|
||||
auto it = std::find_if(
|
||||
pressed_keys.begin(), pressed_keys.end(),
|
||||
[input](const std::pair<InputEvent, bool>& e) { return e.first.input == input; });
|
||||
if (it != pressed_keys.end()) {
|
||||
pressed_keys.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LOG_DEBUG(Input, "No change was made!");
|
||||
return false;
|
||||
}
|
||||
// Check if the binding's all keys are currently active.
|
||||
// It also extracts the analog inputs' parameters, and updates the input hierarchy flags.
|
||||
InputEvent BindingConnection::ProcessBinding() {
|
||||
// the last key is always set (if the connection isn't empty),
|
||||
// and the analog inputs are always the last one due to how they are sorted,
|
||||
// so this signifies whether or not the input is analog
|
||||
InputEvent event = InputEvent(binding.keys[0]);
|
||||
if (pressed_keys.empty()) {
|
||||
return event;
|
||||
}
|
||||
if (event.input.type != InputType::Axis) {
|
||||
// for button inputs
|
||||
event.axis_value = axis_param;
|
||||
}
|
||||
// it's a bit scuffed, but if the output is a toggle, then we put the key here
|
||||
if (output->button == KEY_TOGGLE) {
|
||||
event.input = toggle;
|
||||
}
|
||||
|
||||
// Extract keys from InputBinding and ignore unused or toggled keys
|
||||
std::list<InputID> input_keys = {binding.keys[0], binding.keys[1], binding.keys[2]};
|
||||
input_keys.remove(InputID());
|
||||
for (auto key = input_keys.begin(); key != input_keys.end();) {
|
||||
if (std::find(toggled_keys.begin(), toggled_keys.end(), *key) != toggled_keys.end()) {
|
||||
key = input_keys.erase(key); // Use the returned iterator
|
||||
} else {
|
||||
++key; // Increment only if no erase happened
|
||||
}
|
||||
}
|
||||
if (input_keys.empty()) {
|
||||
LOG_DEBUG(Input, "No actual inputs to check, returning true");
|
||||
event.active = true;
|
||||
return event;
|
||||
}
|
||||
|
||||
// Iterator for pressed_keys, starting from the beginning
|
||||
auto pressed_it = pressed_keys.begin();
|
||||
|
||||
// Store pointers to flags in pressed_keys that need to be set if all keys are active
|
||||
std::list<bool*> flags_to_set;
|
||||
|
||||
// Check if all keys in input_keys are active
|
||||
for (InputID key : input_keys) {
|
||||
bool key_found = false;
|
||||
|
||||
while (pressed_it != pressed_keys.end()) {
|
||||
if (pressed_it->first.input == key && (pressed_it->second == false)) {
|
||||
key_found = true;
|
||||
if (output->positive_axis) {
|
||||
flags_to_set.push_back(&pressed_it->second);
|
||||
}
|
||||
if (pressed_it->first.input.type == InputType::Axis) {
|
||||
event.axis_value = pressed_it->first.axis_value;
|
||||
}
|
||||
++pressed_it;
|
||||
break;
|
||||
}
|
||||
++pressed_it;
|
||||
}
|
||||
if (!key_found) {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
for (bool* flag : flags_to_set) {
|
||||
*flag = true;
|
||||
}
|
||||
if (binding.keys[0].type != InputType::Axis) { // the axes spam inputs, making this unreadable
|
||||
LOG_DEBUG(Input, "Input found: {}", binding.ToString());
|
||||
}
|
||||
event.active = true;
|
||||
return event; // All keys are active
|
||||
}
|
||||
|
||||
void ActivateOutputsFromInputs() {
|
||||
// Reset values and flags
|
||||
for (auto& it : pressed_keys) {
|
||||
it.second = false;
|
||||
}
|
||||
for (auto& it : output_array) {
|
||||
it.ResetUpdate();
|
||||
}
|
||||
|
||||
// Iterate over all inputs, and update their respecive outputs accordingly
|
||||
for (auto& it : connections) {
|
||||
it.output->AddUpdate(it.ProcessBinding());
|
||||
}
|
||||
|
||||
// Update all outputs
|
||||
for (auto& it : output_array) {
|
||||
it.FinalizeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Input
|
407
src/input/input_handler.h
Normal file
407
src/input/input_handler.h
Normal file
|
@ -0,0 +1,407 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "SDL3/SDL_events.h"
|
||||
#include "SDL3/SDL_timer.h"
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "fmt/format.h"
|
||||
#include "input/controller.h"
|
||||
|
||||
// +1 and +2 is taken
|
||||
#define SDL_MOUSE_WHEEL_UP SDL_EVENT_MOUSE_WHEEL + 3
|
||||
#define SDL_MOUSE_WHEEL_DOWN SDL_EVENT_MOUSE_WHEEL + 4
|
||||
#define SDL_MOUSE_WHEEL_LEFT SDL_EVENT_MOUSE_WHEEL + 5
|
||||
#define SDL_MOUSE_WHEEL_RIGHT SDL_EVENT_MOUSE_WHEEL + 7
|
||||
|
||||
// idk who already used what where so I just chose a big number
|
||||
#define SDL_EVENT_MOUSE_WHEEL_OFF SDL_EVENT_USER + 10
|
||||
|
||||
#define LEFTJOYSTICK_HALFMODE 0x00010000
|
||||
#define RIGHTJOYSTICK_HALFMODE 0x00020000
|
||||
#define BACK_BUTTON 0x00040000
|
||||
|
||||
#define KEY_TOGGLE 0x00200000
|
||||
|
||||
namespace Input {
|
||||
using Input::Axis;
|
||||
using Libraries::Pad::OrbisPadButtonDataOffset;
|
||||
|
||||
struct AxisMapping {
|
||||
u32 axis;
|
||||
s16 value;
|
||||
AxisMapping(SDL_GamepadAxis a, s16 v) : axis(a), value(v) {}
|
||||
};
|
||||
|
||||
enum class InputType { Axis, KeyboardMouse, Controller, Count };
|
||||
const std::array<std::string, 4> input_type_names = {"Axis", "KBM", "Controller", "Unknown"};
|
||||
|
||||
class InputID {
|
||||
public:
|
||||
InputType type;
|
||||
u32 sdl_id;
|
||||
InputID(InputType d = InputType::Count, u32 i = (u32)-1) : type(d), sdl_id(i) {}
|
||||
bool operator==(const InputID& o) const {
|
||||
return type == o.type && sdl_id == o.sdl_id;
|
||||
}
|
||||
bool operator!=(const InputID& o) const {
|
||||
return type != o.type || sdl_id != o.sdl_id;
|
||||
}
|
||||
bool operator<=(const InputID& o) const {
|
||||
return type <= o.type && sdl_id <= o.sdl_id;
|
||||
}
|
||||
bool IsValid() const {
|
||||
return *this != InputID();
|
||||
}
|
||||
std::string ToString() {
|
||||
return fmt::format("({}: {:x})", input_type_names[(u8)type], sdl_id);
|
||||
}
|
||||
};
|
||||
|
||||
class InputEvent {
|
||||
public:
|
||||
InputID input;
|
||||
bool active;
|
||||
s8 axis_value;
|
||||
|
||||
InputEvent(InputID i = InputID(), bool a = false, s8 v = 0)
|
||||
: input(i), active(a), axis_value(v) {}
|
||||
InputEvent(InputType d, u32 i, bool a = false, s8 v = 0)
|
||||
: input(d, i), active(a), axis_value(v) {}
|
||||
};
|
||||
|
||||
// i strongly suggest you collapse these maps
|
||||
const std::map<std::string, u32> string_to_cbutton_map = {
|
||||
{"triangle", SDL_GAMEPAD_BUTTON_NORTH},
|
||||
{"circle", SDL_GAMEPAD_BUTTON_EAST},
|
||||
{"cross", SDL_GAMEPAD_BUTTON_SOUTH},
|
||||
{"square", SDL_GAMEPAD_BUTTON_WEST},
|
||||
{"l1", SDL_GAMEPAD_BUTTON_LEFT_SHOULDER},
|
||||
{"r1", SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER},
|
||||
{"l3", SDL_GAMEPAD_BUTTON_LEFT_STICK},
|
||||
{"r3", SDL_GAMEPAD_BUTTON_RIGHT_STICK},
|
||||
{"pad_up", SDL_GAMEPAD_BUTTON_DPAD_UP},
|
||||
{"pad_down", SDL_GAMEPAD_BUTTON_DPAD_DOWN},
|
||||
{"pad_left", SDL_GAMEPAD_BUTTON_DPAD_LEFT},
|
||||
{"pad_right", SDL_GAMEPAD_BUTTON_DPAD_RIGHT},
|
||||
{"options", SDL_GAMEPAD_BUTTON_START},
|
||||
|
||||
// these are outputs only (touchpad can only be bound to itself)
|
||||
{"touchpad", SDL_GAMEPAD_BUTTON_TOUCHPAD},
|
||||
{"leftjoystick_halfmode", LEFTJOYSTICK_HALFMODE},
|
||||
{"rightjoystick_halfmode", RIGHTJOYSTICK_HALFMODE},
|
||||
|
||||
// this is only for input
|
||||
{"back", SDL_GAMEPAD_BUTTON_BACK},
|
||||
};
|
||||
|
||||
const std::map<std::string, AxisMapping> string_to_axis_map = {
|
||||
{"axis_left_x_plus", {SDL_GAMEPAD_AXIS_LEFTX, 127}},
|
||||
{"axis_left_x_minus", {SDL_GAMEPAD_AXIS_LEFTX, -127}},
|
||||
{"axis_left_y_plus", {SDL_GAMEPAD_AXIS_LEFTY, 127}},
|
||||
{"axis_left_y_minus", {SDL_GAMEPAD_AXIS_LEFTY, -127}},
|
||||
{"axis_right_x_plus", {SDL_GAMEPAD_AXIS_RIGHTX, 127}},
|
||||
{"axis_right_x_minus", {SDL_GAMEPAD_AXIS_RIGHTX, -127}},
|
||||
{"axis_right_y_plus", {SDL_GAMEPAD_AXIS_RIGHTY, 127}},
|
||||
{"axis_right_y_minus", {SDL_GAMEPAD_AXIS_RIGHTY, -127}},
|
||||
|
||||
{"l2", {SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 127}},
|
||||
{"r2", {SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 127}},
|
||||
|
||||
// should only use these to bind analog inputs to analog outputs
|
||||
{"axis_left_x", {SDL_GAMEPAD_AXIS_LEFTX, 127}},
|
||||
{"axis_left_y", {SDL_GAMEPAD_AXIS_LEFTY, 127}},
|
||||
{"axis_right_x", {SDL_GAMEPAD_AXIS_RIGHTX, 127}},
|
||||
{"axis_right_y", {SDL_GAMEPAD_AXIS_RIGHTY, 127}},
|
||||
};
|
||||
const std::map<std::string, u32> string_to_keyboard_key_map = {
|
||||
{"a", SDLK_A},
|
||||
{"b", SDLK_B},
|
||||
{"c", SDLK_C},
|
||||
{"d", SDLK_D},
|
||||
{"e", SDLK_E},
|
||||
{"f", SDLK_F},
|
||||
{"g", SDLK_G},
|
||||
{"h", SDLK_H},
|
||||
{"i", SDLK_I},
|
||||
{"j", SDLK_J},
|
||||
{"k", SDLK_K},
|
||||
{"l", SDLK_L},
|
||||
{"m", SDLK_M},
|
||||
{"n", SDLK_N},
|
||||
{"o", SDLK_O},
|
||||
{"p", SDLK_P},
|
||||
{"q", SDLK_Q},
|
||||
{"r", SDLK_R},
|
||||
{"s", SDLK_S},
|
||||
{"t", SDLK_T},
|
||||
{"u", SDLK_U},
|
||||
{"v", SDLK_V},
|
||||
{"w", SDLK_W},
|
||||
{"x", SDLK_X},
|
||||
{"y", SDLK_Y},
|
||||
{"z", SDLK_Z},
|
||||
{"0", SDLK_0},
|
||||
{"1", SDLK_1},
|
||||
{"2", SDLK_2},
|
||||
{"3", SDLK_3},
|
||||
{"4", SDLK_4},
|
||||
{"5", SDLK_5},
|
||||
{"6", SDLK_6},
|
||||
{"7", SDLK_7},
|
||||
{"8", SDLK_8},
|
||||
{"9", SDLK_9},
|
||||
{"kp0", SDLK_KP_0},
|
||||
{"kp1", SDLK_KP_1},
|
||||
{"kp2", SDLK_KP_2},
|
||||
{"kp3", SDLK_KP_3},
|
||||
{"kp4", SDLK_KP_4},
|
||||
{"kp5", SDLK_KP_5},
|
||||
{"kp6", SDLK_KP_6},
|
||||
{"kp7", SDLK_KP_7},
|
||||
{"kp8", SDLK_KP_8},
|
||||
{"kp9", SDLK_KP_9},
|
||||
{"comma", SDLK_COMMA},
|
||||
{"period", SDLK_PERIOD},
|
||||
{"question", SDLK_QUESTION},
|
||||
{"semicolon", SDLK_SEMICOLON},
|
||||
{"minus", SDLK_MINUS},
|
||||
{"underscore", SDLK_UNDERSCORE},
|
||||
{"lparenthesis", SDLK_LEFTPAREN},
|
||||
{"rparenthesis", SDLK_RIGHTPAREN},
|
||||
{"lbracket", SDLK_LEFTBRACKET},
|
||||
{"rbracket", SDLK_RIGHTBRACKET},
|
||||
{"lbrace", SDLK_LEFTBRACE},
|
||||
{"rbrace", SDLK_RIGHTBRACE},
|
||||
{"backslash", SDLK_BACKSLASH},
|
||||
{"dash", SDLK_SLASH},
|
||||
{"enter", SDLK_RETURN},
|
||||
{"space", SDLK_SPACE},
|
||||
{"tab", SDLK_TAB},
|
||||
{"backspace", SDLK_BACKSPACE},
|
||||
{"escape", SDLK_ESCAPE},
|
||||
{"left", SDLK_LEFT},
|
||||
{"right", SDLK_RIGHT},
|
||||
{"up", SDLK_UP},
|
||||
{"down", SDLK_DOWN},
|
||||
{"lctrl", SDLK_LCTRL},
|
||||
{"rctrl", SDLK_RCTRL},
|
||||
{"lshift", SDLK_LSHIFT},
|
||||
{"rshift", SDLK_RSHIFT},
|
||||
{"lalt", SDLK_LALT},
|
||||
{"ralt", SDLK_RALT},
|
||||
{"lmeta", SDLK_LGUI},
|
||||
{"rmeta", SDLK_RGUI},
|
||||
{"lwin", SDLK_LGUI},
|
||||
{"rwin", SDLK_RGUI},
|
||||
{"home", SDLK_HOME},
|
||||
{"end", SDLK_END},
|
||||
{"pgup", SDLK_PAGEUP},
|
||||
{"pgdown", SDLK_PAGEDOWN},
|
||||
{"leftbutton", SDL_BUTTON_LEFT},
|
||||
{"rightbutton", SDL_BUTTON_RIGHT},
|
||||
{"middlebutton", SDL_BUTTON_MIDDLE},
|
||||
{"sidebuttonback", SDL_BUTTON_X1},
|
||||
{"sidebuttonforward", SDL_BUTTON_X2},
|
||||
{"mousewheelup", SDL_MOUSE_WHEEL_UP},
|
||||
{"mousewheeldown", SDL_MOUSE_WHEEL_DOWN},
|
||||
{"mousewheelleft", SDL_MOUSE_WHEEL_LEFT},
|
||||
{"mousewheelright", SDL_MOUSE_WHEEL_RIGHT},
|
||||
{"kpperiod", SDLK_KP_PERIOD},
|
||||
{"kpcomma", SDLK_KP_COMMA},
|
||||
{"kpdivide", SDLK_KP_DIVIDE},
|
||||
{"kpmultiply", SDLK_KP_MULTIPLY},
|
||||
{"kpminus", SDLK_KP_MINUS},
|
||||
{"kpplus", SDLK_KP_PLUS},
|
||||
{"kpenter", SDLK_KP_ENTER},
|
||||
{"kpequals", SDLK_KP_EQUALS},
|
||||
{"capslock", SDLK_CAPSLOCK},
|
||||
};
|
||||
|
||||
void ParseInputConfig(const std::string game_id);
|
||||
|
||||
class InputBinding {
|
||||
public:
|
||||
InputID keys[3];
|
||||
InputBinding(InputID k1 = InputID(), InputID k2 = InputID(), InputID k3 = InputID()) {
|
||||
// we format the keys so comparing them will be very fast, because we will only have to
|
||||
// compare 3 sorted elements, where the only possible duplicate item is 0
|
||||
|
||||
// duplicate entries get changed to one original, one null
|
||||
if (k1 == k2 && k1 != InputID()) {
|
||||
k2 = InputID();
|
||||
}
|
||||
if (k1 == k3 && k1 != InputID()) {
|
||||
k3 = InputID();
|
||||
}
|
||||
if (k3 == k2 && k2 != InputID()) {
|
||||
k2 = InputID();
|
||||
}
|
||||
// this sorts them
|
||||
if (k1 <= k2 && k1 <= k3) {
|
||||
keys[0] = k1;
|
||||
if (k2 <= k3) {
|
||||
keys[1] = k2;
|
||||
keys[2] = k3;
|
||||
} else {
|
||||
keys[1] = k3;
|
||||
keys[2] = k2;
|
||||
}
|
||||
} else if (k2 <= k1 && k2 <= k3) {
|
||||
keys[0] = k2;
|
||||
if (k1 <= k3) {
|
||||
keys[1] = k1;
|
||||
keys[2] = k3;
|
||||
} else {
|
||||
keys[1] = k3;
|
||||
keys[2] = k1;
|
||||
}
|
||||
} else {
|
||||
keys[0] = k3;
|
||||
if (k1 <= k2) {
|
||||
keys[1] = k1;
|
||||
keys[2] = k2;
|
||||
} else {
|
||||
keys[1] = k2;
|
||||
keys[3] = k1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy ctor
|
||||
InputBinding(const InputBinding& o) {
|
||||
keys[0] = o.keys[0];
|
||||
keys[1] = o.keys[1];
|
||||
keys[2] = o.keys[2];
|
||||
}
|
||||
|
||||
inline bool operator==(const InputBinding& o) {
|
||||
// InputID() signifies an unused slot
|
||||
return (keys[0] == o.keys[0] || keys[0] == InputID() || o.keys[0] == InputID()) &&
|
||||
(keys[1] == o.keys[1] || keys[1] == InputID() || o.keys[1] == InputID()) &&
|
||||
(keys[2] == o.keys[2] || keys[2] == InputID() || o.keys[2] == InputID());
|
||||
// it is already very fast,
|
||||
// but reverse order makes it check the actual keys first instead of possible 0-s,
|
||||
// potenially skipping the later expressions of the three-way AND
|
||||
}
|
||||
inline int KeyCount() const {
|
||||
return (keys[0].IsValid() ? 1 : 0) + (keys[1].IsValid() ? 1 : 0) +
|
||||
(keys[2].IsValid() ? 1 : 0);
|
||||
}
|
||||
// Sorts by the amount of non zero keys - left side is 'bigger' here
|
||||
bool operator<(const InputBinding& other) const {
|
||||
return KeyCount() > other.KeyCount();
|
||||
}
|
||||
inline bool IsEmpty() {
|
||||
return !(keys[0].IsValid() || keys[1].IsValid() || keys[2].IsValid());
|
||||
}
|
||||
std::string ToString() { // todo add device type
|
||||
switch (KeyCount()) {
|
||||
case 1:
|
||||
return fmt::format("({})", keys[0].ToString());
|
||||
case 2:
|
||||
return fmt::format("({}, {})", keys[0].ToString(), keys[1].ToString());
|
||||
case 3:
|
||||
return fmt::format("({}, {}, {})", keys[0].ToString(), keys[1].ToString(),
|
||||
keys[2].ToString());
|
||||
default:
|
||||
return "Empty";
|
||||
}
|
||||
}
|
||||
|
||||
// returns an InputEvent based on the event type (keyboard, mouse buttons/wheel, or controller)
|
||||
static InputEvent GetInputEventFromSDLEvent(const SDL_Event& e);
|
||||
};
|
||||
class ControllerOutput {
|
||||
static GameController* controller;
|
||||
|
||||
public:
|
||||
static void SetControllerOutputController(GameController* c);
|
||||
static void LinkJoystickAxes();
|
||||
|
||||
u32 button;
|
||||
u32 axis;
|
||||
// these are only used as s8,
|
||||
// but I added some padding to avoid overflow if it's activated by multiple inputs
|
||||
// axis_plus and axis_minus pairs share a common new_param, the other outputs have their own
|
||||
s16 old_param;
|
||||
s16* new_param;
|
||||
bool old_button_state, new_button_state, state_changed, positive_axis;
|
||||
|
||||
ControllerOutput(const u32 b, u32 a = SDL_GAMEPAD_AXIS_INVALID, bool p = true) {
|
||||
button = b;
|
||||
axis = a;
|
||||
new_param = new s16(0);
|
||||
old_param = 0;
|
||||
positive_axis = p;
|
||||
}
|
||||
ControllerOutput(const ControllerOutput& o) : button(o.button), axis(o.axis) {
|
||||
new_param = new s16(*o.new_param);
|
||||
}
|
||||
~ControllerOutput() {
|
||||
delete new_param;
|
||||
}
|
||||
inline bool operator==(const ControllerOutput& o) const { // fucking consts everywhere
|
||||
return button == o.button && axis == o.axis;
|
||||
}
|
||||
inline bool operator!=(const ControllerOutput& o) const {
|
||||
return button != o.button || axis != o.axis;
|
||||
}
|
||||
std::string ToString() const {
|
||||
return fmt::format("({}, {}, {})", (s32)button, (int)axis, old_param);
|
||||
}
|
||||
inline bool IsButton() const {
|
||||
return axis == SDL_GAMEPAD_AXIS_INVALID && button != SDL_GAMEPAD_BUTTON_INVALID;
|
||||
}
|
||||
inline bool IsAxis() const {
|
||||
return axis != SDL_GAMEPAD_AXIS_INVALID && button == SDL_GAMEPAD_BUTTON_INVALID;
|
||||
}
|
||||
|
||||
void ResetUpdate();
|
||||
void AddUpdate(InputEvent event);
|
||||
void FinalizeUpdate();
|
||||
};
|
||||
class BindingConnection {
|
||||
public:
|
||||
InputBinding binding;
|
||||
ControllerOutput* output;
|
||||
u32 axis_param;
|
||||
InputID toggle;
|
||||
|
||||
BindingConnection(InputBinding b, ControllerOutput* out, u32 param = 0, InputID t = InputID()) {
|
||||
binding = b;
|
||||
axis_param = param;
|
||||
output = out;
|
||||
toggle = t;
|
||||
}
|
||||
bool operator<(const BindingConnection& other) const {
|
||||
// a button is a higher priority than an axis, as buttons can influence axes
|
||||
// (e.g. joystick_halfmode)
|
||||
if (output->IsButton() &&
|
||||
(other.output->IsAxis() && (other.output->axis != SDL_GAMEPAD_AXIS_LEFT_TRIGGER &&
|
||||
other.output->axis != SDL_GAMEPAD_AXIS_RIGHT_TRIGGER))) {
|
||||
return true;
|
||||
}
|
||||
if (binding < other.binding) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
InputEvent ProcessBinding();
|
||||
};
|
||||
|
||||
// Updates the list of pressed keys with the given input.
|
||||
// Returns whether the list was updated or not.
|
||||
bool UpdatePressedKeys(InputEvent event);
|
||||
|
||||
void ActivateOutputsFromInputs();
|
||||
|
||||
} // namespace Input
|
74
src/input/input_mouse.cpp
Normal file
74
src/input/input_mouse.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "input/controller.h"
|
||||
#include "input_mouse.h"
|
||||
|
||||
#include "SDL3/SDL.h"
|
||||
|
||||
namespace Input {
|
||||
|
||||
int mouse_joystick_binding = 0;
|
||||
float mouse_deadzone_offset = 0.5, mouse_speed = 1, mouse_speed_offset = 0.1250;
|
||||
Uint32 mouse_polling_id = 0;
|
||||
bool mouse_enabled = false;
|
||||
|
||||
// We had to go through 3 files of indirection just to update a flag
|
||||
void ToggleMouseEnabled() {
|
||||
mouse_enabled = !mouse_enabled;
|
||||
}
|
||||
|
||||
void SetMouseToJoystick(int joystick) {
|
||||
mouse_joystick_binding = joystick;
|
||||
}
|
||||
|
||||
void SetMouseParams(float mdo, float ms, float mso) {
|
||||
mouse_deadzone_offset = mdo;
|
||||
mouse_speed = ms;
|
||||
mouse_speed_offset = mso;
|
||||
}
|
||||
|
||||
Uint32 MousePolling(void* param, Uint32 id, Uint32 interval) {
|
||||
auto* controller = (GameController*)param;
|
||||
if (!mouse_enabled)
|
||||
return interval;
|
||||
|
||||
Axis axis_x, axis_y;
|
||||
switch (mouse_joystick_binding) {
|
||||
case 1:
|
||||
axis_x = Axis::LeftX;
|
||||
axis_y = Axis::LeftY;
|
||||
break;
|
||||
case 2:
|
||||
axis_x = Axis::RightX;
|
||||
axis_y = Axis::RightY;
|
||||
break;
|
||||
default:
|
||||
return interval; // no update needed
|
||||
}
|
||||
|
||||
float d_x = 0, d_y = 0;
|
||||
SDL_GetRelativeMouseState(&d_x, &d_y);
|
||||
|
||||
float output_speed =
|
||||
SDL_clamp((sqrt(d_x * d_x + d_y * d_y) + mouse_speed_offset * 128) * mouse_speed,
|
||||
mouse_deadzone_offset * 128, 128.0);
|
||||
|
||||
float angle = atan2(d_y, d_x);
|
||||
float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed;
|
||||
|
||||
if (d_x != 0 && d_y != 0) {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, a_x));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, a_y));
|
||||
} else {
|
||||
controller->Axis(0, axis_x, GetAxis(-0x80, 0x80, 0));
|
||||
controller->Axis(0, axis_y, GetAxis(-0x80, 0x80, 0));
|
||||
}
|
||||
|
||||
return interval;
|
||||
}
|
||||
|
||||
} // namespace Input
|
18
src/input/input_mouse.h
Normal file
18
src/input/input_mouse.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SDL3/SDL.h"
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Input {
|
||||
|
||||
void ToggleMouseEnabled();
|
||||
void SetMouseToJoystick(int joystick);
|
||||
void SetMouseParams(float mouse_deadzone_offset, float mouse_speed, float mouse_speed_offset);
|
||||
|
||||
// Polls the mouse for changes, and simulates joystick movement from it.
|
||||
Uint32 MousePolling(void* param, Uint32 id, Uint32 interval);
|
||||
|
||||
} // namespace Input
|
|
@ -167,12 +167,12 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
// Check if the provided path is a valid file
|
||||
if (!std::filesystem::exists(eboot_path)) {
|
||||
// If not a file, treat it as a game ID and search in install directories
|
||||
// If not a file, treat it as a game ID and search in install directories recursively
|
||||
bool game_found = false;
|
||||
const int max_depth = 5;
|
||||
for (const auto& install_dir : Config::getGameInstallDirs()) {
|
||||
const auto candidate_path = install_dir / game_path / "eboot.bin";
|
||||
if (std::filesystem::exists(candidate_path)) {
|
||||
eboot_path = candidate_path;
|
||||
if (auto found_path = Common::FS::FindGameByID(install_dir, game_path, max_depth)) {
|
||||
eboot_path = *found_path;
|
||||
game_found = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -146,14 +146,14 @@ void CheckUpdate::CheckForUpdates(const bool showMessage) {
|
|||
}
|
||||
|
||||
QString currentRev = (updateChannel == "Nightly")
|
||||
? QString::fromStdString(Common::g_scm_rev).left(7)
|
||||
? QString::fromStdString(Common::g_scm_rev)
|
||||
: "v." + QString::fromStdString(Common::VERSION);
|
||||
QString currentDate = Common::g_scm_date;
|
||||
|
||||
QDateTime dateTime = QDateTime::fromString(latestDate, Qt::ISODate);
|
||||
latestDate = dateTime.isValid() ? dateTime.toString("yyyy-MM-dd HH:mm:ss") : "Unknown date";
|
||||
|
||||
if (latestRev == currentRev) {
|
||||
if (latestRev == currentRev.left(7)) {
|
||||
if (showMessage) {
|
||||
QMessageBox::information(this, tr("Auto Updater"),
|
||||
tr("Your version is already up to date!"));
|
||||
|
@ -190,7 +190,7 @@ void CheckUpdate::setupUI(const QString& downloadUrl, const QString& latestDate,
|
|||
QString("<p><b><br>" + tr("Update Channel") + ": </b>" + updateChannel + "<br><b>" +
|
||||
tr("Current Version") + ":</b> %1 (%2)<br><b>" + tr("Latest Version") +
|
||||
":</b> %3 (%4)</p><p>" + tr("Do you want to update?") + "</p>")
|
||||
.arg(currentRev, currentDate, latestRev, latestDate);
|
||||
.arg(currentRev.left(7), currentDate, latestRev, latestDate);
|
||||
QLabel* updateLabel = new QLabel(updateText, this);
|
||||
layout->addWidget(updateLabel);
|
||||
|
||||
|
|
|
@ -260,3 +260,22 @@ void CompatibilityInfoClass::ExtractCompatibilityInfo(QByteArray response) {
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
const QString CompatibilityInfoClass::GetCompatStatusString(const CompatibilityStatus status) {
|
||||
switch (status) {
|
||||
case CompatibilityStatus::Unknown:
|
||||
return tr("Unknown");
|
||||
case CompatibilityStatus::Nothing:
|
||||
return tr("Nothing");
|
||||
case CompatibilityStatus::Boots:
|
||||
return tr("Boots");
|
||||
case CompatibilityStatus::Menus:
|
||||
return tr("Menus");
|
||||
case CompatibilityStatus::Ingame:
|
||||
return tr("Ingame");
|
||||
case CompatibilityStatus::Playable:
|
||||
return tr("Playable");
|
||||
default:
|
||||
return tr("Unknown");
|
||||
}
|
||||
}
|
|
@ -69,13 +69,6 @@ public:
|
|||
{QStringLiteral("os-windows"), OSType::Win32},
|
||||
};
|
||||
|
||||
inline static const std::unordered_map<CompatibilityStatus, QString> CompatStatusToString = {
|
||||
{CompatibilityStatus::Unknown, QStringLiteral("Unknown")},
|
||||
{CompatibilityStatus::Nothing, QStringLiteral("Nothing")},
|
||||
{CompatibilityStatus::Boots, QStringLiteral("Boots")},
|
||||
{CompatibilityStatus::Menus, QStringLiteral("Menus")},
|
||||
{CompatibilityStatus::Ingame, QStringLiteral("Ingame")},
|
||||
{CompatibilityStatus::Playable, QStringLiteral("Playable")}};
|
||||
inline static const std::unordered_map<OSType, QString> OSTypeToString = {
|
||||
{OSType::Linux, QStringLiteral("os-linux")},
|
||||
{OSType::macOS, QStringLiteral("os-macOS")},
|
||||
|
@ -87,6 +80,7 @@ public:
|
|||
void UpdateCompatibilityDatabase(QWidget* parent = nullptr, bool forced = false);
|
||||
bool LoadCompatibilityFile();
|
||||
CompatibilityEntry GetCompatibilityInfo(const std::string& serial);
|
||||
const QString GetCompatStatusString(const CompatibilityStatus status);
|
||||
void ExtractCompatibilityInfo(QByteArray response);
|
||||
static bool WaitForReply(QNetworkReply* reply);
|
||||
QNetworkReply* FetchPage(int page_num);
|
||||
|
|
|
@ -38,17 +38,18 @@ GameGridFrame::GameGridFrame(std::shared_ptr<GameInfoClass> game_info_get,
|
|||
|
||||
void GameGridFrame::onCurrentCellChanged(int currentRow, int currentColumn, int previousRow,
|
||||
int previousColumn) {
|
||||
cellClicked = true;
|
||||
crtRow = currentRow;
|
||||
crtColumn = currentColumn;
|
||||
columnCnt = this->columnCount();
|
||||
|
||||
auto itemID = (crtRow * columnCnt) + currentColumn;
|
||||
if (itemID > m_game_info->m_games.count() - 1) {
|
||||
cellClicked = false;
|
||||
validCellSelected = false;
|
||||
BackgroundMusicPlayer::getInstance().stopMusic();
|
||||
return;
|
||||
}
|
||||
cellClicked = true;
|
||||
validCellSelected = true;
|
||||
SetGridBackgroundImage(crtRow, crtColumn);
|
||||
auto snd0Path = QString::fromStdString(m_game_info->m_games[itemID].snd0_path.string());
|
||||
|
|
|
@ -7,6 +7,33 @@
|
|||
#include "compatibility_info.h"
|
||||
#include "game_info.h"
|
||||
|
||||
// Maximum depth to search for games in subdirectories
|
||||
const int max_recursion_depth = 5;
|
||||
|
||||
void ScanDirectoryRecursively(const QString& dir, QStringList& filePaths, int current_depth = 0) {
|
||||
// Stop recursion if we've reached the maximum depth
|
||||
if (current_depth >= max_recursion_depth) {
|
||||
return;
|
||||
}
|
||||
|
||||
QDir directory(dir);
|
||||
QFileInfoList entries = directory.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
|
||||
for (const auto& entry : entries) {
|
||||
if (entry.fileName().endsWith("-UPDATE")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this directory contains a PS4 game (has sce_sys/param.sfo)
|
||||
if (QFile::exists(entry.filePath() + "/sce_sys/param.sfo")) {
|
||||
filePaths.append(entry.absoluteFilePath());
|
||||
} else {
|
||||
// If not a game directory, recursively scan it with increased depth
|
||||
ScanDirectoryRecursively(entry.absoluteFilePath(), filePaths, current_depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameInfoClass::GameInfoClass() = default;
|
||||
GameInfoClass::~GameInfoClass() = default;
|
||||
|
||||
|
@ -15,13 +42,7 @@ void GameInfoClass::GetGameInfo(QWidget* parent) {
|
|||
for (const auto& installLoc : Config::getGameInstallDirs()) {
|
||||
QString installDir;
|
||||
Common::FS::PathToQString(installDir, installLoc);
|
||||
QDir parentFolder(installDir);
|
||||
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (const auto& fileInfo : fileList) {
|
||||
if (fileInfo.isDir() && !fileInfo.filePath().endsWith("-UPDATE")) {
|
||||
filePaths.append(fileInfo.absoluteFilePath());
|
||||
}
|
||||
}
|
||||
ScanDirectoryRecursively(installDir, filePaths, 0);
|
||||
}
|
||||
|
||||
m_games = QtConcurrent::mapped(filePaths, [&](const QString& path) {
|
||||
|
|
|
@ -69,7 +69,7 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get,
|
|||
ListSortedAsc = true;
|
||||
}
|
||||
this->clearContents();
|
||||
PopulateGameList();
|
||||
PopulateGameList(false);
|
||||
});
|
||||
|
||||
connect(this, &QTableWidget::customContextMenuRequested, this, [=, this](const QPoint& pos) {
|
||||
|
@ -103,7 +103,7 @@ void GameListFrame::PlayBackgroundMusic(QTableWidgetItem* item) {
|
|||
BackgroundMusicPlayer::getInstance().playMusic(snd0path);
|
||||
}
|
||||
|
||||
void GameListFrame::PopulateGameList() {
|
||||
void GameListFrame::PopulateGameList(bool isInitialPopulation) {
|
||||
// Do not show status column if it is not enabled
|
||||
this->setColumnHidden(2, !Config::getCompatibilityEnabled());
|
||||
this->setColumnHidden(6, !Config::GetLoadGameSizeEnabled());
|
||||
|
@ -111,6 +111,11 @@ void GameListFrame::PopulateGameList() {
|
|||
this->setRowCount(m_game_info->m_games.size());
|
||||
ResizeIcons(icon_size);
|
||||
|
||||
if (isInitialPopulation) {
|
||||
SortNameAscending(1); // Column 1 = Name
|
||||
ResizeIcons(icon_size);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_game_info->m_games.size(); i++) {
|
||||
SetTableItem(i, 1, QString::fromStdString(m_game_info->m_games[i].name));
|
||||
SetTableItem(i, 3, QString::fromStdString(m_game_info->m_games[i].serial));
|
||||
|
@ -284,7 +289,7 @@ void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityEntry
|
|||
QLabel* dotLabel = new QLabel("", widget);
|
||||
dotLabel->setPixmap(circle_pixmap);
|
||||
|
||||
QLabel* label = new QLabel(m_compat_info->CompatStatusToString.at(entry.status), widget);
|
||||
QLabel* label = new QLabel(m_compat_info->GetCompatStatusString(entry.status), widget);
|
||||
|
||||
label->setStyleSheet("color: white; font-size: 16px; font-weight: bold;");
|
||||
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm> // std::transform
|
||||
#include <cctype> // std::tolower
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
|
@ -43,7 +46,7 @@ private:
|
|||
bool ListSortedAsc = true;
|
||||
|
||||
public:
|
||||
void PopulateGameList();
|
||||
void PopulateGameList(bool isInitialPopulation = true);
|
||||
void ResizeIcons(int iconSize);
|
||||
|
||||
QImage backgroundImage;
|
||||
|
@ -65,8 +68,12 @@ public:
|
|||
|
||||
static bool CompareStringsAscending(GameInfo a, GameInfo b, int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 1:
|
||||
return a.name < b.name;
|
||||
case 1: {
|
||||
std::string name_a = a.name, name_b = b.name;
|
||||
std::transform(name_a.begin(), name_a.end(), name_a.begin(), ::tolower);
|
||||
std::transform(name_b.begin(), name_b.end(), name_b.begin(), ::tolower);
|
||||
return name_a < name_b;
|
||||
}
|
||||
case 2:
|
||||
return a.compatibility.status < b.compatibility.status;
|
||||
case 3:
|
||||
|
@ -90,8 +97,12 @@ public:
|
|||
|
||||
static bool CompareStringsDescending(GameInfo a, GameInfo b, int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case 1:
|
||||
return a.name > b.name;
|
||||
case 1: {
|
||||
std::string name_a = a.name, name_b = b.name;
|
||||
std::transform(name_a.begin(), name_a.end(), name_a.begin(), ::tolower);
|
||||
std::transform(name_b.begin(), name_b.end(), name_b.begin(), ::tolower);
|
||||
return name_a > name_b;
|
||||
}
|
||||
case 2:
|
||||
return a.compatibility.status > b.compatibility.status;
|
||||
case 3:
|
||||
|
|
|
@ -41,8 +41,8 @@ public:
|
|||
itemID = widget->currentRow() * widget->columnCount() + widget->currentColumn();
|
||||
}
|
||||
|
||||
// Do not show the menu if an item is selected
|
||||
if (itemID == -1) {
|
||||
// Do not show the menu if no item is selected
|
||||
if (itemID < 0 || itemID >= m_games.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -52,10 +52,12 @@ public:
|
|||
// "Open Folder..." submenu
|
||||
QMenu* openFolderMenu = new QMenu(tr("Open Folder..."), widget);
|
||||
QAction* openGameFolder = new QAction(tr("Open Game Folder"), widget);
|
||||
QAction* openUpdateFolder = new QAction(tr("Open Update Folder"), widget);
|
||||
QAction* openSaveDataFolder = new QAction(tr("Open Save Data Folder"), widget);
|
||||
QAction* openLogFolder = new QAction(tr("Open Log Folder"), widget);
|
||||
|
||||
openFolderMenu->addAction(openGameFolder);
|
||||
openFolderMenu->addAction(openUpdateFolder);
|
||||
openFolderMenu->addAction(openSaveDataFolder);
|
||||
openFolderMenu->addAction(openLogFolder);
|
||||
|
||||
|
@ -87,10 +89,12 @@ public:
|
|||
QMenu* deleteMenu = new QMenu(tr("Delete..."), widget);
|
||||
QAction* deleteGame = new QAction(tr("Delete Game"), widget);
|
||||
QAction* deleteUpdate = new QAction(tr("Delete Update"), widget);
|
||||
QAction* deleteSaveData = new QAction(tr("Delete Save Data"), widget);
|
||||
QAction* deleteDLC = new QAction(tr("Delete DLC"), widget);
|
||||
|
||||
deleteMenu->addAction(deleteGame);
|
||||
deleteMenu->addAction(deleteUpdate);
|
||||
deleteMenu->addAction(deleteSaveData);
|
||||
deleteMenu->addAction(deleteDLC);
|
||||
|
||||
menu.addMenu(deleteMenu);
|
||||
|
@ -122,6 +126,18 @@ public:
|
|||
QDesktopServices::openUrl(QUrl::fromLocalFile(folderPath));
|
||||
}
|
||||
|
||||
if (selected == openUpdateFolder) {
|
||||
QString open_update_path;
|
||||
Common::FS::PathToQString(open_update_path, m_games[itemID].path);
|
||||
open_update_path += "-UPDATE";
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
if (selected == openSaveDataFolder) {
|
||||
QString userPath;
|
||||
Common::FS::PathToQString(userPath,
|
||||
|
@ -143,7 +159,7 @@ public:
|
|||
PSF psf;
|
||||
std::filesystem::path game_folder_path = m_games[itemID].path;
|
||||
std::filesystem::path game_update_path = game_folder_path;
|
||||
game_update_path += "UPDATE";
|
||||
game_update_path += "-UPDATE";
|
||||
if (std::filesystem::exists(game_update_path)) {
|
||||
game_folder_path = game_update_path;
|
||||
}
|
||||
|
@ -238,6 +254,11 @@ public:
|
|||
QString trophyPath, gameTrpPath;
|
||||
Common::FS::PathToQString(trophyPath, m_games[itemID].serial);
|
||||
Common::FS::PathToQString(gameTrpPath, m_games[itemID].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);
|
||||
}
|
||||
TrophyViewer* trophyViewer = new TrophyViewer(trophyPath, gameTrpPath);
|
||||
trophyViewer->show();
|
||||
connect(widget->parent(), &QWidget::destroyed, trophyViewer,
|
||||
|
@ -335,14 +356,18 @@ public:
|
|||
clipboard->setText(combinedText);
|
||||
}
|
||||
|
||||
if (selected == deleteGame || selected == deleteUpdate || selected == deleteDLC) {
|
||||
if (selected == deleteGame || selected == deleteUpdate || selected == deleteDLC ||
|
||||
selected == deleteSaveData) {
|
||||
bool error = false;
|
||||
QString folder_path, game_update_path, dlc_path;
|
||||
QString folder_path, game_update_path, dlc_path, save_data_path;
|
||||
Common::FS::PathToQString(folder_path, m_games[itemID].path);
|
||||
game_update_path = folder_path + "-UPDATE";
|
||||
Common::FS::PathToQString(
|
||||
dlc_path, Config::getAddonInstallDir() /
|
||||
Common::FS::PathFromQString(folder_path).parent_path().filename());
|
||||
Common::FS::PathToQString(save_data_path,
|
||||
Common::FS::GetUserPath(Common::FS::PathType::UserDir) /
|
||||
"savedata/1" / m_games[itemID].serial);
|
||||
QString message_type = tr("Game");
|
||||
|
||||
if (selected == deleteUpdate) {
|
||||
|
@ -363,6 +388,15 @@ public:
|
|||
folder_path = dlc_path;
|
||||
message_type = tr("DLC");
|
||||
}
|
||||
} else if (selected == deleteSaveData) {
|
||||
if (!std::filesystem::exists(Common::FS::PathFromQString(save_data_path))) {
|
||||
QMessageBox::critical(nullptr, tr("Error"),
|
||||
QString(tr("This game has no save data to delete!")));
|
||||
error = true;
|
||||
} else {
|
||||
folder_path = save_data_path;
|
||||
message_type = tr("Save Data");
|
||||
}
|
||||
}
|
||||
if (!error) {
|
||||
QString gameName = QString::fromStdString(m_games[itemID].name);
|
||||
|
@ -374,7 +408,10 @@ public:
|
|||
QMessageBox::Yes | QMessageBox::No);
|
||||
if (reply == QMessageBox::Yes) {
|
||||
dir.removeRecursively();
|
||||
widget->removeRow(itemID);
|
||||
if (selected == deleteGame) {
|
||||
widget->removeRow(itemID);
|
||||
m_games.removeAt(itemID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
|
@ -15,10 +16,11 @@
|
|||
#include "install_dir_select.h"
|
||||
|
||||
InstallDirSelect::InstallDirSelect() : selected_dir() {
|
||||
selected_dir = Config::getGameInstallDirs().empty() ? "" : Config::getGameInstallDirs().front();
|
||||
auto install_dirs = Config::getGameInstallDirs();
|
||||
selected_dir = install_dirs.empty() ? "" : install_dirs.front();
|
||||
|
||||
if (!Config::getGameInstallDirs().empty() && Config::getGameInstallDirs().size() == 1) {
|
||||
reject();
|
||||
if (!install_dirs.empty() && install_dirs.size() == 1) {
|
||||
accept();
|
||||
}
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
|
@ -53,6 +55,14 @@ QWidget* InstallDirSelect::SetupInstallDirList() {
|
|||
|
||||
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;
|
||||
}
|
||||
|
@ -66,6 +76,14 @@ void InstallDirSelect::setSelectedDirectory(QListWidgetItem* item) {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -22,9 +22,21 @@ public:
|
|||
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;
|
||||
};
|
||||
|
|
248
src/qt_gui/kbm_config_dialog.cpp
Normal file
248
src/qt_gui/kbm_config_dialog.cpp
Normal file
|
@ -0,0 +1,248 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "kbm_config_dialog.h"
|
||||
#include "kbm_help_dialog.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include "common/config.h"
|
||||
#include "common/path_util.h"
|
||||
#include "game_info.h"
|
||||
#include "src/sdl_window.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QComboBox>
|
||||
#include <QFile>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTextStream>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
QString previous_game = "default";
|
||||
bool isHelpOpen = false;
|
||||
HelpDialog* helpDialog;
|
||||
|
||||
EditorDialog::EditorDialog(QWidget* parent) : QDialog(parent) {
|
||||
|
||||
setWindowTitle("Edit Keyboard + Mouse and Controller input bindings");
|
||||
resize(600, 400);
|
||||
|
||||
// Create the editor widget
|
||||
editor = new QPlainTextEdit(this);
|
||||
editorFont.setPointSize(10); // Set default text size
|
||||
editor->setFont(editorFont); // Apply font to the editor
|
||||
|
||||
// Create the game selection combo box
|
||||
gameComboBox = new QComboBox(this);
|
||||
gameComboBox->addItem("default"); // Add default option
|
||||
/*
|
||||
gameComboBox = new QComboBox(this);
|
||||
layout->addWidget(gameComboBox); // Add the combobox for selecting game configurations
|
||||
|
||||
// Populate the combo box with game configurations
|
||||
QStringList gameConfigs = GameInfoClass::GetGameInfo(this);
|
||||
gameComboBox->addItems(gameConfigs);
|
||||
gameComboBox->setCurrentText("default.ini"); // Set the default selection
|
||||
*/
|
||||
// Load all installed games
|
||||
loadInstalledGames();
|
||||
|
||||
QCheckBox* unifiedInputCheckBox = new QCheckBox("Use Per-Game configs", this);
|
||||
unifiedInputCheckBox->setChecked(!Config::GetUseUnifiedInputConfig());
|
||||
|
||||
// Connect checkbox signal
|
||||
connect(unifiedInputCheckBox, &QCheckBox::toggled, this, [](bool checked) {
|
||||
Config::SetUseUnifiedInputConfig(!checked);
|
||||
Config::save(Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml");
|
||||
});
|
||||
// Create Save, Cancel, and Help buttons
|
||||
Config::SetUseUnifiedInputConfig(!Config::GetUseUnifiedInputConfig());
|
||||
QPushButton* saveButton = new QPushButton("Save", this);
|
||||
QPushButton* cancelButton = new QPushButton("Cancel", this);
|
||||
QPushButton* helpButton = new QPushButton("Help", this);
|
||||
QPushButton* defaultButton = new QPushButton("Default", this);
|
||||
|
||||
// Layout for the game selection and buttons
|
||||
QHBoxLayout* topLayout = new QHBoxLayout();
|
||||
topLayout->addWidget(unifiedInputCheckBox);
|
||||
topLayout->addWidget(gameComboBox);
|
||||
topLayout->addStretch();
|
||||
topLayout->addWidget(saveButton);
|
||||
topLayout->addWidget(cancelButton);
|
||||
topLayout->addWidget(defaultButton);
|
||||
topLayout->addWidget(helpButton);
|
||||
|
||||
// Main layout with editor and buttons
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->addLayout(topLayout);
|
||||
layout->addWidget(editor);
|
||||
|
||||
// Load the default config file content into the editor
|
||||
loadFile(gameComboBox->currentText());
|
||||
|
||||
// Connect button and combo box signals
|
||||
connect(saveButton, &QPushButton::clicked, this, &EditorDialog::onSaveClicked);
|
||||
connect(cancelButton, &QPushButton::clicked, this, &EditorDialog::onCancelClicked);
|
||||
connect(helpButton, &QPushButton::clicked, this, &EditorDialog::onHelpClicked);
|
||||
connect(defaultButton, &QPushButton::clicked, this, &EditorDialog::onResetToDefaultClicked);
|
||||
connect(gameComboBox, &QComboBox::currentTextChanged, this,
|
||||
&EditorDialog::onGameSelectionChanged);
|
||||
}
|
||||
|
||||
void EditorDialog::loadFile(QString game) {
|
||||
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile(game.toStdString());
|
||||
QFile file(config_file);
|
||||
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
editor->setPlainText(in.readAll());
|
||||
originalConfig = editor->toPlainText();
|
||||
file.close();
|
||||
} else {
|
||||
QMessageBox::warning(this, "Error", "Could not open the file for reading");
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDialog::saveFile(QString game) {
|
||||
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile(game.toStdString());
|
||||
QFile file(config_file);
|
||||
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out << editor->toPlainText();
|
||||
file.close();
|
||||
} else {
|
||||
QMessageBox::warning(this, "Error", "Could not open the file for writing");
|
||||
}
|
||||
}
|
||||
|
||||
// Override the close event to show the save confirmation dialog only if changes were made
|
||||
void EditorDialog::closeEvent(QCloseEvent* event) {
|
||||
if (isHelpOpen) {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
// at this point I might have to add this flag and the help dialog to the class itself
|
||||
}
|
||||
if (hasUnsavedChanges()) {
|
||||
QMessageBox::StandardButton reply;
|
||||
reply = QMessageBox::question(this, "Save Changes", "Do you want to save changes?",
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
|
||||
if (reply == QMessageBox::Yes) {
|
||||
saveFile(gameComboBox->currentText());
|
||||
event->accept(); // Close the dialog
|
||||
} else if (reply == QMessageBox::No) {
|
||||
event->accept(); // Close the dialog without saving
|
||||
} else {
|
||||
event->ignore(); // Cancel the close event
|
||||
}
|
||||
} else {
|
||||
event->accept(); // No changes, close the dialog without prompting
|
||||
}
|
||||
}
|
||||
void EditorDialog::keyPressEvent(QKeyEvent* event) {
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
if (isHelpOpen) {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
}
|
||||
close(); // Trigger the close action, same as pressing the close button
|
||||
} else {
|
||||
QDialog::keyPressEvent(event); // Call the base class implementation for other keys
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDialog::onSaveClicked() {
|
||||
if (isHelpOpen) {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
}
|
||||
saveFile(gameComboBox->currentText());
|
||||
reject(); // Close the dialog
|
||||
}
|
||||
|
||||
void EditorDialog::onCancelClicked() {
|
||||
if (isHelpOpen) {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
}
|
||||
reject(); // Close the dialog
|
||||
}
|
||||
|
||||
void EditorDialog::onHelpClicked() {
|
||||
if (!isHelpOpen) {
|
||||
helpDialog = new HelpDialog(&isHelpOpen, this);
|
||||
helpDialog->setWindowTitle("Help");
|
||||
helpDialog->setAttribute(Qt::WA_DeleteOnClose); // Clean up on close
|
||||
// Get the position and size of the Config window
|
||||
QRect configGeometry = this->geometry();
|
||||
int helpX = configGeometry.x() + configGeometry.width() + 10; // 10 pixels offset
|
||||
int helpY = configGeometry.y();
|
||||
// Move the Help dialog to the right side of the Config window
|
||||
helpDialog->move(helpX, helpY);
|
||||
helpDialog->show();
|
||||
isHelpOpen = true;
|
||||
} else {
|
||||
helpDialog->close();
|
||||
isHelpOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorDialog::onResetToDefaultClicked() {
|
||||
bool default_default = gameComboBox->currentText() == "default";
|
||||
QString prompt =
|
||||
default_default
|
||||
? "Do you want to reset your custom default config to the original default config?"
|
||||
: "Do you want to reset this config to your custom default config?";
|
||||
QMessageBox::StandardButton reply =
|
||||
QMessageBox::question(this, "Reset to Default", prompt, QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (reply == QMessageBox::Yes) {
|
||||
if (default_default) {
|
||||
const auto default_file = Config::GetFoolproofKbmConfigFile("default");
|
||||
std::filesystem::remove(default_file);
|
||||
}
|
||||
const auto config_file = Config::GetFoolproofKbmConfigFile("default");
|
||||
QFile file(config_file);
|
||||
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
editor->setPlainText(in.readAll());
|
||||
file.close();
|
||||
} else {
|
||||
QMessageBox::warning(this, "Error", "Could not open the file for reading");
|
||||
}
|
||||
// saveFile(gameComboBox->currentText());
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorDialog::hasUnsavedChanges() {
|
||||
// Compare the current content with the original content to check if there are unsaved changes
|
||||
return editor->toPlainText() != originalConfig;
|
||||
}
|
||||
void EditorDialog::loadInstalledGames() {
|
||||
previous_game = "default";
|
||||
QStringList filePaths;
|
||||
for (const auto& installLoc : Config::getGameInstallDirs()) {
|
||||
QString installDir;
|
||||
Common::FS::PathToQString(installDir, installLoc);
|
||||
QDir parentFolder(installDir);
|
||||
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
for (const auto& fileInfo : fileList) {
|
||||
if (fileInfo.isDir() && !fileInfo.filePath().endsWith("-UPDATE")) {
|
||||
gameComboBox->addItem(fileInfo.fileName()); // Add game name to combo box
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void EditorDialog::onGameSelectionChanged(const QString& game) {
|
||||
saveFile(previous_game);
|
||||
loadFile(gameComboBox->currentText()); // Reload file based on the selected game
|
||||
previous_game = gameComboBox->currentText();
|
||||
}
|
38
src/qt_gui/kbm_config_dialog.h
Normal file
38
src/qt_gui/kbm_config_dialog.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialog>
|
||||
#include <QPlainTextEdit>
|
||||
#include "string"
|
||||
|
||||
class EditorDialog : public QDialog {
|
||||
Q_OBJECT // Necessary for using Qt's meta-object system (signals/slots)
|
||||
public : explicit EditorDialog(QWidget* parent = nullptr); // Constructor
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override; // Override close event
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
private:
|
||||
QPlainTextEdit* editor; // Editor widget for the config file
|
||||
QFont editorFont; // To handle the text size
|
||||
QString originalConfig; // Starting config string
|
||||
std::string gameId;
|
||||
|
||||
QComboBox* gameComboBox; // Combo box for selecting game configurations
|
||||
|
||||
void loadFile(QString game); // Function to load the config file
|
||||
void saveFile(QString game); // Function to save the config file
|
||||
void loadInstalledGames(); // Helper to populate gameComboBox
|
||||
bool hasUnsavedChanges(); // Checks for unsaved changes
|
||||
|
||||
private slots:
|
||||
void onSaveClicked(); // Save button slot
|
||||
void onCancelClicked(); // Slot for handling cancel button
|
||||
void onHelpClicked(); // Slot for handling help button
|
||||
void onResetToDefaultClicked();
|
||||
void onGameSelectionChanged(const QString& game); // Slot for game selection changes
|
||||
};
|
112
src/qt_gui/kbm_help_dialog.cpp
Normal file
112
src/qt_gui/kbm_help_dialog.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "kbm_help_dialog.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDialog>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QPushButton>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
ExpandableSection::ExpandableSection(const QString& title, const QString& content,
|
||||
QWidget* parent = nullptr)
|
||||
: QWidget(parent) {
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
|
||||
// Button to toggle visibility of content
|
||||
toggleButton = new QPushButton(title);
|
||||
layout->addWidget(toggleButton);
|
||||
|
||||
// QTextBrowser for content (initially hidden)
|
||||
contentBrowser = new QTextBrowser();
|
||||
contentBrowser->setPlainText(content);
|
||||
contentBrowser->setVisible(false);
|
||||
|
||||
// Remove scrollbars from QTextBrowser
|
||||
contentBrowser->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
contentBrowser->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
// Set size policy to allow vertical stretching only
|
||||
contentBrowser->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||
|
||||
// Calculate and set initial height based on content
|
||||
updateContentHeight();
|
||||
|
||||
layout->addWidget(contentBrowser);
|
||||
|
||||
// Connect button click to toggle visibility
|
||||
connect(toggleButton, &QPushButton::clicked, [this]() {
|
||||
contentBrowser->setVisible(!contentBrowser->isVisible());
|
||||
if (contentBrowser->isVisible()) {
|
||||
updateContentHeight(); // Update height when expanding
|
||||
}
|
||||
emit expandedChanged(); // Notify for layout adjustments
|
||||
});
|
||||
|
||||
// Connect to update height if content changes
|
||||
connect(contentBrowser->document(), &QTextDocument::contentsChanged, this,
|
||||
&ExpandableSection::updateContentHeight);
|
||||
|
||||
// Minimal layout settings for spacing
|
||||
layout->setSpacing(2);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void HelpDialog::closeEvent(QCloseEvent* event) {
|
||||
*help_open_ptr = false;
|
||||
close();
|
||||
}
|
||||
void HelpDialog::reject() {
|
||||
*help_open_ptr = false;
|
||||
close();
|
||||
}
|
||||
|
||||
HelpDialog::HelpDialog(bool* open_flag, QWidget* parent) : QDialog(parent) {
|
||||
help_open_ptr = open_flag;
|
||||
// Main layout for the help dialog
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout(this);
|
||||
|
||||
// Container widget for the scroll area
|
||||
QWidget* containerWidget = new QWidget;
|
||||
QVBoxLayout* containerLayout = new QVBoxLayout(containerWidget);
|
||||
|
||||
// Add expandable sections to container layout
|
||||
auto* quickstartSection = new ExpandableSection("Quickstart", quickstart());
|
||||
auto* faqSection = new ExpandableSection("FAQ", faq());
|
||||
auto* syntaxSection = new ExpandableSection("Syntax", syntax());
|
||||
auto* specialSection = new ExpandableSection("Special Bindings", special());
|
||||
auto* bindingsSection = new ExpandableSection("Keybindings", bindings());
|
||||
|
||||
containerLayout->addWidget(quickstartSection);
|
||||
containerLayout->addWidget(faqSection);
|
||||
containerLayout->addWidget(syntaxSection);
|
||||
containerLayout->addWidget(specialSection);
|
||||
containerLayout->addWidget(bindingsSection);
|
||||
containerLayout->addStretch(1);
|
||||
|
||||
// Scroll area wrapping the container
|
||||
QScrollArea* scrollArea = new QScrollArea;
|
||||
scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
scrollArea->setWidgetResizable(true);
|
||||
scrollArea->setWidget(containerWidget);
|
||||
|
||||
// Add the scroll area to the main dialog layout
|
||||
mainLayout->addWidget(scrollArea);
|
||||
setLayout(mainLayout);
|
||||
|
||||
// Minimum size for the dialog
|
||||
setMinimumSize(500, 400);
|
||||
|
||||
// Re-adjust dialog layout when any section expands/collapses
|
||||
connect(quickstartSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
connect(faqSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
connect(syntaxSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
connect(specialSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
connect(bindingsSection, &ExpandableSection::expandedChanged, this, &HelpDialog::adjustSize);
|
||||
}
|
175
src/qt_gui/kbm_help_dialog.h
Normal file
175
src/qt_gui/kbm_help_dialog.h
Normal file
|
@ -0,0 +1,175 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDialog>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QTextBrowser>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class ExpandableSection : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ExpandableSection(const QString& title, const QString& content, QWidget* parent);
|
||||
|
||||
signals:
|
||||
void expandedChanged(); // Signal to indicate layout size change
|
||||
|
||||
private:
|
||||
QPushButton* toggleButton;
|
||||
QTextBrowser* contentBrowser; // Changed from QLabel to QTextBrowser
|
||||
QPropertyAnimation* animation;
|
||||
int contentHeight;
|
||||
void updateContentHeight() {
|
||||
int contentHeight = contentBrowser->document()->size().height();
|
||||
contentBrowser->setMinimumHeight(contentHeight + 5);
|
||||
contentBrowser->setMaximumHeight(contentHeight + 50);
|
||||
}
|
||||
};
|
||||
|
||||
class HelpDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HelpDialog(bool* open_flag = nullptr, QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
void reject() override;
|
||||
|
||||
private:
|
||||
bool* help_open_ptr;
|
||||
|
||||
QString quickstart() {
|
||||
return
|
||||
R"(The keyboard and controller remapping backend, GUI and documentation have been written by kalaposfos
|
||||
|
||||
In this section, you will find information about the project, its features and help on setting up your ideal setup.
|
||||
To view the config file's syntax, check out the Syntax tab, for keybind names, visit Normal Keybinds and Special Bindings, and if you are here to view emulator-wide keybinds, you can find it in the FAQ section.
|
||||
This project started out because I didn't like the original unchangeable keybinds, but rather than waiting for someone else to do it, I implemented this myself. From the default keybinds, you can clearly tell this was a project built for Bloodborne, but ovbiously you can make adjustments however you like.
|
||||
)";
|
||||
}
|
||||
QString faq() {
|
||||
return
|
||||
R"(Q: What are the emulator-wide keybinds?
|
||||
A: -F12: Triggers Renderdoc capture
|
||||
-F11: Toggles fullscreen
|
||||
-F10: Toggles FPS counter
|
||||
-Ctrl F10: Open the debug menu
|
||||
-F9: Pauses emultor, if the debug menu is open
|
||||
-F8: Reparses the config file while in-game
|
||||
-F7: Toggles mouse capture and mouse input
|
||||
|
||||
Q: How do I change between mouse and controller joystick input, and why is it even required?
|
||||
A: You can switch between them with F7, and it is required, because mouse input is done with polling, which means mouse movement is checked every frame, and if it didn't move, the code manually sets the emulator's virtual controller to 0 (back to the center), even if other input devices would update it.
|
||||
|
||||
Q: What happens if I accidentally make a typo in the config?
|
||||
A: The code recognises the line as wrong, and skip it, so the rest of the file will get parsed, but that line in question will be treated like a comment line. You can find these lines in the log, if you search for 'input_handler'.
|
||||
|
||||
Q: I want to bind <input> to <output>, but your code doesn't support <input>!
|
||||
A: Some keys are intentionally omitted, but if you read the bindings through, and you're sure it is not there and isn't one of the intentionally disabled ones, open an issue on https://github.com/shadps4-emu/shadPS4.
|
||||
|
||||
Q: What does default.ini do?
|
||||
A: If you're using per-game configs, it's the base from which all new games generate their config file. If you use the unified config, then this is used for every game directly instead.
|
||||
|
||||
Q: What does the use Per-game Config checkbox do?
|
||||
A: It controls whether the config is loaded from CUSAXXXXX.ini for a game, or from default.ini. This way, if you only want to manage one set of bindings, you can do so, but if you want to use a different setup for every game, that's possible as well.
|
||||
)";
|
||||
}
|
||||
QString syntax() {
|
||||
return
|
||||
R"(This is the full list of currently supported mouse, keyboard and controller inputs, and how to use them.
|
||||
Emulator-reserved keys: F1 through F12
|
||||
|
||||
Syntax (aka how a line can look like):
|
||||
#Comment line
|
||||
<controller_button> = <input>, <input>, <input>;
|
||||
<controller_button> = <input>, <input>;
|
||||
<controller_button> = <input>;
|
||||
|
||||
Examples:
|
||||
#Interact
|
||||
cross = e;
|
||||
#Heavy attack (in BB)
|
||||
r2 = leftbutton, lshift;
|
||||
#Move forward
|
||||
axis_left_y_minus = w;
|
||||
|
||||
You can make a comment line by putting # as the first character.
|
||||
Whitespace doesn't matter, <output>=<input>; is just as valid as <output> = <input>;
|
||||
';' at the ends of lines is also optional.
|
||||
)";
|
||||
}
|
||||
QString bindings() {
|
||||
return
|
||||
R"(The following names should be interpreted without the '' around them, and for inputs that have left and right versions, only the left one is shown, but the right can be inferred from that.
|
||||
Example: 'lshift', 'rshift'
|
||||
|
||||
Keyboard:
|
||||
Alphabet: 'a', 'b', ..., 'z'
|
||||
Numbers: '0', '1', ..., '9'
|
||||
Keypad: 'kp0', kp1', ..., 'kp9', 'kpperiod', 'kpcomma',
|
||||
'kpdivide', 'kpmultiply', 'kpdivide', 'kpplus', 'kpminus', 'kpenter'
|
||||
Punctuation and misc:
|
||||
'space', 'comma', 'period', 'question', 'semicolon', 'minus', 'plus', 'lparenthesis', 'lbracket', 'lbrace', 'backslash', 'dash',
|
||||
'enter', 'tab', backspace', 'escape'
|
||||
Arrow keys: 'up', 'down', 'left', 'right'
|
||||
Modifier keys:
|
||||
'lctrl', 'lshift', 'lalt', 'lwin' = 'lmeta' (same input, different names, so if you are not on Windows and don't like calling this the Windows key, there is an alternative)
|
||||
|
||||
Mouse:
|
||||
'leftbutton', 'rightbutton', 'middlebutton', 'sidebuttonforward', 'sidebuttonback'
|
||||
The following wheel inputs cannot be bound to axis input, only button:
|
||||
'mousewheelup', 'mousewheeldown', 'mousewheelleft', 'mousewheelright'
|
||||
|
||||
Controller:
|
||||
The touchpad currently can't be rebound to anything else, but you can bind buttons to it.
|
||||
If you have a controller that has different names for buttons, it will still work, just look up what are the equivalent names for that controller
|
||||
The same left-right rule still applies here.
|
||||
Buttons:
|
||||
'triangle', 'circle', 'cross', 'square', 'l1', 'l3',
|
||||
'options', touchpad', 'up', 'down', 'left', 'right'
|
||||
Axes if you bind them to a button input:
|
||||
'axis_left_x_plus', 'axis_left_x_minus', 'axis_left_y_plus', 'axis_left_y_minus',
|
||||
'axis_right_x_plus', ..., 'axis_right_y_minus',
|
||||
'l2'
|
||||
Axes if you bind them to another axis input:
|
||||
'axis_left_x' 'axis_left_y' 'axis_right_x' 'axis_right_y',
|
||||
'l2'
|
||||
)";
|
||||
}
|
||||
QString special() {
|
||||
return
|
||||
R"(There are some extra bindings you can put into the config file, that don't correspond to a controller input, but rather something else.
|
||||
You can find these here, with detailed comments, examples and suggestions for most of them.
|
||||
|
||||
'leftjoystick_halfmode' and 'rightjoystick_halfmode' = <key>;
|
||||
These are a pair of input modifiers, that change the way keyboard button bound axes work. By default, those push the joystick to the max in their respective direction, but if their respective joystick_halfmode modifier value is true, they only push it... halfway. With this, you can change from run to walk in games like Bloodborne.
|
||||
|
||||
'mouse_to_joystick' = 'none', 'left' or 'right';
|
||||
This binds the mouse movement to either joystick. If it recieves a value that is not 'left' or 'right', it defaults to 'none'.
|
||||
|
||||
'mouse_movement_params' = float, float, float;
|
||||
(If you don't know what a float is, it is a data type that stores non-whole numbers.)
|
||||
Default values: 0.5, 1, 0.125
|
||||
Let's break each parameter down:
|
||||
1st: mouse_deadzone_offset: this value should have a value between 0 and 1 (It gets clamped to that range anyway), with 0 being no offset and 1 being pushing the joystick to the max in the direction the mouse moved.
|
||||
This controls the minimum distance the joystick gets moved, when moving the mouse. If set to 0, it will emulate raw mouse input, which doesn't work very well due to deadzones preventing input if the movement is not large enough.
|
||||
2nd: mouse_speed: It's just a standard multiplier to the mouse input speed.
|
||||
If you input a negative number, the axis directions get reversed (Keep in mind that the offset can still push it back to positive, if it's big enough)
|
||||
3rd: mouse_speed_offset: This also should be in the 0 to 1 range, with 0 being no offset and 1 being offsetting to the max possible value.
|
||||
This is best explained through an example: Let's set mouse_deadzone to 0.5, and this to 0: This means that if we move the mousevery slowly, it still inputs a half-strength joystick input, and if we increase the speed, it would stay that way until we move faster than half the max speed. If we instead set this to 0.25, we now only need to move the mouse faster than the 0.5-0.25=0.25=quarter of the max speed, to get an increase in joystick speed. If we set it to 0.5, then even moving the mouse at 1 pixel per frame will result in a faster-than-minimum speed.
|
||||
|
||||
'key_toggle' = <key>, <key_to_toggle>;
|
||||
This assigns a key to another key, and if pressed, toggles that key's virtual value. If it's on, then it doesn't matter if the key is pressed or not, the input handler will treat it as if it's pressed.
|
||||
You can make an input toggleable with this, for example: Let's say we want to be able to toggle l1 with t. You can then bind l1 to a key you won't use, like kpenter, then bind t to toggle that, so you will end up with this:
|
||||
l1 = kpenter;
|
||||
key_toggle = t, kpenter;
|
||||
'analog_deadzone' = <device>, <value>;
|
||||
value goes from 1 to 127 (no deadzone to max deadzone)
|
||||
devices: leftjoystick, rightjoystick, l2, r2
|
||||
)";
|
||||
}
|
||||
};
|
|
@ -26,6 +26,8 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
QApplication::setDesktopFileName("net.shadps4.shadPS4");
|
||||
|
||||
// Load configurations and initialize Qt application
|
||||
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||
Config::load(user_dir / "config.toml");
|
||||
|
@ -181,12 +183,12 @@ int main(int argc, char* argv[]) {
|
|||
|
||||
// Check if the provided path is a valid file
|
||||
if (!std::filesystem::exists(game_file_path)) {
|
||||
// If not a file, treat it as a game ID and search in install directories
|
||||
// If not a file, treat it as a game ID and search in install directories recursively
|
||||
bool game_found = false;
|
||||
const int max_depth = 5;
|
||||
for (const auto& install_dir : Config::getGameInstallDirs()) {
|
||||
auto potential_game_path = install_dir / game_path / "eboot.bin";
|
||||
if (std::filesystem::exists(potential_game_path)) {
|
||||
game_file_path = potential_game_path;
|
||||
if (auto found_path = Common::FS::FindGameByID(install_dir, game_path, max_depth)) {
|
||||
game_file_path = *found_path;
|
||||
game_found = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <QDockWidget>
|
||||
#include <QKeyEvent>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QProgressDialog>
|
||||
|
||||
#include "about_dialog.h"
|
||||
|
@ -21,6 +22,9 @@
|
|||
#include "install_dir_select.h"
|
||||
#include "main_window.h"
|
||||
#include "settings_dialog.h"
|
||||
|
||||
#include "kbm_config_dialog.h"
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
#ifdef ENABLE_DISCORD_RPC
|
||||
#include "common/discord_rpc_handler.h"
|
||||
|
@ -57,8 +61,16 @@ bool MainWindow::Init() {
|
|||
if (Common::isRelease) {
|
||||
window_title = fmt::format("shadPS4 v{}", Common::VERSION);
|
||||
} else {
|
||||
window_title = fmt::format("shadPS4 v{} {} {}", Common::VERSION, Common::g_scm_branch,
|
||||
Common::g_scm_desc);
|
||||
std::string remote_url(Common::g_scm_remote_url);
|
||||
if (remote_url == "https://github.com/shadps4-emu/shadPS4.git" ||
|
||||
remote_url.length() == 0) {
|
||||
window_title = fmt::format("shadPS4 v{} {} {}", Common::VERSION, Common::g_scm_branch,
|
||||
Common::g_scm_desc);
|
||||
} else {
|
||||
std::string remote_host = remote_url.substr(19, remote_url.rfind('/') - 19);
|
||||
window_title = fmt::format("shadPS4 v{} {}/{} {}", Common::VERSION, remote_host,
|
||||
Common::g_scm_branch, Common::g_scm_desc);
|
||||
}
|
||||
}
|
||||
setWindowTitle(QString::fromStdString(window_title));
|
||||
this->show();
|
||||
|
@ -283,6 +295,12 @@ void MainWindow::CreateConnects() {
|
|||
settingsDialog->exec();
|
||||
});
|
||||
|
||||
// this is the editor for kbm keybinds
|
||||
connect(ui->controllerButton, &QPushButton::clicked, this, [this]() {
|
||||
EditorDialog* editorWindow = new EditorDialog(this);
|
||||
editorWindow->exec(); // Show the editor window modally
|
||||
});
|
||||
|
||||
#ifdef ENABLE_UPDATER
|
||||
connect(ui->updaterAct, &QAction::triggered, this, [this]() {
|
||||
auto checkUpdate = new CheckUpdate(true);
|
||||
|
@ -725,15 +743,56 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||
return;
|
||||
}
|
||||
auto category = psf.GetString("CATEGORY");
|
||||
InstallDirSelect ids;
|
||||
ids.exec();
|
||||
auto game_install_dir = ids.getSelectedDirectory();
|
||||
auto game_folder_path = game_install_dir / pkg.GetTitleID();
|
||||
|
||||
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();
|
||||
auto game_update_path = use_game_update
|
||||
? game_install_dir / (std::string(pkg.GetTitleID()) + "-UPDATE")
|
||||
: game_folder_path;
|
||||
|
||||
// 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);
|
||||
|
@ -878,9 +937,18 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||
connect(&futureWatcher, &QFutureWatcher<void>::finished, this, [=, this]() {
|
||||
if (pkgNum == nPkg) {
|
||||
QString path;
|
||||
Common::FS::PathToQString(path, game_install_dir);
|
||||
|
||||
// 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);
|
||||
|
@ -894,6 +962,9 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
|||
});
|
||||
extractMsgBox.exec();
|
||||
}
|
||||
if (delete_file_on_install) {
|
||||
std::filesystem::remove(file);
|
||||
}
|
||||
});
|
||||
connect(&dialog, &QProgressDialog::canceled, [&]() { futureWatcher.cancel(); });
|
||||
connect(&futureWatcher, &QFutureWatcher<void>::progressValueChanged, &dialog,
|
||||
|
|
|
@ -123,4 +123,8 @@ protected:
|
|||
}
|
||||
|
||||
void resizeEvent(QResizeEvent* event) override;
|
||||
|
||||
std::filesystem::path last_install_dir = "";
|
||||
bool delete_file_on_install = false;
|
||||
bool use_for_all_queued = false;
|
||||
};
|
||||
|
|
|
@ -285,6 +285,11 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
|
|||
ui->vkValidationCheckBox->installEventFilter(this);
|
||||
ui->vkSyncValidationCheckBox->installEventFilter(this);
|
||||
ui->rdocCheckBox->installEventFilter(this);
|
||||
ui->crashDiagnosticsCheckBox->installEventFilter(this);
|
||||
ui->guestMarkersCheckBox->installEventFilter(this);
|
||||
ui->hostMarkersCheckBox->installEventFilter(this);
|
||||
ui->collectShaderCheckBox->installEventFilter(this);
|
||||
ui->copyGPUBuffersCheckBox->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,6 +365,15 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||
ui->vkSyncValidationCheckBox->setChecked(
|
||||
toml::find_or<bool>(data, "Vulkan", "validation_sync", false));
|
||||
ui->rdocCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "rdocEnable", false));
|
||||
ui->crashDiagnosticsCheckBox->setChecked(
|
||||
toml::find_or<bool>(data, "Vulkan", "crashDiagnostic", false));
|
||||
ui->guestMarkersCheckBox->setChecked(
|
||||
toml::find_or<bool>(data, "Vulkan", "guestMarkers", false));
|
||||
ui->hostMarkersCheckBox->setChecked(toml::find_or<bool>(data, "Vulkan", "hostMarkers", false));
|
||||
ui->copyGPUBuffersCheckBox->setChecked(
|
||||
toml::find_or<bool>(data, "GPU", "copyGPUBuffers", false));
|
||||
ui->collectShaderCheckBox->setChecked(
|
||||
toml::find_or<bool>(data, "Debug", "CollectShader", false));
|
||||
ui->enableCompatibilityCheckBox->setChecked(
|
||||
toml::find_or<bool>(data, "General", "compatibilityEnabled", false));
|
||||
ui->checkCompatibilityOnStartupCheckBox->setChecked(
|
||||
|
@ -380,7 +394,7 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||
|
||||
std::string chooseHomeTab = toml::find_or<std::string>(data, "General", "chooseHomeTab", "");
|
||||
ui->chooseHomeTabComboBox->setCurrentText(QString::fromStdString(chooseHomeTab));
|
||||
QStringList tabNames = {tr("General"), tr("Gui"), tr("Graphics"), tr("User"),
|
||||
QStringList tabNames = {tr("General"), tr("GUI"), tr("Graphics"), tr("User"),
|
||||
tr("Input"), tr("Paths"), tr("Debug")};
|
||||
QString chooseHomeTabQString = QString::fromStdString(chooseHomeTab);
|
||||
int indexTab = tabNames.indexOf(chooseHomeTabQString);
|
||||
|
@ -551,6 +565,16 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
|||
text = tr("vkSyncValidationCheckBox");
|
||||
} else if (elementName == "rdocCheckBox") {
|
||||
text = tr("rdocCheckBox");
|
||||
} else if (elementName == "crashDiagnosticsCheckBox") {
|
||||
text = tr("crashDiagnosticsCheckBox");
|
||||
} else if (elementName == "guestMarkersCheckBox") {
|
||||
text = tr("guestMarkersCheckBox");
|
||||
} else if (elementName == "hostMarkersCheckBox") {
|
||||
text = tr("hostMarkersCheckBox");
|
||||
} else if (elementName == "copyGPUBuffersCheckBox") {
|
||||
text = tr("copyGPUBuffersCheckBox");
|
||||
} else if (elementName == "collectShaderCheckBox") {
|
||||
text = tr("collectShaderCheckBox");
|
||||
}
|
||||
|
||||
ui->descriptionText->setText(text.replace("\\n", "\n"));
|
||||
|
@ -604,6 +628,11 @@ void SettingsDialog::UpdateSettings() {
|
|||
Config::setVkValidation(ui->vkValidationCheckBox->isChecked());
|
||||
Config::setVkSyncValidation(ui->vkSyncValidationCheckBox->isChecked());
|
||||
Config::setRdocEnabled(ui->rdocCheckBox->isChecked());
|
||||
Config::setVkHostMarkersEnabled(ui->hostMarkersCheckBox->isChecked());
|
||||
Config::setVkGuestMarkersEnabled(ui->guestMarkersCheckBox->isChecked());
|
||||
Config::setVkCrashDiagnosticEnabled(ui->crashDiagnosticsCheckBox->isChecked());
|
||||
Config::setCollectShaderForDebug(ui->collectShaderCheckBox->isChecked());
|
||||
Config::setCopyGPUCmdBuffers(ui->copyGPUBuffersCheckBox->isChecked());
|
||||
Config::setAutoUpdate(ui->updateCheckBox->isChecked());
|
||||
Config::setUpdateChannel(ui->updateComboBox->currentText().toStdString());
|
||||
Config::setChooseHomeTab(ui->chooseHomeTabComboBox->currentText().toStdString());
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>970</width>
|
||||
<height>600</height>
|
||||
<height>750</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -74,7 +74,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>386</height>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="generalTabVLayout" stretch="0">
|
||||
|
@ -108,9 +108,6 @@
|
|||
<property name="title">
|
||||
<string>Emulator</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignBottom|Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft</set>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
|
@ -476,7 +473,7 @@
|
|||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Gui</string>
|
||||
<string>GUI</string>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="guiTabContents">
|
||||
<property name="geometry">
|
||||
|
@ -484,7 +481,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>386</height>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="guiTabVLayout" stretch="0">
|
||||
|
@ -497,14 +494,14 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="0">
|
||||
<layout class="QVBoxLayout" name="GUITabLayoutMiddle" stretch="0,0">
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="GUIgroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
|
@ -530,7 +527,7 @@
|
|||
<property name="title">
|
||||
<string>Default tab when opening settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="settingsLayout">
|
||||
<layout class="QVBoxLayout" name="tabSettingsLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="chooseHomeTabComboBox">
|
||||
<property name="sizePolicy">
|
||||
|
@ -546,7 +543,7 @@
|
|||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Gui</string>
|
||||
<string>GUI</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -594,6 +591,18 @@
|
|||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
|
@ -605,62 +614,16 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string/>
|
||||
<string>Title Music</string>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QSlider" name="BGMVolumeSlider">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>80</y>
|
||||
<width>416</width>
|
||||
<height>29</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set the volume of the background music.</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="invertedAppearance">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="invertedControls">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TickPosition::NoTicks</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="playBGMCheckBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>22</y>
|
||||
<x>9</x>
|
||||
<y>30</y>
|
||||
<width>416</width>
|
||||
<height>26</height>
|
||||
</rect>
|
||||
|
@ -675,45 +638,119 @@
|
|||
<string>Play title music</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_Volume">
|
||||
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>54</y>
|
||||
<width>416</width>
|
||||
<height>20</height>
|
||||
<x>0</x>
|
||||
<y>50</y>
|
||||
<width>431</width>
|
||||
<height>47</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Volume</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="spacing">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_Volume">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Volume</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="BGMVolumeSlider">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set the volume of the background music.</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Horizontal</enum>
|
||||
</property>
|
||||
<property name="invertedAppearance">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="invertedControls">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="tickPosition">
|
||||
<enum>QSlider::TickPosition::NoTicks</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>10</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="CompatTabLayoutRight" stretch="0">
|
||||
<layout class="QVBoxLayout" name="CompatTabLayoutRight" stretch="0,0">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>210</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="CompatgroupBox">
|
||||
|
@ -790,6 +827,19 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -810,7 +860,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>386</height>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="graphicsTabVLayout" stretch="0,0">
|
||||
|
@ -1054,10 +1104,10 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>386</height>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,0,1">
|
||||
<layout class="QVBoxLayout" name="userTabVLayout" stretch="0,0,1">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
|
@ -1198,7 +1248,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>386</height>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="inputTabVLayout" stretch="0,0">
|
||||
|
@ -1482,7 +1532,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>386</height>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="pathsTabLayout">
|
||||
|
@ -1572,10 +1622,10 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>946</width>
|
||||
<height>386</height>
|
||||
<height>536</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,1">
|
||||
<layout class="QVBoxLayout" name="debugTabVLayout" stretch="0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<property name="leftMargin">
|
||||
|
@ -1585,7 +1635,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="debugTabHLayout" stretch="1">
|
||||
<layout class="QHBoxLayout" name="debugTabHLayout" stretch="0">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="debugTabGroupBox">
|
||||
<property name="enabled">
|
||||
|
@ -1728,20 +1778,57 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="debugTabSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Orientation::Vertical</enum>
|
||||
<widget class="QGroupBox" name="advancedGroupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
|
||||
<property name="title">
|
||||
<string>Advanced</string>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
|
||||
</property>
|
||||
</spacer>
|
||||
<layout class="QVBoxLayout" name="advancedLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="crashDiagnosticsCheckBox">
|
||||
<property name="text">
|
||||
<string>Enable Crash Diagnostics</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="collectShaderCheckBox">
|
||||
<property name="text">
|
||||
<string>Collect Shaders</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="copyGPUBuffersCheckBox">
|
||||
<property name="text">
|
||||
<string>Copy GPU Buffers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="hostMarkersCheckBox">
|
||||
<property name="text">
|
||||
<string>Host Debug Markers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="guestMarkersCheckBox">
|
||||
<property name="text">
|
||||
<string>Guest Debug Markers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>RenderDoc تمكين تصحيح أخطاء</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>تحديث</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>إعدادات الواجهة</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>تمكين تصحيح RenderDoc:\nإذا تم التمكين، سيوفر المحاكي توافقًا مع Renderdoc لالتقاط وتحليل الإطار الذي يتم عرضه حاليًا.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Enable RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Opdatering</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI-Indstillinger</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Aktiver RenderDoc-fejlfinding:\nHvis aktiveret, giver det emulatoren mulighed for kompatibilitet med Renderdoc til at fange og analysere det aktuelle gengivne billede.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Select which directory you want to install to.</source>
|
||||
<translation>Select which directory you want to install to.</translation>
|
||||
<translation>Wählen Sie das Verzeichnis aus, in das Sie installieren möchten.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -105,7 +105,11 @@
|
|||
<translation>Spielordner öffnen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Save Data Folder</source>
|
||||
<source>Open Update Folder</source>
|
||||
<translation>Öffne Update-Ordner</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Save Data Folder</source>
|
||||
<translation>Speicherordner öffnen</translation>
|
||||
</message>
|
||||
<message>
|
||||
|
@ -130,35 +134,39 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Delete...</source>
|
||||
<translation>Delete...</translation>
|
||||
<translation>Löschen...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Game</source>
|
||||
<translation>Delete Game</translation>
|
||||
<translation>Lösche Spiel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Update</source>
|
||||
<translation>Delete Update</translation>
|
||||
</message>
|
||||
<translation>Lösche Aktualisierung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Save Data</source>
|
||||
<translation>Lösche Speicherdaten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete DLC</source>
|
||||
<translation>Delete DLC</translation>
|
||||
<translation>Lösche DLC</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Compatibility...</source>
|
||||
<translation>Compatibility...</translation>
|
||||
<translation>Kompatibilität...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update database</source>
|
||||
<translation>Update database</translation>
|
||||
<translation>Aktualisiere Datenbank</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>View report</source>
|
||||
<translation>View report</translation>
|
||||
<translation>Bericht ansehen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Submit a report</source>
|
||||
<translation>Submit a report</translation>
|
||||
<translation>Einen Bericht einreichen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut creation</source>
|
||||
|
@ -182,23 +190,23 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Game</source>
|
||||
<translation>Game</translation>
|
||||
<translation>Spiel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>requiresEnableSeparateUpdateFolder_MSG</source>
|
||||
<translation>This feature requires the 'Enable Separate Update Folder' config option to work. If you want to use this feature, please enable it.</translation>
|
||||
<translation>Damit diese Funktion funktioniert, ist die Konfigurationsoption „Separaten Update-Ordner aktivieren“ erforderlich. Wenn Sie diese Funktion nutzen möchten, aktivieren Sie sie bitte.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no update to delete!</source>
|
||||
<translation>This game has no update to delete!</translation>
|
||||
<translation>Dieses Spiel hat keine Aktualisierung zum löschen!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Update</translation>
|
||||
<translation>Aktualisieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no DLC to delete!</source>
|
||||
<translation>This game has no DLC to delete!</translation>
|
||||
<translation>Dieses Spiel hat kein DLC zum aktualisieren!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DLC</source>
|
||||
|
@ -206,11 +214,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Delete %1</source>
|
||||
<translation>Delete %1</translation>
|
||||
<translation>Lösche %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to delete %1's %2 directory?</source>
|
||||
<translation>Are you sure you want to delete %1's %2 directory?</translation>
|
||||
<translation>Sind Sie sicher dass Sie %1 %2 Ordner löschen wollen?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -249,7 +257,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
<translation>Öffne shadPS4 Ordner</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
|
@ -305,7 +313,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Download Cheats/Patches</source>
|
||||
<translation>Cheats / Patches herunterladen</translation>
|
||||
<translation>Cheats/Patches herunterladen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Dump Game List</source>
|
||||
|
@ -313,7 +321,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>PKG Viewer</source>
|
||||
<translation>PKG-Ansicht</translation>
|
||||
<translation>PKG-Anschauer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Search...</source>
|
||||
|
@ -329,11 +337,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Game List Icons</source>
|
||||
<translation>Game List Icons</translation>
|
||||
<translation>Spiellisten-Symbole</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game List Mode</source>
|
||||
<translation>Spiellisten-Symoble</translation>
|
||||
<translation>Spiellisten-Modus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
|
@ -373,7 +381,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>toolBar</source>
|
||||
<translation>toolBar</translation>
|
||||
<translation>Werkzeugleiste</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game List</source>
|
||||
|
@ -461,7 +469,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Would you like to install DLC: %1?</source>
|
||||
<translation>Willst du den DLC installieren: %1?</translation>
|
||||
<translation>Willst du das DLC installieren: %1?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>DLC already installed:</source>
|
||||
|
@ -513,7 +521,11 @@
|
|||
<context>
|
||||
<name>SettingsDialog</name>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<source>Save Data Path</source>
|
||||
<translation>Speicherdaten-Pfad</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
<translation>Einstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
|
@ -546,7 +558,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Enable Separate Update Folder</source>
|
||||
<translation>Enable Separate Update Folder</translation>
|
||||
<translation>Separaten Update-Ordner aktivieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default tab when opening settings</source>
|
||||
|
@ -554,7 +566,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Show Game Size In List</source>
|
||||
<translation>Zeigen Sie die Spielgröße in der Liste</translation>
|
||||
<translation>Zeige Spielgröße in der Liste</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Splash</source>
|
||||
|
@ -574,11 +586,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Trophy Key</source>
|
||||
<translation>Trophy Key</translation>
|
||||
<translation>Trophäenschlüssel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy</source>
|
||||
<translation>Trophy</translation>
|
||||
<translation>Trophäe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logger</source>
|
||||
|
@ -599,6 +611,10 @@
|
|||
<message>
|
||||
<source>Input</source>
|
||||
<translation>Eingabe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Motion Controls</source>
|
||||
<translation>Aktiviere Bewegungssteuerung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cursor</source>
|
||||
|
@ -700,6 +716,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>RenderDoc-Debugging aktivieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Absturz-Diagnostik aktivieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Sammle Shader</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Kopiere GPU Puffer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host-Debug-Markierer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest-Debug-Markierer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Aktualisieren</translation>
|
||||
|
@ -720,9 +756,13 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI-Einstellungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Titelmusik</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
<translation>Deaktiviere Trophäen Pop-ups</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play title music</source>
|
||||
|
@ -730,19 +770,19 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Update Compatibility Database On Startup</source>
|
||||
<translation>Update Compatibility Database On Startup</translation>
|
||||
<translation>Aktualisiere Kompatibilitätsdatenbank beim Start</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game Compatibility</source>
|
||||
<translation>Game Compatibility</translation>
|
||||
<translation>Spielkompatibilität</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display Compatibility Data</source>
|
||||
<translation>Display Compatibility Data</translation>
|
||||
<translation>Zeige Kompatibilitätsdaten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Compatibility Database</source>
|
||||
<translation>Update Compatibility Database</translation>
|
||||
<translation>Aktualisiere Kompatibilitätsdatenbank</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Volume</source>
|
||||
|
@ -786,7 +826,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>separateUpdatesCheckBox</source>
|
||||
<translation>Enable Separate Update Folder:\nEnables installing game updates into a separate folder for easy management.</translation>
|
||||
<translation>Separaten Update-Ordner aktivieren:\nErmöglicht die Installation von Spielaktualiserungen in einem separaten Ordner zur einfachen Verwaltung.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>showSplashCheckBox</source>
|
||||
|
@ -806,7 +846,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>TrophyKey</source>
|
||||
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
|
||||
<translation>Trophäenschlüssel:\nSchlüssel zum Entschlüsseln von Trophäen. Muss von Ihrer gejailbreakten Konsole abgerufen werden.\nDarf nur Hex-Zeichen enthalten.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -826,7 +866,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>disableTrophycheckBox</source>
|
||||
<translation>Disable Trophy Pop-ups:\nDisable in-game trophy notifications. Trophy progress can still be tracked using the Trophy Viewer (right-click the game in the main window).</translation>
|
||||
<translation>Trophäen-Popups deaktivieren:\nDeaktivieren Sie Trophäenbenachrichtigungen im Spiel. Der Trophäenfortschritt kann weiterhin mit dem Trophäen-Viewer verfolgt werden (klicken Sie mit der rechten Maustaste auf das Spiel im Hauptfenster)..</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hideCursorGroupBox</source>
|
||||
|
@ -842,15 +882,15 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>enableCompatibilityCheckBox</source>
|
||||
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
|
||||
<translation>Kompatibilitätsdaten anzeigen:\nZeigt Spielkompatibilitätsinformationen in Tabellenansicht an. Aktivieren Sie „Aktualisiere Kompatibilitätsdatenbank beim Start“, um aktuelle Informationen zu erhalten.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>checkCompatibilityOnStartupCheckBox</source>
|
||||
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
|
||||
<translation>Kompatibilität beim Start aktualisieren:\nAktualisiert die Kompatibilitätsdatenbank automatisch, wenn shadPS4 startet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>updateCompatibilityButton</source>
|
||||
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
|
||||
<translation>Aktualisiere Kompatibilitätsdatenbank:\nAktualisiere sofort die Kompatibilitätsdatenbank.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Never</source>
|
||||
|
@ -928,12 +968,32 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>RenderDoc-Debugging aktivieren:\nWenn aktiviert, bietet der Emulator Kompatibilität mit Renderdoc zur Erfassung und Analyse des aktuell gerenderten Frames.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Shader sammeln:\nSie müssen diese Option aktivieren, um Shader mit dem Debug-Menü (Strg + F10) bearbeiten zu können.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Absturzdiagnose:\nErstellt eine .yaml-Datei mit Informationen über den Vulkan-Status zum Zeitpunkt des Absturzes.\nNützlich zum Debuggen von „Gerät verloren“-Fehlern. Wenn Sie dies aktiviert haben, sollten Sie Host- UND Gast-Debug-Markierungen aktivieren.\nFunktioniert nicht auf Intel-GPUs.\nDamit dies funktioniert, müssen Vulkan Validationsschichten aktiviert und das Vulkan SDK installiert sein.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>GPU-Puffer kopieren:\nUmgeht Race-Bedingungen mit GPU-Übermittlungen.\nKann bei PM4-Abstürzen vom Typ 0 hilfreich sein oder auch nicht.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host-Debug-Marker:\nFügt emulatorseitige Informationen wie Marker für bestimmte AMDGPU-Befehle rund um Vulkan-Befehle ein und gibt Ressourcen-Debug-Namen an.\nWenn Sie dies aktiviert haben, sollten Sie die Absturzdiagnose aktivieren.\nNützlich für Programme wie RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Gast-Debug-Markierer:\nFügt alle Debug-Markierer, die das Spiel selbst hinzugefügt hat, in den Befehlspuffer ein.\nWenn Sie dies aktiviert haben, sollten Sie die Absturzdiagnose aktivieren.\nNützlich für Programme wie RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
<message>
|
||||
<source>Cheats / Patches for </source>
|
||||
<translation>Cheats / Patches for </translation>
|
||||
<translation>Cheats / Patches für </translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>defaultTextEdit_MSG</source>
|
||||
|
@ -1121,7 +1181,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Failed to open file:</source>
|
||||
<translation>Fehler beim Öffnen der Datei:</translation>
|
||||
<translation>Öffnung der Datei fehlgeschlagen:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>XML ERROR:</source>
|
||||
|
@ -1168,7 +1228,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
<translation>Kompatibilität</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Region</source>
|
||||
|
@ -1196,7 +1256,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
<translation>Niemals gespielt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>h</source>
|
||||
|
@ -1212,27 +1272,27 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Compatibility is untested</source>
|
||||
<translation>Compatibility is untested</translation>
|
||||
<translation>Kompatibilität wurde noch nicht getested</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game does not initialize properly / crashes the emulator</source>
|
||||
<translation>Game does not initialize properly / crashes the emulator</translation>
|
||||
<translation>Das Spiel wird nicht richtig initialisiert / stürzt den Emulator ab</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game boots, but only displays a blank screen</source>
|
||||
<translation>Game boots, but only displays a blank screen</translation>
|
||||
<translation>Spiel startet, aber zeigt nur einen blanken Bildschirm</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game displays an image but does not go past the menu</source>
|
||||
<translation>Game displays an image but does not go past the menu</translation>
|
||||
<translation>Spiel zeigt ein Bild aber geht nicht über das Menü hinaus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game has game-breaking glitches or unplayable performance</source>
|
||||
<translation>Game has game-breaking glitches or unplayable performance</translation>
|
||||
<translation>Spiel hat spiel-brechende Störungen oder unspielbare Leistung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game can be completed with playable performance and no major glitches</source>
|
||||
<translation>Game can be completed with playable performance and no major glitches</translation>
|
||||
<translation>Spiel kann mit spielbarer Leistung und keinen großen Störungen abgeschlossen werden</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1361,4 +1421,4 @@
|
|||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
</TS>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Enable RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Ενημέρωση</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Ρυθμίσεις GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Ενεργοποίηση Καταγραφής RenderDoc:\nΌταν είναι ενεργοποιημένο, ο εξομοιωτής είναι συμβατός με το RenderDoc για τη λήψη και ανάλυση του τρέχοντος καρέ.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -700,6 +700,27 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Enable RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Update</translation>
|
||||
|
@ -720,6 +741,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI Settings</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +953,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Enable RenderDoc Debugging:\nIf enabled, the emulator will provide compatibility with Renderdoc to allow capture and analysis of the currently rendered frame.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>saveDataBox</source>
|
||||
<translation>Save Data Path:\nThe folder where game save data will be saved.</translation>
|
||||
|
@ -1369,4 +1414,31 @@
|
|||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
<context>
|
||||
<name>CompatibilityInfoClass</name>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Unknown</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nothing</source>
|
||||
<translation>Nothing</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Boots</source>
|
||||
<translation>Boots</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Menus</source>
|
||||
<translation>Menus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ingame</source>
|
||||
<translation>Ingame</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playable</source>
|
||||
<translation>Playable</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Habilitar depuración de RenderDoc</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Actualización</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Configuraciones de la Interfaz</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Habilitar Depuración de RenderDoc:\nSi se habilita, el emulador proporcionará compatibilidad con Renderdoc para permitir la captura y análisis del fotograma actualmente renderizado.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
@ -1361,4 +1405,31 @@
|
|||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CompatibilityInfoClass</name>
|
||||
<message>
|
||||
<source>Unknown</source>
|
||||
<translation>Desconocido</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Nothing</source>
|
||||
<translation>Nada</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Boots</source>
|
||||
<translation>Inicia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Menus</source>
|
||||
<translation>Menús</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Ingame</source>
|
||||
<translation>En el juego</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Playable</source>
|
||||
<translation>Jugable</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>بهروزرسانی</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>تنظیمات رابط کاربری</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>غیرفعال کردن نمایش جوایز</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Enable RenderDoc Debugging:\nIf enabled, the emulator will provide compatibility with Renderdoc to allow capture and analysis of the currently rendered frame.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Ota Käyttöön RenderDoc Virheenkorjaus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Päivitys</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI-asetukset</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Poista Trophy Pop-upit Käytöstä</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Ota Käyttöön RenderDoc Virheenkorjaus:\nJos käytössä, emulaattori tarjoaa Renderdoc-yhteensopivuuden, mikä mahdollistaa renderöidyn kehyksen tallennuksen ja analysoinnin.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -146,19 +146,19 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Compatibility...</source>
|
||||
<translation>Compatibility...</translation>
|
||||
<translation>Compatibilité...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update database</source>
|
||||
<translation>Update database</translation>
|
||||
<translation>Mettre à jour la base de données</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>View report</source>
|
||||
<translation>View report</translation>
|
||||
<translation>Voir rapport</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Submit a report</source>
|
||||
<translation>Submit a report</translation>
|
||||
<translation>Soumettre un rapport</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut creation</source>
|
||||
|
@ -186,7 +186,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>requiresEnableSeparateUpdateFolder_MSG</source>
|
||||
<translation>This feature requires the 'Enable Separate Update Folder' config option to work. If you want to use this feature, please enable it.</translation>
|
||||
<translation>Cette fonctionnalité nécessite l'option 'Dossier séparé pour les mises à jour' pour fonctionner. Si vous voulez utiliser cette fonctionnalité, veuillez l'activer.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no update to delete!</source>
|
||||
|
@ -373,7 +373,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>toolBar</source>
|
||||
<translation>Bare d'outils</translation>
|
||||
<translation>Barre d'outils</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game List</source>
|
||||
|
@ -489,7 +489,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Game successfully installed at %1</source>
|
||||
<translation>Jeu installé avec succès à %1</translation>
|
||||
<translation>Jeu installé avec succès dans %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>File doesn't appear to be a valid PKG file</source>
|
||||
|
@ -546,7 +546,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Enable Separate Update Folder</source>
|
||||
<translation>Dossier séparé pour les mises à jours</translation>
|
||||
<translation>Dossier séparé pour les mises à jour</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default tab when opening settings</source>
|
||||
|
@ -554,7 +554,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Show Game Size In List</source>
|
||||
<translation>Afficher la taille du jeu dans la liste</translation>
|
||||
<translation>Afficher la taille des jeux dans la liste</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Splash</source>
|
||||
|
@ -574,11 +574,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Trophy Key</source>
|
||||
<translation>Trophy Key</translation>
|
||||
<translation>Clé de trophée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy</source>
|
||||
<translation>Trophy</translation>
|
||||
<translation>Trophée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logger</source>
|
||||
|
@ -586,11 +586,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Log Type</source>
|
||||
<translation>Type</translation>
|
||||
<translation>Type de journal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Log Filter</source>
|
||||
<translation>Filtre</translation>
|
||||
<translation>Filtre du journal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Log Location</source>
|
||||
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Activer le débogage RenderDoc</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Activer le diagnostic de crash</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collecter les shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copier la mémoire tampon GPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Marqueur de débogage hôte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Marqueur de débogage invité</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Mise à jour</translation>
|
||||
|
@ -720,9 +740,13 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Paramètres de l'interface</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
<translation>Désactiver les notifications de trophées</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play title music</source>
|
||||
|
@ -730,19 +754,19 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Update Compatibility Database On Startup</source>
|
||||
<translation>Update Compatibility Database On Startup</translation>
|
||||
<translation>Mettre à jour la base de données de compatibilité au lancement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game Compatibility</source>
|
||||
<translation>Game Compatibility</translation>
|
||||
<translation>Compatibilité du jeu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display Compatibility Data</source>
|
||||
<translation>Display Compatibility Data</translation>
|
||||
<translation>Afficher les données de compatibilité</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Compatibility Database</source>
|
||||
<translation>Update Compatibility Database</translation>
|
||||
<translation>Mettre à jour la base de données de compatibilité</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Volume</source>
|
||||
|
@ -750,7 +774,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Audio Backend</source>
|
||||
<translation>Audio Backend</translation>
|
||||
<translation>Back-end audio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save</source>
|
||||
|
@ -786,7 +810,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>separateUpdatesCheckBox</source>
|
||||
<translation>Dossier séparé pour les mises à jours:\nInstalle les mises à jours des jeux dans un dossier séparé pour une gestion plus facile.</translation>
|
||||
<translation>Dossier séparé pour les mises à jour:\nInstalle les mises à jours des jeux dans un dossier séparé pour une gestion plus facile.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>showSplashCheckBox</source>
|
||||
|
@ -806,7 +830,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>TrophyKey</source>
|
||||
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
|
||||
<translation>Clé de trophées:\nClé utilisée pour décrypter les trophées. Doit être obtenu à partir de votre console jailbreakée.\nDoit contenir des caractères hexadécimaux uniquement.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -826,7 +850,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>disableTrophycheckBox</source>
|
||||
<translation>Disable Trophy Pop-ups:\nDisable in-game trophy notifications. Trophy progress can still be tracked using the Trophy Viewer (right-click the game in the main window).</translation>
|
||||
<translation>Désactiver les notifications de trophées:\nDésactive les notifications de trophées en jeu. La progression des trophées peut toujours être suivie à l'aide de la Visionneuse de trophées (clique droit sur le jeu sur la fenêtre principale).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hideCursorGroupBox</source>
|
||||
|
@ -842,15 +866,15 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>enableCompatibilityCheckBox</source>
|
||||
<translation>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable "Update Compatibility On Startup" to get up-to-date information.</translation>
|
||||
<translation>Afficher les données de compatibilité:\nAffiche les informations de compatibilité des jeux dans une colonne dédiée. Activez "Mettre à jour la compatibilité au démarrage" pour avoir des informations à jour.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>checkCompatibilityOnStartupCheckBox</source>
|
||||
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
|
||||
<translation>Mettre à jour la compatibilité au démarrage:\nMettre à jour automatiquement la base de données de compatibilité au démarrage de shadPS4.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>updateCompatibilityButton</source>
|
||||
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation>
|
||||
<translation>Mettre à jour la compatibilité au démarrage:\nMet à jour immédiatement la base de données de compatibilité.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Never</source>
|
||||
|
@ -928,12 +952,32 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Activer le débogage RenderDoc:\nS'il est activé, l'émulateur fournit une compatibilité avec Renderdoc, permettant d'enregistrer et d'analyser la trame rendue actuelle.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collecter les Shaders:\nVous devez activer cette option pour modifier les shaders avec le menu de débogage (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Diagnostic de crash:\nCrée un fichier .yaml avec des informations sur l'état de Vulkan au moment du crash.\nUtile pour déboguer les erreurs "Device lost". Si cette option est activée, vous devez aussi activer Marqueur de débogage hôte ET invité.\nNe marche pas pour les GPUs Intel.\nVous devez activer le Vulkan Validation Layers ainsi que le Vulkan SDK pour que cela fonctionne.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copier la mémoire tampon GPU:\nContourne les conditions de course impliquant des soumissions GPU.\nPeut aider ou non en cas de crash PM4 type 0.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Marqueur de débogage hôte:\nInsère des informations côté émulateur telles que des marqueurs pour des commandes spécifiques AMDGPU autour des commandes Vulkan, ainsi que donner les noms de débogages des ressources.\nSi cette option est activée, vous devriez activer "Diagnostic de crash".\nUtile pour des programmes comme RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Marqueur de débogage invité:\nInsère tous les marqueurs de débogage que le jeu a ajouté a la commande mémoire tampon.\nSi cette option est activée, vous devriez activer "Diagnostic de crash".\nUtile pour des programmes comme RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
<message>
|
||||
<source>Cheats / Patches for </source>
|
||||
<translation>Cheats/Patchs pour </translation>
|
||||
<translation>Cheats / Patchs pour </translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>defaultTextEdit_MSG</source>
|
||||
|
@ -945,7 +989,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Serial: </source>
|
||||
<translation>Série: </translation>
|
||||
<translation>Numéro de série: </translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Version: </source>
|
||||
|
@ -1093,7 +1137,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>DownloadComplete_MSG</source>
|
||||
<translation>Patchs téléchargés avec succès ! Tous les patches disponibles pour tous les jeux ont été téléchargés, il n'est pas nécessaire de les télécharger individuellement pour chaque jeu comme c'est le cas pour les Cheats. Si le correctif n'apparaît pas, il se peut qu'il n'existe pas pour le numéro de série et la version spécifiques du jeu.</translation>
|
||||
<translation>Patchs téléchargés avec succès ! Tous les patches disponibles pour tous les jeux ont été téléchargés, il n'est pas nécessaire de les télécharger individuellement pour chaque jeu comme c'est le cas pour les Cheats. Si le correctif n'apparaît pas, il se peut qu'il n'existe pas pour la série et la version spécifiques du jeu.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Failed to parse JSON data from HTML.</source>
|
||||
|
@ -1113,7 +1157,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>You may need to update your game.</source>
|
||||
<translation>Vous devrez peut-être mettre à jour votre jeu.</translation>
|
||||
<translation>Vous devriez peut-être mettre à jour votre jeu.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Incompatibility Notice</source>
|
||||
|
@ -1137,7 +1181,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Directory does not exist:</source>
|
||||
<translation>Répertoire n'existe pas:</translation>
|
||||
<translation>Le répertoire n'existe pas:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Failed to open files.json for reading.</source>
|
||||
|
@ -1149,7 +1193,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Can't apply cheats before the game is started</source>
|
||||
<translation>Impossible d'appliquer les Cheats avant que le jeu ne commence.</translation>
|
||||
<translation>Impossible d'appliquer les cheats avant que le jeu ne soit lancé</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1164,11 +1208,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Serial</source>
|
||||
<translation>Série</translation>
|
||||
<translation>Numéro de série</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
<translation>Compatibilité</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Region</source>
|
||||
|
@ -1212,27 +1256,27 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Compatibility is untested</source>
|
||||
<translation>Compatibility is untested</translation>
|
||||
<translation>La compatibilité n'a pas été testé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game does not initialize properly / crashes the emulator</source>
|
||||
<translation>Game does not initialize properly / crashes the emulator</translation>
|
||||
<translation>Le jeu ne se lance pas correctement / crash l'émulateur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game boots, but only displays a blank screen</source>
|
||||
<translation>Game boots, but only displays a blank screen</translation>
|
||||
<translation>Le jeu démarre, mais n'affiche qu'un écran noir</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game displays an image but does not go past the menu</source>
|
||||
<translation>Game displays an image but does not go past the menu</translation>
|
||||
<translation>Le jeu affiche une image mais ne dépasse pas le menu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game has game-breaking glitches or unplayable performance</source>
|
||||
<translation>Game has game-breaking glitches or unplayable performance</translation>
|
||||
<translation>Le jeu a des problèmes majeurs ou des performances qui le rendent injouable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game can be completed with playable performance and no major glitches</source>
|
||||
<translation>Game can be completed with playable performance and no major glitches</translation>
|
||||
<translation>Le jeu peut être terminé avec des performances acceptables et sans problèmes majeurs</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1361,4 +1405,4 @@
|
|||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
</TS>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>RenderDoc Debugolás Engedélyezése</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Frissítés</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI Beállítások</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>RenderDoc hibakeresés engedélyezése:\nHa engedélyezve van, az emulátor kompatibilitást biztosít a Renderdoc számára, hogy lehetővé tegye a jelenleg renderelt keret rögzítését és elemzését.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Enable RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Pembaruan</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Pengaturan GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Aktifkan Debugging RenderDoc:\nJika diaktifkan, emulator akan menyediakan kompatibilitas dengan Renderdoc untuk memungkinkan pengambilan dan analisis bingkai yang sedang dirender.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -146,19 +146,19 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Compatibility...</source>
|
||||
<translation>Compatibility...</translation>
|
||||
<translation>Compatibilità...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update database</source>
|
||||
<translation>Update database</translation>
|
||||
<translation>Aggiorna database</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>View report</source>
|
||||
<translation>View report</translation>
|
||||
<translation>Visualizza rapporto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Submit a report</source>
|
||||
<translation>Submit a report</translation>
|
||||
<translation>Invia rapporto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut creation</source>
|
||||
|
@ -194,7 +194,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Update</translation>
|
||||
<translation>Aggiornamento</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no DLC to delete!</source>
|
||||
|
@ -249,7 +249,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
<translation>Apri Cartella shadps4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
|
@ -574,11 +574,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Trophy Key</source>
|
||||
<translation>Trophy Key</translation>
|
||||
<translation>Chiave Trofei</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy</source>
|
||||
<translation>Trophy</translation>
|
||||
<translation>Trofei</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logger</source>
|
||||
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Abilita RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Abilita Diagnostica Crash</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Raccogli Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copia Buffer GPU </translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Marcatori di Debug dell'Host </translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Marcatori di Debug del Guest </translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Aggiornamento</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Impostazioni GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Musica del Titolo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disabilita Notifica Trofei</translation>
|
||||
|
@ -750,7 +774,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Audio Backend</source>
|
||||
<translation>Audio Backend</translation>
|
||||
<translation>Backend Audio</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save</source>
|
||||
|
@ -806,7 +830,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>TrophyKey</source>
|
||||
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
|
||||
<translation>Chiave Trofei:\nChiave utilizzata per la decrittazione dei trofei. Deve essere estratta dalla vostra console con jailbreak.\nDeve contenere solo caratteri esadecimali.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -826,7 +850,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>disableTrophycheckBox</source>
|
||||
<translation>Disable Trophy Pop-ups:\nDisable in-game trophy notifications. Trophy progress can still be tracked using the Trophy Viewer (right-click the game in the main window).</translation>
|
||||
<translation>Disabilita Notifica Trofei:\nDisabilita notifiche in gioco dei trofei. Il progresso dei Trofei può ancora essere controllato con il Visualizzatore Trofei (clicca tasto destro sul gioco nella finestra principale).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hideCursorGroupBox</source>
|
||||
|
@ -928,12 +952,32 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Abilita Debugging RenderDoc:\nSe abilitato, l'emulatore fornirà compatibilità con Renderdoc per consentire la cattura e l'analisi del frame attualmente reso.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Raccogli Shader:\nBisogna attivare questa opzione per poter modificare gli shader nel menu di debug (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Diagnostica Crash:\nCrea un file .yaml che contiene informazioni riguardo lo stato del renderer Vulkan nel momento in cui si verifica un crash.\nUtile per poter effettuare il debug degli errori di tipo "Device Lost". Se hai questa opzione attiva dovresti abilitare anche Marcatori di Debug Host e Guest.\nNon è funzionante su GPU Intel.\nVulkan Validation Layers deve essere abilitato e bisogna aver installato l'SDK Vulkan per poter utilizzare questa funzione.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copia Buffer GPU:\nCerca di aggirare le race conditions che riguardano gli invii alla GPU.\nPotrebbe aiutare ad evitare crash che riguardano i PM4 di tipo 0.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Marcatori di Debug dell'Host:\nInserisce nel log informazioni ottenute dall'emulatore come ad esempio marcatori per comandi specifici AMDGPU quando si hanno comandi Vulkan e associa nomi di debug per le risorse.\nSe hai questa opzione abilitata dovresti abilitare anche Diagnostica Crash.\nUtile per programmi come RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Marcatori di Debug del Guest:\nInserisce nel log marcatori di debug che il gioco stesso ha aggiunto al buffer dei comandi.\nSe hai abilitato questa opzione dovresti abilitare anche Diagnostica Crash.\nUtile per programmi come RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
<message>
|
||||
<source>Cheats / Patches for </source>
|
||||
<translation>Cheats / Patches for </translation>
|
||||
<translation>Cheats / Patch per </translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>defaultTextEdit_MSG</source>
|
||||
|
@ -1200,7 +1244,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>h</source>
|
||||
<translation>h</translation>
|
||||
<translation>o</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>m</source>
|
||||
|
@ -1361,4 +1405,4 @@
|
|||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
</TS>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>RenderDocデバッグを有効にする</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>更新</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>トロフィーのポップアップを無効化</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>RenderDocデバッグを有効にする:\n有効にすると、エミュレーターはRenderdocとの互換性を提供し、現在レンダリング中のフレームのキャプチャと分析を可能にします。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Enable RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Update</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI Settings</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Enable RenderDoc Debugging:\nIf enabled, the emulator will provide compatibility with Renderdoc to allow capture and analysis of the currently rendered frame.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Enable RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Atnaujinimas</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI Nustatymai</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Įjungti RenderDoc derinimą:\nJei įjungta, emuliatorius suteiks suderinamumą su Renderdoc, kad būtų galima užfiksuoti ir analizuoti šiuo metu renderuojamą kadrą.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Open Folder...</source>
|
||||
<translation>Åpne mappen...</translation>
|
||||
<translation>Åpne mappe...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Game Folder</source>
|
||||
|
@ -126,7 +126,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Copy All</source>
|
||||
<translation>Kopier alle</translation>
|
||||
<translation>Kopier alt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete...</source>
|
||||
|
@ -146,19 +146,19 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Compatibility...</source>
|
||||
<translation>Compatibility...</translation>
|
||||
<translation>Kompatibilitet...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update database</source>
|
||||
<translation>Update database</translation>
|
||||
<translation>Oppdater database</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>View report</source>
|
||||
<translation>View report</translation>
|
||||
<translation>Vis rapport</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Submit a report</source>
|
||||
<translation>Submit a report</translation>
|
||||
<translation>Send inn en rapport</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut creation</source>
|
||||
|
@ -574,11 +574,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Trophy Key</source>
|
||||
<translation>Trophy Key</translation>
|
||||
<translation>Trofénøkkel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy</source>
|
||||
<translation>Trophy</translation>
|
||||
<translation>Trofé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logger</source>
|
||||
|
@ -629,7 +629,7 @@
|
|||
<translation>Grafikk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Gui</source>
|
||||
<source>GUI</source>
|
||||
<translation>Grensesnitt</translation>
|
||||
</message>
|
||||
<message>
|
||||
|
@ -658,7 +658,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Enable Shaders Dumping</source>
|
||||
<translation>Aktiver dumping av skyggelegger</translation>
|
||||
<translation>Aktiver skyggeleggerdumping</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable NULL GPU</source>
|
||||
|
@ -666,7 +666,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Paths</source>
|
||||
<translation>Stier</translation>
|
||||
<translation>Mapper</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game Folders</source>
|
||||
|
@ -680,17 +680,33 @@
|
|||
<source>Remove</source>
|
||||
<translation>Fjern</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Data Path</source>
|
||||
<translation>Lagrede datamappe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Browse</source>
|
||||
<translation>Endre mappe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>saveDataBox</source>
|
||||
<translation>Lagrede datamappe:\nListe over data shadPS4 lagrer.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>browseButton</source>
|
||||
<translation>Endre mappe:\nEndrer hvilken mappe shadPS4 skal lagre data til.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Debug</source>
|
||||
<translation>Feilretting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Debug Dumping</source>
|
||||
<translation>Aktiver dumping av feilretting</translation>
|
||||
<translation>Aktiver feilrettingsdumping</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Vulkan Validation Layers</source>
|
||||
<translation>Aktiver Vulkan valideringslag</translation>
|
||||
<translation>Aktiver Vulkan Validation Layers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Vulkan Synchronization Validation</source>
|
||||
|
@ -700,6 +716,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Aktiver RenderDoc feilretting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Aktiver krasjdiagnostikk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Lagre skyggeleggere</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Kopier GPU-buffere</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Vertsfeilsøkingsmarkører</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Gjestefeilsøkingsmarkører</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Oppdatering</translation>
|
||||
|
@ -718,7 +754,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>GUI Settings</source>
|
||||
<translation>GUI-innstillinger</translation>
|
||||
<translation>Grensesnitt-innstillinger</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Tittelmusikk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
|
@ -730,7 +770,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Update Compatibility Database On Startup</source>
|
||||
<translation>Oppdater kompatibilitets-database ved oppstart</translation>
|
||||
<translation>Oppdater database ved oppstart</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game Compatibility</source>
|
||||
|
@ -750,7 +790,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Audio Backend</source>
|
||||
<translation>Audio Backend</translation>
|
||||
<translation>Lydsystem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save</source>
|
||||
|
@ -806,7 +846,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>TrophyKey</source>
|
||||
<translation>Trophy Key:\nKey used to decrypt trophies. Must be obtained from your jailbroken console.\nMust contain only hex characters.</translation>
|
||||
<translation>Trofénøkkel:\nNøkkel brukes til å dekryptere trofeer. Må hentes fra din konsoll (jailbroken).\nMå bare inneholde sekskantede tegn.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>logTypeGroupBox</source>
|
||||
|
@ -846,7 +886,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>checkCompatibilityOnStartupCheckBox</source>
|
||||
<translation>Oppdater kompatibilitets-data ved oppstart:\nOppdaterer kompatibilitets-databasen automatisk når shadPS4 starter.</translation>
|
||||
<translation>Oppdater database ved oppstart:\nOppdaterer kompatibilitets-databasen automatisk når shadPS4 starter.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>updateCompatibilityButton</source>
|
||||
|
@ -894,7 +934,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>dumpShadersCheckBox</source>
|
||||
<translation>Aktiver dumping av skyggelegger:\nFor teknisk feilsøking lagrer skyggeleggerne fra spillet i en mappe mens de gjengis.</translation>
|
||||
<translation>Aktiver skyggeleggerdumping:\nFor teknisk feilsøking lagrer skyggeleggerne fra spillet i en mappe mens de gjengis.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>nullGpuCheckBox</source>
|
||||
|
@ -902,7 +942,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>gameFoldersBox</source>
|
||||
<translation>Spillmapper:\nListen over mapper som brukes for å se etter installerte spill.</translation>
|
||||
<translation>Spillmapper:\nListe over mapper som brukes for å se etter installerte spill.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>addFolderButton</source>
|
||||
|
@ -914,11 +954,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>debugDump</source>
|
||||
<translation>Aktiver dumping av feilsøking:\nLagrer import- og eksport-symbolene og filoverskriftsinformasjonen til det nåværende kjørende PS4-programmet i en katalog.</translation>
|
||||
<translation>Aktiver feilrettingsdumping:\nLagrer import- og eksport-symbolene og filoverskriftsinformasjonen til det nåværende kjørende PS4-programmet i en katalog.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>vkValidationCheckBox</source>
|
||||
<translation>Aktiver Vulkan valideringslag:\nAktiverer et system som validerer tilstanden til Vulkan-gjengiveren og logger informasjon om dens indre tilstand. Dette vil redusere ytelsen og sannsynligvis endre etterlignerens atferd.</translation>
|
||||
<translation>Aktiver Vulkan Validation Layers:\nAktiverer et system som validerer tilstanden til Vulkan-gjengiveren og logger informasjon om dens indre tilstand. Dette vil redusere ytelsen og sannsynligvis endre etterlignerens atferd.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>vkSyncValidationCheckBox</source>
|
||||
|
@ -928,6 +968,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Aktiver RenderDoc feilsøking:\nHvis aktivert, vil etterligneren gi kompatibilitet med Renderdoc for å tillate opptak og analyse av det nåværende gjengitte bildet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Lagre skyggeleggere:\nDu trenger dette aktivert for å redigere skyggeleggerne med feilsøkingsmenyen (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Krasjdiagnostikk:\nOppretter en .yaml-fil med informasjon om Vulkan-tilstanden ved krasj.\nNyttig for feilsøking 'Device lost' feil. Hvis du har dette aktivert, burde du aktivere vert OG gjestefeilsøkingsmarkører.\nFunker ikke med Intel GPU-er.\nDu trenger Vulkan Validation Layers og Vulkan SDK for at dette skal fungere.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Kopier GPU-buffere:\nKommer rundt løpsforhold som involverer GPU-innsendinger.\nKan muligens hjelpe med PM4 type 0 krasj.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Vertsfeilsøkingsmarkører:\nSetter inn etterligner-side informasjon som markører for spesifikke AMDGPU-kommandoer rundt Vulkan-kommandoer, i tillegg til å gi ressurser feilrettingsnavn.\nHvis du har dette aktivert, burde du aktivere krasjdiagnostikk.\nNyttig for programmer som RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Gjestefeilsøkingsmarkører:\nSetter inn eventuelle feilsøkingsmarkører spillet selv har lagt til kommandobufferen.\nHvis du har dette aktivert, burde du aktivere krasjdiagnostikk.\nNyttig for programmer som RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
@ -971,6 +1031,10 @@
|
|||
<source>Delete File</source>
|
||||
<translation>Slett fil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Close</source>
|
||||
<translation>Lukk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No files selected.</source>
|
||||
<translation>Ingen filer valgt.</translation>
|
||||
|
@ -1188,7 +1252,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Path</source>
|
||||
<translation>Sti</translation>
|
||||
<translation>Adresse</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play Time</source>
|
||||
|
@ -1232,7 +1296,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Game can be completed with playable performance and no major glitches</source>
|
||||
<translation>Spillet kan fullføres med spillbar ytelse og ingen store feil</translation>
|
||||
<translation>Spillet kan fullføres med spillbar ytelse og uten store feil</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1361,4 +1425,4 @@
|
|||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
</TS>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Enable RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Bijwerken</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI-Instellingen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>RenderDoc foutopsporing inschakelen:\nAls ingeschakeld, biedt de emulator compatibiliteit met Renderdoc om de momenteel gerenderde frame vast te leggen en te analyseren.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Włącz debugowanie RenderDoc</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Aktualizacja</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Ustawienia Interfejsu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Wyłącz wyskakujące okienka trofeów</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Włącz debugowanie RenderDoc:\nJeśli włączone, emulator zapewnia kompatybilność z Renderdoc, aby umożliwić nagrywanie i analizowanie aktualnie renderowanej klatki.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -538,7 +538,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Enable Fullscreen</source>
|
||||
<translation>Ativar Tela Cheia</translation>
|
||||
<translation>Habilitar Tela Cheia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Fullscreen Mode</source>
|
||||
|
@ -566,7 +566,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Enable Discord Rich Presence</source>
|
||||
<translation>Ativar Discord Rich Presence</translation>
|
||||
<translation>Habilitar Discord Rich Presence</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Username</source>
|
||||
|
@ -574,7 +574,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Trophy Key</source>
|
||||
<translation>Trophy Key</translation>
|
||||
<translation>Chave de Troféu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy</source>
|
||||
|
@ -582,7 +582,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Logger</source>
|
||||
<translation>Registro</translation>
|
||||
<translation>Registro-Log</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Log Type</source>
|
||||
|
@ -594,7 +594,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Open Log Location</source>
|
||||
<translation>Abrir local do log</translation>
|
||||
<translation>Abrir local do registro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Input</source>
|
||||
|
@ -658,11 +658,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Enable Shaders Dumping</source>
|
||||
<translation>Ativar Dumping de Shaders</translation>
|
||||
<translation>Habilitar Dumping de Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable NULL GPU</source>
|
||||
<translation>Ativar GPU NULA</translation>
|
||||
<translation>Habilitar GPU NULA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Paths</source>
|
||||
|
@ -686,19 +686,39 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Enable Debug Dumping</source>
|
||||
<translation>Ativar Depuração de Dumping</translation>
|
||||
<translation>Habilitar Depuração de Dumping</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Vulkan Validation Layers</source>
|
||||
<translation>Ativar Camadas de Validação do Vulkan</translation>
|
||||
<translation>Habilitar Camadas de Validação do Vulkan</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Vulkan Synchronization Validation</source>
|
||||
<translation>Ativar Validação de Sincronização do Vulkan</translation>
|
||||
<translation>Habilitar Validação de Sincronização do Vulkan</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Ativar Depuração por RenderDoc</translation>
|
||||
<translation>Habilitar Depuração do RenderDoc</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Habilitar Diagnóstico de Falhas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Coletar Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copiar Buffers de GPU</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Marcadores de Depuração do Host</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Marcadores de Depuração do Convidado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Configurações da Interface</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Música no Menu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Desabilitar Pop-ups dos Troféus</translation>
|
||||
|
@ -782,7 +806,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>fullscreenCheckBox</source>
|
||||
<translation>Ativar Tela Cheia:\nAltera a janela do jogo para o modo tela cheia.\nIsso pode ser alterado pressionando a tecla F11.</translation>
|
||||
<translation>Habilitar Tela Cheia:\nAltera a janela do jogo para o modo tela cheia.\nIsso pode ser alterado pressionando a tecla F11.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>separateUpdatesCheckBox</source>
|
||||
|
@ -798,7 +822,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>discordRPCCheckbox</source>
|
||||
<translation>Ativar Discord Rich Presence:\nExibe o ícone do emulador e informações relevantes no seu perfil do Discord.</translation>
|
||||
<translation>Habilitar Discord Rich Presence:\nExibe o ícone do emulador e informações relevantes no seu perfil do Discord.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>userName</source>
|
||||
|
@ -898,11 +922,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>dumpShadersCheckBox</source>
|
||||
<translation>Ativar Dumping de Shaders:\nArmazena os shaders do jogo em uma pasta durante a renderização para fins de depuração técnica.</translation>
|
||||
<translation>Habilitar Dumping de Shaders:\nArmazena os shaders do jogo em uma pasta durante a renderização para fins de depuração técnica.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>nullGpuCheckBox</source>
|
||||
<translation>Ativar GPU NULA:\nDesativa a renderização do jogo para fins de depuração técnica, como se não houvesse nenhuma placa gráfica.</translation>
|
||||
<translation>Habilitar GPU NULA:\nDesativa a renderização do jogo para fins de depuração técnica, como se não houvesse nenhuma placa gráfica.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>gameFoldersBox</source>
|
||||
|
@ -918,19 +942,39 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>debugDump</source>
|
||||
<translation>Ativar Depuração de Dumping:\nArmazena os símbolos de importação e exportação e as informações do cabeçalho do arquivo do programa PS4 atual em um diretório.</translation>
|
||||
<translation>Habilitar Depuração de Dumping:\nArmazena os símbolos de importação e exportação e as informações do cabeçalho do arquivo do programa PS4 atual em um diretório.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>vkValidationCheckBox</source>
|
||||
<translation>Ativar Camadas de Validação do Vulkan:\nAtiva um sistema que valida o estado do renderizador Vulkan e registra informações sobre seu estado interno.\nIsso diminui o desempenho e pode alterar o comportamento da emulação.</translation>
|
||||
<translation>Habilitar Camadas de Validação do Vulkan:\nAtiva um sistema que valida o estado do renderizador Vulkan e registra informações sobre seu estado interno.\nIsso diminui o desempenho e pode alterar o comportamento da emulação.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>vkSyncValidationCheckBox</source>
|
||||
<translation>Ativar Validação de Sincronização do Vulkan:\nAtiva um sistema que valida o agendamento de tarefas de renderização Vulkan.\nIsso diminui o desempenho e pode alterar o comportamento da emulação.</translation>
|
||||
<translation>Habilitar Validação de Sincronização do Vulkan:\nAtiva um sistema que valida o agendamento de tarefas de renderização Vulkan.\nIsso diminui o desempenho e pode alterar o comportamento da emulação.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>rdocCheckBox</source>
|
||||
<translation>Ativar depuração por RenderDoc:\nSe ativado, permite que o emulador tenha compatibilidade com RenderDoc para gravação e análise do quadro renderizado atual.</translation>
|
||||
<translation>Habilitar Depuração por RenderDoc:\nSe ativado, permite que o emulador tenha compatibilidade com RenderDoc para gravação e análise do quadro renderizado atual.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Coletar Shaders:\nVocê precisa habilitar isso para editar shaders com o menu de depuração (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Diagnósticos de Falha:\nCria um arquivo .yaml com informações sobre o estado do Vulkan no momento da falha.\nÚtil para depurar erros de 'Device lost'. Se você tiver isso habilitado, você deve habilitar os Marcadores de Depuração de Host e de Convidado.\nNão funciona em GPUs da Intel.\nVocê precisa ter as Camadas de Validação Vulkan habilitadas e o SDK do Vulkan para que isso funcione.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copiar Buffers de GPU:\nContorna condições de corrida envolvendo envios de GPU.\nPode ou não ajudar com travamentos do PM4 tipo 0.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Marcadores de Depuração de Host:\nInsere informações do lado do emulador, como marcadores para comandos AMDGPU específicos em torno de comandos Vulkan, além de fornecer nomes de depuração aos recursos.\nSe isso estiver habilitado, você deve habilitar o "Diagnóstico de Falha".\nÚtil para programas como o RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Marcadores de Depuração de Convidado:\nInsere quaisquer marcadores de depuração que o próprio jogo adicionou ao buffer de comando.\nSe isso estiver habilitado, você deve habilitar "Diagnóstico de Falha".\nÚtil para programas como o RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Enable RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Actualizare</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Setări GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Activează depanarea RenderDoc:\nDacă este activat, emulatorul va oferi compatibilitate cu Renderdoc pentru a permite capturarea și analiza cadrului redat în prezent.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -126,11 +126,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Copy All</source>
|
||||
<translation>Копировать все</translation>
|
||||
<translation>Копировать всё</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete...</source>
|
||||
<translation>Удаление...</translation>
|
||||
<translation>Удалить...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Game</source>
|
||||
|
@ -158,7 +158,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Submit a report</source>
|
||||
<translation>Отправить отчет</translation>
|
||||
<translation>Отправить отчёт</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Shortcut creation</source>
|
||||
|
@ -297,7 +297,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Elf Viewer</source>
|
||||
<translation>Elf</translation>
|
||||
<translation>Исполняемый файл</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game Install Directory</source>
|
||||
|
@ -542,7 +542,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Fullscreen Mode</source>
|
||||
<translation>Режим Полного Экран</translation>
|
||||
<translation>Тип полноэкранного режима</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Separate Update Folder</source>
|
||||
|
@ -574,11 +574,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Trophy Key</source>
|
||||
<translation>Trophy Key</translation>
|
||||
<translation>Ключ трофеев</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy</source>
|
||||
<translation>Trophy</translation>
|
||||
<translation>Трофеи</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logger</source>
|
||||
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Включить отладку RenderDoc</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Обновление</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Интерфейс</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Отключить уведомления о трофеях</translation>
|
||||
|
@ -750,7 +774,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Audio Backend</source>
|
||||
<translation>Звуковая Подсистема</translation>
|
||||
<translation>Звуковая подсистема</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save</source>
|
||||
|
@ -826,7 +850,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>disableTrophycheckBox</source>
|
||||
<translation>Отключить уведомления о трофеях:\nОтключает внутриигровые уведомления о трофеях. Прогресс трофеев по прежнему можно отслеживать в меню Просмотр трофеев (правая кнопка мыши по игре в главном окне).</translation>
|
||||
<translation>Отключить уведомления о трофеях:\nОтключает внутриигровые уведомления о трофеях. Прогресс трофеев по прежнему можно отслеживать в меню просмотра трофеев (правая кнопка мыши по игре в главном окне).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hideCursorGroupBox</source>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Включить отладку RenderDoc:\nЕсли включено, эмулятор обеспечит совместимость с Renderdoc, позволяя захватывать и анализировать текущие кадры во время рендеринга.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
@ -1192,11 +1236,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Play Time</source>
|
||||
<translation>Времени в игре</translation>
|
||||
<translation>Время в игре</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Never Played</source>
|
||||
<translation>Вы не играли</translation>
|
||||
<translation>Нет</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>h</source>
|
||||
|
@ -1361,4 +1405,4 @@
|
|||
<translation>ТБ</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
</TS>
|
||||
|
|
|
@ -249,7 +249,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Open shadPS4 Folder</source>
|
||||
<translation>Open shadPS4 Folder</translation>
|
||||
<translation>Hap dosjen e shadPS4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Exit</source>
|
||||
|
@ -542,7 +542,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Fullscreen Mode</source>
|
||||
<translation>Modaliteti i Plotë</translation>
|
||||
<translation>Mënyra me ekran të plotë</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Separate Update Folder</source>
|
||||
|
@ -550,7 +550,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Default tab when opening settings</source>
|
||||
<translation>Skeda e parazgjedhur kur hapni cilësimet</translation>
|
||||
<translation>Skeda e parazgjedhur kur hapen cilësimet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Game Size In List</source>
|
||||
|
@ -594,7 +594,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Open Log Location</source>
|
||||
<translation>Hap vendndodhjen e regjistrit</translation>
|
||||
<translation>Hap vendndodhjen e Ditarit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Input</source>
|
||||
|
@ -630,11 +630,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Gui</source>
|
||||
<translation>Ndërfaqe</translation>
|
||||
<translation>Ndërfaqja</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>User</source>
|
||||
<translation>Përdorues</translation>
|
||||
<translation>Përdoruesi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Graphics Device</source>
|
||||
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Aktivizo Korrigjimin RenderDoc</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Përditëso</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Cilësimet e GUI-së</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Çaktivizo njoftimet për Trofetë</translation>
|
||||
|
@ -822,7 +846,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>GUIMusicGroupBox</source>
|
||||
<translation>Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës të veçantë kur të zgjidhësh lojën në GUI.</translation>
|
||||
<translation>Luaj muzikën e titullit:\nNëse një lojë e mbështet, aktivizohet luajtja e muzikës të veçantë kur të zgjidhësh lojën në ndërfaqe.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>disableTrophycheckBox</source>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Aktivizo korrigjimin RenderDoc:\nNëse aktivizohet, emulatori do të ofrojë pajtueshmëri me Renderdoc për të lejuar kapjen dhe analizën e pamjes të pasqyruar në moment.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="sv_SE">
|
||||
<!-- SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
<!-- SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
SPDX-License-Identifier: GPL-2.0-or-later -->
|
||||
<context>
|
||||
<context>
|
||||
<name>AboutDialog</name>
|
||||
<message>
|
||||
<source>About shadPS4</source>
|
||||
|
@ -252,6 +252,10 @@
|
|||
<source>ERROR</source>
|
||||
<translation>FEL</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Close</source>
|
||||
<translation>Stäng</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheckUpdate</name>
|
||||
|
@ -676,6 +680,26 @@
|
|||
<source>Failed to convert icon.</source>
|
||||
<translation>Misslyckades med att konvertera ikon.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open Update Folder</source>
|
||||
<translation>Öppna uppdateringsmapp</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Save Data</source>
|
||||
<translation>Ta bort sparat data</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no update folder to open!</source>
|
||||
<translation>Detta spel har ingen uppdateringsmapp att öppna!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This game has no save data to delete!</source>
|
||||
<translation>Detta spel har inget sparat data att ta bort!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Data</source>
|
||||
<translation>Sparat data</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>InstallDirSelect</name>
|
||||
|
@ -687,6 +711,14 @@
|
|||
<source>Select which directory you want to install to.</source>
|
||||
<translation>Välj vilken katalog som du vill installera till.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Install All Queued to Selected Folder</source>
|
||||
<translation>Installera alla köade till markerad mapp</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete PKG File on Install</source>
|
||||
<translation>Ta bort PKG-fil efter installation</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
|
@ -1040,11 +1072,11 @@
|
|||
<source>Enable Separate Update Folder</source>
|
||||
<translation>Aktivera separat uppdateringsmapp</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default tab when opening settings</source>
|
||||
<translation>Standardflik när inställningar öppnas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<message>
|
||||
<source>Default tab when opening settings</source>
|
||||
<translation>Standardflik när inställningar öppnas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Game Size In List</source>
|
||||
<translation>Visa spelstorlek i listan</translation>
|
||||
</message>
|
||||
|
@ -1142,7 +1174,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Advanced</source>
|
||||
<translation>Avancerat</translation>
|
||||
<translation type="vanished">Avancerat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Shaders Dumping</source>
|
||||
|
@ -1188,6 +1220,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Aktivera RenderDoc-felsökning</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Uppdatera</translation>
|
||||
|
@ -1208,6 +1260,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Gränssnittsinställningar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Inaktivera popup för troféer</translation>
|
||||
|
@ -1298,7 +1354,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>updaterGroupBox</source>
|
||||
<translation>updaterGroupBox</translation>
|
||||
<translation>Uppdatering:\nRelease: Officiella versioner som släpps varje månad som kan vara mycket utdaterade, men är mer pålitliga och testade.\nNightly: Utvecklingsversioner som har de senaste funktionerna och fixarna, men kan innehålla fel och är mindre stabila</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>GUIMusicGroupBox</source>
|
||||
|
@ -1408,6 +1464,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Aktivera RenderDoc-felsökning:\nOm aktiverad kommer emulatorn att tillhandahålla kompatibilitet med Renderdoc för att tillåta fångst och analys för aktuell renderad bildruta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Release</source>
|
||||
<translation>Release</translation>
|
||||
|
@ -1432,6 +1508,38 @@
|
|||
<source>Directory to install games</source>
|
||||
<translation>Katalog att installera spel till</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Borderless</source>
|
||||
<translation>Fönster utan kanter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>True</source>
|
||||
<translation>Sant</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Motion Controls</source>
|
||||
<translation>Aktivera rörelsekontroller</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save Data Path</source>
|
||||
<translation>Sökväg för sparat data</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Browse</source>
|
||||
<translation>Bläddra</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Directory to save data</source>
|
||||
<translation>Katalog för sparat data</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>saveDataBox</source>
|
||||
<translation>Sökväg för sparat data:\nSökvägen där spelets sparade data kommer att sparas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>browseButton</source>
|
||||
<translation>Bläddra:\nBläddra efter en mapp att ställa in som sökväg för sparat data</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TrophyViewer</name>
|
||||
|
|
|
@ -546,7 +546,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Enable Separate Update Folder</source>
|
||||
<translation>Enable Separate Update Folder</translation>
|
||||
<translation>Ayrı Güncelleme Klasörünü Etkinleştir</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default tab when opening settings</source>
|
||||
|
@ -554,7 +554,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Show Game Size In List</source>
|
||||
<translation>Göster oyun boyutunu listede</translation>
|
||||
<translation>Oyun Boyutunu Listede Göster</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Splash</source>
|
||||
|
@ -574,11 +574,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Trophy Key</source>
|
||||
<translation>Trophy Key</translation>
|
||||
<translation>Kupa Anahtarı</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trophy</source>
|
||||
<translation>Trophy</translation>
|
||||
<translation>Kupa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logger</source>
|
||||
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>RenderDoc Hata Ayıklamayı Etkinleştir</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Güncelle</translation>
|
||||
|
@ -720,9 +740,13 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>GUI Ayarları</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
<translation>Kupa Açılır Pencerelerini Devre Dışı Bırak</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Play title music</source>
|
||||
|
@ -730,23 +754,23 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Update Compatibility Database On Startup</source>
|
||||
<translation>Update Compatibility Database On Startup</translation>
|
||||
<translation>Başlangıçta Uyumluluk Veritabanını Güncelle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game Compatibility</source>
|
||||
<translation>Game Compatibility</translation>
|
||||
<translation>Oyun Uyumluluğu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Display Compatibility Data</source>
|
||||
<translation>Display Compatibility Data</translation>
|
||||
<translation>Uyumluluk Verilerini Göster</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Compatibility Database</source>
|
||||
<translation>Update Compatibility Database</translation>
|
||||
<translation>Uyumluluk Veritabanını Güncelle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Volume</source>
|
||||
<translation>Ses seviyesi</translation>
|
||||
<translation>Ses Seviyesi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio Backend</source>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>RenderDoc Hata Ayıklamayı Etkinleştir:\nEğer etkinleştirilirse, emülatör mevcut render edilmiş çerçeveyi yakalamak ve analiz etmek için Renderdoc ile uyumluluk sunar.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
@ -1105,11 +1149,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>The game is in version: %1</source>
|
||||
<translation>Oyun sürümde: %1</translation>
|
||||
<translation>Oyun sürümü: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>The downloaded patch only works on version: %1</source>
|
||||
<translation>İndirilen yamanın sadece sürümde çalışıyor: %1</translation>
|
||||
<translation>İndirilen yama sadece şu sürümde çalışıyor: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You may need to update your game.</source>
|
||||
|
@ -1168,7 +1212,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Compatibility</source>
|
||||
<translation>Compatibility</translation>
|
||||
<translation>Uyumluluk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Region</source>
|
||||
|
@ -1196,35 +1240,35 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Never Played</source>
|
||||
<translation>Never Played</translation>
|
||||
<translation>Hiç Oynanmadı</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>h</source>
|
||||
<translation>h</translation>
|
||||
<translation>sa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>m</source>
|
||||
<translation>m</translation>
|
||||
<translation>dk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>s</source>
|
||||
<translation>s</translation>
|
||||
<translation>sn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Compatibility is untested</source>
|
||||
<translation>Compatibility is untested</translation>
|
||||
<translation>Uyumluluk test edilmemiş</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game does not initialize properly / crashes the emulator</source>
|
||||
<translation>Game does not initialize properly / crashes the emulator</translation>
|
||||
<translation>Oyun düzgün bir şekilde başlatılamıyor / emülatörü çökertiyor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game boots, but only displays a blank screen</source>
|
||||
<translation>Game boots, but only displays a blank screen</translation>
|
||||
<translation>Oyun başlatılabiliyor ancak yalnızca boş bir ekran gösteriyor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game displays an image but does not go past the menu</source>
|
||||
<translation>Game displays an image but does not go past the menu</translation>
|
||||
<translation>Oyun bir resim gösteriyor ancak menüleri geçemiyor</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Game has game-breaking glitches or unplayable performance</source>
|
||||
|
@ -1232,7 +1276,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Game can be completed with playable performance and no major glitches</source>
|
||||
<translation>Game can be completed with playable performance and no major glitches</translation>
|
||||
<translation>Oyun, oynanabilir performansla tamamlanabilir ve büyük aksaklık yok</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1267,7 +1311,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Your version is already up to date!</source>
|
||||
<translation>Versiyonunuz zaten güncel!</translation>
|
||||
<translation>Sürümünüz zaten güncel!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update Available</source>
|
||||
|
@ -1279,11 +1323,11 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Current Version</source>
|
||||
<translation>Mevcut Versiyon</translation>
|
||||
<translation>Mevcut Sürüm</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Latest Version</source>
|
||||
<translation>Son Versiyon</translation>
|
||||
<translation>Son Sürüm</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Do you want to update?</source>
|
||||
|
@ -1335,7 +1379,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Failed to create the update script file</source>
|
||||
<translation>Güncelleme betiği dosyası oluşturulamadı</translation>
|
||||
<translation>Güncelleme komut dosyası oluşturulamadı</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1361,4 +1405,4 @@
|
|||
<translation>TB</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
</TS>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Увімкнути налагодження RenderDoc</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Оновлення</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Інтерфейс</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Увімкнути налагодження RenderDoc:\nЯкщо увімкнено, емулятор забезпечить сумісність із Renderdoc, даючи змогу захоплювати й аналізувати поточні кадри під час рендерингу.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
|
@ -700,6 +700,26 @@
|
|||
<source>Enable RenderDoc Debugging</source>
|
||||
<translation>Enable RenderDoc Debugging</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Crash Diagnostics</source>
|
||||
<translation>Enable Crash Diagnostics</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Collect Shaders</source>
|
||||
<translation>Collect Shaders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy GPU Buffers</source>
|
||||
<translation>Copy GPU Buffers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Host Debug Markers</source>
|
||||
<translation>Host Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Guest Debug Markers</source>
|
||||
<translation>Guest Debug Markers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Update</source>
|
||||
<translation>Cập nhật</translation>
|
||||
|
@ -720,6 +740,10 @@
|
|||
<source>GUI Settings</source>
|
||||
<translation>Cài đặt GUI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Title Music</source>
|
||||
<translation>Title Music</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disable Trophy Pop-ups</source>
|
||||
<translation>Disable Trophy Pop-ups</translation>
|
||||
|
@ -928,6 +952,26 @@
|
|||
<source>rdocCheckBox</source>
|
||||
<translation>Bật gỡ lỗi RenderDoc:\nNếu được kích hoạt, trình giả lập sẽ cung cấp tính tương thích với Renderdoc để cho phép bắt và phân tích khung hình hiện tại đang được kết xuất.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>collectShaderCheckBox</source>
|
||||
<translation>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>crashDiagnosticsCheckBox</source>
|
||||
<translation>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging 'Device lost' errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>copyGPUBuffersCheckBox</source>
|
||||
<translation>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>hostMarkersCheckBox</source>
|
||||
<translation>Host Debug Markers:\nInserts emulator-side information like markers for specific AMDGPU commands around Vulkan commands, as well as giving resources debug names.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>guestMarkersCheckBox</source>
|
||||
<translation>Guest Debug Markers:\nInserts any debug markers the game itself has added to the command buffer.\nIf you have this enabled, you should enable Crash Diagnostics.\nUseful for programs like RenderDoc.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>CheatsPatches</name>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue