dep/rcheevos: Bump to 9aa1352

This commit is contained in:
Stenzek
2025-12-07 19:10:36 +10:00
parent de01bf704e
commit 6070bff9f6
14 changed files with 675 additions and 281 deletions

View File

@@ -11,5 +11,7 @@ insert_final_newline = true
charset = latin1
indent_style = space
indent_size = 2
continuation_indent_size = 4
trim_trailing_whitespace = true
curly_bracket_next_line = false
indent_brace_style = K&R

View File

@@ -63,3 +63,6 @@ test/galaga_nes.h
test/smw_snes.h
validator/validator
.vscode/*
# Swift Package Manager
.swiftpm/

View File

@@ -1,3 +1,19 @@
# v12.1.0
* add rc_client_get_user_subset_summary
* add validation warning for using MeasuredIf without Measured
* add validation warning for using ResetIf without hit targets
* add rapi function for update_rich_presence
* add gap to RC_CONSOLE_WII memory map to make it easier to convert pointers
* improve range validation logic
* fix error Remembering float value
* fix MeasuredIf evaluation in rich presence
* fix parsing of code notes with addresses above 0x7FFFFFFF
* fix double evaluation of rich presence parameters
* fix validation of SubSource chain
* fix error if rc_client_allow_background_memory_reads called before calling rc_client_begin_load_raintegration
* fix memory corruption when mixing legacy and new-format macros in rich presence
* fix invalid pointer reference when iterator gets cloned
# v12.0.0
* rc_client changes
* add RC_CLIENT_EVENT_SUBSET_COMPLETED event

View File

@@ -173,6 +173,8 @@ enum {
RC_OPERATOR_SUB,
RC_OPERATOR_SUB_PARENT, /* internal use */
RC_OPERATOR_ADD_ACCUMULATOR, /* internal use */
RC_OPERATOR_SUB_ACCUMULATOR, /* internal use */
RC_OPERATOR_INDIRECT_READ /* internal use */
};

View File

@@ -1726,10 +1726,13 @@ static void rc_client_activate_game(rc_client_load_state_t* load_state, rc_api_s
/* make the loaded game active if another game is not aleady being loaded. */
rc_mutex_lock(&client->state.mutex);
if (client->state.load == load_state)
if (client->state.load == load_state) {
client->game = load_state->game;
else
client->state.frames_processed = client->state.frames_at_last_ping = 0;
}
else {
load_state->progress = RC_CLIENT_LOAD_GAME_STATE_ABORTED;
}
rc_mutex_unlock(&client->state.mutex);
if (load_state->progress != RC_CLIENT_LOAD_GAME_STATE_ABORTED) {
@@ -2358,6 +2361,7 @@ static int rc_client_attach_load_state(rc_client_t* client, rc_client_load_state
rc_mutex_lock(&client->state.mutex);
client->state.load = load_state;
client->state.frames_processed = client->state.frames_at_last_ping = 0;
rc_mutex_unlock(&client->state.mutex);
}
else if (client->state.load != load_state) {
@@ -5192,30 +5196,37 @@ static void rc_client_ping(rc_client_scheduled_callback_data_t* callback_data, r
char buffer[256];
int result;
if (!client->callbacks.rich_presence_override ||
!client->callbacks.rich_presence_override(client, buffer, sizeof(buffer))) {
rc_mutex_lock(&client->state.mutex);
/* if no frames have been processed since the last ping, the emulator is idle. let the
* server session expire. it will be resumed/restarted once frames start getting
* processed again. */
if (client->state.frames_processed != client->state.frames_at_last_ping) {
client->state.frames_at_last_ping = client->state.frames_processed;
rc_runtime_get_richpresence(&client->game->runtime, buffer, sizeof(buffer),
client->state.legacy_peek, client, NULL);
if (!client->callbacks.rich_presence_override ||
!client->callbacks.rich_presence_override(client, buffer, sizeof(buffer))) {
rc_mutex_lock(&client->state.mutex);
rc_mutex_unlock(&client->state.mutex);
}
rc_runtime_get_richpresence(&client->game->runtime, buffer, sizeof(buffer),
client->state.legacy_peek, client, NULL);
memset(&api_params, 0, sizeof(api_params));
api_params.username = client->user.username;
api_params.api_token = client->user.token;
api_params.game_id = client->game->public_.id;
api_params.rich_presence = buffer;
api_params.game_hash = client->game->public_.hash;
api_params.hardcore = client->state.hardcore;
rc_mutex_unlock(&client->state.mutex);
}
result = rc_api_init_ping_request_hosted(&request, &api_params, &client->state.host);
if (result != RC_OK) {
RC_CLIENT_LOG_WARN_FORMATTED(client, "Error generating ping request: %s", rc_error_str(result));
}
else {
client->callbacks.server_call(&request, rc_client_ping_callback, client, client);
memset(&api_params, 0, sizeof(api_params));
api_params.username = client->user.username;
api_params.api_token = client->user.token;
api_params.game_id = client->game->public_.id;
api_params.rich_presence = buffer;
api_params.game_hash = client->game->public_.hash;
api_params.hardcore = client->state.hardcore;
result = rc_api_init_ping_request_hosted(&request, &api_params, &client->state.host);
if (result != RC_OK) {
RC_CLIENT_LOG_WARN_FORMATTED(client, "Error generating ping request: %s", rc_error_str(result));
}
else {
client->callbacks.server_call(&request, rc_client_ping_callback, client, client);
}
}
callback_data->when = now + 120 * 1000;
@@ -5929,6 +5940,8 @@ void rc_client_do_frame(rc_client_t* client)
rc_mutex_unlock(&client->state.mutex);
rc_client_raise_pending_events(client, client->game);
++client->state.frames_processed;
}
/* we've processed a frame. if there's a pause delay in effect, process it */

View File

@@ -316,6 +316,8 @@ typedef struct rc_client_state_t {
rc_client_raintegration_t* raintegration;
#endif
uint32_t frames_processed;
uint32_t frames_at_last_ping;
uint16_t unpaused_frame_decay;
uint16_t required_unpaused_frames;

View File

@@ -374,7 +374,7 @@ void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t
memcpy(&parse->addsource_parent, &cond_operand, sizeof(cond_operand));
}
parse->addsource_oper = RC_OPERATOR_ADD;
parse->addsource_oper = RC_OPERATOR_ADD_ACCUMULATOR;
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
@@ -388,13 +388,13 @@ void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t
/* type determined by parent */
const uint8_t new_size = rc_operand_is_float(&parse->addsource_parent) ? RC_MEMSIZE_FLOAT : RC_MEMSIZE_32_BITS;
if (parse->addsource_oper == RC_OPERATOR_ADD && !rc_operand_is_memref(&parse->addsource_parent)) {
if (parse->addsource_oper == RC_OPERATOR_ADD_ACCUMULATOR && !rc_operand_is_memref(&parse->addsource_parent)) {
/* if the previous element was a constant we have to turn it into a memref by adding zero */
rc_modified_memref_t* memref;
rc_operand_t zero;
rc_operand_set_const(&zero, 0);
memref = rc_alloc_modified_memref(parse,
parse->addsource_parent.size, &parse->addsource_parent, RC_OPERATOR_ADD, &zero);
parse->addsource_parent.size, &parse->addsource_parent, RC_OPERATOR_ADD_ACCUMULATOR, &zero);
parse->addsource_parent.value.memref = (rc_memref_t*)memref;
parse->addsource_parent.type = RC_OPERAND_ADDRESS;
}
@@ -414,19 +414,27 @@ void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t
}
/* subtract the condition from the chain */
parse->addsource_oper = rc_operand_is_memref(&parse->addsource_parent) ? RC_OPERATOR_SUB : RC_OPERATOR_SUB_PARENT;
parse->addsource_oper = rc_operand_is_memref(&parse->addsource_parent) ? RC_OPERATOR_SUB_ACCUMULATOR : RC_OPERATOR_SUB_PARENT;
rc_condition_convert_to_operand(condition, &cond_operand, parse);
rc_operand_addsource(&cond_operand, parse, new_size);
memcpy(&parse->addsource_parent, &cond_operand, sizeof(cond_operand));
/* indicate the next value can be added to the chain */
parse->addsource_oper = RC_OPERATOR_ADD;
parse->addsource_oper = RC_OPERATOR_ADD_ACCUMULATOR;
}
parse->indirect_parent.type = RC_OPERAND_NONE;
break;
case RC_CONDITION_REMEMBER:
if (condition->operand1.type == RC_OPERAND_RECALL &&
condition->oper == RC_OPERATOR_NONE &&
parse->addsource_parent.type == RC_OPERAND_NONE &&
parse->indirect_parent.type == RC_OPERAND_NONE) {
/* Remembering {recall} without any modifications is a no-op */
break;
}
rc_condition_convert_to_operand(condition, &condition->operand1, parse);
if (parse->addsource_parent.type != RC_OPERAND_NONE) {
@@ -465,6 +473,9 @@ void rc_condition_update_parse_state(rc_condition_t* condition, rc_parse_state_t
default:
if (parse->addsource_parent.type != RC_OPERAND_NONE) {
/* type determined by leaf */
if (parse->addsource_oper == RC_OPERATOR_ADD_ACCUMULATOR)
parse->addsource_oper = RC_OPERATOR_ADD;
rc_operand_addsource(&condition->operand1, parse, condition->operand1.size);
condition->operand1.is_combining = 1;

View File

@@ -62,8 +62,10 @@ static int32_t rc_classify_conditions(rc_condset_t* self, const char* memaddr, c
do {
rc_parse_condition_internal(&condition, &memaddr, &parse);
if (parse.offset < 0)
if (parse.offset < 0) {
rc_destroy_parse_state(&parse);
return parse.offset;
}
++index;
@@ -106,7 +108,9 @@ static int32_t rc_classify_conditions(rc_condset_t* self, const char* memaddr, c
* logic in rc_find_next_classification */
self->num_other_conditions += chain_length - 1;
return index;
rc_destroy_parse_state(&parse);
return (int32_t)index;
}
static int rc_find_next_classification(const char* memaddr) {

View File

@@ -154,8 +154,14 @@ rc_modified_memref_t* rc_alloc_modified_memref(rc_parse_state_t* parse, uint8_t
memcpy(&modified_memref->parent, parent, sizeof(modified_memref->parent));
memcpy(&modified_memref->modifier, modifier, sizeof(modified_memref->modifier));
modified_memref->modifier_type = modifier_type;
modified_memref->depth = 0;
modified_memref->memref.address = rc_operand_is_memref(modifier) ? modifier->value.memref->address : modifier->value.num;
if (rc_operand_is_memref(parent) && parent->value.memref->value.memref_type == RC_MEMREF_TYPE_MODIFIED_MEMREF) {
const rc_modified_memref_t* parent_modified_memref = (rc_modified_memref_t*)parent->value.memref;
modified_memref->depth = parent_modified_memref->depth + 1;
}
return modified_memref;
}
@@ -729,11 +735,34 @@ uint32_t rc_get_modified_memref_value(const rc_modified_memref_t* memref, rc_pee
break;
case RC_OPERATOR_SUB_PARENT:
/* sub parent is "-parent + modifier" */
rc_typed_value_negate(&value);
rc_typed_value_add(&value, &modifier);
rc_typed_value_convert(&value, memref->memref.value.type);
break;
case RC_OPERATOR_SUB_ACCUMULATOR:
rc_typed_value_negate(&modifier);
/* fallthrough */ /* to case RC_OPERATOR_SUB_ACCUMULATOR */
case RC_OPERATOR_ADD_ACCUMULATOR:
/* when modifying the accumulator, force the modifier to match the accumulator
* type instead of promoting them both to the less restrictive type.
*
* 18 - 17.5 will result in an integer. should it be 0 or 1?
*
* default: float is less restrictive, convert both to float for combine,
* then convert to the memref type.
* (int)((float)18 - 17.5) -> (int)(0.5) -> 0
*
* accumulator is integer: force modifier to be integer before combining
* (int)(18 - (int)17.5) -> (int)(18 - 17) -> 1
*/
rc_typed_value_convert(&modifier, value.type);
rc_typed_value_add(&value, &modifier);
rc_typed_value_convert(&value, memref->memref.value.type);
break;
default:
rc_typed_value_combine(&value, &modifier, memref->modifier_type);
rc_typed_value_convert(&value, memref->memref.value.type);

View File

@@ -334,8 +334,11 @@ int rc_operands_are_equal(const rc_operand_t* left, const rc_operand_t* right) {
const rc_modified_memref_t* left_memref = (const rc_modified_memref_t*)left->value.memref;
const rc_modified_memref_t* right_memref = (const rc_modified_memref_t*)right->value.memref;
return (left_memref->modifier_type == right_memref->modifier_type &&
left_memref->depth == right_memref->depth &&
rc_operands_are_equal(&left_memref->modifier, &right_memref->modifier) &&
rc_operands_are_equal(&left_memref->parent, &right_memref->parent) &&
rc_operands_are_equal(&left_memref->modifier, &right_memref->modifier));
1 == 1
);
}
default:

View File

@@ -14,10 +14,11 @@ typedef struct rc_scratch_string {
rc_scratch_string_t;
typedef struct rc_modified_memref_t {
rc_memref_t memref; /* for compatibility with rc_operand_t.value.memref */
rc_memref_t memref; /* For compatibility with rc_operand_t.value.memref */
rc_operand_t parent; /* The parent memref this memref is derived from (type will always be a memref type) */
rc_operand_t modifier; /* The modifier to apply to the parent. */
uint8_t modifier_type; /* How to apply the modifier to the parent. (RC_OPERATOR_*) */
uint16_t depth; /* The number of parents this memref has. */
}
rc_modified_memref_t;
@@ -382,7 +383,6 @@ rc_memrefs_t* rc_richpresence_get_memrefs(rc_richpresence_t* self);
void rc_reset_richpresence_triggers(rc_richpresence_t* self);
void rc_update_richpresence_internal(rc_richpresence_t* richpresence, rc_peek_t peek, void* peek_ud);
int rc_validate_memrefs(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t max_address);
int rc_validate_memrefs_for_console(const rc_memrefs_t* memrefs, char result[], const size_t result_size, uint32_t console_id);
RC_END_C_DECLS

File diff suppressed because it is too large Load Diff

View File

@@ -235,8 +235,14 @@ int rc_evaluate_trigger(rc_trigger_t* self, rc_peek_t peek, void* ud, void* unus
is_paused |= sub_paused;
}
/* if paused, the measured value may not be captured, keep the old value */
if (!is_paused) {
if (is_paused) {
/* if the trigger is fully paused, ignore any updates to the measured value */
}
else if (measured_value.type == RC_VALUE_TYPE_NONE) {
/* if a measured value was not captured, keep the old value (it's possible to pause
* an alt that is generating the measured value without fully pausing the trigger) */
}
else {
rc_typed_value_convert(&measured_value, RC_VALUE_TYPE_UNSIGNED);
self->measured_value = measured_value.value.u32;
}

View File

@@ -67,6 +67,7 @@ static void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_par
next_clause = &self->conditions;
do {
/* count the number of joiners and add one to determine the number of clauses. */
buffer[0] = 'A'; /* reset to AddSource */
done = 0;
num_measured_conditions = 1;
buffer_ptr = *memaddr;
@@ -97,8 +98,8 @@ static void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_par
}
} while (!done);
/* if last condition is SubSource, we'll need to add a dummy condition for the Measured */
if (buffer[0] == 'B')
/* if last condition is not AddSource, we'll need to add a dummy condition for the Measured */
if (buffer[0] != 'A')
++num_measured_conditions;
condset_with_conditions = RC_ALLOC_WITH_TRAILING(rc_condset_with_trailing_conditions_t,
@@ -121,10 +122,18 @@ static void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_par
for (;; ++(*memaddr)) {
switch (**memaddr) {
case '_': /* add next */
*ptr = '\0';
break;
case '$': /* maximum of */
case '\0': /* end of string */
case ':': /* end of leaderboard clause */
case ')': /* end of rich presence macro */
/* the last condition needs to be Measured - AddSource can be changed here,
* SubSource will be handled later */
if (buffer[0] == 'A')
buffer[0] = 'M';
*ptr = '\0';
break;
@@ -176,33 +185,34 @@ static void rc_parse_legacy_value(rc_value_t* self, const char** memaddr, rc_par
return;
}
rc_condition_update_parse_state(cond, parse);
*next = cond;
next = &cond->next;
if (**memaddr != '_') /* add next */
break;
rc_condition_update_parse_state(cond, parse);
++cond;
}
/* end of clause */
if (cond->type == RC_CONDITION_SUB_SOURCE) {
/* cannot change SubSource to Measured. add a dummy condition */
rc_condition_update_parse_state(cond, parse);
if (parse->buffer)
/* -- end of clause -- */
/* clause must end in a Measured. if it doesn't, append one */
if (cond->type != RC_CONDITION_MEASURED) {
if (!parse->buffer)
cond = &local_cond;
else
++cond;
buffer_ptr = "A:0";
buffer_ptr = "M:0";
rc_parse_condition_internal(cond, &buffer_ptr, parse);
*next = cond;
next = &cond->next;
rc_condition_update_parse_state(cond, parse);
}
/* convert final AddSource condition to Measured */
cond->type = RC_CONDITION_MEASURED;
cond->next = NULL;
rc_condition_update_parse_state(cond, parse);
*next = NULL;
/* finalize clause */
*next_clause = condset;