mirror of
https://github.com/libretro/RetroArch
synced 2025-01-31 06:32:48 +00:00
Merge pull request #9521 from Jamiras/segacd_cheevos
(cheevos) support for Sega CD/Saturn; reduce hash calls to server
This commit is contained in:
commit
38fe58e746
@ -1068,7 +1068,9 @@ static void rcheevos_unlock_cb(unsigned id, void* userdata)
|
|||||||
#ifndef CHEEVOS_DONT_DEACTIVATE
|
#ifndef CHEEVOS_DONT_DEACTIVATE
|
||||||
cheevo->active &= ~*(unsigned*)userdata;
|
cheevo->active &= ~*(unsigned*)userdata;
|
||||||
#endif
|
#endif
|
||||||
CHEEVOS_LOG(RCHEEVOS_TAG "cheevo %u deactivated: %s\n", id, cheevo->info->title);
|
CHEEVOS_LOG(RCHEEVOS_TAG "cheevo %u deactivated (%s): %s\n", id,
|
||||||
|
(*(unsigned*)userdata) == RCHEEVOS_ACTIVE_HARDCORE ? "hardcore" : "softcore",
|
||||||
|
cheevo->info->title);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1099,8 +1101,9 @@ typedef struct
|
|||||||
char url[256];
|
char url[256];
|
||||||
char badge_basepath[PATH_MAX_LENGTH];
|
char badge_basepath[PATH_MAX_LENGTH];
|
||||||
char badge_fullpath[PATH_MAX_LENGTH];
|
char badge_fullpath[PATH_MAX_LENGTH];
|
||||||
|
unsigned char last_hash[16];
|
||||||
unsigned char hash[16];
|
unsigned char hash[16];
|
||||||
bool round;
|
unsigned ext_hash;
|
||||||
unsigned gameid;
|
unsigned gameid;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
unsigned j;
|
unsigned j;
|
||||||
@ -1133,14 +1136,14 @@ typedef struct
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
/* Negative values because CORO_SUB generates positive values */
|
/* Negative values because CORO_SUB generates positive values */
|
||||||
RCHEEVOS_SNES_MD5 = -1,
|
RCHEEVOS_GENERIC_MD5 = -1,
|
||||||
RCHEEVOS_GENESIS_MD5 = -2,
|
RCHEEVOS_SNES_MD5 = -2,
|
||||||
RCHEEVOS_LYNX_MD5 = -3,
|
RCHEEVOS_LYNX_MD5 = -3,
|
||||||
RCHEEVOS_NES_MD5 = -4,
|
RCHEEVOS_NES_MD5 = -4,
|
||||||
RCHEEVOS_GENERIC_MD5 = -5,
|
RCHEEVOS_PSX_MD5 = -5,
|
||||||
RCHEEVOS_FILENAME_MD5 = -6,
|
RCHEEVOS_ARCADE_MD5 = -6,
|
||||||
RCHEEVOS_EVAL_MD5 = -7,
|
RCHEEVOS_EVAL_MD5 = -7,
|
||||||
RCHEEVOS_FILL_MD5 = -8,
|
RCHEEVOS_SEGACD_MD5 = -8,
|
||||||
RCHEEVOS_GET_GAMEID = -9,
|
RCHEEVOS_GET_GAMEID = -9,
|
||||||
RCHEEVOS_GET_CHEEVOS = -10,
|
RCHEEVOS_GET_CHEEVOS = -10,
|
||||||
RCHEEVOS_GET_BADGES = -11,
|
RCHEEVOS_GET_BADGES = -11,
|
||||||
@ -1148,8 +1151,7 @@ enum
|
|||||||
RCHEEVOS_HTTP_GET = -13,
|
RCHEEVOS_HTTP_GET = -13,
|
||||||
RCHEEVOS_DEACTIVATE = -14,
|
RCHEEVOS_DEACTIVATE = -14,
|
||||||
RCHEEVOS_PLAYING = -15,
|
RCHEEVOS_PLAYING = -15,
|
||||||
RCHEEVOS_DELAY = -16,
|
RCHEEVOS_DELAY = -16
|
||||||
RCHEEVOS_PSX_MD5 = -17
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rcheevos_iterate(rcheevos_coro_t* coro)
|
static int rcheevos_iterate(rcheevos_coro_t* coro)
|
||||||
@ -1166,21 +1168,6 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
|||||||
char* scan = NULL;
|
char* scan = NULL;
|
||||||
char buffer[2048];
|
char buffer[2048];
|
||||||
|
|
||||||
static const uint32_t genesis_exts[] =
|
|
||||||
{
|
|
||||||
0x0b888feeU, /* mdx */
|
|
||||||
0x005978b6U, /* md */
|
|
||||||
0x0b88aa89U, /* smd */
|
|
||||||
0x0b88767fU, /* gen */
|
|
||||||
0x0b8861beU, /* bin */
|
|
||||||
0x0b886782U, /* cue */
|
|
||||||
0x0b8880d0U, /* iso */
|
|
||||||
0x0b88aa98U, /* sms */
|
|
||||||
0x005977f3U, /* gg */
|
|
||||||
0x0059797fU, /* sg */
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint32_t snes_exts[] =
|
static const uint32_t snes_exts[] =
|
||||||
{
|
{
|
||||||
0x0b88aa88U, /* smc */
|
0x0b88aa88U, /* smc */
|
||||||
@ -1194,6 +1181,12 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint32_t nes_exts[] =
|
||||||
|
{
|
||||||
|
0x0b88944bU, /* nes */
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
static const uint32_t lynx_exts[] =
|
static const uint32_t lynx_exts[] =
|
||||||
{
|
{
|
||||||
0x0b888cf7U, /* lnx */
|
0x0b888cf7U, /* lnx */
|
||||||
@ -1211,15 +1204,29 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const uint32_t segacd_exts[] =
|
||||||
|
{
|
||||||
|
0x0b886782U, /* cue */
|
||||||
|
0x0b8880d0U, /* iso */
|
||||||
|
0x0b8865d4U, /* chd */
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t arcade_exts[] =
|
||||||
|
{
|
||||||
|
0x0b88c7d8U, /* zip */
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
static rcheevos_finder_t finders[] =
|
static rcheevos_finder_t finders[] =
|
||||||
{
|
{
|
||||||
{RCHEEVOS_SNES_MD5, "SNES (discards header)", snes_exts},
|
{RCHEEVOS_SNES_MD5, "SNES (discards header)", snes_exts},
|
||||||
{RCHEEVOS_GENESIS_MD5, "Genesis (6Mb padding)", genesis_exts},
|
|
||||||
{RCHEEVOS_LYNX_MD5, "Atari Lynx (discards header)", lynx_exts},
|
{RCHEEVOS_LYNX_MD5, "Atari Lynx (discards header)", lynx_exts},
|
||||||
{RCHEEVOS_NES_MD5, "NES (discards header)", NULL},
|
{RCHEEVOS_NES_MD5, "NES (discards header)", nes_exts},
|
||||||
{RCHEEVOS_PSX_MD5, "Playstation (main executable)", psx_exts},
|
{RCHEEVOS_PSX_MD5, "Playstation (main executable)", psx_exts},
|
||||||
{RCHEEVOS_GENERIC_MD5, "Generic (plain content)", NULL},
|
{RCHEEVOS_SEGACD_MD5, "Sega CD/Saturn (first sector)", segacd_exts},
|
||||||
{RCHEEVOS_FILENAME_MD5, "Generic (filename)", NULL}
|
{RCHEEVOS_ARCADE_MD5, "Arcade (filename)", arcade_exts},
|
||||||
|
{RCHEEVOS_GENERIC_MD5, "Generic (plain content)", NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
CORO_ENTER();
|
CORO_ENTER();
|
||||||
@ -1286,14 +1293,44 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
|||||||
CHEEVOS_FREE(coro->stream);
|
CHEEVOS_FREE(coro->stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use the supported extensions as a hint
|
/* Use the selected file's extension to determine which method to use */
|
||||||
* to what method we should use. */
|
|
||||||
core_get_system_info(&coro->sysinfo);
|
|
||||||
|
|
||||||
for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++)
|
for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++)
|
||||||
{
|
{
|
||||||
if (finders[coro->i].ext_hashes)
|
if (finders[coro->i].ext_hashes)
|
||||||
{
|
{
|
||||||
|
for (coro->j = 0; finders[coro->i].ext_hashes[coro->j]; coro->j++)
|
||||||
|
{
|
||||||
|
if (finders[coro->i].ext_hashes[coro->j] == coro->ext_hash)
|
||||||
|
{
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n", finders[coro->i].name);
|
||||||
|
CORO_GOSUB(finders[coro->i].label);
|
||||||
|
|
||||||
|
if (coro->gameid != 0)
|
||||||
|
goto found;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use the extensions supported by the core as a hint to what method we should use. */
|
||||||
|
core_get_system_info(&coro->sysinfo);
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "no method for file extension, trying core supported extensions: %s\n", coro->sysinfo.valid_extensions);
|
||||||
|
for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++)
|
||||||
|
{
|
||||||
|
if (finders[coro->i].ext_hashes)
|
||||||
|
{
|
||||||
|
for (coro->j = 0; finders[coro->i].ext_hashes[coro->j]; coro->j++)
|
||||||
|
{
|
||||||
|
if (finders[coro->i].ext_hashes[coro->j] == coro->ext_hash)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* did we already check this one? */
|
||||||
|
if (finders[coro->i].ext_hashes[coro->j] == coro->ext_hash)
|
||||||
|
continue;
|
||||||
|
|
||||||
coro->ext = coro->sysinfo.valid_extensions;
|
coro->ext = coro->sysinfo.valid_extensions;
|
||||||
|
|
||||||
while (coro->ext)
|
while (coro->ext)
|
||||||
@ -1316,13 +1353,7 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
|||||||
{
|
{
|
||||||
if (finders[coro->i].ext_hashes[coro->j] == hash)
|
if (finders[coro->i].ext_hashes[coro->j] == hash)
|
||||||
{
|
{
|
||||||
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n",
|
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n", finders[coro->i].name);
|
||||||
finders[coro->i].name);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inputs: CHEEVOS_VAR_INFO
|
|
||||||
* Outputs: CHEEVOS_VAR_GAMEID, the game was found if it's different from 0
|
|
||||||
*/
|
|
||||||
CORO_GOSUB(finders[coro->i].label);
|
CORO_GOSUB(finders[coro->i].label);
|
||||||
|
|
||||||
if (coro->gameid != 0)
|
if (coro->gameid != 0)
|
||||||
@ -1336,18 +1367,13 @@ static int rcheevos_iterate(rcheevos_coro_t* coro)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try hashing methods not specifically tied to a file extension */
|
||||||
for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++)
|
for (coro->i = 0; coro->i < ARRAY_SIZE(finders); coro->i++)
|
||||||
{
|
{
|
||||||
if (finders[coro->i].ext_hashes)
|
if (finders[coro->i].ext_hashes)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n",
|
CHEEVOS_LOG(RCHEEVOS_TAG "testing %s\n", finders[coro->i].name);
|
||||||
finders[coro->i].name);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inputs: CHEEVOS_VAR_INFO
|
|
||||||
* Outputs: CHEEVOS_VAR_GAMEID
|
|
||||||
*/
|
|
||||||
CORO_GOSUB(finders[coro->i].label);
|
CORO_GOSUB(finders[coro->i].label);
|
||||||
|
|
||||||
if (coro->gameid != 0)
|
if (coro->gameid != 0)
|
||||||
@ -1450,11 +1476,12 @@ found:
|
|||||||
CORO_GOSUB(RCHEEVOS_GET_BADGES);
|
CORO_GOSUB(RCHEEVOS_GET_BADGES);
|
||||||
CORO_STOP();
|
CORO_STOP();
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Tries to identify a SNES game
|
/**************************************************************************
|
||||||
* Input CHEEVOS_VAR_INFO the content info
|
* Info Tries to identify a SNES game
|
||||||
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
* Input CHEEVOS_VAR_INFO the content info
|
||||||
*************************************************************************/
|
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_SNES_MD5)
|
CORO_SUB(RCHEEVOS_SNES_MD5)
|
||||||
MD5_Init(&coro->md5);
|
MD5_Init(&coro->md5);
|
||||||
|
|
||||||
@ -1462,6 +1489,7 @@ found:
|
|||||||
Unheadered files fall back to RCHEEVOS_GENERIC_MD5. */
|
Unheadered files fall back to RCHEEVOS_GENERIC_MD5. */
|
||||||
if (coro->len < 0x2000 || coro->len % 0x2000 != snes_header_len)
|
if (coro->len < 0x2000 || coro->len % 0x2000 != snes_header_len)
|
||||||
{
|
{
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate SNES header\n", coro->gameid);
|
||||||
coro->gameid = 0;
|
coro->gameid = 0;
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
}
|
}
|
||||||
@ -1474,41 +1502,12 @@ found:
|
|||||||
|
|
||||||
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Tries to identify a Genesis game
|
|
||||||
* Input CHEEVOS_VAR_INFO the content info
|
|
||||||
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
|
||||||
*************************************************************************/
|
|
||||||
CORO_SUB(RCHEEVOS_GENESIS_MD5)
|
|
||||||
|
|
||||||
MD5_Init(&coro->md5);
|
/**************************************************************************
|
||||||
|
* Info Tries to identify an Atari Lynx game
|
||||||
coro->offset = 0;
|
* Input CHEEVOS_VAR_INFO the content info
|
||||||
coro->count = 0;
|
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
||||||
CORO_GOSUB(RCHEEVOS_EVAL_MD5);
|
*************************************************************************/
|
||||||
|
|
||||||
if (coro->count == 0)
|
|
||||||
{
|
|
||||||
MD5_Final(coro->hash, &coro->md5);
|
|
||||||
coro->gameid = 0;
|
|
||||||
CORO_RET();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (coro->count < CHEEVOS_MB(6))
|
|
||||||
{
|
|
||||||
coro->offset = 0;
|
|
||||||
coro->count = CHEEVOS_MB(6) - coro->count;
|
|
||||||
CORO_GOSUB(RCHEEVOS_FILL_MD5);
|
|
||||||
}
|
|
||||||
|
|
||||||
MD5_Final(coro->hash, &coro->md5);
|
|
||||||
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Tries to identify an Atari Lynx game
|
|
||||||
* Input CHEEVOS_VAR_INFO the content info
|
|
||||||
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
|
||||||
*************************************************************************/
|
|
||||||
CORO_SUB(RCHEEVOS_LYNX_MD5)
|
CORO_SUB(RCHEEVOS_LYNX_MD5)
|
||||||
|
|
||||||
/* Checks for the existence of a headered Lynx file.
|
/* Checks for the existence of a headered Lynx file.
|
||||||
@ -1516,6 +1515,7 @@ found:
|
|||||||
if (coro->len <= (unsigned)lynx_header_len ||
|
if (coro->len <= (unsigned)lynx_header_len ||
|
||||||
memcmp("LYNX", (void *)coro->data, 5) != 0)
|
memcmp("LYNX", (void *)coro->data, 5) != 0)
|
||||||
{
|
{
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate LYNX header\n", coro->gameid);
|
||||||
coro->gameid = 0;
|
coro->gameid = 0;
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
}
|
}
|
||||||
@ -1528,11 +1528,12 @@ found:
|
|||||||
MD5_Final(coro->hash, &coro->md5);
|
MD5_Final(coro->hash, &coro->md5);
|
||||||
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Tries to identify a NES game
|
/**************************************************************************
|
||||||
* Input CHEEVOS_VAR_INFO the content info
|
* Info Tries to identify a NES game
|
||||||
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
* Input CHEEVOS_VAR_INFO the content info
|
||||||
*************************************************************************/
|
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_NES_MD5)
|
CORO_SUB(RCHEEVOS_NES_MD5)
|
||||||
|
|
||||||
/* Checks for the existence of a headered NES file.
|
/* Checks for the existence of a headered NES file.
|
||||||
@ -1552,6 +1553,7 @@ found:
|
|||||||
|| coro->header.id[3] != 0x1a)
|
|| coro->header.id[3] != 0x1a)
|
||||||
{
|
{
|
||||||
coro->gameid = 0;
|
coro->gameid = 0;
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate NES header\n", coro->gameid);
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1564,6 +1566,57 @@ found:
|
|||||||
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Info Tries to identify a Sega CD game
|
||||||
|
* Input CHEEVOS_VAR_INFO the content info
|
||||||
|
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
||||||
|
*************************************************************************/
|
||||||
|
CORO_SUB(RCHEEVOS_SEGACD_MD5)
|
||||||
|
{
|
||||||
|
/* ignore bin files less than 16MB - they're probably a ROM, not a CD */
|
||||||
|
if (coro->ext_hash == 0x0b8861beU && coro->len < CHEEVOS_MB(16))
|
||||||
|
{
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "ignoring small BIN file - assuming not CD\n", coro->gameid);
|
||||||
|
coro->gameid = 0;
|
||||||
|
CORO_RET();
|
||||||
|
}
|
||||||
|
|
||||||
|
MD5_Init(&coro->md5);
|
||||||
|
|
||||||
|
/* find the data track - it should be the first one */
|
||||||
|
coro->stream = cdfs_open_data_track(coro->path);
|
||||||
|
if (coro->stream)
|
||||||
|
{
|
||||||
|
/* open the raw CD */
|
||||||
|
if (cdfs_open_file(&coro->cdfp, coro->stream, NULL))
|
||||||
|
{
|
||||||
|
coro->count = 512;
|
||||||
|
free(coro->data);
|
||||||
|
coro->data = (uint8_t*)malloc(coro->count);
|
||||||
|
cdfs_read_file(&coro->cdfp, coro->data, coro->count);
|
||||||
|
coro->len = coro->count;
|
||||||
|
|
||||||
|
CORO_GOSUB(RCHEEVOS_EVAL_MD5);
|
||||||
|
MD5_Final(coro->hash, &coro->md5);
|
||||||
|
|
||||||
|
cdfs_close_file(&coro->cdfp);
|
||||||
|
|
||||||
|
intfstream_close(coro->stream);
|
||||||
|
CHEEVOS_FREE(coro->stream);
|
||||||
|
|
||||||
|
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
||||||
|
}
|
||||||
|
|
||||||
|
intfstream_close(coro->stream);
|
||||||
|
CHEEVOS_FREE(coro->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "could not open CD\n", coro->gameid);
|
||||||
|
coro->gameid = 0;
|
||||||
|
CORO_RET();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Info Tries to identify a Playstation game
|
* Info Tries to identify a Playstation game
|
||||||
* Input CHEEVOS_VAR_INFO the content info
|
* Input CHEEVOS_VAR_INFO the content info
|
||||||
@ -1706,20 +1759,26 @@ found:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "could not locate primary executable\n", coro->gameid);
|
||||||
|
|
||||||
intfstream_close(coro->stream);
|
intfstream_close(coro->stream);
|
||||||
CHEEVOS_FREE(coro->stream);
|
CHEEVOS_FREE(coro->stream);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "could not open CD\n", coro->gameid);
|
||||||
|
}
|
||||||
|
|
||||||
coro->gameid = 0;
|
coro->gameid = 0;
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* Info Tries to identify a "generic" game
|
* Info Tries to identify a game by examining the entire file (no special processing)
|
||||||
* Input CHEEVOS_VAR_INFO the content info
|
* Input CHEEVOS_VAR_INFO the content info
|
||||||
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
||||||
*************************************************************************/
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_GENERIC_MD5)
|
CORO_SUB(RCHEEVOS_GENERIC_MD5)
|
||||||
|
|
||||||
MD5_Init(&coro->md5);
|
MD5_Init(&coro->md5);
|
||||||
@ -1735,12 +1794,14 @@ found:
|
|||||||
|
|
||||||
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
CORO_GOTO(RCHEEVOS_GET_GAMEID);
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Tries to identify a game based on its filename (with no extension)
|
/**************************************************************************
|
||||||
* Input CHEEVOS_VAR_INFO the content info
|
* Info Tries to identify an arcade game based on its filename (with no extension).
|
||||||
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
* An arcade game "rom" is a zip file containing many ROMs.
|
||||||
*************************************************************************/
|
* Input CHEEVOS_VAR_INFO the content info
|
||||||
CORO_SUB(RCHEEVOS_FILENAME_MD5)
|
* Output CHEEVOS_VAR_GAMEID the Retro Achievements game ID, or 0 if not found
|
||||||
|
*************************************************************************/
|
||||||
|
CORO_SUB(RCHEEVOS_ARCADE_MD5)
|
||||||
if (!string_is_empty(coro->path))
|
if (!string_is_empty(coro->path))
|
||||||
{
|
{
|
||||||
char base_noext[PATH_MAX_LENGTH];
|
char base_noext[PATH_MAX_LENGTH];
|
||||||
@ -1754,11 +1815,12 @@ found:
|
|||||||
}
|
}
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Evaluates the CHEEVOS_VAR_MD5 hash
|
/**************************************************************************
|
||||||
* Inputs CHEEVOS_VAR_INFO, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT
|
* Info Evaluates the CHEEVOS_VAR_MD5 hash
|
||||||
* Outputs CHEEVOS_VAR_MD5, CHEEVOS_VAR_COUNT
|
* Inputs CHEEVOS_VAR_INFO, CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT
|
||||||
*************************************************************************/
|
* Outputs CHEEVOS_VAR_MD5, CHEEVOS_VAR_COUNT
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_EVAL_MD5)
|
CORO_SUB(RCHEEVOS_EVAL_MD5)
|
||||||
|
|
||||||
if (coro->count == 0)
|
if (coro->count == 0)
|
||||||
@ -1776,40 +1838,24 @@ found:
|
|||||||
coro->count);
|
coro->count);
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Updates the CHEEVOS_VAR_MD5 hash with a repeated value
|
|
||||||
* Inputs CHEEVOS_VAR_OFFSET, CHEEVOS_VAR_COUNT
|
|
||||||
* Outputs CHEEVOS_VAR_MD5
|
|
||||||
*************************************************************************/
|
|
||||||
CORO_SUB(RCHEEVOS_FILL_MD5)
|
|
||||||
|
|
||||||
{
|
/**************************************************************************
|
||||||
char buffer[4096];
|
* Info Gets the achievements from Retro Achievements
|
||||||
|
* Inputs coro->hash
|
||||||
while (coro->count > 0)
|
* Outputs CHEEVOS_VAR_GAMEID
|
||||||
{
|
*************************************************************************/
|
||||||
size_t len = sizeof(buffer);
|
|
||||||
|
|
||||||
if (len > coro->count)
|
|
||||||
len = coro->count;
|
|
||||||
|
|
||||||
memset((void*)buffer, coro->offset, len);
|
|
||||||
MD5_Update(&coro->md5, (void*)buffer, len);
|
|
||||||
coro->count -= len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CORO_RET();
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Gets the achievements from Retro Achievements
|
|
||||||
* Inputs coro->hash
|
|
||||||
* Outputs CHEEVOS_VAR_GAMEID
|
|
||||||
*************************************************************************/
|
|
||||||
CORO_SUB(RCHEEVOS_GET_GAMEID)
|
CORO_SUB(RCHEEVOS_GET_GAMEID)
|
||||||
|
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
|
if (memcmp(coro->last_hash, coro->hash, sizeof(coro->hash)) == 0)
|
||||||
|
{
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "hash did not change, returning %u\n", coro->gameid);
|
||||||
|
CORO_RET();
|
||||||
|
}
|
||||||
|
memcpy(coro->last_hash, coro->hash, sizeof(coro->hash));
|
||||||
|
|
||||||
size = rc_url_get_gameid(coro->url, sizeof(coro->url), coro->hash);
|
size = rc_url_get_gameid(coro->url, sizeof(coro->url), coro->hash);
|
||||||
|
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
@ -1818,6 +1864,11 @@ found:
|
|||||||
CORO_RET();
|
CORO_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "checking %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||||
|
coro->hash[0], coro->hash[1], coro->hash[2], coro->hash[3],
|
||||||
|
coro->hash[4], coro->hash[5], coro->hash[6], coro->hash[7],
|
||||||
|
coro->hash[8], coro->hash[9], coro->hash[10], coro->hash[11],
|
||||||
|
coro->hash[12], coro->hash[13], coro->hash[14], coro->hash[15]);
|
||||||
rcheevos_log_url(RCHEEVOS_TAG "rc_url_get_gameid: %s\n", coro->url);
|
rcheevos_log_url(RCHEEVOS_TAG "rc_url_get_gameid: %s\n", coro->url);
|
||||||
CORO_GOSUB(RCHEEVOS_HTTP_GET);
|
CORO_GOSUB(RCHEEVOS_HTTP_GET);
|
||||||
|
|
||||||
@ -1831,11 +1882,12 @@ found:
|
|||||||
CORO_RET();
|
CORO_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Gets the achievements from Retro Achievements
|
/**************************************************************************
|
||||||
* Inputs CHEEVOS_VAR_GAMEID
|
* Info Gets the achievements from Retro Achievements
|
||||||
* Outputs CHEEVOS_VAR_JSON
|
* Inputs CHEEVOS_VAR_GAMEID
|
||||||
*************************************************************************/
|
* Outputs CHEEVOS_VAR_JSON
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_GET_CHEEVOS)
|
CORO_SUB(RCHEEVOS_GET_CHEEVOS)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
@ -1863,11 +1915,12 @@ found:
|
|||||||
CORO_RET();
|
CORO_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Gets the achievements from Retro Achievements
|
/**************************************************************************
|
||||||
* Inputs CHEEVOS_VAR_GAMEID
|
* Info Gets the achievements from Retro Achievements
|
||||||
* Outputs CHEEVOS_VAR_JSON
|
* Inputs CHEEVOS_VAR_GAMEID
|
||||||
*************************************************************************/
|
* Outputs CHEEVOS_VAR_JSON
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_GET_BADGES)
|
CORO_SUB(RCHEEVOS_GET_BADGES)
|
||||||
|
|
||||||
badges_ctx = new_badges_ctx;
|
badges_ctx = new_badges_ctx;
|
||||||
@ -1958,9 +2011,10 @@ found:
|
|||||||
|
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Logs in the user at Retro Achievements
|
/**************************************************************************
|
||||||
*************************************************************************/
|
* Info Logs in the user at Retro Achievements
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_LOGIN)
|
CORO_SUB(RCHEEVOS_LOGIN)
|
||||||
{
|
{
|
||||||
const char* username;
|
const char* username;
|
||||||
@ -2050,9 +2104,10 @@ found:
|
|||||||
CORO_RET();
|
CORO_RET();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Pauses execution for five seconds
|
/**************************************************************************
|
||||||
*************************************************************************/
|
* Info Pauses execution for five seconds
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_DELAY)
|
CORO_SUB(RCHEEVOS_DELAY)
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -2068,11 +2123,12 @@ found:
|
|||||||
|
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Makes a HTTP GET request
|
/**************************************************************************
|
||||||
* Inputs CHEEVOS_VAR_URL
|
* Info Makes a HTTP GET request
|
||||||
* Outputs CHEEVOS_VAR_JSON
|
* Inputs CHEEVOS_VAR_URL
|
||||||
*************************************************************************/
|
* Outputs CHEEVOS_VAR_JSON
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_HTTP_GET)
|
CORO_SUB(RCHEEVOS_HTTP_GET)
|
||||||
|
|
||||||
for (coro->k = 0; coro->k < 5; coro->k++)
|
for (coro->k = 0; coro->k < 5; coro->k++)
|
||||||
@ -2143,11 +2199,12 @@ found:
|
|||||||
CHEEVOS_LOG(RCHEEVOS_TAG "Couldn't connect to server after 5 tries\n");
|
CHEEVOS_LOG(RCHEEVOS_TAG "Couldn't connect to server after 5 tries\n");
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Deactivates the achievements already awarded
|
/**************************************************************************
|
||||||
* Inputs CHEEVOS_VAR_GAMEID
|
* Info Deactivates the achievements already awarded
|
||||||
* Outputs
|
* Inputs CHEEVOS_VAR_GAMEID
|
||||||
*************************************************************************/
|
* Outputs
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_DEACTIVATE)
|
CORO_SUB(RCHEEVOS_DEACTIVATE)
|
||||||
|
|
||||||
CORO_GOSUB(RCHEEVOS_LOGIN);
|
CORO_GOSUB(RCHEEVOS_LOGIN);
|
||||||
@ -2155,6 +2212,7 @@ found:
|
|||||||
int ret;
|
int ret;
|
||||||
unsigned mode;
|
unsigned mode;
|
||||||
|
|
||||||
|
/* Two calls - one for softcore and one for hardcore */
|
||||||
for (coro->i = 0; coro->i < 2; coro->i++)
|
for (coro->i = 0; coro->i < 2; coro->i++)
|
||||||
{
|
{
|
||||||
ret = rc_url_get_unlock_list(coro->url, sizeof(coro->url), coro->settings->arrays.cheevos_username, rcheevos_locals.token, coro->gameid, coro->i);
|
ret = rc_url_get_unlock_list(coro->url, sizeof(coro->url), coro->settings->arrays.cheevos_username, rcheevos_locals.token, coro->gameid, coro->i);
|
||||||
@ -2181,11 +2239,12 @@ found:
|
|||||||
|
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Info Posts the "playing" activity to Retro Achievements
|
/**************************************************************************
|
||||||
* Inputs CHEEVOS_VAR_GAMEID
|
* Info Posts the "playing" activity to Retro Achievements
|
||||||
* Outputs
|
* Inputs CHEEVOS_VAR_GAMEID
|
||||||
*************************************************************************/
|
* Outputs
|
||||||
|
*************************************************************************/
|
||||||
CORO_SUB(RCHEEVOS_PLAYING)
|
CORO_SUB(RCHEEVOS_PLAYING)
|
||||||
|
|
||||||
snprintf(
|
snprintf(
|
||||||
@ -2208,7 +2267,6 @@ found:
|
|||||||
else
|
else
|
||||||
CHEEVOS_ERR(RCHEEVOS_TAG "error posting playing activity\n");
|
CHEEVOS_ERR(RCHEEVOS_TAG "error posting playing activity\n");
|
||||||
|
|
||||||
CHEEVOS_LOG(RCHEEVOS_TAG "posted playing activity\n");
|
|
||||||
CORO_RET();
|
CORO_RET();
|
||||||
|
|
||||||
CORO_LEAVE();
|
CORO_LEAVE();
|
||||||
@ -2248,7 +2306,8 @@ bool rcheevos_load(const void *data)
|
|||||||
{
|
{
|
||||||
retro_task_t *task;
|
retro_task_t *task;
|
||||||
const struct retro_game_info *info = NULL;
|
const struct retro_game_info *info = NULL;
|
||||||
rcheevos_coro_t *coro = NULL;
|
rcheevos_coro_t *coro = NULL;
|
||||||
|
char buffer[32];
|
||||||
|
|
||||||
rcheevos_loaded = false;
|
rcheevos_loaded = false;
|
||||||
rcheevos_hardcore_paused = false;
|
rcheevos_hardcore_paused = false;
|
||||||
@ -2299,6 +2358,12 @@ bool rcheevos_load(const void *data)
|
|||||||
coro->path = strdup(info->path);
|
coro->path = strdup(info->path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strncpy(buffer, path_get_extension(info->path), sizeof(buffer));
|
||||||
|
buffer[sizeof(buffer) - 1] = '\0';
|
||||||
|
string_to_lower(buffer);
|
||||||
|
coro->ext_hash = rcheevos_djb2(buffer, strlen(buffer));
|
||||||
|
CHEEVOS_LOG(RCHEEVOS_TAG "ext_hash %08x ('%s')\n", coro->ext_hash, buffer);
|
||||||
|
|
||||||
task->handler = rcheevos_task_handler;
|
task->handler = rcheevos_task_handler;
|
||||||
task->state = (void*)coro;
|
task->state = (void*)coro;
|
||||||
task->mute = true;
|
task->mute = true;
|
||||||
|
@ -151,7 +151,7 @@ static int cdfs_find_file(cdfs_file_t* file, const char* path)
|
|||||||
|
|
||||||
int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path)
|
int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path)
|
||||||
{
|
{
|
||||||
if (!file || !stream || !path)
|
if (!file || !stream)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
memset(file, 0, sizeof(*file));
|
memset(file, 0, sizeof(*file));
|
||||||
@ -160,16 +160,28 @@ int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path)
|
|||||||
cdfs_determine_sector_size(file);
|
cdfs_determine_sector_size(file);
|
||||||
|
|
||||||
file->current_sector = -1;
|
file->current_sector = -1;
|
||||||
file->first_sector = cdfs_find_file(file, path);
|
if (path != NULL)
|
||||||
|
{
|
||||||
|
file->first_sector = cdfs_find_file(file, path);
|
||||||
|
}
|
||||||
|
else if (file->stream_sector_size)
|
||||||
|
{
|
||||||
|
file->first_sector = 0;
|
||||||
|
file->size = (intfstream_get_size(file->stream) / file->stream_sector_size) * 2048;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file->first_sector = -1;
|
||||||
|
}
|
||||||
|
|
||||||
return (file->first_sector > 0);
|
return (file->first_sector >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)
|
int64_t cdfs_read_file(cdfs_file_t* file, void* buffer, uint64_t len)
|
||||||
{
|
{
|
||||||
int bytes_read = 0;
|
int bytes_read = 0;
|
||||||
|
|
||||||
if (!file || !file->first_sector || !buffer)
|
if (!file || file->first_sector < 0 || !buffer)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (len > file->size - file->pos)
|
if (len > file->size - file->pos)
|
||||||
@ -240,13 +252,13 @@ void cdfs_close_file(cdfs_file_t* file)
|
|||||||
if (file)
|
if (file)
|
||||||
{
|
{
|
||||||
/* not really anything to do here, just clear out the first_sector so read() won't do anything */
|
/* not really anything to do here, just clear out the first_sector so read() won't do anything */
|
||||||
file->first_sector = 0;
|
file->first_sector = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t cdfs_get_size(cdfs_file_t* file)
|
int64_t cdfs_get_size(cdfs_file_t* file)
|
||||||
{
|
{
|
||||||
if (!file || !file->first_sector)
|
if (!file || file->first_sector < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return file->size;
|
return file->size;
|
||||||
@ -254,7 +266,7 @@ int64_t cdfs_get_size(cdfs_file_t* file)
|
|||||||
|
|
||||||
int64_t cdfs_tell(cdfs_file_t* file)
|
int64_t cdfs_tell(cdfs_file_t* file)
|
||||||
{
|
{
|
||||||
if (!file || !file->first_sector)
|
if (!file || file->first_sector < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return file->pos;
|
return file->pos;
|
||||||
@ -265,7 +277,7 @@ int64_t cdfs_seek(cdfs_file_t* file, int64_t offset, int whence)
|
|||||||
int64_t new_pos;
|
int64_t new_pos;
|
||||||
int new_sector;
|
int new_sector;
|
||||||
|
|
||||||
if (!file || !file->first_sector)
|
if (!file || file->first_sector < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (whence)
|
switch (whence)
|
||||||
@ -459,8 +471,8 @@ intfstream_t* cdfs_open_data_track(const char* path)
|
|||||||
return intfstream_open_chd_track(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE, 1);
|
return intfstream_open_chd_track(path, RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unsupported file type */
|
/* unsupported file type - try opening as a raw track */
|
||||||
return NULL;
|
return cdfs_open_raw_track(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
intfstream_t* cdfs_open_raw_track(const char* path)
|
intfstream_t* cdfs_open_raw_track(const char* path)
|
||||||
|
@ -45,6 +45,10 @@ typedef struct cdfs_file_t
|
|||||||
uint8_t sector_buffer[2048];
|
uint8_t sector_buffer[2048];
|
||||||
} cdfs_file_t;
|
} cdfs_file_t;
|
||||||
|
|
||||||
|
/* opens the specified file within the CD or virtual CD.
|
||||||
|
* if path is NULL, will open the raw CD (useful for reading CD without having to worry about sector sizes,
|
||||||
|
* headers, or checksum data)
|
||||||
|
*/
|
||||||
int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path);
|
int cdfs_open_file(cdfs_file_t* file, intfstream_t* stream, const char* path);
|
||||||
|
|
||||||
void cdfs_close_file(cdfs_file_t* file);
|
void cdfs_close_file(cdfs_file_t* file);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user