mirror of https://github.com/PCSX2/pcsx2.git
3rdparty/rcheevos: Bump to v11.6.0
This commit is contained in:
parent
ac968f9a6a
commit
981fedfdd1
|
@ -220,6 +220,8 @@ typedef struct rc_api_award_achievement_request_t {
|
||||||
uint32_t hardcore;
|
uint32_t hardcore;
|
||||||
/* The hash associated to the game being played */
|
/* The hash associated to the game being played */
|
||||||
const char* game_hash;
|
const char* game_hash;
|
||||||
|
/* The number of seconds since the achievement was unlocked */
|
||||||
|
uint32_t seconds_since_unlock;
|
||||||
}
|
}
|
||||||
rc_api_award_achievement_request_t;
|
rc_api_award_achievement_request_t;
|
||||||
|
|
||||||
|
@ -263,6 +265,8 @@ typedef struct rc_api_submit_lboard_entry_request_t {
|
||||||
int32_t score;
|
int32_t score;
|
||||||
/* The hash associated to the game being played */
|
/* The hash associated to the game being played */
|
||||||
const char* game_hash;
|
const char* game_hash;
|
||||||
|
/* The number of seconds since the leaderboard attempt was completed */
|
||||||
|
uint32_t seconds_since_completion;
|
||||||
}
|
}
|
||||||
rc_api_submit_lboard_entry_request_t;
|
rc_api_submit_lboard_entry_request_t;
|
||||||
|
|
||||||
|
|
|
@ -412,6 +412,8 @@ int rc_api_init_award_achievement_request(rc_api_request_t* request, const rc_ap
|
||||||
rc_url_builder_append_unum_param(&builder, "h", api_params->hardcore ? 1 : 0);
|
rc_url_builder_append_unum_param(&builder, "h", api_params->hardcore ? 1 : 0);
|
||||||
if (api_params->game_hash && *api_params->game_hash)
|
if (api_params->game_hash && *api_params->game_hash)
|
||||||
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
|
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
|
||||||
|
if (api_params->seconds_since_unlock)
|
||||||
|
rc_url_builder_append_unum_param(&builder, "o", api_params->seconds_since_unlock);
|
||||||
|
|
||||||
/* Evaluate the signature. */
|
/* Evaluate the signature. */
|
||||||
md5_init(&md5);
|
md5_init(&md5);
|
||||||
|
@ -420,6 +422,14 @@ int rc_api_init_award_achievement_request(rc_api_request_t* request, const rc_ap
|
||||||
md5_append(&md5, (md5_byte_t*)api_params->username, (int)strlen(api_params->username));
|
md5_append(&md5, (md5_byte_t*)api_params->username, (int)strlen(api_params->username));
|
||||||
snprintf(buffer, sizeof(buffer), "%d", api_params->hardcore ? 1 : 0);
|
snprintf(buffer, sizeof(buffer), "%d", api_params->hardcore ? 1 : 0);
|
||||||
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
||||||
|
if (api_params->seconds_since_unlock) {
|
||||||
|
/* second achievement id is needed by delegated unlock. including it here allows overloading
|
||||||
|
* the hash generating code on the server */
|
||||||
|
snprintf(buffer, sizeof(buffer), "%u", api_params->achievement_id);
|
||||||
|
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
||||||
|
snprintf(buffer, sizeof(buffer), "%u", api_params->seconds_since_unlock);
|
||||||
|
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
||||||
|
}
|
||||||
md5_finish(&md5, digest);
|
md5_finish(&md5, digest);
|
||||||
rc_format_md5(buffer, digest);
|
rc_format_md5(buffer, digest);
|
||||||
rc_url_builder_append_str_param(&builder, "v", buffer);
|
rc_url_builder_append_str_param(&builder, "v", buffer);
|
||||||
|
@ -505,6 +515,9 @@ int rc_api_init_submit_lboard_entry_request(rc_api_request_t* request, const rc_
|
||||||
if (api_params->game_hash && *api_params->game_hash)
|
if (api_params->game_hash && *api_params->game_hash)
|
||||||
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
|
rc_url_builder_append_str_param(&builder, "m", api_params->game_hash);
|
||||||
|
|
||||||
|
if (api_params->seconds_since_completion)
|
||||||
|
rc_url_builder_append_unum_param(&builder, "o", api_params->seconds_since_completion);
|
||||||
|
|
||||||
/* Evaluate the signature. */
|
/* Evaluate the signature. */
|
||||||
md5_init(&md5);
|
md5_init(&md5);
|
||||||
snprintf(buffer, sizeof(buffer), "%u", api_params->leaderboard_id);
|
snprintf(buffer, sizeof(buffer), "%u", api_params->leaderboard_id);
|
||||||
|
@ -512,6 +525,10 @@ int rc_api_init_submit_lboard_entry_request(rc_api_request_t* request, const rc_
|
||||||
md5_append(&md5, (md5_byte_t*)api_params->username, (int)strlen(api_params->username));
|
md5_append(&md5, (md5_byte_t*)api_params->username, (int)strlen(api_params->username));
|
||||||
snprintf(buffer, sizeof(buffer), "%d", api_params->score);
|
snprintf(buffer, sizeof(buffer), "%d", api_params->score);
|
||||||
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
||||||
|
if (api_params->seconds_since_completion) {
|
||||||
|
snprintf(buffer, sizeof(buffer), "%u", api_params->seconds_since_completion);
|
||||||
|
md5_append(&md5, (md5_byte_t*)buffer, (int)strlen(buffer));
|
||||||
|
}
|
||||||
md5_finish(&md5, digest);
|
md5_finish(&md5, digest);
|
||||||
rc_format_md5(buffer, digest);
|
rc_format_md5(buffer, digest);
|
||||||
rc_url_builder_append_str_param(&builder, "v", buffer);
|
rc_url_builder_append_str_param(&builder, "v", buffer);
|
||||||
|
|
|
@ -578,13 +578,7 @@ static int rc_client_get_image_url(char buffer[], size_t buffer_size, int image_
|
||||||
image_request.image_name = image_name;
|
image_request.image_name = image_name;
|
||||||
result = rc_api_init_fetch_image_request(&request, &image_request);
|
result = rc_api_init_fetch_image_request(&request, &image_request);
|
||||||
if (result == RC_OK)
|
if (result == RC_OK)
|
||||||
{
|
snprintf(buffer, buffer_size, "%s", request.url);
|
||||||
const size_t url_length = strlen(request.url);
|
|
||||||
if (url_length >= buffer_size)
|
|
||||||
result = RC_INSUFFICIENT_BUFFER;
|
|
||||||
else
|
|
||||||
memcpy(buffer, request.url, url_length + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
rc_api_destroy_request(&request);
|
rc_api_destroy_request(&request);
|
||||||
return result;
|
return result;
|
||||||
|
@ -1440,7 +1434,6 @@ static void rc_client_activate_game(rc_client_load_state_t* load_state, rc_api_s
|
||||||
rc_mutex_lock(&client->state.mutex);
|
rc_mutex_lock(&client->state.mutex);
|
||||||
load_state->progress = (client->state.load == load_state) ?
|
load_state->progress = (client->state.load == load_state) ?
|
||||||
RC_CLIENT_LOAD_GAME_STATE_DONE : RC_CLIENT_LOAD_GAME_STATE_ABORTED;
|
RC_CLIENT_LOAD_GAME_STATE_DONE : RC_CLIENT_LOAD_GAME_STATE_ABORTED;
|
||||||
client->state.load = NULL;
|
|
||||||
rc_mutex_unlock(&client->state.mutex);
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
|
||||||
if (load_state->progress != RC_CLIENT_LOAD_GAME_STATE_DONE) {
|
if (load_state->progress != RC_CLIENT_LOAD_GAME_STATE_DONE) {
|
||||||
|
@ -1461,17 +1454,15 @@ static void rc_client_activate_game(rc_client_load_state_t* load_state, rc_api_s
|
||||||
start_session_response->num_unlocks, RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE);
|
start_session_response->num_unlocks, RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* make the loaded game active if another game is not aleady being loaded. */
|
||||||
rc_mutex_lock(&client->state.mutex);
|
rc_mutex_lock(&client->state.mutex);
|
||||||
if (client->state.load == NULL)
|
if (client->state.load == load_state)
|
||||||
client->game = load_state->game;
|
client->game = load_state->game;
|
||||||
|
else
|
||||||
|
load_state->progress = RC_CLIENT_LOAD_GAME_STATE_ABORTED;
|
||||||
rc_mutex_unlock(&client->state.mutex);
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
|
||||||
if (client->game != load_state->game) {
|
if (load_state->progress != RC_CLIENT_LOAD_GAME_STATE_ABORTED) {
|
||||||
/* previous load state was aborted */
|
|
||||||
if (load_state->callback)
|
|
||||||
load_state->callback(RC_ABORTED, "The requested game is no longer active", client, load_state->callback_userdata);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* if a change media request is pending, kick it off */
|
/* if a change media request is pending, kick it off */
|
||||||
rc_client_pending_media_t* pending_media;
|
rc_client_pending_media_t* pending_media;
|
||||||
|
|
||||||
|
@ -1481,6 +1472,9 @@ static void rc_client_activate_game(rc_client_load_state_t* load_state, rc_api_s
|
||||||
rc_mutex_unlock(&load_state->client->state.mutex);
|
rc_mutex_unlock(&load_state->client->state.mutex);
|
||||||
|
|
||||||
if (pending_media) {
|
if (pending_media) {
|
||||||
|
/* rc_client_check_pending_media will fail if it can't find the game in client->game or
|
||||||
|
* client->state.load->game. since we've detached the load_state, this has to occur after
|
||||||
|
* we've made the game active. */
|
||||||
if (pending_media->hash) {
|
if (pending_media->hash) {
|
||||||
rc_client_begin_change_media_from_hash(client, pending_media->hash,
|
rc_client_begin_change_media_from_hash(client, pending_media->hash,
|
||||||
pending_media->callback, pending_media->callback_userdata);
|
pending_media->callback, pending_media->callback_userdata);
|
||||||
|
@ -1494,12 +1488,50 @@ static void rc_client_activate_game(rc_client_load_state_t* load_state, rc_api_s
|
||||||
rc_client_free_pending_media(pending_media);
|
rc_client_free_pending_media(pending_media);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* client->game must be set before calling this function so it can query the console_id */
|
rc_mutex_lock(&client->state.mutex);
|
||||||
|
if (client->state.load != load_state)
|
||||||
|
load_state->progress = RC_CLIENT_LOAD_GAME_STATE_ABORTED;
|
||||||
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the game is still being loaded, make sure all the required memory addresses are accessible
|
||||||
|
* so we can mark achievements as unsupported before loading them into the runtime. */
|
||||||
|
if (load_state->progress != RC_CLIENT_LOAD_GAME_STATE_ABORTED) {
|
||||||
|
/* TODO: it is desirable to not do memory reads from a background thread. Some emulators (like Dolphin) don't
|
||||||
|
* allow it. Dolphin's solution is to use a dummy read function that says all addresses are valid and
|
||||||
|
* switches to the actual read function after the callback is called. latter invalid reads will
|
||||||
|
* mark achievements as unsupported. */
|
||||||
|
|
||||||
|
/* ASSERT: client->game must be set before calling this function so the read_memory callback can query the console_id */
|
||||||
rc_client_validate_addresses(load_state->game, client);
|
rc_client_validate_addresses(load_state->game, client);
|
||||||
|
|
||||||
|
rc_mutex_lock(&client->state.mutex);
|
||||||
|
if (client->state.load != load_state)
|
||||||
|
load_state->progress = RC_CLIENT_LOAD_GAME_STATE_ABORTED;
|
||||||
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the game is still being loaded, load any active acheivements/leaderboards into the runtime */
|
||||||
|
if (load_state->progress != RC_CLIENT_LOAD_GAME_STATE_ABORTED) {
|
||||||
rc_client_activate_achievements(load_state->game, client);
|
rc_client_activate_achievements(load_state->game, client);
|
||||||
rc_client_activate_leaderboards(load_state->game, client);
|
rc_client_activate_leaderboards(load_state->game, client);
|
||||||
|
|
||||||
|
/* detach the load state to indicate that loading is fully complete */
|
||||||
|
rc_mutex_lock(&client->state.mutex);
|
||||||
|
if (client->state.load == load_state)
|
||||||
|
client->state.load = NULL;
|
||||||
|
else
|
||||||
|
load_state->progress = RC_CLIENT_LOAD_GAME_STATE_ABORTED;
|
||||||
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* one last sanity check to make sure the game is still being loaded. */
|
||||||
|
if (load_state->progress == RC_CLIENT_LOAD_GAME_STATE_ABORTED) {
|
||||||
|
/* game has been unloaded, or another game is being loaded over the top of this game */
|
||||||
|
if (load_state->callback)
|
||||||
|
load_state->callback(RC_ABORTED, "The requested game is no longer active", client, load_state->callback_userdata);
|
||||||
|
}
|
||||||
|
else {
|
||||||
if (load_state->hash->hash[0] != '[') {
|
if (load_state->hash->hash[0] != '[') {
|
||||||
if (load_state->client->state.spectator_mode != RC_CLIENT_SPECTATOR_MODE_LOCKED) {
|
if (load_state->client->state.spectator_mode != RC_CLIENT_SPECTATOR_MODE_LOCKED) {
|
||||||
/* schedule the periodic ping */
|
/* schedule the periodic ping */
|
||||||
|
@ -2007,7 +2039,6 @@ static int rc_client_attach_load_state(rc_client_t* client, rc_client_load_state
|
||||||
{
|
{
|
||||||
if (client->state.load == NULL) {
|
if (client->state.load == NULL) {
|
||||||
rc_client_unload_game(client);
|
rc_client_unload_game(client);
|
||||||
client->state.load = load_state;
|
|
||||||
|
|
||||||
if (load_state->game == NULL) {
|
if (load_state->game == NULL) {
|
||||||
load_state->game = rc_client_allocate_game();
|
load_state->game = rc_client_allocate_game();
|
||||||
|
@ -2018,6 +2049,10 @@ static int rc_client_attach_load_state(rc_client_t* client, rc_client_load_state
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rc_mutex_lock(&client->state.mutex);
|
||||||
|
client->state.load = load_state;
|
||||||
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
}
|
}
|
||||||
else if (client->state.load != load_state) {
|
else if (client->state.load != load_state) {
|
||||||
/* previous load was aborted */
|
/* previous load was aborted */
|
||||||
|
@ -2621,8 +2656,6 @@ static void rc_client_game_mark_ui_to_be_hidden(rc_client_t* client, rc_client_g
|
||||||
void rc_client_unload_game(rc_client_t* client)
|
void rc_client_unload_game(rc_client_t* client)
|
||||||
{
|
{
|
||||||
rc_client_game_info_t* game;
|
rc_client_game_info_t* game;
|
||||||
rc_client_scheduled_callback_data_t** last;
|
|
||||||
rc_client_scheduled_callback_data_t* next;
|
|
||||||
|
|
||||||
if (!client)
|
if (!client)
|
||||||
return;
|
return;
|
||||||
|
@ -2649,29 +2682,38 @@ void rc_client_unload_game(rc_client_t* client)
|
||||||
if (client->state.load) {
|
if (client->state.load) {
|
||||||
/* this mimics rc_client_abort_async without nesting the lock */
|
/* this mimics rc_client_abort_async without nesting the lock */
|
||||||
client->state.load->async_handle.aborted = RC_CLIENT_ASYNC_ABORTED;
|
client->state.load->async_handle.aborted = RC_CLIENT_ASYNC_ABORTED;
|
||||||
|
|
||||||
|
/* if the game is still being loaded, let the load process clean it up */
|
||||||
|
if (client->state.load->game == game)
|
||||||
|
game = NULL;
|
||||||
|
|
||||||
client->state.load = NULL;
|
client->state.load = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->state.spectator_mode == RC_CLIENT_SPECTATOR_MODE_LOCKED)
|
if (client->state.spectator_mode == RC_CLIENT_SPECTATOR_MODE_LOCKED)
|
||||||
client->state.spectator_mode = RC_CLIENT_SPECTATOR_MODE_ON;
|
client->state.spectator_mode = RC_CLIENT_SPECTATOR_MODE_ON;
|
||||||
|
|
||||||
if (game != NULL)
|
if (game != NULL) {
|
||||||
|
rc_client_scheduled_callback_data_t** last;
|
||||||
|
rc_client_scheduled_callback_data_t* next;
|
||||||
|
|
||||||
rc_client_game_mark_ui_to_be_hidden(client, game);
|
rc_client_game_mark_ui_to_be_hidden(client, game);
|
||||||
|
|
||||||
last = &client->state.scheduled_callbacks;
|
last = &client->state.scheduled_callbacks;
|
||||||
do {
|
do {
|
||||||
next = *last;
|
next = *last;
|
||||||
if (!next)
|
if (!next)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* remove rich presence ping scheduled event for game */
|
/* remove rich presence ping scheduled event for game */
|
||||||
if (next->callback == rc_client_ping && game && next->related_id == game->public_.id) {
|
if (next->callback == rc_client_ping && next->related_id == game->public_.id) {
|
||||||
*last = next->next;
|
*last = next->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
last = &next->next;
|
last = &next->next;
|
||||||
} while (1);
|
} while (1);
|
||||||
|
}
|
||||||
|
|
||||||
rc_mutex_unlock(&client->state.mutex);
|
rc_mutex_unlock(&client->state.mutex);
|
||||||
|
|
||||||
|
@ -3534,7 +3576,7 @@ typedef struct rc_client_award_achievement_callback_data_t
|
||||||
uint32_t retry_count;
|
uint32_t retry_count;
|
||||||
uint8_t hardcore;
|
uint8_t hardcore;
|
||||||
const char* game_hash;
|
const char* game_hash;
|
||||||
time_t unlock_time;
|
rc_clock_t unlock_time;
|
||||||
rc_client_t* client;
|
rc_client_t* client;
|
||||||
rc_client_scheduled_callback_data_t* scheduled_callback_data;
|
rc_client_scheduled_callback_data_t* scheduled_callback_data;
|
||||||
} rc_client_award_achievement_callback_data_t;
|
} rc_client_award_achievement_callback_data_t;
|
||||||
|
@ -3685,6 +3727,11 @@ static void rc_client_award_achievement_server_call(rc_client_award_achievement_
|
||||||
api_params.hardcore = ach_data->hardcore;
|
api_params.hardcore = ach_data->hardcore;
|
||||||
api_params.game_hash = ach_data->game_hash;
|
api_params.game_hash = ach_data->game_hash;
|
||||||
|
|
||||||
|
if (ach_data->retry_count) {
|
||||||
|
const rc_clock_t now = ach_data->client->callbacks.get_time_millisecs(ach_data->client);
|
||||||
|
api_params.seconds_since_unlock = (uint32_t)((now - ach_data->unlock_time) / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
result = rc_api_init_award_achievement_request(&request, &api_params);
|
result = rc_api_init_award_achievement_request(&request, &api_params);
|
||||||
if (result != RC_OK) {
|
if (result != RC_OK) {
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(ach_data->client, "Error constructing unlock request for achievement %u: %s", ach_data->id, rc_error_str(result));
|
RC_CLIENT_LOG_ERR_FORMATTED(ach_data->client, "Error constructing unlock request for achievement %u: %s", ach_data->id, rc_error_str(result));
|
||||||
|
@ -3751,7 +3798,8 @@ static void rc_client_award_achievement(rc_client_t* client, rc_client_achieveme
|
||||||
callback_data->client = client;
|
callback_data->client = client;
|
||||||
callback_data->id = achievement->public_.id;
|
callback_data->id = achievement->public_.id;
|
||||||
callback_data->hardcore = client->state.hardcore;
|
callback_data->hardcore = client->state.hardcore;
|
||||||
callback_data->unlock_time = achievement->public_.unlock_time;
|
callback_data->game_hash = client->game->public_.hash;
|
||||||
|
callback_data->unlock_time = client->callbacks.get_time_millisecs(client);
|
||||||
|
|
||||||
if (client->game) /* may be NULL if this gets called while unloading the game (from another thread - events are raised outside the lock) */
|
if (client->game) /* may be NULL if this gets called while unloading the game (from another thread - events are raised outside the lock) */
|
||||||
callback_data->game_hash = client->game->public_.hash;
|
callback_data->game_hash = client->game->public_.hash;
|
||||||
|
@ -4185,7 +4233,7 @@ typedef struct rc_client_submit_leaderboard_entry_callback_data_t
|
||||||
int32_t score;
|
int32_t score;
|
||||||
uint32_t retry_count;
|
uint32_t retry_count;
|
||||||
const char* game_hash;
|
const char* game_hash;
|
||||||
time_t submit_time;
|
rc_clock_t submit_time;
|
||||||
rc_client_t* client;
|
rc_client_t* client;
|
||||||
rc_client_scheduled_callback_data_t* scheduled_callback_data;
|
rc_client_scheduled_callback_data_t* scheduled_callback_data;
|
||||||
} rc_client_submit_leaderboard_entry_callback_data_t;
|
} rc_client_submit_leaderboard_entry_callback_data_t;
|
||||||
|
@ -4340,6 +4388,11 @@ static void rc_client_submit_leaderboard_entry_server_call(rc_client_submit_lead
|
||||||
api_params.score = lboard_data->score;
|
api_params.score = lboard_data->score;
|
||||||
api_params.game_hash = lboard_data->game_hash;
|
api_params.game_hash = lboard_data->game_hash;
|
||||||
|
|
||||||
|
if (lboard_data->retry_count) {
|
||||||
|
const rc_clock_t now = lboard_data->client->callbacks.get_time_millisecs(lboard_data->client);
|
||||||
|
api_params.seconds_since_completion = (uint32_t)((now - lboard_data->submit_time) / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
result = rc_api_init_submit_lboard_entry_request(&request, &api_params);
|
result = rc_api_init_submit_lboard_entry_request(&request, &api_params);
|
||||||
if (result != RC_OK) {
|
if (result != RC_OK) {
|
||||||
RC_CLIENT_LOG_ERR_FORMATTED(lboard_data->client, "Error constructing submit leaderboard entry for leaderboard %u: %s", lboard_data->id, rc_error_str(result));
|
RC_CLIENT_LOG_ERR_FORMATTED(lboard_data->client, "Error constructing submit leaderboard entry for leaderboard %u: %s", lboard_data->id, rc_error_str(result));
|
||||||
|
@ -4383,7 +4436,7 @@ static void rc_client_submit_leaderboard_entry(rc_client_t* client, rc_client_le
|
||||||
callback_data->id = leaderboard->public_.id;
|
callback_data->id = leaderboard->public_.id;
|
||||||
callback_data->score = leaderboard->value;
|
callback_data->score = leaderboard->value;
|
||||||
callback_data->game_hash = client->game->public_.hash;
|
callback_data->game_hash = client->game->public_.hash;
|
||||||
callback_data->submit_time = time(NULL);
|
callback_data->submit_time = client->callbacks.get_time_millisecs(client);
|
||||||
|
|
||||||
RC_CLIENT_LOG_INFO_FORMATTED(client, "Submitting %s (%d) for leaderboard %u: %s",
|
RC_CLIENT_LOG_INFO_FORMATTED(client, "Submitting %s (%d) for leaderboard %u: %s",
|
||||||
leaderboard->public_.tracker_value, leaderboard->value, leaderboard->public_.id, leaderboard->public_.title);
|
leaderboard->public_.tracker_value, leaderboard->value, leaderboard->public_.id, leaderboard->public_.title);
|
||||||
|
|
|
@ -36,6 +36,17 @@ typedef struct rc_disallowed_core_settings_t
|
||||||
const rc_disallowed_setting_t* disallowed_settings;
|
const rc_disallowed_setting_t* disallowed_settings;
|
||||||
} rc_disallowed_core_settings_t;
|
} rc_disallowed_core_settings_t;
|
||||||
|
|
||||||
|
|
||||||
|
static const rc_disallowed_setting_t _rc_disallowed_beetle_psx_settings[] = {
|
||||||
|
{ "beetle_psx_cpu_freq_scale", "<100" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const rc_disallowed_setting_t _rc_disallowed_beetle_psx_hw_settings[] = {
|
||||||
|
{ "beetle_psx_hw_cpu_freq_scale", "<100" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static const rc_disallowed_setting_t _rc_disallowed_bsnes_settings[] = {
|
static const rc_disallowed_setting_t _rc_disallowed_bsnes_settings[] = {
|
||||||
{ "bsnes_region", "pal" },
|
{ "bsnes_region", "pal" },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
|
@ -80,6 +91,11 @@ static const rc_disallowed_setting_t _rc_disallowed_fceumm_settings[] = {
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const rc_disallowed_setting_t _rc_disallowed_flycast_settings[] = {
|
||||||
|
{ "reicast_sh4clock", "<200" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static const rc_disallowed_setting_t _rc_disallowed_gpgx_settings[] = {
|
static const rc_disallowed_setting_t _rc_disallowed_gpgx_settings[] = {
|
||||||
{ "genesis_plus_gx_lock_on", ",action replay (pro),game genie" },
|
{ "genesis_plus_gx_lock_on", ",action replay (pro),game genie" },
|
||||||
{ "genesis_plus_gx_region_detect", "pal" },
|
{ "genesis_plus_gx_region_detect", "pal" },
|
||||||
|
@ -108,6 +124,7 @@ static const rc_disallowed_setting_t _rc_disallowed_neocd_settings[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const rc_disallowed_setting_t _rc_disallowed_pcsx_rearmed_settings[] = {
|
static const rc_disallowed_setting_t _rc_disallowed_pcsx_rearmed_settings[] = {
|
||||||
|
{ "pcsx_rearmed_psxclock", "<55" },
|
||||||
{ "pcsx_rearmed_region", "pal" },
|
{ "pcsx_rearmed_region", "pal" },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
@ -140,6 +157,11 @@ static const rc_disallowed_setting_t _rc_disallowed_snes9x_settings[] = {
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const rc_disallowed_setting_t _rc_disallowed_swanstation_settings[] = {
|
||||||
|
{ "swanstation_CPU_Overclock", "<100" },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static const rc_disallowed_setting_t _rc_disallowed_vice_settings[] = {
|
static const rc_disallowed_setting_t _rc_disallowed_vice_settings[] = {
|
||||||
{ "vice_autostart", "disabled" }, /* autostart dictates initial load and reset from menu */
|
{ "vice_autostart", "disabled" }, /* autostart dictates initial load and reset from menu */
|
||||||
{ "vice_reset", "!autostart" }, /* reset dictates behavior when pressing reset button (END) */
|
{ "vice_reset", "!autostart" }, /* reset dictates behavior when pressing reset button (END) */
|
||||||
|
@ -152,6 +174,8 @@ static const rc_disallowed_setting_t _rc_disallowed_virtual_jaguar_settings[] =
|
||||||
};
|
};
|
||||||
|
|
||||||
static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
|
static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
|
||||||
|
{ "Beetle PSX", _rc_disallowed_beetle_psx_settings },
|
||||||
|
{ "Beetle PSX HW", _rc_disallowed_beetle_psx_hw_settings },
|
||||||
{ "bsnes-mercury", _rc_disallowed_bsnes_settings },
|
{ "bsnes-mercury", _rc_disallowed_bsnes_settings },
|
||||||
{ "cap32", _rc_disallowed_cap32_settings },
|
{ "cap32", _rc_disallowed_cap32_settings },
|
||||||
{ "dolphin-emu", _rc_disallowed_dolphin_settings },
|
{ "dolphin-emu", _rc_disallowed_dolphin_settings },
|
||||||
|
@ -160,6 +184,7 @@ static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
|
||||||
{ "ecwolf", _rc_disallowed_ecwolf_settings },
|
{ "ecwolf", _rc_disallowed_ecwolf_settings },
|
||||||
{ "FCEUmm", _rc_disallowed_fceumm_settings },
|
{ "FCEUmm", _rc_disallowed_fceumm_settings },
|
||||||
{ "FinalBurn Neo", _rc_disallowed_fbneo_settings },
|
{ "FinalBurn Neo", _rc_disallowed_fbneo_settings },
|
||||||
|
{ "Flycast", _rc_disallowed_flycast_settings },
|
||||||
{ "Genesis Plus GX", _rc_disallowed_gpgx_settings },
|
{ "Genesis Plus GX", _rc_disallowed_gpgx_settings },
|
||||||
{ "Genesis Plus GX Wide", _rc_disallowed_gpgx_wide_settings },
|
{ "Genesis Plus GX Wide", _rc_disallowed_gpgx_wide_settings },
|
||||||
{ "Mesen", _rc_disallowed_mesen_settings },
|
{ "Mesen", _rc_disallowed_mesen_settings },
|
||||||
|
@ -171,6 +196,7 @@ static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
|
||||||
{ "QUASI88", _rc_disallowed_quasi88_settings },
|
{ "QUASI88", _rc_disallowed_quasi88_settings },
|
||||||
{ "SMS Plus GX", _rc_disallowed_smsplus_settings },
|
{ "SMS Plus GX", _rc_disallowed_smsplus_settings },
|
||||||
{ "Snes9x", _rc_disallowed_snes9x_settings },
|
{ "Snes9x", _rc_disallowed_snes9x_settings },
|
||||||
|
{ "SwanStation", _rc_disallowed_swanstation_settings },
|
||||||
{ "VICE x64", _rc_disallowed_vice_settings },
|
{ "VICE x64", _rc_disallowed_vice_settings },
|
||||||
{ "Virtual Jaguar", _rc_disallowed_virtual_jaguar_settings },
|
{ "Virtual Jaguar", _rc_disallowed_virtual_jaguar_settings },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
|
@ -186,6 +212,12 @@ static int rc_libretro_string_equal_nocase_wildcard(const char* test, const char
|
||||||
return (*value == '\0');
|
return (*value == '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rc_libretro_numeric_less_than(const char* test, const char* value) {
|
||||||
|
int test_num = atoi(test);
|
||||||
|
int value_num = atoi(value);
|
||||||
|
return (test_num < value_num);
|
||||||
|
}
|
||||||
|
|
||||||
static int rc_libretro_match_value(const char* val, const char* match) {
|
static int rc_libretro_match_value(const char* val, const char* match) {
|
||||||
/* if value starts with a comma, it's a CSV list of potential matches */
|
/* if value starts with a comma, it's a CSV list of potential matches */
|
||||||
if (*match == ',') {
|
if (*match == ',') {
|
||||||
|
@ -218,6 +250,10 @@ static int rc_libretro_match_value(const char* val, const char* match) {
|
||||||
if (*match == '!')
|
if (*match == '!')
|
||||||
return !rc_libretro_match_value(val, &match[1]);
|
return !rc_libretro_match_value(val, &match[1]);
|
||||||
|
|
||||||
|
/* a leading less tahn means the provided value is the minimum allowed */
|
||||||
|
if (*match == '<')
|
||||||
|
return rc_libretro_numeric_less_than(val, &match[1]);
|
||||||
|
|
||||||
/* just a single value, attempt to match it */
|
/* just a single value, attempt to match it */
|
||||||
return rc_libretro_string_equal_nocase_wildcard(val, match);
|
return rc_libretro_string_equal_nocase_wildcard(val, match);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
RC_BEGIN_C_DECLS
|
RC_BEGIN_C_DECLS
|
||||||
|
|
||||||
#define RCHEEVOS_VERSION_MAJOR 11
|
#define RCHEEVOS_VERSION_MAJOR 11
|
||||||
#define RCHEEVOS_VERSION_MINOR 5
|
#define RCHEEVOS_VERSION_MINOR 6
|
||||||
#define RCHEEVOS_VERSION_PATCH 0
|
#define RCHEEVOS_VERSION_PATCH 0
|
||||||
|
|
||||||
#define RCHEEVOS_MAKE_VERSION(major, minor, patch) (major * 1000000 + minor * 1000 + patch)
|
#define RCHEEVOS_MAKE_VERSION(major, minor, patch) (major * 1000000 + minor * 1000 + patch)
|
||||||
|
|
|
@ -721,16 +721,29 @@ static const rc_memory_regions_t rc_memory_regions_n64 = { _rc_memory_regions_n6
|
||||||
/* ===== Nintendo DS ===== */
|
/* ===== Nintendo DS ===== */
|
||||||
/* https://www.akkit.org/info/gbatek.htm#dsmemorymaps */
|
/* https://www.akkit.org/info/gbatek.htm#dsmemorymaps */
|
||||||
static const rc_memory_region_t _rc_memory_regions_nintendo_ds[] = {
|
static const rc_memory_region_t _rc_memory_regions_nintendo_ds[] = {
|
||||||
{ 0x000000U, 0x3FFFFFU, 0x02000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
{ 0x0000000U, 0x03FFFFFU, 0x02000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||||
|
/* To keep DS/DSi memory maps aligned, padding is set here for the DSi's extra RAM */
|
||||||
|
{ 0x0400000U, 0x0FFFFFFU, 0x02400000U, RC_MEMORY_TYPE_UNUSED, "Unused (DSi exclusive)" },
|
||||||
|
/* The DS/DSi have "tightly coupled memory": very fast memory directly connected to the CPU.
|
||||||
|
* This memory has an instruction variant (ITCM) and a data variant (DTCM).
|
||||||
|
* For achievement purposes it is useful to be able to access the data variant.
|
||||||
|
* This memory does not have a fixed address on console, being able to be moved to any $0xxxx000 region.
|
||||||
|
* While normally this kind of memory is addressed outside of the possible native addressing space, this is simply not possible,
|
||||||
|
* as the DS/DSi's address space covers all possible uint32_t values.
|
||||||
|
* $0E000000 is used here as a "pseudo-end," as this is nearly the end of all the memory actually mapped to addresses
|
||||||
|
* This means that (with the exception of $FFFF0000 onwards, which has the ARM9 BIOS mapped) $0E000000 onwards has nothing mapped to it
|
||||||
|
*/
|
||||||
|
{ 0x1000000U, 0x1003FFFU, 0x0E000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Data TCM" }
|
||||||
};
|
};
|
||||||
static const rc_memory_regions_t rc_memory_regions_nintendo_ds = { _rc_memory_regions_nintendo_ds, 1 };
|
static const rc_memory_regions_t rc_memory_regions_nintendo_ds = { _rc_memory_regions_nintendo_ds, 3 };
|
||||||
|
|
||||||
/* ===== Nintendo DSi ===== */
|
/* ===== Nintendo DSi ===== */
|
||||||
/* https://problemkaputt.de/gbatek.htm#dsiiomap */
|
/* https://problemkaputt.de/gbatek.htm#dsiiomap */
|
||||||
static const rc_memory_region_t _rc_memory_regions_nintendo_dsi[] = {
|
static const rc_memory_region_t _rc_memory_regions_nintendo_dsi[] = {
|
||||||
{ 0x000000U, 0xFFFFFFU, 0x02000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
{ 0x0000000U, 0x0FFFFFFU, 0x02000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||||
|
{ 0x1000000U, 0x1003FFFU, 0x0E000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Data TCM" }
|
||||||
};
|
};
|
||||||
static const rc_memory_regions_t rc_memory_regions_nintendo_dsi = { _rc_memory_regions_nintendo_dsi, 1 };
|
static const rc_memory_regions_t rc_memory_regions_nintendo_dsi = { _rc_memory_regions_nintendo_dsi, 2 };
|
||||||
|
|
||||||
/* ===== Oric ===== */
|
/* ===== Oric ===== */
|
||||||
static const rc_memory_region_t _rc_memory_regions_oric[] = {
|
static const rc_memory_region_t _rc_memory_regions_oric[] = {
|
||||||
|
@ -956,6 +969,31 @@ static const rc_memory_region_t _rc_memory_regions_wonderswan[] = {
|
||||||
};
|
};
|
||||||
static const rc_memory_regions_t rc_memory_regions_wonderswan = { _rc_memory_regions_wonderswan, 2 };
|
static const rc_memory_regions_t rc_memory_regions_wonderswan = { _rc_memory_regions_wonderswan, 2 };
|
||||||
|
|
||||||
|
/* ===== ZX Spectrum ===== */
|
||||||
|
/* https://github.com/TASEmulators/BizHawk/blob/3a3b22c/src/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum16K/ZX16.cs
|
||||||
|
* https://github.com/TASEmulators/BizHawk/blob/3a3b22c/src/BizHawk.Emulation.Cores/Computers/SinclairSpectrum/Machine/ZXSpectrum48K/ZX48.Memory.cs
|
||||||
|
* https://worldofspectrum.org/faq/reference/128kreference.htm */
|
||||||
|
static const rc_memory_region_t _rc_memory_regions_zx_spectrum[] = {
|
||||||
|
/* ZX Spectrum is complicated as multiple models exist with varying amounts of memory.
|
||||||
|
* In practice, this can be reduced to two categories: 16K/48K units, and 128K units.
|
||||||
|
* 16K/48K units have RAM starting at $4000 onwards, 16K ending at $7FFF, 48K ending at $FFFF.
|
||||||
|
* 128K units have banked memory, with $4000-$7FFF normally having RAM bank 5, and $8000-$BFFF normally having RAM bank 2.
|
||||||
|
* $C000-$FFFF is normally reserved for banked RAM, having any of banks 0-7.
|
||||||
|
* For the purposes of the RAM map, $C000-$FFFF is assumed to be bank 0, and $10000 onwards has the other banks in order (1, 3, 4, 6, 7)
|
||||||
|
* Doing it this way always for 16K/48K games to have the same memory map on the 128K, and thus avoid issues due to the model selected.
|
||||||
|
* Later 128K units also have a special banking mode that changes up banking completely, but for 16K/48K compatibility purposes this doesn't matter, and so is irrelevant.
|
||||||
|
*/
|
||||||
|
{ 0x00000U, 0x03FFFU, 0x04000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Screen RAM" }, /* RAM bank 5 on 128K units */
|
||||||
|
{ 0x04000U, 0x07FFFU, 0x08000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* RAM bank 2 on 128K units */
|
||||||
|
{ 0x08000U, 0x0BFFFU, 0x0C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* RAM bank 0-7 on 128K units, assumed to be bank 0 here */
|
||||||
|
{ 0x0C000U, 0x0FFFFU, 0x10000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* RAM bank 1 on 128K units */
|
||||||
|
{ 0x10000U, 0x13FFFU, 0x14000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* RAM bank 3 on 128K units */
|
||||||
|
{ 0x14000U, 0x17FFFU, 0x18000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* RAM bank 4 on 128K units */
|
||||||
|
{ 0x18000U, 0x1BFFFU, 0x1C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* RAM bank 6 on 128K units */
|
||||||
|
{ 0x1C000U, 0x1FFFFU, 0x20000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Screen RAM" } /* RAM bank 7 on 128K units */
|
||||||
|
};
|
||||||
|
static const rc_memory_regions_t rc_memory_regions_zx_spectrum = { _rc_memory_regions_zx_spectrum, 8 };
|
||||||
|
|
||||||
/* ===== default ===== */
|
/* ===== default ===== */
|
||||||
static const rc_memory_regions_t rc_memory_regions_none = { 0, 0 };
|
static const rc_memory_regions_t rc_memory_regions_none = { 0, 0 };
|
||||||
|
|
||||||
|
@ -1141,6 +1179,9 @@ const rc_memory_regions_t* rc_console_memory_regions(uint32_t console_id)
|
||||||
case RC_CONSOLE_WONDERSWAN:
|
case RC_CONSOLE_WONDERSWAN:
|
||||||
return &rc_memory_regions_wonderswan;
|
return &rc_memory_regions_wonderswan;
|
||||||
|
|
||||||
|
case RC_CONSOLE_ZX_SPECTRUM:
|
||||||
|
return &rc_memory_regions_zx_spectrum;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return &rc_memory_regions_none;
|
return &rc_memory_regions_none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,19 +199,19 @@ int rc_evaluate_lboard(rc_lboard_t* self, int32_t* value, rc_peek_t peek, void*
|
||||||
/* start and submit are both true in the same frame, just submit without announcing the leaderboard is available */
|
/* start and submit are both true in the same frame, just submit without announcing the leaderboard is available */
|
||||||
self->state = RC_LBOARD_STATE_TRIGGERED;
|
self->state = RC_LBOARD_STATE_TRIGGERED;
|
||||||
}
|
}
|
||||||
else if (self->start.requirement == 0 && self->start.alternative == 0) {
|
else if (!self->start.requirement && !self->start.alternative) {
|
||||||
/* start condition is empty - this leaderboard is submit-only with no measured progress */
|
/* start trigger is empty. assume the leaderboard is in development and ignore */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* start the leaderboard attempt */
|
/* start the leaderboard attempt */
|
||||||
self->state = RC_LBOARD_STATE_STARTED;
|
self->state = RC_LBOARD_STATE_STARTED;
|
||||||
|
|
||||||
/* reset any hit counts in the value */
|
|
||||||
if (self->progress)
|
|
||||||
rc_reset_value(self->progress);
|
|
||||||
|
|
||||||
rc_reset_value(&self->value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* reset any hit counts in the value */
|
||||||
|
if (self->progress)
|
||||||
|
rc_reset_value(self->progress);
|
||||||
|
|
||||||
|
rc_reset_value(&self->value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -726,6 +726,7 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
|
||||||
const rc_condition_t* condition;
|
const rc_condition_t* condition;
|
||||||
const rc_condition_t* condition_chain_start;
|
const rc_condition_t* condition_chain_start;
|
||||||
int overlap;
|
int overlap;
|
||||||
|
int chain_matches;
|
||||||
|
|
||||||
/* empty group */
|
/* empty group */
|
||||||
if (conditions == NULL || compare_conditions == NULL)
|
if (conditions == NULL || compare_conditions == NULL)
|
||||||
|
@ -777,9 +778,9 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
|
||||||
|
|
||||||
/* if combining conditions exist, make sure the same combining conditions exist in the
|
/* if combining conditions exist, make sure the same combining conditions exist in the
|
||||||
* compare logic. conflicts can only occur if the combinining conditions match. */
|
* compare logic. conflicts can only occur if the combinining conditions match. */
|
||||||
|
chain_matches = 1;
|
||||||
if (condition_chain_start != condition)
|
if (condition_chain_start != condition)
|
||||||
{
|
{
|
||||||
int chain_matches = 1;
|
|
||||||
const rc_condition_t* condition_chain_iter = condition_chain_start;
|
const rc_condition_t* condition_chain_iter = condition_chain_start;
|
||||||
while (condition_chain_iter != condition)
|
while (condition_chain_iter != condition)
|
||||||
{
|
{
|
||||||
|
@ -795,11 +796,8 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
|
||||||
if (compare_condition->oper != RC_OPERATOR_NONE &&
|
if (compare_condition->oper != RC_OPERATOR_NONE &&
|
||||||
!rc_validate_are_operands_equal(&compare_condition->operand2, &condition_chain_iter->operand2))
|
!rc_validate_are_operands_equal(&compare_condition->operand2, &condition_chain_iter->operand2))
|
||||||
{
|
{
|
||||||
if (compare_condition->operand2.type != condition_chain_iter->operand2.type)
|
chain_matches = 0;
|
||||||
{
|
break;
|
||||||
chain_matches = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!compare_condition->next)
|
if (!compare_condition->next)
|
||||||
|
@ -808,17 +806,27 @@ static int rc_validate_conflicting_conditions(const rc_condset_t* conditions, co
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (compare_condition->type != RC_CONDITION_ADD_ADDRESS &&
|
||||||
|
compare_condition->type != RC_CONDITION_ADD_SOURCE &&
|
||||||
|
compare_condition->type != RC_CONDITION_SUB_SOURCE &&
|
||||||
|
compare_condition->type != RC_CONDITION_AND_NEXT)
|
||||||
|
{
|
||||||
|
/* things like AddHits and OrNext are hard to definitively detect conflicts. ignore them. */
|
||||||
|
chain_matches = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
compare_condition = compare_condition->next;
|
compare_condition = compare_condition->next;
|
||||||
condition_chain_iter = condition_chain_iter->next;
|
condition_chain_iter = condition_chain_iter->next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* combining field didn't match, or there's more unmatched combining fields. ignore this condition */
|
/* combining field didn't match, or there's more unmatched combining fields. ignore this condition */
|
||||||
if (!chain_matches || rc_validate_is_combining_condition(compare_condition))
|
if (!chain_matches || rc_validate_is_combining_condition(compare_condition))
|
||||||
{
|
{
|
||||||
while (compare_condition->next && rc_validate_is_combining_condition(compare_condition))
|
while (compare_condition->next && rc_validate_is_combining_condition(compare_condition))
|
||||||
compare_condition = compare_condition->next;
|
compare_condition = compare_condition->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compare_condition->required_hits)
|
if (compare_condition->required_hits)
|
||||||
|
|
|
@ -360,6 +360,9 @@ static const char* rc_parse_richpresence_lookup(rc_richpresence_lookup_t* lookup
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
line = nextline;
|
line = nextline;
|
||||||
|
if (line == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
nextline = rc_parse_line(line, &endline, parse);
|
nextline = rc_parse_line(line, &endline, parse);
|
||||||
|
|
||||||
if (endline - line < 2) {
|
if (endline - line < 2) {
|
||||||
|
@ -438,6 +441,9 @@ static const char* rc_parse_richpresence_lookup(rc_richpresence_lookup_t* lookup
|
||||||
|
|
||||||
/* insert the current item and continue scanning the next one */
|
/* insert the current item and continue scanning the next one */
|
||||||
rc_insert_richpresence_lookup_item(lookup, first, last, label, (int)(endline - label), parse);
|
rc_insert_richpresence_lookup_item(lookup, first, last, label, (int)(endline - label), parse);
|
||||||
|
if (parse->offset < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
line = endptr + 1;
|
line = endptr + 1;
|
||||||
} while (line < endline);
|
} while (line < endline);
|
||||||
|
|
||||||
|
|
|
@ -3113,6 +3113,7 @@ int rc_hash_generate_from_buffer(char hash[33], uint32_t console_id, const uint8
|
||||||
case RC_CONSOLE_VIRTUAL_BOY:
|
case RC_CONSOLE_VIRTUAL_BOY:
|
||||||
case RC_CONSOLE_WASM4:
|
case RC_CONSOLE_WASM4:
|
||||||
case RC_CONSOLE_WONDERSWAN:
|
case RC_CONSOLE_WONDERSWAN:
|
||||||
|
case RC_CONSOLE_ZX_SPECTRUM:
|
||||||
return rc_hash_buffer(hash, buffer, buffer_size);
|
return rc_hash_buffer(hash, buffer, buffer_size);
|
||||||
|
|
||||||
case RC_CONSOLE_ARDUBOY:
|
case RC_CONSOLE_ARDUBOY:
|
||||||
|
@ -3411,6 +3412,7 @@ int rc_hash_generate_from_file(char hash[33], uint32_t console_id, const char* p
|
||||||
case RC_CONSOLE_VIRTUAL_BOY:
|
case RC_CONSOLE_VIRTUAL_BOY:
|
||||||
case RC_CONSOLE_WASM4:
|
case RC_CONSOLE_WASM4:
|
||||||
case RC_CONSOLE_WONDERSWAN:
|
case RC_CONSOLE_WONDERSWAN:
|
||||||
|
case RC_CONSOLE_ZX_SPECTRUM:
|
||||||
/* generic whole-file hash - don't buffer */
|
/* generic whole-file hash - don't buffer */
|
||||||
return rc_hash_whole_file(hash, path);
|
return rc_hash_whole_file(hash, path);
|
||||||
|
|
||||||
|
@ -3466,6 +3468,9 @@ int rc_hash_generate_from_file(char hash[33], uint32_t console_id, const char* p
|
||||||
case RC_CONSOLE_NINTENDO_64:
|
case RC_CONSOLE_NINTENDO_64:
|
||||||
return rc_hash_n64(hash, path);
|
return rc_hash_n64(hash, path);
|
||||||
|
|
||||||
|
case RC_CONSOLE_NINTENDO_3DS:
|
||||||
|
return rc_hash_nintendo_3ds(hash, path);
|
||||||
|
|
||||||
case RC_CONSOLE_NINTENDO_DS:
|
case RC_CONSOLE_NINTENDO_DS:
|
||||||
case RC_CONSOLE_NINTENDO_DSI:
|
case RC_CONSOLE_NINTENDO_DSI:
|
||||||
return rc_hash_nintendo_ds(hash, path);
|
return rc_hash_nintendo_ds(hash, path);
|
||||||
|
@ -3573,6 +3578,7 @@ static void rc_hash_initialize_dsk_iterator(struct rc_hash_iterator* iterator, c
|
||||||
/* check MSX first, as Apple II isn't supported by RetroArch, and RAppleWin won't use the iterator */
|
/* check MSX first, as Apple II isn't supported by RetroArch, and RAppleWin won't use the iterator */
|
||||||
rc_hash_iterator_append_console(iterator, RC_CONSOLE_MSX);
|
rc_hash_iterator_append_console(iterator, RC_CONSOLE_MSX);
|
||||||
rc_hash_iterator_append_console(iterator, RC_CONSOLE_AMSTRAD_PC);
|
rc_hash_iterator_append_console(iterator, RC_CONSOLE_AMSTRAD_PC);
|
||||||
|
rc_hash_iterator_append_console(iterator, RC_CONSOLE_ZX_SPECTRUM);
|
||||||
rc_hash_iterator_append_console(iterator, RC_CONSOLE_APPLE_II);
|
rc_hash_iterator_append_console(iterator, RC_CONSOLE_APPLE_II);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3725,6 +3731,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||||
{
|
{
|
||||||
iterator->consoles[0] = RC_CONSOLE_NINTENDO_3DS;
|
iterator->consoles[0] = RC_CONSOLE_NINTENDO_3DS;
|
||||||
}
|
}
|
||||||
|
else if (rc_path_compare_extension(ext, "csw"))
|
||||||
|
{
|
||||||
|
iterator->consoles[0] = RC_CONSOLE_ZX_SPECTRUM;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
|
@ -3808,6 +3818,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||||
iterator->consoles[1] = RC_CONSOLE_PSP;
|
iterator->consoles[1] = RC_CONSOLE_PSP;
|
||||||
iterator->consoles[2] = RC_CONSOLE_3DO;
|
iterator->consoles[2] = RC_CONSOLE_3DO;
|
||||||
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
iterator->consoles[3] = RC_CONSOLE_SEGA_CD; /* ASSERT: handles both Sega CD and Saturn */
|
||||||
|
iterator->consoles[4] = RC_CONSOLE_GAMECUBE;
|
||||||
need_path = 1;
|
need_path = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3909,6 +3920,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||||
{
|
{
|
||||||
iterator->consoles[0] = RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER;
|
iterator->consoles[0] = RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER;
|
||||||
}
|
}
|
||||||
|
else if (rc_path_compare_extension(ext, "pzx"))
|
||||||
|
{
|
||||||
|
iterator->consoles[0] = RC_CONSOLE_ZX_SPECTRUM;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r':
|
case 'r':
|
||||||
|
@ -3947,11 +3962,16 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||||
{
|
{
|
||||||
iterator->consoles[0] = RC_CONSOLE_THOMSONTO8; /* disk */
|
iterator->consoles[0] = RC_CONSOLE_THOMSONTO8; /* disk */
|
||||||
}
|
}
|
||||||
|
else if (rc_path_compare_extension(ext, "scl"))
|
||||||
|
{
|
||||||
|
iterator->consoles[0] = RC_CONSOLE_ZX_SPECTRUM;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
if (rc_path_compare_extension(ext, "tap"))
|
if (rc_path_compare_extension(ext, "tap"))
|
||||||
{
|
{
|
||||||
|
/* also Commodore 64 and ZX Spectrum, but all are full file hashes */
|
||||||
iterator->consoles[0] = RC_CONSOLE_ORIC;
|
iterator->consoles[0] = RC_CONSOLE_ORIC;
|
||||||
}
|
}
|
||||||
else if (rc_path_compare_extension(ext, "tic"))
|
else if (rc_path_compare_extension(ext, "tic"))
|
||||||
|
@ -3962,6 +3982,11 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||||
{
|
{
|
||||||
iterator->consoles[0] = RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER;
|
iterator->consoles[0] = RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER;
|
||||||
}
|
}
|
||||||
|
else if (rc_path_compare_extension(ext, "trd") ||
|
||||||
|
rc_path_compare_extension(ext, "tzx"))
|
||||||
|
{
|
||||||
|
iterator->consoles[0] = RC_CONSOLE_ZX_SPECTRUM;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
|
|
Loading…
Reference in New Issue