diff --git a/src/core/file_format/playgo_chunk.cpp b/src/core/file_format/playgo_chunk.cpp index 43d8a4de..a430b1ac 100644 --- a/src/core/file_format/playgo_chunk.cpp +++ b/src/core/file_format/playgo_chunk.cpp @@ -1,16 +1,75 @@ // 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) { +bool PlaygoFile::Open(const std::filesystem::path& filepath) { Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read); - if (!file.IsOpen()) { - return false; + if (file.IsOpen()) { + file.Read(playgoHeader); + if (LoadChunks(file)) { + return true; + } } - file.Read(playgoHeader); + return false; +} - return true; +bool PlaygoFile::LoadChunks(const Common::FS::IOFile& file) { + if (file.IsOpen()) { + if (playgoHeader.magic == PLAYGO_MAGIC) { + bool ret = true; + + std::string chunk_attrs_data, chunk_mchunks_data, chunk_labels_data, mchunk_attrs_data; + ret = ret && load_chunk_data(file, playgoHeader.chunk_attrs, chunk_attrs_data); + ret = ret && load_chunk_data(file, playgoHeader.chunk_mchunks, chunk_mchunks_data); + ret = ret && load_chunk_data(file, playgoHeader.chunk_labels, chunk_labels_data); + ret = ret && load_chunk_data(file, playgoHeader.mchunk_attrs, mchunk_attrs_data); + + if (ret) { + chunks.resize(playgoHeader.chunk_count); + + auto chunk_attrs = + reinterpret_cast(&chunk_attrs_data[0]); + auto chunk_mchunks = reinterpret_cast(&chunk_mchunks_data[0]); + auto chunk_labels = reinterpret_cast(&chunk_labels_data[0]); + auto mchunk_attrs = + reinterpret_cast(&mchunk_attrs_data[0]); + + for (u16 i = 0; i < playgoHeader.chunk_count; i++) { + chunks[i].req_locus = chunk_attrs[i].req_locus; + chunks[i].language_mask = chunk_attrs[i].language_mask; + chunks[i].label_name = std::string(chunk_labels + chunk_attrs[i].label_offset); + + u64 total_size = 0; + u16 mchunk_count = chunk_attrs[i].mchunk_count; + if (mchunk_count != 0) { + auto mchunks = reinterpret_cast( + ((u8*)chunk_mchunks + chunk_attrs[i].mchunks_offset)); + for (u16 j = 0; j < mchunk_count; j++) { + u16 mchunk_id = mchunks[j]; + total_size += mchunk_attrs[mchunk_id].size.size; + } + } + chunks[i].total_size = total_size; + } + } + + return ret; + } + } + return false; +} + +bool PlaygoFile::load_chunk_data(const Common::FS::IOFile& file, const chunk_t& chunk, + std::string& data) { + if (file.IsOpen()) { + if (file.Seek(chunk.offset)) { + data.resize(chunk.length); + if (data.size() == chunk.length) { + file.ReadRaw(&data[0], chunk.length); + return true; + } + } + } + return false; } \ No newline at end of file diff --git a/src/core/file_format/playgo_chunk.h b/src/core/file_format/playgo_chunk.h index d17d24bf..439e27d0 100644 --- a/src/core/file_format/playgo_chunk.h +++ b/src/core/file_format/playgo_chunk.h @@ -3,29 +3,129 @@ #pragma once #include -#include "common/types.h" +#include +#include +#include "common/io_file.h" +#include "core/libraries/playgo/playgo_types.h" + +constexpr u32 PLAYGO_MAGIC = 0x6F676C70; + +struct chunk_t { + u32 offset; + u32 length; +} __attribute__((packed)); struct PlaygoHeader { u32 magic; u16 version_major; u16 version_minor; - u16 image_count; + u16 image_count; // [0;1] + u16 chunk_count; // [0;1000] + u16 mchunk_count; // [0;8000] + u16 scenario_count; // [0;32] + + u32 file_size; + u16 default_scenario_id; + u16 attrib; + u32 sdk_version; + u16 disc_count; // [0;2] (if equals to 0 then disc count = 1) + u16 layer_bmp; + + u8 reserved[32]; + char content_id[128]; + + chunk_t chunk_attrs; // [0;32000] + chunk_t chunk_mchunks; + chunk_t chunk_labels; // [0;16000] + chunk_t mchunk_attrs; // [0;12800] + chunk_t scenario_attrs; // [0;1024] + chunk_t scenario_chunks; + chunk_t scenario_labels; + chunk_t inner_mchunk_attrs; // [0;12800] +} __attribute__((packed)); + +struct playgo_scenario_attr_entry_t { + u8 _type; + u8 _unk[19]; + u16 initial_chunk_count; u16 chunk_count; + u32 chunks_offset; //<-scenario_chunks + u32 label_offset; //<-scenario_labels +} __attribute__((packed)); + +struct image_disc_layer_no_t { + u8 layer_no : 2; + u8 disc_no : 2; + u8 image_no : 4; +} __attribute__((packed)); + +struct playgo_chunk_attr_entry_t { + u8 flag; + image_disc_layer_no_t image_disc_layer_no; + u8 req_locus; + u8 unk[11]; u16 mchunk_count; - u16 scenario_count; - // TODO fill the rest + u64 language_mask; + u32 mchunks_offset; //<-chunk_mchunks + u32 label_offset; //<-chunk_labels +} __attribute__((packed)); + +struct playgo_chunk_loc_t { + u64 offset : 48; + u64 _align1 : 8; + u64 image_no : 4; + u64 _align2 : 4; +} __attribute__((packed)); + +struct playgo_chunk_size_t { + u64 size : 48; + u64 _align : 16; +} __attribute__((packed)); + +struct playgo_mchunk_attr_entry_t { + playgo_chunk_loc_t loc; + playgo_chunk_size_t size; +} __attribute__((packed)); + +struct PlaygoChunk { + u64 req_locus; + u64 language_mask; + u64 total_size; + std::string label_name; }; -class PlaygoChunk { + +class PlaygoFile { public: - PlaygoChunk() = default; - ~PlaygoChunk() = default; + bool initialized; + OrbisPlayGoHandle handle; + OrbisPlayGoChunkId id; + OrbisPlayGoLocus locus; + OrbisPlayGoInstallSpeed speed; + s64 speed_tick; + OrbisPlayGoEta eta; + OrbisPlayGoLanguageMask langMask; + std::vector chunks; + +public: + PlaygoFile() + : initialized(false), handle(0), id(0), locus(0), speed(ORBIS_PLAYGO_INSTALL_SPEED_TRICKLE), + speed_tick(0), eta(0), langMask(0), playgoHeader{0} {} + ~PlaygoFile() = default; bool Open(const std::filesystem::path& filepath); - PlaygoHeader GetPlaygoHeader() { + bool LoadChunks(const Common::FS::IOFile& file); + PlaygoHeader& GetPlaygoHeader() { return playgoHeader; } + std::mutex& GetSpeedMutex() { + return speed_mutex; + } + +private: + bool load_chunk_data(const Common::FS::IOFile& file, const chunk_t& chunk, std::string& data); private: PlaygoHeader playgoHeader; -}; \ No newline at end of file + std::mutex speed_mutex; +}; diff --git a/src/core/libraries/playgo/playgo.cpp b/src/core/libraries/playgo/playgo.cpp index af98253f..66422dc2 100644 --- a/src/core/libraries/playgo/playgo.cpp +++ b/src/core/libraries/playgo/playgo.cpp @@ -6,6 +6,7 @@ #include "common/singleton.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" +#include "core/libraries/system/systemservice.h" #include "playgo.h" namespace Libraries::PlayGo { @@ -20,42 +21,129 @@ s32 PS4_SYSV_ABI sceDbgPlayGoSnapshot() { return ORBIS_OK; } -s32 PS4_SYSV_ABI scePlayGoClose() { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); +s32 PS4_SYSV_ABI scePlayGoClose(OrbisPlayGoHandle handle) { + LOG_INFO(Lib_PlayGo, "called"); + + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; return ORBIS_OK; } -s32 PS4_SYSV_ABI scePlayGoGetChunkId() { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); +s32 PS4_SYSV_ABI scePlayGoGetChunkId(OrbisPlayGoHandle handle, OrbisPlayGoChunkId* outChunkIdList, + u32 numberOfEntries, u32* outEntries) { + LOG_INFO(Lib_PlayGo, "called"); + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (outEntries == nullptr) + return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (outChunkIdList != nullptr && numberOfEntries == 0) + return ORBIS_PLAYGO_ERROR_BAD_SIZE; + + if (playgo->GetPlaygoHeader().file_size == 0) { + *outEntries = 0; + } else { + if (outChunkIdList == nullptr) { + *outEntries = playgo->chunks.size(); + } else { + if (numberOfEntries > playgo->chunks.size()) { + numberOfEntries = playgo->chunks.size(); + } + + if (numberOfEntries != 0) { + for (u32 i = 0; i < numberOfEntries; i++) { + outChunkIdList[i] = i; + } + *outEntries = numberOfEntries; + } + } + } return ORBIS_OK; } -s32 PS4_SYSV_ABI scePlayGoGetEta() { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); +s32 PS4_SYSV_ABI scePlayGoGetEta(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds, + u32 numberOfEntries, OrbisPlayGoEta* outEta) { + LOG_INFO(Lib_PlayGo, "called"); + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (chunkIds == nullptr || outEta == nullptr) + return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (numberOfEntries == 0) + return ORBIS_PLAYGO_ERROR_BAD_SIZE; + + *outEta = 0; // all is loaded return ORBIS_OK; } -s32 PS4_SYSV_ABI scePlayGoGetInstallSpeed() { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); +s32 PS4_SYSV_ABI scePlayGoGetInstallSpeed(OrbisPlayGoHandle handle, + OrbisPlayGoInstallSpeed* outSpeed) { + LOG_INFO(Lib_PlayGo, "called"); + + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (outSpeed == nullptr) + return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; + + std::scoped_lock lk{playgo->GetSpeedMutex()}; + + if (playgo->speed == 0) { + using namespace std::chrono; + if ((duration_cast(steady_clock::now().time_since_epoch()).count() - + playgo->speed_tick) > 30 * 1000) { // 30sec + playgo->speed = ORBIS_PLAYGO_INSTALL_SPEED_TRICKLE; + } + } + *outSpeed = playgo->speed; + return ORBIS_OK; } s32 PS4_SYSV_ABI scePlayGoGetLanguageMask(OrbisPlayGoHandle handle, - OrbisPlayGoLanguageMask* languageMask) { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); - *languageMask = 1; // En, todo; + OrbisPlayGoLanguageMask* outLanguageMask) { + LOG_INFO(Lib_PlayGo, "called"); + + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (outLanguageMask == nullptr) + return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; + + *outLanguageMask = playgo->langMask; return ORBIS_OK; } s32 PS4_SYSV_ABI scePlayGoGetLocus(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds, uint32_t numberOfEntries, OrbisPlayGoLocus* outLoci) { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called handle = {}, chunkIds = {}, numberOfEntries = {}", - handle, *chunkIds, numberOfEntries); + LOG_INFO(Lib_PlayGo, "called handle = {}, chunkIds = {}, numberOfEntries = {}", handle, + *chunkIds, numberOfEntries); - auto* playgo = Common::Singleton::Instance(); + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (chunkIds == nullptr || outLoci == nullptr) + return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (numberOfEntries == 0) + return ORBIS_PLAYGO_ERROR_BAD_SIZE; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; + if (playgo->GetPlaygoHeader().file_size == 0) + return ORBIS_PLAYGO_ERROR_NOT_SUPPORT_PLAYGO; for (uint32_t i = 0; i < numberOfEntries; i++) { - if (chunkIds[i] <= playgo->GetPlaygoHeader().mchunk_count) { + if (chunkIds[i] <= playgo->chunks.size()) { outLoci[i] = OrbisPlayGoLocusValue::ORBIS_PLAYGO_LOCUS_LOCAL_FAST; } else { outLoci[i] = ORBIS_PLAYGO_LOCUS_NOT_DOWNLOADED; @@ -67,64 +155,202 @@ s32 PS4_SYSV_ABI scePlayGoGetLocus(OrbisPlayGoHandle handle, const OrbisPlayGoCh s32 PS4_SYSV_ABI scePlayGoGetProgress(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds, uint32_t numberOfEntries, OrbisPlayGoProgress* outProgress) { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called handle = {}, chunkIds = {}, numberOfEntries = {}", - handle, *chunkIds, numberOfEntries); - outProgress->progressSize = 0x10000; // todo? - outProgress->totalSize = 0x10000; + LOG_INFO(Lib_PlayGo, "called handle = {}, chunkIds = {}, numberOfEntries = {}", handle, + *chunkIds, numberOfEntries); + + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (chunkIds == nullptr || outProgress == nullptr) + return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (numberOfEntries == 0) + return ORBIS_PLAYGO_ERROR_BAD_SIZE; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; + if (playgo->GetPlaygoHeader().file_size == 0) + return ORBIS_PLAYGO_ERROR_BAD_CHUNK_ID; + + outProgress->progressSize = 0; + outProgress->totalSize = 0; + + u64 total_size = 0; + for (u32 i = 0; i < numberOfEntries; i++) { + u32 chunk_id = chunkIds[i]; + if (chunk_id < playgo->chunks.size()) { + total_size += playgo->chunks[chunk_id].total_size; + } else { + return ORBIS_PLAYGO_ERROR_BAD_CHUNK_ID; + } + } + + outProgress->progressSize = total_size; + outProgress->totalSize = total_size; + return ORBIS_OK; } s32 PS4_SYSV_ABI scePlayGoGetToDoList(OrbisPlayGoHandle handle, OrbisPlayGoToDo* outTodoList, u32 numberOfEntries, u32* outEntries) { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called handle = {} numberOfEntries = {}", handle, - numberOfEntries); + LOG_INFO(Lib_PlayGo, "called handle = {} numberOfEntries = {}", handle, numberOfEntries); + + auto* playgo = Common::Singleton::Instance(); + if (handle != 1) return ORBIS_PLAYGO_ERROR_BAD_HANDLE; - if (outTodoList == nullptr) + if (outTodoList == nullptr || outEntries == nullptr) return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (numberOfEntries == 0) + return ORBIS_PLAYGO_ERROR_BAD_SIZE; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; *outEntries = 0; // nothing to do return ORBIS_OK; } +int scePlayGoConvertLanguage(int systemLang) { + if (systemLang >= 0 && systemLang < 48) { + return (1 << (64 - systemLang - 1)); + } else { + return 0; + } +} + s32 PS4_SYSV_ABI scePlayGoInitialize(OrbisPlayGoInitParams* param) { + LOG_INFO(Lib_PlayGo, "called, bufSize = {}", param->bufSize); if (param->bufAddr == nullptr) return ORBIS_PLAYGO_ERROR_BAD_POINTER; if (param->bufSize < 0x200000) return ORBIS_PLAYGO_ERROR_BAD_SIZE; - LOG_INFO(Lib_PlayGo, "(STUBBED)called, bufSize = {}", param->bufSize); + + auto* playgo = Common::Singleton::Instance(); + + if (!playgo->initialized) { + using namespace SystemService; + // get system lang + int systemLang = 0; + sceSystemServiceParamGetInt(ORBIS_SYSTEM_SERVICE_PARAM_ID_LANG, &systemLang); + playgo->langMask = scePlayGoConvertLanguage(systemLang); + playgo->initialized = true; + } else { + return ORBIS_PLAYGO_ERROR_ALREADY_INITIALIZED; + } return ORBIS_OK; } s32 PS4_SYSV_ABI scePlayGoOpen(OrbisPlayGoHandle* outHandle, const void* param) { - *outHandle = 1; - LOG_INFO(Lib_PlayGo, "(STUBBED)called"); + LOG_INFO(Lib_PlayGo, "called"); + + auto* playgo = Common::Singleton::Instance(); + + if (outHandle == nullptr) + return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (param) + return ORBIS_PLAYGO_ERROR_INVALID_ARGUMENT; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; + if (playgo->GetPlaygoHeader().file_size == 0) + return ORBIS_PLAYGO_ERROR_NOT_SUPPORT_PLAYGO; + + playgo->handle = *outHandle = 1; return ORBIS_OK; } -s32 PS4_SYSV_ABI scePlayGoPrefetch() { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); +s32 PS4_SYSV_ABI scePlayGoPrefetch(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds, + u32 numberOfEntries, OrbisPlayGoLocus minimumLocus) { + LOG_INFO(Lib_PlayGo, "called"); + + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (chunkIds == nullptr) + return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (numberOfEntries == 0) + return ORBIS_PLAYGO_ERROR_BAD_SIZE; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; + + switch (minimumLocus) { + case ORBIS_PLAYGO_LOCUS_NOT_DOWNLOADED: + case ORBIS_PLAYGO_LOCUS_LOCAL_SLOW: + case ORBIS_PLAYGO_LOCUS_LOCAL_FAST: + break; + default: + return ORBIS_PLAYGO_ERROR_BAD_LOCUS; + } return ORBIS_OK; } -s32 PS4_SYSV_ABI scePlayGoSetInstallSpeed() { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); +s32 PS4_SYSV_ABI scePlayGoSetInstallSpeed(OrbisPlayGoHandle handle, OrbisPlayGoInstallSpeed speed) { + LOG_INFO(Lib_PlayGo, "called"); + + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; + + switch (speed) { + case ORBIS_PLAYGO_INSTALL_SPEED_SUSPENDED: + case ORBIS_PLAYGO_INSTALL_SPEED_TRICKLE: + case ORBIS_PLAYGO_INSTALL_SPEED_FULL: + break; + default: + return ORBIS_PLAYGO_ERROR_INVALID_ARGUMENT; + } + + std::scoped_lock lk{playgo->GetSpeedMutex()}; + + using namespace std::chrono; + playgo->speed = speed; + playgo->speed_tick = + duration_cast(steady_clock::now().time_since_epoch()).count(); + return ORBIS_OK; } s32 PS4_SYSV_ABI scePlayGoSetLanguageMask(OrbisPlayGoHandle handle, OrbisPlayGoLanguageMask languageMask) { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); + LOG_INFO(Lib_PlayGo, "called"); + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; + + playgo->langMask = languageMask; return ORBIS_OK; } s32 PS4_SYSV_ABI scePlayGoSetToDoList(OrbisPlayGoHandle handle, const OrbisPlayGoToDo* todoList, uint32_t numberOfEntries) { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); + LOG_INFO(Lib_PlayGo, "called"); + + auto* playgo = Common::Singleton::Instance(); + + if (handle != 1) + return ORBIS_PLAYGO_ERROR_BAD_HANDLE; + if (todoList == nullptr) + return ORBIS_PLAYGO_ERROR_BAD_POINTER; + if (numberOfEntries == 0) + return ORBIS_PLAYGO_ERROR_BAD_SIZE; + if (!playgo->initialized) + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; return ORBIS_OK; } s32 PS4_SYSV_ABI scePlayGoTerminate() { - LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); + LOG_INFO(Lib_PlayGo, "called"); + + auto* playgo = Common::Singleton::Instance(); + if (playgo->initialized) { + playgo->initialized = false; + } else { + return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED; + } return ORBIS_OK; } diff --git a/src/core/libraries/playgo/playgo.h b/src/core/libraries/playgo/playgo.h index a6b8c91d..f5ae1baa 100644 --- a/src/core/libraries/playgo/playgo.h +++ b/src/core/libraries/playgo/playgo.h @@ -14,10 +14,13 @@ constexpr int shadMagic = 0x53484144; s32 PS4_SYSV_ABI sceDbgPlayGoRequestNextChunk(); s32 PS4_SYSV_ABI sceDbgPlayGoSnapshot(); -s32 PS4_SYSV_ABI scePlayGoClose(); -s32 PS4_SYSV_ABI scePlayGoGetChunkId(); -s32 PS4_SYSV_ABI scePlayGoGetEta(); -s32 PS4_SYSV_ABI scePlayGoGetInstallSpeed(); +s32 PS4_SYSV_ABI scePlayGoClose(OrbisPlayGoHandle handle); +s32 PS4_SYSV_ABI scePlayGoGetChunkId(OrbisPlayGoHandle handle, OrbisPlayGoChunkId* outChunkIdList, + u32 numberOfEntries, u32* outEntries); +s32 PS4_SYSV_ABI scePlayGoGetEta(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds, + u32 numberOfEntries, OrbisPlayGoEta* outEta); +s32 PS4_SYSV_ABI scePlayGoGetInstallSpeed(OrbisPlayGoHandle handle, + OrbisPlayGoInstallSpeed* outSpeed); s32 PS4_SYSV_ABI scePlayGoGetLanguageMask(OrbisPlayGoHandle handle, OrbisPlayGoLanguageMask* outLanguageMask); s32 PS4_SYSV_ABI scePlayGoGetLocus(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds, @@ -28,8 +31,9 @@ s32 PS4_SYSV_ABI scePlayGoGetToDoList(OrbisPlayGoHandle handle, OrbisPlayGoToDo* u32 numberOfEntries, u32* outEntries); s32 PS4_SYSV_ABI scePlayGoInitialize(OrbisPlayGoInitParams* param); s32 PS4_SYSV_ABI scePlayGoOpen(OrbisPlayGoHandle* outHandle, const void* param); -s32 PS4_SYSV_ABI scePlayGoPrefetch(); -s32 PS4_SYSV_ABI scePlayGoSetInstallSpeed(); +s32 PS4_SYSV_ABI scePlayGoPrefetch(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds, + u32 numberOfEntries, OrbisPlayGoLocus minimumLocus); +s32 PS4_SYSV_ABI scePlayGoSetInstallSpeed(OrbisPlayGoHandle handle, OrbisPlayGoInstallSpeed speed); s32 PS4_SYSV_ABI scePlayGoSetLanguageMask(OrbisPlayGoHandle handle, OrbisPlayGoLanguageMask languageMask); s32 PS4_SYSV_ABI scePlayGoSetToDoList(OrbisPlayGoHandle handle, const OrbisPlayGoToDo* todoList, diff --git a/src/emulator.cpp b/src/emulator.cpp index 12e89349..9cc7a130 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -91,8 +91,11 @@ void Emulator::Run(const std::filesystem::path& file) { 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"); + auto* playgo = Common::Singleton::Instance(); + auto filepath = sce_sys_folder / "playgo-chunk.dat"; + if (!playgo->Open(filepath)) { + LOG_ERROR(Loader, "PlayGo: unable to open file"); + } } else if (entry.path().filename() == "pic0.png" || entry.path().filename() == "pic1.png") { auto* splash = Common::Singleton::Instance();