mirror of
https://github.com/libretro/RetroArch
synced 2025-04-01 04:20:27 +00:00
commit
621af4192e
376
cheevos.c
376
cheevos.c
@ -17,19 +17,19 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <configuration.h>
|
||||
#include <formats/jsonsax.h>
|
||||
#include <net/net_http.h>
|
||||
#include <rhash.h>
|
||||
#include <performance.h>
|
||||
#include <runloop.h>
|
||||
#include <retro_log.h>
|
||||
|
||||
#include "cheevos.h"
|
||||
|
||||
#include "dynamic.h"
|
||||
#include "runloop.h"
|
||||
#include "performance.h"
|
||||
|
||||
enum
|
||||
{
|
||||
@ -78,6 +78,7 @@ enum
|
||||
CHEEVOS_COND_TYPE_STANDARD,
|
||||
CHEEVOS_COND_TYPE_PAUSE_IF,
|
||||
CHEEVOS_COND_TYPE_RESET_IF,
|
||||
|
||||
CHEEVOS_COND_TYPE_LAST
|
||||
}; /* cheevos_cond_t.type */
|
||||
|
||||
@ -103,7 +104,8 @@ typedef struct
|
||||
unsigned bank_id;
|
||||
unsigned value;
|
||||
unsigned previous;
|
||||
} cheevos_var_t;
|
||||
}
|
||||
cheevos_var_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -114,7 +116,8 @@ typedef struct
|
||||
cheevos_var_t source;
|
||||
unsigned op;
|
||||
cheevos_var_t target;
|
||||
} cheevos_cond_t;
|
||||
}
|
||||
cheevos_cond_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -122,7 +125,8 @@ typedef struct
|
||||
unsigned count;
|
||||
|
||||
const char* expression;
|
||||
} cheevos_condset_t;
|
||||
}
|
||||
cheevos_condset_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -138,13 +142,15 @@ typedef struct
|
||||
|
||||
cheevos_condset_t* condsets;
|
||||
unsigned count;
|
||||
} cheevo_t;
|
||||
}
|
||||
cheevo_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
cheevo_t* cheevos;
|
||||
unsigned count;
|
||||
} cheevoset_t;
|
||||
}
|
||||
cheevoset_t;
|
||||
|
||||
static cheevoset_t core_cheevos = { NULL, 0 };
|
||||
static cheevoset_t unofficial_cheevos = { NULL, 0 };
|
||||
@ -162,7 +168,9 @@ static uint32_t cheevos_djb2( const char* str, size_t length )
|
||||
uint32_t hash = 5381;
|
||||
|
||||
while ( aux < end )
|
||||
{
|
||||
hash = ( hash << 5 ) + hash + *aux++;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
@ -177,7 +185,8 @@ typedef struct
|
||||
uint32_t field_hash;
|
||||
unsigned core_count;
|
||||
unsigned unofficial_count;
|
||||
} cheevos_countud_t;
|
||||
}
|
||||
cheevos_countud_t;
|
||||
|
||||
static int count__json_end_array( void* userdata )
|
||||
{
|
||||
@ -192,7 +201,9 @@ static int count__json_key( void* userdata, const char* name, size_t length )
|
||||
ud->field_hash = cheevos_djb2( name, length );
|
||||
|
||||
if ( ud->field_hash == 0x69749ae1U /* Achievements */ )
|
||||
{
|
||||
ud->in_cheevos = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -206,18 +217,20 @@ static int count__json_number( void* userdata, const char* number, size_t length
|
||||
long flags = strtol( number, NULL, 10 );
|
||||
|
||||
if ( flags == 3 ) /* core achievements */
|
||||
{
|
||||
ud->core_count++;
|
||||
}
|
||||
else if ( flags == 5 ) /* unofficial achievements */
|
||||
{
|
||||
ud->unofficial_count++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int count_cheevos( const char* json, unsigned* core_count, unsigned* unofficial_count )
|
||||
{
|
||||
int res;
|
||||
cheevos_countud_t ud;
|
||||
static const jsonsax_handlers_t handlers =
|
||||
{
|
||||
NULL,
|
||||
@ -234,6 +247,8 @@ static int count_cheevos( const char* json, unsigned* core_count, unsigned* unof
|
||||
NULL
|
||||
};
|
||||
|
||||
int res;
|
||||
cheevos_countud_t ud;
|
||||
ud.in_cheevos = 0;
|
||||
ud.core_count = 0;
|
||||
ud.unofficial_count = 0;
|
||||
@ -256,42 +271,27 @@ static unsigned prefix_to_comp_size( char prefix )
|
||||
|
||||
switch( toupper( prefix ) )
|
||||
{
|
||||
case 'M':
|
||||
return CHEEVOS_VAR_SIZE_BIT_0;
|
||||
case 'N':
|
||||
return CHEEVOS_VAR_SIZE_BIT_1;
|
||||
case 'O':
|
||||
return CHEEVOS_VAR_SIZE_BIT_2;
|
||||
case 'P':
|
||||
return CHEEVOS_VAR_SIZE_BIT_3;
|
||||
case 'Q':
|
||||
return CHEEVOS_VAR_SIZE_BIT_4;
|
||||
case 'R':
|
||||
return CHEEVOS_VAR_SIZE_BIT_5;
|
||||
case 'S':
|
||||
return CHEEVOS_VAR_SIZE_BIT_6;
|
||||
case 'T':
|
||||
return CHEEVOS_VAR_SIZE_BIT_7;
|
||||
case 'L':
|
||||
return CHEEVOS_VAR_SIZE_NIBBLE_LOWER;
|
||||
case 'U':
|
||||
return CHEEVOS_VAR_SIZE_NIBBLE_UPPER;
|
||||
case 'H':
|
||||
return CHEEVOS_VAR_SIZE_EIGHT_BITS;
|
||||
case 'X':
|
||||
return CHEEVOS_VAR_SIZE_THIRTYTWO_BITS;
|
||||
case 'M': return CHEEVOS_VAR_SIZE_BIT_0;
|
||||
case 'N': return CHEEVOS_VAR_SIZE_BIT_1;
|
||||
case 'O': return CHEEVOS_VAR_SIZE_BIT_2;
|
||||
case 'P': return CHEEVOS_VAR_SIZE_BIT_3;
|
||||
case 'Q': return CHEEVOS_VAR_SIZE_BIT_4;
|
||||
case 'R': return CHEEVOS_VAR_SIZE_BIT_5;
|
||||
case 'S': return CHEEVOS_VAR_SIZE_BIT_6;
|
||||
case 'T': return CHEEVOS_VAR_SIZE_BIT_7;
|
||||
case 'L': return CHEEVOS_VAR_SIZE_NIBBLE_LOWER;
|
||||
case 'U': return CHEEVOS_VAR_SIZE_NIBBLE_UPPER;
|
||||
case 'H': return CHEEVOS_VAR_SIZE_EIGHT_BITS;
|
||||
case 'X': return CHEEVOS_VAR_SIZE_THIRTYTWO_BITS;
|
||||
default:
|
||||
case ' ':
|
||||
break;
|
||||
case ' ': return CHEEVOS_VAR_SIZE_SIXTEEN_BITS;
|
||||
}
|
||||
|
||||
return CHEEVOS_VAR_SIZE_SIXTEEN_BITS;
|
||||
}
|
||||
|
||||
static unsigned read_hits( const char** memaddr )
|
||||
{
|
||||
char* end;
|
||||
const char* str = *memaddr;
|
||||
char* end;
|
||||
unsigned num_hits = 0;
|
||||
|
||||
if ( *str == '(' || *str == '.' )
|
||||
@ -306,8 +306,8 @@ static unsigned read_hits( const char** memaddr )
|
||||
|
||||
static unsigned parse_operator( const char** memaddr )
|
||||
{
|
||||
unsigned char op;
|
||||
const char* str = *memaddr;
|
||||
unsigned char op;
|
||||
|
||||
if ( *str == '=' && str[ 1 ] == '=' )
|
||||
{
|
||||
@ -344,8 +344,11 @@ static unsigned parse_operator( const char** memaddr )
|
||||
op = CHEEVOS_COND_OP_GREATER_THAN;
|
||||
str++;
|
||||
}
|
||||
else /* TODO log the exception */
|
||||
else
|
||||
{
|
||||
/* TODO log the exception */
|
||||
op = CHEEVOS_COND_OP_EQUALS;
|
||||
}
|
||||
|
||||
*memaddr = str;
|
||||
return op;
|
||||
@ -353,8 +356,8 @@ static unsigned parse_operator( const char** memaddr )
|
||||
|
||||
static void parse_var( cheevos_var_t* var, const char** memaddr )
|
||||
{
|
||||
char* end;
|
||||
const char* str = *memaddr;
|
||||
char* end;
|
||||
unsigned base = 16;
|
||||
|
||||
if ( toupper( *str ) == 'D' && str[ 1 ] == '0' && toupper( str[ 2 ] ) == 'X' )
|
||||
@ -374,18 +377,24 @@ static void parse_var( cheevos_var_t* var, const char** memaddr )
|
||||
var->type = CHEEVOS_VAR_TYPE_VALUE_COMP;
|
||||
|
||||
if ( toupper( *str ) == 'H' )
|
||||
{
|
||||
str++;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = 10;
|
||||
}
|
||||
}
|
||||
|
||||
if ( var->type != CHEEVOS_VAR_TYPE_VALUE_COMP )
|
||||
{
|
||||
var->size = prefix_to_comp_size( *str );
|
||||
|
||||
if ( var->size != CHEEVOS_VAR_SIZE_SIXTEEN_BITS )
|
||||
{
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
var->value = strtol( str, &end, base );
|
||||
*memaddr = end;
|
||||
@ -406,7 +415,9 @@ static void parse_cond( cheevos_cond_t* cond, const char** memaddr )
|
||||
str += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
cond->type = CHEEVOS_COND_TYPE_STANDARD;
|
||||
}
|
||||
|
||||
parse_var( &cond->source, &str );
|
||||
cond->op = parse_operator( &str );
|
||||
@ -419,44 +430,54 @@ static void parse_cond( cheevos_cond_t* cond, const char** memaddr )
|
||||
|
||||
static unsigned count_cond_sets( const char* memaddr )
|
||||
{
|
||||
cheevos_cond_t cond;
|
||||
unsigned count = 0;
|
||||
cheevos_cond_t cond;
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
while( *memaddr == ' ' || *memaddr == '_' || *memaddr == '|' || *memaddr == 'S' )
|
||||
{
|
||||
memaddr++; /* Skip any chars up til the start of the achievement condition */
|
||||
}
|
||||
|
||||
parse_cond( &cond, &memaddr );
|
||||
}while( *memaddr == '_' || *memaddr == 'R' || *memaddr == 'P' ); /* AND, ResetIf, PauseIf */
|
||||
}
|
||||
while( *memaddr == '_' || *memaddr == 'R' || *memaddr == 'P' ); /* AND, ResetIf, PauseIf */
|
||||
|
||||
count++;
|
||||
}while( *memaddr == 'S' ); /* Repeat for all subconditions if they exist */
|
||||
}
|
||||
while( *memaddr == 'S' ); /* Repeat for all subconditions if they exist */
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static unsigned count_conds_in_set( const char* memaddr, unsigned set )
|
||||
{
|
||||
cheevos_cond_t cond;
|
||||
unsigned index = 0;
|
||||
unsigned count = 0;
|
||||
cheevos_cond_t cond;
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
while ( *memaddr == ' ' || *memaddr == '_' || *memaddr == '|' || *memaddr == 'S' )
|
||||
{
|
||||
memaddr++; /* Skip any chars up til the start of the achievement condition */
|
||||
}
|
||||
|
||||
parse_cond( &cond, &memaddr );
|
||||
|
||||
if ( index == set )
|
||||
{
|
||||
count++;
|
||||
}while ( *memaddr == '_' || *memaddr == 'R' || *memaddr == 'P' ); /* AND, ResetIf, PauseIf */
|
||||
}while( *memaddr == 'S' ); /* Repeat for all subconditions if they exist */
|
||||
}
|
||||
}
|
||||
while ( *memaddr == '_' || *memaddr == 'R' || *memaddr == 'P' ); /* AND, ResetIf, PauseIf */
|
||||
}
|
||||
while( *memaddr == 'S' ); /* Repeat for all subconditions if they exist */
|
||||
|
||||
return count;
|
||||
}
|
||||
@ -468,11 +489,15 @@ static void parse_memaddr( cheevos_cond_t* cond, const char* memaddr )
|
||||
do
|
||||
{
|
||||
while( *memaddr == ' ' || *memaddr == '_' || *memaddr == '|' || *memaddr == 'S' )
|
||||
{
|
||||
memaddr++; /* Skip any chars up til the start of the achievement condition */
|
||||
}
|
||||
|
||||
parse_cond( cond++, &memaddr );
|
||||
}while( *memaddr == '_' || *memaddr == 'R' || *memaddr == 'P' ); /* AND, ResetIf, PauseIf */
|
||||
}while( *memaddr == 'S' ); /* Repeat for all subconditions if they exist */
|
||||
}
|
||||
while( *memaddr == '_' || *memaddr == 'R' || *memaddr == 'P' ); /* AND, ResetIf, PauseIf */
|
||||
}
|
||||
while( *memaddr == 'S' ); /* Repeat for all subconditions if they exist */
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
@ -483,7 +508,8 @@ typedef struct
|
||||
{
|
||||
const char* string;
|
||||
size_t length;
|
||||
} cheevos_field_t;
|
||||
}
|
||||
cheevos_field_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -494,9 +520,10 @@ typedef struct
|
||||
cheevos_field_t* field;
|
||||
cheevos_field_t id, memaddr, title, desc, points, author;
|
||||
cheevos_field_t modified, created, badge, flags;
|
||||
} cheevos_readud_t;
|
||||
}
|
||||
cheevos_readud_t;
|
||||
|
||||
static inline const char* dupstr( const cheevos_field_t* field )
|
||||
static INLINE const char* dupstr( const cheevos_field_t* field )
|
||||
{
|
||||
char* string = (char*)malloc( field->length + 1 );
|
||||
|
||||
@ -518,9 +545,13 @@ static int new_cheevo( cheevos_readud_t* ud )
|
||||
int flags = strtol( ud->flags.string, NULL, 10 );
|
||||
|
||||
if ( flags == 3 )
|
||||
{
|
||||
cheevo = core_cheevos.cheevos + ud->core_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
cheevo = unofficial_cheevos.cheevos + ud->unofficial_count++;
|
||||
}
|
||||
|
||||
cheevo->id = strtol( ud->id.string, NULL, 10 );
|
||||
cheevo->title = dupstr( &ud->title );
|
||||
@ -548,7 +579,9 @@ static int new_cheevo( cheevos_readud_t* ud )
|
||||
cheevo->condsets = (cheevos_condset_t*)malloc( cheevo->count * sizeof( cheevos_condset_t ) );
|
||||
|
||||
if ( !cheevo->condsets )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset( (void*)cheevo->condsets, 0, cheevo->count * sizeof( cheevos_condset_t ) );
|
||||
end = cheevo->condsets + cheevo->count;
|
||||
@ -557,19 +590,24 @@ static int new_cheevo( cheevos_readud_t* ud )
|
||||
for ( condset = cheevo->condsets; condset < end; condset++ )
|
||||
{
|
||||
condset->count = count_conds_in_set( ud->memaddr.string, set++ );
|
||||
condset->conds = NULL;
|
||||
|
||||
if ( condset->count )
|
||||
{
|
||||
condset->conds = (cheevos_cond_t*)malloc( condset->count * sizeof( cheevos_cond_t ) );
|
||||
|
||||
if ( !condset->conds )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset( (void*)condset->conds, 0, condset->count * sizeof( cheevos_cond_t ) );
|
||||
condset->expression = dupstr( &ud->memaddr );
|
||||
parse_memaddr( condset->conds, ud->memaddr.string );
|
||||
}
|
||||
else
|
||||
{
|
||||
condset->conds = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -584,41 +622,23 @@ static int read__json_key( void* userdata, const char* name, size_t length )
|
||||
ud->field = NULL;
|
||||
|
||||
if ( hash == 0x69749ae1U /* Achievements */ )
|
||||
{
|
||||
ud->in_cheevos = 1;
|
||||
}
|
||||
else if ( ud->in_cheevos )
|
||||
{
|
||||
switch ( hash )
|
||||
{
|
||||
case 0x005973f2U: /* ID */
|
||||
ud->field = &ud->id;
|
||||
break;
|
||||
case 0x1e76b53fU: /* MemAddr */
|
||||
ud->field = &ud->memaddr;
|
||||
break;
|
||||
case 0x0e2a9a07U: /* Title */
|
||||
ud->field = &ud->title;
|
||||
break;
|
||||
case 0xe61a1f69U: /* Description */
|
||||
ud->field = &ud->desc;
|
||||
break;
|
||||
case 0xca8fce22U: /* Points */
|
||||
ud->field = &ud->points;
|
||||
break;
|
||||
case 0xa804edb8U: /* Author */
|
||||
ud->field = &ud->author;
|
||||
break;
|
||||
case 0xdcea4fe6U: /* Modified */
|
||||
ud->field = &ud->modified;
|
||||
break;
|
||||
case 0x3a84721dU: /* Created */
|
||||
ud->field = &ud->created;
|
||||
break;
|
||||
case 0x887685d9U: /* BadgeName */
|
||||
ud->field = &ud->badge;
|
||||
break;
|
||||
case 0x0d2e96b2U: /* Flags */
|
||||
ud->field = &ud->flags;
|
||||
break;
|
||||
case 0x005973f2U: /* ID */ ud->field = &ud->id; break;
|
||||
case 0x1e76b53fU: /* MemAddr */ ud->field = &ud->memaddr; break;
|
||||
case 0x0e2a9a07U: /* Title */ ud->field = &ud->title; break;
|
||||
case 0xe61a1f69U: /* Description */ ud->field = &ud->desc; break;
|
||||
case 0xca8fce22U: /* Points */ ud->field = &ud->points; break;
|
||||
case 0xa804edb8U: /* Author */ ud->field = &ud->author; break;
|
||||
case 0xdcea4fe6U: /* Modified */ ud->field = &ud->modified; break;
|
||||
case 0x3a84721dU: /* Created */ ud->field = &ud->created; break;
|
||||
case 0x887685d9U: /* BadgeName */ ud->field = &ud->badge; break;
|
||||
case 0x0d2e96b2U: /* Flags */ ud->field = &ud->flags; break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,7 +676,9 @@ static int read__json_end_object( void* userdata )
|
||||
cheevos_readud_t* ud = (cheevos_readud_t*)userdata;
|
||||
|
||||
if ( ud->in_cheevos )
|
||||
{
|
||||
return new_cheevo( ud );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -689,9 +711,12 @@ int cheevos_load( const char* json )
|
||||
/* Count the number of achievements in the JSON file. */
|
||||
|
||||
unsigned core_count, unofficial_count;
|
||||
cheevos_readud_t ud;
|
||||
|
||||
if ( count_cheevos( json, &core_count, &unofficial_count ) != JSONSAX_OK )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate the achievements. */
|
||||
|
||||
@ -715,14 +740,15 @@ int cheevos_load( const char* json )
|
||||
|
||||
/* Load the achievements. */
|
||||
|
||||
cheevos_readud_t ud;
|
||||
ud.in_cheevos = 0;
|
||||
ud.field = NULL;
|
||||
ud.core_count = 0;
|
||||
ud.unofficial_count = 0;
|
||||
|
||||
if ( jsonsax_parse( json, &handlers, (void*)&ud ) == JSONSAX_OK )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
cheevos_unload();
|
||||
return -1;
|
||||
@ -775,28 +801,41 @@ static const uint8_t* get_memory( unsigned offset )
|
||||
|
||||
static unsigned get_var_value( cheevos_var_t* var )
|
||||
{
|
||||
const uint8_t* memory;
|
||||
unsigned previous = var->previous;
|
||||
unsigned live_val = 0;
|
||||
const uint8_t* memory;
|
||||
|
||||
if ( var->type == CHEEVOS_VAR_TYPE_VALUE_COMP )
|
||||
{
|
||||
return var->value;
|
||||
}
|
||||
|
||||
if ( var->type == CHEEVOS_VAR_TYPE_ADDRESS || var->type == CHEEVOS_VAR_TYPE_DELTA_MEM )
|
||||
{
|
||||
/* TODO Check with Scott if the bank id is needed */
|
||||
memory = (uint8_t*)get_memory( var->value );
|
||||
live_val = memory[ var->value ];
|
||||
memory = get_memory( var->value );
|
||||
live_val = memory[ 0 ];
|
||||
|
||||
if ( var->size >= CHEEVOS_VAR_SIZE_BIT_0 && var->size <= CHEEVOS_VAR_SIZE_BIT_7 )
|
||||
{
|
||||
live_val = ( live_val & ( 1 << ( var->size - CHEEVOS_VAR_SIZE_BIT_0 ) ) ) != 0;
|
||||
}
|
||||
else if ( var->size == CHEEVOS_VAR_SIZE_NIBBLE_LOWER )
|
||||
{
|
||||
live_val &= 0x0f;
|
||||
}
|
||||
else if ( var->size == CHEEVOS_VAR_SIZE_NIBBLE_UPPER )
|
||||
{
|
||||
live_val = ( live_val >> 4 ) & 0x0f;
|
||||
else if ( var->size == CHEEVOS_VAR_SIZE_EIGHT_BITS ) { }
|
||||
}
|
||||
else if ( var->size == CHEEVOS_VAR_SIZE_EIGHT_BITS )
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
else if ( var->size == CHEEVOS_VAR_SIZE_SIXTEEN_BITS )
|
||||
{
|
||||
live_val |= memory[ 1 ] << 8;
|
||||
}
|
||||
else if ( var->size == CHEEVOS_VAR_SIZE_THIRTYTWO_BITS )
|
||||
{
|
||||
live_val |= memory[ 1 ] << 8;
|
||||
@ -843,19 +882,17 @@ static int test_condition( cheevos_cond_t* cond )
|
||||
return sval != tval;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int test_cond_set( const cheevos_condset_t* condset, int* dirty_conds, int* reset_conds, int match_any )
|
||||
{
|
||||
cheevos_cond_t* cond;
|
||||
int cond_valid = 0;
|
||||
int set_valid = 1;
|
||||
int pause_active = 0;
|
||||
const cheevos_cond_t* end = condset->conds + condset->count;
|
||||
cheevos_cond_t* cond;
|
||||
|
||||
/* Now, read all Pause conditions, and if any are true, do not process further (retain old state) */
|
||||
for ( cond = condset->conds; cond < end; cond++ )
|
||||
@ -880,10 +917,14 @@ static int test_cond_set( const cheevos_condset_t* condset, int* dirty_conds, in
|
||||
for ( cond = condset->conds; cond < end; cond++ )
|
||||
{
|
||||
if ( cond->type == CHEEVOS_COND_TYPE_PAUSE_IF || cond->type == CHEEVOS_COND_TYPE_RESET_IF )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( cond->req_hits != 0 && cond->curr_hits >= cond->req_hits )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cond_valid = test_condition( cond );
|
||||
|
||||
@ -904,8 +945,10 @@ static int test_cond_set( const cheevos_condset_t* condset, int* dirty_conds, in
|
||||
}
|
||||
|
||||
if ( match_any )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sequential or non-sequential? */
|
||||
set_valid &= cond_valid;
|
||||
@ -932,9 +975,9 @@ static int test_cond_set( const cheevos_condset_t* condset, int* dirty_conds, in
|
||||
|
||||
static int reset_cond_set( cheevos_condset_t* condset, int deltas )
|
||||
{
|
||||
cheevos_cond_t* cond;
|
||||
int dirty = 0;
|
||||
const cheevos_cond_t* end = condset->conds + condset->count;
|
||||
cheevos_cond_t* cond;
|
||||
|
||||
if ( deltas )
|
||||
{
|
||||
@ -961,10 +1004,10 @@ static int reset_cond_set( cheevos_condset_t* condset, int deltas )
|
||||
|
||||
static int test_cheevo( cheevo_t* cheevo )
|
||||
{
|
||||
int dirty;
|
||||
int dirty_conds = 0;
|
||||
int reset_conds = 0;
|
||||
int ret_val = 0;
|
||||
int dirty;
|
||||
int ret_val_sub_cond = cheevo->count == 1;
|
||||
cheevos_condset_t* condset = cheevo->condsets;
|
||||
const cheevos_condset_t* end = condset + cheevo->count;
|
||||
@ -985,26 +1028,32 @@ static int test_cheevo( cheevo_t* cheevo )
|
||||
}
|
||||
|
||||
if ( dirty_conds )
|
||||
{
|
||||
cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS;
|
||||
}
|
||||
|
||||
if ( reset_conds )
|
||||
{
|
||||
dirty = 0;
|
||||
|
||||
for ( condset = cheevo->condsets; condset < end; condset++ )
|
||||
{
|
||||
dirty |= reset_cond_set( condset, 0 );
|
||||
}
|
||||
|
||||
if ( dirty )
|
||||
{
|
||||
cheevo->dirty |= CHEEVOS_DIRTY_CONDITIONS;
|
||||
}
|
||||
}
|
||||
|
||||
return ret_val && ret_val_sub_cond;
|
||||
}
|
||||
|
||||
static void test_cheevo_set( const cheevoset_t* set )
|
||||
{
|
||||
cheevo_t* cheevo;
|
||||
const cheevo_t* end = set->cheevos + set->count;
|
||||
cheevo_t* cheevo;
|
||||
|
||||
for ( cheevo = set->cheevos; cheevo < end; cheevo++ )
|
||||
{
|
||||
@ -1023,19 +1072,16 @@ static void test_cheevo_set( const cheevoset_t* set )
|
||||
|
||||
void cheevos_test( void )
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
if (!settings)
|
||||
return;
|
||||
|
||||
if ( settings->cheevos.enable )
|
||||
if ( config_get_ptr()->cheevos.enable )
|
||||
{
|
||||
test_cheevo_set( &core_cheevos );
|
||||
|
||||
if ( settings->cheevos.test_unofficial )
|
||||
if ( config_get_ptr()->cheevos.test_unofficial )
|
||||
{
|
||||
test_cheevo_set( &unofficial_cheevos );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
Free the loaded achievements.
|
||||
@ -1061,7 +1107,9 @@ static void free_cheevo_set( const cheevoset_t* set )
|
||||
const cheevo_t* end = cheevo + set->count;
|
||||
|
||||
while ( cheevo < end )
|
||||
{
|
||||
free_cheevo( cheevo++ );
|
||||
}
|
||||
|
||||
free( (void*)set->cheevos );
|
||||
}
|
||||
@ -1079,31 +1127,46 @@ void cheevos_unload(void)
|
||||
static const char* cheevos_http_get( const char* url, size_t* size )
|
||||
{
|
||||
#ifdef HAVE_NETWORKING
|
||||
|
||||
struct http_connection_t* conn;
|
||||
struct http_t* http;
|
||||
uint8_t* data;
|
||||
size_t length;
|
||||
char* result;
|
||||
struct http_connection_t *conn = net_http_connection_new( url );
|
||||
|
||||
RARCH_LOG( "CHEEVOS http get %s\n", url );
|
||||
conn = net_http_connection_new( url );
|
||||
|
||||
if ( !conn )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ( !net_http_connection_iterate( conn ) ) { }
|
||||
while ( !net_http_connection_iterate( conn ) )
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
if ( !net_http_connection_done( conn ) )
|
||||
goto error;
|
||||
{
|
||||
error1:
|
||||
net_http_connection_free( conn );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
http = net_http_new( conn );
|
||||
|
||||
if ( !http )
|
||||
{
|
||||
goto error1;
|
||||
}
|
||||
|
||||
while ( !net_http_update( http, NULL, NULL ) ) { }
|
||||
while ( !net_http_update( http, NULL, NULL ) )
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
data = net_http_data( http, &length, false );
|
||||
result = NULL;
|
||||
|
||||
if ( data )
|
||||
{
|
||||
@ -1111,6 +1174,10 @@ static const char* cheevos_http_get( const char* url, size_t* size )
|
||||
memcpy( (void*)result, (void*)data, length );
|
||||
result[ length ] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
net_http_delete( http );
|
||||
net_http_connection_free( conn );
|
||||
@ -1118,21 +1185,21 @@ static const char* cheevos_http_get( const char* url, size_t* size )
|
||||
RARCH_LOG( "CHEEVOS http result is %s\n", result );
|
||||
|
||||
if ( size )
|
||||
{
|
||||
*size = length;
|
||||
}
|
||||
|
||||
return (char*)result;
|
||||
|
||||
error1:
|
||||
net_http_connection_free( conn );
|
||||
return NULL;
|
||||
|
||||
#else /* HAVE_NETWORKING */
|
||||
|
||||
RARCH_LOG( "CHEEVOS http get %s\n", url );
|
||||
RARCH_ERROR( "CHEEVOS Network unavailable\n" );
|
||||
|
||||
if ( size )
|
||||
{
|
||||
*size = 0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@ -1237,78 +1304,72 @@ static int cheevos_login(void)
|
||||
{
|
||||
char request[ 256 ];
|
||||
const char* json;
|
||||
cheevo_getvalueud_t ud;
|
||||
int res = 0;
|
||||
int res;
|
||||
|
||||
if ( token[ 0 ] == 0 )
|
||||
if ( !token[ 0 ] )
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
if (!settings)
|
||||
return -1;
|
||||
|
||||
snprintf(
|
||||
request, sizeof( request ),
|
||||
"http://retroachievements.org/dorequest.php?r=login&u=%s&p=%s",
|
||||
settings->cheevos.username, settings->cheevos.password
|
||||
config_get_ptr()->cheevos.user_name, config_get_ptr()->cheevos.password
|
||||
);
|
||||
|
||||
request[ sizeof( request ) - 1 ] = 0;
|
||||
|
||||
json = cheevos_http_get( request, NULL );
|
||||
|
||||
if ( !json )
|
||||
return -1;
|
||||
|
||||
if ( json )
|
||||
{
|
||||
res = cheevos_get_value( json, 0x0e2dbd26U /* Token */, token, sizeof( token ) );
|
||||
free( (void*)json );
|
||||
|
||||
if ( !res )
|
||||
{
|
||||
RARCH_LOG( "CHEEVOS user token is '%s'\n", token );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RARCH_LOG( "CHEEVOS user token is %s\n", token );
|
||||
return res;
|
||||
RARCH_LOG( "CHEEVOS error getting user token\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cheevos_get_by_game_id( const char** json, unsigned game_id )
|
||||
{
|
||||
char request[ 256 ];
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
if (!settings)
|
||||
return -1;
|
||||
|
||||
cheevos_login();
|
||||
|
||||
snprintf(
|
||||
request, sizeof( request ),
|
||||
"http://retroachievements.org/dorequest.php?r=patch&u=%s&g=%u&f=3&l=1&t=%s",
|
||||
settings->cheevos.username, game_id, settings->cheevos.token
|
||||
config_get_ptr()->cheevos.user_name, game_id, token
|
||||
);
|
||||
|
||||
request[ sizeof( request ) - 1 ] = 0;
|
||||
|
||||
*json = cheevos_http_get( request, NULL );
|
||||
|
||||
if ( !*json )
|
||||
return -1;
|
||||
|
||||
if ( *json )
|
||||
{
|
||||
RARCH_LOG( "CHEEVOS got achievements for game id %u\n", game_id );
|
||||
return 0;
|
||||
}
|
||||
|
||||
RARCH_LOG( "CHEEVOS error getting achievements for game id %u\n", game_id );
|
||||
return -1;
|
||||
}
|
||||
|
||||
static unsigned cheevos_get_game_id( unsigned char* hash )
|
||||
{
|
||||
MD5_CTX ctx;
|
||||
const char* json;
|
||||
char request[ 256 ];
|
||||
const char* json;
|
||||
char game_id[ 16 ];
|
||||
int res;
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
if (!settings)
|
||||
return -1;
|
||||
|
||||
snprintf(
|
||||
request, sizeof( request ),
|
||||
"http://retroachievements.org/dorequest.php?r=gameid&u=%s&m=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||
settings->cheevos.username,
|
||||
config_get_ptr()->cheevos.user_name,
|
||||
hash[ 0 ], hash[ 1 ], hash[ 2 ], hash[ 3 ],
|
||||
hash[ 4 ], hash[ 5 ], hash[ 6 ], hash[ 7 ],
|
||||
hash[ 8 ], hash[ 9 ], hash[ 10 ], hash[ 11 ],
|
||||
@ -1316,16 +1377,22 @@ static unsigned cheevos_get_game_id( unsigned char* hash )
|
||||
);
|
||||
|
||||
request[ sizeof( request ) - 1 ] = 0;
|
||||
|
||||
json = cheevos_http_get( request, NULL );
|
||||
|
||||
if ( !json )
|
||||
return 0;
|
||||
|
||||
if ( json )
|
||||
{
|
||||
res = cheevos_get_value( json, 0xb4960eecU /* GameID */, game_id, sizeof( game_id ) );
|
||||
free( (void*)json );
|
||||
|
||||
return res ? 0 : strtoul( game_id, NULL, 10 );
|
||||
if ( !res )
|
||||
{
|
||||
RARCH_LOG( "CHEEVOS got game id %s\n", game_id );
|
||||
return strtoul( game_id, NULL, 10 );
|
||||
}
|
||||
}
|
||||
|
||||
RARCH_LOG( "CHEEVOS error getting game_id\n" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CHEEVOS_EIGHT_MB ( 8 * 1024 * 1024 )
|
||||
@ -1333,10 +1400,10 @@ static unsigned cheevos_get_game_id( unsigned char* hash )
|
||||
int cheevos_get_by_content( const char** json, const void* data, size_t size )
|
||||
{
|
||||
MD5_CTX ctx, saved_ctx;
|
||||
char buffer[ 4096 ];
|
||||
size_t len;
|
||||
unsigned char hash[ 16 ];
|
||||
char request[ 256 ];
|
||||
char buffer[ 4096 ];
|
||||
unsigned game_id;
|
||||
int res;
|
||||
|
||||
@ -1358,20 +1425,19 @@ int cheevos_get_by_content( const char** json, const void* data, size_t size )
|
||||
len = sizeof( buffer );
|
||||
|
||||
if ( len > size )
|
||||
{
|
||||
len = size;
|
||||
}
|
||||
|
||||
MD5_Update( &saved_ctx, (void*)buffer, len );
|
||||
size -= len;
|
||||
}while(size);
|
||||
}
|
||||
while ( size );
|
||||
|
||||
MD5_Final( hash, &saved_ctx );
|
||||
|
||||
game_id = cheevos_get_game_id( hash );
|
||||
|
||||
if ( !game_id )
|
||||
return -1;
|
||||
}
|
||||
|
||||
RARCH_LOG( "CHEEVOS game id is %u\n", game_id );
|
||||
return cheevos_get_by_game_id( json, game_id );
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user