mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-27 02:00:41 +00:00
upgrade to rcheevos 10.4 (#13908)
This commit is contained in:
parent
4804d7015a
commit
e3b59fd36d
@ -650,7 +650,7 @@ bool rcheevos_unload(void)
|
||||
{
|
||||
CHEEVOS_FREE(rcheevos_locals.menuitems);
|
||||
rcheevos_locals.menuitems = NULL;
|
||||
rcheevos_locals.menuitem_capacity =
|
||||
rcheevos_locals.menuitem_capacity =
|
||||
rcheevos_locals.menuitem_count = 0;
|
||||
}
|
||||
#endif
|
||||
@ -663,13 +663,8 @@ bool rcheevos_unload(void)
|
||||
|
||||
rcheevos_locals.loaded = false;
|
||||
rcheevos_locals.hardcore_active = false;
|
||||
}
|
||||
|
||||
while (rcheevos_locals.game.hashes)
|
||||
{
|
||||
rcheevos_hash_entry_t* hash_entry = rcheevos_locals.game.hashes;
|
||||
rcheevos_locals.game.hashes = hash_entry->next;
|
||||
free(hash_entry);
|
||||
rc_libretro_hash_set_destroy(&rcheevos_locals.game.hashes);
|
||||
}
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
@ -1011,6 +1006,21 @@ void rcheevos_validate_config_settings(void)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rcheevos_locals.game.console_id &&
|
||||
!rc_libretro_is_system_allowed(system->library_name, rcheevos_locals.game.console_id))
|
||||
{
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"Hardcore paused. You cannot earn hardcore achievements for %s using %s",
|
||||
rc_console_name(rcheevos_locals.game.console_id), system->library_name);
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", buffer);
|
||||
rcheevos_pause_hardcore();
|
||||
|
||||
runloop_msg_queue_push(buffer, 0, 4 * 60, false, NULL,
|
||||
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_WARNING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void rcheevos_runtime_event_handler(
|
||||
@ -1645,6 +1655,10 @@ static void rcheevos_start_session(void)
|
||||
return;
|
||||
}
|
||||
|
||||
/* re-validate the config settings now that we know
|
||||
* which console_id is active */
|
||||
rcheevos_validate_config_settings();
|
||||
|
||||
task = task_init();
|
||||
task->handler = rcheevos_start_session_async;
|
||||
task->callback = rcheevos_start_session_finish;
|
||||
@ -1726,7 +1740,9 @@ static void rcheevos_fetch_game_data(void)
|
||||
struct rcheevos_identify_game_data
|
||||
{
|
||||
struct rc_hash_iterator iterator;
|
||||
char* path;
|
||||
uint8_t* datacopy;
|
||||
char hash[33];
|
||||
};
|
||||
|
||||
static void rcheevos_identify_game_callback(void* userdata)
|
||||
@ -1734,47 +1750,82 @@ static void rcheevos_identify_game_callback(void* userdata)
|
||||
struct rcheevos_identify_game_data* data =
|
||||
(struct rcheevos_identify_game_data*)userdata;
|
||||
|
||||
if (data)
|
||||
{
|
||||
if (rcheevos_locals.game.id == 0)
|
||||
{
|
||||
/* previous hash didn't match, try the next one */
|
||||
char hash[33];
|
||||
if (rc_hash_iterate(hash, &data->iterator))
|
||||
{
|
||||
memcpy(rcheevos_locals.game.hashes->hash, hash, sizeof(hash));
|
||||
rcheevos_locals.load_info.hashes_tried++;
|
||||
rcheevos_locals.load_info.hashes_tried++;
|
||||
|
||||
rcheevos_client_identify_game(hash,
|
||||
rcheevos_identify_game_callback, data);
|
||||
return;
|
||||
}
|
||||
if (rcheevos_locals.game.id == 0)
|
||||
{
|
||||
/* previous hash didn't match, try the next one */
|
||||
char new_hash[33];
|
||||
int found_new_hash;
|
||||
while ((found_new_hash = rc_hash_iterate(new_hash, &data->iterator)) != 0)
|
||||
{
|
||||
if (!rc_libretro_hash_set_get_game_id(&rcheevos_locals.game.hashes, new_hash))
|
||||
break;
|
||||
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Ignoring [%s]. Already tried.\n", new_hash);
|
||||
}
|
||||
|
||||
/* no more hashes generated, free the iterator data */
|
||||
if (data->datacopy)
|
||||
free(data->datacopy);
|
||||
free(data);
|
||||
if (found_new_hash)
|
||||
{
|
||||
memcpy(data->hash, new_hash, sizeof(data->hash));
|
||||
rcheevos_client_identify_game(data->hash,
|
||||
rcheevos_identify_game_callback, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rcheevos_locals.game.hashes->game_id = rcheevos_locals.game.id;
|
||||
rc_libretro_hash_set_add(&rcheevos_locals.game.hashes,
|
||||
data->path, rcheevos_locals.game.id, data->hash);
|
||||
rcheevos_locals.game.hash =
|
||||
rc_libretro_hash_set_get_hash(&rcheevos_locals.game.hashes, data->path);
|
||||
|
||||
if (data->iterator.path && strcmp(data->iterator.path, data->path) != 0)
|
||||
{
|
||||
rc_libretro_hash_set_add(&rcheevos_locals.game.hashes,
|
||||
data->iterator.path, rcheevos_locals.game.id, data->hash);
|
||||
rcheevos_locals.game.hash =
|
||||
rc_libretro_hash_set_get_hash(&rcheevos_locals.game.hashes, data->iterator.path);
|
||||
}
|
||||
|
||||
/* no more hashes generated, free the iterator data */
|
||||
rc_hash_destroy_iterator(&data->iterator);
|
||||
if (data->datacopy)
|
||||
free(data->datacopy);
|
||||
if (data->path)
|
||||
free(data->path);
|
||||
free(data);
|
||||
|
||||
/* hash resolution complete, proceed to fetching game data */
|
||||
if (rcheevos_end_load_state() == 0)
|
||||
rcheevos_fetch_game_data();
|
||||
}
|
||||
|
||||
static int rcheevos_get_image_path(unsigned index, char* buffer, size_t buffer_size)
|
||||
{
|
||||
rarch_system_info_t* system = &runloop_state_get_ptr()->system;
|
||||
if (!system->disk_control.cb.get_image_path)
|
||||
return 0;
|
||||
|
||||
return system->disk_control.cb.get_image_path(index, buffer, buffer_size);
|
||||
}
|
||||
|
||||
static bool rcheevos_identify_game(const struct retro_game_info* info)
|
||||
{
|
||||
struct rcheevos_identify_game_data* data;
|
||||
struct rc_hash_filereader filereader;
|
||||
struct rc_hash_iterator iterator;
|
||||
size_t len;
|
||||
char hash[33];
|
||||
#ifndef DEBUG
|
||||
settings_t* settings = config_get_ptr();
|
||||
#endif
|
||||
|
||||
data = (struct rcheevos_identify_game_data*)
|
||||
calloc(1, sizeof(struct rcheevos_identify_game_data));
|
||||
if (!data)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "allocation failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* provide hooks for reading files */
|
||||
memset(&filereader, 0, sizeof(filereader));
|
||||
filereader.open = rc_hash_handle_file_open;
|
||||
@ -1797,59 +1848,44 @@ static bool rcheevos_identify_game(const struct retro_game_info* info)
|
||||
rc_hash_reset_cdreader_hooks();
|
||||
|
||||
/* fetch the first hash */
|
||||
rc_hash_initialize_iterator(&iterator,
|
||||
rc_hash_initialize_iterator(&data->iterator,
|
||||
info->path, (uint8_t*)info->data, info->size);
|
||||
if (!rc_hash_iterate(hash, &iterator))
|
||||
if (!rc_hash_iterate(data->hash, &data->iterator))
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "no hashes generated\n");
|
||||
rc_hash_destroy_iterator(&data->iterator);
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
rcheevos_locals.game.hashes = (rcheevos_hash_entry_t*)calloc(1, sizeof(rcheevos_hash_entry_t));
|
||||
rcheevos_locals.game.hashes->path_djb2 = djb2_calculate(info->path);
|
||||
rcheevos_locals.game.hash = rcheevos_locals.game.hashes->hash;
|
||||
memcpy(rcheevos_locals.game.hashes->hash, hash, sizeof(hash));
|
||||
rcheevos_locals.load_info.hashes_tried++;
|
||||
rc_libretro_hash_set_init(&rcheevos_locals.game.hashes, info->path, rcheevos_get_image_path);
|
||||
data->path = strdup(info->path);
|
||||
|
||||
if (iterator.consoles[iterator.index] == 0)
|
||||
if (data->iterator.consoles[data->iterator.index] != 0)
|
||||
{
|
||||
/* no more potential matches, just try the one hash */
|
||||
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_IDENTIFYING_GAME);
|
||||
rcheevos_client_identify_game(hash,
|
||||
rcheevos_identify_game_callback, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* multiple potential matches, clone the data for the next attempt */
|
||||
data = (struct rcheevos_identify_game_data*)
|
||||
calloc(1, sizeof(struct rcheevos_identify_game_data));
|
||||
if (!data)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "allocation failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info->data)
|
||||
{
|
||||
len = info->size;
|
||||
if (len > CHEEVOS_MB(64))
|
||||
len = CHEEVOS_MB(64);
|
||||
|
||||
data->datacopy = (uint8_t*)malloc(len);
|
||||
if (!data->datacopy)
|
||||
/* multiple potential matches, clone the data for the next attempt */
|
||||
if (info->data)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "allocation failed\n");
|
||||
free(data);
|
||||
return false;
|
||||
len = info->size;
|
||||
if (len > CHEEVOS_MB(64))
|
||||
len = CHEEVOS_MB(64);
|
||||
|
||||
data->datacopy = (uint8_t*)malloc(len);
|
||||
if (!data->datacopy)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "allocation failed\n");
|
||||
rc_hash_destroy_iterator(&data->iterator);
|
||||
free(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(data->datacopy, info->data, len);
|
||||
data->iterator.buffer = data->datacopy;
|
||||
}
|
||||
|
||||
memcpy(data->datacopy, info->data, len);
|
||||
}
|
||||
|
||||
memcpy(&data->iterator, &iterator, sizeof(iterator));
|
||||
|
||||
rcheevos_begin_load_state(RCHEEVOS_LOAD_STATE_IDENTIFYING_GAME);
|
||||
rcheevos_client_identify_game(hash,
|
||||
rcheevos_client_identify_game(data->hash,
|
||||
rcheevos_identify_game_callback, data);
|
||||
return true;
|
||||
}
|
||||
@ -2049,59 +2085,64 @@ bool rcheevos_load(const void *data)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rcheevos_add_hash(rcheevos_hash_entry_t* hash_entry)
|
||||
struct rcheevos_identify_changed_disc_data
|
||||
{
|
||||
hash_entry->next = rcheevos_locals.game.hashes;
|
||||
rcheevos_locals.game.hashes = hash_entry;
|
||||
rcheevos_locals.game.hash = hash_entry->hash;
|
||||
}
|
||||
int real_game_id;
|
||||
char* path;
|
||||
char hash[33];
|
||||
};
|
||||
|
||||
static void rcheevos_identify_game_disc_callback(void* userdata)
|
||||
{
|
||||
rcheevos_hash_entry_t* hash_entry = (rcheevos_hash_entry_t*)userdata;
|
||||
struct rcheevos_identify_changed_disc_data* changed_disc_data =
|
||||
(struct rcheevos_identify_changed_disc_data*)userdata;
|
||||
|
||||
/* rcheevos_locals.game.id has the game id for the new hash, swap it with the old game id */
|
||||
const int hash_game_id = rcheevos_locals.game.id;
|
||||
rcheevos_locals.game.id = changed_disc_data->real_game_id;
|
||||
|
||||
/* rcheevos_client_identify_game will update rcheevos_locals.game.id */
|
||||
if (rcheevos_locals.game.id == hash_entry->game_id)
|
||||
if (rcheevos_locals.game.id == hash_game_id)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Hash valid for current game\n");
|
||||
}
|
||||
else if (hash_game_id != 0)
|
||||
{
|
||||
/* when changing discs, if the disc is recognized but belongs to another game, allow it.
|
||||
* this allows loading known game discs for games that leverage user-provided discs. */
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Hash identified for game %d\n", hash_game_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* rcheevos_locals.game.id has the game id for the new hash, swap it with the old game id */
|
||||
const int hash_game_id = rcheevos_locals.game.id;
|
||||
rcheevos_locals.game.id = hash_entry->game_id;
|
||||
hash_entry->game_id = hash_game_id;
|
||||
|
||||
if (hash_game_id != 0)
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Disc not recognized\n");
|
||||
if (rcheevos_hardcore_active())
|
||||
{
|
||||
/* when changing discs, if the disc is recognized but belongs to another game, allow it.
|
||||
* this allows loading known game discs for games that leverage user-provided discs. */
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Hash identified for game %d\n", hash_game_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Disc not recognized\n");
|
||||
if (rcheevos_hardcore_active())
|
||||
{
|
||||
/* don't allow unknown game discs in hardcore.
|
||||
* assume it's a modified version of the base game. */
|
||||
runloop_msg_queue_push("Hardcore paused. Game disc unrecognized.", 0, 5 * 60, false, NULL,
|
||||
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
|
||||
rcheevos_pause_hardcore();
|
||||
}
|
||||
/* don't allow unknown game discs in hardcore.
|
||||
* assume it's a modified version of the base game. */
|
||||
runloop_msg_queue_push("Hardcore paused. Game disc unrecognized.", 0, 5 * 60, false, NULL,
|
||||
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
|
||||
rcheevos_pause_hardcore();
|
||||
}
|
||||
}
|
||||
|
||||
/* disc is valid, add it to the known disk list */
|
||||
rcheevos_add_hash(hash_entry);
|
||||
rc_libretro_hash_set_add(&rcheevos_locals.game.hashes,
|
||||
changed_disc_data->path, hash_game_id, changed_disc_data->hash);
|
||||
|
||||
rcheevos_locals.game.hash =
|
||||
rc_libretro_hash_set_get_hash(&rcheevos_locals.game.hashes, changed_disc_data->hash);
|
||||
|
||||
free(changed_disc_data->path);
|
||||
free(changed_disc_data);
|
||||
}
|
||||
|
||||
static void rcheevos_identify_initial_disc_callback(void* userdata)
|
||||
{
|
||||
rcheevos_hash_entry_t* hash_entry = (rcheevos_hash_entry_t*)userdata;
|
||||
struct rcheevos_identify_changed_disc_data* changed_disc_data =
|
||||
(struct rcheevos_identify_changed_disc_data*)userdata;
|
||||
|
||||
/* rcheevos_client_identify_game will update rcheevos_locals.game.id */
|
||||
if (rcheevos_locals.game.id != hash_entry->game_id)
|
||||
if (rcheevos_locals.game.id != changed_disc_data->real_game_id)
|
||||
{
|
||||
if (rcheevos_locals.game.id == 0)
|
||||
{
|
||||
@ -2116,15 +2157,22 @@ static void rcheevos_identify_initial_disc_callback(void* userdata)
|
||||
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR);
|
||||
}
|
||||
|
||||
rcheevos_locals.game.hash = NULL;
|
||||
rcheevos_unload();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* disc is valid, add it to the known disk list */
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Hash valid for current game\n");
|
||||
rc_libretro_hash_set_add(&rcheevos_locals.game.hashes,
|
||||
changed_disc_data->path, rcheevos_locals.game.id, changed_disc_data->hash);
|
||||
|
||||
free(hash_entry);
|
||||
return;
|
||||
rcheevos_locals.game.hash =
|
||||
rc_libretro_hash_set_get_hash(&rcheevos_locals.game.hashes, changed_disc_data->hash);
|
||||
}
|
||||
|
||||
/* disc is valid, add it to the known disk list */
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Hash valid for current game\n");
|
||||
rcheevos_add_hash(hash_entry);
|
||||
free(changed_disc_data->path);
|
||||
free(changed_disc_data);
|
||||
}
|
||||
|
||||
static void rcheevos_validate_initial_disc_handler(retro_task_t* task)
|
||||
@ -2154,22 +2202,21 @@ static void rcheevos_validate_initial_disc_handler(retro_task_t* task)
|
||||
|
||||
void rcheevos_change_disc(const char* new_disc_path, bool initial_disc)
|
||||
{
|
||||
rcheevos_hash_entry_t* hash_entry = rcheevos_locals.game.hashes;
|
||||
rcheevos_hash_entry_t* hash_entry2;
|
||||
const uint32_t path_djb2 = djb2_calculate(new_disc_path);
|
||||
struct rcheevos_identify_changed_disc_data* data;
|
||||
char hash[33];
|
||||
int hash_game_id;
|
||||
|
||||
/* no game loaded */
|
||||
if (rcheevos_locals.game.id == 0)
|
||||
return;
|
||||
|
||||
/* see if we've already identified this file */
|
||||
for (; hash_entry; hash_entry = hash_entry->next)
|
||||
rcheevos_locals.game.hash =
|
||||
rc_libretro_hash_set_get_hash(&rcheevos_locals.game.hashes, new_disc_path);
|
||||
if (rcheevos_locals.game.hash)
|
||||
{
|
||||
if (hash_entry->path_djb2 == path_djb2)
|
||||
{
|
||||
rcheevos_locals.game.hash = hash_entry->hash;
|
||||
return;
|
||||
}
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Switched to known hash: %s\n", rcheevos_locals.game.hash);
|
||||
return;
|
||||
}
|
||||
|
||||
/* don't check the disc until the game is done loading */
|
||||
@ -2185,35 +2232,45 @@ void rcheevos_change_disc(const char* new_disc_path, bool initial_disc)
|
||||
}
|
||||
|
||||
/* attempt to identify the file */
|
||||
hash_entry = (rcheevos_hash_entry_t*)calloc(1, sizeof(rcheevos_hash_entry_t));
|
||||
hash_entry->path_djb2 = path_djb2;
|
||||
|
||||
if (!rc_hash_generate_from_file(hash_entry->hash, rcheevos_locals.game.console_id, new_disc_path))
|
||||
if (rc_hash_generate_from_file(hash, rcheevos_locals.game.console_id, new_disc_path))
|
||||
{
|
||||
/* check to see if the hash is already known */
|
||||
hash_game_id = rc_libretro_hash_set_get_game_id(&rcheevos_locals.game.hashes, hash);
|
||||
if (hash_game_id)
|
||||
{
|
||||
/* hash identical to some other file - probably the first disc matching the m3u. */
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Hash valid for current game\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* when changing discs, if the disc is not supported by the system, allow it. this is
|
||||
* primarily for games that support user-provided audio CDs, but does allow using discs
|
||||
* from other systems for games that leverage user-provided discs. */
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "No hash generated\n");
|
||||
rcheevos_add_hash(hash_entry);
|
||||
hash_game_id = -1;
|
||||
strcpy(hash, "[NO HASH]");
|
||||
}
|
||||
|
||||
if (hash_game_id)
|
||||
{
|
||||
/* we know how to handle this disc. no need to call the server */
|
||||
rc_libretro_hash_set_add(&rcheevos_locals.game.hashes, new_disc_path, hash_game_id, hash);
|
||||
rcheevos_locals.game.hash =
|
||||
rc_libretro_hash_set_get_hash(&rcheevos_locals.game.hashes, new_disc_path);
|
||||
return;
|
||||
}
|
||||
|
||||
/* assume it's for the same game. we'll validate in the callback */
|
||||
hash_entry->game_id = rcheevos_locals.game.id;
|
||||
|
||||
/* check to see if the hash is already known - may have generated it for the m3u */
|
||||
for (hash_entry2 = rcheevos_locals.game.hashes; hash_entry2; hash_entry2 = hash_entry2->next)
|
||||
{
|
||||
if (string_is_equal(hash_entry->hash, hash_entry2->hash))
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Hash valid for current game\n");
|
||||
rcheevos_add_hash(hash_entry);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* call the server to make sure the hash is valid for the loaded game */
|
||||
rcheevos_client_identify_game(hash_entry->hash,
|
||||
initial_disc ? rcheevos_identify_initial_disc_callback :
|
||||
rcheevos_identify_game_disc_callback, hash_entry);
|
||||
data = (struct rcheevos_identify_changed_disc_data*)
|
||||
calloc(1, sizeof(struct rcheevos_identify_changed_disc_data));
|
||||
if (data) {
|
||||
data->real_game_id = rcheevos_locals.game.id;
|
||||
data->path = strdup(new_disc_path);
|
||||
memcpy(data->hash, hash, sizeof(data->hash));
|
||||
|
||||
rcheevos_client_identify_game(data->hash,
|
||||
initial_disc ? rcheevos_identify_initial_disc_callback :
|
||||
rcheevos_identify_game_disc_callback, data);
|
||||
}
|
||||
}
|
||||
|
@ -120,24 +120,16 @@ typedef struct rcheevos_load_info_t
|
||||
#endif
|
||||
} rcheevos_load_info_t;
|
||||
|
||||
typedef struct rcheevos_hash_entry_t
|
||||
{
|
||||
uint32_t path_djb2;
|
||||
int game_id;
|
||||
struct rcheevos_hash_entry_t* next;
|
||||
char hash[33];
|
||||
} rcheevos_hash_entry_t;
|
||||
|
||||
typedef struct rcheevos_game_info_t
|
||||
{
|
||||
int id;
|
||||
int console_id;
|
||||
char* title;
|
||||
char badge_name[16];
|
||||
char* hash;
|
||||
const char* hash;
|
||||
bool mastery_placard_shown;
|
||||
|
||||
rcheevos_hash_entry_t* hashes;
|
||||
rc_libretro_hash_set_t hashes;
|
||||
|
||||
rcheevos_racheevo_t* achievements;
|
||||
rcheevos_ralboard_t* leaderboards;
|
||||
|
1
deps/rcheevos/include/rc_consoles.h
vendored
1
deps/rcheevos/include/rc_consoles.h
vendored
@ -81,6 +81,7 @@ enum {
|
||||
RC_CONSOLE_MEGADUCK = 69,
|
||||
RC_CONSOLE_ZEEBO = 70,
|
||||
RC_CONSOLE_ARDUBOY = 71,
|
||||
RC_CONSOLE_WASM4 = 72,
|
||||
|
||||
RC_CONSOLE_HUBS = 100,
|
||||
RC_CONSOLE_EVENTS = 101
|
||||
|
68
deps/rcheevos/src/rcheevos/consoleinfo.c
vendored
68
deps/rcheevos/src/rcheevos/consoleinfo.c
vendored
@ -201,6 +201,9 @@ const char* rc_console_name(int console_id)
|
||||
case RC_CONSOLE_VIRTUAL_BOY:
|
||||
return "Virtual Boy";
|
||||
|
||||
case RC_CONSOLE_WASM4:
|
||||
return "WASM-4";
|
||||
|
||||
case RC_CONSOLE_WII:
|
||||
return "Wii";
|
||||
|
||||
@ -242,6 +245,14 @@ static const rc_memory_region_t _rc_memory_regions_3do[] = {
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_3do = { _rc_memory_regions_3do, 1 };
|
||||
|
||||
/* ===== Amiga ===== */
|
||||
/* http://amigadev.elowar.com/read/ADCD_2.1/Hardware_Manual_guide/node00D3.html */
|
||||
static const rc_memory_region_t _rc_memory_regions_amiga[] = {
|
||||
{ 0x000000U, 0x07FFFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Main RAM" }, /* 512KB main RAM */
|
||||
{ 0x080000U, 0x0FFFFFU, 0x080000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Extended RAM" }, /* 512KB extended RAM */
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_amiga = { _rc_memory_regions_amiga, 2 };
|
||||
|
||||
/* ===== Amstrad CPC ===== */
|
||||
/* http://www.cpcalive.com/docs/amstrad_cpc_6128_memory_map.html */
|
||||
/* https://www.cpcwiki.eu/index.php/File:AWMG_page151.jpg */
|
||||
@ -324,6 +335,20 @@ static const rc_memory_region_t _rc_memory_regions_colecovision[] = {
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_colecovision = { _rc_memory_regions_colecovision, 1 };
|
||||
|
||||
/* ===== Commodore 64 ===== */
|
||||
/* https://www.c64-wiki.com/wiki/Memory_Map */
|
||||
/* https://sta.c64.org/cbm64mem.html */
|
||||
static const rc_memory_region_t _rc_memory_regions_c64[] = {
|
||||
{ 0x000000U, 0x0003FFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Kernel RAM" },
|
||||
{ 0x000400U, 0x0007FFU, 0x000400U, RC_MEMORY_TYPE_VIDEO_RAM, "Screen RAM" },
|
||||
{ 0x000800U, 0x009FFFU, 0x000800U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* BASIC Program Storage Area */
|
||||
{ 0x00A000U, 0x00BFFFU, 0x00A000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* Machine Language Storage Area / BASIC ROM Area */
|
||||
{ 0x00C000U, 0x00CFFFU, 0x00C000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* Machine Language Storage Area */
|
||||
{ 0x00D000U, 0x00DFFFU, 0x00D000U, RC_MEMORY_TYPE_SYSTEM_RAM, "I/O Area" }, /* also Character ROM */
|
||||
{ 0x00E000U, 0x00FFFFU, 0x00E000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }, /* Machine Language Storage Area / Kernal ROM */
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_c64 = { _rc_memory_regions_c64, 7 };
|
||||
|
||||
/* ===== Dreamcast ===== */
|
||||
/* http://archiv.sega-dc.de/munkeechuff/hardware/Memory.html */
|
||||
static const rc_memory_region_t _rc_memory_regions_dreamcast[] = {
|
||||
@ -331,6 +356,21 @@ static const rc_memory_region_t _rc_memory_regions_dreamcast[] = {
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_dreamcast = { _rc_memory_regions_dreamcast, 1 };
|
||||
|
||||
/* ===== Fairchild Channel F ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_fairchild_channel_f[] = {
|
||||
/* "System RAM" is actually just a bunch of registers internal to CPU so all carts have it.
|
||||
* "Video RAM" is part of the console so it's always available but it is write-only by the ROMs.
|
||||
* "Cartridge RAM" is the cart BUS. Most carts only have ROMs on this bus. Exception are
|
||||
* German Schach and homebrew carts that have 2K of RAM there in addition to ROM.
|
||||
* "F2102 RAM" is used by Maze for 1K of RAM.
|
||||
* https://discord.com/channels/310192285306454017/645777658319208448/967001438087708714 */
|
||||
{ 0x00000000U, 0x0000003FU, 0x00100000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x00000040U, 0x0000083FU, 0x00300000U, RC_MEMORY_TYPE_VIDEO_RAM, "Video RAM" },
|
||||
{ 0x00000840U, 0x0001083FU, 0x00000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Cartridge RAM" },
|
||||
{ 0x00010840U, 0x00010C3FU, 0x00200000U, RC_MEMORY_TYPE_SYSTEM_RAM, "F2102 RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_fairchild_channel_f = { _rc_memory_regions_fairchild_channel_f, 4 };
|
||||
|
||||
/* ===== GameBoy / GameBoy Color ===== */
|
||||
static const rc_memory_region_t _rc_memory_regions_gameboy[] = {
|
||||
{ 0x000000U, 0x0000FFU, 0x000000U, RC_MEMORY_TYPE_HARDWARE_CONTROLLER, "Interrupt vector" },
|
||||
@ -553,9 +593,10 @@ static const rc_memory_regions_t rc_memory_regions_playstation = { _rc_memory_re
|
||||
/* https://psi-rockin.github.io/ps2tek/ */
|
||||
static const rc_memory_region_t _rc_memory_regions_playstation2[] = {
|
||||
{ 0x00000000U, 0x000FFFFFU, 0x00000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Kernel RAM" },
|
||||
{ 0x00100000U, 0x01FFFFFFU, 0x00100000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
{ 0x00100000U, 0x01FFFFFFU, 0x00100000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
{ 0x02000000U, 0x02003FFFU, 0x70000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Scratchpad RAM" },
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_playstation2 = { _rc_memory_regions_playstation2, 2 };
|
||||
static const rc_memory_regions_t rc_memory_regions_playstation2 = { _rc_memory_regions_playstation2, 3 };
|
||||
|
||||
/* ===== PlayStation Portable ===== */
|
||||
/* https://github.com/uofw/upspd/wiki/Memory-map */
|
||||
@ -670,6 +711,17 @@ static const rc_memory_region_t _rc_memory_regions_watara_supervision[] = {
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_watara_supervision = { _rc_memory_regions_watara_supervision, 3 };
|
||||
|
||||
/* ===== WASM-4 ===== */
|
||||
/* fantasy console that runs specifically designed WebAssembly games */
|
||||
/* https://github.com/aduros/wasm4/blob/main/site/docs/intro.md#hardware-specs */
|
||||
static const rc_memory_region_t _rc_memory_regions_wasm4[] = {
|
||||
{ 0x000000U, 0x00FFFFU, 0x00000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" },
|
||||
/* Persistent storage is not directly accessible from the game. It has to be loaded into System RAM first
|
||||
{ 0x010000U, 0x0103FFU, 0x80000000U, RC_MEMORY_TYPE_SAVE_RAM, "Disk Storage"}
|
||||
*/
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_wasm4 = { _rc_memory_regions_wasm4, 1 };
|
||||
|
||||
/* ===== WonderSwan ===== */
|
||||
/* http://daifukkat.su/docs/wsman/#ovr_memmap */
|
||||
static const rc_memory_region_t _rc_memory_regions_wonderswan[] = {
|
||||
@ -697,6 +749,9 @@ const rc_memory_regions_t* rc_console_memory_regions(int console_id)
|
||||
case RC_CONSOLE_3DO:
|
||||
return &rc_memory_regions_3do;
|
||||
|
||||
case RC_CONSOLE_AMIGA:
|
||||
return &rc_memory_regions_amiga;
|
||||
|
||||
case RC_CONSOLE_AMSTRAD_PC:
|
||||
return &rc_memory_regions_amstrad_pc;
|
||||
|
||||
@ -721,9 +776,15 @@ const rc_memory_regions_t* rc_console_memory_regions(int console_id)
|
||||
case RC_CONSOLE_COLECOVISION:
|
||||
return &rc_memory_regions_colecovision;
|
||||
|
||||
case RC_CONSOLE_COMMODORE_64:
|
||||
return &rc_memory_regions_c64;
|
||||
|
||||
case RC_CONSOLE_DREAMCAST:
|
||||
return &rc_memory_regions_dreamcast;
|
||||
|
||||
case RC_CONSOLE_FAIRCHILD_CHANNEL_F:
|
||||
return &rc_memory_regions_fairchild_channel_f;
|
||||
|
||||
case RC_CONSOLE_MEGADUCK:
|
||||
case RC_CONSOLE_GAMEBOY:
|
||||
return &rc_memory_regions_gameboy;
|
||||
@ -821,6 +882,9 @@ const rc_memory_regions_t* rc_console_memory_regions(int console_id)
|
||||
case RC_CONSOLE_VIRTUAL_BOY:
|
||||
return &rc_memory_regions_virtualboy;
|
||||
|
||||
case RC_CONSOLE_WASM4:
|
||||
return &rc_memory_regions_wasm4;
|
||||
|
||||
case RC_CONSOLE_WONDERSWAN:
|
||||
return &rc_memory_regions_wonderswan;
|
||||
|
||||
|
210
deps/rcheevos/src/rcheevos/rc_libretro.c
vendored
210
deps/rcheevos/src/rcheevos/rc_libretro.c
vendored
@ -14,6 +14,16 @@
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
/* internal helper functions in hash.c */
|
||||
extern void* rc_file_open(const char* path);
|
||||
extern void rc_file_seek(void* file_handle, int64_t offset, int origin);
|
||||
extern int64_t rc_file_tell(void* file_handle);
|
||||
extern size_t rc_file_read(void* file_handle, void* buffer, int requested_bytes);
|
||||
extern void rc_file_close(void* file_handle);
|
||||
extern int rc_path_compare_extension(const char* path, const char* ext);
|
||||
extern int rc_hash_error(const char* message);
|
||||
|
||||
|
||||
static rc_libretro_message_callback rc_libretro_verbose_message_callback = NULL;
|
||||
|
||||
/* a value that starts with a comma is a CSV.
|
||||
@ -229,6 +239,41 @@ const rc_disallowed_setting_t* rc_libretro_get_disallowed_settings(const char* l
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct rc_disallowed_core_systems_t
|
||||
{
|
||||
const char* library_name;
|
||||
const int disallowed_consoles[4];
|
||||
} rc_disallowed_core_systems_t;
|
||||
|
||||
static const rc_disallowed_core_systems_t rc_disallowed_core_systems[] = {
|
||||
/* https://github.com/libretro/Mesen-S/issues/8 */
|
||||
{ "Mesen-S", { RC_CONSOLE_GAMEBOY, RC_CONSOLE_GAMEBOY_COLOR, 0 }},
|
||||
{ NULL, { 0 } }
|
||||
};
|
||||
|
||||
int rc_libretro_is_system_allowed(const char* library_name, int console_id) {
|
||||
const rc_disallowed_core_systems_t* core_filter = rc_disallowed_core_systems;
|
||||
size_t library_name_length;
|
||||
size_t i;
|
||||
|
||||
if (!library_name || !library_name[0])
|
||||
return 1;
|
||||
|
||||
library_name_length = strlen(library_name) + 1;
|
||||
while (core_filter->library_name) {
|
||||
if (memcmp(core_filter->library_name, library_name, library_name_length) == 0) {
|
||||
for (i = 0; i < sizeof(core_filter->disallowed_consoles) / sizeof(core_filter->disallowed_consoles[0]); ++i) {
|
||||
if (core_filter->disallowed_consoles[i] == console_id)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
++core_filter;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char* rc_libretro_memory_find(const rc_libretro_memory_regions_t* regions, unsigned address) {
|
||||
unsigned i;
|
||||
@ -556,3 +601,168 @@ int rc_libretro_memory_init(rc_libretro_memory_regions_t* regions, const struct
|
||||
void rc_libretro_memory_destroy(rc_libretro_memory_regions_t* regions) {
|
||||
memset(regions, 0, sizeof(*regions));
|
||||
}
|
||||
|
||||
void rc_libretro_hash_set_init(struct rc_libretro_hash_set_t* hash_set,
|
||||
const char* m3u_path, rc_libretro_get_image_path_func get_image_path) {
|
||||
char image_path[1024];
|
||||
char* m3u_contents;
|
||||
char* ptr;
|
||||
size_t file_len;
|
||||
void* file_handle;
|
||||
int index = 0;
|
||||
|
||||
memset(hash_set, 0, sizeof(*hash_set));
|
||||
|
||||
if (!rc_path_compare_extension(m3u_path, "m3u"))
|
||||
return;
|
||||
|
||||
file_handle = rc_file_open(m3u_path);
|
||||
if (!file_handle)
|
||||
{
|
||||
rc_hash_error("Could not open playlist");
|
||||
return;
|
||||
}
|
||||
|
||||
rc_file_seek(file_handle, 0, SEEK_END);
|
||||
file_len = rc_file_tell(file_handle);
|
||||
rc_file_seek(file_handle, 0, SEEK_SET);
|
||||
|
||||
m3u_contents = (char*)malloc(file_len + 1);
|
||||
rc_file_read(file_handle, m3u_contents, (int)file_len);
|
||||
m3u_contents[file_len] = '\0';
|
||||
|
||||
rc_file_close(file_handle);
|
||||
|
||||
ptr = m3u_contents;
|
||||
do
|
||||
{
|
||||
/* ignore whitespace */
|
||||
while (isspace((int)*ptr))
|
||||
++ptr;
|
||||
|
||||
if (*ptr == '#')
|
||||
{
|
||||
/* ignore comment unless it's the special SAVEDISK extension */
|
||||
if (memcmp(ptr, "#SAVEDISK:", 10) == 0)
|
||||
{
|
||||
/* get the path to the save disk from the frontend, assign it a bogus hash so
|
||||
* it doesn't get hashed later */
|
||||
if (get_image_path(index, image_path, sizeof(image_path)))
|
||||
{
|
||||
const char save_disk_hash[33] = "[SAVE DISK]";
|
||||
rc_libretro_hash_set_add(hash_set, image_path, -1, save_disk_hash);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* non-empty line, tally a file */
|
||||
++index;
|
||||
}
|
||||
|
||||
/* find the end of the line */
|
||||
while (*ptr && *ptr != '\n')
|
||||
++ptr;
|
||||
|
||||
} while (*ptr);
|
||||
|
||||
free(m3u_contents);
|
||||
|
||||
if (hash_set->entries_count > 0)
|
||||
{
|
||||
/* at least one save disk was found. make sure the core supports the #SAVEDISK: extension by
|
||||
* asking for the last expected disk. if it's not found, assume no #SAVEDISK: support */
|
||||
if (!get_image_path(index - 1, image_path, sizeof(image_path)))
|
||||
hash_set->entries_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void rc_libretro_hash_set_destroy(struct rc_libretro_hash_set_t* hash_set) {
|
||||
if (hash_set->entries)
|
||||
free(hash_set->entries);
|
||||
memset(hash_set, 0, sizeof(*hash_set));
|
||||
}
|
||||
|
||||
static unsigned rc_libretro_djb2(const char* input)
|
||||
{
|
||||
unsigned result = 5381;
|
||||
char c;
|
||||
|
||||
while ((c = *input++) != '\0')
|
||||
result = ((result << 5) + result) + c; /* result = result * 33 + c */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void rc_libretro_hash_set_add(struct rc_libretro_hash_set_t* hash_set,
|
||||
const char* path, int game_id, const char hash[33]) {
|
||||
const unsigned path_djb2 = (path != NULL) ? rc_libretro_djb2(path) : 0;
|
||||
struct rc_libretro_hash_entry_t* entry = NULL;
|
||||
struct rc_libretro_hash_entry_t* scan;
|
||||
struct rc_libretro_hash_entry_t* stop = hash_set->entries + hash_set->entries_count;;
|
||||
|
||||
if (path_djb2)
|
||||
{
|
||||
/* attempt to match the path */
|
||||
for (scan = hash_set->entries; scan < stop; ++scan)
|
||||
{
|
||||
if (scan->path_djb2 == path_djb2)
|
||||
{
|
||||
entry = scan;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
/* entry not found, allocate a new one */
|
||||
if (hash_set->entries_size == 0)
|
||||
{
|
||||
hash_set->entries_size = 4;
|
||||
hash_set->entries = (struct rc_libretro_hash_entry_t*)
|
||||
malloc(hash_set->entries_size * sizeof(struct rc_libretro_hash_entry_t));
|
||||
}
|
||||
else if (hash_set->entries_count == hash_set->entries_size)
|
||||
{
|
||||
hash_set->entries_size += 4;
|
||||
hash_set->entries = (struct rc_libretro_hash_entry_t*)realloc(hash_set->entries,
|
||||
hash_set->entries_size * sizeof(struct rc_libretro_hash_entry_t));
|
||||
}
|
||||
|
||||
entry = hash_set->entries + hash_set->entries_count++;
|
||||
}
|
||||
|
||||
/* update the entry */
|
||||
entry->path_djb2 = path_djb2;
|
||||
entry->game_id = game_id;
|
||||
memcpy(entry->hash, hash, sizeof(entry->hash));
|
||||
}
|
||||
|
||||
const char* rc_libretro_hash_set_get_hash(const struct rc_libretro_hash_set_t* hash_set, const char* path)
|
||||
{
|
||||
const unsigned path_djb2 = rc_libretro_djb2(path);
|
||||
struct rc_libretro_hash_entry_t* scan = hash_set->entries;
|
||||
struct rc_libretro_hash_entry_t* stop = scan + hash_set->entries_count;
|
||||
for (; scan < stop; ++scan)
|
||||
{
|
||||
if (scan->path_djb2 == path_djb2)
|
||||
return scan->hash;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rc_libretro_hash_set_get_game_id(const struct rc_libretro_hash_set_t* hash_set, const char* hash)
|
||||
{
|
||||
struct rc_libretro_hash_entry_t* scan = hash_set->entries;
|
||||
struct rc_libretro_hash_entry_t* stop = scan + hash_set->entries_count;
|
||||
for (; scan < stop; ++scan)
|
||||
{
|
||||
if (memcmp(scan->hash, hash, sizeof(scan->hash)) == 0)
|
||||
return scan->game_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
30
deps/rcheevos/src/rcheevos/rc_libretro.h
vendored
30
deps/rcheevos/src/rcheevos/rc_libretro.h
vendored
@ -21,6 +21,7 @@ typedef struct rc_disallowed_setting_t
|
||||
|
||||
const rc_disallowed_setting_t* rc_libretro_get_disallowed_settings(const char* library_name);
|
||||
int rc_libretro_is_setting_allowed(const rc_disallowed_setting_t* disallowed_settings, const char* setting, const char* value);
|
||||
int rc_libretro_is_system_allowed(const char* library_name, int console_id);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Memory Mapping |
|
||||
@ -53,6 +54,35 @@ void rc_libretro_memory_destroy(rc_libretro_memory_regions_t* regions);
|
||||
|
||||
unsigned char* rc_libretro_memory_find(const rc_libretro_memory_regions_t* regions, unsigned address);
|
||||
|
||||
/*****************************************************************************\
|
||||
| Disk Identification |
|
||||
\*****************************************************************************/
|
||||
|
||||
typedef struct rc_libretro_hash_entry_t
|
||||
{
|
||||
uint32_t path_djb2;
|
||||
int game_id;
|
||||
char hash[33];
|
||||
} rc_libretro_hash_entry_t;
|
||||
|
||||
typedef struct rc_libretro_hash_set_t
|
||||
{
|
||||
struct rc_libretro_hash_entry_t* entries;
|
||||
uint16_t entries_count;
|
||||
uint16_t entries_size;
|
||||
} rc_libretro_hash_set_t;
|
||||
|
||||
typedef int (*rc_libretro_get_image_path_func)(unsigned index, char* buffer, size_t buffer_size);
|
||||
|
||||
void rc_libretro_hash_set_init(struct rc_libretro_hash_set_t* hash_set,
|
||||
const char* m3u_path, rc_libretro_get_image_path_func get_image_path);
|
||||
void rc_libretro_hash_set_destroy(struct rc_libretro_hash_set_t* hash_set);
|
||||
|
||||
void rc_libretro_hash_set_add(struct rc_libretro_hash_set_t* hash_set,
|
||||
const char* path, int game_id, const char hash[33]);
|
||||
const char* rc_libretro_hash_set_get_hash(const struct rc_libretro_hash_set_t* hash_set, const char* path);
|
||||
int rc_libretro_hash_set_get_game_id(const struct rc_libretro_hash_set_t* hash_set, const char* hash);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
49
deps/rcheevos/src/rcheevos/trigger.c
vendored
49
deps/rcheevos/src/rcheevos/trigger.c
vendored
@ -96,16 +96,29 @@ int rc_trigger_state_active(int state)
|
||||
}
|
||||
}
|
||||
|
||||
static int rc_condset_is_measured_from_hitcount(const rc_condset_t* condset, unsigned measured_value)
|
||||
{
|
||||
const rc_condition_t* condition;
|
||||
for (condition = condset->conditions; condition; condition = condition->next) {
|
||||
if (condition->type == RC_CONDITION_MEASURED && condition->required_hits &&
|
||||
condition->current_hits == measured_value) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rc_reset_trigger_hitcounts(rc_trigger_t* self) {
|
||||
rc_condset_t* condset;
|
||||
|
||||
if (self->requirement != 0) {
|
||||
if (self->requirement) {
|
||||
rc_reset_condset(self->requirement);
|
||||
}
|
||||
|
||||
condset = self->alternative;
|
||||
|
||||
while (condset != 0) {
|
||||
while (condset) {
|
||||
rc_reset_condset(condset);
|
||||
condset = condset->next;
|
||||
}
|
||||
@ -168,7 +181,7 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||
sub_primed |= eval_state.primed;
|
||||
|
||||
condset = condset->next;
|
||||
} while (condset != 0);
|
||||
} while (condset);
|
||||
|
||||
/* to trigger, the core must be true and at least one alt must be true */
|
||||
ret &= sub;
|
||||
@ -192,13 +205,31 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||
return RC_TRIGGER_STATE_WAITING;
|
||||
}
|
||||
|
||||
/* if any ResetIf condition was true, reset the hit counts */
|
||||
if (eval_state.was_reset) {
|
||||
/* if any ResetIf condition was true, reset the hit counts */
|
||||
rc_reset_trigger_hitcounts(self);
|
||||
|
||||
/* if the measured value came from a hit count, reset it too */
|
||||
if (eval_state.measured_from_hits)
|
||||
/* if the measured value came from a hit count, reset it. do this before calling
|
||||
* rc_reset_trigger_hitcounts in case we need to call rc_condset_is_measured_from_hitcount */
|
||||
if (eval_state.measured_from_hits) {
|
||||
self->measured_value = 0;
|
||||
}
|
||||
else if (is_paused && self->measured_value) {
|
||||
/* if the measured value is in a paused group, measured_from_hits won't have been set.
|
||||
* attempt to determine if it should have been */
|
||||
if (self->requirement && self->requirement->is_paused &&
|
||||
rc_condset_is_measured_from_hitcount(self->requirement, self->measured_value)) {
|
||||
self->measured_value = 0;
|
||||
}
|
||||
else {
|
||||
for (condset = self->alternative; condset; condset = condset->next) {
|
||||
if (condset->is_paused && rc_condset_is_measured_from_hitcount(condset, self->measured_value)) {
|
||||
self->measured_value = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc_reset_trigger_hitcounts(self);
|
||||
|
||||
/* if there were hit counts to clear, return RESET, but don't change the state */
|
||||
if (self->has_hits) {
|
||||
@ -206,7 +237,7 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State*
|
||||
|
||||
/* cannot be PRIMED while ResetIf is true */
|
||||
if (self->state == RC_TRIGGER_STATE_PRIMED)
|
||||
self->state = RC_TRIGGER_STATE_ACTIVE;
|
||||
self->state = RC_TRIGGER_STATE_ACTIVE;
|
||||
|
||||
return RC_TRIGGER_STATE_RESET;
|
||||
}
|
||||
|
28
deps/rcheevos/src/rhash/cdreader.c
vendored
28
deps/rcheevos/src/rhash/cdreader.c
vendored
@ -563,32 +563,34 @@ static void* cdreader_open_cue_track(const char* path, uint32_t track)
|
||||
|
||||
static void* cdreader_open_gdi_track(const char* path, uint32_t track)
|
||||
{
|
||||
void* file_handle;
|
||||
char buffer[1024];
|
||||
char mode[16] = "MODE1/";
|
||||
char sector_size[16];
|
||||
char file[256];
|
||||
int64_t track_size;
|
||||
int track_type;
|
||||
char *ptr, *ptr2, *end;
|
||||
char* bin_path = "";
|
||||
uint32_t current_track = 0;
|
||||
char* ptr, *ptr2, *end;
|
||||
int lba = 0;
|
||||
|
||||
uint32_t largest_track = 0;
|
||||
int64_t largest_track_size = 0;
|
||||
char largest_track_file[256];
|
||||
char largest_track_sector_size[16];
|
||||
char *bin_path = NULL;
|
||||
uint32_t current_track = 0;
|
||||
int lba = 0;
|
||||
uint32_t largest_track = 0;
|
||||
int64_t largest_track_size = 0;
|
||||
int largest_track_lba = 0;
|
||||
int largest_track_lba = 0;
|
||||
|
||||
int found = 0;
|
||||
size_t num_read = 0;
|
||||
int64_t file_offset = 0;
|
||||
struct cdrom_t* cdrom = NULL;
|
||||
void *file_handle = rc_file_open(path);
|
||||
int found = 0;
|
||||
size_t num_read = 0;
|
||||
int64_t file_offset = 0;
|
||||
struct cdrom_t* cdrom = NULL;
|
||||
|
||||
file_handle = rc_file_open(path);
|
||||
if (!file_handle)
|
||||
return NULL;
|
||||
|
||||
file[0] = '\0';
|
||||
file[0] = '\0';
|
||||
do
|
||||
{
|
||||
num_read = rc_file_read(file_handle, buffer, sizeof(buffer) - 1);
|
||||
|
28
deps/rcheevos/src/rhash/hash.c
vendored
28
deps/rcheevos/src/rhash/hash.c
vendored
@ -1609,6 +1609,8 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* b
|
||||
case RC_CONSOLE_ATARI_2600:
|
||||
case RC_CONSOLE_ATARI_JAGUAR:
|
||||
case RC_CONSOLE_COLECOVISION:
|
||||
case RC_CONSOLE_COMMODORE_64:
|
||||
case RC_CONSOLE_FAIRCHILD_CHANNEL_F:
|
||||
case RC_CONSOLE_GAMEBOY:
|
||||
case RC_CONSOLE_GAMEBOY_ADVANCE:
|
||||
case RC_CONSOLE_GAMEBOY_COLOR:
|
||||
@ -1629,6 +1631,7 @@ int rc_hash_generate_from_buffer(char hash[33], int console_id, const uint8_t* b
|
||||
case RC_CONSOLE_TIC80:
|
||||
case RC_CONSOLE_VECTREX:
|
||||
case RC_CONSOLE_VIRTUAL_BOY:
|
||||
case RC_CONSOLE_WASM4:
|
||||
case RC_CONSOLE_WONDERSWAN:
|
||||
return rc_hash_buffer(hash, buffer, buffer_size);
|
||||
|
||||
@ -1898,6 +1901,7 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
|
||||
case RC_CONSOLE_ATARI_2600:
|
||||
case RC_CONSOLE_ATARI_JAGUAR:
|
||||
case RC_CONSOLE_COLECOVISION:
|
||||
case RC_CONSOLE_FAIRCHILD_CHANNEL_F:
|
||||
case RC_CONSOLE_GAMEBOY:
|
||||
case RC_CONSOLE_GAMEBOY_ADVANCE:
|
||||
case RC_CONSOLE_GAMEBOY_COLOR:
|
||||
@ -1916,12 +1920,14 @@ int rc_hash_generate_from_file(char hash[33], int console_id, const char* path)
|
||||
case RC_CONSOLE_TIC80:
|
||||
case RC_CONSOLE_VECTREX:
|
||||
case RC_CONSOLE_VIRTUAL_BOY:
|
||||
case RC_CONSOLE_WASM4:
|
||||
case RC_CONSOLE_WONDERSWAN:
|
||||
/* generic whole-file hash - don't buffer */
|
||||
return rc_hash_whole_file(hash, path);
|
||||
|
||||
case RC_CONSOLE_AMSTRAD_PC:
|
||||
case RC_CONSOLE_APPLE_II:
|
||||
case RC_CONSOLE_COMMODORE_64:
|
||||
case RC_CONSOLE_MSX:
|
||||
case RC_CONSOLE_PC8800:
|
||||
/* generic whole-file hash with m3u support - don't buffer */
|
||||
@ -2132,7 +2138,7 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
}
|
||||
}
|
||||
|
||||
/* bin is associated with MegaDrive, Sega32X, Atari 2600, Watara Supervision, and MegaDuck.
|
||||
/* bin is associated with MegaDrive, Sega32X, Atari 2600, Watara Supervision, MegaDuck, and Fairchild Channel F.
|
||||
* Since they all use the same hashing algorithm, only specify one of them */
|
||||
iterator->consoles[0] = RC_CONSOLE_MEGA_DRIVE;
|
||||
}
|
||||
@ -2173,6 +2179,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_MSX;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "chf"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_FAIRCHILD_CHANNEL_F;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
@ -2180,6 +2190,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
{
|
||||
rc_hash_initialize_dsk_iterator(iterator, path);
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "d64"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_COMMODORE_64;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "d88"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_PC8800;
|
||||
@ -2320,6 +2334,11 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_NEOGEO_POCKET;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "nib"))
|
||||
{
|
||||
/* also Apple II, but both are full-file hashes */
|
||||
iterator->consoles[0] = RC_CONSOLE_COMMODORE_64;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
@ -2332,8 +2351,9 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
case 'r':
|
||||
if (rc_path_compare_extension(ext, "rom"))
|
||||
{
|
||||
/* rom is associated with MSX, Thomson TO-8, and Fairchild Channel F.
|
||||
* Since they all use the same hashing algorithm, only specify one of them */
|
||||
iterator->consoles[0] = RC_CONSOLE_MSX;
|
||||
iterator->consoles[1] = RC_CONSOLE_THOMSONTO8; /* cartridge */
|
||||
}
|
||||
if (rc_path_compare_extension(ext, "ri"))
|
||||
{
|
||||
@ -2393,6 +2413,10 @@ void rc_hash_initialize_iterator(struct rc_hash_iterator* iterator, const char*
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_WONDERSWAN;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "wasm"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_WASM4;
|
||||
}
|
||||
else if (rc_path_compare_extension(ext, "woz"))
|
||||
{
|
||||
iterator->consoles[0] = RC_CONSOLE_APPLE_II;
|
||||
|
@ -331,7 +331,16 @@ bool disk_control_set_eject_state(
|
||||
|
||||
#ifdef HAVE_CHEEVOS
|
||||
if (!error && !eject)
|
||||
rcheevos_change_disc(disk_control->index_record.image_path, false);
|
||||
{
|
||||
if (disk_control->cb.get_image_index && disk_control->cb.get_image_path)
|
||||
{
|
||||
char image_path[PATH_MAX_LENGTH] = "";
|
||||
unsigned image_index = disk_control->cb.get_image_index();
|
||||
|
||||
if (disk_control->cb.get_image_path(image_index, image_path, sizeof(image_path)))
|
||||
rcheevos_change_disc(image_path, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return !error;
|
||||
|
Loading…
Reference in New Issue
Block a user