diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ec7cd54..880d1cf5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -308,6 +308,8 @@ set(CORE src/core/aerolib/stubs.cpp src/core/file_format/pkg_type.h src/core/file_format/psf.cpp src/core/file_format/psf.h + src/core/file_format/playgo_chunk.cpp + src/core/file_format/playgo_chunk.h src/core/file_format/trp.cpp src/core/file_format/trp.h src/core/file_format/splash.h diff --git a/src/common/config.cpp b/src/common/config.cpp index a577b143..218575ff 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -220,7 +220,7 @@ void load(const std::filesystem::path& path) { auto general = generalResult.unwrap(); isNeo = toml::find_or(general, "isPS4Pro", false); - isFullscreen = toml::find_or(general, "Fullscreen", true); + isFullscreen = toml::find_or(general, "Fullscreen", false); logFilter = toml::find_or(general, "logFilter", ""); logType = toml::find_or(general, "logType", "sync"); isShowSplash = toml::find_or(general, "showSplash", true); diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index 429fe2a5..f0f56b85 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -72,6 +72,7 @@ static auto UserPaths = [] { create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR); create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR); create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR); + create_path(PathType::DownloadDir, user_dir / DOWNLOAD_DIR); return paths; }(); diff --git a/src/common/path_util.h b/src/common/path_util.h index 57a9a73f..67688f89 100644 --- a/src/common/path_util.h +++ b/src/common/path_util.h @@ -18,6 +18,7 @@ enum class PathType { TempDataDir, // Where game temp data is stored. GameDataDir, // Where game data is stored. SysModuleDir, // Where system modules are stored. + DownloadDir, // Where downloads/temp files are stored. }; constexpr auto PORTABLE_DIR = "user"; @@ -31,6 +32,7 @@ constexpr auto SAVEDATA_DIR = "savedata"; constexpr auto GAMEDATA_DIR = "data"; constexpr auto TEMPDATA_DIR = "temp"; constexpr auto SYSMODULES_DIR = "sys_modules"; +constexpr auto DOWNLOAD_DIR = "download"; // Filenames constexpr auto LOG_FILE = "shad_log.txt"; diff --git a/src/core/file_format/playgo_chunk.cpp b/src/core/file_format/playgo_chunk.cpp new file mode 100644 index 00000000..43d8a4de --- /dev/null +++ b/src/core/file_format/playgo_chunk.cpp @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/io_file.h" + +#include "playgo_chunk.h" + +bool PlaygoChunk::Open(const std::filesystem::path& filepath) { + Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read); + if (!file.IsOpen()) { + return false; + } + file.Read(playgoHeader); + + return true; +} \ No newline at end of file diff --git a/src/core/file_format/playgo_chunk.h b/src/core/file_format/playgo_chunk.h new file mode 100644 index 00000000..d17d24bf --- /dev/null +++ b/src/core/file_format/playgo_chunk.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once +#include +#include "common/types.h" + +struct PlaygoHeader { + u32 magic; + + u16 version_major; + u16 version_minor; + u16 image_count; + u16 chunk_count; + u16 mchunk_count; + u16 scenario_count; + // TODO fill the rest +}; +class PlaygoChunk { +public: + PlaygoChunk() = default; + ~PlaygoChunk() = default; + + bool Open(const std::filesystem::path& filepath); + PlaygoHeader GetPlaygoHeader() { + return playgoHeader; + } + +private: + PlaygoHeader playgoHeader; +}; \ No newline at end of file diff --git a/src/core/file_sys/fs.cpp b/src/core/file_sys/fs.cpp index 2f57c9f3..3177770b 100644 --- a/src/core/file_sys/fs.cpp +++ b/src/core/file_sys/fs.cpp @@ -26,23 +26,27 @@ void MntPoints::UnmountAll() { } std::filesystem::path MntPoints::GetHostPath(const std::string& guest_directory) { - const MntPair* mount = GetMount(guest_directory); + // Evil games like Turok2 pass double slashes e.g /app0//game.kpf + auto corrected_path = guest_directory; + size_t pos = corrected_path.find("//"); + while (pos != std::string::npos) { + corrected_path.replace(pos, 2, "/"); + pos = corrected_path.find("//", pos + 1); + } + + const MntPair* mount = GetMount(corrected_path); if (!mount) { - return guest_directory; + return ""; } // Nothing to do if getting the mount itself. - if (guest_directory == mount->mount) { + if (corrected_path == mount->mount) { return mount->host_path; } // Remove device (e.g /app0) from path to retrieve relative path. - u32 pos = mount->mount.size() + 1; - // Evil games like Turok2 pass double slashes e.g /app0//game.kpf - if (guest_directory[pos] == '/') { - pos++; - } - const auto rel_path = std::string_view(guest_directory).substr(pos); + pos = mount->mount.size() + 1; + const auto rel_path = std::string_view(corrected_path).substr(pos); const auto host_path = mount->host_path / rel_path; if (!NeedsCaseInsensiveSearch) { return host_path; diff --git a/src/core/libraries/app_content/app_content.cpp b/src/core/libraries/app_content/app_content.cpp index 7e9cf7a2..882f99e4 100644 --- a/src/core/libraries/app_content/app_content.cpp +++ b/src/core/libraries/app_content/app_content.cpp @@ -198,13 +198,9 @@ int PS4_SYSV_ABI sceAppContentTemporaryDataMount() { int PS4_SYSV_ABI sceAppContentTemporaryDataMount2(OrbisAppContentTemporaryDataOption option, OrbisAppContentMountPoint* mountPoint) { - if (std::string_view(mountPoint->data).empty()) // causing issues with save_data. + if (mountPoint == nullptr) return ORBIS_APP_CONTENT_ERROR_PARAMETER; - auto* param_sfo = Common::Singleton::Instance(); - std::string id(param_sfo->GetString("CONTENT_ID"), 7, 9); - const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id; - auto* mnt = Common::Singleton::Instance(); - mnt->Mount(mount_dir, mountPoint->data); + strncpy(mountPoint->data, "/temp0", 16); LOG_INFO(Lib_AppContent, "sceAppContentTemporaryDataMount2: option = {}, mountPoint = {}", option, mountPoint->data); return ORBIS_OK; diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index 8734b964..4a42b0d6 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -53,6 +53,9 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) { if (std::string_view{path} == "/dev/stdout") { return 2002; } + if (std::string_view{path} == "/dev/urandom") { + return 2003; + } u32 handle = h->CreateHandle(); auto* file = h->GetFile(handle); if (directory) { @@ -113,6 +116,9 @@ int PS4_SYSV_ABI sceKernelClose(int d) { if (d < 3) { // d probably hold an error code return ORBIS_KERNEL_ERROR_EPERM; } + if (d == 2003) { // dev/urandom case + return SCE_OK; + } auto* h = Common::Singleton::Instance(); auto* file = h->GetFile(d); if (file == nullptr) { @@ -223,6 +229,13 @@ s64 PS4_SYSV_ABI posix_lseek(int d, s64 offset, int whence) { } s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes) { + if (d == 2003) // dev urandom case + { + auto rbuf = static_cast(buf); + for (size_t i = 0; i < nbytes; i++) + rbuf[i] = std::rand() & 0xFF; + return nbytes; + } auto* h = Common::Singleton::Instance(); auto* file = h->GetFile(d); if (file == nullptr) { @@ -460,6 +473,7 @@ s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset) { } void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) { + std::srand(std::time(nullptr)); LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen); LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open); LIB_FUNCTION("UK2Tl2DWUns", "libkernel", 1, "libkernel", 1, 1, sceKernelClose); diff --git a/src/core/libraries/kernel/memory_management.cpp b/src/core/libraries/kernel/memory_management.cpp index e0509fb4..988b69d0 100644 --- a/src/core/libraries/kernel/memory_management.cpp +++ b/src/core/libraries/kernel/memory_management.cpp @@ -228,7 +228,8 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries, int* numEntriesOut) { - return sceKernelBatchMap2(entries, numEntries, numEntriesOut, 0x10); // 0x10 : Fixed / 0x410 + return sceKernelBatchMap2(entries, numEntries, numEntriesOut, + MemoryFlags::SCE_KERNEL_MAP_FIXED); // 0x10, 0x410? } int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len); @@ -243,7 +244,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn break; // break and assign a value to numEntriesOut. } - if (entries[i].operation == 0) { // MAP_DIRECT + if (entries[i].operation == MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_DIRECT) { result = sceKernelMapNamedDirectMemory(&entries[i].start, entries[i].length, entries[i].protection, flags, static_cast(entries[i].offset), 0, ""); @@ -256,7 +257,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn if (result == 0) processed++; - } else if (entries[i].operation == 1) { + } else if (entries[i].operation == MemoryOpTypes::ORBIS_KERNEL_MAP_OP_UNMAP) { result = sceKernelMunmap(entries[i].start, entries[i].length); LOG_INFO(Kernel_Vmm, "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", i, entries[i].operation, entries[i].length, result); diff --git a/src/core/libraries/kernel/memory_management.h b/src/core/libraries/kernel/memory_management.h index 25434ecb..cc89dfa7 100644 --- a/src/core/libraries/kernel/memory_management.h +++ b/src/core/libraries/kernel/memory_management.h @@ -31,6 +31,14 @@ enum MemoryProtection : u32 { SCE_KERNEL_PROT_GPU_RW = 0x30 // Permit reads/writes from the GPU }; +enum MemoryOpTypes : u32 { + ORBIS_KERNEL_MAP_OP_MAP_DIRECT = 0, + ORBIS_KERNEL_MAP_OP_UNMAP = 1, + ORBIS_KERNEL_MAP_OP_PROTECT = 2, + ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE = 3, + ORBIS_KERNEL_MAP_OP_TYPE_PROTECT = 4 +}; + struct OrbisQueryInfo { uintptr_t start; uintptr_t end; diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 7c075e87..3e9e1994 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -1336,10 +1336,23 @@ int PS4_SYSV_ABI posix_sem_wait(sem_t* sem) { return sem_wait(sem); } +int PS4_SYSV_ABI posix_sem_timedwait(sem_t* sem, const timespec* t) { +#ifndef __APPLE__ + return sem_timedwait(sem, t); +#else + LOG_ERROR(Kernel_Pthread, "Apple doesn't support sem_timedwait yet"); + return 0; // unsupported for apple yet +#endif +} + int PS4_SYSV_ABI posix_sem_post(sem_t* sem) { return sem_post(sem); } +int PS4_SYSV_ABI posix_sem_destroy(sem_t* sem) { + return sem_destroy(sem); +} + int PS4_SYSV_ABI posix_sem_getvalue(sem_t* sem, int* sval) { return sem_getvalue(sem, sval); } @@ -1403,6 +1416,26 @@ int PS4_SYSV_ABI posix_pthread_condattr_setclock(ScePthreadCondattr* attr, clock return SCE_OK; } +int PS4_SYSV_ABI posix_pthread_getschedparam(ScePthread thread, int* policy, + SceKernelSchedParam* param) { + return scePthreadGetschedparam(thread, policy, param); +} + +int PS4_SYSV_ABI posix_pthread_setschedparam(ScePthread thread, int policy, + const SceKernelSchedParam* param) { + return scePthreadSetschedparam(thread, policy, param); +} + +int PS4_SYSV_ABI posix_pthread_attr_getschedpolicy(const ScePthreadAttr* attr, int* policy) { + return scePthreadAttrGetschedpolicy(attr, policy); +} + +int PS4_SYSV_ABI scePthreadRename(ScePthread thread, const char* name) { + thread->name = name; + LOG_INFO(Kernel_Pthread, "scePthreadRename: name = {}", thread->name); + return SCE_OK; +} + void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("lZzFeSxPl08", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setcancelstate); LIB_FUNCTION("0TyVk4MSLt0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_init); @@ -1427,6 +1460,7 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("EI-5-jlq2dE", "libkernel", 1, "libkernel", 1, 1, scePthreadGetthreadid); LIB_FUNCTION("1tKyG7RlMJo", "libkernel", 1, "libkernel", 1, 1, scePthreadGetprio); LIB_FUNCTION("W0Hpm2X0uPE", "libkernel", 1, "libkernel", 1, 1, scePthreadSetprio); + LIB_FUNCTION("GBUY7ywdULE", "libkernel", 1, "libkernel", 1, 1, scePthreadRename); LIB_FUNCTION("aI+OeCz8xrQ", "libkernel", 1, "libkernel", 1, 1, scePthreadSelf); LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self); @@ -1498,6 +1532,8 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("EjllaAqAPZo", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_condattr_setclock); LIB_FUNCTION("Z4QosVuAsA0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_once); + LIB_FUNCTION("RtLRV-pBTTY", "libScePosix", 1, "libkernel", 1, 1, + posix_pthread_attr_getschedpolicy); // openorbis weird functions LIB_FUNCTION("7H0iTOciTLo", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_lock); @@ -1512,9 +1548,13 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("+U1R4WtXvoc", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_detach); LIB_FUNCTION("CBNtXOoef-E", "libScePosix", 1, "libkernel", 1, 1, posix_sched_get_priority_max); LIB_FUNCTION("m0iS6jNsXds", "libScePosix", 1, "libkernel", 1, 1, posix_sched_get_priority_min); + LIB_FUNCTION("FIs3-UQT9sg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_getschedparam); + LIB_FUNCTION("Xs9hdiD7sAA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setschedparam); LIB_FUNCTION("pDuPEf3m4fI", "libScePosix", 1, "libkernel", 1, 1, posix_sem_init); LIB_FUNCTION("YCV5dGGBcCo", "libScePosix", 1, "libkernel", 1, 1, posix_sem_wait); + LIB_FUNCTION("w5IHyvahg-o", "libScePosix", 1, "libkernel", 1, 1, posix_sem_timedwait); LIB_FUNCTION("IKP8typ0QUk", "libScePosix", 1, "libkernel", 1, 1, posix_sem_post); + LIB_FUNCTION("cDW233RAwWo", "libScePosix", 1, "libkernel", 1, 1, posix_sem_destroy); LIB_FUNCTION("Bq+LRV-N6Hk", "libScePosix", 1, "libkernel", 1, 1, posix_sem_getvalue); // libs RwlockSymbolsRegister(sym); diff --git a/src/core/libraries/playgo/playgo.cpp b/src/core/libraries/playgo/playgo.cpp index e029413e..a3af8b4c 100644 --- a/src/core/libraries/playgo/playgo.cpp +++ b/src/core/libraries/playgo/playgo.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include "common/logging/log.h" #include "common/singleton.h" #include "core/libraries/error_codes.h" @@ -50,9 +51,16 @@ s32 PS4_SYSV_ABI scePlayGoGetLocus(OrbisPlayGoHandle handle, const OrbisPlayGoCh uint32_t numberOfEntries, OrbisPlayGoLocus* outLoci) { LOG_ERROR(Lib_PlayGo, "(STUBBED)called handle = {}, chunkIds = {}, numberOfEntries = {}", handle, *chunkIds, numberOfEntries); - // assign all now so that scePlayGoGetLocus is not called again for every single entry - std::fill(outLoci, outLoci + numberOfEntries, - OrbisPlayGoLocusValue::ORBIS_PLAYGO_LOCUS_LOCAL_FAST); + + auto* playgo = Common::Singleton::Instance(); + + for (uint32_t i = 0; i < numberOfEntries; i++) { + if (chunkIds[i] <= playgo->GetPlaygoHeader().mchunk_count) { + outLoci[i] = OrbisPlayGoLocusValue::ORBIS_PLAYGO_LOCUS_LOCAL_FAST; + } else { + return ORBIS_PLAYGO_ERROR_BAD_CHUNK_ID; + } + } return ORBIS_OK; } @@ -68,7 +76,7 @@ s32 PS4_SYSV_ABI scePlayGoGetProgress(OrbisPlayGoHandle handle, const OrbisPlayG s32 PS4_SYSV_ABI scePlayGoGetToDoList(OrbisPlayGoHandle handle, OrbisPlayGoToDo* outTodoList, u32 numberOfEntries, u32* outEntries) { LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); - if (handle != shadMagic) + if (handle != 1) return ORBIS_PLAYGO_ERROR_BAD_HANDLE; if (outTodoList == nullptr) return ORBIS_PLAYGO_ERROR_BAD_POINTER; @@ -86,7 +94,7 @@ s32 PS4_SYSV_ABI scePlayGoInitialize(OrbisPlayGoInitParams* param) { } s32 PS4_SYSV_ABI scePlayGoOpen(OrbisPlayGoHandle* outHandle, const void* param) { - *outHandle = shadMagic; + *outHandle = 1; LOG_INFO(Lib_PlayGo, "(STUBBED)called"); return ORBIS_OK; } diff --git a/src/core/libraries/save_data/savedata.cpp b/src/core/libraries/save_data/savedata.cpp index db6d0964..a8519ab7 100644 --- a/src/core/libraries/save_data/savedata.cpp +++ b/src/core/libraries/save_data/savedata.cpp @@ -186,21 +186,23 @@ int PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond* if (!mount_dir.empty() && std::filesystem::exists(mount_dir)) { if (cond->dirName == nullptr) { // look for all dirs if no dir is provided. for (int i = 0; const auto& entry : std::filesystem::directory_iterator(mount_dir)) { - if (std::filesystem::is_directory(entry.path())) { + if (std::filesystem::is_directory(entry.path()) && + entry.path().filename().string() != "sdmemory") { + // sceSaveDataDirNameSearch does not search for dataMemory1/2 dirs. i++; result->dirNamesNum = 0; // why is it 1024? is it max? // copy dir name to be used by sceSaveDataMount in read mode. strncpy(result->dirNames[i].data, entry.path().filename().string().c_str(), 32); result->hitNum = i + 1; - result->dirNamesNum = i + 1; // to confirm - result->setNum = i + 1; // to confirm + result->dirNamesNum = i + 1; + result->setNum = i + 1; } } } else { // Need a game to test. strncpy(result->dirNames[0].data, cond->dirName->data, 32); result->hitNum = 1; - result->dirNamesNum = 1; // to confirm - result->setNum = 1; // to confirm + result->dirNamesNum = 1; + result->setNum = 1; } } else { result->hitNum = 0; @@ -321,7 +323,7 @@ int PS4_SYSV_ABI sceSaveDataGetSaveDataCount() { int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(const u32 userId, void* buf, const size_t bufSize, const int64_t offset) { const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / - std::to_string(userId) / game_serial / "save_mem1.sav"; + std::to_string(userId) / game_serial / "sdmemory/save_mem1.sav"; Common::FS::IOFile file(mount_dir, Common::FS::FileAccessMode::Read); if (!file.IsOpen()) { @@ -336,7 +338,7 @@ int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(const u32 userId, void* buf, const int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getParam) { const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / - std::to_string(getParam->userId) / game_serial; + std::to_string(getParam->userId) / game_serial / "sdmemory"; if (getParam == nullptr) return ORBIS_SAVE_DATA_ERROR_PARAMETER; if (getParam->data != nullptr) { @@ -604,7 +606,7 @@ int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(const u32 userId, const void* buf, const size_t bufSize, const int64_t offset) { LOG_INFO(Lib_SaveData, "called"); const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / - std::to_string(userId) / game_serial / "save_mem1.sav"; + std::to_string(userId) / game_serial / "sdmemory/save_mem1.sav"; Common::FS::IOFile file(mount_dir, Common::FS::FileAccessMode::Write); file.Seek(offset); @@ -616,7 +618,7 @@ int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(const u32 userId, const void* buf, int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam) { LOG_INFO(Lib_SaveData, "called: dataNum = {}, slotId= {}", setParam->dataNum, setParam->slotId); const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / - std::to_string(setParam->userId) / game_serial; + std::to_string(setParam->userId) / game_serial / "sdmemory"; if (setParam->data != nullptr) { Common::FS::IOFile file(mount_dir / "save_mem2.sav", Common::FS::FileAccessMode::Write); if (!file.IsOpen()) @@ -644,7 +646,7 @@ int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(u32 userId, size_t memorySize, LOG_INFO(Lib_SaveData, "called:userId = {}, memorySize = {}", userId, memorySize); const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / - std::to_string(userId) / game_serial; + std::to_string(userId) / game_serial / "sdmemory"; if (std::filesystem::exists(mount_dir)) { return ORBIS_SAVE_DATA_ERROR_EXISTS; @@ -663,7 +665,7 @@ int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2 LOG_INFO(Lib_SaveData, "called"); // if (setupParam->option == 1) { // check this later. const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) / - std::to_string(setupParam->userId) / game_serial; + std::to_string(setupParam->userId) / game_serial / "sdmemory"; if (std::filesystem::exists(mount_dir) && std::filesystem::exists(mount_dir / "save_mem2.sav")) { Common::FS::IOFile file(mount_dir / "save_mem2.sav", Common::FS::FileAccessMode::Read); diff --git a/src/emulator.cpp b/src/emulator.cpp index 47ac57ac..0b542e68 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include #include #include #include @@ -51,9 +52,6 @@ Emulator::Emulator() { memory = Core::Memory::Instance(); controller = Common::Singleton::Instance(); linker = Common::Singleton::Instance(); - window = std::make_unique(WindowWidth, WindowHeight, controller); - - g_window = window.get(); } Emulator::~Emulator() { @@ -68,6 +66,8 @@ void Emulator::Run(const std::filesystem::path& file) { // Loading param.sfo file if exists std::string id; + std::string title; + std::string app_version; std::filesystem::path sce_sys_folder = file.parent_path() / "sce_sys"; if (std::filesystem::is_directory(sce_sys_folder)) { for (const auto& entry : std::filesystem::directory_iterator(sce_sys_folder)) { @@ -75,11 +75,14 @@ void Emulator::Run(const std::filesystem::path& file) { auto* param_sfo = Common::Singleton::Instance(); param_sfo->open(sce_sys_folder.string() + "/param.sfo", {}); id = std::string(param_sfo->GetString("CONTENT_ID"), 7, 9); - std::string title(param_sfo->GetString("TITLE")); + title = param_sfo->GetString("TITLE"); LOG_INFO(Loader, "Game id: {} Title: {}", id, title); u32 fw_version = param_sfo->GetInteger("SYSTEM_VER"); - std::string app_version = param_sfo->GetString("APP_VER"); + app_version = param_sfo->GetString("APP_VER"); LOG_INFO(Loader, "Fw: {:#x} App Version: {}", fw_version, app_version); + } else if (entry.path().filename() == "playgo-chunk.dat") { + auto* playgo = Common::Singleton::Instance(); + playgo->Open(sce_sys_folder.string() + "/playgo-chunk.dat"); } else if (entry.path().filename() == "pic0.png" || entry.path().filename() == "pic1.png") { auto* splash = Common::Singleton::Instance(); @@ -92,6 +95,12 @@ void Emulator::Run(const std::filesystem::path& file) { } } } + std::string game_title = fmt::format("{} - {} <{}>", id, title, app_version); + + window = + std::make_unique(WindowWidth, WindowHeight, controller, game_title); + + g_window = window.get(); const auto& mount_data_dir = Common::FS::GetUserPath(Common::FS::PathType::GameDataDir) / id; if (!std::filesystem::exists(mount_data_dir)) { @@ -104,6 +113,13 @@ void Emulator::Run(const std::filesystem::path& file) { } mnt->Mount(mount_temp_dir, "/temp0"); // called in app_content ==> stat/mkdir + const auto& mount_download_dir = + Common::FS::GetUserPath(Common::FS::PathType::DownloadDir) / id; + if (!std::filesystem::exists(mount_download_dir)) { + std::filesystem::create_directory(mount_download_dir); + } + mnt->Mount(mount_download_dir, "/download0"); + // Initialize kernel and library facilities. Libraries::Kernel::init_pthreads(); Libraries::InitHLELibs(&linker->GetHLESymbols()); diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index c4fcbcfa..4570b64e 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -18,14 +18,15 @@ namespace Frontend { -WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_) +WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_, + std::string_view game_title) : width{width_}, height{height_}, controller{controller_} { if (SDL_Init(SDL_INIT_VIDEO) < 0) { UNREACHABLE_MSG("Failed to initialize SDL video subsystem: {}", SDL_GetError()); } SDL_InitSubSystem(SDL_INIT_AUDIO); - const std::string title = "shadPS4 v" + std::string(Common::VERSION); + const std::string title = fmt::format("shadPS4 v{} | {}", Common::VERSION, game_title); SDL_PropertiesID props = SDL_CreateProperties(); SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, title.c_str()); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED); diff --git a/src/sdl_window.h b/src/sdl_window.h index 6e14fbd0..89b2a877 100644 --- a/src/sdl_window.h +++ b/src/sdl_window.h @@ -3,6 +3,7 @@ #pragma once +#include #include "common/types.h" struct SDL_Window; @@ -40,7 +41,8 @@ struct WindowSystemInfo { class WindowSDL { public: - explicit WindowSDL(s32 width, s32 height, Input::GameController* controller); + explicit WindowSDL(s32 width, s32 height, Input::GameController* controller, + std::string_view game_title); ~WindowSDL(); s32 getWidth() const {