Deps: Update rcheevos to v12.2.0

This commit is contained in:
Stenzek
2025-12-23 19:34:29 +10:00
parent 7bc32cdfa2
commit 9370642434
4 changed files with 145 additions and 32 deletions

View File

@@ -1,3 +1,18 @@
# v12.2.0
* add rc_client_create_subset_list
* add rc_client_begin_fetch_game_titles
* greatly improve performance parsing long AddSource chains
* don't send pings if not processing frames; allows server to suspend session while emulator is paused
* modify validation logic to return most severe error instead of first error found
* improve validation warning when 'PauseIf {recall}' attempts to use non-PauseIf Remember
* fix rounding error when subtracting floats from integers
* fix infinite loop processing 'Remember {recall}' with no modifiers
* fix measured value jumping to 0 if all measured-generating alts are paused
* fix buffer overflow converting long user names between rc_client_external versions
* fix validation warning when adding differently sized values
* fix validation warning when ResetIf only applies to hit count inside an AndNext chain
* fix validation warning when only last node of modified memref chain differs
# v12.1.0
* add rc_client_get_user_subset_summary
* add validation warning for using MeasuredIf without Measured

View File

@@ -1692,6 +1692,67 @@ static void rc_client_free_pending_media(rc_client_pending_media_t* pending_medi
free(pending_media);
}
static void rc_client_log_active_assets(rc_client_t* client)
{
uint32_t num_achievements;
uint32_t num_active_achievements;
uint32_t num_unsupported_achievements;
uint32_t num_leaderboards;
uint32_t num_unsupported_leaderboards;
const rc_client_achievement_info_t* ach;
const rc_client_achievement_info_t* ach_stop;
const rc_client_leaderboard_info_t* lbd;
const rc_client_leaderboard_info_t* lbd_stop;
const rc_client_subset_info_t* subset = client->game->subsets;
for (; subset; subset = subset->next) {
num_achievements = 0;
num_active_achievements = 0;
num_unsupported_achievements = 0;
num_leaderboards = 0;
num_unsupported_leaderboards = 0;
ach = subset->achievements;
ach_stop = ach + subset->public_.num_achievements;
for (; ach < ach_stop; ++ach) {
if (ach->public_.category == RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE) {
++num_achievements;
if (ach->public_.state == RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE)
++num_active_achievements;
else if (ach->public_.state == RC_CLIENT_ACHIEVEMENT_STATE_DISABLED)
++num_unsupported_achievements;
}
}
lbd = subset->leaderboards;
lbd_stop = lbd + subset->public_.num_leaderboards;
for (; lbd < lbd_stop; ++lbd) {
++num_leaderboards;
if (lbd->public_.state == RC_CLIENT_LEADERBOARD_STATE_DISABLED)
++num_unsupported_leaderboards;
}
if (num_unsupported_achievements) {
if (num_unsupported_leaderboards) {
RC_CLIENT_LOG_INFO_FORMATTED(client, "Set %u: %u/%u achievements active (%u unsupported), %u leaderboards (%u unsupported)",
subset->public_.id, num_active_achievements, num_achievements, num_unsupported_achievements, num_leaderboards, num_unsupported_leaderboards);
}
else {
RC_CLIENT_LOG_INFO_FORMATTED(client, "Set %u: %u/%u achievements active (%u unsupported), %u leaderboards",
subset->public_.id, num_active_achievements, num_achievements, num_unsupported_achievements, num_leaderboards);
}
}
else if (num_unsupported_leaderboards) {
RC_CLIENT_LOG_INFO_FORMATTED(client, "Set %u: %u/%u achievements active, %u leaderboards (%u unsupported)",
subset->public_.id, num_active_achievements, num_achievements, num_leaderboards, num_unsupported_leaderboards);
}
else {
RC_CLIENT_LOG_INFO_FORMATTED(client, "Set %u: %u/%u achievements active, %u leaderboards",
subset->public_.id, num_active_achievements, num_achievements, num_leaderboards);
}
}
}
/* NOTE: address validation uses the read_memory callback to make sure the client
* will return data for the requested address. As such, this function must
* respect the `client->state.allow_background_memory_reads setting. Use
@@ -1816,6 +1877,9 @@ static void rc_client_activate_game(rc_client_load_state_t* load_state, rc_api_s
RC_CLIENT_LOG_INFO_FORMATTED(client, "Game %u loaded, hardcore %s%s", load_state->game->public_.id,
client->state.hardcore ? "enabled" : "disabled",
(client->state.spectator_mode != RC_CLIENT_SPECTATOR_MODE_OFF) ? ", spectating" : "");
if (client->state.log_level >= RC_CLIENT_LOG_LEVEL_INFO)
rc_client_log_active_assets(client);
}
else {
RC_CLIENT_LOG_INFO_FORMATTED(client, "Subset %u loaded", load_state->subset->public_.id);

View File

@@ -8,7 +8,7 @@
RC_BEGIN_C_DECLS
#define RCHEEVOS_VERSION_MAJOR 12
#define RCHEEVOS_VERSION_MINOR 1
#define RCHEEVOS_VERSION_MINOR 2
#define RCHEEVOS_VERSION_PATCH 0
#define RCHEEVOS_MAKE_VERSION(major, minor, patch) (major * 1000000 + minor * 1000 + patch)

View File

@@ -16,6 +16,7 @@ enum
/* errors that prevent the achievement from functioning */
RC_VALIDATION_ERR_ADDRESS_OUT_OF_RANGE,
RC_VALIDATION_ERR_RECALL_WITHOUT_REMEMBER,
RC_VALIDATION_ERR_RECALL_BEFORE_REMEMBER,
RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_WITH_MAX,
RC_VALIDATION_ERR_COMPARISON_NEVER_TRUE_INTEGER_TO_FLOAT,
@@ -268,7 +269,14 @@ static int rc_validate_format_error(char buffer[], size_t buffer_size, const rc_
break;
case RC_VALIDATION_ERR_RECALL_BEFORE_REMEMBER:
snprintf(buffer, buffer_size, "Recall used before Remember");
if (error->data1 == RC_CONDITION_PAUSE_IF)
snprintf(buffer, buffer_size, "PauseIf cannot use Remembered value not associated to PauseIf chain");
else
snprintf(buffer, buffer_size, "Recall used before Remember");
break;
case RC_VALIDATION_ERR_RECALL_WITHOUT_REMEMBER:
snprintf(buffer, buffer_size, "Recall used without Remember");
break;
case RC_VALIDATION_ERR_RESET_HIT_TARGET_OF_ONE:
@@ -312,6 +320,53 @@ static void rc_validate_add_error(rc_validation_state_t* state, uint32_t error_c
error->data2 = data2;
}
/* rc_condition_is_combining doesn't look at conditions that build a memref (like AddSource) */
static int rc_validate_is_combining_condition(const rc_condition_t* condition)
{
switch (condition->type)
{
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_ADD_HITS:
case RC_CONDITION_ADD_SOURCE:
case RC_CONDITION_AND_NEXT:
case RC_CONDITION_OR_NEXT:
case RC_CONDITION_RESET_NEXT_IF:
case RC_CONDITION_SUB_HITS:
case RC_CONDITION_SUB_SOURCE:
case RC_CONDITION_REMEMBER:
return 1;
default:
return 0;
}
}
static const rc_condition_t* rc_validate_get_next_non_combining_condition(const rc_condition_t* cond)
{
while (cond && rc_validate_is_combining_condition(cond))
cond = cond->next;
return cond;
}
static int rc_validate_has_condition(const rc_condition_t* cond, uint8_t type)
{
for (; cond; cond = cond->next) {
if (cond->type == type)
return 1;
}
return 0;
}
static int rc_validate_is_invalid_recall(const rc_operand_t* operand)
{
/* if operand is {recall}, but memref is null, that means the Remember wasn't found */
return rc_operand_is_recall(operand) &&
rc_operand_type_is_memref(operand->memref_access_type) &&
!operand->value.memref;
}
static void rc_validate_memref(const rc_memref_t* memref, rc_validation_state_t* state)
{
if (memref->address > state->max_address) {
@@ -603,15 +658,15 @@ static int rc_validate_condset_internal(const rc_condset_t* condset, rc_validati
}
/* if operand is {recall}, but memref is null, that means the Remember wasn't found */
if (rc_operand_is_recall(operand1) &&
rc_operand_type_is_memref(operand1->memref_access_type) &&
!operand1->value.memref) {
rc_validate_add_error(state, RC_VALIDATION_ERR_RECALL_BEFORE_REMEMBER, 0, 0);
}
if (rc_operand_is_recall(&cond->operand2) &&
rc_operand_type_is_memref(cond->operand2.memref_access_type) &&
!cond->operand2.value.memref) {
rc_validate_add_error(state, RC_VALIDATION_ERR_RECALL_BEFORE_REMEMBER, 0, 0);
if (rc_validate_is_invalid_recall(operand1) || rc_validate_is_invalid_recall(&cond->operand2)) {
if (!rc_validate_has_condition(condset->conditions, RC_CONDITION_REMEMBER)) {
rc_validate_add_error(state, RC_VALIDATION_ERR_RECALL_WITHOUT_REMEMBER, 0, 0);
}
else {
const rc_condition_t* next_cond = rc_validate_get_next_non_combining_condition(cond);
const uint8_t next_cond_type = next_cond ? next_cond->type : RC_CONDITION_STANDARD;
rc_validate_add_error(state, RC_VALIDATION_ERR_RECALL_BEFORE_REMEMBER, next_cond_type, 0);
}
}
switch (cond->type) {
@@ -840,27 +895,6 @@ int rc_validate_condset_for_console(const rc_condset_t* condset, char result[],
return 1;
}
/* rc_condition_is_combining doesn't look at conditions that build a memref (like AddSource) */
static int rc_validate_is_combining_condition(const rc_condition_t* condition)
{
switch (condition->type)
{
case RC_CONDITION_ADD_ADDRESS:
case RC_CONDITION_ADD_HITS:
case RC_CONDITION_ADD_SOURCE:
case RC_CONDITION_AND_NEXT:
case RC_CONDITION_OR_NEXT:
case RC_CONDITION_RESET_NEXT_IF:
case RC_CONDITION_SUB_HITS:
case RC_CONDITION_SUB_SOURCE:
case RC_CONDITION_REMEMBER:
return 1;
default:
return 0;
}
}
static int rc_validate_get_opposite_comparison(int oper)
{
switch (oper)