mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
RetroAchievements CSO support, delay until identified (#17699)
* Support CSO (and any future block based formats) for RetroAchievements identification * Avoid auto-loading savestates in challenge mode
This commit is contained in:
1 parent
6c49af73c7
commit
431a0551b2
4 files changed
+92
-20
No files matched your search
@@ -31,6 +31,8 @@
|
||||
#include "Common/Log.h"
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Core/FileLoaders/LocalFileLoader.h"
|
||||
#include "Core/FileSystems/BlockDevices.h"
|
||||
#include "Common/Net/HTTPClient.h"
|
||||
#include "Common/System/OSD.h"
|
||||
#include "Common/System/System.h"
|
||||
@@ -502,6 +504,8 @@ void DoState(PointerWrap &p) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DoArray(p, buffer, data_size);
|
||||
@@ -516,6 +520,8 @@ void DoState(PointerWrap &p) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
delete[] buffer;
|
||||
} else {
|
||||
@@ -605,22 +611,72 @@ void identify_and_load_callback(int result, const char *error_message, rc_client
|
||||
g_isIdentifying = false;
|
||||
}
|
||||
|
||||
void SetGame(const Path &path) {
|
||||
struct FileContext {
|
||||
BlockDevice *bd;
|
||||
int64_t seekPos;
|
||||
};
|
||||
|
||||
static BlockDevice *g_blockDevice;
|
||||
|
||||
void SetGame(const Path &path, FileLoader *fileLoader) {
|
||||
if (!g_rcClient || !IsLoggedIn()) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Fish the block device out of the loading process somewhere else. Though, probably easier to just do it here.
|
||||
g_blockDevice = constructBlockDevice(fileLoader);
|
||||
if (!g_blockDevice) {
|
||||
ERROR_LOG(ACHIEVEMENTS, "Failed to construct block device for '%s' - can't identify", path.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
rc_hash_filereader rc_filereader;
|
||||
rc_filereader.open = [](const char *utf8Path) {
|
||||
Path path(utf8Path);
|
||||
FILE *f = File::OpenCFile(path, "rb");
|
||||
return (void *)f;
|
||||
return (void *) new FileContext{ g_blockDevice, 0 };
|
||||
};
|
||||
rc_filereader.seek = [](void *file_handle, int64_t offset, int origin) {
|
||||
FileContext *ctx = (FileContext *)file_handle;
|
||||
switch (origin) {
|
||||
case SEEK_SET: ctx->seekPos = offset; break;
|
||||
case SEEK_END: ctx->seekPos = ctx->bd->GetBlockSize() * ctx->bd->GetNumBlocks() + offset; break;
|
||||
case SEEK_CUR: ctx->seekPos += offset; break;
|
||||
default: break;
|
||||
}
|
||||
};
|
||||
rc_filereader.tell = [](void *file_handle) -> int64_t {
|
||||
return ((FileContext *)file_handle)->seekPos;
|
||||
};
|
||||
rc_filereader.read = [](void *file_handle, void *buffer, size_t requested_bytes) -> size_t {
|
||||
FileContext *ctx = (FileContext *)file_handle;
|
||||
|
||||
int blockSize = ctx->bd->GetBlockSize();
|
||||
|
||||
int64_t offset = ctx->seekPos;
|
||||
int64_t endOffset = ctx->seekPos + requested_bytes;
|
||||
int firstBlock = offset / blockSize;
|
||||
int afterLastBlock = (endOffset + blockSize - 1) / blockSize;
|
||||
int numBlocks = afterLastBlock - firstBlock;
|
||||
// This is suboptimal, but good enough since we're not doing a lot of accesses.
|
||||
uint8_t *buf = new uint8_t[numBlocks * blockSize];
|
||||
bool success = ctx->bd->ReadBlocks(firstBlock, numBlocks, (u8 *)buf);
|
||||
if (success) {
|
||||
int64_t firstOffset = firstBlock * blockSize;
|
||||
memcpy(buffer, buf + (offset - firstOffset), requested_bytes);
|
||||
ctx->seekPos += requested_bytes;
|
||||
delete[] buf;
|
||||
return requested_bytes;
|
||||
} else {
|
||||
delete[] buf;
|
||||
ERROR_LOG(ACHIEVEMENTS, "Block device load fail");
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
rc_filereader.close = [](void *file_handle) {
|
||||
FileContext *ctx = (FileContext *)file_handle;
|
||||
delete ctx->bd;
|
||||
delete ctx;
|
||||
};
|
||||
rc_filereader.seek = [](void *file_handle, int64_t offset, int origin) { fseek((FILE *)file_handle, offset, origin); };
|
||||
rc_filereader.tell = [](void *file_handle) -> int64_t { return (int64_t)ftell((FILE *)file_handle); };
|
||||
rc_filereader.read = [](void *file_handle, void *buffer, size_t requested_bytes) -> size_t { return fread(buffer, 1, requested_bytes, (FILE *)file_handle); };
|
||||
rc_filereader.close = [](void *file_handle) { fclose((FILE *)file_handle); };
|
||||
|
||||
// The caller should hold off on executing game code until this turns false, checking with IsBlockingExecution()
|
||||
g_isIdentifying = true;
|
||||
@@ -633,6 +689,9 @@ void SetGame(const Path &path) {
|
||||
rc_hash_init_custom_filereader(&rc_filereader);
|
||||
rc_hash_init_default_cdreader();
|
||||
rc_client_begin_identify_and_load_game(g_rcClient, RC_CONSOLE_PSP, path.c_str(), nullptr, 0, &identify_and_load_callback, nullptr);
|
||||
|
||||
// fclose above will have deleted it.
|
||||
g_blockDevice = nullptr;
|
||||
}
|
||||
|
||||
void UnloadGame() {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
class Path;
|
||||
class PointerWrap;
|
||||
class FileLoader;
|
||||
|
||||
namespace Achievements {
|
||||
|
||||
@@ -98,7 +99,7 @@ bool HasAchievementsOrLeaderboards();
|
||||
bool LoginAsync(const char *username, const char *password);
|
||||
void Logout();
|
||||
|
||||
void SetGame(const Path &path);
|
||||
void SetGame(const Path &path, FileLoader *fileLoader);
|
||||
void ChangeUMD(const Path &path); // for in-game UMD change
|
||||
void UnloadGame(); // Call when leaving a game.
|
||||
|
||||
|
||||
+19
-8
@@ -43,6 +43,7 @@
|
||||
#include "Common/TimeUtil.h"
|
||||
#include "Common/GraphicsContext.h"
|
||||
|
||||
#include "Core/RetroAchievements.h"
|
||||
#include "Core/MemFault.h"
|
||||
#include "Core/HDRemaster.h"
|
||||
#include "Core/MIPS/MIPS.h"
|
||||
@@ -72,6 +73,7 @@
|
||||
#include "GPU/GPUState.h"
|
||||
#include "GPU/GPUInterface.h"
|
||||
#include "GPU/Debugger/RecordFormat.h"
|
||||
#include "Core/RetroAchievements.h"
|
||||
|
||||
enum CPUThreadState {
|
||||
CPU_THREAD_NOT_RUNNING,
|
||||
@@ -234,7 +236,7 @@ bool DiscIDFromGEDumpPath(const Path &path, FileLoader *fileLoader, std::string
|
||||
}
|
||||
}
|
||||
|
||||
bool CPU_Init(std::string *errorString) {
|
||||
bool CPU_Init(std::string *errorString, FileLoader *loadedFile) {
|
||||
coreState = CORE_POWERUP;
|
||||
currentMIPS = &mipsr4k;
|
||||
|
||||
@@ -249,12 +251,6 @@ bool CPU_Init(std::string *errorString) {
|
||||
Memory::g_PSPModel = g_Config.iPSPModel;
|
||||
|
||||
Path filename = g_CoreParameter.fileToStart;
|
||||
loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename));
|
||||
#if PPSSPP_ARCH(AMD64)
|
||||
if (g_Config.bCacheFullIsoInRam) {
|
||||
loadedFile = new RamCachingFileLoader(loadedFile);
|
||||
}
|
||||
#endif
|
||||
|
||||
IdentifiedFileType type = Identify_File(loadedFile, errorString);
|
||||
|
||||
@@ -440,7 +436,17 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) {
|
||||
pspIsIniting = true;
|
||||
PSP_SetLoading("Loading game...");
|
||||
|
||||
if (!CPU_Init(&g_CoreParameter.errorString)) {
|
||||
Path filename = g_CoreParameter.fileToStart;
|
||||
FileLoader *loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename));
|
||||
#if PPSSPP_ARCH(AMD64)
|
||||
if (g_Config.bCacheFullIsoInRam) {
|
||||
loadedFile = new RamCachingFileLoader(loadedFile);
|
||||
}
|
||||
#endif
|
||||
|
||||
Achievements::SetGame(filename, loadedFile);
|
||||
|
||||
if (!CPU_Init(&g_CoreParameter.errorString, loadedFile)) {
|
||||
*error_string = g_CoreParameter.errorString;
|
||||
if (error_string->empty()) {
|
||||
*error_string = "Failed initializing CPU/Memory";
|
||||
@@ -467,6 +473,11 @@ bool PSP_InitStart(const CoreParameter &coreParam, std::string *error_string) {
|
||||
}
|
||||
|
||||
bool PSP_InitUpdate(std::string *error_string) {
|
||||
if (Achievements::IsBlockingExecution()) {
|
||||
// Keep waiting.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pspIsInited || !pspIsIniting) {
|
||||
return true;
|
||||
}
|
||||
|
||||
+4
-3
@@ -246,6 +246,7 @@ void EmuScreen::bootGame(const Path &filename) {
|
||||
if (PSP_IsIniting()) {
|
||||
std::string error_string;
|
||||
bootPending_ = !PSP_InitUpdate(&error_string);
|
||||
|
||||
if (!bootPending_) {
|
||||
invalid_ = !PSP_IsInited();
|
||||
if (invalid_) {
|
||||
@@ -349,8 +350,6 @@ void EmuScreen::bootGame(const Path &filename) {
|
||||
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("DefaultCPUClockRequired", "Warning: This game requires the CPU clock to be set to default."), 10.0f);
|
||||
}
|
||||
|
||||
Achievements::SetGame(filename);
|
||||
|
||||
loadingViewColor_->Divert(0xFFFFFFFF, 0.75f);
|
||||
loadingViewVisible_->Divert(UI::V_VISIBLE, 0.75f);
|
||||
|
||||
@@ -363,7 +362,9 @@ void EmuScreen::bootComplete() {
|
||||
System_Notify(SystemNotification::DISASSEMBLY);
|
||||
|
||||
NOTICE_LOG(BOOT, "Loading %s...", PSP_CoreParameter().fileToStart.c_str());
|
||||
autoLoad();
|
||||
if (!Achievements::ChallengeModeActive()) {
|
||||
autoLoad();
|
||||
}
|
||||
|
||||
auto sc = GetI18NCategory(I18NCat::SCREEN);
|
||||
|
||||
|
||||
Reference in new issue
Block a user