Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[develop] Add datel cheat support from filesystem #204

Draft
wants to merge 30 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
db6a7b8
inital support for cheat parsing in frontend
XLuma Jan 12, 2025
bfc28b4
move cheat functions to separate file, move calls to load function
XLuma Jan 12, 2025
cd26c23
hardcode cheats for test, add new files to makefile, add proper error…
XLuma Jan 13, 2025
2b52a92
add extension checck for filetype detection
XLuma Jan 13, 2025
e9cb8d1
fix merge.
XLuma Jan 14, 2025
9ad2ec1
add cheat to develop
XLuma Jan 14, 2025
d308f67
strtol -> strtoul, change longs to uint32_t
XLuma Jan 14, 2025
fabe4b1
remove a lot of comments
XLuma Jan 14, 2025
9123c8e
small credit header
XLuma Jan 14, 2025
1afa136
fix indentation in files
XLuma Jan 14, 2025
c39142d
apply suggestion in menu.c
XLuma Jan 14, 2025
466684c
add EOF's
XLuma Jan 14, 2025
0c61055
convert indentation from tab to 4 spaces in cheat_load.c
XLuma Jan 14, 2025
85ad8d0
move includes to top
XLuma Jan 14, 2025
df26ee0
remove leftover tab in ft_split
XLuma Jan 14, 2025
5a73092
remove unused header files in cart_load.c
XLuma Jan 14, 2025
1bd32a3
Formatting improvements
networkfusion Jan 14, 2025
bde4a79
Merge branch 'develop' into develop-cheat-frontend
networkfusion Jan 14, 2025
fc23d60
Merge branch 'develop' into develop-cheat-frontend
networkfusion Jan 15, 2025
7f6630f
add menu option to rom settings, todo: handling code
XLuma Jan 15, 2025
10c1b0c
forgot semicolon
XLuma Jan 15, 2025
14a6af4
add Cheats option in rom settings screen
XLuma Jan 16, 2025
a1e9cc5
remove call to load_cheat in rom loading
XLuma Jan 16, 2025
d9c0a38
ignore lines starting with $ (pj64 cheats)
XLuma Jan 16, 2025
8181626
Code style fixes
networkfusion Jan 16, 2025
6f25047
Minor codestyle fixes
networkfusion Jan 16, 2025
8165d8c
Example documentation improvements
networkfusion Jan 16, 2025
8634424
Re-order context menu
networkfusion Jan 16, 2025
f293848
Update 13_datel_cheats.md
networkfusion Jan 16, 2025
b8f3bcc
Further document improvements
networkfusion Jan 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ SRCS = \
menu/actions.c \
menu/bookkeeping.c \
menu/cart_load.c \
menu/cheat_load.c \
menu/disk_info.c \
menu/fonts.c \
menu/hdmi.c \
Expand Down
6 changes: 4 additions & 2 deletions src/menu/cart_load.c
XLuma marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include "path.h"
#include "utils/fs.h"
#include "utils/utils.h"
#include <stdio.h>
#include <sys/stat.h>
#include "cheat_load.h"

#ifndef SAVES_SUBDIRECTORY
#define SAVES_SUBDIRECTORY "saves"
Expand Down Expand Up @@ -92,9 +95,8 @@ cart_load_err_t cart_load_n64_rom_and_save (menu_t *menu, flashcart_progress_cal
path_free(path);
return CART_LOAD_ERR_SAVE_LOAD_FAIL;
}

path_free(path);
XLuma marked this conversation as resolved.
Show resolved Hide resolved

return CART_LOAD_OK;
}

Expand Down
197 changes: 197 additions & 0 deletions src/menu/cheat_load.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
#include <string.h>

#include <libdragon.h>

#include <stdio.h>
#include <sys/stat.h>
#include "views/views.h"
#include "cheat_load.h"
#include "../utils/fs.h"

/**
XLuma marked this conversation as resolved.
Show resolved Hide resolved
* Frontend cheat support
*
* Made by Mena and XLuma
*/

char *cheat_load_convert_error_message (cheat_load_err_t err) {
switch (err) {
case CHEAT_LOAD_OK: return "Cart load OK";
case CHEAT_LOAD_ERR_NO_CHEAT_FILE: return "No cheat file found";
case CHEAT_LOAD_ERR_SIZE_FAILED: return "Error occured acquiring cheat size";
case CHEAT_LOAD_ERR_CHEAT_EMPTY: return "Cheat file is empty";
case CHEAT_LOAD_ERR_CHEAT_TOO_LARGE: return "Cheat file is too large (over 128KiB)";
case CHEAT_LOAD_ERR_MALLOC_FAILED: return "Error occured allocating memory for file";
case CHEAT_LOAD_ERR_READ_FAILED: return "Error occured during file read";
case CHEAT_LOAD_ERR_CLOSE_FAILED: return "Error occured during file close";
default: return "Unknown error [CHEAT_LOAD]";
}
}

static int find_str(char const *s, char c)
{
int i;
int nb_str;

i = 0;
nb_str = 0;
if (!s[0])
return (0);
while (s[i] && s[i] == c)
i++;
while (s[i])
{
if (s[i] == c)
{
nb_str++;
while (s[i] && s[i] == c)
i++;
continue ;
}
i++;
}
if (s[i - 1] != c)
nb_str++;
return (nb_str);
}

static void get_next_str(char **next_str, size_t *next_strlen, char c)
{
size_t i;

*next_str += *next_strlen;
*next_strlen = 0;
i = 0;
while (**next_str && **next_str == c)
(*next_str)++;
while ((*next_str)[i])
{
if ((*next_str)[i] == c)
return ;
(*next_strlen)++;
i++;
}
}

static char **free_tab(char **tab)
{
int i;

i = 0;
while (tab[i])
{
free(tab[i]);
i++;
}
free(tab);
return (NULL);
}

char **ft_split(char const *s, char c)
XLuma marked this conversation as resolved.
Show resolved Hide resolved
{
char **tab;
char *next_str;
size_t next_strlen;
int i;

i = -1;
if (!s)
return (NULL);
tab = malloc(sizeof(char *) * (find_str(s, c) + 1));
if (!tab)
return (NULL);
next_str = (char *)s;
next_strlen = 0;
while (++i < find_str(s, c))
{
get_next_str(&next_str, &next_strlen, c);
tab[i] = (char *)malloc(sizeof(char) * (next_strlen + 1));
if (!tab[i])
return (free_tab(tab));
strlcpy(tab[i], next_str, next_strlen + 1);
}
tab[i] = NULL;
return (tab);
}

cheat_load_err_t load_cheats(menu_t *menu) {
FILE *cheatsFile;
struct stat st;
size_t cheatsLength;
path_t *path = path_clone(menu->load.rom_path);

//Parse cheats from file
path_ext_replace(path, "cht");
if((cheatsFile = fopen(path_get(path), "rb")) == NULL) {
path_free(path);
return CHEAT_LOAD_OK;//no file is not an error.
}

if (fstat(fileno(cheatsFile), &st)){
path_free(path);
return CHEAT_LOAD_ERR_SIZE_FAILED;
}

cheatsLength = st.st_size;
if (cheatsLength <= 0) {
path_free(path);
return CHEAT_LOAD_ERR_CHEAT_EMPTY;
}
if (cheatsLength > KiB(128)) {
path_free(path);
return CHEAT_LOAD_ERR_CHEAT_TOO_LARGE;
}

char *cheatsContent = NULL;
if((cheatsContent = malloc((cheatsLength + 1) * sizeof(char))) == NULL) {
path_free(path);
return CHEAT_LOAD_ERR_MALLOC_FAILED;
}
if(fread(cheatsContent, cheatsLength, 1, cheatsFile) != 1) {
path_free(path);
return CHEAT_LOAD_ERR_READ_FAILED;
}

cheatsContent[cheatsLength] = '\0';
if(fclose(cheatsFile) != 0){
path_free(path);
return CHEAT_LOAD_ERR_CLOSE_FAILED;
}
cheatsFile = NULL;

char **tab = ft_split(cheatsContent, '\n');
size_t lines = 1;
for (size_t i = 0; tab[i] != NULL; i++) {
lines++;
}

free(cheatsContent);

uint32_t *cheats = (uint32_t*)malloc(((lines * sizeof(uint32_t)) * 2) + 2);
memset(cheats, 0, ((lines * sizeof(uint32_t)) * 2) + 2);
size_t cheatIndex = 0;
for(size_t i = 0; tab[i] != NULL; i++) {
//ignore titles
if (tab[i][0] == '#') {
continue;
}
//ignore empty, too small or too big lines
if (strlen(tab[i]) < 12 || strlen(tab[i]) > 15) {
continue;
}
char **splitCheat = ft_split(tab[i], ' ');
//thank you mena for checking my fucky wucky
uint32_t cheatValue1 = strtoul(splitCheat[0], NULL, 16);
uint32_t cheatValue2 = strtoul(splitCheat[1], NULL, 16);
cheats[cheatIndex] = cheatValue1;
cheats[cheatIndex + 1] = cheatValue2;
free_tab(splitCheat);
cheatIndex += 2;
}
free_tab(tab);

cheats[cheatIndex] = 0;
cheats[cheatIndex + 1] = 0;
menu->boot_params->cheat_list = cheats;
return CHEAT_LOAD_OK;
}
XLuma marked this conversation as resolved.
Show resolved Hide resolved
26 changes: 26 additions & 0 deletions src/menu/cheat_load.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/***
* @file cheat_load.h
* @brief Cheat loading functions
*/

#include "path.h"
#include "utils/fs.h"
#include "utils/utils.h"
#include "menu_state.h"

/** @brief Cheat code loading enum */

typedef enum {
CHEAT_LOAD_OK,
CHEAT_LOAD_ERR_NO_CHEAT_FILE,
CHEAT_LOAD_ERR_SIZE_FAILED,
CHEAT_LOAD_ERR_CHEAT_EMPTY,
CHEAT_LOAD_ERR_CHEAT_TOO_LARGE,
CHEAT_LOAD_ERR_MALLOC_FAILED,
CHEAT_LOAD_ERR_READ_FAILED,
CHEAT_LOAD_ERR_CLOSE_FAILED,
CHEAT_LOAD_ERR_UNKNOWN_ERROR
} cheat_load_err_t;

cheat_load_err_t load_cheats(menu_t *menu);
networkfusion marked this conversation as resolved.
Show resolved Hide resolved
char *cheat_load_convert_error_message (cheat_load_err_t err);
XLuma marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions src/menu/views/file_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ static const char *image_extensions[] = { "png", "jpg", "gif", NULL };
static const char *music_extensions[] = { "mp3", "wav", "ogg", "wma", "flac", NULL };
static const char *controller_pak_extensions[] = { "mpk", "pak", NULL };
static const char *emulator_extensions[] = { "nes", "smc", "gb", "gbc", "sms", "gg", "chf", NULL };
static const char *cheat_extensions[] = {"cht", NULL};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we happy with this extension name?!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows users to kinda drag-and-drop files from other sources(PJ64 for ex) with only some reformatting. Totally open to other extensions though



static struct stat st;
Expand Down Expand Up @@ -44,6 +45,9 @@ static char *format_file_type (char *name, bool is_directory) {
} else if (file_has_extensions(name, emulator_extensions)) {
return " Type: Emulator ROM file\n";
}
else if (file_has_extensions(name, cheat_extensions)) {
return " Type: Cheats\n";
}
return " Type: Unknown file\n";
}

Expand Down
10 changes: 9 additions & 1 deletion src/menu/views/load_rom.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string.h>
#include "utils/fs.h"
#include "../bookkeeping.h"
#include "../cheat_load.h"

static bool show_extra_info_message = false;
static component_boxart_t *boxart;
Expand Down Expand Up @@ -362,7 +363,14 @@ static void load (menu_t *menu) {
case ROM_TV_TYPE_MPAL: menu->boot_params->tv_type = BOOT_TV_TYPE_MPAL; break;
default: menu->boot_params->tv_type = BOOT_TV_TYPE_PASSTHROUGH; break;
}
menu->boot_params->cheat_list = NULL;
cheat_load_err_t cheat_err = load_cheats(menu);
if (cheat_err != CHEAT_LOAD_OK) {
menu_show_error(menu, cheat_load_convert_error_message(cheat_err));
return;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If cheats are not loaded, are you sure you want to return? that will stop the ROM from loading?!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to display the error, but proceed with boot after a timeout ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can also just set cheat_list to NULL if there is an error, but I wanted to provide the user with feedback in case something happened

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to think about that senario in a bit more depth then.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An idea is to parse the cheats not at game launch, but rather when a user enables cheats for their game. This way, feedback can be provided way earlier in the timeline without hindering at the game boot process

}
//TODO remove this once cheats work

//menu->boot_params->cheat_list = cheats;
}

static void deinit (void) {
Expand Down