mirror of
https://github.com/libretro/RetroArch.git
synced 2025-04-01 12:11:43 +00:00
(cheevos) use common functionality moved into rcheevos (#12504)
* user rcheevos for disallowed_settings * use rcheevos for memory map
This commit is contained in:
parent
27cacffe54
commit
75fcd63b4a
@ -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 \
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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 ®ions->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;
|
||||
}
|
@ -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
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user