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
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);
|
|
}
|
|
}
|