mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
replace coroutines with tasks (#13178)
This commit is contained in:
parent
abce5e1c6f
commit
20264aaced
@ -2120,7 +2120,6 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
OBJ += cheevos/cheevos.o \
|
||||
cheevos/cheevos_client.o \
|
||||
cheevos/cheevos_menu.o \
|
||||
cheevos/cheevos_parser.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/cdfs/cdfs.o \
|
||||
deps/rcheevos/src/rcheevos/alloc.o \
|
||||
deps/rcheevos/src/rcheevos/compat.o \
|
||||
@ -2141,7 +2140,6 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
deps/rcheevos/src/rapi/rc_api_common.o \
|
||||
deps/rcheevos/src/rapi/rc_api_runtime.o \
|
||||
deps/rcheevos/src/rapi/rc_api_user.o \
|
||||
deps/rcheevos/src/rurl/url.o
|
||||
|
||||
ifeq ($(HAVE_LUA), 1)
|
||||
DEFINES += -DHAVE_LUA \
|
||||
|
1746
cheevos/cheevos.c
1746
cheevos/cheevos.c
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -20,13 +20,29 @@
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef void (*rcheevos_client_callback)(void* userdata);
|
||||
|
||||
void rcheevos_client_initialize(void);
|
||||
|
||||
void rcheevos_client_login_with_password(const char* username, const char* password,
|
||||
rcheevos_client_callback callback, void* userdata);
|
||||
void rcheevos_client_login_with_token(const char* username, const char* token,
|
||||
rcheevos_client_callback callback, void* userdata);
|
||||
|
||||
void rcheevos_client_identify_game(const char* hash, rcheevos_client_callback callback, void* userdata);
|
||||
|
||||
void rcheevos_client_initialize_runtime(unsigned game_id, rcheevos_client_callback callback, void* userdata);
|
||||
|
||||
void rcheevos_client_start_session(unsigned game_id);
|
||||
void rcheevos_client_award_achievement(unsigned achievement_id);
|
||||
void rcheevos_client_submit_lboard_entry(unsigned leaderboard_id, int value);
|
||||
|
||||
void rcheevos_client_fetch_badges(rcheevos_client_callback callback, void* userdata);
|
||||
|
||||
void rcheevos_log_url(const char* api, const char* url);
|
||||
void rcheevos_get_user_agent(rcheevos_locals_t *locals, char *buffer, size_t len);
|
||||
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif /* __RARCH_CHEEVOS_MENU_H */
|
||||
|
@ -61,7 +61,8 @@ enum
|
||||
{
|
||||
RCHEEVOS_ACTIVE_SOFTCORE = 1 << 0,
|
||||
RCHEEVOS_ACTIVE_HARDCORE = 1 << 1,
|
||||
RCHEEVOS_ACTIVE_UNOFFICIAL = 1 << 2
|
||||
RCHEEVOS_ACTIVE_UNOFFICIAL = 1 << 2,
|
||||
RCHEEVOS_ACTIVE_UNSUPPORTED = 1 << 3
|
||||
};
|
||||
|
||||
typedef struct rcheevos_racheevo_t
|
||||
@ -94,20 +95,45 @@ typedef struct rcheevos_ralboard_t
|
||||
unsigned format;
|
||||
} rcheevos_ralboard_t;
|
||||
|
||||
typedef struct rcheevos_rapatchdata_t
|
||||
{
|
||||
char* title;
|
||||
rcheevos_racheevo_t* core;
|
||||
rcheevos_racheevo_t* unofficial;
|
||||
rcheevos_ralboard_t* lboards;
|
||||
char* richpresence_script;
|
||||
|
||||
unsigned game_id;
|
||||
unsigned console_id;
|
||||
unsigned core_count;
|
||||
unsigned unofficial_count;
|
||||
unsigned lboard_count;
|
||||
} rcheevos_rapatchdata_t;
|
||||
enum rcheevos_load_state
|
||||
{
|
||||
RCHEEVOS_LOAD_STATE_NONE,
|
||||
RCHEEVOS_LOAD_STATE_IDENTIFYING_GAME,
|
||||
RCHEEVOS_LOAD_STATE_FETCHING_GAME_DATA,
|
||||
RCHEEVOS_LOAD_STATE_STARTING_SESSION,
|
||||
RCHEEVOS_LOAD_STATE_FETCHING_BADGES,
|
||||
RCHEEVOS_LOAD_STATE_DONE,
|
||||
RCHEEVOS_LOAD_STATE_UNKNOWN_GAME,
|
||||
RCHEEVOS_LOAD_STATE_NETWORK_ERROR,
|
||||
RCHEEVOS_LOAD_STATE_LOGIN_FAILED,
|
||||
RCHEEVOS_LOAD_STATE_ABORTED
|
||||
};
|
||||
|
||||
typedef struct rcheevos_load_info_t
|
||||
{
|
||||
enum rcheevos_load_state state;
|
||||
int hashes_tried;
|
||||
int outstanding_requests;
|
||||
#ifdef HAVE_THREADS
|
||||
slock_t* request_lock;
|
||||
#endif
|
||||
} rcheevos_load_info_t;
|
||||
|
||||
typedef struct rcheevos_game_info_t
|
||||
{
|
||||
int id;
|
||||
int console_id;
|
||||
char* title;
|
||||
char hash[33];
|
||||
|
||||
rcheevos_racheevo_t* achievements;
|
||||
rcheevos_ralboard_t* leaderboards;
|
||||
|
||||
unsigned achievement_count;
|
||||
unsigned leaderboard_count;
|
||||
|
||||
} rcheevos_game_info_t;
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
|
||||
@ -124,18 +150,15 @@ void rcheevos_menu_reset_badges(void);
|
||||
typedef struct rcheevos_locals_t
|
||||
{
|
||||
rc_runtime_t runtime; /* rcheevos runtime state */
|
||||
rcheevos_rapatchdata_t patchdata; /* achievement/leaderboard data from the server */
|
||||
rcheevos_game_info_t game; /* information about the current game */
|
||||
rc_libretro_memory_regions_t memory;/* achievement addresses to core memory mappings */
|
||||
|
||||
retro_task_t* task; /* load task */
|
||||
#ifdef HAVE_THREADS
|
||||
slock_t* task_lock; /* mutex for starting/stopping load task */
|
||||
enum event_command queued_command; /* action queued by background thread to be run on main thread */
|
||||
#endif
|
||||
|
||||
char username[32]; /* case-corrected username */
|
||||
char token[32]; /* user's session token */
|
||||
char hash[33]; /* retroachievements hash for current content */
|
||||
char user_agent_prefix[128]; /* RetroArch/OS version information */
|
||||
char user_agent_core[256]; /* RetroArch/OS/Core version information */
|
||||
|
||||
@ -145,16 +168,28 @@ typedef struct rcheevos_locals_t
|
||||
unsigned menuitem_count; /* current number of items in the menuitems array */
|
||||
#endif
|
||||
|
||||
rcheevos_load_info_t load_info; /* load info */
|
||||
|
||||
bool hardcore_active; /* hardcore functionality is active */
|
||||
bool loaded; /* load task has completed */
|
||||
bool core_supports; /* false if core explicitly disables achievements */
|
||||
bool network_error; /* hash lookup or login failed with network error */
|
||||
bool leaderboards_enabled; /* leaderboards are enabled */
|
||||
bool leaderboard_notifications; /* leaderboard notifications are enabled */
|
||||
bool leaderboard_trackers; /* leaderboard trackers are enabled */
|
||||
} rcheevos_locals_t;
|
||||
|
||||
rcheevos_locals_t* get_rcheevos_locals(void);
|
||||
void rcheevos_begin_load_state(enum rcheevos_load_state state);
|
||||
int rcheevos_end_load_state(void);
|
||||
bool rcheevos_load_aborted(void);
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
#define CHEEVOS_LOCK(l) do { slock_lock(l); } while (0)
|
||||
#define CHEEVOS_UNLOCK(l) do { slock_unlock(l); } while (0)
|
||||
#else
|
||||
#define CHEEVOS_LOCK(l)
|
||||
#define CHEEVOS_UNLOCK(l)
|
||||
#endif
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
|
@ -35,6 +35,7 @@ enum rcheevos_menuitem_bucket
|
||||
RCHEEVOS_MENUITEM_BUCKET_LOCKED,
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNLOCKED,
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED,
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL,
|
||||
RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED,
|
||||
RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE,
|
||||
RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE
|
||||
@ -44,7 +45,7 @@ static void rcheevos_menu_update_bucket(rcheevos_racheevo_t* cheevo)
|
||||
{
|
||||
cheevo->menu_progress = 0;
|
||||
|
||||
if (!cheevo->memaddr)
|
||||
if (cheevo->active & RCHEEVOS_ACTIVE_UNSUPPORTED)
|
||||
{
|
||||
/* non-active unsupported achievement */
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED;
|
||||
@ -67,7 +68,10 @@ static void rcheevos_menu_update_bucket(rcheevos_racheevo_t* cheevo)
|
||||
}
|
||||
|
||||
/* active achievement */
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_LOCKED;
|
||||
if (cheevo->active & RCHEEVOS_ACTIVE_UNOFFICIAL)
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL;
|
||||
else
|
||||
cheevo->menu_bucket = RCHEEVOS_MENUITEM_BUCKET_LOCKED;
|
||||
|
||||
trigger = rc_runtime_get_achievement(&rcheevos_locals->runtime, cheevo->id);
|
||||
if (trigger)
|
||||
@ -88,29 +92,17 @@ static void rcheevos_menu_update_bucket(rcheevos_racheevo_t* cheevo)
|
||||
}
|
||||
}
|
||||
|
||||
static void rcheevos_menu_update_buckets(bool cheevos_test_unofficial)
|
||||
static void rcheevos_menu_update_buckets(void)
|
||||
{
|
||||
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->patchdata.core;
|
||||
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->patchdata.core_count;
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->game.achievements;
|
||||
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->game.achievement_count;
|
||||
|
||||
while (cheevo < stop)
|
||||
{
|
||||
rcheevos_menu_update_bucket(cheevo);
|
||||
++cheevo;
|
||||
}
|
||||
|
||||
if (cheevos_test_unofficial)
|
||||
{
|
||||
cheevo = rcheevos_locals->patchdata.unofficial;
|
||||
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
|
||||
|
||||
while (cheevo < stop)
|
||||
{
|
||||
rcheevos_menu_update_bucket(cheevo);
|
||||
++cheevo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool rcheevos_menu_get_state(unsigned menu_offset, char *buffer, size_t len)
|
||||
@ -165,18 +157,8 @@ bool rcheevos_menu_get_sublabel(unsigned menu_offset, char *buffer, size_t len)
|
||||
void rcheevos_menu_reset_badges(void)
|
||||
{
|
||||
const rcheevos_locals_t* rcheevos_locals = get_rcheevos_locals();
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->patchdata.core;
|
||||
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->patchdata.core_count;
|
||||
|
||||
while (cheevo < stop)
|
||||
{
|
||||
if (cheevo->menu_badge_texture)
|
||||
video_driver_texture_unload(&cheevo->menu_badge_texture);
|
||||
++cheevo;
|
||||
}
|
||||
|
||||
cheevo = rcheevos_locals->patchdata.unofficial;
|
||||
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->game.achievements;
|
||||
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->game.achievement_count;
|
||||
|
||||
while (cheevo < stop)
|
||||
{
|
||||
@ -250,6 +232,7 @@ static void rcheevos_menu_update_badge(rcheevos_racheevo_t* cheevo)
|
||||
switch (cheevo->menu_bucket)
|
||||
{
|
||||
case RCHEEVOS_MENUITEM_BUCKET_LOCKED:
|
||||
case RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL:
|
||||
case RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED:
|
||||
case RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE:
|
||||
case RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE:
|
||||
@ -292,27 +275,15 @@ static void rcheevos_menu_update_badge(rcheevos_racheevo_t* cheevo)
|
||||
}
|
||||
|
||||
static void rcheevos_menu_append_items(rcheevos_locals_t* rcheevos_locals,
|
||||
bool cheevos_test_unofficial, enum rcheevos_menuitem_bucket bucket)
|
||||
enum rcheevos_menuitem_bucket bucket)
|
||||
{
|
||||
const settings_t *settings = config_get_ptr();
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->patchdata.core;
|
||||
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->patchdata.core_count;
|
||||
bool processing_unofficial = false;
|
||||
rcheevos_racheevo_t* cheevo = rcheevos_locals->game.achievements;
|
||||
rcheevos_racheevo_t* stop = cheevo + rcheevos_locals->game.achievement_count;
|
||||
const unsigned first_index = rcheevos_locals->menuitem_count;
|
||||
|
||||
do
|
||||
while (cheevo < stop)
|
||||
{
|
||||
if (cheevo == stop)
|
||||
{
|
||||
if (!cheevos_test_unofficial || processing_unofficial)
|
||||
break;
|
||||
|
||||
processing_unofficial = true;
|
||||
cheevo = rcheevos_locals->patchdata.unofficial;
|
||||
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cheevo->menu_bucket == bucket)
|
||||
{
|
||||
rcheevos_menuitem_t* menuitem = rcheevos_menu_allocate(rcheevos_locals, cheevo);
|
||||
@ -371,7 +342,7 @@ static void rcheevos_menu_append_items(rcheevos_locals_t* rcheevos_locals,
|
||||
/* fallthrough to default */
|
||||
|
||||
default:
|
||||
if (processing_unofficial)
|
||||
if (cheevo->active & RCHEEVOS_ACTIVE_UNOFFICIAL)
|
||||
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNOFFICIAL_ENTRY;
|
||||
else if (!(cheevo->active & RCHEEVOS_ACTIVE_SOFTCORE))
|
||||
menuitem->state_label_idx = MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY;
|
||||
@ -388,7 +359,7 @@ static void rcheevos_menu_append_items(rcheevos_locals_t* rcheevos_locals,
|
||||
}
|
||||
|
||||
++cheevo;
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t rcheevos_menu_get_badge_texture(unsigned menu_offset)
|
||||
@ -472,7 +443,6 @@ void rcheevos_menu_populate(void* data)
|
||||
{
|
||||
const retro_time_t now = cpu_features_get_time_usec();
|
||||
const retro_time_t recent_unlock_time = now - (10 * 60 * 1000000); /* 10 minutes ago */
|
||||
bool processing_unofficial = false;
|
||||
rcheevos_racheevo_t* cheevo = NULL;
|
||||
rcheevos_racheevo_t* stop = NULL;
|
||||
|
||||
@ -494,25 +464,14 @@ void rcheevos_menu_populate(void* data)
|
||||
}
|
||||
|
||||
/* update the bucket for each achievement */
|
||||
rcheevos_menu_update_buckets(cheevos_test_unofficial);
|
||||
rcheevos_menu_update_buckets();
|
||||
|
||||
/* count items in each bucket */
|
||||
cheevo = rcheevos_locals->patchdata.core;
|
||||
stop = cheevo + rcheevos_locals->patchdata.core_count;
|
||||
cheevo = rcheevos_locals->game.achievements;
|
||||
stop = cheevo + rcheevos_locals->game.achievement_count;
|
||||
|
||||
do
|
||||
while (cheevo < stop)
|
||||
{
|
||||
if (cheevo == stop)
|
||||
{
|
||||
if (!cheevos_test_unofficial || processing_unofficial)
|
||||
break;
|
||||
|
||||
processing_unofficial = true;
|
||||
cheevo = rcheevos_locals->patchdata.unofficial;
|
||||
stop = cheevo + rcheevos_locals->patchdata.unofficial_count;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (cheevo->menu_bucket)
|
||||
{
|
||||
case RCHEEVOS_MENUITEM_BUCKET_UNLOCKED:
|
||||
@ -528,6 +487,7 @@ void rcheevos_menu_populate(void* data)
|
||||
break;
|
||||
|
||||
case RCHEEVOS_MENUITEM_BUCKET_LOCKED:
|
||||
case RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL:
|
||||
++num_locked;
|
||||
break;
|
||||
|
||||
@ -545,14 +505,12 @@ void rcheevos_menu_populate(void* data)
|
||||
}
|
||||
|
||||
++cheevo;
|
||||
} while(true);
|
||||
}
|
||||
|
||||
if (!rcheevos_locals->menuitems)
|
||||
{
|
||||
/* reserve space for all achievements and up to 6 headers before we need to realloc */
|
||||
rcheevos_locals->menuitem_capacity = rcheevos_locals->patchdata.core_count + 6;
|
||||
if (cheevos_test_unofficial)
|
||||
rcheevos_locals->menuitem_capacity += rcheevos_locals->patchdata.unofficial_count;
|
||||
rcheevos_locals->menuitem_capacity = rcheevos_locals->game.achievement_count + 6;
|
||||
|
||||
rcheevos_locals->menuitems = (rcheevos_menuitem_t*)
|
||||
malloc(rcheevos_locals->menuitem_capacity * sizeof(rcheevos_menuitem_t));
|
||||
@ -570,7 +528,7 @@ void rcheevos_menu_populate(void* data)
|
||||
rcheevos_menu_append_header(rcheevos_locals,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_ACTIVE_CHALLENGES_ENTRY);
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
rcheevos_menu_append_items(rcheevos_locals,
|
||||
RCHEEVOS_MENUITEM_BUCKET_ACTIVE_CHALLENGE);
|
||||
}
|
||||
|
||||
@ -580,7 +538,7 @@ void rcheevos_menu_populate(void* data)
|
||||
rcheevos_menu_append_header(rcheevos_locals,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_RECENTLY_UNLOCKED_ENTRY);
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
rcheevos_menu_append_items(rcheevos_locals,
|
||||
RCHEEVOS_MENUITEM_BUCKET_RECENTLY_UNLOCKED);
|
||||
}
|
||||
|
||||
@ -590,7 +548,7 @@ void rcheevos_menu_populate(void* data)
|
||||
rcheevos_menu_append_header(rcheevos_locals,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_ALMOST_THERE_ENTRY);
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
rcheevos_menu_append_items(rcheevos_locals,
|
||||
RCHEEVOS_MENUITEM_BUCKET_ALMOST_THERE);
|
||||
}
|
||||
|
||||
@ -603,8 +561,23 @@ void rcheevos_menu_populate(void* data)
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_LOCKED_ENTRY);
|
||||
}
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
rcheevos_menu_append_items(rcheevos_locals,
|
||||
RCHEEVOS_MENUITEM_BUCKET_LOCKED);
|
||||
rcheevos_menu_append_items(rcheevos_locals,
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNOFFICIAL);
|
||||
}
|
||||
|
||||
/* unsupported */
|
||||
if (num_unsupported)
|
||||
{
|
||||
if (rcheevos_locals->menuitem_count > 0)
|
||||
{
|
||||
rcheevos_menu_append_header(rcheevos_locals,
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_UNSUPPORTED_ENTRY);
|
||||
}
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals,
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/* unlocked */
|
||||
@ -616,7 +589,7 @@ void rcheevos_menu_populate(void* data)
|
||||
MENU_ENUM_LABEL_VALUE_CHEEVOS_UNLOCKED_ENTRY);
|
||||
}
|
||||
|
||||
rcheevos_menu_append_items(rcheevos_locals, cheevos_test_unofficial,
|
||||
rcheevos_menu_append_items(rcheevos_locals,
|
||||
RCHEEVOS_MENUITEM_BUCKET_UNLOCKED);
|
||||
}
|
||||
|
||||
@ -662,7 +635,7 @@ void rcheevos_menu_populate(void* data)
|
||||
MENU_ENUM_LABEL_CANNOT_ACTIVATE_ACHIEVEMENTS_WITH_THIS_CORE,
|
||||
FILE_TYPE_NONE, 0, 0);
|
||||
}
|
||||
else if (rcheevos_locals->network_error)
|
||||
else if (rcheevos_locals->load_info.state == RCHEEVOS_LOAD_STATE_NETWORK_ERROR)
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETWORK_ERROR),
|
||||
@ -670,7 +643,7 @@ void rcheevos_menu_populate(void* data)
|
||||
MENU_ENUM_LABEL_NETWORK_ERROR,
|
||||
FILE_TYPE_NONE, 0, 0);
|
||||
}
|
||||
else if (!rcheevos_locals->patchdata.game_id)
|
||||
else if (!rcheevos_locals->game.id)
|
||||
{
|
||||
menu_entries_append_enum(info->list,
|
||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN_GAME),
|
||||
|
@ -1,692 +0,0 @@
|
||||
#include "cheevos_parser.h"
|
||||
|
||||
#include "cheevos_locals.h"
|
||||
|
||||
#include <encodings/utf.h>
|
||||
#include <formats/rjson.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include "../deps/rcheevos/include/rcheevos.h"
|
||||
|
||||
/* C89 wants only int values in enums. */
|
||||
#define CHEEVOS_JSON_KEY_GAMEID 0xb4960eecU
|
||||
#define CHEEVOS_JSON_KEY_ACHIEVEMENTS 0x69749ae1U
|
||||
#define CHEEVOS_JSON_KEY_ID 0x005973f2U
|
||||
#define CHEEVOS_JSON_KEY_MEMADDR 0x1e76b53fU
|
||||
#define CHEEVOS_JSON_KEY_TITLE 0x0e2a9a07U
|
||||
#define CHEEVOS_JSON_KEY_DESCRIPTION 0xe61a1f69U
|
||||
#define CHEEVOS_JSON_KEY_POINTS 0xca8fce22U
|
||||
#define CHEEVOS_JSON_KEY_AUTHOR 0xa804edb8U
|
||||
#define CHEEVOS_JSON_KEY_MODIFIED 0xdcea4fe6U
|
||||
#define CHEEVOS_JSON_KEY_CREATED 0x3a84721dU
|
||||
#define CHEEVOS_JSON_KEY_BADGENAME 0x887685d9U
|
||||
#define CHEEVOS_JSON_KEY_CONSOLE_ID 0x071656e5U
|
||||
#define CHEEVOS_JSON_KEY_TOKEN 0x0e2dbd26U
|
||||
#define CHEEVOS_JSON_KEY_USERNAME 0x7c8da264U
|
||||
#define CHEEVOS_JSON_KEY_FLAGS 0x0d2e96b2U
|
||||
#define CHEEVOS_JSON_KEY_LEADERBOARDS 0xf1247d2dU
|
||||
#define CHEEVOS_JSON_KEY_RICHPRESENCE 0xf18dd230U
|
||||
#define CHEEVOS_JSON_KEY_MEM 0x0b8807e4U
|
||||
#define CHEEVOS_JSON_KEY_FORMAT 0xb341208eU
|
||||
#define CHEEVOS_JSON_KEY_SUCCESS 0x110461deU
|
||||
#define CHEEVOS_JSON_KEY_ERROR 0x0d2011cfU
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* value;
|
||||
int is_key;
|
||||
size_t length;
|
||||
unsigned key_hash;
|
||||
} rcheevos_getvalueud_t;
|
||||
|
||||
#define CHEEVOS_RJSON_OPTIONS \
|
||||
/* Inside the field RichPresencePatch newlines are
|
||||
* encoded as '\r\n'. This will filter the \r out. */ \
|
||||
RJSON_OPTION_IGNORE_STRING_CARRIAGE_RETURN \
|
||||
/* This matches the behavior of the previously used
|
||||
* json parser. It is probably not required */ \
|
||||
| RJSON_OPTION_ALLOW_TRAILING_DATA
|
||||
|
||||
/*****************************************************************************
|
||||
Gets a value in a JSON
|
||||
*****************************************************************************/
|
||||
|
||||
static uint32_t rcheevos_djb2(const char* str, size_t length)
|
||||
{
|
||||
const unsigned char* aux = (const unsigned char*)str;
|
||||
uint32_t hash = 5381;
|
||||
|
||||
while (length--)
|
||||
hash = (hash << 5) + hash + *aux++;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static bool rcheevos_getvalue_key(void* userdata,
|
||||
const char* name, size_t length)
|
||||
{
|
||||
rcheevos_getvalueud_t* ud = (rcheevos_getvalueud_t*)userdata;
|
||||
|
||||
ud->is_key = rcheevos_djb2(name, length) == ud->key_hash;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_getvalue_string(void* userdata,
|
||||
const char* string, size_t length)
|
||||
{
|
||||
rcheevos_getvalueud_t* ud = (rcheevos_getvalueud_t*)userdata;
|
||||
|
||||
if (ud->is_key && ud->length > length)
|
||||
{
|
||||
strlcpy(ud->value, string, ud->length);
|
||||
ud->is_key = 2;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_getvalue_boolean(void* userdata, bool istrue)
|
||||
{
|
||||
rcheevos_getvalueud_t* ud = (rcheevos_getvalueud_t*)userdata;
|
||||
|
||||
if (ud->is_key)
|
||||
{
|
||||
if (istrue && ud->length > 4)
|
||||
{
|
||||
strlcpy(ud->value, "true", ud->length);
|
||||
ud->is_key = 2;
|
||||
return false;
|
||||
}
|
||||
if (!istrue && ud->length > 5)
|
||||
{
|
||||
strlcpy(ud->value, "false", ud->length);
|
||||
ud->is_key = 2;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_getvalue_null(void* userdata)
|
||||
{
|
||||
rcheevos_getvalueud_t* ud = (rcheevos_getvalueud_t*)userdata;
|
||||
|
||||
if (ud->is_key && ud->length > 4)
|
||||
{
|
||||
strlcpy(ud->value, "null", ud->length);
|
||||
ud->is_key = 2;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int rcheevos_get_value(const char* json, unsigned key_hash,
|
||||
char* value, size_t length)
|
||||
{
|
||||
rcheevos_getvalueud_t ud;
|
||||
|
||||
ud.key_hash = key_hash;
|
||||
ud.is_key = 0;
|
||||
ud.value = value;
|
||||
ud.length = length;
|
||||
*value = 0;
|
||||
|
||||
rjson_parse_quick(json, &ud, CHEEVOS_RJSON_OPTIONS,
|
||||
rcheevos_getvalue_key,
|
||||
rcheevos_getvalue_string,
|
||||
rcheevos_getvalue_string, /* number */
|
||||
NULL, NULL, NULL, NULL,
|
||||
rcheevos_getvalue_boolean,
|
||||
rcheevos_getvalue_null, NULL);
|
||||
|
||||
return (ud.is_key == 2 ? 0 : -1);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Returns the token or the error message
|
||||
*****************************************************************************/
|
||||
|
||||
int rcheevos_get_token(const char* json, char* username, size_t username_length,
|
||||
char* token, size_t length)
|
||||
{
|
||||
rcheevos_get_value(json, CHEEVOS_JSON_KEY_ERROR, token, length);
|
||||
|
||||
if (!string_is_empty(token))
|
||||
return -1;
|
||||
|
||||
return rcheevos_get_value(json, CHEEVOS_JSON_KEY_TOKEN, token, length) +
|
||||
rcheevos_get_value(json, CHEEVOS_JSON_KEY_USERNAME, username, username_length);
|
||||
}
|
||||
|
||||
int rcheevos_get_json_error(const char* json, char* token, size_t length)
|
||||
{
|
||||
return rcheevos_get_value(json, CHEEVOS_JSON_KEY_ERROR, token, length);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Count number of achievements in a JSON file
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int in_cheevos;
|
||||
int in_lboards;
|
||||
int has_error;
|
||||
uint32_t field_hash;
|
||||
unsigned core_count;
|
||||
unsigned unofficial_count;
|
||||
unsigned lboard_count;
|
||||
} rcheevos_countud_t;
|
||||
|
||||
static bool rcheevos_count_end_array(void* userdata)
|
||||
{
|
||||
rcheevos_countud_t* ud = (rcheevos_countud_t*)userdata;
|
||||
|
||||
ud->in_cheevos = 0;
|
||||
ud->in_lboards = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_count_key(void* userdata,
|
||||
const char* name, size_t length)
|
||||
{
|
||||
rcheevos_countud_t* ud = (rcheevos_countud_t*)userdata;
|
||||
|
||||
ud->field_hash = rcheevos_djb2(name, length);
|
||||
|
||||
if (ud->field_hash == CHEEVOS_JSON_KEY_ACHIEVEMENTS)
|
||||
ud->in_cheevos = 1;
|
||||
else if (ud->field_hash == CHEEVOS_JSON_KEY_LEADERBOARDS)
|
||||
ud->in_lboards = 1;
|
||||
else if (ud->field_hash == CHEEVOS_JSON_KEY_ERROR)
|
||||
ud->has_error = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_count_number(void* userdata,
|
||||
const char* number, size_t length)
|
||||
{
|
||||
rcheevos_countud_t* ud = (rcheevos_countud_t*)userdata;
|
||||
|
||||
if (ud->in_cheevos && ud->field_hash == CHEEVOS_JSON_KEY_FLAGS)
|
||||
{
|
||||
long flags = strtol(number, NULL, 10);
|
||||
|
||||
if (flags == 3)
|
||||
ud->core_count++; /* Core achievements */
|
||||
else if (flags == 5)
|
||||
ud->unofficial_count++; /* Unofficial achievements */
|
||||
}
|
||||
else if (ud->in_lboards && ud->field_hash == CHEEVOS_JSON_KEY_ID)
|
||||
ud->lboard_count++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_count_cheevos(const char* json,
|
||||
unsigned* core_count, unsigned* unofficial_count,
|
||||
unsigned* lboard_count, int* has_error)
|
||||
{
|
||||
bool res;
|
||||
rcheevos_countud_t ud;
|
||||
ud.in_cheevos = 0;
|
||||
ud.in_lboards = 0;
|
||||
ud.has_error = 0;
|
||||
ud.core_count = 0;
|
||||
ud.unofficial_count = 0;
|
||||
ud.lboard_count = 0;
|
||||
|
||||
|
||||
res = rjson_parse_quick(json, &ud, CHEEVOS_RJSON_OPTIONS,
|
||||
rcheevos_count_key,
|
||||
NULL,
|
||||
rcheevos_count_number,
|
||||
NULL, NULL, NULL,
|
||||
rcheevos_count_end_array,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
*core_count = ud.core_count;
|
||||
*unofficial_count = ud.unofficial_count;
|
||||
*lboard_count = ud.lboard_count;
|
||||
*has_error = ud.has_error;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Parses the cheevos in the JSON
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int in_cheevos;
|
||||
int in_lboards;
|
||||
int lboard_had_id;
|
||||
unsigned core_count;
|
||||
unsigned unofficial_count;
|
||||
unsigned lboard_count;
|
||||
|
||||
unsigned cheevo_flags;
|
||||
const char* lboard_format;
|
||||
const char** field_string;
|
||||
unsigned* field_unsigned;
|
||||
|
||||
rcheevos_racheevo_t cheevo;
|
||||
rcheevos_ralboard_t lboard;
|
||||
|
||||
rcheevos_rapatchdata_t* patchdata;
|
||||
} rcheevos_readud_t;
|
||||
|
||||
static bool rcheevos_new_cheevo(rcheevos_readud_t* ud)
|
||||
{
|
||||
rcheevos_racheevo_t* cheevo = NULL;
|
||||
|
||||
if (ud->cheevo_flags == 3)
|
||||
cheevo = ud->patchdata->core + ud->core_count++;
|
||||
else if (ud->cheevo_flags == 5)
|
||||
cheevo = ud->patchdata->unofficial + ud->unofficial_count++;
|
||||
ud->cheevo_flags = 0;
|
||||
|
||||
if (!cheevo
|
||||
|| !ud->cheevo.title
|
||||
|| !ud->cheevo.description
|
||||
|| !ud->cheevo.badge
|
||||
|| !ud->cheevo.memaddr)
|
||||
{
|
||||
CHEEVOS_FREE(ud->cheevo.title);
|
||||
CHEEVOS_FREE(ud->cheevo.description);
|
||||
CHEEVOS_FREE(ud->cheevo.badge);
|
||||
CHEEVOS_FREE(ud->cheevo.memaddr);
|
||||
memset(&ud->cheevo, 0, sizeof(ud->cheevo));
|
||||
return (cheevo ? false : true);
|
||||
}
|
||||
|
||||
*cheevo = ud->cheevo;
|
||||
memset(&ud->cheevo, 0, sizeof(ud->cheevo));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_new_lboard(rcheevos_readud_t* ud)
|
||||
{
|
||||
rcheevos_ralboard_t* lboard = NULL;
|
||||
|
||||
if (ud->lboard_had_id)
|
||||
lboard = ud->patchdata->lboards + ud->lboard_count++;
|
||||
ud->lboard_had_id = 0;
|
||||
|
||||
if (!lboard
|
||||
|| !ud->lboard.title
|
||||
|| !ud->lboard.description
|
||||
|| !ud->lboard.mem)
|
||||
{
|
||||
CHEEVOS_FREE(ud->lboard.title);
|
||||
CHEEVOS_FREE(ud->lboard.description);
|
||||
CHEEVOS_FREE(ud->lboard.mem);
|
||||
memset(&ud->lboard, 0, sizeof(ud->lboard));
|
||||
CHEEVOS_FREE(ud->lboard_format);
|
||||
ud->lboard_format = NULL;
|
||||
return (lboard ? false : true);
|
||||
}
|
||||
|
||||
*lboard = ud->lboard;
|
||||
memset(&ud->lboard, 0, sizeof(ud->lboard));
|
||||
|
||||
if (ud->lboard_format)
|
||||
{
|
||||
lboard->format = rc_parse_format(ud->lboard_format);
|
||||
CHEEVOS_FREE(ud->lboard_format);
|
||||
ud->lboard_format = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_read_end_object(void* userdata)
|
||||
{
|
||||
rcheevos_readud_t* ud = (rcheevos_readud_t*)userdata;
|
||||
|
||||
if (ud->in_cheevos)
|
||||
return rcheevos_new_cheevo(ud);
|
||||
|
||||
if (ud->in_lboards)
|
||||
return rcheevos_new_lboard(ud);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_read_end_array(void* userdata)
|
||||
{
|
||||
rcheevos_readud_t* ud = (rcheevos_readud_t*)userdata;
|
||||
|
||||
ud->in_cheevos = 0;
|
||||
ud->in_lboards = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_read_key(void* userdata,
|
||||
const char* name, size_t length)
|
||||
{
|
||||
rcheevos_readud_t* ud = (rcheevos_readud_t*)userdata;
|
||||
|
||||
uint32_t hash = rcheevos_djb2(name, length);
|
||||
ud->field_unsigned = NULL;
|
||||
ud->field_string = NULL;
|
||||
|
||||
switch (hash)
|
||||
{
|
||||
case CHEEVOS_JSON_KEY_ACHIEVEMENTS:
|
||||
ud->in_cheevos = 1;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_LEADERBOARDS:
|
||||
ud->in_lboards = 1;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_CONSOLE_ID:
|
||||
ud->field_unsigned = &ud->patchdata->console_id;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_RICHPRESENCE:
|
||||
ud->field_string = (const char**)&ud->patchdata->richpresence_script;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_ID:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_unsigned = &ud->cheevo.id;
|
||||
else if (ud->in_lboards)
|
||||
{
|
||||
ud->field_unsigned = &ud->lboard.id;
|
||||
ud->lboard_had_id = 1;
|
||||
}
|
||||
else
|
||||
ud->field_unsigned = &ud->patchdata->game_id;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_MEMADDR:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_string = &ud->cheevo.memaddr;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_MEM:
|
||||
if (ud->in_lboards)
|
||||
ud->field_string = &ud->lboard.mem;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_TITLE:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_string = &ud->cheevo.title;
|
||||
else if (ud->in_lboards)
|
||||
ud->field_string = &ud->lboard.title;
|
||||
else
|
||||
ud->field_string = (const char**)&ud->patchdata->title;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_DESCRIPTION:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_string = &ud->cheevo.description;
|
||||
else if (ud->in_lboards)
|
||||
ud->field_string = &ud->lboard.description;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_POINTS:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_unsigned = &ud->cheevo.points;
|
||||
break;
|
||||
/* UNUSED
|
||||
case CHEEVOS_JSON_KEY_AUTHOR:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_string = &ud->cheevo.author;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_MODIFIED:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_string = &ud->cheevo.modified;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_CREATED:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_string = &ud->cheevo.created;
|
||||
break; */
|
||||
case CHEEVOS_JSON_KEY_BADGENAME:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_string = &ud->cheevo.badge;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_FLAGS:
|
||||
if (ud->in_cheevos)
|
||||
ud->field_unsigned = &ud->cheevo_flags;
|
||||
break;
|
||||
case CHEEVOS_JSON_KEY_FORMAT:
|
||||
if (ud->in_lboards)
|
||||
ud->field_string = &ud->lboard_format;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_read_string(void* userdata,
|
||||
const char* string, size_t length)
|
||||
{
|
||||
rcheevos_readud_t* ud = (rcheevos_readud_t*)userdata;
|
||||
|
||||
if (ud->field_string)
|
||||
{
|
||||
if (*ud->field_string)
|
||||
CHEEVOS_FREE((*ud->field_string));
|
||||
*ud->field_string = strdup(string);
|
||||
ud->field_string = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_read_number(void* userdata,
|
||||
const char* number, size_t length)
|
||||
{
|
||||
rcheevos_readud_t* ud = (rcheevos_readud_t*)userdata;
|
||||
|
||||
if (ud->field_unsigned)
|
||||
{
|
||||
*ud->field_unsigned = (unsigned)strtol(number, NULL, 10);
|
||||
ud->field_unsigned = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int rcheevos_get_patchdata(const char* json, rcheevos_rapatchdata_t* patchdata)
|
||||
{
|
||||
rcheevos_readud_t ud;
|
||||
bool res;
|
||||
int has_error;
|
||||
|
||||
/* Count the number of achievements in the JSON file. */
|
||||
res = rcheevos_count_cheevos(json, &patchdata->core_count,
|
||||
&patchdata->unofficial_count, &patchdata->lboard_count, &has_error);
|
||||
|
||||
if (!res || has_error)
|
||||
return -1;
|
||||
|
||||
/* Allocate the achievements. */
|
||||
|
||||
patchdata->core = (rcheevos_racheevo_t*)
|
||||
calloc(patchdata->core_count, sizeof(rcheevos_racheevo_t));
|
||||
|
||||
patchdata->unofficial = (rcheevos_racheevo_t*)
|
||||
calloc(patchdata->unofficial_count, sizeof(rcheevos_racheevo_t));
|
||||
|
||||
patchdata->lboards = (rcheevos_ralboard_t*)
|
||||
calloc(patchdata->lboard_count, sizeof(rcheevos_ralboard_t));
|
||||
|
||||
if (!patchdata->core ||
|
||||
!patchdata->unofficial ||
|
||||
!patchdata->lboards)
|
||||
{
|
||||
CHEEVOS_FREE(patchdata->core);
|
||||
CHEEVOS_FREE(patchdata->unofficial);
|
||||
CHEEVOS_FREE(patchdata->lboards);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
patchdata->richpresence_script = NULL;
|
||||
patchdata->title = NULL;
|
||||
|
||||
/* Load the achievements. */
|
||||
memset(&ud, 0, sizeof(ud));
|
||||
ud.patchdata = patchdata;
|
||||
|
||||
res = rjson_parse_quick(json, &ud, CHEEVOS_RJSON_OPTIONS,
|
||||
rcheevos_read_key,
|
||||
rcheevos_read_string,
|
||||
rcheevos_read_number,
|
||||
NULL, rcheevos_read_end_object,
|
||||
NULL, rcheevos_read_end_array,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
CHEEVOS_FREE(ud.cheevo.title);
|
||||
CHEEVOS_FREE(ud.cheevo.description);
|
||||
CHEEVOS_FREE(ud.cheevo.badge);
|
||||
CHEEVOS_FREE(ud.cheevo.memaddr);
|
||||
CHEEVOS_FREE(ud.lboard.title);
|
||||
CHEEVOS_FREE(ud.lboard.description);
|
||||
CHEEVOS_FREE(ud.lboard.mem);
|
||||
CHEEVOS_FREE(ud.lboard_format);
|
||||
|
||||
if (!res)
|
||||
{
|
||||
rcheevos_free_patchdata(patchdata);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Frees the patchdata
|
||||
*****************************************************************************/
|
||||
|
||||
void rcheevos_free_patchdata(rcheevos_rapatchdata_t* patchdata)
|
||||
{
|
||||
unsigned i = 0, count = 0;
|
||||
const rcheevos_racheevo_t* cheevo = NULL;
|
||||
const rcheevos_ralboard_t* lboard = NULL;
|
||||
|
||||
cheevo = patchdata->core;
|
||||
|
||||
for (i = 0, count = patchdata->core_count; i < count; i++, cheevo++)
|
||||
{
|
||||
CHEEVOS_FREE(cheevo->title);
|
||||
CHEEVOS_FREE(cheevo->description);
|
||||
CHEEVOS_FREE(cheevo->badge);
|
||||
CHEEVOS_FREE(cheevo->memaddr);
|
||||
}
|
||||
|
||||
cheevo = patchdata->unofficial;
|
||||
|
||||
for (i = 0, count = patchdata->unofficial_count; i < count; i++, cheevo++)
|
||||
{
|
||||
CHEEVOS_FREE(cheevo->title);
|
||||
CHEEVOS_FREE(cheevo->description);
|
||||
CHEEVOS_FREE(cheevo->badge);
|
||||
CHEEVOS_FREE(cheevo->memaddr);
|
||||
}
|
||||
|
||||
lboard = patchdata->lboards;
|
||||
|
||||
for (i = 0, count = patchdata->lboard_count; i < count; i++, lboard++)
|
||||
{
|
||||
CHEEVOS_FREE(lboard->title);
|
||||
CHEEVOS_FREE(lboard->description);
|
||||
CHEEVOS_FREE(lboard->mem);
|
||||
}
|
||||
|
||||
CHEEVOS_FREE(patchdata->core);
|
||||
CHEEVOS_FREE(patchdata->unofficial);
|
||||
CHEEVOS_FREE(patchdata->lboards);
|
||||
CHEEVOS_FREE(patchdata->richpresence_script);
|
||||
CHEEVOS_FREE(patchdata->title);
|
||||
|
||||
patchdata->game_id = 0;
|
||||
patchdata->console_id = 0;
|
||||
patchdata->core = NULL;
|
||||
patchdata->unofficial = NULL;
|
||||
patchdata->lboards = NULL;
|
||||
patchdata->title = NULL;
|
||||
patchdata->richpresence_script = NULL;
|
||||
patchdata->core_count = 0;
|
||||
patchdata->unofficial_count = 0;
|
||||
patchdata->lboard_count = 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Deactivates unlocked cheevos
|
||||
*****************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int is_element;
|
||||
rcheevos_unlock_cb_t unlock_cb;
|
||||
void* userdata;
|
||||
} rcheevos_deactivate_t;
|
||||
|
||||
static bool rcheevos_deactivate_elements_begin(void* userdata)
|
||||
{
|
||||
rcheevos_deactivate_t* ud = (rcheevos_deactivate_t*)userdata;
|
||||
|
||||
ud->is_element = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_deactivate_elements_stop(void* userdata)
|
||||
{
|
||||
rcheevos_deactivate_t* ud = (rcheevos_deactivate_t*)userdata;
|
||||
|
||||
ud->is_element = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rcheevos_deactivate_number(void* userdata,
|
||||
const char* number, size_t length)
|
||||
{
|
||||
rcheevos_deactivate_t* ud = (rcheevos_deactivate_t*)userdata;
|
||||
unsigned id = 0;
|
||||
|
||||
if (ud->is_element)
|
||||
{
|
||||
id = (unsigned)strtol(number, NULL, 10);
|
||||
|
||||
ud->unlock_cb(id, ud->userdata);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void rcheevos_deactivate_unlocks(const char* json, rcheevos_unlock_cb_t unlock_cb, void* userdata)
|
||||
{
|
||||
rcheevos_deactivate_t ud;
|
||||
|
||||
ud.is_element = 0;
|
||||
ud.unlock_cb = unlock_cb;
|
||||
ud.userdata = userdata;
|
||||
|
||||
rjson_parse_quick(json, &ud, CHEEVOS_RJSON_OPTIONS,
|
||||
NULL, NULL,
|
||||
rcheevos_deactivate_number,
|
||||
rcheevos_deactivate_elements_stop,
|
||||
rcheevos_deactivate_elements_stop,
|
||||
rcheevos_deactivate_elements_begin,
|
||||
rcheevos_deactivate_elements_stop,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Returns the game ID
|
||||
*****************************************************************************/
|
||||
|
||||
unsigned chevos_get_gameid(const char* json)
|
||||
{
|
||||
char gameid[32];
|
||||
|
||||
if (rcheevos_get_value(json, CHEEVOS_JSON_KEY_GAMEID, gameid, sizeof(gameid)) != 0)
|
||||
return 0;
|
||||
|
||||
return (unsigned)strtol(gameid, NULL, 10);
|
||||
}
|
@ -1,39 +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_PARSER_H
|
||||
#define __RARCH_CHEEVOS_PARSER_H
|
||||
|
||||
#include "cheevos_locals.h"
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef void (*rcheevos_unlock_cb_t)(unsigned id, void* userdata);
|
||||
|
||||
int rcheevos_get_json_error(const char* json, char* token, size_t length);
|
||||
|
||||
int rcheevos_get_token(const char* json, char* username, size_t username_length,
|
||||
char* token, size_t length);
|
||||
|
||||
int rcheevos_get_patchdata(const char* json, rcheevos_rapatchdata_t* patchdata);
|
||||
void rcheevos_free_patchdata(rcheevos_rapatchdata_t* patchdata);
|
||||
|
||||
void rcheevos_deactivate_unlocks(const char* json, rcheevos_unlock_cb_t unlock_cb, void* userdata);
|
||||
|
||||
unsigned chevos_get_gameid(const char* json);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
@ -1,75 +0,0 @@
|
||||
#ifndef __RARCH_CHEEVOS_CORO_H
|
||||
#define __RARCH_CHEEVOS_CORO_H
|
||||
|
||||
/*
|
||||
Released under the CC0: https://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/* Use at the beginning of the coroutine, you must have declared a variable rcheevos_coro_t* coro */
|
||||
#define CORO_ENTER() \
|
||||
{ \
|
||||
CORO_again: ; \
|
||||
switch ( coro->step ) { \
|
||||
case CORO_BEGIN: ;
|
||||
|
||||
/* Use to define labels which are targets to GOTO and GOSUB */
|
||||
#define CORO_SUB( x ) \
|
||||
case x: ;
|
||||
|
||||
/* Use at the end of the coroutine */
|
||||
#define CORO_LEAVE() \
|
||||
} } \
|
||||
do { return 0; } while ( 0 )
|
||||
|
||||
/* Go to the x label */
|
||||
#define CORO_GOTO( x ) \
|
||||
do { \
|
||||
coro->step = ( x ); \
|
||||
goto CORO_again; \
|
||||
} while ( 0 )
|
||||
|
||||
/* Go to a subroutine, execution continues until the subroutine returns via RET */
|
||||
#define CORO_GOSUB( x ) \
|
||||
do { \
|
||||
coro->stack[ coro->sp++ ] = __LINE__; \
|
||||
coro->step = ( x ); \
|
||||
goto CORO_again; \
|
||||
case __LINE__: ; \
|
||||
} while ( 0 )
|
||||
|
||||
/* Returns from a subroutine */
|
||||
#define CORO_RET() \
|
||||
do { \
|
||||
coro->step = coro->stack[ --coro->sp ]; \
|
||||
goto CORO_again; \
|
||||
} while ( 0 )
|
||||
|
||||
/* Yields to the caller, execution continues from this point when the coroutine is resumed */
|
||||
#define CORO_YIELD() \
|
||||
do { \
|
||||
coro->step = __LINE__; \
|
||||
return 1; \
|
||||
case __LINE__: ; \
|
||||
} while ( 0 )
|
||||
|
||||
/* The coroutine entry point, never use 0 as a label */
|
||||
#define CORO_BEGIN 0
|
||||
|
||||
/* Sets up the coroutine */
|
||||
#define CORO_SETUP() \
|
||||
do { \
|
||||
coro->step = CORO_BEGIN; \
|
||||
coro->sp = 0; \
|
||||
} while ( 0 )
|
||||
|
||||
#define CORO_STOP() \
|
||||
do { \
|
||||
return 0; \
|
||||
} while ( 0 )
|
||||
|
||||
/* Add this macro to your rcheevos_coro_t structure containing the variables for the coroutine */
|
||||
#define CORO_FIELDS \
|
||||
int step, sp; \
|
||||
int stack[ 8 ];
|
||||
|
||||
#endif /* __RARCH_CHEEVOS_CORO_H */
|
@ -193,7 +193,6 @@ ACHIEVEMENTS
|
||||
#include "../cheevos/cheevos.c"
|
||||
#include "../cheevos/cheevos_client.c"
|
||||
#include "../cheevos/cheevos_menu.c"
|
||||
#include "../cheevos/cheevos_parser.c"
|
||||
|
||||
#include "../deps/rcheevos/src/rapi/rc_api_common.c"
|
||||
#include "../deps/rcheevos/src/rapi/rc_api_runtime.c"
|
||||
@ -214,7 +213,6 @@ ACHIEVEMENTS
|
||||
#include "../deps/rcheevos/src/rcheevos/trigger.c"
|
||||
#include "../deps/rcheevos/src/rcheevos/value.c"
|
||||
#include "../deps/rcheevos/src/rhash/hash.c"
|
||||
#include "../deps/rcheevos/src/rurl/url.c"
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user