Added savestatus
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user