mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-12-29 11:06:07 +00:00
PlayGo: basic implementation, credits to red-prig
This commit is contained in:
parent
138c9ce787
commit
516a3e7104
|
@ -1,16 +1,75 @@
|
||||||
// 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
|
||||||
|
|
||||||
#include "common/io_file.h"
|
|
||||||
|
|
||||||
#include "playgo_chunk.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);
|
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
|
||||||
if (!file.IsOpen()) {
|
if (file.IsOpen()) {
|
||||||
return false;
|
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;
|
||||||
}
|
}
|
|
@ -3,29 +3,128 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <filesystem>
|
#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 {
|
struct PlaygoHeader {
|
||||||
u32 magic;
|
u32 magic;
|
||||||
|
|
||||||
u16 version_major;
|
u16 version_major;
|
||||||
u16 version_minor;
|
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;
|
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 mchunk_count;
|
||||||
u16 scenario_count;
|
u64 language_mask;
|
||||||
// TODO fill the rest
|
u32 mchunks_offset; //<-chunk_mchunks
|
||||||
};
|
u32 label_offset; //<-chunk_labels
|
||||||
class PlaygoChunk {
|
} __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:
|
public:
|
||||||
PlaygoChunk() = default;
|
bool initialized;
|
||||||
~PlaygoChunk() = default;
|
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);
|
bool Open(const std::filesystem::path& filepath);
|
||||||
PlaygoHeader GetPlaygoHeader() {
|
bool LoadChunks(const Common::FS::IOFile& file);
|
||||||
|
PlaygoHeader& GetPlaygoHeader() {
|
||||||
return playgoHeader;
|
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:
|
private:
|
||||||
PlaygoHeader playgoHeader;
|
PlaygoHeader playgoHeader;
|
||||||
|
std::mutex speed_mutex;
|
||||||
};
|
};
|
|
@ -6,6 +6,7 @@
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
#include "core/libraries/system/systemservice.h"
|
||||||
#include "playgo.h"
|
#include "playgo.h"
|
||||||
|
|
||||||
namespace Libraries::PlayGo {
|
namespace Libraries::PlayGo {
|
||||||
|
@ -20,42 +21,129 @@ s32 PS4_SYSV_ABI sceDbgPlayGoSnapshot() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoClose() {
|
s32 PS4_SYSV_ABI scePlayGoClose(OrbisPlayGoHandle handle) {
|
||||||
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;
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetChunkId() {
|
s32 PS4_SYSV_ABI scePlayGoGetChunkId(OrbisPlayGoHandle handle, OrbisPlayGoChunkId* outChunkIdList,
|
||||||
LOG_ERROR(Lib_PlayGo, "(STUBBED)called");
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetEta() {
|
s32 PS4_SYSV_ABI scePlayGoGetEta(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds,
|
||||||
LOG_ERROR(Lib_PlayGo, "(STUBBED)called");
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetInstallSpeed() {
|
s32 PS4_SYSV_ABI scePlayGoGetInstallSpeed(OrbisPlayGoHandle handle,
|
||||||
LOG_ERROR(Lib_PlayGo, "(STUBBED)called");
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetLanguageMask(OrbisPlayGoHandle handle,
|
s32 PS4_SYSV_ABI scePlayGoGetLanguageMask(OrbisPlayGoHandle handle,
|
||||||
OrbisPlayGoLanguageMask* languageMask) {
|
OrbisPlayGoLanguageMask* outLanguageMask) {
|
||||||
LOG_ERROR(Lib_PlayGo, "(STUBBED)called");
|
LOG_INFO(Lib_PlayGo, "called");
|
||||||
*languageMask = 1; // En, todo;
|
|
||||||
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetLocus(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds,
|
s32 PS4_SYSV_ABI scePlayGoGetLocus(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds,
|
||||||
uint32_t numberOfEntries, OrbisPlayGoLocus* outLoci) {
|
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);
|
handle, *chunkIds, numberOfEntries);
|
||||||
|
|
||||||
auto* playgo = Common::Singleton<PlaygoChunk>::Instance();
|
auto* playgo = Common::Singleton<PlaygoFile>::Instance();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < numberOfEntries; i++) {
|
if (handle != 1)
|
||||||
if (chunkIds[i] <= playgo->GetPlaygoHeader().mchunk_count) {
|
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;
|
outLoci[i] = OrbisPlayGoLocusValue::ORBIS_PLAYGO_LOCUS_LOCAL_FAST;
|
||||||
} else {
|
} else {
|
||||||
outLoci[i] = ORBIS_PLAYGO_LOCUS_NOT_DOWNLOADED;
|
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,
|
s32 PS4_SYSV_ABI scePlayGoGetProgress(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds,
|
||||||
uint32_t numberOfEntries, OrbisPlayGoProgress* outProgress) {
|
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);
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetToDoList(OrbisPlayGoHandle handle, OrbisPlayGoToDo* outTodoList,
|
s32 PS4_SYSV_ABI scePlayGoGetToDoList(OrbisPlayGoHandle handle, OrbisPlayGoToDo* outTodoList,
|
||||||
u32 numberOfEntries, u32* outEntries) {
|
u32 numberOfEntries, u32* outEntries) {
|
||||||
LOG_ERROR(Lib_PlayGo, "(STUBBED)called handle = {} numberOfEntries = {}", handle,
|
LOG_INFO(Lib_PlayGo, "called handle = {} numberOfEntries = {}", handle,
|
||||||
numberOfEntries);
|
numberOfEntries);
|
||||||
|
|
||||||
|
auto* playgo = Common::Singleton<PlaygoFile>::Instance();
|
||||||
|
|
||||||
if (handle != 1)
|
if (handle != 1)
|
||||||
return ORBIS_PLAYGO_ERROR_BAD_HANDLE;
|
return ORBIS_PLAYGO_ERROR_BAD_HANDLE;
|
||||||
if (outTodoList == nullptr)
|
if (outTodoList == nullptr || outEntries == nullptr)
|
||||||
return ORBIS_PLAYGO_ERROR_BAD_POINTER;
|
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
|
*outEntries = 0; // nothing to do
|
||||||
return ORBIS_OK;
|
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) {
|
s32 PS4_SYSV_ABI scePlayGoInitialize(OrbisPlayGoInitParams* param) {
|
||||||
|
LOG_INFO(Lib_PlayGo, "called, bufSize = {}", param->bufSize);
|
||||||
if (param->bufAddr == nullptr)
|
if (param->bufAddr == nullptr)
|
||||||
return ORBIS_PLAYGO_ERROR_BAD_POINTER;
|
return ORBIS_PLAYGO_ERROR_BAD_POINTER;
|
||||||
if (param->bufSize < 0x200000)
|
if (param->bufSize < 0x200000)
|
||||||
return ORBIS_PLAYGO_ERROR_BAD_SIZE;
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoOpen(OrbisPlayGoHandle* outHandle, const void* param) {
|
s32 PS4_SYSV_ABI scePlayGoOpen(OrbisPlayGoHandle* outHandle, const void* param) {
|
||||||
*outHandle = 1;
|
LOG_INFO(Lib_PlayGo, "called");
|
||||||
LOG_INFO(Lib_PlayGo, "(STUBBED)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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoPrefetch() {
|
s32 PS4_SYSV_ABI scePlayGoPrefetch(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds,
|
||||||
LOG_ERROR(Lib_PlayGo, "(STUBBED)called");
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoSetInstallSpeed() {
|
s32 PS4_SYSV_ABI scePlayGoSetInstallSpeed(OrbisPlayGoHandle handle, OrbisPlayGoInstallSpeed speed) {
|
||||||
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;
|
||||||
|
|
||||||
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoSetLanguageMask(OrbisPlayGoHandle handle,
|
s32 PS4_SYSV_ABI scePlayGoSetLanguageMask(OrbisPlayGoHandle handle,
|
||||||
OrbisPlayGoLanguageMask languageMask) {
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoSetToDoList(OrbisPlayGoHandle handle, const OrbisPlayGoToDo* todoList,
|
s32 PS4_SYSV_ABI scePlayGoSetToDoList(OrbisPlayGoHandle handle, const OrbisPlayGoToDo* todoList,
|
||||||
uint32_t numberOfEntries) {
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI scePlayGoTerminate() {
|
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;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,12 @@ constexpr int shadMagic = 0x53484144;
|
||||||
|
|
||||||
s32 PS4_SYSV_ABI sceDbgPlayGoRequestNextChunk();
|
s32 PS4_SYSV_ABI sceDbgPlayGoRequestNextChunk();
|
||||||
s32 PS4_SYSV_ABI sceDbgPlayGoSnapshot();
|
s32 PS4_SYSV_ABI sceDbgPlayGoSnapshot();
|
||||||
s32 PS4_SYSV_ABI scePlayGoClose();
|
s32 PS4_SYSV_ABI scePlayGoClose(OrbisPlayGoHandle handle);
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetChunkId();
|
s32 PS4_SYSV_ABI scePlayGoGetChunkId(OrbisPlayGoHandle handle, OrbisPlayGoChunkId* outChunkIdList,
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetEta();
|
u32 numberOfEntries, u32* outEntries);
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetInstallSpeed();
|
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,
|
s32 PS4_SYSV_ABI scePlayGoGetLanguageMask(OrbisPlayGoHandle handle,
|
||||||
OrbisPlayGoLanguageMask* outLanguageMask);
|
OrbisPlayGoLanguageMask* outLanguageMask);
|
||||||
s32 PS4_SYSV_ABI scePlayGoGetLocus(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds,
|
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);
|
u32 numberOfEntries, u32* outEntries);
|
||||||
s32 PS4_SYSV_ABI scePlayGoInitialize(OrbisPlayGoInitParams* param);
|
s32 PS4_SYSV_ABI scePlayGoInitialize(OrbisPlayGoInitParams* param);
|
||||||
s32 PS4_SYSV_ABI scePlayGoOpen(OrbisPlayGoHandle* outHandle, const void* param);
|
s32 PS4_SYSV_ABI scePlayGoOpen(OrbisPlayGoHandle* outHandle, const void* param);
|
||||||
s32 PS4_SYSV_ABI scePlayGoPrefetch();
|
s32 PS4_SYSV_ABI scePlayGoPrefetch(OrbisPlayGoHandle handle, const OrbisPlayGoChunkId* chunkIds,
|
||||||
s32 PS4_SYSV_ABI scePlayGoSetInstallSpeed();
|
u32 numberOfEntries, OrbisPlayGoLocus minimumLocus);
|
||||||
|
s32 PS4_SYSV_ABI scePlayGoSetInstallSpeed(OrbisPlayGoHandle handle, OrbisPlayGoInstallSpeed speed);
|
||||||
s32 PS4_SYSV_ABI scePlayGoSetLanguageMask(OrbisPlayGoHandle handle,
|
s32 PS4_SYSV_ABI scePlayGoSetLanguageMask(OrbisPlayGoHandle handle,
|
||||||
OrbisPlayGoLanguageMask languageMask);
|
OrbisPlayGoLanguageMask languageMask);
|
||||||
s32 PS4_SYSV_ABI scePlayGoSetToDoList(OrbisPlayGoHandle handle, const OrbisPlayGoToDo* todoList,
|
s32 PS4_SYSV_ABI scePlayGoSetToDoList(OrbisPlayGoHandle handle, const OrbisPlayGoToDo* todoList,
|
||||||
|
|
|
@ -91,8 +91,11 @@ void Emulator::Run(const std::filesystem::path& file) {
|
||||||
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);
|
LOG_INFO(Loader, "Fw: {:#x} App Version: {}", fw_version, app_version);
|
||||||
} else if (entry.path().filename() == "playgo-chunk.dat") {
|
} else if (entry.path().filename() == "playgo-chunk.dat") {
|
||||||
auto* playgo = Common::Singleton<PlaygoChunk>::Instance();
|
auto* playgo = Common::Singleton<PlaygoFile>::Instance();
|
||||||
playgo->Open(sce_sys_folder.string() + "/playgo-chunk.dat");
|
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" ||
|
} else if (entry.path().filename() == "pic0.png" ||
|
||||||
entry.path().filename() == "pic1.png") {
|
entry.path().filename() == "pic1.png") {
|
||||||
auto* splash = Common::Singleton<Splash>::Instance();
|
auto* splash = Common::Singleton<Splash>::Instance();
|
||||||
|
|
Loading…
Reference in a new issue