RetroAchievement - only register the file reader once

This commit is contained in:
Henrik Rydgård committed 2023-09-12 14:02:12 +02:00
1 parent a44efae67e
commit 95badd03b4
1 file changed
+60 -61
+60 -61
View File
@@ -86,6 +86,12 @@ static rc_client_t *g_rcClient;
static const std::string g_RAImageID = "I_RETROACHIEVEMENTS_LOGO";
constexpr double LOGIN_ATTEMPT_INTERVAL_S = 10.0;
struct FileContext {
BlockDevice *bd;
int64_t seekPos;
};
static BlockDevice *g_blockDevice;
#define PSP_MEMORY_OFFSET 0x08000000
static void TryLoginByToken(bool isInitialAttempt);
@@ -411,6 +417,60 @@ void Initialize() {
rc_client_set_event_handler(g_rcClient, event_handler_callback);
rc_hash_filereader rc_filereader;
rc_filereader.open = [](const char *utf8Path) -> void *{
if (!g_blockDevice) {
ERROR_LOG(ACHIEVEMENTS, "No block device");
return nullptr;
}
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_hash_init_custom_filereader(&rc_filereader);
rc_hash_init_default_cdreader();
TryLoginByToken(true);
}
@@ -723,13 +783,6 @@ void identify_and_load_callback(int result, const char *error_message, rc_client
g_isIdentifying = false;
}
struct FileContext {
BlockDevice *bd;
int64_t seekPos;
};
static BlockDevice *g_blockDevice;
bool IsReadyToStart() {
return !g_isLoggingIn;
}
@@ -770,58 +823,6 @@ void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoad
return;
}
rc_hash_filereader rc_filereader;
rc_filereader.open = [](const char *utf8Path) -> void * {
if (!g_blockDevice) {
ERROR_LOG(ACHIEVEMENTS, "No block device");
return nullptr;
}
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;
};
// The caller should hold off on executing game code until this turns false, checking with IsBlockingExecution()
g_isIdentifying = true;
@@ -830,8 +831,6 @@ void SetGame(const Path &path, IdentifiedFileType fileType, FileLoader *fileLoad
rc_client_set_encore_mode_enabled(g_rcClient, g_Config.bAchievementsEncoreMode ? 1 : 0);
rc_client_set_unofficial_enabled(g_rcClient, g_Config.bAchievementsUnofficial ? 1 : 0);
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.