added RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS; cheevos now work with mmaps

This commit is contained in:
Andre Leiradella 2016-05-12 22:03:18 -03:00
parent 3d7be61363
commit 031686f27a
4 changed files with 135 additions and 110 deletions

225
cheevos.c
View File

@ -24,6 +24,7 @@
#include "cheevos.h"
#include "dynamic.h"
#include "libretro.h"
#include "system.h"
#include "network/net_http_special.h"
#include "configuration.h"
#include "performance_counters.h"
@ -44,6 +45,9 @@
/* Define this macro to log URLs (will log the user token). */
#undef CHEEVOS_LOG_URLS
/* Define this macro to dump all cheevos' addresses. */
#undef CHEEVOS_DUMP_ADDRS
#define JSON_KEY_GAMEID 0xb4960eecU
#define JSON_KEY_ACHIEVEMENTS 0x69749ae1U
#define JSON_KEY_ID 0x005973f2U
@ -62,6 +66,7 @@
enum
{
CHEEVOS_CONSOLE_GAMEBOY = 4,
CHEEVOS_CONSOLE_GAMEBOY_ADVANCED = 5,
CHEEVOS_CONSOLE_GAMEBOY_COLOR = 6,
};
@ -142,7 +147,7 @@ typedef struct
{
unsigned size;
unsigned type;
unsigned bank_id;
int bank_id;
unsigned value;
unsigned previous;
} cheevos_var_t;
@ -218,7 +223,7 @@ typedef struct
typedef struct
{
int in_cheevos;
int console_id;
int is_console_id;
unsigned core_count;
unsigned unofficial_count;
@ -236,19 +241,23 @@ typedef struct
typedef struct
{
int loaded;
int console_id;
int loaded;
int console_id;
bool core_supports;
cheevoset_t core;
cheevoset_t unofficial;
char token[32];
retro_ctx_memory_info_t meminfo[4];
} cheevos_locals_t;
static cheevos_locals_t cheevos_locals =
{
0,
0,
true,
{NULL, 0},
{NULL, 0},
{0},
@ -620,6 +629,69 @@ static void cheevos_parse_var(cheevos_var_t *var, const char **memaddr)
var->value = strtol(str, &end, base);
*memaddr = end;
if ( var->type == CHEEVOS_VAR_TYPE_ADDRESS
|| var->type == CHEEVOS_VAR_TYPE_DELTA_MEM)
{
rarch_system_info_t *system;
runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system);
var->bank_id = -1;
if (system->mmaps.num_descriptors != 0)
{
const struct retro_memory_descriptor *desc;
const struct retro_memory_descriptor *end;
#if 0
if (cheevos_locals.console_id == CHEEVOS_CONSOLE_GAMEBOY_ADVANCED)
{
/* Patch the address to correctly map it to the mmaps */
if (var->value < 0x8000)
{
/* Internal RAM */
var->value += 0x3000000;
}
else
{
/* Work RAM */
var->value += 0x2000000 - 0x8000;
}
}
#endif
desc = system->mmaps.descriptors;
end = desc + system->mmaps.num_descriptors;
for (; desc < end; desc++)
{
if (var->value >= desc->start && var->value < (desc->start + desc->len))
{
var->bank_id = desc - system->mmaps.descriptors;
var->value = var->value - desc->start + desc->offset;
break;
}
}
}
else
{
unsigned i;
for (i = 0; i < sizeof(cheevos_locals.meminfo) / sizeof(cheevos_locals.meminfo[0]); i++)
{
if (var->value < cheevos_locals.meminfo[i].size)
{
var->bank_id = i;
break;
}
var->value -= cheevos_locals.meminfo[i].size;
}
}
#ifdef CHEEVOS_DUMP_ADDRS
RARCH_LOG("CHEEVOS var %03d:%08X\n", var->bank_id + 1, var->value);
#endif
}
}
static void cheevos_parse_cond(cheevos_cond_t *cond, const char **memaddr)
@ -818,7 +890,7 @@ static int cheevos_read__json_key( void *userdata,
if (hash == JSON_KEY_ACHIEVEMENTS)
ud->in_cheevos = 1;
else if (hash == JSON_KEY_CONSOLE_ID)
ud->console_id = 0;
ud->is_console_id = 1;
else if (ud->in_cheevos)
{
switch ( hash )
@ -883,8 +955,11 @@ static int cheevos_read__json_number(void *userdata,
ud->field->string = number;
ud->field->length = length;
}
else if (ud->console_id == 0)
ud->console_id = strtol(number, NULL, 10);
else if (ud->is_console_id)
{
cheevos_locals.console_id = strtol(number, NULL, 10);
ud->is_console_id = 0;
}
return 0;
}
@ -963,7 +1038,7 @@ static int cheevos_parse(const char *json)
/* Load the achievements. */
ud.in_cheevos = 0;
ud.console_id = -1;
ud.is_console_id = 0;
ud.field = NULL;
ud.core_count = 0;
ud.unofficial_count = 0;
@ -974,7 +1049,6 @@ static int cheevos_parse(const char *json)
return -1;
}
cheevos_locals.console_id = ud.console_id;
return 0;
}
@ -982,63 +1056,23 @@ static int cheevos_parse(const char *json)
Test all the achievements (call once per frame).
*****************************************************************************/
static const uint8_t *cheevos_get_memory(unsigned offset)
static const uint8_t *cheevos_get_memory(const cheevos_var_t *var)
{
retro_ctx_memory_info_t mem_info;
uint8_t *memory = NULL;
if (var->bank_id >= 0)
{
rarch_system_info_t *system;
runloop_ctl(RUNLOOP_CTL_SYSTEM_INFO_GET, &system);
if (system->mmaps.num_descriptors != 0)
{
return (uint8_t *)system->mmaps.descriptors[var->bank_id].ptr + var->value;
}
else
{
return (uint8_t *)cheevos_locals.meminfo[var->bank_id].data + var->value;
}
}
mem_info.id = RETRO_MEMORY_SYSTEM_RAM;
core_get_memory(&mem_info);
if (offset < mem_info.size)
{
memory = (uint8_t*)mem_info.data;
return memory + offset;
}
offset -= mem_info.size;
mem_info.data = NULL;
mem_info.size = 0;
mem_info.id = RETRO_MEMORY_SAVE_RAM;
core_get_memory(&mem_info);
if (offset < mem_info.size)
{
memory = (uint8_t*)mem_info.data;
return memory + offset;
}
offset -= mem_info.size;
mem_info.data = NULL;
mem_info.size = 0;
mem_info.id = RETRO_MEMORY_VIDEO_RAM;
core_get_memory(&mem_info);
if (offset < mem_info.size)
{
memory = (uint8_t*)mem_info.data;
return memory + offset;
}
offset -= mem_info.size;
mem_info.data = NULL;
mem_info.size = 0;
mem_info.id = RETRO_MEMORY_RTC;
core_get_memory(&mem_info);
if (offset < mem_info.size)
{
memory = (uint8_t*)mem_info.data;
return memory + offset;
}
return NULL;
}
@ -1055,7 +1089,7 @@ static unsigned cheevos_get_var_value(cheevos_var_t *var)
|| var->type == CHEEVOS_VAR_TYPE_DELTA_MEM)
{
/* TODO Check with Scott if the bank id is needed */
memory = cheevos_get_memory(var->value);
memory = cheevos_get_memory(var);
if (memory)
{
@ -1396,7 +1430,7 @@ static void cheevos_unlocker(void *payload)
request[sizeof(request) - 1] = 0;
#ifdef CHEEVOS_LOG_URLS
RARCH_LOG("CHEEVOS url to award a cheevo: %s\n", request);
RARCH_LOG("CHEEVOS url to award the cheevo: %s\n", request);
#endif
if (!cheevos_http_get(&result, NULL, request, NULL))
@ -1970,8 +2004,6 @@ static unsigned cheevos_find_game_id_nes(
bool cheevos_load(const void *data)
{
retro_ctx_memory_info_t mem_info;
static const uint32_t genesis_exts[] =
{
0x0b888feeU, /* mdx */
@ -2008,7 +2040,6 @@ bool cheevos_load(const void *data)
{cheevos_find_game_id_generic, "Generic (plain content)", NULL},
};
size_t memory;
struct retro_system_info sysinfo;
unsigned i;
const char *json = NULL;
@ -2019,52 +2050,21 @@ bool cheevos_load(const void *data)
cheevos_locals.loaded = 0;
/* Just return OK if cheevos are disabled. */
if (!settings->cheevos.enable)
/* Just return OK if cheevos are disabled, the core doesn't support cheevos, or info is NULL. */
if (!settings->cheevos.enable || !cheevos_locals.core_supports || !info)
return true;
/* Also return OK if there's no content. */
if (!info)
return true;
cheevos_locals.meminfo[0].id = RETRO_MEMORY_SYSTEM_RAM;
core_get_memory(&cheevos_locals.meminfo[0]);
mem_info.data = NULL;
mem_info.size = 0;
mem_info.id = RETRO_MEMORY_SYSTEM_RAM;
cheevos_locals.meminfo[1].id = RETRO_MEMORY_SAVE_RAM;
core_get_memory(&cheevos_locals.meminfo[1]);
core_get_memory(&mem_info);
memory = mem_info.size;
cheevos_locals.meminfo[2].id = RETRO_MEMORY_VIDEO_RAM;
core_get_memory(&cheevos_locals.meminfo[2]);
mem_info.data = NULL;
mem_info.size = 0;
mem_info.id = RETRO_MEMORY_VIDEO_RAM;
core_get_memory(&mem_info);
memory += mem_info.size;
mem_info.data = NULL;
mem_info.size = 0;
mem_info.id = RETRO_MEMORY_RTC;
core_get_memory(&mem_info);
memory += mem_info.size;
mem_info.data = NULL;
mem_info.size = 0;
mem_info.id = RETRO_MEMORY_SAVE_RAM;
core_get_memory(&mem_info);
memory += mem_info.size;
if (!memory)
{
runloop_msg_queue_push("This core doesn't support achievements", 0, 5 * 60, false);
RARCH_ERR("This core doesn't support achievements\n");
return false;
}
cheevos_locals.meminfo[3].id = RETRO_MEMORY_RTC;
core_get_memory(&cheevos_locals.meminfo[3]);
/* The the supported extensions as a hint to what method we should use. */
@ -2306,3 +2306,8 @@ bool cheevos_set_cheats(void)
return true;
}
void cheevos_set_support_cheevos(bool state)
{
cheevos_locals.core_supports = state;
}

View File

@ -42,4 +42,6 @@ bool cheevos_test(void);
bool cheevos_set_cheats(void);
void cheevos_set_support_cheevos(bool state);
#endif /* __RARCH_CHEEVOS_H */

View File

@ -45,6 +45,7 @@
#include "cores/internal_cores.h"
#include "frontend/frontend_driver.h"
#include "content.h"
#include "cheevos.h"
#include "retroarch.h"
#include "configuration.h"
#include "general.h"
@ -1428,6 +1429,14 @@ bool rarch_environment_cb(unsigned cmd, void *data)
case RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE:
return video_driver_get_hw_render_interface(
(const struct retro_hw_render_interface**)data);
case RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS:
{
bool state = *(const bool*)data;
RARCH_LOG("Environ SET_SUPPORT_ACHIEVEMENTS: %s.\n", state ? "yes" : "no");
cheevos_set_support_cheevos(state);
break;
}
/* Private extensions for internal use, not part of libretro API. */
/* None yet. */

View File

@ -946,6 +946,15 @@ struct retro_hw_render_interface
* the contents of the HW_RENDER_INTERFACE are invalidated.
*/
#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)
/* const bool * --
* If true, the libretro implementation supports achievements
* either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS
* or via retro_get_memory_data/retro_get_memory_size.
*
* This must be called before the first call to retro_run.
*/
#define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */
#define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */
#define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */