mirror of
https://github.com/gopher64/gopher64.git
synced 2026-07-11 01:25:20 +02:00
More RA code (#733)
* implement RC_CLIENT_EVENT_SERVER_ERROR * handle more * more * more * more * more * more * more * more * more * more
This commit is contained in:
@@ -159,6 +159,7 @@ fn main() {
|
||||
let retroachievements_bindings = bindgen::Builder::default()
|
||||
.header("retroachievements/retroachievements.h")
|
||||
.allowlist_function("ra_init_client")
|
||||
.allowlist_function("ra_welcome")
|
||||
.allowlist_function("ra_shutdown_client")
|
||||
.allowlist_function("ra_get_hardcore")
|
||||
.allowlist_function("ra_load_game")
|
||||
|
||||
@@ -12,19 +12,23 @@ void rust_server_call(const char *url, const char *post_data,
|
||||
void store_retroachievements_credentials(const char *username,
|
||||
const char *token, void *userdata);
|
||||
|
||||
rc_client_t *g_client = NULL;
|
||||
const uint8_t *g_dmem = NULL;
|
||||
size_t g_dmem_size = 0;
|
||||
bool g_game_loaded = false;
|
||||
bool g_user_logged_in = false;
|
||||
const char *g_username = NULL;
|
||||
const char *g_token = NULL;
|
||||
void notify_load_game(void *userdata);
|
||||
|
||||
static rc_client_t *g_client = NULL;
|
||||
static const uint8_t *g_dmem = NULL;
|
||||
static size_t g_dmem_size = 0;
|
||||
static bool g_game_loaded = false;
|
||||
static bool g_user_logged_in = false;
|
||||
static const char *g_username = NULL;
|
||||
static const char *g_token = NULL;
|
||||
static char load_game_error_message[512];
|
||||
|
||||
static uint32_t read_memory(uint32_t address, uint8_t *buffer,
|
||||
uint32_t num_bytes, rc_client_t *client) {
|
||||
if (address + num_bytes >= g_dmem_size)
|
||||
return 0;
|
||||
memcpy(buffer, &g_dmem[address], num_bytes);
|
||||
memset(buffer, 0, num_bytes);
|
||||
else
|
||||
memcpy(buffer, &g_dmem[address], num_bytes);
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
@@ -109,22 +113,41 @@ void ra_login_token_user(const char *username, const char *token,
|
||||
|
||||
static void load_game_callback(int result, const char *error_message,
|
||||
rc_client_t *client, void *userdata) {
|
||||
char buffer[512];
|
||||
if (result != RC_OK) {
|
||||
snprintf(buffer, sizeof(buffer), "RA load failed: %s", error_message);
|
||||
rdp_onscreen_message(buffer);
|
||||
rdp_onscreen_message(buffer); // show it a bit longer
|
||||
rc_client_set_hardcore_enabled(client, false);
|
||||
snprintf(load_game_error_message, sizeof(load_game_error_message),
|
||||
"RA load failed: %s", error_message);
|
||||
notify_load_game(userdata);
|
||||
return;
|
||||
}
|
||||
|
||||
const rc_client_game_t *game = rc_client_get_game_info(client);
|
||||
rc_client_user_game_summary_t summary;
|
||||
rc_client_get_user_game_summary(client, &summary);
|
||||
if (!rc_client_is_processing_required(client)) {
|
||||
rc_client_set_hardcore_enabled(client, false);
|
||||
}
|
||||
|
||||
int hardcore_enabled = rc_client_get_hardcore_enabled(client);
|
||||
int message_length =
|
||||
snprintf(buffer, sizeof(buffer), "RA loaded: %s\nMode: %s\n", game->title,
|
||||
hardcore_enabled ? "Hardcore" : "Softcore");
|
||||
g_game_loaded = true;
|
||||
notify_load_game(userdata);
|
||||
}
|
||||
|
||||
void ra_welcome() {
|
||||
if (!g_user_logged_in)
|
||||
return;
|
||||
|
||||
if (!g_game_loaded) {
|
||||
rdp_onscreen_message(load_game_error_message);
|
||||
rdp_onscreen_message(load_game_error_message); // show it a bit longer
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[512];
|
||||
|
||||
const rc_client_game_t *game = rc_client_get_game_info(g_client);
|
||||
rc_client_user_game_summary_t summary;
|
||||
rc_client_get_user_game_summary(g_client, &summary);
|
||||
|
||||
int message_length = snprintf(
|
||||
buffer, sizeof(buffer), "RA loaded: %s\nMode: %s\n", game->title,
|
||||
rc_client_get_hardcore_enabled(g_client) ? "Hardcore" : "Softcore");
|
||||
|
||||
if (summary.num_core_achievements != 0) {
|
||||
snprintf(buffer + message_length, sizeof(buffer) - message_length,
|
||||
@@ -136,17 +159,17 @@ static void load_game_callback(int result, const char *error_message,
|
||||
}
|
||||
rdp_onscreen_message(buffer);
|
||||
rdp_onscreen_message(buffer); // show it a bit longer
|
||||
|
||||
g_game_loaded = true;
|
||||
}
|
||||
|
||||
void ra_load_game(const uint8_t *rom, size_t rom_size) {
|
||||
if (!g_user_logged_in)
|
||||
void ra_load_game(const uint8_t *rom, size_t rom_size, void *userdata) {
|
||||
if (!g_user_logged_in) {
|
||||
notify_load_game(userdata);
|
||||
return;
|
||||
}
|
||||
|
||||
rc_client_begin_identify_and_load_game(g_client, RC_CONSOLE_NINTENDO_64, NULL,
|
||||
rom, rom_size, load_game_callback,
|
||||
NULL);
|
||||
userdata);
|
||||
}
|
||||
|
||||
void ra_set_dmem(const uint8_t *dmem, size_t dmem_size) {
|
||||
@@ -189,7 +212,7 @@ static void
|
||||
achievement_progress_updated(const rc_client_achievement_t *achievement) {
|
||||
char buffer[512];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "RA updated: %s: %s", achievement->title,
|
||||
snprintf(buffer, sizeof(buffer), "RA updated: %s - %s", achievement->title,
|
||||
achievement->measured_progress);
|
||||
rdp_onscreen_message(buffer);
|
||||
}
|
||||
@@ -214,6 +237,14 @@ static void subset_completed(const rc_client_subset_t *subset,
|
||||
rdp_onscreen_message(buffer);
|
||||
}
|
||||
|
||||
static void server_error(const rc_client_server_error_t *server_error) {
|
||||
char buffer[512];
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "RA server error: %s",
|
||||
server_error->error_message);
|
||||
rdp_onscreen_message(buffer);
|
||||
}
|
||||
|
||||
static void event_handler(const rc_client_event_t *event, rc_client_t *client) {
|
||||
switch (event->type) {
|
||||
case RC_CLIENT_EVENT_ACHIEVEMENT_TRIGGERED:
|
||||
@@ -253,6 +284,9 @@ static void event_handler(const rc_client_event_t *event, rc_client_t *client) {
|
||||
case RC_CLIENT_EVENT_SUBSET_COMPLETED:
|
||||
subset_completed(event->subset, client);
|
||||
break;
|
||||
case RC_CLIENT_EVENT_SERVER_ERROR:
|
||||
server_error(event->server_error);
|
||||
break;
|
||||
default:
|
||||
printf("RetroAchievements: Unhandled event %d\n", event->type);
|
||||
break;
|
||||
@@ -267,6 +301,7 @@ void ra_init_client(bool hardcore) {
|
||||
g_user_logged_in = false;
|
||||
g_dmem = NULL;
|
||||
g_dmem_size = 0;
|
||||
memset(load_game_error_message, 0, sizeof(load_game_error_message));
|
||||
|
||||
// Provide a logging function to simplify debugging
|
||||
rc_client_enable_logging(g_client, RC_CLIENT_LOG_LEVEL_WARN, log_message);
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
void ra_init_client(bool hardcore);
|
||||
void ra_shutdown_client();
|
||||
void ra_welcome();
|
||||
bool ra_get_hardcore();
|
||||
void ra_load_game(const uint8_t *rom, size_t rom_size);
|
||||
void ra_load_game(const uint8_t *rom, size_t rom_size, void *userdata);
|
||||
void ra_set_dmem(const uint8_t *dmem, size_t dmem_size);
|
||||
void ra_do_frame();
|
||||
void ra_do_idle();
|
||||
|
||||
+4
-4
@@ -44,7 +44,7 @@ pub mod tlb;
|
||||
pub mod unmapped;
|
||||
pub mod vi;
|
||||
|
||||
pub fn run_game(device: &mut Device, rom_contents: Vec<u8>, game_settings: ui::gui::GameSettings) {
|
||||
pub fn run_game(device: &mut Device, rom_contents: &[u8], game_settings: ui::gui::GameSettings) {
|
||||
device.cpu.overclock = game_settings.overclock;
|
||||
if game_settings.disable_expansion_pak {
|
||||
device.rdram.size = 0x400000;
|
||||
@@ -56,7 +56,7 @@ pub fn run_game(device: &mut Device, rom_contents: Vec<u8>, game_settings: ui::g
|
||||
|
||||
init_rng(device);
|
||||
|
||||
cart::rom::init(device, &rom_contents); // cart needs to come before rdram
|
||||
cart::rom::init(device, rom_contents); // cart needs to come before rdram
|
||||
|
||||
// rdram pointer is shared with parallel-rdp and retroachievements
|
||||
rdram::init(device);
|
||||
@@ -65,8 +65,8 @@ pub fn run_game(device: &mut Device, rom_contents: Vec<u8>, game_settings: ui::g
|
||||
ui::audio::init(&mut device.ui, device.ai.freq);
|
||||
ui::input::init(&mut device.ui);
|
||||
|
||||
// shows messages, needs to be after video init
|
||||
retroachievements::load_game(&rom_contents, rom_contents.len());
|
||||
// must be after video init
|
||||
retroachievements::welcome();
|
||||
|
||||
mi::init(device);
|
||||
pif::init(device);
|
||||
|
||||
+2
-1
@@ -199,9 +199,10 @@ async fn main() -> std::io::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
retroachievements::load_game(&rom_contents, rom_contents.len()).await;
|
||||
device::run_game(
|
||||
&mut device,
|
||||
rom_contents,
|
||||
&rom_contents,
|
||||
ui::gui::GameSettings {
|
||||
overclock,
|
||||
disable_expansion_pak,
|
||||
|
||||
@@ -11,6 +11,12 @@ pub struct RAConfig {
|
||||
pub hardcore: bool,
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn notify_load_game(ctx: *mut std::ffi::c_void) {
|
||||
let tx = unsafe { Box::from_raw(ctx as *mut tokio::sync::oneshot::Sender<bool>) };
|
||||
tx.send(true).unwrap();
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn store_retroachievements_credentials(
|
||||
c_username: *const std::ffi::c_char,
|
||||
@@ -231,8 +237,17 @@ pub fn ra_window(app: &ui::gui::AppWindow) {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn load_game(rom: &[u8], rom_size: usize) {
|
||||
unsafe { ra_load_game(rom.as_ptr(), rom_size) };
|
||||
pub async fn load_game(rom: &[u8], rom_size: usize) {
|
||||
let (tx, rx) = tokio::sync::oneshot::channel::<bool>();
|
||||
unsafe {
|
||||
let tx_ptr = Box::into_raw(Box::new(tx)) as *mut std::ffi::c_void;
|
||||
ra_load_game(rom.as_ptr(), rom_size, tx_ptr);
|
||||
};
|
||||
rx.await.unwrap();
|
||||
}
|
||||
|
||||
pub fn welcome() {
|
||||
unsafe { ra_welcome() };
|
||||
}
|
||||
|
||||
pub fn set_dmem(dmem: *const u8, dmem_size: usize) {
|
||||
|
||||
Reference in New Issue
Block a user