From 5ecdc4c1701de6435705ebd8193dba411380afe1 Mon Sep 17 00:00:00 2001 From: Jamiras <32680403+Jamiras@users.noreply.github.com> Date: Fri, 27 Jan 2023 06:52:29 -0700 Subject: [PATCH] upgrade to rcheevos 10.6 (#14911) --- cheevos/cheevos.c | 43 ++++ deps/rcheevos/CHANGELOG.md | 64 +++++ deps/rcheevos/include/rc_runtime_types.h | 3 + deps/rcheevos/src/rcheevos/condition.c | 284 ++++++++++++++++++++++- deps/rcheevos/src/rcheevos/memref.c | 2 +- deps/rcheevos/src/rcheevos/rc_internal.h | 16 ++ deps/rcheevos/src/rcheevos/rc_libretro.c | 9 +- deps/rcheevos/src/rcheevos/trigger.c | 15 +- deps/rcheevos/src/rhash/hash.c | 9 +- 9 files changed, 432 insertions(+), 13 deletions(-) diff --git a/cheevos/cheevos.c b/cheevos/cheevos.c index 86de1fb118..ac5a648bf6 100644 --- a/cheevos/cheevos.c +++ b/cheevos/cheevos.c @@ -672,6 +672,7 @@ bool rcheevos_unload(void) if (rcheevos_locals.loaded) { + unsigned count = 0; #ifdef HAVE_MENU rcheevos_menu_reset_badges(); @@ -684,6 +685,45 @@ bool rcheevos_unload(void) } #endif + count = rcheevos_locals.game.achievement_count; + rcheevos_locals.game.achievement_count = 0; + if (rcheevos_locals.game.achievements) + { + rcheevos_racheevo_t* achievement = rcheevos_locals.game.achievements; + rcheevos_racheevo_t* end = achievement + count; + while (achievement < end) + { + CHEEVOS_FREE(achievement->title); + CHEEVOS_FREE(achievement->description); + CHEEVOS_FREE(achievement->badge); + CHEEVOS_FREE(achievement->memaddr); + + ++achievement; + } + + CHEEVOS_FREE(rcheevos_locals.game.achievements); + rcheevos_locals.game.achievements = NULL; + } + + count = rcheevos_locals.game.leaderboard_count; + rcheevos_locals.game.leaderboard_count = 0; + if (rcheevos_locals.game.leaderboards) + { + rcheevos_ralboard_t* lboard = rcheevos_locals.game.leaderboards; + rcheevos_ralboard_t* end = lboard + count; + while (lboard < end) + { + CHEEVOS_FREE(lboard->title); + CHEEVOS_FREE(lboard->description); + CHEEVOS_FREE(lboard->mem); + + ++lboard; + } + + CHEEVOS_FREE(rcheevos_locals.game.leaderboards); + rcheevos_locals.game.leaderboards = NULL; + } + if (rcheevos_locals.game.title) { CHEEVOS_FREE(rcheevos_locals.game.title); @@ -1535,6 +1575,9 @@ static void rcheevos_show_game_placard(void) int number_of_core = 0; int mode = RCHEEVOS_ACTIVE_SOFTCORE; + if (rcheevos_locals.game.id < 0) /* make sure there's actually a game loaded */ + return; + if (rcheevos_locals.hardcore_active) mode = RCHEEVOS_ACTIVE_HARDCORE; diff --git a/deps/rcheevos/CHANGELOG.md b/deps/rcheevos/CHANGELOG.md index 99af21020f..b40205b3be 100644 --- a/deps/rcheevos/CHANGELOG.md +++ b/deps/rcheevos/CHANGELOG.md @@ -1,3 +1,67 @@ +# v10.6.0 +* add RC_RUNTIME_EVENT_ACHIEVEMENT_PROGRESS_UPDATED +* use optimized comparators for most common condition logic +* fix game identification of psx ISOs that have extra slashes in their boot path +* fix game identification of ndd files + +# v10.5.0 +* add RC_MEMSIZE_MBF32_LE +* add RC_OPERATOR_XOR +* add RC_CONSOLE_ATARI_JAGUAR_CD and hash/memory map for Atari Jaguar CD +* add RC_CONSOLE_ARCADIA_2001 and hash/memory map for Arcadia 2001 +* add RC_CONSOLE_INTERTON_VC_4000 and hash/memory map for Interton VC 4000 +* add RC_CONSOLE_ELEKTOR_TV_GAMES_COMPUTER and hash/memory map for Elektor TV Games Computer +* split RC_CONSOLE_PC_ENGINE_CD off of RC_CONSOLE_PC_ENGINE +* add hash/memory map for RC_CONSOLE_NEO_GEO_CD +* add additional 256KB of RAM to memory map for RC_CONSOLE_SEGA_32X +* validation: don't report redundancy between trigger and non-trigger conditions +* validation: don't report range validation errors for float comparisons +* change default image host to media.retroachievements.org +* fix decoding of denormalized floats +* fix full line comments in the middle of Display: section causing RC_MISSING_DISPLAY_STRING + +# v10.4.0 +* add rc_libretro_hash_set_t with support for #SAVEDISK: m3u extension +* add rc_libretro_is_system_allowed for finer-grain control over core support +* fix measured value from hitcount not resetting while paused +* add RC_CONSOLE_WASM and hash/memory map for WASM-4 +* add scratchpad memory to RC_CONSOLE_PLAYSTATION_2 memory map +* add hash/memory map for RC_CONSOLE_FAIRCHILD_CHANNEL_F +* add hash/memory map for RC_CONSOLE_COMMODORE_64 +* add memory map for RC_CONSOLE_AMIGA + +# v10.3.3 +* add RC_CONSOLE_ARDUBOY and hash/memory map for Arduboy +* add display_name to rc_api_login_response_t +* detect logical conflicts and redundancies in validator +* fix tab sequences in JSON responses being turned into t +* fix overflow when float value has more than 9 digits after the decimal +* fix libretro memory mapping when disconnect mask breaks a region into multiple blocks +* fix non-virtualized file system call when reading some iso files + +# v10.3.2 +* fix RC_OPERAND_PRIOR for bit sizes other than RC_MEMSIZE_BIT_0 +* add memory map and hash for Amstrad CPC +* fix an issue where fetch_game_data and fetch_user_unlocks could return RC_MISSING_VALUE instead of acknowledging a server error + +# v10.3.1 +* allow empty description in rc_api_init_update_leaderboard_request +* fix buffered n64 hash when no filereader is registered +* add memory map and hash for Mega Duck + +# v10.3.0 +* support for floating point memory sizes and logic +* add built-in macros for rich presence: @Number, @Score, @Centisecs, @Seconds, @Minutes, @ASCIIChar, @UnicodeChar +* add rapi functions for fetch_code_notes, update_code_note, upload_achievement, update_leaderboard, fetch_badge_range, and add_game_hash +* add lower_is_better and hidden flags to leaderboards in rc_api_fetch_game_data_response_t +* add achievements_remaining to rc_api_award_achievement_response_t +* add console enums for PC6000, PICO, MEGADUCK and ZEEBO +* add memory map for Dreamcast +* capture leaderboard/rich presence state in rc_runtime_progress data +* support for hashing Dreamcast bin/cues +* support for hashing buffered NDS ROMs +* fix prior for sizes smaller than a byte sometimes returning current value + # v10.2.0 * add RC_MEMSIZE_16_BITS_BE, RC_MEMSIZE_24_BITS_BE, and RC_MEMSIZE_32_BITS_BE diff --git a/deps/rcheevos/include/rc_runtime_types.h b/deps/rcheevos/include/rc_runtime_types.h index 8b519e1ce1..dc3ab60c92 100644 --- a/deps/rcheevos/include/rc_runtime_types.h +++ b/deps/rcheevos/include/rc_runtime_types.h @@ -200,6 +200,9 @@ struct rc_condition_t { /* Whether or not the condition evaluated true on the last check */ char is_true; + + /* Unique identifier of optimized comparator to use */ + char optimized_comparator; }; /*****************************************************************************\ diff --git a/deps/rcheevos/src/rcheevos/condition.c b/deps/rcheevos/src/rcheevos/condition.c index fb8caec0f4..55a8084e71 100644 --- a/deps/rcheevos/src/rcheevos/condition.c +++ b/deps/rcheevos/src/rcheevos/condition.c @@ -1,6 +1,91 @@ #include "rc_internal.h" #include +#include + +static int rc_test_condition_compare(unsigned value1, unsigned value2, char oper) { + switch (oper) { + case RC_OPERATOR_EQ: return value1 == value2; + case RC_OPERATOR_NE: return value1 != value2; + case RC_OPERATOR_LT: return value1 < value2; + case RC_OPERATOR_LE: return value1 <= value2; + case RC_OPERATOR_GT: return value1 > value2; + case RC_OPERATOR_GE: return value1 >= value2; + default: return 1; + } +} + +static char rc_condition_determine_comparator(const rc_condition_t* self) { + switch (self->oper) { + case RC_OPERATOR_EQ: + case RC_OPERATOR_NE: + case RC_OPERATOR_LT: + case RC_OPERATOR_LE: + case RC_OPERATOR_GT: + case RC_OPERATOR_GE: + break; + + default: + /* not a comparison. should not be getting compared. but if it is, legacy behavior was to return 1 */ + return RC_PROCESSING_COMPARE_ALWAYS_TRUE; + } + + if ((self->operand1.type == RC_OPERAND_ADDRESS || self->operand1.type == RC_OPERAND_DELTA) && + !self->operand1.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand1)) { + /* left side is an integer memory reference */ + int needs_translate = (self->operand1.size != self->operand1.value.memref->value.size); + + if (self->operand2.type == RC_OPERAND_CONST) { + /* right side is a constant */ + if (self->operand1.type == RC_OPERAND_ADDRESS) + return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_CONST; + + return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_CONST; + } + else if ((self->operand2.type == RC_OPERAND_ADDRESS || self->operand2.type == RC_OPERAND_DELTA) && + !self->operand2.value.memref->value.is_indirect && !rc_operand_is_float(&self->operand2)) { + /* right side is an integer memory reference */ + const int is_same_memref = (self->operand1.value.memref == self->operand2.value.memref); + needs_translate |= (self->operand2.size != self->operand2.value.memref->value.size); + + if (self->operand1.type == RC_OPERAND_ADDRESS) { + if (self->operand2.type == RC_OPERAND_ADDRESS) { + if (is_same_memref && !needs_translate) { + /* comparing a memref to itself, will evaluate to a constant */ + return rc_test_condition_compare(0, 0, self->oper) ? RC_PROCESSING_COMPARE_ALWAYS_TRUE : RC_PROCESSING_COMPARE_ALWAYS_FALSE; + } + + return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF; + } + + assert(self->operand2.type == RC_OPERAND_DELTA); + + if (is_same_memref) { + /* delta comparison is optimized to compare with itself (for detecting change) */ + return needs_translate ? RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED : RC_PROCESSING_COMPARE_MEMREF_TO_DELTA; + } + } + else { + assert(self->operand1.type == RC_OPERAND_DELTA); + + if (self->operand2.type == RC_OPERAND_ADDRESS) { + if (is_same_memref) { + /* delta comparison is optimized to compare with itself (for detecting change) */ + return needs_translate ? RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED : RC_PROCESSING_COMPARE_DELTA_TO_MEMREF; + } + } + } + } + } + + if (self->operand1.type == RC_OPERAND_CONST && self->operand2.type == RC_OPERAND_CONST) { + /* comparing constants will always generate a constant result */ + return rc_test_condition_compare(self->operand1.value.num, self->operand2.value.num, self->oper) ? + RC_PROCESSING_COMPARE_ALWAYS_TRUE : RC_PROCESSING_COMPARE_ALWAYS_FALSE; + } + + return RC_PROCESSING_COMPARE_DEFAULT; +} static int rc_parse_operator(const char** memaddr) { const char* oper = *memaddr; @@ -75,6 +160,7 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse self->current_hits = 0; self->is_true = 0; self->pause = 0; + self->optimized_comparator = RC_PROCESSING_COMPARE_DEFAULT; if (*aux != 0 && aux[1] == ':') { switch (*aux) { @@ -214,6 +300,9 @@ rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse self->required_hits = 0; } + if (parse->buffer != 0) + self->optimized_comparator = rc_condition_determine_comparator(self); + *memaddr = aux; return self; } @@ -233,12 +322,203 @@ int rc_condition_is_combining(const rc_condition_t* self) { } } +static int rc_test_condition_compare_memref_to_const(rc_condition_t* self) { + const unsigned value1 = self->operand1.value.memref->value.value; + const unsigned value2 = self->operand2.value.num; + assert(self->operand1.size == self->operand1.value.memref->value.size); + return rc_test_condition_compare(value1, value2, self->oper); +} + +static int rc_test_condition_compare_delta_to_const(rc_condition_t* self) { + const rc_memref_value_t* memref1 = &self->operand1.value.memref->value; + const unsigned value1 = (memref1->changed) ? memref1->prior : memref1->value; + const unsigned value2 = self->operand2.value.num; + assert(self->operand1.size == self->operand1.value.memref->value.size); + return rc_test_condition_compare(value1, value2, self->oper); +} + +static int rc_test_condition_compare_memref_to_memref(rc_condition_t* self) { + const unsigned value1 = self->operand1.value.memref->value.value; + const unsigned value2 = self->operand2.value.memref->value.value; + assert(self->operand1.size == self->operand1.value.memref->value.size); + assert(self->operand2.size == self->operand2.value.memref->value.size); + return rc_test_condition_compare(value1, value2, self->oper); +} + +static int rc_test_condition_compare_memref_to_delta(rc_condition_t* self) { + const rc_memref_value_t* memref = &self->operand1.value.memref->value; + assert(self->operand1.value.memref == self->operand2.value.memref); + assert(self->operand1.size == self->operand1.value.memref->value.size); + assert(self->operand2.size == self->operand2.value.memref->value.size); + + if (memref->changed) + return rc_test_condition_compare(memref->value, memref->prior, self->oper); + + switch (self->oper) { + case RC_OPERATOR_EQ: + case RC_OPERATOR_GE: + case RC_OPERATOR_LE: + return 1; + + default: + return 0; + } +} + +static int rc_test_condition_compare_delta_to_memref(rc_condition_t* self) { + const rc_memref_value_t* memref = &self->operand1.value.memref->value; + assert(self->operand1.value.memref == self->operand2.value.memref); + assert(self->operand1.size == self->operand1.value.memref->value.size); + assert(self->operand2.size == self->operand2.value.memref->value.size); + + if (memref->changed) + return rc_test_condition_compare(memref->prior, memref->value, self->oper); + + switch (self->oper) { + case RC_OPERATOR_EQ: + case RC_OPERATOR_GE: + case RC_OPERATOR_LE: + return 1; + + default: + return 0; + } +} + +static int rc_test_condition_compare_memref_to_const_transformed(rc_condition_t* self) { + rc_typed_value_t value1; + const unsigned value2 = self->operand2.value.num; + + value1.type = RC_VALUE_TYPE_UNSIGNED; + value1.value.u32 = self->operand1.value.memref->value.value; + rc_transform_memref_value(&value1, self->operand1.size); + + return rc_test_condition_compare(value1.value.u32, value2, self->oper); +} + +static int rc_test_condition_compare_delta_to_const_transformed(rc_condition_t* self) { + rc_typed_value_t value1; + const rc_memref_value_t* memref1 = &self->operand1.value.memref->value; + const unsigned value2 = self->operand2.value.num; + + value1.type = RC_VALUE_TYPE_UNSIGNED; + value1.value.u32 = (memref1->changed) ? memref1->prior : memref1->value; + rc_transform_memref_value(&value1, self->operand1.size); + + return rc_test_condition_compare(value1.value.u32, value2, self->oper); +} + +static int rc_test_condition_compare_memref_to_memref_transformed(rc_condition_t* self) { + rc_typed_value_t value1, value2; + + value1.type = RC_VALUE_TYPE_UNSIGNED; + value1.value.u32 = self->operand1.value.memref->value.value; + rc_transform_memref_value(&value1, self->operand1.size); + + value2.type = RC_VALUE_TYPE_UNSIGNED; + value2.value.u32 = self->operand2.value.memref->value.value; + rc_transform_memref_value(&value2, self->operand2.size); + + return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper); +} + +static int rc_test_condition_compare_memref_to_delta_transformed(rc_condition_t* self) { + const rc_memref_value_t* memref = &self->operand1.value.memref->value; + assert(self->operand1.value.memref == self->operand2.value.memref); + + if (memref->changed) { + rc_typed_value_t value1, value2; + + value1.type = RC_VALUE_TYPE_UNSIGNED; + value1.value.u32 = memref->value; + rc_transform_memref_value(&value1, self->operand1.size); + + value2.type = RC_VALUE_TYPE_UNSIGNED; + value2.value.u32 = memref->prior; + rc_transform_memref_value(&value2, self->operand2.size); + + return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper); + } + + switch (self->oper) { + case RC_OPERATOR_EQ: + case RC_OPERATOR_GE: + case RC_OPERATOR_LE: + return 1; + + default: + return 0; + } +} + +static int rc_test_condition_compare_delta_to_memref_transformed(rc_condition_t* self) { + const rc_memref_value_t* memref = &self->operand1.value.memref->value; + assert(self->operand1.value.memref == self->operand2.value.memref); + + if (memref->changed) { + rc_typed_value_t value1, value2; + + value1.type = RC_VALUE_TYPE_UNSIGNED; + value1.value.u32 = memref->prior; + rc_transform_memref_value(&value1, self->operand1.size); + + value2.type = RC_VALUE_TYPE_UNSIGNED; + value2.value.u32 = memref->value; + rc_transform_memref_value(&value2, self->operand2.size); + + return rc_test_condition_compare(value1.value.u32, value2.value.u32, self->oper); + } + + switch (self->oper) { + case RC_OPERATOR_EQ: + case RC_OPERATOR_GE: + case RC_OPERATOR_LE: + return 1; + + default: + return 0; + } +} + int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state) { rc_typed_value_t value1, value2; - rc_evaluate_operand(&value1, &self->operand1, eval_state); - if (eval_state->add_value.type != RC_VALUE_TYPE_NONE) + if (eval_state->add_value.type != RC_VALUE_TYPE_NONE) { + /* if there's an accumulator, we can't use the optimized comparators */ + rc_evaluate_operand(&value1, &self->operand1, eval_state); rc_typed_value_add(&value1, &eval_state->add_value); + } else { + /* use an optimized comparator whenever possible */ + switch (self->optimized_comparator) { + case RC_PROCESSING_COMPARE_MEMREF_TO_CONST: + return rc_test_condition_compare_memref_to_const(self); + case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA: + return rc_test_condition_compare_memref_to_delta(self); + case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF: + return rc_test_condition_compare_memref_to_memref(self); + case RC_PROCESSING_COMPARE_DELTA_TO_CONST: + return rc_test_condition_compare_delta_to_const(self); + case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF: + return rc_test_condition_compare_delta_to_memref(self); + case RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED: + return rc_test_condition_compare_memref_to_const_transformed(self); + case RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED: + return rc_test_condition_compare_memref_to_delta_transformed(self); + case RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED: + return rc_test_condition_compare_memref_to_memref_transformed(self); + case RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED: + return rc_test_condition_compare_delta_to_const_transformed(self); + case RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED: + return rc_test_condition_compare_delta_to_memref_transformed(self); + case RC_PROCESSING_COMPARE_ALWAYS_TRUE: + return 1; + case RC_PROCESSING_COMPARE_ALWAYS_FALSE: + return 0; + default: + rc_evaluate_operand(&value1, &self->operand1, eval_state); + break; + } + } rc_evaluate_operand(&value2, &self->operand2, eval_state); diff --git a/deps/rcheevos/src/rcheevos/memref.c b/deps/rcheevos/src/rcheevos/memref.c index 545f388b45..964f68490d 100644 --- a/deps/rcheevos/src/rcheevos/memref.c +++ b/deps/rcheevos/src/rcheevos/memref.c @@ -444,7 +444,7 @@ void rc_init_parse_state_memrefs(rc_parse_state_t* parse, rc_memref_t** memrefs) *memrefs = 0; } -static unsigned rc_get_memref_value_value(rc_memref_value_t* memref, int operand_type) { +static unsigned rc_get_memref_value_value(const rc_memref_value_t* memref, int operand_type) { switch (operand_type) { /* most common case explicitly first, even though it could be handled by default case. diff --git a/deps/rcheevos/src/rcheevos/rc_internal.h b/deps/rcheevos/src/rcheevos/rc_internal.h index c764714e3c..66a6aebe6a 100644 --- a/deps/rcheevos/src/rcheevos/rc_internal.h +++ b/deps/rcheevos/src/rcheevos/rc_internal.h @@ -146,6 +146,22 @@ rc_condset_t* rc_parse_condset(const char** memaddr, rc_parse_state_t* parse, in int rc_test_condset(rc_condset_t* self, rc_eval_state_t* eval_state); void rc_reset_condset(rc_condset_t* self); +enum { + RC_PROCESSING_COMPARE_DEFAULT = 0, + RC_PROCESSING_COMPARE_MEMREF_TO_CONST, + RC_PROCESSING_COMPARE_MEMREF_TO_DELTA, + RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF, + RC_PROCESSING_COMPARE_DELTA_TO_MEMREF, + RC_PROCESSING_COMPARE_DELTA_TO_CONST, + RC_PROCESSING_COMPARE_MEMREF_TO_CONST_TRANSFORMED, + RC_PROCESSING_COMPARE_MEMREF_TO_DELTA_TRANSFORMED, + RC_PROCESSING_COMPARE_MEMREF_TO_MEMREF_TRANSFORMED, + RC_PROCESSING_COMPARE_DELTA_TO_MEMREF_TRANSFORMED, + RC_PROCESSING_COMPARE_DELTA_TO_CONST_TRANSFORMED, + RC_PROCESSING_COMPARE_ALWAYS_TRUE, + RC_PROCESSING_COMPARE_ALWAYS_FALSE +}; + rc_condition_t* rc_parse_condition(const char** memaddr, rc_parse_state_t* parse, int is_indirect); int rc_test_condition(rc_condition_t* self, rc_eval_state_t* eval_state); void rc_evaluate_condition_value(rc_typed_value_t* value, rc_condition_t* self, rc_eval_state_t* eval_state); diff --git a/deps/rcheevos/src/rcheevos/rc_libretro.c b/deps/rcheevos/src/rcheevos/rc_libretro.c index 42b76579d2..440d63fca4 100644 --- a/deps/rcheevos/src/rcheevos/rc_libretro.c +++ b/deps/rcheevos/src/rcheevos/rc_libretro.c @@ -129,6 +129,12 @@ static const rc_disallowed_setting_t _rc_disallowed_snes9x_settings[] = { { NULL, NULL } }; +static const rc_disallowed_setting_t _rc_disallowed_vice_settings[] = { + { "vice_autostart", "disabled" }, /* autostart dictates initial load and reset from menu */ + { "vice_reset", "!autostart" }, /* reset dictates behavior when pressing reset button (END) */ + { NULL, NULL } +}; + static const rc_disallowed_setting_t _rc_disallowed_virtual_jaguar_settings[] = { { "virtualjaguar_pal", "enabled" }, { NULL, NULL } @@ -152,6 +158,7 @@ static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = { { "QUASI88", _rc_disallowed_quasi88_settings }, { "SMS Plus GX", _rc_disallowed_smsplus_settings }, { "Snes9x", _rc_disallowed_snes9x_settings }, + { "VICE x64", _rc_disallowed_vice_settings }, { "Virtual Jaguar", _rc_disallowed_virtual_jaguar_settings }, { NULL, NULL } }; @@ -613,7 +620,7 @@ void rc_libretro_hash_set_init(struct rc_libretro_hash_set_t* hash_set, char image_path[1024]; char* m3u_contents; char* ptr; - size_t file_len; + int64_t file_len; void* file_handle; int index = 0; diff --git a/deps/rcheevos/src/rcheevos/trigger.c b/deps/rcheevos/src/rcheevos/trigger.c index dda918b536..f310d29f3e 100644 --- a/deps/rcheevos/src/rcheevos/trigger.c +++ b/deps/rcheevos/src/rcheevos/trigger.c @@ -197,14 +197,6 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State* self->measured_value = eval_state.measured_value.value.u32; } - /* if the state is WAITING and the trigger is ready to fire, ignore it and reset the hit counts */ - /* otherwise, if the state is WAITING, proceed to activating the trigger */ - if (self->state == RC_TRIGGER_STATE_WAITING && ret) { - rc_reset_trigger(self); - self->has_hits = 0; - return RC_TRIGGER_STATE_WAITING; - } - /* if any ResetIf condition was true, reset the hit counts */ if (eval_state.was_reset) { /* if the measured value came from a hit count, reset it. do this before calling @@ -247,6 +239,13 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, lua_State* is_primed = 0; } else if (ret) { + /* if the state is WAITING and the trigger is ready to fire, ignore it and reset the hit counts */ + if (self->state == RC_TRIGGER_STATE_WAITING) { + rc_reset_trigger(self); + self->has_hits = 0; + return RC_TRIGGER_STATE_WAITING; + } + /* trigger was triggered */ self->state = RC_TRIGGER_STATE_TRIGGERED; return RC_TRIGGER_STATE_TRIGGERED; diff --git a/deps/rcheevos/src/rhash/hash.c b/deps/rcheevos/src/rhash/hash.c index 249f811c64..f8ee4fceb2 100644 --- a/deps/rcheevos/src/rhash/hash.c +++ b/deps/rcheevos/src/rhash/hash.c @@ -230,6 +230,10 @@ static uint32_t rc_cd_find_file_sector(void* track_handle, const char* path, uns if (!track_handle) return 0; + /* we start at the root. don't need to explicitly find it */ + if (*path == '\\') + ++path; + filename_length = strlen(path); slash = strrchr(path, '\\'); if (slash) @@ -966,6 +970,9 @@ static int rc_hash_n64(char hash[33], const char* path) rc_hash_verbose("converting n64 to z64"); is_n64 = 1; } + else if (buffer[0] == 0xE8 || buffer[0] == 0x22) /* ndd format (don't byteswap) */ + { + } else { free(buffer); @@ -1469,7 +1476,7 @@ static int rc_hash_find_playstation_executable(void* track_handle, const char* b if (strncmp(ptr, cdrom_prefix, cdrom_prefix_len) == 0) ptr += cdrom_prefix_len; - if (*ptr == '\\') + while (*ptr == '\\') ++ptr; start = ptr;