Added savestatus

This commit is contained in:
2026-08-17 00:17:23 -05:00
parent 560c51cf27
commit 08b4bbfe91
13 changed files with 502 additions and 16 deletions
+197 -5
View File
@@ -1,18 +1,23 @@
/**
* Copyright (c) 2026 Dominic Masters
*
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "save/savedevice.h"
#include "save/savedevicelinux.h"
#include "save/saveslot.h"
#include "save/savesettings.h"
#include "save/savejson.h"
#include "assert/assert.h"
#include "util/mkdirp.h"
#include "util/string.h"
#include <stdlib.h>
errorret_t saveDeviceLinuxInit(savedevice_t *device) {
assertNotNull(device, "device cannot be null");
device->state = SAVE_DEVICE_STATE_UNKNOWN;
errorOk();
@@ -31,9 +36,21 @@ void saveDeviceLinuxCheckAvailability(savedevice_t *device) {
device->state == SAVE_DEVICE_STATE_CHECKING_AVAILABILITY,
"Device state incorrect?"
);
// Resolve the save directory.
char_t directory[SAVE_DEVICE_LINUX_PATH_MAX];
errorret_t directoryResult = saveDeviceLinuxGetDirectory(
directory, sizeof(directory)
);
if(errorIsNotOk(directoryResult)) {
errorCatch(errorPrint(directoryResult));
device->state = SAVE_DEVICE_STATE_UNAVAILABLE;
device->reasonKey = "save.linux.no_home";
return saveDeviceFireCallback(device);
}
// Mkdirp the save directory.
int mkdirpResult = mkdirp(SAVE_DEVICE_LINUX_DIRECTORY, 0700);
int mkdirpResult = mkdirp(directory, 0700);
if(mkdirpResult != 0) {
device->state = SAVE_DEVICE_STATE_UNAVAILABLE;
device->reasonKey = "save.linux.mkdirp_failed";
@@ -46,6 +63,181 @@ void saveDeviceLinuxCheckAvailability(savedevice_t *device) {
saveDeviceFireCallback(device);
}
errorret_t saveDeviceLinuxGetDirectory(char_t *dest, const size_t destSize) {
assertNotNull(dest, "dest cannot be null");
const char_t *home = getenv("HOME");
if(home == NULL) errorThrow("HOME environment variable is not set");
stringFormat(dest, destSize, "%s/%s", home, SAVE_DEVICE_LINUX_DIRECTORY_NAME);
errorOk();
}
errorret_t saveDeviceLinuxGetSettingsPath(
char_t *dest,
const size_t destSize
) {
assertNotNull(dest, "dest cannot be null");
char_t directory[SAVE_DEVICE_LINUX_PATH_MAX];
errorChain(saveDeviceLinuxGetDirectory(directory, sizeof(directory)));
stringFormat(
dest, destSize, "%s/%s", directory, SAVE_DEVICE_LINUX_SETTINGS_FILENAME
);
errorOk();
}
errorret_t saveDeviceLinuxGetSlotPath(
char_t *dest,
const size_t destSize,
const uint8_t slotIndex
) {
assertNotNull(dest, "dest cannot be null");
char_t directory[SAVE_DEVICE_LINUX_PATH_MAX];
errorChain(saveDeviceLinuxGetDirectory(directory, sizeof(directory)));
char_t filename[SAVE_SLOT_NAME_LENGTH + 16];
stringFormat(
filename, sizeof(filename) - 1,
SAVE_DEVICE_LINUX_SLOT_FILENAME_FORMAT, (uint32_t)slotIndex
);
stringFormat(dest, destSize, "%s/%s", directory, filename);
errorOk();
}
errorret_t saveDeviceLinuxSlotWrite(
savedevice_t *device,
saveslot_t *slot,
uint8_t slotIndex
) {
assertNotNull(device, "device cannot be null");
assertNotNull(slot, "slot cannot be null");
char_t path[SAVE_DEVICE_LINUX_PATH_MAX];
errorChain(saveDeviceLinuxGetSlotPath(path, sizeof(path), slotIndex));
writeInit();
errorret_t writeResult = saveSlotWriteJSON(slot, doc, object);
if(errorIsNotOk(writeResult)) {
yyjson_mut_doc_free(doc);
errorChain(writeResult);
}
yyjson_write_err writeErr;
bool_t written = yyjson_mut_write_file(path, doc, 0, NULL, &writeErr);
yyjson_mut_doc_free(doc);
if(!written) {
errorThrow(
"Failed to write save slot file: %s (%s)", path, writeErr.msg
);
}
errorOk();
}
errorret_t saveDeviceLinuxSlotRead(
savedevice_t *device,
saveslot_t *slot,
uint8_t slotIndex
) {
assertNotNull(device, "device cannot be null");
assertNotNull(slot, "slot cannot be null");
char_t path[SAVE_DEVICE_LINUX_PATH_MAX];
errorChain(saveDeviceLinuxGetSlotPath(path, sizeof(path), slotIndex));
yyjson_read_err readErr;
yyjson_doc *jsonDoc = yyjson_read_file(path, 0, NULL, &readErr);
if(jsonDoc == NULL) {
// No save file at this slot yet, leave the slot as-is.
if(readErr.code == YYJSON_READ_ERROR_FILE_OPEN) errorOk();
errorThrow(
"Failed to parse save slot file: %s (%s)", path, readErr.msg
);
}
yyjson_val *object = yyjson_doc_get_root(jsonDoc);
if(object == NULL) {
yyjson_doc_free(jsonDoc);
errorThrow("Save slot file missing root object: %s", path);
}
errorret_t readResult = saveSlotReadJSON(slot, object);
yyjson_doc_free(jsonDoc);
errorChain(readResult);
errorOk();
}
errorret_t saveDeviceLinuxSettingsWrite(
savedevice_t *device,
savesettings_t *settings
) {
assertNotNull(device, "device cannot be null");
assertNotNull(settings, "settings cannot be null");
char_t path[SAVE_DEVICE_LINUX_PATH_MAX];
errorChain(saveDeviceLinuxGetSettingsPath(path, sizeof(path)));
writeInit();
errorret_t writeResult = saveSettingsWriteJSON(settings, doc, object);
if(errorIsNotOk(writeResult)) {
yyjson_mut_doc_free(doc);
errorChain(writeResult);
}
yyjson_write_err writeErr;
bool_t written = yyjson_mut_write_file(path, doc, 0, NULL, &writeErr);
yyjson_mut_doc_free(doc);
if(!written) {
errorThrow(
"Failed to write save settings file: %s (%s)", path, writeErr.msg
);
}
errorOk();
}
errorret_t saveDeviceLinuxSettingsRead(
savedevice_t *device,
savesettings_t *settings
) {
assertNotNull(device, "device cannot be null");
assertNotNull(settings, "settings cannot be null");
char_t path[SAVE_DEVICE_LINUX_PATH_MAX];
errorChain(saveDeviceLinuxGetSettingsPath(path, sizeof(path)));
yyjson_read_err readErr;
yyjson_doc *jsonDoc = yyjson_read_file(path, 0, NULL, &readErr);
if(jsonDoc == NULL) {
// No settings file yet, leave settings as-is.
if(readErr.code == YYJSON_READ_ERROR_FILE_OPEN) errorOk();
errorThrow(
"Failed to parse save settings file: %s (%s)", path, readErr.msg
);
}
yyjson_val *object = yyjson_doc_get_root(jsonDoc);
if(object == NULL) {
yyjson_doc_free(jsonDoc);
errorThrow("Save settings file missing root object: %s", path);
}
errorret_t readResult = saveSettingsReadJSON(settings, object);
yyjson_doc_free(jsonDoc);
errorChain(readResult);
errorOk();
}
errorret_t saveDeviceLinuxDispose(savedevice_t *device) {
errorOk();
}
}
+104 -8
View File
@@ -1,6 +1,6 @@
/**
* Copyright (c) 2026 Dominic Masters
*
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
@@ -8,18 +8,24 @@
#pragma once
#include "error/error.h"
#define SAVE_DEVICE_LINUX_DIRECTORY "~/.dusk/saves"
#define SAVE_DEVICE_LINUX_FILE "~/.dusk/saves/save.dat"
// Saves live under $HOME/<SAVE_DEVICE_LINUX_DIRECTORY_NAME>, one JSON file
// per save slot plus a separate settings file.
#define SAVE_DEVICE_LINUX_DIRECTORY_NAME ".dusk/saves"
#define SAVE_DEVICE_LINUX_SETTINGS_FILENAME "settings.json"
#define SAVE_DEVICE_LINUX_SLOT_FILENAME_FORMAT "slot%u.json"
#define SAVE_DEVICE_LINUX_PATH_MAX 512
typedef struct {
void *nothing;
} savedeviceplatform_t;
typedef struct savedevice_s savedevice_t;
typedef struct saveslot_s saveslot_t;
typedef struct savesettings_s savesettings_t;
/**
* Initializes the save device platform.
*
*
* @param device The save device platform to initialize.
* @return Error state if any.
*/
@@ -27,7 +33,7 @@ errorret_t saveDeviceLinuxInit(savedevice_t *device);
/**
* Updates the save device platform.
*
*
* @param device The save device platform to update.
* @return Error state if any.
*/
@@ -36,15 +42,105 @@ errorret_t saveDeviceLinuxUpdate(savedevice_t *device);
/**
* Requests the device to check its availability, this will call the callback
* whence completed.
*
*
* @param device The save device platform to check availability.
*/
void saveDeviceLinuxCheckAvailability(savedevice_t *device);
/**
* Builds the absolute path to the directory saves are stored in, creating
* intermediate directories is not done by this method, see mkdirp.
*
* @param dest The destination buffer to write the path into.
* @param destSize The size of the destination buffer, exc. null terminator.
* @return Error state if any.
*/
errorret_t saveDeviceLinuxGetDirectory(char_t *dest, const size_t destSize);
/**
* Builds the absolute path to the settings file.
*
* @param dest The destination buffer to write the path into.
* @param destSize The size of the destination buffer, exc. null terminator.
* @return Error state if any.
*/
errorret_t saveDeviceLinuxGetSettingsPath(
char_t *dest,
const size_t destSize
);
/**
* Builds the absolute path to the given save slot's file.
*
* @param dest The destination buffer to write the path into.
* @param destSize The size of the destination buffer, exc. null terminator.
* @param slotIndex The slot index to build the path for.
* @return Error state if any.
*/
errorret_t saveDeviceLinuxGetSlotPath(
char_t *dest,
const size_t destSize,
const uint8_t slotIndex
);
/**
* Writes the given save slot out to its file on disk.
*
* @param device The save device to write to.
* @param slot The save slot to write.
* @param slotIndex The slot index to write to.
* @return Error state if any.
*/
errorret_t saveDeviceLinuxSlotWrite(
savedevice_t *device,
saveslot_t *slot,
uint8_t slotIndex
);
/**
* Reads a save slot in from its file on disk. If no file exists yet for the
* given slot index, this is not an error - the slot is simply left as-is.
*
* @param device The save device to read from.
* @param slot The save slot to read into.
* @param slotIndex The slot index to read from.
* @return Error state if any.
*/
errorret_t saveDeviceLinuxSlotRead(
savedevice_t *device,
saveslot_t *slot,
uint8_t slotIndex
);
/**
* Writes the given save settings out to the settings file on disk.
*
* @param device The save device to write to.
* @param settings The save settings to write.
* @return Error state if any.
*/
errorret_t saveDeviceLinuxSettingsWrite(
savedevice_t *device,
savesettings_t *settings
);
/**
* Reads the save settings in from the settings file on disk. If no settings
* file exists yet, this is not an error - settings is simply left as-is.
*
* @param device The save device to read from.
* @param settings The save settings to read into.
* @return Error state if any.
*/
errorret_t saveDeviceLinuxSettingsRead(
savedevice_t *device,
savesettings_t *settings
);
/**
* Disposes of the save device platform.
*
*
* @param device The save device platform to dispose.
* @return Error state if any.
*/
errorret_t saveDeviceLinuxDispose(savedevice_t *device);
errorret_t saveDeviceLinuxDispose(savedevice_t *device);
+5 -1
View File
@@ -13,4 +13,8 @@
#define saveDevicePlatformInit saveDeviceLinuxInit
#define saveDevicePlatformUpdate saveDeviceLinuxUpdate
#define saveDeviceCheckAvailabilityPlatform saveDeviceLinuxCheckAvailability
#define saveDevicePlatformDispose saveDeviceLinuxDispose
#define saveDevicePlatformDispose saveDeviceLinuxDispose
#define saveDeviceSlotWritePlatform saveDeviceLinuxSlotWrite
#define saveDeviceSlotReadPlatform saveDeviceLinuxSlotRead
#define saveDeviceSettingsWritePlatform saveDeviceLinuxSettingsWrite
#define saveDeviceSettingsReadPlatform saveDeviceLinuxSettingsRead