mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-18 23:07:07 -05:00
fix(libScePlayGo): let users answer unlisted chunks
This commit is contained in:
1 parent
d92a8dad39
commit
e088fd8741
3 files changed
+76
-3
No files matched your search
@@ -2,6 +2,7 @@
|
||||
#include <cstddef>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
@@ -86,11 +87,30 @@ static const ChunkTable& Chunks() {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
enum class UnlistedChunkAnswer { Stop, Installed, Absent };
|
||||
|
||||
static UnlistedChunkAnswer UnlistedChunks() {
|
||||
static const UnlistedChunkAnswer answer = [] {
|
||||
const char* text = std::getenv("APS5_PLAYGO_UNLISTED_CHUNKS");
|
||||
if (text == nullptr || text[0] == '\0') return UnlistedChunkAnswer::Stop;
|
||||
const std::string value(text);
|
||||
if (value == "installed") return UnlistedChunkAnswer::Installed;
|
||||
if (value == "absent") return UnlistedChunkAnswer::Absent;
|
||||
throw std::runtime_error("scePlayGo: APS5_PLAYGO_UNLISTED_CHUNKS must be installed or absent, not \"" + value + "\"");
|
||||
}();
|
||||
return answer;
|
||||
}
|
||||
|
||||
static bool IsKnownChunk(uint16_t id) {
|
||||
const auto& chunks = Chunks();
|
||||
if (chunks.defined) return chunks.ids.contains(id);
|
||||
if (chunks.scenario || id == 0) return true;
|
||||
throw std::runtime_error("scePlayGo: sce_sys/playgo-chunk.dat and sce_sys/playgo-scenario.json are missing, so chunk ID " + std::to_string(id) + " cannot be checked");
|
||||
switch (UnlistedChunks()) {
|
||||
case UnlistedChunkAnswer::Installed: return true;
|
||||
case UnlistedChunkAnswer::Absent: return false;
|
||||
case UnlistedChunkAnswer::Stop: break;
|
||||
}
|
||||
throw std::runtime_error("scePlayGo: sce_sys/playgo-chunk.dat and sce_sys/playgo-scenario.json are missing, so chunk ID " + std::to_string(id) + " cannot be checked; set APS5_PLAYGO_UNLISTED_CHUNKS=installed or =absent to answer for this dump");
|
||||
}
|
||||
|
||||
static int ValidateChunks(const uint16_t* chunk_ids, uint32_t number_of_entries) {
|
||||
|
||||
@@ -35,7 +35,8 @@ static void RequireMissingChunkMetadata(Operation&& operation) {
|
||||
const std::string_view message(error.what());
|
||||
threw = message.find("playgo-chunk.dat") != std::string_view::npos &&
|
||||
message.find("playgo-scenario.json") != std::string_view::npos &&
|
||||
message.find("chunk ID") != std::string_view::npos;
|
||||
message.find("chunk ID") != std::string_view::npos &&
|
||||
message.find("APS5_PLAYGO_UNLISTED_CHUNKS") != std::string_view::npos;
|
||||
}
|
||||
Require(threw);
|
||||
}
|
||||
@@ -149,6 +150,52 @@ static int CheckRejectedLayout(const char* root, const char* fileName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SetUnlistedChunks(const char* value) {
|
||||
#ifdef _WIN32
|
||||
Require(_putenv_s("APS5_PLAYGO_UNLISTED_CHUNKS", value) == 0);
|
||||
#else
|
||||
Require(setenv("APS5_PLAYGO_UNLISTED_CHUNKS", value, 1) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int CheckNoPlayGoFileAnswered(const char* root, const char* answer) {
|
||||
constexpr int badChunkId = static_cast<int>(0x80B2000C);
|
||||
SetUnlistedChunks(answer);
|
||||
std::filesystem::current_path(root);
|
||||
PlayGoInitParams init{};
|
||||
int handle = 0;
|
||||
Require(scePlayGoInitialize(&init) == 0);
|
||||
Require(scePlayGoOpen(&handle, nullptr) == 0);
|
||||
const std::uint16_t unlisted[3] = {0, 1, 999};
|
||||
std::int8_t loci[3] = {0, 0, 0};
|
||||
const int result = scePlayGoGetLocus(handle, unlisted, 3, loci);
|
||||
if (std::string_view(answer) == "installed") Require(result == 0 && loci[0] == 3 && loci[1] == 3 && loci[2] == 3);
|
||||
else Require(result == badChunkId);
|
||||
const std::uint16_t first = 0;
|
||||
Require(scePlayGoGetLocus(handle, &first, 1, loci) == 0 && loci[0] == 3);
|
||||
Require(scePlayGoClose(handle) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CheckUnknownUnlistedChunkAnswer(const char* root) {
|
||||
SetUnlistedChunks("maybe");
|
||||
std::filesystem::current_path(root);
|
||||
PlayGoInitParams init{};
|
||||
int handle = 0;
|
||||
Require(scePlayGoInitialize(&init) == 0);
|
||||
Require(scePlayGoOpen(&handle, nullptr) == 0);
|
||||
const std::uint16_t unlisted = 1;
|
||||
std::int8_t locus = 0;
|
||||
bool threw = false;
|
||||
try {
|
||||
scePlayGoGetLocus(handle, &unlisted, 1, &locus);
|
||||
} catch (const std::runtime_error& error) {
|
||||
threw = std::string_view(error.what()).find("APS5_PLAYGO_UNLISTED_CHUNKS must be installed or absent") != std::string_view::npos;
|
||||
}
|
||||
Require(threw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void RunLayout(const char* self, const char* mode, std::initializer_list<std::pair<const char*, std::string>> files) {
|
||||
const auto root = std::filesystem::temp_directory_path() / ("guest_playgo_" + std::to_string(std::random_device{}()));
|
||||
std::filesystem::remove_all(root);
|
||||
@@ -176,6 +223,9 @@ int main(int argc, char** argv) {
|
||||
if (argc == 3) {
|
||||
const std::string_view mode = argv[1];
|
||||
if (mode == "--no-file") return CheckNoPlayGoFile(argv[2]);
|
||||
if (mode == "--no-file-installed") return CheckNoPlayGoFileAnswered(argv[2], "installed");
|
||||
if (mode == "--no-file-absent") return CheckNoPlayGoFileAnswered(argv[2], "absent");
|
||||
if (mode == "--no-file-unknown-answer") return CheckUnknownUnlistedChunkAnswer(argv[2]);
|
||||
if (mode == "--package-chunk-table" || mode == "--scenario-with-chunk-table") return CheckPackageChunkTable(argv[2]);
|
||||
if (mode == "--scenario-only") return CheckScenarioWithoutChunkTable(argv[2]);
|
||||
if (mode == "--ficm-only") return CheckRejectedLayout(argv[2], "playgo-ficm.dat");
|
||||
@@ -183,6 +233,9 @@ int main(int argc, char** argv) {
|
||||
if (mode == "--invalid-chunk-table") return CheckRejectedLayout(argv[2], "playgo-chunk.dat");
|
||||
}
|
||||
RunLayout(argv[0], "--no-file", {});
|
||||
RunLayout(argv[0], "--no-file-installed", {});
|
||||
RunLayout(argv[0], "--no-file-absent", {});
|
||||
RunLayout(argv[0], "--no-file-unknown-answer", {});
|
||||
RunLayout(argv[0], "--package-chunk-table", {{"playgo-chunk.dat", ChunkTableFile()}});
|
||||
RunLayout(argv[0], "--scenario-with-chunk-table", {{"playgo-chunk.dat", ChunkTableFile()}, {"playgo-scenario.json", "{}"}});
|
||||
RunLayout(argv[0], "--scenario-only", {{"playgo-scenario.json", "{}"}});
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
### Unknown function info
|
||||
|
||||
- [libScePlayGo](../../../core/libs/prx/libScePlayGo/Export.cpp) - the chunk set comes from `playgo-chunkdefs.xml` (every listed chunk plus chunks 0 through the default chunk), otherwise from `sce_sys/playgo-chunk.dat`, whose `plgx` header is read as holding the chunk count as a 16-bit value at offset 0x0A and ids 0 to count - 1 are taken as valid. The field was identified on four dumps, where exactly that many 0x20-byte entries follow from offset 0x100 (RIDE 4 PPSA01599: 35, Persona 5 Royal PPSA05110: 25, LEGO Horizon Adventures PPSA14632 and Kena PPSA01802: 1); the rest of the format is not decoded and ids are assumed to be contiguous. Every listed chunk is reported as installed (`LOCAL_FAST`). Without either file, a package with `sce_sys/playgo-scenario.json` (PPSA01748, whose dump lists no chunks) accepts every chunk id as installed while `scePlayGoGetChunkId` lists only chunk 0. A package with no `playgo-*` file in `sce_sys` (PPSA03001, PPSA03490 and PPSA01285 here) accepts chunk 0; querying any other id throws with a message naming the missing `playgo-chunk.dat` and `playgo-scenario.json`, since the incomplete dump cannot establish whether that id exists. A `sce_sys` that holds other `playgo-*` files (`playgo-ficm.dat`, `playgo-hash-table.dat`) without `playgo-chunk.dat` or `playgo-scenario.json`, or a `playgo-chunk.dat` without a `plgx` header and a nonzero count, throws naming the file, because no such dump is known. These answers are unverified on a console, as is the console's answer for an id outside a package's chunk table.
|
||||
- [libScePlayGo](../../../core/libs/prx/libScePlayGo/Export.cpp) - the chunk set comes from `playgo-chunkdefs.xml` (every listed chunk plus chunks 0 through the default chunk), otherwise from `sce_sys/playgo-chunk.dat`, whose `plgx` header is read as holding the chunk count as a 16-bit value at offset 0x0A and ids 0 to count - 1 are taken as valid. The field was identified on four dumps, where exactly that many 0x20-byte entries follow from offset 0x100 (RIDE 4 PPSA01599: 35, Persona 5 Royal PPSA05110: 25, LEGO Horizon Adventures PPSA14632 and Kena PPSA01802: 1); the rest of the format is not decoded and ids are assumed to be contiguous. Every listed chunk is reported as installed (`LOCAL_FAST`). Without either file, a package with `sce_sys/playgo-scenario.json` (PPSA01748, whose dump lists no chunks) accepts every chunk id as installed while `scePlayGoGetChunkId` lists only chunk 0. A package with no `playgo-*` file in `sce_sys` (PPSA03001, PPSA03490 and PPSA01285 here) accepts chunk 0; querying any other id throws with a message naming the missing `playgo-chunk.dat` and `playgo-scenario.json`, since the incomplete dump cannot establish whether that id exists; `APS5_PLAYGO_UNLISTED_CHUNKS=installed` answers every such id as installed (`LOCAL_FAST`, which PPSA15388 needs to load its saves) and `=absent` answers `SCE_PLAYGO_ERROR_BAD_CHUNK_ID` (which ends PPSA03001's id walk), as the user's choice for that dump. A `sce_sys` that holds other `playgo-*` files (`playgo-ficm.dat`, `playgo-hash-table.dat`) without `playgo-chunk.dat` or `playgo-scenario.json`, or a `playgo-chunk.dat` without a `plgx` header and a nonzero count, throws naming the file, because no such dump is known. These answers are unverified on a console, as is the console's answer for an id outside a package's chunk table.
|
||||
- [libScePlayGo](../../../core/libs/prx/libScePlayGo/Export.cpp) - `scePlayGoGetSupportedOptionalChunk` and `scePlayGoGetOptionalChunk` report every bit set for any `type`, i.e. every optional chunk (language pack) supported and installed, like `scePlayGoGetLanguageMask`. The bit layout and the values of `type` are not known; PPSA01748 calls both with type 0 and hides every text language listed in `playgo-scenario.json` `chunkSupportedLanguages` when the bitmask is 0. The console's answer for a package that ships no optional chunks is unverified.
|
||||
Reference in new issue
Block a user