Merge branch 'main' into qt-style

This commit is contained in:
tomboylover93 2024-12-28 12:27:50 -03:00 committed by GitHub
commit a6e864f2e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 428 additions and 195 deletions

View File

@ -425,6 +425,8 @@ set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
src/core/libraries/screenshot/screenshot.h src/core/libraries/screenshot/screenshot.h
src/core/libraries/move/move.cpp
src/core/libraries/move/move.h
) )
set(DEV_TOOLS src/core/devtools/layer.cpp set(DEV_TOOLS src/core/devtools/layer.cpp

View File

@ -121,6 +121,11 @@ R3 | M | |
- [**skmp**](https://github.com/skmp) - [**skmp**](https://github.com/skmp)
- [**wheremyfoodat**](https://github.com/wheremyfoodat) - [**wheremyfoodat**](https://github.com/wheremyfoodat)
- [**raziel1000**](https://github.com/raziel1000) - [**raziel1000**](https://github.com/raziel1000)
- [**viniciuslrangel**](https://github.com/viniciuslrangel)
- [**roamic**](https://github.com/vladmikhalin)
- [**poly**](https://github.com/polybiusproxy)
- [**squidbus**](https://github.com/squidbus)
- [**frodo**](https://github.com/baggins183)
Logo is done by [**Xphalnos**](https://github.com/Xphalnos) Logo is done by [**Xphalnos**](https://github.com/Xphalnos)

View File

@ -97,6 +97,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, Http) \ SUB(Lib, Http) \
SUB(Lib, Ssl) \ SUB(Lib, Ssl) \
SUB(Lib, SysModule) \ SUB(Lib, SysModule) \
SUB(Lib, Move) \
SUB(Lib, NpManager) \ SUB(Lib, NpManager) \
SUB(Lib, NpScore) \ SUB(Lib, NpScore) \
SUB(Lib, NpTrophy) \ SUB(Lib, NpTrophy) \

View File

@ -57,8 +57,9 @@ enum class Class : u8 {
Lib_MsgDlg, ///< The LibSceMsgDialog implementation. Lib_MsgDlg, ///< The LibSceMsgDialog implementation.
Lib_AudioOut, ///< The LibSceAudioOut implementation. Lib_AudioOut, ///< The LibSceAudioOut implementation.
Lib_AudioIn, ///< The LibSceAudioIn implementation. Lib_AudioIn, ///< The LibSceAudioIn implementation.
Lib_Move, ///< The LibSceMove implementation.
Lib_Net, ///< The LibSceNet implementation. Lib_Net, ///< The LibSceNet implementation.
Lib_NetCtl, ///< The LibSecNetCtl implementation. Lib_NetCtl, ///< The LibSceNetCtl implementation.
Lib_SaveData, ///< The LibSceSaveData implementation. Lib_SaveData, ///< The LibSceSaveData implementation.
Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation. Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation.
Lib_Ssl, ///< The LibSceSsl implementation. Lib_Ssl, ///< The LibSceSsl implementation.

View File

@ -26,7 +26,7 @@ asm(".zerofill GUEST_SYSTEM,GUEST_SYSTEM,__guest_system,0xFBFC00000");
namespace Core { namespace Core {
static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE_PRO; static constexpr size_t BackingSize = SCE_KERNEL_TOTAL_MEM_PRO;
#ifdef _WIN32 #ifdef _WIN32

View File

@ -12,6 +12,7 @@
#include <atomic> #include <atomic>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <optional>
#include <semaphore> #include <semaphore>
#include <span> #include <span>
#include <vector> #include <vector>

View File

@ -5,7 +5,7 @@
#include <mutex> #include <mutex>
#include <cubeb/cubeb.h> #include <cubeb/cubeb.h>
#include "common/assert.h" #include "common/logging/log.h"
#include "common/ringbuffer.h" #include "common/ringbuffer.h"
#include "core/libraries/audio/audioout.h" #include "core/libraries/audio/audioout.h"
#include "core/libraries/audio/audioout_backend.h" #include "core/libraries/audio/audioout_backend.h"
@ -58,6 +58,8 @@ public:
} }
if (const auto ret = cubeb_stream_start(stream); ret != CUBEB_OK) { if (const auto ret = cubeb_stream_start(stream); ret != CUBEB_OK) {
LOG_ERROR(Lib_AudioOut, "Failed to start cubeb stream: {}", ret); LOG_ERROR(Lib_AudioOut, "Failed to start cubeb stream: {}", ret);
cubeb_stream_destroy(stream);
stream = nullptr;
return; return;
} }
} }
@ -74,6 +76,9 @@ public:
} }
void Output(void* ptr, size_t size) override { void Output(void* ptr, size_t size) override {
if (!stream) {
return;
}
auto* data = static_cast<u8*>(ptr); auto* data = static_cast<u8*>(ptr);
std::unique_lock lock{buffer_mutex}; std::unique_lock lock{buffer_mutex};

View File

@ -2,9 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <thread> #include <thread>
#include <SDL3/SDL_audio.h> #include <SDL3/SDL_audio.h>
#include <SDL3/SDL_init.h>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/audio/audioout.h" #include "core/libraries/audio/audioout.h"
@ -26,18 +24,28 @@ public:
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr); SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, nullptr, nullptr);
if (stream == nullptr) { if (stream == nullptr) {
LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError()); LOG_ERROR(Lib_AudioOut, "Failed to create SDL audio stream: {}", SDL_GetError());
return;
}
if (!SDL_ResumeAudioStreamDevice(stream)) {
LOG_ERROR(Lib_AudioOut, "Failed to resume SDL audio stream: {}", SDL_GetError());
SDL_DestroyAudioStream(stream);
stream = nullptr;
return;
} }
SDL_ResumeAudioStreamDevice(stream);
} }
~SDLPortBackend() override { ~SDLPortBackend() override {
if (stream) { if (!stream) {
SDL_DestroyAudioStream(stream); return;
stream = nullptr;
} }
SDL_DestroyAudioStream(stream);
stream = nullptr;
} }
void Output(void* ptr, size_t size) override { void Output(void* ptr, size_t size) override {
if (!stream) {
return;
}
SDL_PutAudioStreamData(stream, ptr, static_cast<int>(size)); SDL_PutAudioStreamData(stream, ptr, static_cast<int>(size));
while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) { while (SDL_GetAudioStreamAvailable(stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
// Yield to allow the stream to drain. // Yield to allow the stream to drain.
@ -46,7 +54,15 @@ public:
} }
void SetVolume(const std::array<int, 8>& ch_volumes) override { void SetVolume(const std::array<int, 8>& ch_volumes) override {
// TODO: Not yet implemented if (!stream) {
return;
}
// SDL does not have per-channel volumes, for now just take the maximum of the channels.
const auto vol = *std::ranges::max_element(ch_volumes);
if (!SDL_SetAudioStreamGain(stream, static_cast<float>(vol) / SCE_AUDIO_OUT_VOLUME_0DB)) {
LOG_WARNING(Lib_AudioOut, "Failed to change SDL audio stream volume: {}",
SDL_GetError());
}
} }
private: private:

View File

@ -513,10 +513,14 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
auto vqid = gnm_vqid - 1; auto vqid = gnm_vqid - 1;
auto& asc_queue = liverpool->asc_queues[{vqid}]; auto& asc_queue = liverpool->asc_queues[{vqid}];
const auto& offs_dw = asc_next_offs_dw[vqid]; auto& offs_dw = asc_next_offs_dw[vqid];
if (next_offs_dw < offs_dw) { if (next_offs_dw < offs_dw && next_offs_dw != 0) {
ASSERT_MSG(next_offs_dw == 0, "ACB submission is split at the end of ring buffer"); // For cases if a submission is split at the end of the ring buffer, we need to submit it in
// two parts to handle the wrap
liverpool->SubmitAsc(gnm_vqid, {reinterpret_cast<const u32*>(asc_queue.map_addr) + offs_dw,
asc_queue.ring_size_dw - offs_dw});
offs_dw = 0;
} }
const auto* acb_ptr = reinterpret_cast<const u32*>(asc_queue.map_addr) + offs_dw; const auto* acb_ptr = reinterpret_cast<const u32*>(asc_queue.map_addr) + offs_dw;

View File

@ -6,9 +6,11 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/types.h" #include "common/types.h"
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5056_MB; // ~ 5GB constexpr u64 SCE_KERNEL_TOTAL_MEM = 5248_MB;
// TODO: Confirm this value on hardware. constexpr u64 SCE_KERNEL_TOTAL_MEM_PRO = 5888_MB;
constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE_PRO = 5568_MB; // ~ 5.5GB
constexpr u64 SCE_FLEXIBLE_MEMORY_BASE = 64_MB;
constexpr u64 SCE_FLEXIBLE_MEMORY_SIZE = 512_MB;
namespace Core::Loader { namespace Core::Loader {
class SymbolsResolver; class SymbolsResolver;
@ -129,10 +131,6 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags);
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len); int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);
void* Malloc(size_t size);
void Free(void* ptr);
void RegisterMemory(Core::Loader::SymbolsResolver* sym); void RegisterMemory(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -18,6 +18,7 @@
#include "core/libraries/libc_internal/libc_internal.h" #include "core/libraries/libc_internal/libc_internal.h"
#include "core/libraries/libpng/pngdec.h" #include "core/libraries/libpng/pngdec.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "core/libraries/move/move.h"
#include "core/libraries/network/http.h" #include "core/libraries/network/http.h"
#include "core/libraries/network/net.h" #include "core/libraries/network/net.h"
#include "core/libraries/network/netctl.h" #include "core/libraries/network/netctl.h"
@ -91,6 +92,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::Remoteplay::RegisterlibSceRemoteplay(sym); Libraries::Remoteplay::RegisterlibSceRemoteplay(sym);
Libraries::Videodec::RegisterlibSceVideodec(sym); Libraries::Videodec::RegisterlibSceVideodec(sym);
Libraries::RazorCpu::RegisterlibSceRazorCpu(sym); Libraries::RazorCpu::RegisterlibSceRazorCpu(sym);
Libraries::Move::RegisterlibSceMove(sym);
} }
} // namespace Libraries } // namespace Libraries

View File

@ -0,0 +1,44 @@
// 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 "move.h"
namespace Libraries::Move {
int PS4_SYSV_ABI sceMoveOpen() {
LOG_ERROR(Lib_Move, "(STUBBED) called");
return ORBIS_FAIL;
}
int PS4_SYSV_ABI sceMoveGetDeviceInfo() {
LOG_ERROR(Lib_Move, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceMoveReadStateRecent() {
LOG_TRACE(Lib_Move, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceMoveTerm() {
LOG_ERROR(Lib_Move, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceMoveInit() {
LOG_ERROR(Lib_Move, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterlibSceMove(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("HzC60MfjJxU", "libSceMove", 1, "libSceMove", 1, 1, sceMoveOpen);
LIB_FUNCTION("GWXTyxs4QbE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveGetDeviceInfo);
LIB_FUNCTION("f2bcpK6kJfg", "libSceMove", 1, "libSceMove", 1, 1, sceMoveReadStateRecent);
LIB_FUNCTION("tsZi60H4ypY", "libSceMove", 1, "libSceMove", 1, 1, sceMoveTerm);
LIB_FUNCTION("j1ITE-EoJmE", "libSceMove", 1, "libSceMove", 1, 1, sceMoveInit);
};
} // namespace Libraries::Move

View 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::Move {
int PS4_SYSV_ABI sceMoveOpen();
int PS4_SYSV_ABI sceMoveGetDeviceInfo();
int PS4_SYSV_ABI sceMoveReadStateRecent();
int PS4_SYSV_ABI sceMoveTerm();
int PS4_SYSV_ABI sceMoveInit();
void RegisterlibSceMove(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Move

View File

@ -498,7 +498,7 @@ int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo(OrbisNpTrophyContext context, OrbisNpT
s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context, s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
OrbisNpTrophyHandle handle, OrbisNpTrophyHandle handle,
OrbisNpTrophyFlagArray* flags, u32* count) { OrbisNpTrophyFlagArray* flags, u32* count) {
LOG_INFO(Lib_NpTrophy, "GetTrophyUnlockState called"); LOG_INFO(Lib_NpTrophy, "called");
if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT) if (context == ORBIS_NP_TROPHY_INVALID_CONTEXT)
return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT; return ORBIS_NP_TROPHY_ERROR_INVALID_CONTEXT;
@ -519,8 +519,9 @@ s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(OrbisNpTrophyContext context,
pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str()); pugi::xml_parse_result result = doc.load_file(trophy_file.native().c_str());
if (!result) { if (!result) {
LOG_ERROR(Lib_NpTrophy, "Failed to open trophy xml : {}", result.description()); LOG_ERROR(Lib_NpTrophy, "Failed to open trophy XML: {}", result.description());
return -1; *count = 0;
return ORBIS_OK;
} }
int num_trophies = 0; int num_trophies = 0;

View File

@ -5,6 +5,7 @@
#include "common/arch.h" #include "common/arch.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/config.h" #include "common/config.h"
#include "common/elf_info.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/path_util.h" #include "common/path_util.h"
#include "common/string_util.h" #include "common/string_util.h"
@ -65,21 +66,41 @@ void Linker::Execute() {
Relocate(m.get()); Relocate(m.get());
} }
// Configure used flexible memory size. // Configure the direct and flexible memory regions.
if (const auto* proc_param = GetProcParam()) { u64 fmem_size = SCE_FLEXIBLE_MEMORY_SIZE;
if (proc_param->size >= bool use_extended_mem1 = true, use_extended_mem2 = true;
offsetof(OrbisProcParam, mem_param) + sizeof(OrbisKernelMemParam*)) {
if (const auto* mem_param = proc_param->mem_param) { const auto* proc_param = GetProcParam();
if (mem_param->size >= ASSERT(proc_param);
offsetof(OrbisKernelMemParam, flexible_memory_size) + sizeof(u64*)) {
if (const auto* flexible_size = mem_param->flexible_memory_size) { Core::OrbisKernelMemParam mem_param{};
memory->SetupMemoryRegions(*flexible_size); if (proc_param->size >= offsetof(OrbisProcParam, mem_param) + sizeof(OrbisKernelMemParam*)) {
} if (proc_param->mem_param) {
mem_param = *proc_param->mem_param;
if (mem_param.size >=
offsetof(OrbisKernelMemParam, flexible_memory_size) + sizeof(u64*)) {
if (const auto* flexible_size = mem_param.flexible_memory_size) {
fmem_size = *flexible_size + SCE_FLEXIBLE_MEMORY_BASE;
} }
} }
} }
} }
if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_1) + sizeof(u64*)) {
mem_param.extended_memory_1 = nullptr;
}
if (mem_param.size < offsetof(OrbisKernelMemParam, extended_memory_2) + sizeof(u64*)) {
mem_param.extended_memory_2 = nullptr;
}
const u64 sdk_ver = proc_param->sdk_version;
if (sdk_ver < Common::ElfInfo::FW_50) {
use_extended_mem1 = mem_param.extended_memory_1 ? *mem_param.extended_memory_1 : false;
use_extended_mem2 = mem_param.extended_memory_2 ? *mem_param.extended_memory_2 : false;
}
memory->SetupMemoryRegions(fmem_size, use_extended_mem1, use_extended_mem2);
main_thread.Run([this, module](std::stop_token) { main_thread.Run([this, module](std::stop_token) {
Common::SetCurrentThreadName("GAME_MainThread"); Common::SetCurrentThreadName("GAME_MainThread");
LoadSharedLibraries(); LoadSharedLibraries();

View File

@ -22,8 +22,9 @@ struct OrbisKernelMemParam {
u8* extended_memory_1; u8* extended_memory_1;
u64* extended_gpu_page_table; u64* extended_gpu_page_table;
u8* extended_memory_2; u8* extended_memory_2;
u64* exnteded_cpu_page_table; u64* extended_cpu_page_table;
}; };
static_assert(sizeof(OrbisKernelMemParam) == 0x38);
struct OrbisProcParam { struct OrbisProcParam {
u64 size; u64 size;

View File

@ -12,12 +12,7 @@
namespace Core { namespace Core {
constexpr u64 SCE_DEFAULT_FLEXIBLE_MEMORY_SIZE = 448_MB;
MemoryManager::MemoryManager() { MemoryManager::MemoryManager() {
// Set up the direct and flexible memory regions.
SetupMemoryRegions(SCE_DEFAULT_FLEXIBLE_MEMORY_SIZE);
// Insert a virtual memory area that covers the entire area we manage. // Insert a virtual memory area that covers the entire area we manage.
const VAddr system_managed_base = impl.SystemManagedVirtualBase(); const VAddr system_managed_base = impl.SystemManagedVirtualBase();
const size_t system_managed_size = impl.SystemManagedVirtualSize(); const size_t system_managed_size = impl.SystemManagedVirtualSize();
@ -38,10 +33,17 @@ MemoryManager::MemoryManager() {
MemoryManager::~MemoryManager() = default; MemoryManager::~MemoryManager() = default;
void MemoryManager::SetupMemoryRegions(u64 flexible_size) { void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1,
const auto total_size = bool use_extended_mem2) {
Config::isNeoMode() ? SCE_KERNEL_MAIN_DMEM_SIZE_PRO : SCE_KERNEL_MAIN_DMEM_SIZE; const bool is_neo = Config::isNeoMode();
total_flexible_size = flexible_size; auto total_size = is_neo ? SCE_KERNEL_TOTAL_MEM_PRO : SCE_KERNEL_TOTAL_MEM;
if (!use_extended_mem1 && is_neo) {
total_size -= 256_MB;
}
if (!use_extended_mem2 && !is_neo) {
total_size -= 128_MB;
}
total_flexible_size = flexible_size - SCE_FLEXIBLE_MEMORY_BASE;
total_direct_size = total_size - flexible_size; total_direct_size = total_size - flexible_size;
// Insert an area that covers direct memory physical block. // Insert an area that covers direct memory physical block.

View File

@ -166,7 +166,7 @@ public:
bool TryWriteBacking(void* address, const void* data, u32 num_bytes); bool TryWriteBacking(void* address, const void* data, u32 num_bytes);
void SetupMemoryRegions(u64 flexible_size); void SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1, bool use_extended_mem2);
PAddr PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment); PAddr PoolExpand(PAddr search_start, PAddr search_end, size_t size, u64 alignment);

View File

@ -4,11 +4,14 @@
#include "functional" #include "functional"
#include "iostream" #include "iostream"
#include "string" #include "string"
#include "system_error"
#include "unordered_map" #include "unordered_map"
#include <fmt/core.h> #include <fmt/core.h>
#include "common/config.h" #include "common/config.h"
#include "common/memory_patcher.h" #include "common/memory_patcher.h"
#include "common/path_util.h"
#include "core/file_sys/fs.h"
#include "emulator.h" #include "emulator.h"
#ifdef _WIN32 #ifdef _WIN32
@ -20,6 +23,10 @@ int main(int argc, char* argv[]) {
SetConsoleOutputCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8);
#endif #endif
// Load configurations
const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
Config::load(user_dir / "config.toml");
bool has_game_argument = false; bool has_game_argument = false;
std::string game_path; std::string game_path;
@ -33,6 +40,7 @@ int main(int argc, char* argv[]) {
" -p, --patch <patch_file> Apply specified patch file\n" " -p, --patch <patch_file> Apply specified patch file\n"
" -f, --fullscreen <true|false> Specify window initial fullscreen " " -f, --fullscreen <true|false> Specify window initial fullscreen "
"state. Does not overwrite the config file.\n" "state. Does not overwrite the config file.\n"
" --add-game-folder <folder> Adds a new game folder to the config.\n"
" -h, --help Display this help message\n"; " -h, --help Display this help message\n";
exit(0); exit(0);
}}, }},
@ -81,6 +89,25 @@ int main(int argc, char* argv[]) {
Config::setFullscreenMode(is_fullscreen); Config::setFullscreenMode(is_fullscreen);
}}, }},
{"--fullscreen", [&](int& i) { arg_map["-f"](i); }}, {"--fullscreen", [&](int& i) { arg_map["-f"](i); }},
{"--add-game-folder",
[&](int& i) {
if (++i >= argc) {
std::cerr << "Error: Missing argument for --add-game-folder\n";
exit(1);
}
std::string config_dir(argv[i]);
std::filesystem::path config_path = std::filesystem::path(config_dir);
std::error_code discard;
if (!std::filesystem::exists(config_path, discard)) {
std::cerr << "Error: File does not exist: " << config_path << "\n";
exit(1);
}
Config::addGameInstallDir(config_path);
Config::save(Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml");
std::cout << "Game folder successfully saved.\n";
exit(0);
}},
}; };
if (argc == 1) { if (argc == 1) {
@ -105,20 +132,41 @@ int main(int argc, char* argv[]) {
} }
} }
// If no game directory is set and no command line argument, prompt for it
if (Config::getGameInstallDirs().empty()) {
std::cout << "Warning: No game folder set, please set it by calling shadps4"
" with the --add-game-folder <folder_name> argument";
}
if (!has_game_argument) { if (!has_game_argument) {
std::cerr << "Error: Please provide a game path or ID.\n"; std::cerr << "Error: Please provide a game path or ID.\n";
exit(1); exit(1);
} }
// Check if the game path or ID exists // Check if the game path or ID exists
if (!std::filesystem::exists(game_path)) { std::filesystem::path eboot_path(game_path);
std::cerr << "Error: Game file not found\n";
return -1; // 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
bool game_found = false;
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;
game_found = true;
break;
}
}
if (!game_found) {
std::cerr << "Error: Game ID or file path not found: " << game_path << std::endl;
return 1;
}
} }
// Run the emulator with the specified game // Run the emulator with the resolved eboot path
Core::Emulator emulator; Core::Emulator emulator;
emulator.Run(game_path); emulator.Run(eboot_path);
return 0; return 0;
} }

View File

@ -347,9 +347,8 @@ public:
if (selected == deleteUpdate) { if (selected == deleteUpdate) {
if (!std::filesystem::exists(Common::FS::PathFromQString(game_update_path))) { if (!std::filesystem::exists(Common::FS::PathFromQString(game_update_path))) {
QMessageBox::critical( QMessageBox::critical(nullptr, tr("Error"),
nullptr, tr("Error"), QString(tr("This game has no update to delete!")));
QString(tr("This game has no separate update to delete!")));
error = true; error = true;
} else { } else {
folder_path = game_update_path; folder_path = game_update_path;

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "iostream" #include "iostream"
#include "system_error"
#include "unordered_map" #include "unordered_map"
#include "common/config.h" #include "common/config.h"
@ -31,7 +32,7 @@ int main(int argc, char* argv[]) {
bool has_command_line_argument = argc > 1; bool has_command_line_argument = argc > 1;
bool show_gui = false, has_game_argument = false; bool show_gui = false, has_game_argument = false;
std::string gamePath; std::string game_path;
// Map of argument strings to lambda functions // Map of argument strings to lambda functions
std::unordered_map<std::string, std::function<void(int&)>> arg_map = { std::unordered_map<std::string, std::function<void(int&)>> arg_map = {
@ -46,6 +47,7 @@ int main(int argc, char* argv[]) {
" -s, --show-gui Show the GUI\n" " -s, --show-gui Show the GUI\n"
" -f, --fullscreen <true|false> Specify window initial fullscreen " " -f, --fullscreen <true|false> Specify window initial fullscreen "
"state. Does not overwrite the config file.\n" "state. Does not overwrite the config file.\n"
" --add-game-folder <folder> Adds a new game folder to the config.\n"
" -h, --help Display this help message\n"; " -h, --help Display this help message\n";
exit(0); exit(0);
}}, }},
@ -57,7 +59,7 @@ int main(int argc, char* argv[]) {
{"-g", {"-g",
[&](int& i) { [&](int& i) {
if (i + 1 < argc) { if (i + 1 < argc) {
gamePath = argv[++i]; game_path = argv[++i];
has_game_argument = true; has_game_argument = true;
} else { } else {
std::cerr << "Error: Missing argument for -g/--game\n"; std::cerr << "Error: Missing argument for -g/--game\n";
@ -98,6 +100,25 @@ int main(int argc, char* argv[]) {
Config::setFullscreenMode(is_fullscreen); Config::setFullscreenMode(is_fullscreen);
}}, }},
{"--fullscreen", [&](int& i) { arg_map["-f"](i); }}, {"--fullscreen", [&](int& i) { arg_map["-f"](i); }},
{"--add-game-folder",
[&](int& i) {
if (++i >= argc) {
std::cerr << "Error: Missing argument for --add-game-folder\n";
exit(1);
}
std::string config_dir(argv[i]);
std::filesystem::path config_path = std::filesystem::path(config_dir);
std::error_code discard;
if (!std::filesystem::is_directory(config_path, discard)) {
std::cerr << "Error: Directory does not exist: " << config_path << "\n";
exit(1);
}
Config::addGameInstallDir(config_path);
Config::save(Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "config.toml");
std::cout << "Game folder successfully saved.\n";
exit(0);
}},
}; };
// Parse command-line arguments using the map // Parse command-line arguments using the map
@ -106,6 +127,10 @@ int main(int argc, char* argv[]) {
auto it = arg_map.find(cur_arg); auto it = arg_map.find(cur_arg);
if (it != arg_map.end()) { if (it != arg_map.end()) {
it->second(i); // Call the associated lambda function it->second(i); // Call the associated lambda function
} else if (i == argc - 1 && !has_game_argument) {
// Assume the last argument is the game file if not specified via -g/--game
game_path = argv[i];
has_game_argument = true;
} else { } else {
std::cerr << "Unknown argument: " << cur_arg << ", see --help for info.\n"; std::cerr << "Unknown argument: " << cur_arg << ", see --help for info.\n";
return 1; return 1;
@ -134,14 +159,14 @@ int main(int argc, char* argv[]) {
// Process game path or ID if provided // Process game path or ID if provided
if (has_game_argument) { if (has_game_argument) {
std::filesystem::path game_file_path(gamePath); std::filesystem::path game_file_path(game_path);
// Check if the provided path is a valid file // Check if the provided path is a valid file
if (!std::filesystem::exists(game_file_path)) { 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
bool game_found = false; bool game_found = false;
for (const auto& install_dir : Config::getGameInstallDirs()) { for (const auto& install_dir : Config::getGameInstallDirs()) {
auto potential_game_path = install_dir / gamePath / "eboot.bin"; auto potential_game_path = install_dir / game_path / "eboot.bin";
if (std::filesystem::exists(potential_game_path)) { if (std::filesystem::exists(potential_game_path)) {
game_file_path = potential_game_path; game_file_path = potential_game_path;
game_found = true; game_found = true;
@ -149,7 +174,7 @@ int main(int argc, char* argv[]) {
} }
} }
if (!game_found) { if (!game_found) {
std::cerr << "Error: Game ID or file path not found: " << gamePath << std::endl; std::cerr << "Error: Game ID or file path not found: " << game_path << std::endl;
return 1; return 1;
} }
} }

View File

@ -115,6 +115,7 @@ void MainWindow::CreateActions() {
m_theme_act_group->addAction(ui->setThemeBlue); m_theme_act_group->addAction(ui->setThemeBlue);
m_theme_act_group->addAction(ui->setThemeViolet); m_theme_act_group->addAction(ui->setThemeViolet);
m_theme_act_group->addAction(ui->setThemeGruvbox); m_theme_act_group->addAction(ui->setThemeGruvbox);
m_theme_act_group->addAction(ui->setThemeTokyoNight);
m_theme_act_group->addAction(ui->setThemeSystem); m_theme_act_group->addAction(ui->setThemeSystem);
} }
@ -572,6 +573,14 @@ void MainWindow::CreateConnects() {
isIconBlack = false; isIconBlack = false;
} }
}); });
connect(ui->setThemeTokyoNight, &QAction::triggered, &m_window_themes, [this]() {
m_window_themes.SetWindowTheme(Theme::TokyoNight, ui->mw_searchbar);
Config::setMainWindowTheme(static_cast<int>(Theme::TokyoNight));
if (isIconBlack) {
SetUiIcons(false);
isIconBlack = false;
}
});
connect(ui->setThemeSystem, &QAction::triggered, &m_window_themes, [this]() { connect(ui->setThemeSystem, &QAction::triggered, &m_window_themes, [this]() {
m_window_themes.SetWindowTheme(Theme::System, ui->mw_searchbar); m_window_themes.SetWindowTheme(Theme::System, ui->mw_searchbar);
Config::setMainWindowTheme(static_cast<int>(Theme::System)); Config::setMainWindowTheme(static_cast<int>(Theme::System));
@ -980,6 +989,11 @@ void MainWindow::SetLastUsedTheme() {
isIconBlack = false; isIconBlack = false;
SetUiIcons(false); SetUiIcons(false);
break; break;
case Theme::TokyoNight:
ui->setThemeTokyoNight->setChecked(true);
isIconBlack = false;
SetUiIcons(false);
break;
case Theme::System: case Theme::System:
ui->setThemeSystem->setChecked(true); ui->setThemeSystem->setChecked(true);
bool isSystemDarkMode; bool isSystemDarkMode;

View File

@ -151,6 +151,28 @@ void WindowThemes::SetWindowTheme(Theme theme, QLineEdit* mw_searchbar) {
themePalette.setColor(QPalette::HighlightedText, Qt::black); themePalette.setColor(QPalette::HighlightedText, Qt::black);
qApp->setPalette(themePalette); qApp->setPalette(themePalette);
break; break;
case Theme::TokyoNight:
mw_searchbar->setStyleSheet(
"QLineEdit {"
"background-color: #1a1b26; color: #9d7cd8; border: 1px solid #9d7cd8; "
"border-radius: 4px; padding: 5px; }"
"QLineEdit:focus {"
"border: 1px solid #7aa2f7; }");
themePalette.setColor(QPalette::Window, QColor(31, 35, 53));
themePalette.setColor(QPalette::WindowText, QColor(192, 202, 245));
themePalette.setColor(QPalette::Base, QColor(25, 28, 39));
themePalette.setColor(QPalette::AlternateBase, QColor(36, 40, 59));
themePalette.setColor(QPalette::ToolTipBase, QColor(192, 202, 245));
themePalette.setColor(QPalette::ToolTipText, QColor(192, 202, 245));
themePalette.setColor(QPalette::Text, QColor(192, 202, 245));
themePalette.setColor(QPalette::Button, QColor(30, 30, 41));
themePalette.setColor(QPalette::ButtonText, QColor(192, 202, 245));
themePalette.setColor(QPalette::BrightText, QColor(197, 59, 83));
themePalette.setColor(QPalette::Link, QColor(79, 214, 190));
themePalette.setColor(QPalette::Highlight, QColor(79, 214, 190));
themePalette.setColor(QPalette::HighlightedText, Qt::black);
qApp->setPalette(themePalette);
break;
case Theme::System: case Theme::System:
mw_searchbar->setStyleSheet("QLineEdit {" mw_searchbar->setStyleSheet("QLineEdit {"
"border: 1px solid;" "border: 1px solid;"

View File

@ -9,7 +9,7 @@
#include <QStyleFactory> #include <QStyleFactory>
#include <QWidget> #include <QWidget>
enum class Theme : int { Dark, Light, Green, Blue, Violet, Gruvbox, System }; enum class Theme : int { Dark, Light, Green, Blue, Violet, Gruvbox, TokyoNight, System };
class WindowThemes : public QObject { class WindowThemes : public QObject {
Q_OBJECT Q_OBJECT

View File

@ -37,6 +37,7 @@ public:
QAction* setThemeBlue; QAction* setThemeBlue;
QAction* setThemeViolet; QAction* setThemeViolet;
QAction* setThemeGruvbox; QAction* setThemeGruvbox;
QAction* setThemeTokyoNight;
QAction* setThemeSystem; QAction* setThemeSystem;
QWidget* centralWidget; QWidget* centralWidget;
QLineEdit* mw_searchbar; QLineEdit* mw_searchbar;
@ -163,6 +164,9 @@ public:
setThemeGruvbox = new QAction(MainWindow); setThemeGruvbox = new QAction(MainWindow);
setThemeGruvbox->setObjectName("setThemeGruvbox"); setThemeGruvbox->setObjectName("setThemeGruvbox");
setThemeGruvbox->setCheckable(true); setThemeGruvbox->setCheckable(true);
setThemeTokyoNight = new QAction(MainWindow);
setThemeTokyoNight->setObjectName("setThemeTokyoNight");
setThemeTokyoNight->setCheckable(true);
setThemeSystem = new QAction(MainWindow); setThemeSystem = new QAction(MainWindow);
setThemeSystem->setObjectName("setThemeSystem"); setThemeSystem->setObjectName("setThemeSystem");
setThemeSystem->setCheckable(true); setThemeSystem->setCheckable(true);
@ -291,6 +295,7 @@ public:
menuThemes->addAction(setThemeBlue); menuThemes->addAction(setThemeBlue);
menuThemes->addAction(setThemeViolet); menuThemes->addAction(setThemeViolet);
menuThemes->addAction(setThemeGruvbox); menuThemes->addAction(setThemeGruvbox);
menuThemes->addAction(setThemeTokyoNight);
menuThemes->addAction(setThemeSystem); menuThemes->addAction(setThemeSystem);
menuGame_List_Icons->addAction(setIconSizeTinyAct); menuGame_List_Icons->addAction(setIconSizeTinyAct);
menuGame_List_Icons->addAction(setIconSizeSmallAct); menuGame_List_Icons->addAction(setIconSizeSmallAct);
@ -379,6 +384,7 @@ public:
setThemeBlue->setText(QCoreApplication::translate("MainWindow", "Blue", nullptr)); setThemeBlue->setText(QCoreApplication::translate("MainWindow", "Blue", nullptr));
setThemeViolet->setText(QCoreApplication::translate("MainWindow", "Violet", nullptr)); setThemeViolet->setText(QCoreApplication::translate("MainWindow", "Violet", nullptr));
setThemeGruvbox->setText("Gruvbox"); setThemeGruvbox->setText("Gruvbox");
setThemeTokyoNight->setText("Tokyo Night");
setThemeSystem->setText(QCoreApplication::translate("MainWindow", "System", nullptr)); setThemeSystem->setText(QCoreApplication::translate("MainWindow", "System", nullptr));
toolBar->setWindowTitle(QCoreApplication::translate("MainWindow", "toolBar", nullptr)); toolBar->setWindowTitle(QCoreApplication::translate("MainWindow", "toolBar", nullptr));
} // retranslateUi } // retranslateUi

View File

@ -200,7 +200,6 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices,
ui->fullscreenCheckBox->installEventFilter(this); ui->fullscreenCheckBox->installEventFilter(this);
ui->separateUpdatesCheckBox->installEventFilter(this); ui->separateUpdatesCheckBox->installEventFilter(this);
ui->showSplashCheckBox->installEventFilter(this); ui->showSplashCheckBox->installEventFilter(this);
ui->ps4proCheckBox->installEventFilter(this);
ui->discordRPCCheckbox->installEventFilter(this); ui->discordRPCCheckbox->installEventFilter(this);
ui->userName->installEventFilter(this); ui->userName->installEventFilter(this);
ui->logTypeGroupBox->installEventFilter(this); ui->logTypeGroupBox->installEventFilter(this);
@ -297,7 +296,6 @@ void SettingsDialog::LoadValuesFromConfig() {
ui->separateUpdatesCheckBox->setChecked( ui->separateUpdatesCheckBox->setChecked(
toml::find_or<bool>(data, "General", "separateUpdateEnabled", false)); toml::find_or<bool>(data, "General", "separateUpdateEnabled", false));
ui->showSplashCheckBox->setChecked(toml::find_or<bool>(data, "General", "showSplash", false)); ui->showSplashCheckBox->setChecked(toml::find_or<bool>(data, "General", "showSplash", false));
ui->ps4proCheckBox->setChecked(toml::find_or<bool>(data, "General", "isPS4Pro", false));
ui->logTypeComboBox->setCurrentText( ui->logTypeComboBox->setCurrentText(
QString::fromStdString(toml::find_or<std::string>(data, "General", "logType", "async"))); QString::fromStdString(toml::find_or<std::string>(data, "General", "logType", "async")));
ui->logFilterLineEdit->setText( ui->logFilterLineEdit->setText(
@ -414,8 +412,6 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
text = tr("separateUpdatesCheckBox"); text = tr("separateUpdatesCheckBox");
} else if (elementName == "showSplashCheckBox") { } else if (elementName == "showSplashCheckBox") {
text = tr("showSplashCheckBox"); text = tr("showSplashCheckBox");
} else if (elementName == "ps4proCheckBox") {
text = tr("ps4proCheckBox");
} else if (elementName == "discordRPCCheckbox") { } else if (elementName == "discordRPCCheckbox") {
text = tr("discordRPCCheckbox"); text = tr("discordRPCCheckbox");
} else if (elementName == "userName") { } else if (elementName == "userName") {
@ -528,11 +524,9 @@ void SettingsDialog::UpdateSettings() {
const QVector<std::string> TouchPadIndex = {"left", "center", "right", "none"}; const QVector<std::string> TouchPadIndex = {"left", "center", "right", "none"};
Config::setBackButtonBehavior(TouchPadIndex[ui->backButtonBehaviorComboBox->currentIndex()]); Config::setBackButtonBehavior(TouchPadIndex[ui->backButtonBehaviorComboBox->currentIndex()]);
Config::setNeoMode(ui->ps4proCheckBox->isChecked());
Config::setFullscreenMode(ui->fullscreenCheckBox->isChecked()); Config::setFullscreenMode(ui->fullscreenCheckBox->isChecked());
Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked()); Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked());
Config::setPlayBGM(ui->playBGMCheckBox->isChecked()); Config::setPlayBGM(ui->playBGMCheckBox->isChecked());
Config::setNeoMode(ui->ps4proCheckBox->isChecked());
Config::setLogType(ui->logTypeComboBox->currentText().toStdString()); Config::setLogType(ui->logTypeComboBox->currentText().toStdString());
Config::setLogFilter(ui->logFilterLineEdit->text().toStdString()); Config::setLogFilter(ui->logFilterLineEdit->text().toStdString());
Config::setUserName(ui->userNameLineEdit->text().toStdString()); Config::setUserName(ui->userNameLineEdit->text().toStdString());

View File

@ -246,13 +246,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="ps4proCheckBox">
<property name="text">
<string>Is PS4 Pro</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="discordRPCCheckbox"> <widget class="QCheckBox" name="discordRPCCheckbox">
<property name="text"> <property name="text">

View File

@ -2,7 +2,7 @@
<!DOCTYPE TS> <!DOCTYPE TS>
<TS version="2.1" language="zh_CN"> <TS version="2.1" language="zh_CN">
<!-- SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project <!-- SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later --> SPDX-License-Identifier: GPL-2.0-or-later -->
<context> <context>
<name>AboutDialog</name> <name>AboutDialog</name>
<message> <message>
@ -18,7 +18,7 @@
<message> <message>
<location filename="../about_dialog.ui" line="78"/> <location filename="../about_dialog.ui" line="78"/>
<source>shadPS4 is an experimental open-source emulator for the PlayStation 4.</source> <source>shadPS4 is an experimental open-source emulator for the PlayStation 4.</source>
<translation>shadPS4 PlayStation 4</translation> <translation>shadPS4 PlayStation 4 </translation>
</message> </message>
<message> <message>
<location filename="../about_dialog.ui" line="99"/> <location filename="../about_dialog.ui" line="99"/>
@ -103,7 +103,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="48"/> <location filename="../gui_context_menus.h" line="48"/>
<source>Cheats / Patches</source> <source>Cheats / Patches</source>
<translation> / </translation> <translation>/</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="49"/> <location filename="../gui_context_menus.h" line="49"/>
@ -113,7 +113,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="50"/> <location filename="../gui_context_menus.h" line="50"/>
<source>Trophy Viewer</source> <source>Trophy Viewer</source>
<translation>Trophy </translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="49"/> <location filename="../gui_context_menus.h" line="49"/>
@ -128,7 +128,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="51"/> <location filename="../gui_context_menus.h" line="51"/>
<source>Open Save Data Folder</source> <source>Open Save Data Folder</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="52"/> <location filename="../gui_context_menus.h" line="52"/>
@ -173,27 +173,27 @@
<message> <message>
<location filename="../gui_context_menus.h" line="75"/> <location filename="../gui_context_menus.h" line="75"/>
<source>Delete DLC</source> <source>Delete DLC</source>
<translation>DLC</translation> <translation> DLC</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="99"/> <location filename="../gui_context_menus.h" line="99"/>
<source>Compatibility...</source> <source>Compatibility...</source>
<translation>Compatibility...</translation> <translation>...</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="100"/> <location filename="../gui_context_menus.h" line="100"/>
<source>Update database</source> <source>Update database</source>
<translation>Update database</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="101"/> <location filename="../gui_context_menus.h" line="101"/>
<source>View report</source> <source>View report</source>
<translation>View report</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="102"/> <location filename="../gui_context_menus.h" line="102"/>
<source>Submit a report</source> <source>Submit a report</source>
<translation>Submit a report</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="195"/> <location filename="../gui_context_menus.h" line="195"/>
@ -203,7 +203,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="196"/> <location filename="../gui_context_menus.h" line="196"/>
<source>Shortcut created successfully!</source> <source>Shortcut created successfully!</source>
<translation>!</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="199"/> <location filename="../gui_context_menus.h" line="199"/>
@ -213,7 +213,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="200"/> <location filename="../gui_context_menus.h" line="200"/>
<source>Error creating shortcut!</source> <source>Error creating shortcut!</source>
<translation>!</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="275"/> <location filename="../gui_context_menus.h" line="275"/>
@ -228,7 +228,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="305"/> <location filename="../gui_context_menus.h" line="305"/>
<source>requiresEnableSeparateUpdateFolder_MSG</source> <source>requiresEnableSeparateUpdateFolder_MSG</source>
<translation>使</translation> <translation>使</translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="312"/> <location filename="../gui_context_menus.h" line="312"/>
@ -243,7 +243,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="321"/> <location filename="../gui_context_menus.h" line="321"/>
<source>This game has no DLC to delete!</source> <source>This game has no DLC to delete!</source>
<translation>DLC可以删除</translation> <translation> DLC </translation>
</message> </message>
<message> <message>
<location filename="../gui_context_menus.h" line="325"/> <location filename="../gui_context_menus.h" line="325"/>
@ -258,7 +258,7 @@
<message> <message>
<location filename="../gui_context_menus.h" line="333"/> <location filename="../gui_context_menus.h" line="333"/>
<source>Are you sure you want to delete %1's %2 directory?</source> <source>Are you sure you want to delete %1's %2 directory?</source>
<translation> %1 %2 </translation> <translation> %1 %2</translation>
</message> </message>
</context> </context>
<context> <context>
@ -266,7 +266,7 @@
<message> <message>
<location filename="../main_window_ui.h" line="310"/> <location filename="../main_window_ui.h" line="310"/>
<source>Open/Add Elf Folder</source> <source>Open/Add Elf Folder</source>
<translation>/Elf文件夹</translation> <translation>/ Elf </translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="312"/> <location filename="../main_window_ui.h" line="312"/>
@ -316,7 +316,7 @@
<message> <message>
<location filename="../main_window_ui.h" line="327"/> <location filename="../main_window_ui.h" line="327"/>
<source>Exit the application.</source> <source>Exit the application.</source>
<translation>退.</translation> <translation>退</translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="330"/> <location filename="../main_window_ui.h" line="330"/>
@ -341,12 +341,12 @@
<message> <message>
<location filename="../main_window_ui.h" line="335"/> <location filename="../main_window_ui.h" line="335"/>
<source>Medium</source> <source>Medium</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="336"/> <location filename="../main_window_ui.h" line="336"/>
<source>Large</source> <source>Large</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="338"/> <location filename="../main_window_ui.h" line="338"/>
@ -376,7 +376,7 @@
<message> <message>
<location filename="../main_window_ui.h" line="345"/> <location filename="../main_window_ui.h" line="345"/>
<source>Dump Game List</source> <source>Dump Game List</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main_window_ui.h" line="346"/> <location filename="../main_window_ui.h" line="346"/>
@ -472,7 +472,7 @@
<message> <message>
<location filename="../trophy_viewer.cpp" line="8"/> <location filename="../trophy_viewer.cpp" line="8"/>
<source>Trophy Viewer</source> <source>Trophy Viewer</source>
<translation>Trophy </translation> <translation></translation>
</message> </message>
</context> </context>
<context> <context>
@ -485,7 +485,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="67"/> <location filename="../settings_dialog.ui" line="67"/>
<source>General</source> <source>General</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="77"/> <location filename="../settings_dialog.ui" line="77"/>
@ -520,12 +520,12 @@
<message> <message>
<location filename="../settings_dialog.ui" line="129"/> <location filename="../settings_dialog.ui" line="129"/>
<source>Show Splash</source> <source>Show Splash</source>
<translation>Splash</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="136"/> <location filename="../settings_dialog.ui" line="136"/>
<source>Is PS4 Pro</source> <source>Is PS4 Pro</source>
<translation> PS4 Pro</translation> <translation> PS4 Pro</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="154"/> <location filename="../settings_dialog.ui" line="154"/>
@ -570,17 +570,17 @@
<message> <message>
<location filename="../settings_dialog.ui" line="668"/> <location filename="../settings_dialog.ui" line="668"/>
<source>Hide Cursor Idle Timeout</source> <source>Hide Cursor Idle Timeout</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="816"/> <location filename="../settings_dialog.ui" line="816"/>
<source>s</source> <source>s</source>
<translation>s</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="767"/> <location filename="../settings_dialog.ui" line="767"/>
<source>Controller</source> <source>Controller</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="797"/> <location filename="../settings_dialog.ui" line="797"/>
@ -595,7 +595,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="282"/> <location filename="../settings_dialog.ui" line="282"/>
<source>Graphics Device</source> <source>Graphics Device</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="326"/> <location filename="../settings_dialog.ui" line="326"/>
@ -700,7 +700,7 @@
<message> <message>
<location filename="../settings_dialog.ui" line="475"/> <location filename="../settings_dialog.ui" line="475"/>
<source>Disable Trophy Pop-ups</source> <source>Disable Trophy Pop-ups</source>
<translation>Disable Trophy Pop-ups</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="375"/> <location filename="../settings_dialog.ui" line="375"/>
@ -710,22 +710,22 @@
<message> <message>
<location filename="../settings_dialog.ui"/> <location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database On Startup</source> <source>Update Compatibility Database On Startup</source>
<translation>Update Compatibility Database On Startup</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui"/> <location filename="../settings_dialog.ui"/>
<source>Game Compatibility</source> <source>Game Compatibility</source>
<translation>Game Compatibility</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui"/> <location filename="../settings_dialog.ui"/>
<source>Display Compatibility Data</source> <source>Display Compatibility Data</source>
<translation>Display Compatibility Data</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui"/> <location filename="../settings_dialog.ui"/>
<source>Update Compatibility Database</source> <source>Update Compatibility Database</source>
<translation>Update Compatibility Database</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.ui" line="394"/> <location filename="../settings_dialog.ui" line="394"/>
@ -735,7 +735,7 @@
<message> <message>
<location filename="../settings_dialog.ui"/> <location filename="../settings_dialog.ui"/>
<source>Audio Backend</source> <source>Audio Backend</source>
<translation>Audio Backend</translation> <translation></translation>
</message> </message>
</context> </context>
<context> <context>
@ -778,12 +778,12 @@
<message> <message>
<location filename="../main_window.cpp" line="392"/> <location filename="../main_window.cpp" line="392"/>
<source>All Patches available for all games have been downloaded.</source> <source>All Patches available for all games have been downloaded.</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="549"/> <location filename="../main_window.cpp" line="549"/>
<source>Games: </source> <source>Games: </source>
<translation>: </translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="575"/> <location filename="../main_window.cpp" line="575"/>
@ -798,7 +798,7 @@
<message> <message>
<location filename="../main_window.cpp" line="600"/> <location filename="../main_window.cpp" line="600"/>
<source>Game Boot</source> <source>Game Boot</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="600"/> <location filename="../main_window.cpp" line="600"/>
@ -818,7 +818,7 @@
<message> <message>
<location filename="../main_window.cpp" line="646"/> <location filename="../main_window.cpp" line="646"/>
<source>PKG and Game versions match: </source> <source>PKG and Game versions match: </source>
<translation>PKG : </translation> <translation>PKG </translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="647"/> <location filename="../main_window.cpp" line="647"/>
@ -828,17 +828,17 @@
<message> <message>
<location filename="../main_window.cpp" line="639"/> <location filename="../main_window.cpp" line="639"/>
<source>PKG Version %1 is older than installed version: </source> <source>PKG Version %1 is older than installed version: </source>
<translation>PKG %1 : </translation> <translation>PKG %1 </translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="660"/> <location filename="../main_window.cpp" line="660"/>
<source>Game is installed: </source> <source>Game is installed: </source>
<translation>: </translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="660"/> <location filename="../main_window.cpp" line="660"/>
<source>Would you like to install Patch: </source> <source>Would you like to install Patch: </source>
<translation>: </translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="673"/> <location filename="../main_window.cpp" line="673"/>
@ -848,12 +848,12 @@
<message> <message>
<location filename="../main_window.cpp" line="674"/> <location filename="../main_window.cpp" line="674"/>
<source>Would you like to install DLC: %1?</source> <source>Would you like to install DLC: %1?</source>
<translation> DLC: %1 </translation> <translation> DLC%1 </translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="688"/> <location filename="../main_window.cpp" line="688"/>
<source>DLC already installed:</source> <source>DLC already installed:</source>
<translation>DLC :</translation> <translation>DLC </translation>
</message> </message>
<message> <message>
<location filename="../main_window.cpp" line="701"/> <location filename="../main_window.cpp" line="701"/>
@ -896,42 +896,42 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="44"/> <location filename="../cheats_patches.cpp" line="44"/>
<source>Cheats / Patches for </source> <source>Cheats / Patches for </source>
<translation>Cheats / Patches for </translation> <translation>/</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="50"/> <location filename="../cheats_patches.cpp" line="50"/>
<source>defaultTextEdit_MSG</source> <source>defaultTextEdit_MSG</source>
<translation>/\n请小心使用\n\n通过选择存储库并点击下载按钮\n在使\n\n由于我们不开发作弊程序/\n请将问题报告给作弊程序的作者\n\n创建了新的作弊程序访\nhttps://github.com/shadps4-emu/ps4_cheats</translation> <translation>/\n请小心使用\n\n通过选择存储库并点击下载按钮\n在使\n\n由于我们不开发作弊/\n请将问题报告给作弊码/\n\n创建了新的作弊码/\nhttps://github.com/shadps4-emu/ps4_cheats</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="69"/> <location filename="../cheats_patches.cpp" line="69"/>
<source>No Image Available</source> <source>No Image Available</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="79"/> <location filename="../cheats_patches.cpp" line="79"/>
<source>Serial: </source> <source>Serial: </source>
<translation>: </translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="83"/> <location filename="../cheats_patches.cpp" line="83"/>
<source>Version: </source> <source>Version: </source>
<translation>: </translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="87"/> <location filename="../cheats_patches.cpp" line="87"/>
<source>Size: </source> <source>Size: </source>
<translation>: </translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="126"/> <location filename="../cheats_patches.cpp" line="126"/>
<source>Select Cheat File:</source> <source>Select Cheat File:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="133"/> <location filename="../cheats_patches.cpp" line="133"/>
<source>Repository:</source> <source>Repository:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="149"/> <location filename="../cheats_patches.cpp" line="149"/>
@ -961,7 +961,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="213"/> <location filename="../cheats_patches.cpp" line="213"/>
<source>Select Patch File:</source> <source>Select Patch File:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="241"/> <location filename="../cheats_patches.cpp" line="241"/>
@ -1016,7 +1016,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="432"/> <location filename="../cheats_patches.cpp" line="432"/>
<source>Failed to parse XML: </source> <source>Failed to parse XML: </source>
<translation> XML : </translation> <translation> XML </translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="434"/> <location filename="../cheats_patches.cpp" line="434"/>
@ -1046,17 +1046,17 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="520"/> <location filename="../cheats_patches.cpp" line="520"/>
<source>File already exists. Do you want to replace it?</source> <source>File already exists. Do you want to replace it?</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="539"/> <location filename="../cheats_patches.cpp" line="539"/>
<source>Failed to save file:</source> <source>Failed to save file:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="545"/> <location filename="../cheats_patches.cpp" line="545"/>
<source>Failed to download file:</source> <source>Failed to download file:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="556"/> <location filename="../cheats_patches.cpp" line="556"/>
@ -1076,17 +1076,17 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="594"/> <location filename="../cheats_patches.cpp" line="594"/>
<source>CheatsDownloadedSuccessfully_MSG</source> <source>CheatsDownloadedSuccessfully_MSG</source>
<translation> 使</translation> <translation>使</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="747"/> <location filename="../cheats_patches.cpp" line="747"/>
<source>Failed to save:</source> <source>Failed to save:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="754"/> <location filename="../cheats_patches.cpp" line="754"/>
<source>Failed to download:</source> <source>Failed to download:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="762"/> <location filename="../cheats_patches.cpp" line="762"/>
@ -1096,7 +1096,7 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="763"/> <location filename="../cheats_patches.cpp" line="763"/>
<source>DownloadComplete_MSG</source> <source>DownloadComplete_MSG</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="773"/> <location filename="../cheats_patches.cpp" line="773"/>
@ -1111,12 +1111,12 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="850"/> <location filename="../cheats_patches.cpp" line="850"/>
<source>The game is in version: %1</source> <source>The game is in version: %1</source>
<translation>: %1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="851"/> <location filename="../cheats_patches.cpp" line="851"/>
<source>The downloaded patch only works on version: %1</source> <source>The downloaded patch only works on version: %1</source>
<translation>: %1</translation> <translation>%1</translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="856"/> <location filename="../cheats_patches.cpp" line="856"/>
@ -1131,12 +1131,12 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="801"/> <location filename="../cheats_patches.cpp" line="801"/>
<source>Failed to open file:</source> <source>Failed to open file:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="819"/> <location filename="../cheats_patches.cpp" line="819"/>
<source>XML ERROR:</source> <source>XML ERROR:</source>
<translation>XML :</translation> <translation>XML </translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="826"/> <location filename="../cheats_patches.cpp" line="826"/>
@ -1146,12 +1146,12 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="925"/> <location filename="../cheats_patches.cpp" line="925"/>
<source>Author: </source> <source>Author: </source>
<translation>: </translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="997"/> <location filename="../cheats_patches.cpp" line="997"/>
<source>Directory does not exist:</source> <source>Directory does not exist:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="1006"/> <location filename="../cheats_patches.cpp" line="1006"/>
@ -1161,12 +1161,12 @@
<message> <message>
<location filename="../cheats_patches.cpp" line="1006"/> <location filename="../cheats_patches.cpp" line="1006"/>
<source>Name:</source> <source>Name:</source>
<translation>:</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../cheats_patches.cpp" line="1163"/> <location filename="../cheats_patches.cpp" line="1163"/>
<source>Can't apply cheats before the game is started</source> <source>Can't apply cheats before the game is started</source>
<translation></translation> <translation></translation>
</message> </message>
</context> </context>
<context> <context>
@ -1199,17 +1199,17 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="289"/> <location filename="../settings_dialog.cpp" line="289"/>
<source>consoleLanguageGroupBox</source> <source>consoleLanguageGroupBox</source>
<translation>:\n设置 PS4 使\n建议设置为支持的语言</translation> <translation>\n设置 PS4 使\n建议设置为支持的语言</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="291"/> <location filename="../settings_dialog.cpp" line="291"/>
<source>emulatorLanguageGroupBox</source> <source>emulatorLanguageGroupBox</source>
<translation>:\n设置模拟器用户界面的语言</translation> <translation>\n设置模拟器用户界面的语言</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="293"/> <location filename="../settings_dialog.cpp" line="293"/>
<source>fullscreenCheckBox</source> <source>fullscreenCheckBox</source>
<translation>:\n自动将游戏窗口设置为全屏模式\n您可以按 F11 </translation> <translation>\n以全屏模式启动游戏\n您可以按 F11 </translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="293"/> <location filename="../settings_dialog.cpp" line="293"/>
@ -1219,77 +1219,77 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="295"/> <location filename="../settings_dialog.cpp" line="295"/>
<source>showSplashCheckBox</source> <source>showSplashCheckBox</source>
<translation>:\n在游戏启动时显示游戏的启动画面</translation> <translation>\n在游戏启动时显示游戏的启动画面</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="297"/> <location filename="../settings_dialog.cpp" line="297"/>
<source>ps4proCheckBox</source> <source>ps4proCheckBox</source>
<translation> PS4 Pro:\n使模拟器作为 PS4 PRO </translation> <translation> PS4 Pro:\n使模拟器作为 PS4 Pro </translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="438"/> <location filename="../settings_dialog.cpp" line="438"/>
<source>discordRPCCheckbox</source> <source>discordRPCCheckbox</source>
<translation> Discord Rich Presence:\n在您的 Discord 仿</translation> <translation> Discord Rich Presence\n在您的 Discord </translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="299"/> <location filename="../settings_dialog.cpp" line="299"/>
<source>userName</source> <source>userName</source>
<translation>:\n设置 PS4 </translation> <translation>\n设置 PS4 </translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="301"/> <location filename="../settings_dialog.cpp" line="301"/>
<source>logTypeGroupBox</source> <source>logTypeGroupBox</source>
<translation>:\n设置是否同步日志窗口的输出以提高性能</translation> <translation>\n设置日志窗口输出的同步方式以提高性能</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="303"/> <location filename="../settings_dialog.cpp" line="303"/>
<source>logFilter</source> <source>logFilter</source>
<translation>:\n过滤日志\n例如"Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" 级别: Trace, Debug, Info, Warning, Error, Critical - </translation> <translation>\n过滤日志\n例如"Core:Trace" "Lib.Pad:Debug Common.Filesystem:Error" "*:Critical" 级别: Trace, Debug, Info, Warning, Error, Critical - </translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="305"/> <location filename="../settings_dialog.cpp" line="305"/>
<source>updaterGroupBox</source> <source>updaterGroupBox</source>
<translation>:\nRelease: 官方版本\nNightly: 开发版本</translation> <translation>\nRelease\nNightly</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="306"/> <location filename="../settings_dialog.cpp" line="306"/>
<source>GUIgroupBox</source> <source>GUIgroupBox</source>
<translation>:\n如果游戏支持</translation> <translation>\n如果游戏支持</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="267"/> <location filename="../settings_dialog.cpp" line="267"/>
<source>disableTrophycheckBox</source> <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>\n禁用游戏内奖杯通知</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="450"/> <location filename="../settings_dialog.cpp" line="450"/>
<source>hideCursorGroupBox</source> <source>hideCursorGroupBox</source>
<translation>:\n选择光标何时消失:\n从不: 您将始终看到鼠标\n空闲: 设置光标在空闲后消失的时间\n始终: 您将永远看不到鼠</translation> <translation>\n选择光标何时消失:\n从不: 始终显示光标\闲置: 光标在闲置若干秒后消失\n始终: 始终显示光</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="452"/> <location filename="../settings_dialog.cpp" line="452"/>
<source>idleTimeoutGroupBox</source> <source>idleTimeoutGroupBox</source>
<translation></translation> <translation>\n光标自动隐藏之前的闲置时长</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="454"/> <location filename="../settings_dialog.cpp" line="454"/>
<source>backButtonBehaviorGroupBox</source> <source>backButtonBehaviorGroupBox</source>
<translation>:\n设置控制器的返回按钮以模拟在 PS4 </translation> <translation>\n设置手柄的返回按钮模拟在 PS4 </translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp"/> <location filename="../settings_dialog.cpp"/>
<source>enableCompatibilityCheckBox</source> <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>\n在列表视图中显示游戏兼容性信息</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp"/> <location filename="../settings_dialog.cpp"/>
<source>checkCompatibilityOnStartupCheckBox</source> <source>checkCompatibilityOnStartupCheckBox</source>
<translation>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation> <translation>\n当 shadPS4 </translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp"/> <location filename="../settings_dialog.cpp"/>
<source>updateCompatibilityButton</source> <source>updateCompatibilityButton</source>
<translation>Update Compatibility Database:\nImmediately update the compatibility database.</translation> <translation>\n立即更新兼容性数据库</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="70"/> <location filename="../settings_dialog.cpp" line="70"/>
@ -1299,7 +1299,7 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="71"/> <location filename="../settings_dialog.cpp" line="71"/>
<source>Idle</source> <source>Idle</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="72"/> <location filename="../settings_dialog.cpp" line="72"/>
@ -1329,62 +1329,62 @@
<message> <message>
<location filename="../settings_dialog.cpp" line="312"/> <location filename="../settings_dialog.cpp" line="312"/>
<source>graphicsAdapterGroupBox</source> <source>graphicsAdapterGroupBox</source>
<translation>:\n在具有多个 GPU 使 GPU\n或者选择</translation> <translation>\n在具有多个 GPU 使 GPU\n或者选择</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="314"/> <location filename="../settings_dialog.cpp" line="314"/>
<source>resolutionLayout</source> <source>resolutionLayout</source>
<translation>/:\n设置启动时模拟器的窗口大小\n这与游戏中的分辨率不同</translation> <translation>/\n设置启动游戏时的窗口大小\n这与游戏内的分辨率不同</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="318"/> <location filename="../settings_dialog.cpp" line="318"/>
<source>heightDivider</source> <source>heightDivider</source>
<translation>Vblank :\n模拟器更新的帧速率乘以此数字!</translation> <translation>Vblank Divider\n模拟器刷新的帧率会乘以此数字</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="320"/> <location filename="../settings_dialog.cpp" line="320"/>
<source>dumpShadersCheckBox</source> <source>dumpShadersCheckBox</source>
<translation>:\n为了技术调试</translation> <translation>\n用于技术调试</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="322"/> <location filename="../settings_dialog.cpp" line="322"/>
<source>nullGpuCheckBox</source> <source>nullGpuCheckBox</source>
<translation> GPU:\n为了技术调试仿</translation> <translation> NULL GPU\n用于技术调试</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="465"/> <location filename="../settings_dialog.cpp" line="465"/>
<source>gameFoldersBox</source> <source>gameFoldersBox</source>
<translation>:\n检查已安装游戏的文件夹列表</translation> <translation>\n检查已安装游戏的文件夹列表</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="465"/> <location filename="../settings_dialog.cpp" line="465"/>
<source>addFolderButton</source> <source>addFolderButton</source>
<translation>:\n将文件夹添加到列表</translation> <translation>\n将文件夹添加到列表</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="465"/> <location filename="../settings_dialog.cpp" line="465"/>
<source>removeFolderButton</source> <source>removeFolderButton</source>
<translation>:\n从列表中移除文件夹</translation> <translation>\n从列表中移除文件夹</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="329"/> <location filename="../settings_dialog.cpp" line="329"/>
<source>debugDump</source> <source>debugDump</source>
<translation>:\n将当前正在运行的 PS4 </translation> <translation>\n将当前正在运行的 PS4 </translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="331"/> <location filename="../settings_dialog.cpp" line="331"/>
<source>vkValidationCheckBox</source> <source>vkValidationCheckBox</source>
<translation> Vulkan :\n启用验证 Vulkan </translation> <translation> Vulkan \n启用一个系统来验证 Vulkan \n这将降低性能并可能改变模拟的行</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="333"/> <location filename="../settings_dialog.cpp" line="333"/>
<source>vkSyncValidationCheckBox</source> <source>vkSyncValidationCheckBox</source>
<translation> Vulkan :\n启用验证 Vulkan </translation> <translation> Vulkan \n启用一个系统来验证 Vulkan \n这将降低性能并可能改变模拟的行</translation>
</message> </message>
<message> <message>
<location filename="../settings_dialog.cpp" line="335"/> <location filename="../settings_dialog.cpp" line="335"/>
<source>rdocCheckBox</source> <source>rdocCheckBox</source>
<translation> RenderDoc :\n如果启用Renderdoc </translation> <translation> RenderDoc :\n启用后模拟器将提供Renderdoc </translation>
</message> </message>
</context> </context>
<context> <context>
@ -1407,7 +1407,7 @@
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>Compatibility</source> <source>Compatibility</source>
<translation>Compatibility</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp" line="34"/> <location filename="../game_list_frame.cpp" line="34"/>
@ -1442,52 +1442,52 @@
<message> <message>
<location filename="../game_list_frame.cpp" line="108"/> <location filename="../game_list_frame.cpp" line="108"/>
<source>Never Played</source> <source>Never Played</source>
<translation>Never Played</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>h</source> <source>h</source>
<translation>h</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>m</source> <source>m</source>
<translation>m</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>s</source> <source>s</source>
<translation>s</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>Compatibility is untested</source> <source>Compatibility is untested</source>
<translation>Compatibility is untested</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>Game does not initialize properly / crashes the emulator</source> <source>Game does not initialize properly / crashes the emulator</source>
<translation>Game does not initialize properly / crashes the emulator</translation> <translation>/</translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>Game boots, but only displays a blank screen</source> <source>Game boots, but only displays a blank screen</source>
<translation>Game boots, but only displays a blank screen</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>Game displays an image but does not go past the menu</source> <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></translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>Game has game-breaking glitches or unplayable performance</source> <source>Game has game-breaking glitches or unplayable performance</source>
<translation>Game has game-breaking glitches or unplayable performance</translation> <translation> Bug </translation>
</message> </message>
<message> <message>
<location filename="../game_list_frame.cpp"/> <location filename="../game_list_frame.cpp"/>
<source>Game can be completed with playable performance and no major glitches</source> <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> Bug</translation>
</message> </message>
</context> </context>
<context> <context>
@ -1525,7 +1525,7 @@
<message> <message>
<location filename="../check_update.cpp" line="142"/> <location filename="../check_update.cpp" line="142"/>
<source>No download URL found for the specified asset.</source> <source>No download URL found for the specified asset.</source>
<translation> URL</translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="148"/> <location filename="../check_update.cpp" line="148"/>
@ -1560,7 +1560,7 @@
<message> <message>
<location filename="../check_update.cpp" line="193"/> <location filename="../check_update.cpp" line="193"/>
<source>Show Changelog</source> <source>Show Changelog</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="198"/> <location filename="../check_update.cpp" line="198"/>
@ -1580,17 +1580,17 @@
<message> <message>
<location filename="../check_update.cpp" line="223"/> <location filename="../check_update.cpp" line="223"/>
<source>Hide Changelog</source> <source>Hide Changelog</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="296"/> <location filename="../check_update.cpp" line="296"/>
<source>Changes</source> <source>Changes</source>
<translation></translation> <translation></translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="310"/> <location filename="../check_update.cpp" line="310"/>
<source>Network error occurred while trying to access the URL</source> <source>Network error occurred while trying to access the URL</source>
<translation>访 URL </translation> <translation>访</translation>
</message> </message>
<message> <message>
<location filename="../check_update.cpp" line="330"/> <location filename="../check_update.cpp" line="330"/>

View File

@ -24,9 +24,11 @@ static constexpr spv::ExecutionMode GetInputPrimitiveType(AmdGpu::PrimitiveType
case AmdGpu::PrimitiveType::PointList: case AmdGpu::PrimitiveType::PointList:
return spv::ExecutionMode::InputPoints; return spv::ExecutionMode::InputPoints;
case AmdGpu::PrimitiveType::LineList: case AmdGpu::PrimitiveType::LineList:
case AmdGpu::PrimitiveType::LineStrip:
return spv::ExecutionMode::InputLines; return spv::ExecutionMode::InputLines;
case AmdGpu::PrimitiveType::TriangleList: case AmdGpu::PrimitiveType::TriangleList:
case AmdGpu::PrimitiveType::TriangleStrip: case AmdGpu::PrimitiveType::TriangleStrip:
case AmdGpu::PrimitiveType::RectList:
return spv::ExecutionMode::Triangles; return spv::ExecutionMode::Triangles;
case AmdGpu::PrimitiveType::AdjTriangleList: case AmdGpu::PrimitiveType::AdjTriangleList:
return spv::ExecutionMode::InputTrianglesAdjacency; return spv::ExecutionMode::InputTrianglesAdjacency;

View File

@ -43,9 +43,11 @@ static constexpr u32 NumVertices(AmdGpu::PrimitiveType type) {
case AmdGpu::PrimitiveType::PointList: case AmdGpu::PrimitiveType::PointList:
return 1u; return 1u;
case AmdGpu::PrimitiveType::LineList: case AmdGpu::PrimitiveType::LineList:
case AmdGpu::PrimitiveType::LineStrip:
return 2u; return 2u;
case AmdGpu::PrimitiveType::TriangleList: case AmdGpu::PrimitiveType::TriangleList:
case AmdGpu::PrimitiveType::TriangleStrip: case AmdGpu::PrimitiveType::TriangleStrip:
case AmdGpu::PrimitiveType::RectList:
return 3u; return 3u;
case AmdGpu::PrimitiveType::AdjTriangleList: case AmdGpu::PrimitiveType::AdjTriangleList:
return 6u; return 6u;

View File

@ -3565,8 +3565,8 @@ constexpr std::array<InstFormat, 112> InstructionFormatMIMG = {{
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Float32, {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Float32,
ScalarType::Float32}, ScalarType::Float32},
// 64 = IMAGE_GATHER4 // 64 = IMAGE_GATHER4
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32,
ScalarType::Undefined}, ScalarType::Float32},
// 65 = IMAGE_GATHER4_CL // 65 = IMAGE_GATHER4_CL
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined}, ScalarType::Undefined},
@ -3603,10 +3603,10 @@ constexpr std::array<InstFormat, 112> InstructionFormatMIMG = {{
ScalarType::Undefined}, ScalarType::Undefined},
// 79 = IMAGE_GATHER4_C_LZ // 79 = IMAGE_GATHER4_C_LZ
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32,
ScalarType::Uint32}, ScalarType::Float32},
// 80 = IMAGE_GATHER4_O // 80 = IMAGE_GATHER4_O
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32,
ScalarType::Undefined}, ScalarType::Float32},
// 81 = IMAGE_GATHER4_CL_O // 81 = IMAGE_GATHER4_CL_O
{InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, {InstClass::VectorMemImgSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined,
ScalarType::Undefined}, ScalarType::Undefined},

View File

@ -144,8 +144,10 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
return IMAGE_SAMPLE(inst); return IMAGE_SAMPLE(inst);
// Image gather operations // Image gather operations
case Opcode::IMAGE_GATHER4:
case Opcode::IMAGE_GATHER4_LZ: case Opcode::IMAGE_GATHER4_LZ:
case Opcode::IMAGE_GATHER4_C: case Opcode::IMAGE_GATHER4_C:
case Opcode::IMAGE_GATHER4_O:
case Opcode::IMAGE_GATHER4_C_O: case Opcode::IMAGE_GATHER4_C_O:
case Opcode::IMAGE_GATHER4_C_LZ: case Opcode::IMAGE_GATHER4_C_LZ:
case Opcode::IMAGE_GATHER4_LZ_O: case Opcode::IMAGE_GATHER4_LZ_O:

View File

@ -447,7 +447,7 @@ struct Sampler {
} }
float MaxAniso() const { float MaxAniso() const {
switch (max_aniso) { switch (max_aniso.Value()) {
case AnisoRatio::One: case AnisoRatio::One:
return 1.0f; return 1.0f;
case AnisoRatio::Two: case AnisoRatio::Two:

View File

@ -18,7 +18,8 @@ Sampler::Sampler(const Vulkan::Instance& instance, const AmdGpu::Sampler& sample
(AmdGpu::IsAnisoFilter(sampler.xy_mag_filter) || (AmdGpu::IsAnisoFilter(sampler.xy_mag_filter) ||
AmdGpu::IsAnisoFilter(sampler.xy_min_filter)); AmdGpu::IsAnisoFilter(sampler.xy_min_filter));
const float maxAnisotropy = const float maxAnisotropy =
std::clamp(sampler.MaxAniso(), 1.0f, instance.MaxSamplerAnisotropy()); anisotropyEnable ? std::clamp(sampler.MaxAniso(), 1.0f, instance.MaxSamplerAnisotropy())
: 1.0f;
const vk::SamplerCreateInfo sampler_ci = { const vk::SamplerCreateInfo sampler_ci = {
.magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter), .magFilter = LiverpoolToVK::Filter(sampler.xy_mag_filter),
.minFilter = LiverpoolToVK::Filter(sampler.xy_min_filter), .minFilter = LiverpoolToVK::Filter(sampler.xy_min_filter),