You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
3.2 KiB

#include "rc_hash.h"
#include "rc_runtime.h"
#include <fat.h>
#include <nds.h>
#include <stdio.h>
typedef struct rc_bsach_header_t {
char magic[8];
u32 game_id;
u32 console_id;
u32 forum_topic_id;
u32 flags;
u32 is_final;
u32 achievement_count;
u32 leaderboard_count;
u32 reserved1[3];
u8 hash[16];
char title[32];
char publisher[32];
char developer[32];
char genre[32];
char release_date[32];
char console_name[32];
} __packed rc_bsach_header_t;
typedef struct rc_achievement_t {
u32 id;
u32 points;
u32 flags;
u32 creation_time;
u32 modified_time;
u32 description_len;
u32 mem_addr_len;
u32 completion_time;
u32 reserved1[8];
char title[32];
char author[32];
char reserved2[128];
char description[256];
char mem_addr[512];
} __packed rc_achievement_t;
typedef struct rc_leaderboard_t {
u32 id;
u32 hidden;
u32 lower_is_better;
u32 description_len;
u32 mem_len;
u32 reserved1[11];
char title[32];
char format[32];
char reserved2[128];
char description[256];
char mem[512];
} __packed rc_leaderboard_t;
rc_runtime_t runtime;
void eventHandler(const rc_runtime_event_t *runtime_event) {
iprintf("%d : %d : %d\n", runtime_event->id, runtime_event->value, runtime_event->type);
if(runtime_event->type == RC_RUNTIME_EVENT_ACHIEVEMENT_TRIGGERED) {
iprintf("!!!\n");
rc_runtime_deactivate_achievement(&runtime, runtime_event->id);
}
}
unsigned peek(unsigned address, unsigned num_bytes, void *ud) {
switch(num_bytes) {
case 1:
return *(u8 *)address;
case 2:
return *(u16 *)address;
case 4:
return *(u32 *)address;
}
return 0;
}
void error(const char *str) {
iprintf("\x1B[41mError:\x1B[47m %s\n", str);
}
void verbose(const char *str) {
iprintf("\x1B[42mVerbose:\x1B[47m %s\n", str);
}
void register_achievements(const char *path, char *file_hash) {
FILE *file = fopen(path, "rb");
if(file) {
rc_bsach_header_t header;
fread(&header, 1, sizeof(header), file);
iprintf("Loading: %s\n", header.title);
char hash_str[33];
u8 *d = header.hash;
sniprintf(hash_str, 33, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]
);
if(strcmp(hash_str, file_hash) != 0) {
iprintf("Invalid hash:\n%s\n\nExpected:\n%s\n", file_hash, hash_str);
}
for(int i = 0; i < header.achievement_count; i++) {
rc_achievement_t achievement;
fread(&achievement, 1, sizeof(achievement), file);
rc_runtime_activate_achievement(&runtime, achievement.id, achievement.mem_addr, NULL, 0);
iprintf("- %s\n", achievement.title);
}
fclose(file);
}
}
int main(void) {
consoleDemoInit();
if(!fatInitDefault())
iprintf("FAT init fail\n");
rc_hash_init_error_message_callback(error);
rc_hash_init_verbose_message_callback(verbose);
char hash[33];
if(!rc_hash_generate_from_file(hash, RC_CONSOLE_NINTENDO_DS, "sd:/Mario Kart DS.nds"))
printf("hash fail\n");
rc_runtime_init(&runtime);
register_achievements("sd:/Mario Kart DS.bsach", hash);
while(1) {
swiWaitForVBlank();
scanKeys();
int pressed = keysDown();
if(pressed & KEY_START) break;
rc_runtime_do_frame(&runtime, eventHandler, peek, NULL, NULL);
}
}