Split device settings out of the per-slot save file
Deadzone (and future prefs like locale) now live in their own settingsfile_t/settings.c, loaded eagerly at boot and saved immediately on Apply, instead of inside savefile_t - a setting shouldn't reset or diverge just because the player is on a different save slot, and this also fixes settings changes not actually reaching disk until the next full game Save. PSP settings use a new plain sceIo path rather than sceUtilitySavedata, since that dialog would flash its native icon on every settings tweak. GameCube reuses the save system's existing memory card mount rather than mounting it twice (settingsInit() now runs after saveInit()). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "input/input.h"
|
||||
#include "save/save.h"
|
||||
#include "save/settings.h"
|
||||
|
||||
// #define INPUT_PSP_GAMEPAD_BUTTON_ACCEPT INPUT_SDL2_GAMEPAD_BUTTON_CUSTOM
|
||||
// #define INPUT_PSP_GAMEPAD_BUTTON_CANCEL INPUT_SDL2_GAMEPAD_BUTTON_CUSTOM
|
||||
@@ -95,5 +95,5 @@ errorret_t inputInitPSP(void) {
|
||||
}
|
||||
|
||||
float_t inputGetDeadzoneSDL2(const inputbutton_t button) {
|
||||
return saveGet(SAVE_ACTIVE_SLOT)->deadzone;
|
||||
return settingsGet()->deadzone;
|
||||
}
|
||||
@@ -8,4 +8,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
savepsp.c
|
||||
savestreampsp.c
|
||||
settingspsp.c
|
||||
settingsstreampsp.c
|
||||
)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "save/settingspsp.h"
|
||||
#include "save/settingsstreampsp.h"
|
||||
|
||||
typedef settingspsp_t settingsplatform_t;
|
||||
typedef settingsstreampsp_t settingsplatformstream_t;
|
||||
|
||||
#define settingsInitPlatform settingsInitPSP
|
||||
#define settingsDisposePlatform settingsDisposePSP
|
||||
|
||||
#define settingsStreamOpenReadPlatform(stream) \
|
||||
settingsStreamOpenReadPSP(&(stream)->platform, &(stream)->found)
|
||||
#define settingsStreamOpenWritePlatform(stream) \
|
||||
settingsStreamOpenWritePSP(&(stream)->platform)
|
||||
#define settingsStreamClosePlatform(stream) \
|
||||
settingsStreamClosePSP(&(stream)->platform)
|
||||
#define settingsStreamReadBytesPlatform(stream, buf, len) \
|
||||
settingsStreamReadBytesPSP(&(stream)->platform, buf, len)
|
||||
#define settingsStreamWriteBytesPlatform(stream, buf, len) \
|
||||
settingsStreamWriteBytesPSP(&(stream)->platform, buf, len)
|
||||
#define settingsStreamSeekPlatform(stream, pos) \
|
||||
settingsStreamSeekPSP(&(stream)->platform, pos)
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "save/settingspsp.h"
|
||||
|
||||
errorret_t settingsInitPSP(void) {
|
||||
SceIoStat stat;
|
||||
if(sceIoGetstat(SAVE_PSP_ROOT, &stat) < 0) {
|
||||
errorThrow("No memory stick detected");
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t settingsDisposePSP(void) {
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "save/settingsfile.h"
|
||||
#include "save/savepsp.h"
|
||||
#include <pspiofilemgr.h>
|
||||
|
||||
#define SETTINGS_PSP_DIR_FORMAT "ms0:/PSP/SAVEDATA/%sCFG"
|
||||
#define SETTINGS_PSP_FILE_FORMAT SETTINGS_PSP_DIR_FORMAT "/settings.bin"
|
||||
#define SETTINGS_PSP_PATH_MAX 256
|
||||
|
||||
typedef struct {
|
||||
uint8_t reserved;
|
||||
} settingspsp_t;
|
||||
|
||||
/**
|
||||
* Initializes the settings system on PSP. Confirms the memory stick is
|
||||
* reachable (sceIoGetstat on SAVE_PSP_ROOT), same check as saveInitPSP().
|
||||
* Deliberately does not go through sceUtilitySavedata (see savepsp.h) -
|
||||
* that dialog is built for the "game save" browser/PARAM.SFO experience
|
||||
* and shows a visible native icon flash on every write, which is fine for
|
||||
* an explicit menu Save but not for a settings file that can be written
|
||||
* every time the player nudges a slider. Plain sceIo file I/O, in its own
|
||||
* directory outside the per-slot savedata folders, avoids that entirely.
|
||||
*
|
||||
* @return An error code if no memory stick is reachable.
|
||||
*/
|
||||
errorret_t settingsInitPSP(void);
|
||||
|
||||
/**
|
||||
* Disposes of the settings system on PSP.
|
||||
*
|
||||
* @return An error code if disposal fails.
|
||||
*/
|
||||
errorret_t settingsDisposePSP(void);
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "save/settingspsp.h"
|
||||
#include "save/settingsstreampsp.h"
|
||||
#include "util/string.h"
|
||||
|
||||
errorret_t settingsStreamOpenReadPSP(settingsstreampsp_t *p, bool_t *found) {
|
||||
char_t path[SETTINGS_PSP_PATH_MAX];
|
||||
stringFormat(
|
||||
path, sizeof(path), SETTINGS_PSP_FILE_FORMAT, SAVE_PSP_GAME_NAME
|
||||
);
|
||||
|
||||
p->fd = sceIoOpen(path, PSP_O_RDONLY, 0);
|
||||
*found = (p->fd >= 0);
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t settingsStreamOpenWritePSP(settingsstreampsp_t *p) {
|
||||
char_t dir[SETTINGS_PSP_PATH_MAX];
|
||||
stringFormat(dir, sizeof(dir), SETTINGS_PSP_DIR_FORMAT, SAVE_PSP_GAME_NAME);
|
||||
sceIoMkdir(dir, 0777);
|
||||
|
||||
char_t path[SETTINGS_PSP_PATH_MAX];
|
||||
stringFormat(
|
||||
path, sizeof(path), SETTINGS_PSP_FILE_FORMAT, SAVE_PSP_GAME_NAME
|
||||
);
|
||||
|
||||
p->fd = sceIoOpen(path, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_TRUNC, 0777);
|
||||
if(p->fd < 0) {
|
||||
errorThrow("Failed to open settings file for writing");
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void settingsStreamClosePSP(settingsstreampsp_t *p) {
|
||||
if(p->fd >= 0) {
|
||||
sceIoClose(p->fd);
|
||||
p->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
errorret_t settingsStreamReadBytesPSP(
|
||||
settingsstreampsp_t *p, void *buf, const size_t len
|
||||
) {
|
||||
int32_t read = sceIoRead(p->fd, buf, len);
|
||||
if(read != (int32_t)len) {
|
||||
errorThrow("Unexpected end of settings file");
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t settingsStreamWriteBytesPSP(
|
||||
settingsstreampsp_t *p, const void *buf, const size_t len
|
||||
) {
|
||||
int32_t written = sceIoWrite(p->fd, buf, len);
|
||||
if(written != (int32_t)len) {
|
||||
errorThrow("Failed to write settings data");
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t settingsStreamSeekPSP(settingsstreampsp_t *p, const size_t pos) {
|
||||
if(sceIoLseek(p->fd, (SceOff)pos, PSP_SEEK_SET) < 0) {
|
||||
errorThrow("Failed to seek in settings file");
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include <pspiofilemgr.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
SceUID fd;
|
||||
} settingsstreampsp_t;
|
||||
|
||||
/**
|
||||
* Opens the settings file for reading via plain sceIo (not the
|
||||
* sceUtilitySavedata dialog - see settingspsp.h).
|
||||
*
|
||||
* @param p Stream to initialize.
|
||||
* @param found Set to true if the file exists, false if it does not.
|
||||
* @return An error if the open fails for a reason other than missing file.
|
||||
*/
|
||||
errorret_t settingsStreamOpenReadPSP(settingsstreampsp_t *p, bool_t *found);
|
||||
|
||||
/**
|
||||
* Opens the settings file for writing, creating its directory and
|
||||
* truncating the file if needed.
|
||||
*
|
||||
* @param p Stream to initialize.
|
||||
* @return An error if the file cannot be opened for writing.
|
||||
*/
|
||||
errorret_t settingsStreamOpenWritePSP(settingsstreampsp_t *p);
|
||||
|
||||
/**
|
||||
* Closes the file descriptor held by the stream.
|
||||
*
|
||||
* @param p Stream to close.
|
||||
*/
|
||||
void settingsStreamClosePSP(settingsstreampsp_t *p);
|
||||
|
||||
/**
|
||||
* Reads len bytes from the stream into buf.
|
||||
*
|
||||
* @param p Active stream.
|
||||
* @param buf Destination buffer.
|
||||
* @param len Number of bytes to read.
|
||||
* @return An error if fewer than len bytes are available.
|
||||
*/
|
||||
errorret_t settingsStreamReadBytesPSP(
|
||||
settingsstreampsp_t *p, void *buf, const size_t len
|
||||
);
|
||||
|
||||
/**
|
||||
* Writes len bytes from buf into the stream.
|
||||
*
|
||||
* @param p Active stream.
|
||||
* @param buf Source buffer.
|
||||
* @param len Number of bytes to write.
|
||||
* @return An error if the write fails.
|
||||
*/
|
||||
errorret_t settingsStreamWriteBytesPSP(
|
||||
settingsstreampsp_t *p, const void *buf, const size_t len
|
||||
);
|
||||
|
||||
/**
|
||||
* Seeks to an absolute byte position within the stream.
|
||||
*
|
||||
* @param p Active stream.
|
||||
* @param pos Target byte offset from the start of the file.
|
||||
* @return An error if the seek fails.
|
||||
*/
|
||||
errorret_t settingsStreamSeekPSP(settingsstreampsp_t *p, const size_t pos);
|
||||
Reference in New Issue
Block a user