(cheevos) use common functionality moved into rcheevos (#12504)

* user rcheevos for disallowed_settings

* use rcheevos for memory map
This commit is contained in:
Jamiras 2021-06-08 22:32:34 -06:00 committed by GitHub
parent 27cacffe54
commit 75fcd63b4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 83 additions and 578 deletions

View File

@ -2112,7 +2112,6 @@ ifeq ($(HAVE_NETWORKING), 1)
OBJ += cheevos/cheevos.o \
cheevos/cheevos_menu.o \
cheevos/cheevos_memory.o \
cheevos/cheevos_parser.o \
$(LIBRETRO_COMM_DIR)/formats/cdfs/cdfs.o \
deps/rcheevos/src/rcheevos/alloc.o \
@ -2124,6 +2123,7 @@ ifeq ($(HAVE_NETWORKING), 1)
deps/rcheevos/src/rcheevos/lboard.o \
deps/rcheevos/src/rcheevos/memref.o \
deps/rcheevos/src/rcheevos/operand.o \
deps/rcheevos/src/rcheevos/rc_libretro.o \
deps/rcheevos/src/rcheevos/richpresence.o \
deps/rcheevos/src/rcheevos/runtime.o \
deps/rcheevos/src/rcheevos/runtime_progress.o \

View File

@ -55,7 +55,6 @@
#include "cheevos.h"
#include "cheevos_locals.h"
#include "cheevos_memory.h"
#include "cheevos_parser.h"
#include "../file_path_special.h"
@ -77,6 +76,7 @@
#include "../deps/rcheevos/include/rc_runtime_types.h"
#include "../deps/rcheevos/include/rc_url.h"
#include "../deps/rcheevos/include/rc_hash.h"
#include "../deps/rcheevos/src/rcheevos/rc_libretro.h"
/* Define this macro to prevent cheevos from being deactivated. */
#undef CHEEVOS_DONT_DEACTIVATE
@ -493,20 +493,66 @@ static void rcheevos_invalidate_address(unsigned address)
}
}
static void rcheevos_handle_log_message(const char* message)
{
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", message);
}
static void rcheevos_get_core_memory_info(unsigned id, rc_libretro_core_memory_info_t* info)
{
retro_ctx_memory_info_t ctx_info;
if (!info)
return;
ctx_info.id = id;
if (core_get_memory(&ctx_info))
{
info->data = (unsigned char*)ctx_info.data;
info->size = ctx_info.size;
}
else
{
info->data = NULL;
info->size = 0;
}
}
static int rcheevos_init_memory(rcheevos_locals_t* locals)
{
rarch_system_info_t* system = runloop_get_system_info();
rarch_memory_map_t* mmaps = &system->mmaps;
struct retro_memory_descriptor descriptors[64];
struct retro_memory_map mmap;
unsigned i;
mmap.descriptors = &descriptors[0];
mmap.num_descriptors = sizeof(descriptors) / sizeof(descriptors[0]);
if (mmaps->num_descriptors < mmap.num_descriptors)
mmap.num_descriptors = mmaps->num_descriptors;
/* RetroArch wraps the retro_memory_descriptor's in rarch_memory_descriptor_t's, pull them back out */
for (i = 0; i < mmap.num_descriptors; ++i)
memcpy(&descriptors[i], &mmaps->descriptors[i].core, sizeof(descriptors[0]));
rc_libretro_init_verbose_message_callback(rcheevos_handle_log_message);
return rc_libretro_memory_init(&locals->memory, &mmap,
rcheevos_get_core_memory_info, locals->patchdata.console_id);
}
uint8_t* rcheevos_patch_address(unsigned address)
{
if (rcheevos_locals.memory.count == 0)
{
/* memory map was not previously initialized (no achievements for this game?) try now */
rcheevos_memory_init(&rcheevos_locals.memory, rcheevos_locals.patchdata.console_id);
rcheevos_init_memory(&rcheevos_locals);
}
return rcheevos_memory_find(&rcheevos_locals.memory, address);
return rc_libretro_memory_find(&rcheevos_locals.memory, address);
}
static unsigned rcheevos_peek(unsigned address, unsigned num_bytes, void* ud)
{
uint8_t* data = rcheevos_memory_find(&rcheevos_locals.memory, address);
uint8_t* data = rc_libretro_memory_find(&rcheevos_locals.memory, address);
if (data)
{
switch (num_bytes)
@ -736,7 +782,7 @@ static void rcheevos_validate_memrefs(rcheevos_locals_t* locals)
{
if (!memref->value.is_indirect)
{
uint8_t* data = rcheevos_memory_find(&rcheevos_locals.memory,
uint8_t* data = rc_libretro_memory_find(&rcheevos_locals.memory,
memref->address);
if (!data)
rcheevos_invalidate_address(memref->address);
@ -821,7 +867,7 @@ static int rcheevos_parse(rcheevos_locals_t *locals, const char* json)
settings = config_get_ptr();
if (!rcheevos_memory_init(&locals->memory, locals->patchdata.console_id))
if (!rcheevos_init_memory(locals))
{
/* some cores (like Mupen64-Plus) don't expose the
* memory until the first call to retro_run.
@ -921,7 +967,7 @@ static int rcheevos_parse(rcheevos_locals_t *locals, const char* json)
error:
rcheevos_free_patchdata(&locals->patchdata);
rcheevos_memory_destroy(&locals->memory);
rc_libretro_memory_destroy(&locals->memory);
return -1;
}
@ -1227,9 +1273,7 @@ void rcheevos_reset_game(bool widgets_ready)
/* Some cores reallocate memory on reset,
* make sure we update our pointers */
if (rcheevos_locals.memory.total_size > 0)
rcheevos_memory_init(
&rcheevos_locals.memory,
rcheevos_locals.patchdata.console_id);
rcheevos_init_memory(&rcheevos_locals);
}
bool rcheevos_hardcore_active(void)
@ -1268,7 +1312,7 @@ bool rcheevos_unload(void)
}
if (rcheevos_locals.memory.count > 0)
rcheevos_memory_destroy(&rcheevos_locals.memory);
rc_libretro_memory_destroy(&rcheevos_locals.memory);
if (rcheevos_locals.loaded)
{
@ -1536,177 +1580,39 @@ void rcheevos_hardcore_enabled_changed(void)
}
}
typedef struct rc_disallowed_setting_t
{
const char* setting;
const char* value;
} rc_disallowed_setting_t;
typedef struct rc_disallowed_core_settings_t
{
const char* library_name;
const rc_disallowed_setting_t* disallowed_settings;
} rc_disallowed_core_settings_t;
static const rc_disallowed_setting_t _rc_disallowed_dolphin_settings[] = {
{ "dolphin_cheats_enabled", "enabled" },
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_ecwolf_settings[] = {
{ "ecwolf-invulnerability", "enabled" },
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_fbneo_settings[] = {
{ "fbneo-allow-patched-romsets", "enabled" },
{ "fbneo-cheat-*", "!,Disabled,0 - Disabled" },
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_gpgx_settings[] = {
{ "genesis_plus_gx_lock_on", ",action replay (pro),game genie" },
{ NULL, NULL }
};
static const rc_disallowed_setting_t _rc_disallowed_ppsspp_settings[] = {
{ "ppsspp_cheats", "enabled" },
{ NULL, NULL }
};
static const rc_disallowed_core_settings_t rc_disallowed_core_settings[] = {
{ "dolphin-emu", _rc_disallowed_dolphin_settings },
{ "ecwolf", _rc_disallowed_ecwolf_settings },
{ "FinalBurn Neo", _rc_disallowed_fbneo_settings },
{ "Genesis Plus GX", _rc_disallowed_gpgx_settings },
{ "PPSSPP", _rc_disallowed_ppsspp_settings },
{ NULL, NULL }
};
static int rcheevos_match_value(const char* val, const char* match)
{
/* if value starts with a comma, it's a CSV list of potential matches */
if (*match == ',')
{
do
{
int size;
const char* ptr = ++match;
while (*match && *match != ',')
++match;
size = match - ptr;
if (val[size] == '\0')
{
char buffer[128];
if (string_is_equal_fast(ptr, val, size))
return true;
memcpy(buffer, ptr, size);
buffer[size] = '\0';
if (string_is_equal_case_insensitive(buffer, val))
return true;
}
} while(*match == ',');
return false;
}
/* a leading exclamation point means the provided value(s)
* are not forbidden (are allowed) */
if (*match == '!')
return !rcheevos_match_value(val, &match[1]);
/* just a single value, attempt to match it */
return string_is_equal_case_insensitive(val, match);
}
void rcheevos_validate_config_settings(void)
{
const rc_disallowed_core_settings_t
*core_filter = rc_disallowed_core_settings;
const rc_disallowed_setting_t* disallowed_settings;
core_option_manager_t* coreopts = NULL;
struct retro_system_info* system = runloop_get_libretro_system_info();
int i;
if (!system->library_name || !rcheevos_locals.hardcore_active)
return;
while (core_filter->library_name)
disallowed_settings = rc_libretro_get_disallowed_settings(system->library_name);
if (disallowed_settings == NULL)
return;
if (!rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts))
return;
for (i = 0; i < coreopts->size; i++)
{
if (string_is_equal(core_filter->library_name, system->library_name))
const char* key = coreopts->opts[i].key;
const char* val = core_option_manager_get_val(coreopts, i);
if (!rc_libretro_is_setting_allowed(disallowed_settings, key, val))
{
core_option_manager_t* coreopts = NULL;
char buffer[256];
snprintf(buffer, sizeof(buffer), "Hardcore paused. Setting not allowed: %s=%s", key, val);
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", buffer);
rcheevos_pause_hardcore();
if (rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts))
{
size_t i;
const char *val = NULL;
const rc_disallowed_setting_t
*disallowed_setting = core_filter->disallowed_settings;
int allowed = 1;
for (; disallowed_setting->setting; ++disallowed_setting)
{
const char *key = disallowed_setting->setting;
size_t key_len = strlen(key);
if (key[key_len - 1] == '*')
{
for (i = 0; i < coreopts->size; i++)
{
if (string_starts_with_size(
coreopts->opts[i].key, key, key_len - 1))
{
const char* val = core_option_manager_get_val(
coreopts, i);
if (val)
{
if (rcheevos_match_value(
val, disallowed_setting->value))
{
key = coreopts->opts[i].key;
allowed = 0;
break;
}
}
}
}
}
else
{
for (i = 0; i < coreopts->size; i++)
{
if (string_is_equal(coreopts->opts[i].key, key))
{
val = core_option_manager_get_val(coreopts, i);
if (rcheevos_match_value(val, disallowed_setting->value))
{
allowed = 0;
break;
}
}
}
}
if (!allowed)
{
char buffer[256];
snprintf(buffer, sizeof(buffer), "Hardcore paused. Setting not allowed: %s=%s", key, val);
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);
break;
}
}
}
runloop_msg_queue_push(buffer, 0, 4 * 60, false, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_WARNING);
break;
}
++core_filter;
}
}
@ -1783,7 +1689,7 @@ void rcheevos_test(void)
if (rcheevos_locals.memory.count == 0)
{
/* we were unable to initialize memory earlier, try now */
if (!rcheevos_memory_init(&rcheevos_locals.memory, rcheevos_locals.patchdata.console_id))
if (!rcheevos_init_memory(&rcheevos_locals))
{
const settings_t* settings = config_get_ptr();
rcheevos_locals.core_supports = false;
@ -2761,11 +2667,6 @@ static void rc_hash_handle_cd_close_track(void* track_handle)
}
}
static void rc_hash_handle_log_message(const char* message)
{
CHEEVOS_LOG(RCHEEVOS_TAG "%s\n", message);
}
/* end hooks */
bool rcheevos_load(const void *data)
@ -2815,13 +2716,13 @@ bool rcheevos_load(const void *data)
cdreader.close_track = rc_hash_handle_cd_close_track;
rc_hash_init_custom_cdreader(&cdreader);
rc_hash_init_error_message_callback(rc_hash_handle_log_message);
rc_hash_init_error_message_callback(rcheevos_handle_log_message);
#ifndef DEBUG /* in DEBUG mode, always initialize the verbose message handler */
if (settings->bools.cheevos_verbose_enable)
#endif
{
rc_hash_init_verbose_message_callback(rc_hash_handle_log_message);
rc_hash_init_verbose_message_callback(rcheevos_handle_log_message);
}
task = task_init();

View File

@ -19,7 +19,7 @@
#include "../deps/rcheevos/include/rc_runtime.h"
#include "cheevos_memory.h"
#include "../deps/rcheevos/src/rcheevos/rc_libretro.h"
#include <../command.h>
#include <../verbosity.h>
@ -125,7 +125,7 @@ typedef struct rcheevos_locals_t
{
rc_runtime_t runtime; /* rcheevos runtime state */
rcheevos_rapatchdata_t patchdata; /* achievement/leaderboard data from the server */
rcheevos_memory_regions_t memory; /* achievement addresses to core memory mappings */
rc_libretro_memory_regions_t memory;/* achievement addresses to core memory mappings */
retro_task_t* task; /* load task */
#ifdef HAVE_THREADS

View File

@ -1,352 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2015-2016 - Andre Leiradella
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "cheevos_memory.h"
#include "cheevos_locals.h"
#include "../retroarch.h"
#include "../verbosity.h"
#include "../deps/rcheevos/include/rcheevos.h"
#include <stdio.h>
uint8_t* rcheevos_memory_find(
const rcheevos_memory_regions_t* regions, unsigned address)
{
unsigned i;
for (i = 0; i < regions->count; ++i)
{
const size_t size = regions->size[i];
if (address < size)
{
if (regions->data[i] == NULL)
break;
return &regions->data[i][address];
}
address -= size;
}
return NULL;
}
static const char* rcheevos_memory_type(int type)
{
switch (type)
{
case RC_MEMORY_TYPE_SAVE_RAM:
return "SRAM";
case RC_MEMORY_TYPE_VIDEO_RAM:
return "VRAM";
case RC_MEMORY_TYPE_UNUSED:
return "UNUSED";
default:
break;
}
return "SYSTEM RAM";
}
static void rcheevos_memory_register_region(rcheevos_memory_regions_t* regions,
int type, uint8_t* data, size_t size, const char* description)
{
if (size == 0)
return;
if (regions->count == MAX_MEMORY_REGIONS)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Too many memory memory regions to register\n");
return;
}
if (!data && regions->count > 0 && !regions->data[regions->count - 1])
{
/* extend null region */
regions->size[regions->count - 1] += size;
}
else if (data && regions->count > 0 &&
data == (regions->data[regions->count - 1] + regions->size[regions->count - 1]))
{
/* extend non-null region */
regions->size[regions->count - 1] += size;
}
else
{
/* create new region */
regions->data[regions->count] = data;
regions->size[regions->count] = size;
++regions->count;
}
regions->total_size += size;
CHEEVOS_LOG(RCHEEVOS_TAG "Registered 0x%04X bytes of %s at $%06X (%s)\n", (unsigned)size,
rcheevos_memory_type(type), (unsigned)(regions->total_size - size), description);
}
static void rcheevos_memory_init_without_regions(
rcheevos_memory_regions_t* regions)
{
/* no regions specified, assume system RAM followed by save RAM */
char description[64];
retro_ctx_memory_info_t meminfo;
snprintf(description, sizeof(description), "offset 0x%06x", 0);
meminfo.id = RETRO_MEMORY_SYSTEM_RAM;
core_get_memory(&meminfo);
rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SYSTEM_RAM, (uint8_t*)meminfo.data, meminfo.size, description);
meminfo.id = RETRO_MEMORY_SAVE_RAM;
core_get_memory(&meminfo);
rcheevos_memory_register_region(regions, RC_MEMORY_TYPE_SAVE_RAM, (uint8_t*)meminfo.data, meminfo.size, description);
}
static const rarch_memory_descriptor_t* rcheevos_memory_get_descriptor(const rarch_memory_map_t* mmap, unsigned real_address)
{
const rarch_memory_descriptor_t* desc = mmap->descriptors;
const rarch_memory_descriptor_t* end = desc + mmap->num_descriptors;
if (mmap->num_descriptors == 0)
return NULL;
for (; desc < end; desc++)
{
if (desc->core.select == 0)
{
/* if select is 0, attempt to explcitly match the address */
if (real_address >= desc->core.start && real_address < desc->core.start + desc->core.len)
return desc;
}
else
{
/* otherwise, attempt to match the address by matching the select bits */
if (((desc->core.start ^ real_address) & desc->core.select) == 0)
{
/* sanity check - make sure the descriptor is large enough to hold the target address */
if (real_address - desc->core.start < desc->core.len)
return desc;
}
}
}
return NULL;
}
void rcheevos_memory_init_from_memory_map(rcheevos_memory_regions_t* regions, const rarch_memory_map_t* mmap, const rc_memory_regions_t* console_regions)
{
char description[64];
unsigned i;
uint8_t* region_start;
uint8_t* desc_start;
size_t desc_size;
size_t offset;
for (i = 0; i < console_regions->num_regions; ++i)
{
const rc_memory_region_t* console_region = &console_regions->region[i];
size_t console_region_size = console_region->end_address - console_region->start_address + 1;
unsigned real_address = console_region->real_address;
while (console_region_size > 0)
{
const rarch_memory_descriptor_t* desc = rcheevos_memory_get_descriptor(mmap, real_address);
if (!desc)
{
if (console_region->type != RC_MEMORY_TYPE_UNUSED)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Could not map region starting at $%06X\n",
real_address - console_region->real_address + console_region->start_address);
}
rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size, "null filler");
break;
}
offset = real_address - desc->core.start;
snprintf(description, sizeof(description),
"descriptor %u, offset 0x%06X",
(int)(desc - mmap->descriptors) + 1, (int)offset);
if (desc->core.ptr)
{
desc_start = (uint8_t*)desc->core.ptr + desc->core.offset;
region_start = desc_start + offset;
}
else
region_start = NULL;
desc_size = desc->core.len - offset;
if (console_region_size > desc_size)
{
if (desc_size == 0)
{
if (console_region->type != RC_MEMORY_TYPE_UNUSED)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Could not map region starting at $%06X\n",
real_address - console_region->real_address + console_region->start_address);
}
rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size, "null filler");
console_region_size = 0;
}
else
{
rcheevos_memory_register_region(regions, console_region->type, region_start, desc_size, description);
console_region_size -= desc_size;
real_address += desc_size;
}
}
else
{
rcheevos_memory_register_region(regions, console_region->type, region_start, console_region_size, description);
console_region_size = 0;
}
}
}
}
static unsigned rcheevos_memory_console_region_to_ram_type(int region_type)
{
switch (region_type)
{
case RC_MEMORY_TYPE_SAVE_RAM:
return RETRO_MEMORY_SAVE_RAM;
case RC_MEMORY_TYPE_VIDEO_RAM:
return RETRO_MEMORY_VIDEO_RAM;
default:
break;
}
return RETRO_MEMORY_SYSTEM_RAM;
}
static void rcheevos_memory_init_from_unmapped_memory(rcheevos_memory_regions_t* regions, const rc_memory_regions_t* console_regions, int console)
{
char description[64];
unsigned i;
for (i = 0; i < console_regions->num_regions; ++i)
{
size_t offset;
unsigned j;
retro_ctx_memory_info_t meminfo;
const rc_memory_region_t* console_region = &console_regions->region[i];
const size_t console_region_size =
console_region->end_address - console_region->start_address + 1;
unsigned base_address = 0;
meminfo.id = rcheevos_memory_console_region_to_ram_type(console_region->type);
for (j = 0; j <= i; ++j)
{
const rc_memory_region_t* console_region2 = &console_regions->region[j];
if (rcheevos_memory_console_region_to_ram_type(
console_region2->type) == meminfo.id)
{
base_address = console_region2->start_address;
break;
}
}
offset = console_region->start_address - base_address;
core_get_memory(&meminfo);
if (offset < meminfo.size)
{
meminfo.size -= offset;
if (meminfo.data)
{
snprintf(description, sizeof(description),
"offset 0x%06X", (int)offset);
meminfo.data = (uint8_t*)meminfo.data + offset;
}
else
snprintf(description, sizeof(description), "null filler");
}
else
{
if (console_region->type != RC_MEMORY_TYPE_UNUSED)
{
CHEEVOS_LOG(RCHEEVOS_TAG "Could not map region starting at $%06X\n", console_region->start_address);
}
meminfo.data = NULL;
meminfo.size = 0;
}
if (console_region_size > meminfo.size)
{
/* want more than what is available, take what we can and null fill the rest */
rcheevos_memory_register_region(regions, console_region->type, (uint8_t*)meminfo.data, meminfo.size, description);
rcheevos_memory_register_region(regions, console_region->type, NULL, console_region_size - meminfo.size, "null filler");
}
else
{
/* only take as much as we need */
rcheevos_memory_register_region(regions, console_region->type, (uint8_t*)meminfo.data, console_region_size, description);
}
}
}
void rcheevos_memory_destroy(rcheevos_memory_regions_t* regions)
{
memset(regions, 0, sizeof(*regions));
}
bool rcheevos_memory_init(rcheevos_memory_regions_t* regions, int console)
{
unsigned i;
const rc_memory_regions_t* console_regions = rc_console_memory_regions(console);
rcheevos_memory_regions_t new_regions;
bool has_valid_region = false;
if (!regions)
return false;
memset(&new_regions, 0, sizeof(new_regions));
if (console_regions == NULL || console_regions->num_regions == 0)
{
rcheevos_memory_init_without_regions(&new_regions);
}
else
{
rarch_system_info_t* system = runloop_get_system_info();
if (system->mmaps.num_descriptors != 0)
rcheevos_memory_init_from_memory_map(&new_regions, &system->mmaps, console_regions);
else
rcheevos_memory_init_from_unmapped_memory(&new_regions, console_regions, console);
}
/* determine if any valid regions were found */
for (i = 0; i < new_regions.count; i++)
{
if (new_regions.data[i])
{
has_valid_region = true;
break;
}
}
memcpy(regions, &new_regions, sizeof(*regions));
return has_valid_region;
}

View File

@ -1,44 +0,0 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2015-2018 - Andre Leiradella
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RARCH_CHEEVOS_MEMORY_H
#define __RARCH_CHEEVOS_MEMORY_H
#include <stdint.h>
#include <stdlib.h>
#include <boolean.h>
#include <retro_common_api.h>
RETRO_BEGIN_DECLS
#define MAX_MEMORY_REGIONS 32
typedef struct
{
uint8_t* data[MAX_MEMORY_REGIONS];
size_t size[MAX_MEMORY_REGIONS];
size_t total_size;
unsigned count;
} rcheevos_memory_regions_t;
bool rcheevos_memory_init(rcheevos_memory_regions_t* regions, int console);
void rcheevos_memory_destroy(rcheevos_memory_regions_t* regions);
uint8_t* rcheevos_memory_find(const rcheevos_memory_regions_t* regions,
unsigned address);
RETRO_END_DECLS
#endif

View File

@ -192,7 +192,6 @@ ACHIEVEMENTS
#include "../cheevos/cheevos.c"
#include "../cheevos/cheevos_menu.c"
#include "../cheevos/cheevos_memory.c"
#include "../cheevos/cheevos_parser.c"
#include "../deps/rcheevos/src/rcheevos/alloc.c"
@ -204,6 +203,7 @@ ACHIEVEMENTS
#include "../deps/rcheevos/src/rcheevos/lboard.c"
#include "../deps/rcheevos/src/rcheevos/memref.c"
#include "../deps/rcheevos/src/rcheevos/operand.c"
#include "../deps/rcheevos/src/rcheevos/rc_libretro.c"
#include "../deps/rcheevos/src/rcheevos/richpresence.c"
#include "../deps/rcheevos/src/rcheevos/runtime.c"
#include "../deps/rcheevos/src/rcheevos/runtime_progress.c"