PlayGo: basic implementation, credits to red-prig

This commit is contained in:
bax-cz 2024-08-19 13:14:14 +02:00
parent 138c9ce787
commit 516a3e7104
5 changed files with 446 additions and 54 deletions

View File

@ -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<playgo_chunk_attr_entry_t*>(&chunk_attrs_data[0]);
auto chunk_mchunks = reinterpret_cast<u16*>(&chunk_mchunks_data[0]);
auto chunk_labels = reinterpret_cast<char*>(&chunk_labels_data[0]);
auto mchunk_attrs =
reinterpret_cast<playgo_mchunk_attr_entry_t*>(&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<u16*>(
((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<char>(&data[0], chunk.length);
return true;
}
}
}
return false;
}

View File

@ -3,29 +3,128 @@
#pragma once
#include <filesystem>
#include "common/types.h"
#include <mutex>
#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
};
class PlaygoChunk {
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;
} __attribute__((packed));
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<PlaygoChunk> 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;
std::mutex speed_mutex;
};

View File

@ -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<PlaygoFile>::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<PlaygoFile>::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<PlaygoFile>::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<milliseconds>(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<PlaygoFile>::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 = {}",
LOG_INFO(Lib_PlayGo, "called handle = {}, chunkIds = {}, numberOfEntries = {}",
handle, *chunkIds, numberOfEntries);
auto* playgo = Common::Singleton<PlaygoChunk>::Instance();
auto* playgo = Common::Singleton<PlaygoFile>::Instance();
for (uint32_t i = 0; i < numberOfEntries; i++) {
if (chunkIds[i] <= playgo->GetPlaygoHeader().mchunk_count) {
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->chunks.size()) {
outLoci[i] = OrbisPlayGoLocusValue::ORBIS_PLAYGO_LOCUS_LOCAL_FAST;
} else {
outLoci[i] = ORBIS_PLAYGO_LOCUS_NOT_DOWNLOADED;
@ -67,64 +155,204 @@ 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 = {}",
LOG_INFO(Lib_PlayGo, "called handle = {}, chunkIds = {}, numberOfEntries = {}",
handle, *chunkIds, numberOfEntries);
outProgress->progressSize = 0x10000; // todo?
outProgress->totalSize = 0x10000;
auto* playgo = Common::Singleton<PlaygoFile>::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,
LOG_INFO(Lib_PlayGo, "called handle = {} numberOfEntries = {}", handle,
numberOfEntries);
auto* playgo = Common::Singleton<PlaygoFile>::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<PlaygoFile>::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<PlaygoFile>::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<PlaygoFile>::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<PlaygoFile>::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<milliseconds>(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<PlaygoFile>::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<PlaygoFile>::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<PlaygoFile>::Instance();
if (playgo->initialized) {
playgo->initialized = false;
} else {
return ORBIS_PLAYGO_ERROR_NOT_INITIALIZED;
}
return ORBIS_OK;
}

View File

@ -14,10 +14,12 @@ 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 +30,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,

View File

@ -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<PlaygoChunk>::Instance();
playgo->Open(sce_sys_folder.string() + "/playgo-chunk.dat");
auto* playgo = Common::Singleton<PlaygoFile>::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<Splash>::Instance();