mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-22 11:25:02 +00:00
PlayGo: basic implementation, credits to red-prig
This commit is contained in:
parent
138c9ce787
commit
516a3e7104
5 changed files with 446 additions and 54 deletions
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue