Allow arbitrary and duplicate Save names.

This is done by replacing all illegal file name characters with `-`. Unicode is still preserved because it doesn't seem to be a problem for modern file systems.
The idea of file name encoding/decoding is discarded, instead the name is just stored in the zon
fixes #606
This commit is contained in:
IntegratedQuantum 2025-05-13 21:10:14 +02:00
parent 8bcc00f536
commit 73bbdcc033
2 changed files with 39 additions and 37 deletions

View File

@ -44,16 +44,48 @@ fn createWorld(_: usize) void {
};
}
fn findValidFolderName(allocator: NeverFailingAllocator, name: []const u8) []const u8 {
// Remove illegal ASCII characters:
const escapedName = main.stackAllocator.alloc(u8, name.len);
defer main.stackAllocator.free(escapedName);
for(name, 0..) |char, i| {
escapedName[i] = switch(char) {
'a'...'z',
'A'...'Z',
'0'...'9',
'_',
'-',
'.',
' ' => char,
128...255 => char,
else => '-',
};
}
// Avoid duplicates:
var resultName = main.stackAllocator.dupe(u8, escapedName);
defer main.stackAllocator.free(resultName);
var i: usize = 0;
while(true) {
const resultPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}", .{resultName}) catch unreachable;
defer main.stackAllocator.free(resultPath);
var dir = std.fs.cwd().openDir(resultPath, .{}) catch break;
dir.close();
main.stackAllocator.free(resultName);
resultName = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}_{}", .{escapedName, i}) catch unreachable;
i += 1;
}
return allocator.dupe(u8, resultName);
}
fn flawedCreateWorld() !void {
const worldName = textInput.currentString.items;
const worldPath = worldName; // TODO: Make sure that only valid file name characters are used, and add a check to allow different worlds of the same name.
const worldPath = findValidFolderName(main.stackAllocator, worldName);
defer main.stackAllocator.free(worldPath);
const saveFolder = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}", .{worldPath}) catch unreachable;
defer main.stackAllocator.free(saveFolder);
if(std.fs.cwd().openDir(saveFolder, .{})) |_dir| {
var dir = _dir;
dir.close();
return error.AlreadyExists;
} else |_| {}
try main.files.makeDir(saveFolder);
{
const generatorSettingsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/generatorSettings.zig.zon", .{worldPath}) catch unreachable;

View File

@ -94,33 +94,6 @@ fn openFolder(index: usize) void {
main.files.openDirInWindow(path);
}
fn parseEscapedFolderName(allocator: NeverFailingAllocator, name: []const u8) []const u8 {
var result = main.List(u8).init(allocator);
defer result.deinit();
var i: u32 = 0;
while(i < name.len) : (i += 1) {
if(name[i] == '_') {
var val: u21 = 0;
for(0..4) |_| {
i += 1;
if(i < name.len) {
val = val*16 + switch(name[i]) {
'0'...'9' => name[i] - '0',
'a'...'f' => name[i] - 'a' + 10,
'A'...'F' => name[i] - 'A' + 10,
else => 0,
};
}
}
var buf: [4]u8 = undefined;
result.appendSlice(buf[0 .. std.unicode.utf8Encode(val, &buf) catch 0]); // TODO: Change this to full unicode rather than using this broken utf-16 converter.
} else {
result.append(name[i]);
}
}
return result.toOwnedSlice();
}
pub fn update() void {
if(needsUpdate) {
needsUpdate = false;
@ -157,13 +130,10 @@ pub fn onOpen() void {
};
defer worldInfo.deinit(main.stackAllocator);
const decodedName = parseEscapedFolderName(main.stackAllocator, entry.name);
defer main.stackAllocator.free(decodedName);
worldList.append(main.globalAllocator, .{
.fileName = main.globalAllocator.dupe(u8, entry.name),
.lastUsedTime = worldInfo.get(i64, "lastUsedTime", 0),
.name = main.globalAllocator.dupe(u8, worldInfo.get([]const u8, "", decodedName)),
.name = main.globalAllocator.dupe(u8, worldInfo.get([]const u8, "name", entry.name)),
});
}
}