mirror of
https://github.com/libretro/RetroArch.git
synced 2025-01-23 18:06:36 +00:00
update to rcheevos 10.1 (#12512)
This commit is contained in:
parent
0caeed6e1d
commit
5d4069cf8f
@ -73,7 +73,7 @@
|
||||
#include "../network/net_http_special.h"
|
||||
#include "../tasks/tasks_internal.h"
|
||||
|
||||
#include "../deps/rcheevos/include/rc_runtime_types.h"
|
||||
#include "../deps/rcheevos/include/rc_runtime.h"
|
||||
#include "../deps/rcheevos/include/rc_url.h"
|
||||
#include "../deps/rcheevos/include/rc_hash.h"
|
||||
#include "../deps/rcheevos/src/rcheevos/rc_libretro.h"
|
||||
@ -171,6 +171,7 @@ static void rcheevos_async_task_callback(
|
||||
retro_task_t* task, void* task_data, void* user_data, const char* error);
|
||||
static void rcheevos_async_submit_lboard(rcheevos_locals_t *locals,
|
||||
rcheevos_async_io_request* request);
|
||||
static void rcheevos_validate_memrefs(rcheevos_locals_t* locals);
|
||||
|
||||
/*****************************************************************************
|
||||
Supporting functions.
|
||||
@ -351,48 +352,13 @@ static void rcheevos_log_post_url(
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool rcheevos_condset_contains_memref(const rc_condset_t* condset,
|
||||
const rc_memref_t* memref)
|
||||
{
|
||||
if (condset)
|
||||
{
|
||||
rc_condition_t* cond = NULL;
|
||||
for (cond = condset->conditions; cond; cond = cond->next)
|
||||
{
|
||||
if ( cond->operand1.value.memref == memref
|
||||
|| cond->operand2.value.memref == memref)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rcheevos_trigger_contains_memref(const rc_trigger_t* trigger,
|
||||
const rc_memref_t* memref)
|
||||
{
|
||||
rc_condset_t* condset;
|
||||
if (!trigger)
|
||||
return false;
|
||||
|
||||
if (rcheevos_condset_contains_memref(trigger->requirement, memref))
|
||||
return true;
|
||||
|
||||
for (condset = trigger->alternative; condset; condset = condset->next)
|
||||
{
|
||||
if (rcheevos_condset_contains_memref(condset, memref))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void rcheevos_achievement_disabled(rcheevos_racheevo_t* cheevo, unsigned address)
|
||||
{
|
||||
if (!cheevo)
|
||||
return;
|
||||
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "Achievement disabled (invalid address %06X): %s\n", address, cheevo->title);
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "Achievement %u disabled (invalid address %06X): %s\n",
|
||||
cheevo->id, address, cheevo->title);
|
||||
CHEEVOS_FREE(cheevo->memaddr);
|
||||
cheevo->memaddr = NULL;
|
||||
}
|
||||
@ -402,97 +368,12 @@ static void rcheevos_lboard_disabled(rcheevos_ralboard_t* lboard, unsigned addre
|
||||
if (!lboard)
|
||||
return;
|
||||
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "Leaderboard disabled (invalid address %06X): %s\n", address, lboard->title);
|
||||
CHEEVOS_ERR(RCHEEVOS_TAG "Leaderboard %u disabled (invalid address %06X): %s\n",
|
||||
lboard->id, address, lboard->title);
|
||||
CHEEVOS_FREE(lboard->mem);
|
||||
lboard->mem = NULL;
|
||||
}
|
||||
|
||||
static void rcheevos_invalidate_address(unsigned address)
|
||||
{
|
||||
unsigned i, count;
|
||||
rcheevos_racheevo_t* cheevo = NULL;
|
||||
rcheevos_ralboard_t* lboard = NULL;
|
||||
/* Remove the invalid memref from the chain so we don't
|
||||
* try to evaluate it in the future.
|
||||
* It's still there, so anything referencing it will
|
||||
* continue to fetch 0. */
|
||||
rc_memref_t **last_memref = &rcheevos_locals.runtime.memrefs;
|
||||
rc_memref_t *memref = *last_memref;
|
||||
|
||||
do
|
||||
{
|
||||
if (memref->address == address && !memref->value.is_indirect)
|
||||
{
|
||||
*last_memref = memref->next;
|
||||
break;
|
||||
}
|
||||
|
||||
last_memref = &memref->next;
|
||||
memref = *last_memref;
|
||||
} while(memref);
|
||||
|
||||
/* If the address is only used indirectly,
|
||||
* don't disable anything dependent on it */
|
||||
if (!memref)
|
||||
return;
|
||||
|
||||
/* Disable any achievements dependent on the address */
|
||||
for (i = 0; i < 2; ++i)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
cheevo = rcheevos_locals.patchdata.core;
|
||||
count = rcheevos_locals.patchdata.core_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
cheevo = rcheevos_locals.patchdata.unofficial;
|
||||
count = rcheevos_locals.patchdata.unofficial_count;
|
||||
}
|
||||
|
||||
while (count--)
|
||||
{
|
||||
if (cheevo->memaddr)
|
||||
{
|
||||
const rc_trigger_t* trigger = rc_runtime_get_achievement(
|
||||
&rcheevos_locals.runtime, cheevo->id);
|
||||
|
||||
if (trigger && rcheevos_trigger_contains_memref(trigger, memref))
|
||||
{
|
||||
rcheevos_achievement_disabled(cheevo, address);
|
||||
rc_runtime_deactivate_achievement(&rcheevos_locals.runtime,
|
||||
cheevo->id);
|
||||
}
|
||||
}
|
||||
|
||||
++cheevo;
|
||||
}
|
||||
}
|
||||
|
||||
/* disable any leaderboards dependent on the address */
|
||||
lboard = rcheevos_locals.patchdata.lboards;
|
||||
for (i = 0; i < rcheevos_locals.patchdata.lboard_count; ++i, ++lboard)
|
||||
{
|
||||
if (lboard->mem)
|
||||
{
|
||||
const rc_lboard_t* rc_lboard = rc_runtime_get_lboard(
|
||||
&rcheevos_locals.runtime, lboard->id);
|
||||
|
||||
if ( rc_lboard &&
|
||||
( rcheevos_trigger_contains_memref(&rc_lboard->start, memref) ||
|
||||
rcheevos_trigger_contains_memref(&rc_lboard->cancel, memref) ||
|
||||
rcheevos_trigger_contains_memref(&rc_lboard->submit, memref) ||
|
||||
rcheevos_condset_contains_memref(rc_lboard->value.conditions,
|
||||
memref))
|
||||
)
|
||||
{
|
||||
rcheevos_lboard_disabled(lboard, address);
|
||||
rc_runtime_deactivate_lboard(&rcheevos_locals.runtime, lboard->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rcheevos_handle_log_message(const char* message)
|
||||
{
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", message);
|
||||
@ -774,24 +655,6 @@ static void rcheevos_async_task_callback(
|
||||
}
|
||||
}
|
||||
|
||||
static void rcheevos_validate_memrefs(rcheevos_locals_t* locals)
|
||||
{
|
||||
rc_memref_t* memref = locals->runtime.memrefs;
|
||||
|
||||
while (memref)
|
||||
{
|
||||
if (!memref->value.is_indirect)
|
||||
{
|
||||
uint8_t* data = rc_libretro_memory_find(&rcheevos_locals.memory,
|
||||
memref->address);
|
||||
if (!data)
|
||||
rcheevos_invalidate_address(memref->address);
|
||||
}
|
||||
|
||||
memref = memref->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void rcheevos_activate_achievements(rcheevos_locals_t *locals,
|
||||
rcheevos_racheevo_t* cheevo, unsigned count, unsigned flags)
|
||||
{
|
||||
@ -859,7 +722,9 @@ static int rcheevos_parse(rcheevos_locals_t *locals, const char* json)
|
||||
|
||||
if ( locals->patchdata.core_count == 0
|
||||
&& locals->patchdata.unofficial_count == 0
|
||||
&& locals->patchdata.lboard_count == 0)
|
||||
&& locals->patchdata.lboard_count == 0
|
||||
&& (!locals->patchdata.richpresence_script ||
|
||||
!*locals->patchdata.richpresence_script))
|
||||
{
|
||||
rcheevos_free_patchdata(&locals->patchdata);
|
||||
return 0;
|
||||
@ -1121,7 +986,7 @@ static void rcheevos_lboard_submit(rcheevos_locals_t *locals,
|
||||
char formatted_value[16];
|
||||
|
||||
/* Show the OSD message (regardless of notifications setting). */
|
||||
rc_format_value(formatted_value, sizeof(formatted_value),
|
||||
rc_runtime_format_lboard_value(formatted_value, sizeof(formatted_value),
|
||||
value, lboard->format);
|
||||
|
||||
CHEEVOS_LOG(RCHEEVOS_TAG "Submitting %s for leaderboard %u\n",
|
||||
@ -1191,7 +1056,7 @@ static void rcheevos_lboard_started(rcheevos_ralboard_t * lboard, int value,
|
||||
#if defined(HAVE_GFX_WIDGETS)
|
||||
if (widgets_ready && rcheevos_locals.leaderboard_trackers)
|
||||
{
|
||||
rc_format_value(buffer, sizeof(buffer), value, lboard->format);
|
||||
rc_runtime_format_lboard_value(buffer, sizeof(buffer), value, lboard->format);
|
||||
gfx_widgets_set_leaderboard_display(lboard->id, buffer);
|
||||
}
|
||||
#endif
|
||||
@ -1222,7 +1087,7 @@ static void rcheevos_lboard_updated(rcheevos_ralboard_t* lboard, int value,
|
||||
if (widgets_ready && rcheevos_locals.leaderboard_trackers)
|
||||
{
|
||||
char buffer[32];
|
||||
rc_format_value(buffer, sizeof(buffer), value, lboard->format);
|
||||
rc_runtime_format_lboard_value(buffer, sizeof(buffer), value, lboard->format);
|
||||
gfx_widgets_set_leaderboard_display(lboard->id, buffer);
|
||||
}
|
||||
}
|
||||
@ -1670,6 +1535,17 @@ static void rcheevos_runtime_event_handler(const rc_runtime_event_t* runtime_eve
|
||||
}
|
||||
}
|
||||
|
||||
static int rcheevos_runtime_address_validator(unsigned address)
|
||||
{
|
||||
return (rc_libretro_memory_find(&rcheevos_locals.memory, address) != NULL);
|
||||
}
|
||||
|
||||
static void rcheevos_validate_memrefs(rcheevos_locals_t* locals)
|
||||
{
|
||||
rc_runtime_validate_addresses(&locals->runtime,
|
||||
rcheevos_runtime_event_handler, rcheevos_runtime_address_validator);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Test all the achievements (call once per frame).
|
||||
*****************************************************************************/
|
||||
@ -1949,10 +1825,20 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
||||
"This game has no achievements.",
|
||||
0, 5 * 60, false, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||
|
||||
rcheevos_pause_hardcore();
|
||||
if (rcheevos_locals.patchdata.richpresence_script &&
|
||||
*rcheevos_locals.patchdata.richpresence_script)
|
||||
{
|
||||
rcheevos_locals.loaded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rcheevos_pause_hardcore();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rcheevos_locals.loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_REWIND
|
||||
|
3
deps/rcheevos/include/rc_runtime.h
vendored
3
deps/rcheevos/include/rc_runtime.h
vendored
@ -130,6 +130,9 @@ typedef void (*rc_runtime_event_handler_t)(const rc_runtime_event_t* runtime_eve
|
||||
|
||||
void rc_runtime_do_frame(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_peek_t peek, void* ud, lua_State* L);
|
||||
void rc_runtime_reset(rc_runtime_t* runtime);
|
||||
|
||||
typedef int (*rc_runtime_validate_address_t)(unsigned address);
|
||||
void rc_runtime_validate_addresses(rc_runtime_t* runtime, rc_runtime_event_handler_t event_handler, rc_runtime_validate_address_t validate_handler);
|
||||
void rc_runtime_invalidate_address(rc_runtime_t* runtime, unsigned address);
|
||||
|
||||
int rc_runtime_progress_size(const rc_runtime_t* runtime, lua_State* L);
|
||||
|
12
deps/rcheevos/src/rcheevos/condition.c
vendored
12
deps/rcheevos/src/rcheevos/condition.c
vendored
@ -239,10 +239,18 @@ int rc_evaluate_condition_value(rc_condition_t* self, rc_eval_state_t* eval_stat
|
||||
|
||||
switch (self->oper) {
|
||||
case RC_OPERATOR_MULT:
|
||||
if (self->operand2.type == RC_OPERAND_FP)
|
||||
if (self->operand2.type == RC_OPERAND_FP) {
|
||||
value = (int)((double)value * self->operand2.value.dbl);
|
||||
else
|
||||
}
|
||||
else {
|
||||
/* the c standard for unsigned multiplication is well defined as non-overflowing truncation
|
||||
* to the type's size. this allows negative multiplication through twos-complements. i.e.
|
||||
* 1 * -1 (0xFFFFFFFF) = 0xFFFFFFFF = -1
|
||||
* 3 * -2 (0xFFFFFFFE) = 0x2FFFFFFFA & 0xFFFFFFFF = 0xFFFFFFFA = -6
|
||||
* 10 * -5 (0xFFFFFFFB) = 0x9FFFFFFCE & 0xFFFFFFFF = 0xFFFFFFCE = -50
|
||||
*/
|
||||
value *= rc_evaluate_operand(&self->operand2, eval_state);
|
||||
}
|
||||
break;
|
||||
|
||||
case RC_OPERATOR_DIV:
|
||||
|
13
deps/rcheevos/src/rcheevos/consoleinfo.c
vendored
13
deps/rcheevos/src/rcheevos/consoleinfo.c
vendored
@ -338,10 +338,14 @@ static const rc_memory_region_t _rc_memory_regions_intellivision[] = {
|
||||
static const rc_memory_regions_t rc_memory_regions_intellivision = { _rc_memory_regions_intellivision, 9 };
|
||||
|
||||
/* ===== Magnavox Odyssey 2 ===== */
|
||||
/* https://sudonull.com/post/76885-Architecture-and-programming-Philips-Videopac-Magnavox-Odyssey-2 */
|
||||
static const rc_memory_region_t _rc_memory_regions_magnavox_odyssey_2[] = {
|
||||
{ 0x000000U, 0x00003FU, 0x000040U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
/* Internal and external RAMs are reachable using unique instructions.
|
||||
* The real addresses provided are virtual and for mapping purposes only. */
|
||||
{ 0x000000U, 0x00003FU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "Internal RAM" },
|
||||
{ 0x000040U, 0x00013FU, 0x000040U, RC_MEMORY_TYPE_SYSTEM_RAM, "External RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_magnavox_odyssey_2 = { _rc_memory_regions_magnavox_odyssey_2, 1 };
|
||||
static const rc_memory_regions_t rc_memory_regions_magnavox_odyssey_2 = { _rc_memory_regions_magnavox_odyssey_2, 2 };
|
||||
|
||||
/* ===== Master System ===== */
|
||||
/* http://www.smspower.org/Development/MemoryMap */
|
||||
@ -374,8 +378,9 @@ static const rc_memory_regions_t rc_memory_regions_msx = { _rc_memory_regions_ms
|
||||
/* ===== Neo Geo Pocket ===== */
|
||||
/* http://neopocott.emuunlim.com/docs/tech-11.txt */
|
||||
static const rc_memory_region_t _rc_memory_regions_neo_geo_pocket[] = {
|
||||
/* MednafenNGP exposes 16KB, but the doc suggests there's 24-32KB */
|
||||
{ 0x000000U, 0x003FFFU, 0x000000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
/* The docs suggest there's Work RAM exposed from $0000-$6FFF, Sound RAM from $7000-$7FFF, and Video
|
||||
* RAM from $8000-$BFFF, but both MednafenNGP and FBNeo only expose system RAM from $4000-$7FFF */
|
||||
{ 0x000000U, 0x003FFFU, 0x004000U, RC_MEMORY_TYPE_SYSTEM_RAM, "System RAM" }
|
||||
};
|
||||
static const rc_memory_regions_t rc_memory_regions_neo_geo_pocket = { _rc_memory_regions_neo_geo_pocket, 1 };
|
||||
|
||||
|
130
deps/rcheevos/src/rcheevos/memref.c
vendored
130
deps/rcheevos/src/rcheevos/memref.c
vendored
@ -95,6 +95,86 @@ int rc_parse_memref(const char** memaddr, char* size, unsigned* address) {
|
||||
return RC_OK;
|
||||
}
|
||||
|
||||
static const unsigned char rc_bits_set[16] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
|
||||
|
||||
unsigned rc_transform_memref_value(unsigned value, char size)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case RC_MEMSIZE_BIT_0:
|
||||
value = (value >> 0) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_1:
|
||||
value = (value >> 1) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_2:
|
||||
value = (value >> 2) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_3:
|
||||
value = (value >> 3) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_4:
|
||||
value = (value >> 4) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_5:
|
||||
value = (value >> 5) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_6:
|
||||
value = (value >> 6) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_7:
|
||||
value = (value >> 7) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_LOW:
|
||||
value = value & 0x0f;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_HIGH:
|
||||
value = (value >> 4) & 0x0f;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BITCOUNT:
|
||||
value = rc_bits_set[(value & 0x0F)]
|
||||
+ rc_bits_set[((value >> 4) & 0x0F)];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
char rc_memref_shared_size(char size)
|
||||
{
|
||||
switch (size) {
|
||||
case RC_MEMSIZE_BIT_0:
|
||||
case RC_MEMSIZE_BIT_1:
|
||||
case RC_MEMSIZE_BIT_2:
|
||||
case RC_MEMSIZE_BIT_3:
|
||||
case RC_MEMSIZE_BIT_4:
|
||||
case RC_MEMSIZE_BIT_5:
|
||||
case RC_MEMSIZE_BIT_6:
|
||||
case RC_MEMSIZE_BIT_7:
|
||||
case RC_MEMSIZE_LOW:
|
||||
case RC_MEMSIZE_HIGH:
|
||||
case RC_MEMSIZE_BITCOUNT:
|
||||
/* these can all share an 8-bit memref and just mask off the appropriate data in rc_transform_memref_value */
|
||||
return RC_MEMSIZE_8_BITS;
|
||||
|
||||
default:
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void* ud) {
|
||||
unsigned value;
|
||||
|
||||
@ -103,46 +183,6 @@ static unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void*
|
||||
|
||||
switch (size)
|
||||
{
|
||||
case RC_MEMSIZE_BIT_0:
|
||||
value = (peek(address, 1, ud) >> 0) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_1:
|
||||
value = (peek(address, 1, ud) >> 1) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_2:
|
||||
value = (peek(address, 1, ud) >> 2) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_3:
|
||||
value = (peek(address, 1, ud) >> 3) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_4:
|
||||
value = (peek(address, 1, ud) >> 4) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_5:
|
||||
value = (peek(address, 1, ud) >> 5) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_6:
|
||||
value = (peek(address, 1, ud) >> 6) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_7:
|
||||
value = (peek(address, 1, ud) >> 7) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_LOW:
|
||||
value = peek(address, 1, ud) & 0x0f;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_HIGH:
|
||||
value = (peek(address, 1, ud) >> 4) & 0x0f;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_8_BITS:
|
||||
value = peek(address, 1, ud);
|
||||
break;
|
||||
@ -161,7 +201,15 @@ static unsigned rc_peek_value(unsigned address, char size, rc_peek_t peek, void*
|
||||
break;
|
||||
|
||||
default:
|
||||
value = 0;
|
||||
if (rc_memref_shared_size(size) == RC_MEMSIZE_8_BITS)
|
||||
{
|
||||
value = peek(address, 1, ud);
|
||||
value = rc_transform_memref_value(value, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
75
deps/rcheevos/src/rcheevos/operand.c
vendored
75
deps/rcheevos/src/rcheevos/operand.c
vendored
@ -102,27 +102,7 @@ static int rc_parse_operand_memory(rc_operand_t* self, const char** memaddr, rc_
|
||||
if (ret != RC_OK)
|
||||
return ret;
|
||||
|
||||
switch (self->size) {
|
||||
case RC_MEMSIZE_BIT_0:
|
||||
case RC_MEMSIZE_BIT_1:
|
||||
case RC_MEMSIZE_BIT_2:
|
||||
case RC_MEMSIZE_BIT_3:
|
||||
case RC_MEMSIZE_BIT_4:
|
||||
case RC_MEMSIZE_BIT_5:
|
||||
case RC_MEMSIZE_BIT_6:
|
||||
case RC_MEMSIZE_BIT_7:
|
||||
case RC_MEMSIZE_LOW:
|
||||
case RC_MEMSIZE_HIGH:
|
||||
case RC_MEMSIZE_BITCOUNT:
|
||||
/* these can all share an 8-bit memref and just mask off the appropriate data in rc_evaluate_operand */
|
||||
size = RC_MEMSIZE_8_BITS;
|
||||
break;
|
||||
|
||||
default:
|
||||
size = self->size;
|
||||
break;
|
||||
}
|
||||
|
||||
size = rc_memref_shared_size(self->size);
|
||||
self->value.memref = rc_alloc_memref(parse, address, size, is_indirect);
|
||||
if (parse->offset < 0)
|
||||
return parse->offset;
|
||||
@ -295,8 +275,6 @@ int rc_operand_is_memref(rc_operand_t* self) {
|
||||
}
|
||||
}
|
||||
|
||||
static const unsigned char rc_bits_set[16] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
|
||||
|
||||
unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
|
||||
#ifndef RC_DISABLE_LUA
|
||||
rc_luapeek_t luapeek;
|
||||
@ -348,56 +326,7 @@ unsigned rc_evaluate_operand(rc_operand_t* self, rc_eval_state_t* eval_state) {
|
||||
}
|
||||
|
||||
/* step 2: mask off appropriate bits */
|
||||
switch (self->size)
|
||||
{
|
||||
case RC_MEMSIZE_BIT_0:
|
||||
value = (value >> 0) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_1:
|
||||
value = (value >> 1) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_2:
|
||||
value = (value >> 2) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_3:
|
||||
value = (value >> 3) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_4:
|
||||
value = (value >> 4) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_5:
|
||||
value = (value >> 5) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_6:
|
||||
value = (value >> 6) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BIT_7:
|
||||
value = (value >> 7) & 1;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_LOW:
|
||||
value = value & 0x0f;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_HIGH:
|
||||
value = (value >> 4) & 0x0f;
|
||||
break;
|
||||
|
||||
case RC_MEMSIZE_BITCOUNT:
|
||||
value = rc_bits_set[(value & 0x0F)]
|
||||
+ rc_bits_set[((value >> 4) & 0x0F)];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
value = rc_transform_memref_value(value, self->size);
|
||||
|
||||
/* step 3: apply logic */
|
||||
switch (self->type)
|
||||
|
2
deps/rcheevos/src/rcheevos/rc_internal.h
vendored
2
deps/rcheevos/src/rcheevos/rc_internal.h
vendored
@ -117,6 +117,8 @@ void rc_update_memref_values(rc_memref_t* memref, rc_peek_t peek, void* ud);
|
||||
void rc_update_memref_value(rc_memref_value_t* memref, unsigned value);
|
||||
unsigned rc_get_memref_value(rc_memref_t* memref, int operand_type, rc_eval_state_t* eval_state);
|
||||
unsigned rc_get_memref_value_value(rc_memref_value_t* memref, int operand_type);
|
||||
char rc_memref_shared_size(char size);
|
||||
unsigned rc_transform_memref_value(unsigned value, char size);
|
||||
|
||||
void rc_parse_trigger_internal(rc_trigger_t* self, const char** memaddr, rc_parse_state_t* parse);
|
||||
int rc_trigger_state_active(int state);
|
||||
|
10
deps/rcheevos/src/rcheevos/rc_libretro.c
vendored
10
deps/rcheevos/src/rcheevos/rc_libretro.c
vendored
@ -131,7 +131,7 @@ static int rc_libretro_match_value(const char* val, const char* match) {
|
||||
if (*match == ',') {
|
||||
do {
|
||||
const char* ptr = ++match;
|
||||
int size;
|
||||
size_t size;
|
||||
|
||||
while (*match && *match != ',')
|
||||
++match;
|
||||
@ -218,7 +218,7 @@ unsigned char* rc_libretro_memory_find(const rc_libretro_memory_regions_t* regio
|
||||
return ®ions->data[i][address];
|
||||
}
|
||||
|
||||
address -= size;
|
||||
address -= (unsigned)size;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -360,8 +360,8 @@ static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(description, sizeof(description), "descriptor %u, offset 0x%06X",
|
||||
(unsigned)(desc - mmap->descriptors) + 1, (int)offset);
|
||||
snprintf(description, sizeof(description), "descriptor %u, offset 0x%06X%s",
|
||||
(unsigned)(desc - mmap->descriptors) + 1, (int)offset, desc->ptr ? "" : " [no pointer]");
|
||||
|
||||
if (desc->ptr) {
|
||||
desc_start = (uint8_t*)desc->ptr + desc->offset;
|
||||
@ -387,7 +387,7 @@ static void rc_libretro_memory_init_from_memory_map(rc_libretro_memory_regions_t
|
||||
else {
|
||||
rc_libretro_memory_register_region(regions, console_region->type, region_start, desc_size, description);
|
||||
console_region_size -= desc_size;
|
||||
real_address += desc_size;
|
||||
real_address += (unsigned)desc_size;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
5
deps/rcheevos/src/rcheevos/richpresence.c
vendored
5
deps/rcheevos/src/rcheevos/richpresence.c
vendored
@ -22,8 +22,9 @@ static rc_memref_value_t* rc_alloc_helper_variable_memref_value(const char* mema
|
||||
if (rc_parse_memref(&end, &size, &address) == RC_OK) {
|
||||
/* make sure the entire memaddr was consumed. if not, there's an operator and it's a comparison, not a memory reference */
|
||||
if (end == &memaddr[memaddr_len]) {
|
||||
/* just a memory reference, allocate it */
|
||||
return &rc_alloc_memref(parse, address, size, 0)->value;
|
||||
/* if it's not a derived size, we can reference the memref directly */
|
||||
if (rc_memref_shared_size(size) == size)
|
||||
return &rc_alloc_memref(parse, address, size, 0)->value;
|
||||
}
|
||||
}
|
||||
|
||||
|
126
deps/rcheevos/src/rcheevos/runtime.c
vendored
126
deps/rcheevos/src/rcheevos/runtime.c
vendored
@ -491,23 +491,32 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
|
||||
|
||||
old_state = trigger->state;
|
||||
new_state = rc_evaluate_trigger(trigger, peek, ud, L);
|
||||
|
||||
/* the trigger state doesn't actually change to RESET, RESET just serves as a notification.
|
||||
* handle the notification, then look at the actual state */
|
||||
if (new_state == RC_TRIGGER_STATE_RESET)
|
||||
{
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_RESET;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
event_handler(&runtime_event);
|
||||
|
||||
new_state = trigger->state;
|
||||
}
|
||||
|
||||
/* if the state hasn't changed, there won't be any events raised */
|
||||
if (new_state == old_state)
|
||||
continue;
|
||||
|
||||
/* raise an UNPRIMED event when changing from UNPRIMED to anything else */
|
||||
if (old_state == RC_TRIGGER_STATE_PRIMED) {
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_UNPRIMED;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
|
||||
/* raise events for each of the possible new states */
|
||||
switch (new_state)
|
||||
{
|
||||
case RC_TRIGGER_STATE_RESET:
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_RESET;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
event_handler(&runtime_event);
|
||||
break;
|
||||
|
||||
case RC_TRIGGER_STATE_TRIGGERED:
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
@ -527,6 +536,8 @@ void rc_runtime_do_frame(rc_runtime_t* self, rc_runtime_event_handler_t event_ha
|
||||
break;
|
||||
|
||||
case RC_TRIGGER_STATE_ACTIVE:
|
||||
/* only raise ACTIVATED event when transitioning from an inactive state.
|
||||
* note that inactive in this case means active but cannot trigger. */
|
||||
if (old_state == RC_TRIGGER_STATE_WAITING || old_state == RC_TRIGGER_STATE_PAUSED) {
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_ACTIVATED;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
@ -667,32 +678,8 @@ static int rc_trigger_contains_memref(const rc_trigger_t* trigger, const rc_memr
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rc_runtime_invalidate_address(rc_runtime_t* self, unsigned address) {
|
||||
static void rc_runtime_invalidate_memref(rc_runtime_t* self, rc_memref_t* memref) {
|
||||
unsigned i;
|
||||
rc_memref_t* memref;
|
||||
rc_memref_t** last_memref;
|
||||
|
||||
if (!self->memrefs)
|
||||
return;
|
||||
|
||||
/* remove the invalid memref from the chain so we don't try to evaluate it in the future.
|
||||
* it's still there, so anything referencing it will continue to fetch 0.
|
||||
*/
|
||||
last_memref = &self->memrefs;
|
||||
memref = *last_memref;
|
||||
do {
|
||||
if (memref->address == address && !memref->value.is_indirect) {
|
||||
*last_memref = memref->next;
|
||||
break;
|
||||
}
|
||||
|
||||
last_memref = &memref->next;
|
||||
memref = *last_memref;
|
||||
} while (memref);
|
||||
|
||||
/* if the address is only used indirectly, don't disable anything dependent on it */
|
||||
if (!memref)
|
||||
return;
|
||||
|
||||
/* disable any achievements dependent on the address */
|
||||
for (i = 0; i < self->trigger_count; ++i) {
|
||||
@ -726,3 +713,80 @@ void rc_runtime_invalidate_address(rc_runtime_t* self, unsigned address) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rc_runtime_invalidate_address(rc_runtime_t* self, unsigned address) {
|
||||
rc_memref_t** last_memref = &self->memrefs;
|
||||
rc_memref_t* memref = self->memrefs;
|
||||
|
||||
while (memref) {
|
||||
if (memref->address == address && !memref->value.is_indirect) {
|
||||
/* remove the invalid memref from the chain so we don't try to evaluate it in the future.
|
||||
* it's still there, so anything referencing it will continue to fetch 0.
|
||||
*/
|
||||
*last_memref = memref->next;
|
||||
|
||||
rc_runtime_invalidate_memref(self, memref);
|
||||
break;
|
||||
}
|
||||
|
||||
last_memref = &memref->next;
|
||||
memref = *last_memref;
|
||||
}
|
||||
}
|
||||
|
||||
void rc_runtime_validate_addresses(rc_runtime_t* self, rc_runtime_event_handler_t event_handler,
|
||||
rc_runtime_validate_address_t validate_handler) {
|
||||
rc_memref_t** last_memref = &self->memrefs;
|
||||
rc_memref_t* memref = self->memrefs;
|
||||
int num_invalid = 0;
|
||||
|
||||
while (memref) {
|
||||
if (!memref->value.is_indirect && !validate_handler(memref->address)) {
|
||||
/* remove the invalid memref from the chain so we don't try to evaluate it in the future.
|
||||
* it's still there, so anything referencing it will continue to fetch 0.
|
||||
*/
|
||||
*last_memref = memref->next;
|
||||
|
||||
rc_runtime_invalidate_memref(self, memref);
|
||||
++num_invalid;
|
||||
}
|
||||
else {
|
||||
last_memref = &memref->next;
|
||||
}
|
||||
|
||||
memref = *last_memref;
|
||||
}
|
||||
|
||||
if (num_invalid) {
|
||||
rc_runtime_event_t runtime_event;
|
||||
int i;
|
||||
|
||||
for (i = self->trigger_count - 1; i >= 0; --i) {
|
||||
rc_trigger_t* trigger = self->triggers[i].trigger;
|
||||
if (trigger && self->triggers[i].invalid_memref) {
|
||||
runtime_event.type = RC_RUNTIME_EVENT_ACHIEVEMENT_DISABLED;
|
||||
runtime_event.id = self->triggers[i].id;
|
||||
runtime_event.value = self->triggers[i].invalid_memref->address;
|
||||
|
||||
trigger->state = RC_TRIGGER_STATE_DISABLED;
|
||||
self->triggers[i].invalid_memref = NULL;
|
||||
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = self->lboard_count - 1; i >= 0; --i) {
|
||||
rc_lboard_t* lboard = self->lboards[i].lboard;
|
||||
if (lboard && self->lboards[i].invalid_memref) {
|
||||
runtime_event.type = RC_RUNTIME_EVENT_LBOARD_DISABLED;
|
||||
runtime_event.id = self->lboards[i].id;
|
||||
runtime_event.value = self->lboards[i].invalid_memref->address;
|
||||
|
||||
lboard->state = RC_LBOARD_STATE_DISABLED;
|
||||
self->lboards[i].invalid_memref = NULL;
|
||||
|
||||
event_handler(&runtime_event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user