Added per-game config support. Place "romName.ini" in "/3ds/open_agb_firm/saves" to change per-game settings. Currently only saveSlot is configurable.

Updated README.md.
This commit is contained in:
profi200 2021-12-21 19:40:16 +01:00
parent 247cb19cb5
commit 15cf1bffd5
No known key found for this signature in database
GPG Key ID: 17B42AE5911139F3
2 changed files with 63 additions and 31 deletions

View File

@ -62,6 +62,12 @@ Video-related settings.
`float brightness` - Screen lift
* Default: `0.0`
### Game
Game-specific settings. Only intended to be used in the per-game settings (romName.ini in `/3ds/open_agb_firm/saves`).
`u8 saveSlot` - Savegame slot (0-9)
* Default: `0`
### Advanced
Options for advanced users. No pun intended.

View File

@ -70,6 +70,9 @@ typedef struct
float contrast;
float brightness;
// [game]
u8 saveSlot;
// [advanced]
bool saveOverride;
u16 defaultSave;
@ -98,6 +101,9 @@ static OafConfig g_oafConfig =
1.f, // contrast
0.f, // brightness
// [game]
0, // saveSlot
// [advanced]
false, // saveOverride
14 // defaultSave
@ -492,7 +498,7 @@ static void gbaGfxHandler(void *args)
taskExit();
}
static int confIniHandler(void* user, const char* section, const char* name, const char* value)
static int cfgIniCallback(void* user, const char* section, const char* name, const char* value)
{
OafConfig *const config = (OafConfig*)user;
@ -516,6 +522,11 @@ static int confIniHandler(void* user, const char* section, const char* name, con
else if(strcmp(name, "brightness") == 0)
config->brightness = str2float(value);
}
else if(strcmp(section, "game") == 0)
{
if(strcmp(name, "saveSlot") == 0)
config->saveSlot = (u8)strtoul(value, NULL, 10);
}
else if(strcmp(section, "advanced") == 0)
{
if(strcmp(name, "saveOverride") == 0)
@ -528,14 +539,14 @@ static int confIniHandler(void* user, const char* section, const char* name, con
return 1; // 1 is no error? Really?
}
static Result parseConfig(const char *const path, void *config)
static Result parseOafConfig(const char *const path, const bool writeDefaultCfg)
{
char *iniBuf = (char*)calloc(INI_BUF_SIZE, 1);
if(iniBuf == NULL) return RES_OUT_OF_MEM;
Result res = fsQuickRead(path, iniBuf, INI_BUF_SIZE - 1);
if(res == RES_OK) ini_parse_string(iniBuf, confIniHandler, config);
else
if(res == RES_OK) ini_parse_string(iniBuf, cfgIniCallback, &g_oafConfig);
else if(writeDefaultCfg)
{
const char *const defaultConfig = DEFAULT_CONFIG;
res = fsQuickWrite(path, defaultConfig, strlen(defaultConfig));
@ -591,29 +602,35 @@ static Result showFileBrowser(char romAndSavePath[512])
return res;
}
static void rom2SavePath(char romPath[512], const u8 saveSlot)
static void rom2GameCfgPath(char romPath[512])
{
if(saveSlot > 9)
{
*romPath = '\0'; // Prevent using the ROM as save file.
return;
}
char tmpSaveFileName[256];
static char numberedExt[7] = {'.', 'X', '.', 's', 'a', 'v', '\0'};
numberedExt[1] = '0' + saveSlot;
// Extract the file name and change the extension.
// The numbered extension is 2 chars longer than unnumbered.
// For cfg2SavePath() we need to reserve 2 extra bytes/chars.
char tmpSaveFileName[256];
safeStrcpy(tmpSaveFileName, strrchr(romPath, '/') + 1, 256 - 2);
strcpy(tmpSaveFileName + strlen(tmpSaveFileName) - 4, (saveSlot == 0 ? ".sav" : numberedExt));
strcpy(tmpSaveFileName + strlen(tmpSaveFileName) - 4, ".ini");
// Construct the new path.
strcpy(romPath, OAF_SAVE_DIR "/");
strcat(romPath, tmpSaveFileName);
}
static void gameCfg2SavePath(char cfgPath[512], const u8 saveSlot)
{
if(saveSlot > 9)
{
*cfgPath = '\0'; // Prevent using the ROM as save file.
return;
}
static char numberedExt[7] = {'.', 'X', '.', 's', 'a', 'v', '\0'};
// Change the extension.
// This relies on rom2GameCfgPath() to reserve 2 extra bytes/chars.
numberedExt[1] = '0' + saveSlot;
strcpy(cfgPath + strlen(cfgPath) - 4, (saveSlot == 0 ? ".sav" : numberedExt));
}
Result oafParseConfigEarly(void)
{
Result res;
@ -627,7 +644,7 @@ Result oafParseConfigEarly(void)
if((res = fMkdir(OAF_SAVE_DIR)) != RES_OK && res != RES_FR_EXIST) break;
// Parse the config.
res = parseConfig("config.ini", &g_oafConfig);
res = parseOafConfig("config.ini", true);
} while(0);
return res;
@ -641,38 +658,47 @@ u8 oafGetBacklightConfig(void)
Result oafInitAndRun(void)
{
Result res;
char *const romAndSavePath = (char*)calloc(512, 1);
if(romAndSavePath != NULL)
char *const filePath = (char*)calloc(512, 1);
if(filePath != NULL)
{
do
{
if((res = fsLoadPathFromFile("autoboot.txt", romAndSavePath)) == RES_FR_NO_FILE)
// Try to load the ROM path from autoboot.txt.
// If this file doesn't exist show the file browser.
if((res = fsLoadPathFromFile("autoboot.txt", filePath)) == RES_FR_NO_FILE)
{
if((res = showFileBrowser(romAndSavePath)) != RES_OK || *romAndSavePath == '\0') break;
if((res = showFileBrowser(filePath)) != RES_OK || *filePath == '\0') break;
ee_puts("Loading...");
}
else if(res != RES_OK) break;
// Load the ROM file.
u32 romSize;
if((res = loadGbaRom(romAndSavePath, &romSize)) != RES_OK) break;
if((res = loadGbaRom(filePath, &romSize)) != RES_OK) break;
// Adjust path for the save file and get save type.
rom2SavePath(romAndSavePath, 0); // TODO: Save slot config.
// Load the per-game config.
rom2GameCfgPath(filePath);
if((res = parseOafConfig(filePath, false)) != RES_OK && res != RES_FR_NO_FILE) break;
// Adjust the path for the save file and get save type.
gameCfg2SavePath(filePath, g_oafConfig.saveSlot);
u16 saveType;
if(g_oafConfig.useGbaDb || g_oafConfig.saveOverride)
saveType = getSaveType(romSize, romAndSavePath);
saveType = getSaveType(romSize, filePath);
else
saveType = detectSaveType(romSize);
// Prepare ARM9 for GBA mode + settings and save loading.
if((res = LGY_prepareGbaMode(g_oafConfig.directBoot, saveType, romAndSavePath)) == RES_OK)
// Prepare ARM9 for GBA mode + save loading.
if((res = LGY_prepareGbaMode(g_oafConfig.directBoot, saveType, filePath)) == RES_OK)
{
#ifdef NDEBUG
// Force black and turn the backlight off on the bottom screen.
// Don't turn the backlight off on 2DS (1 panel).
GFX_setForceBlack(false, true);
// Don't turn the backlight off on 2DS.
if(MCU_getSystemModel() != 3) GFX_powerOffBacklights(GFX_BLIGHT_BOT);
#endif
// Initialize the legacy frame buffer and frame handler.
const KHandle frameReadyEvent = createEvent(false);
LGYFB_init(frameReadyEvent); // Setup Legacy Framebuffer.
createTask(0x800, 3, gbaGfxHandler, (void*)frameReadyEvent);
@ -687,7 +713,7 @@ Result oafInitAndRun(void)
}
else res = RES_OUT_OF_MEM;
free(romAndSavePath);
free(filePath);
return res;
}