mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Sort the world list in save selection by least recently used.
Also did some further refactoring to make it easier to deal with different world paths (#606) in the future. fixes #1311
This commit is contained in:
parent
ab4beca0f4
commit
8bcc00f536
@ -325,7 +325,7 @@ pub const Sync = struct { // MARK: Sync
|
||||
defer main.stackAllocator.free(dest);
|
||||
const hashedName = std.base64.url_safe.Encoder.encode(dest, user.name);
|
||||
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players/{s}.zig.zon", .{main.server.world.?.name, hashedName}) catch unreachable;
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players/{s}.zig.zon", .{main.server.world.?.path, hashedName}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
|
||||
const playerData = main.files.readToZon(main.stackAllocator, path) catch .null;
|
||||
|
@ -46,7 +46,8 @@ fn createWorld(_: usize) void {
|
||||
|
||||
fn flawedCreateWorld() !void {
|
||||
const worldName = textInput.currentString.items;
|
||||
const saveFolder = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}", .{worldName}) catch unreachable;
|
||||
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 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;
|
||||
@ -55,7 +56,7 @@ fn flawedCreateWorld() !void {
|
||||
} else |_| {}
|
||||
try main.files.makeDir(saveFolder);
|
||||
{
|
||||
const generatorSettingsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/generatorSettings.zig.zon", .{worldName}) catch unreachable;
|
||||
const generatorSettingsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/generatorSettings.zig.zon", .{worldPath}) catch unreachable;
|
||||
defer main.stackAllocator.free(generatorSettingsPath);
|
||||
const generatorSettings = main.ZonElement.initObject(main.stackAllocator);
|
||||
defer generatorSettings.deinit(main.stackAllocator);
|
||||
@ -75,7 +76,19 @@ fn flawedCreateWorld() !void {
|
||||
try main.files.writeZon(generatorSettingsPath, generatorSettings);
|
||||
}
|
||||
{
|
||||
const gamerulePath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/gamerules.zig.zon", .{worldName}) catch unreachable;
|
||||
const worldInfoPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/world.zig.zon", .{worldPath}) catch unreachable;
|
||||
defer main.stackAllocator.free(worldInfoPath);
|
||||
const worldInfo = main.ZonElement.initObject(main.stackAllocator);
|
||||
defer worldInfo.deinit(main.stackAllocator);
|
||||
|
||||
worldInfo.put("name", worldName);
|
||||
worldInfo.put("version", main.server.world_zig.worldDataVersion);
|
||||
worldInfo.put("lastUsedTime", std.time.milliTimestamp());
|
||||
|
||||
try main.files.writeZon(worldInfoPath, worldInfo);
|
||||
}
|
||||
{
|
||||
const gamerulePath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/gamerules.zig.zon", .{worldPath}) catch unreachable;
|
||||
defer main.stackAllocator.free(gamerulePath);
|
||||
const gamerules = main.ZonElement.initObject(main.stackAllocator);
|
||||
defer gamerules.deinit(main.stackAllocator);
|
||||
@ -86,7 +99,7 @@ fn flawedCreateWorld() !void {
|
||||
try main.files.writeZon(gamerulePath, gamerules);
|
||||
}
|
||||
{ // Make assets subfolder
|
||||
const assetsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/assets", .{worldName}) catch unreachable;
|
||||
const assetsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/assets", .{worldPath}) catch unreachable;
|
||||
defer main.stackAllocator.free(assetsPath);
|
||||
try main.files.makeDir(assetsPath);
|
||||
}
|
||||
|
@ -29,6 +29,13 @@ pub var needsUpdate: bool = false;
|
||||
var deleteIcon: Texture = undefined;
|
||||
var fileExplorerIcon: Texture = undefined;
|
||||
|
||||
const WorldInfo = struct {
|
||||
lastUsedTime: i64,
|
||||
name: []const u8,
|
||||
fileName: []const u8,
|
||||
};
|
||||
var worldList: main.ListUnmanaged(WorldInfo) = .{};
|
||||
|
||||
pub fn init() void {
|
||||
deleteIcon = Texture.initFromFile("assets/cubyz/ui/delete_icon.png");
|
||||
fileExplorerIcon = Texture.initFromFile("assets/cubyz/ui/file_explorer_icon.png");
|
||||
@ -70,25 +77,18 @@ pub fn openWorld(name: []const u8) void {
|
||||
gui.openHud();
|
||||
}
|
||||
|
||||
fn openWorldWrap(namePtr: usize) void { // TODO: Improve this situation. Maybe it makes sense to always use 2 arguments in the Callback.
|
||||
const nullTerminatedName: [*:0]const u8 = @ptrFromInt(namePtr);
|
||||
const name = std.mem.span(nullTerminatedName);
|
||||
openWorld(name);
|
||||
fn openWorldWrap(index: usize) void { // TODO: Improve this situation. Maybe it makes sense to always use 2 arguments in the Callback.
|
||||
openWorld(worldList.items[index].fileName);
|
||||
}
|
||||
|
||||
fn deleteWorld(namePtr: usize) void {
|
||||
const nullTerminatedName: [*:0]const u8 = @ptrFromInt(namePtr);
|
||||
const name = std.mem.span(nullTerminatedName);
|
||||
fn deleteWorld(index: usize) void {
|
||||
main.gui.closeWindow("delete_world_confirmation");
|
||||
main.gui.windowlist.delete_world_confirmation.setDeleteWorldName(name);
|
||||
main.gui.windowlist.delete_world_confirmation.setDeleteWorldName(worldList.items[index].fileName);
|
||||
main.gui.openWindow("delete_world_confirmation");
|
||||
}
|
||||
|
||||
fn openFolder(namePtr: usize) void {
|
||||
const nullTerminatedName: [*:0]const u8 = @ptrFromInt(namePtr);
|
||||
const name = std.mem.span(nullTerminatedName);
|
||||
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}", .{name}) catch unreachable;
|
||||
fn openFolder(index: usize) void {
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}", .{worldList.items[index].fileName}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
|
||||
main.files.openDirInWindow(path);
|
||||
@ -149,22 +149,41 @@ pub fn onOpen() void {
|
||||
break :readingSaves;
|
||||
}) |entry| {
|
||||
if(entry.kind == .directory) {
|
||||
const row = HorizontalList.init();
|
||||
const worldInfoPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/world.zig.zon", .{entry.name}) catch unreachable;
|
||||
defer main.stackAllocator.free(worldInfoPath);
|
||||
const worldInfo = main.files.readToZon(main.stackAllocator, worldInfoPath) catch |err| {
|
||||
std.log.err("Couldn't open save {s}: {s}", .{worldInfoPath, @errorName(err)});
|
||||
continue;
|
||||
};
|
||||
defer worldInfo.deinit(main.stackAllocator);
|
||||
|
||||
const decodedName = parseEscapedFolderName(main.stackAllocator, entry.name);
|
||||
defer main.stackAllocator.free(decodedName);
|
||||
const name = buttonNameArena.allocator().dupeZ(u8, entry.name); // Null terminate, so we can later recover the string from just the pointer.
|
||||
const buttonName = std.fmt.allocPrint(buttonNameArena.allocator().allocator, "{s}", .{decodedName}) catch unreachable;
|
||||
|
||||
row.add(Button.initText(.{0, 0}, 128, buttonName, .{.callback = &openWorldWrap, .arg = @intFromPtr(name.ptr)}));
|
||||
row.add(Button.initIcon(.{8, 0}, .{16, 16}, fileExplorerIcon, false, .{.callback = &openFolder, .arg = @intFromPtr(name.ptr)}));
|
||||
row.add(Button.initIcon(.{8, 0}, .{16, 16}, deleteIcon, false, .{.callback = &deleteWorld, .arg = @intFromPtr(name.ptr)}));
|
||||
row.finish(.{0, 0}, .center);
|
||||
list.add(row);
|
||||
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)),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std.sort.insertion(WorldInfo, worldList.items, {}, struct {
|
||||
fn lessThan(_: void, lhs: WorldInfo, rhs: WorldInfo)bool {
|
||||
return rhs.lastUsedTime -% lhs.lastUsedTime < 0;
|
||||
}
|
||||
}.lessThan);
|
||||
|
||||
for(worldList.items, 0..) |worldInfo, i| {
|
||||
const row = HorizontalList.init();
|
||||
row.add(Button.initText(.{0, 0}, 128, worldInfo.name, .{.callback = &openWorldWrap, .arg = i}));
|
||||
row.add(Button.initIcon(.{8, 0}, .{16, 16}, fileExplorerIcon, false, .{.callback = &openFolder, .arg = i}));
|
||||
row.add(Button.initIcon(.{8, 0}, .{16, 16}, deleteIcon, false, .{.callback = &deleteWorld, .arg = i}));
|
||||
row.finish(.{0, 0}, .center);
|
||||
list.add(row);
|
||||
}
|
||||
|
||||
list.finish(.center);
|
||||
window.rootComponent = list.toComponent();
|
||||
window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding));
|
||||
@ -172,6 +191,11 @@ pub fn onOpen() void {
|
||||
}
|
||||
|
||||
pub fn onClose() void {
|
||||
for(worldList.items) |worldInfo| {
|
||||
main.globalAllocator.free(worldInfo.fileName);
|
||||
main.globalAllocator.free(worldInfo.name);
|
||||
}
|
||||
worldList.clearAndFree(main.globalAllocator);
|
||||
buttonNameArena.deinit();
|
||||
if(window.rootComponent) |*comp| {
|
||||
comp.deinit();
|
||||
|
@ -667,7 +667,7 @@ pub const Protocols = struct {
|
||||
std.log.info("User {s} joined using version {s}.", .{name, version});
|
||||
|
||||
{
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/assets/", .{main.server.world.?.name}) catch unreachable;
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/assets/", .{main.server.world.?.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
var dir = try std.fs.cwd().openDir(path, .{.iterate = true});
|
||||
defer dir.close();
|
||||
|
@ -17,7 +17,8 @@ const Blueprint = main.blueprint.Blueprint;
|
||||
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
|
||||
const CircularBufferQueue = main.utils.CircularBufferQueue;
|
||||
|
||||
pub const ServerWorld = @import("world.zig").ServerWorld;
|
||||
pub const world_zig = @import("world.zig");
|
||||
pub const ServerWorld = world_zig.ServerWorld;
|
||||
pub const terrain = @import("terrain/terrain.zig");
|
||||
pub const Entity = @import("Entity.zig");
|
||||
pub const storage = @import("storage.zig");
|
||||
|
@ -215,7 +215,7 @@ fn cacheInit(pos: chunk.ChunkPosition) *RegionFile {
|
||||
return region;
|
||||
}
|
||||
hashMapMutex.unlock();
|
||||
const path: []const u8 = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/chunks", .{server.world.?.name}) catch unreachable;
|
||||
const path: []const u8 = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/chunks", .{server.world.?.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
return RegionFile.init(pos, path);
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ pub const MapFragment = struct { // MARK: MapFragment
|
||||
};
|
||||
|
||||
pub fn load(self: *MapFragment, biomePalette: *main.assets.Palette, originalHeightMap: ?*[mapSize][mapSize]i32) !NeighborInfo {
|
||||
const saveFolder: []const u8 = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/maps", .{main.server.world.?.name}) catch unreachable;
|
||||
const saveFolder: []const u8 = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/maps", .{main.server.world.?.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(saveFolder);
|
||||
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}/{}/{}/{}.surface", .{saveFolder, self.pos.voxelSize, self.pos.wx, self.pos.wy}) catch unreachable;
|
||||
@ -208,7 +208,7 @@ pub const MapFragment = struct { // MARK: MapFragment
|
||||
outputWriter.writeInt(u8, @bitCast(header.neighborInfo));
|
||||
outputWriter.writeSlice(compressedData);
|
||||
|
||||
const saveFolder: []const u8 = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/maps", .{main.server.world.?.name}) catch unreachable;
|
||||
const saveFolder: []const u8 = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/maps", .{main.server.world.?.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(saveFolder);
|
||||
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "{s}/{}/{}/{}.surface", .{saveFolder, self.pos.voxelSize, self.pos.wx, self.pos.wy}) catch unreachable;
|
||||
|
@ -355,8 +355,9 @@ const ChunkManager = struct { // MARK: ChunkManager
|
||||
}
|
||||
};
|
||||
|
||||
pub const worldDataVersion: u32 = 2;
|
||||
|
||||
const WorldIO = struct { // MARK: WorldIO
|
||||
const worldDataVersion: u32 = 2;
|
||||
|
||||
dir: files.Dir,
|
||||
world: *ServerWorld,
|
||||
@ -372,10 +373,6 @@ const WorldIO = struct { // MARK: WorldIO
|
||||
self.dir.close();
|
||||
}
|
||||
|
||||
pub fn hasWorldData(self: WorldIO) bool {
|
||||
return self.dir.hasFile("world.zig.zon");
|
||||
}
|
||||
|
||||
/// Load the seed, which is needed before custom item and ore generation.
|
||||
pub fn loadWorldSeed(self: WorldIO) !u64 {
|
||||
const worldData = try self.dir.readToZon(main.stackAllocator, "world.zig.zon");
|
||||
@ -384,7 +381,7 @@ const WorldIO = struct { // MARK: WorldIO
|
||||
std.log.err("Cannot read world file version {}. Expected version {}.", .{worldData.get(u32, "version", 0), worldDataVersion});
|
||||
return error.OldWorld;
|
||||
}
|
||||
return worldData.get(u64, "seed", 0);
|
||||
return worldData.get(?u64, "seed", null) orelse main.random.nextInt(u48, &main.seed);
|
||||
}
|
||||
|
||||
pub fn loadWorldData(self: WorldIO) !void {
|
||||
@ -395,6 +392,7 @@ const WorldIO = struct { // MARK: WorldIO
|
||||
self.world.gameTime = worldData.get(i64, "gameTime", 0);
|
||||
self.world.spawn = worldData.get(Vec3i, "spawn", .{0, 0, 0});
|
||||
self.world.biomeChecksum = worldData.get(i64, "biomeChecksum", 0);
|
||||
self.world.name = main.globalAllocator.dupe(u8, worldData.get([]const u8, "name", self.world.path));
|
||||
}
|
||||
|
||||
pub fn saveWorldData(self: WorldIO) !void {
|
||||
@ -406,6 +404,8 @@ const WorldIO = struct { // MARK: WorldIO
|
||||
worldData.put("gameTime", self.world.gameTime);
|
||||
worldData.put("spawn", self.world.spawn);
|
||||
worldData.put("biomeChecksum", self.world.biomeChecksum);
|
||||
worldData.put("name", self.world.name);
|
||||
worldData.put("lastUsedTime", std.time.milliTimestamp());
|
||||
// TODO: Save entities
|
||||
try self.dir.writeZon("world.zig.zon", worldData);
|
||||
}
|
||||
@ -420,8 +420,6 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
biomePalette: *main.assets.Palette = undefined,
|
||||
chunkManager: ChunkManager = undefined,
|
||||
|
||||
generated: bool = false,
|
||||
|
||||
gameTime: i64 = 0,
|
||||
milliTime: i64,
|
||||
lastUpdateTime: i64,
|
||||
@ -432,7 +430,8 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
allowCheats: bool = undefined,
|
||||
|
||||
seed: u64,
|
||||
name: []const u8,
|
||||
path: []const u8,
|
||||
name: []const u8 = &.{},
|
||||
spawn: Vec3i = undefined,
|
||||
|
||||
wio: WorldIO = undefined,
|
||||
@ -454,14 +453,14 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
milliTimeStamp: i64,
|
||||
};
|
||||
|
||||
pub fn init(name: []const u8, nullGeneratorSettings: ?ZonElement) !*ServerWorld { // MARK: init()
|
||||
pub fn init(path: []const u8, nullGeneratorSettings: ?ZonElement) !*ServerWorld { // MARK: init()
|
||||
covert_old_worlds: { // TODO: Remove after #480
|
||||
const worldDatPath = try std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/world.dat", .{name});
|
||||
const worldDatPath = try std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/world.dat", .{path});
|
||||
defer main.stackAllocator.free(worldDatPath);
|
||||
if(std.fs.cwd().openFile(worldDatPath, .{})) |file| {
|
||||
file.close();
|
||||
std.log.warn("Detected old world in saves/{s}. Converting all .json files to .zig.zon", .{name});
|
||||
const dirPath = try std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}", .{name});
|
||||
std.log.warn("Detected old world in saves/{s}. Converting all .json files to .zig.zon", .{path});
|
||||
const dirPath = try std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}", .{path});
|
||||
defer main.stackAllocator.free(dirPath);
|
||||
var dir = std.fs.cwd().openDir(dirPath, .{.iterate = true}) catch |err| {
|
||||
std.log.err("Could not open world directory to convert json files: {s}. Conversion aborted", .{@errorName(err)});
|
||||
@ -490,7 +489,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
.milliTime = std.time.milliTimestamp(),
|
||||
.lastUnimportantDataSent = std.time.milliTimestamp(),
|
||||
.seed = @bitCast(@as(i64, @truncate(std.time.nanoTimestamp()))),
|
||||
.name = main.globalAllocator.dupe(u8, name),
|
||||
.path = main.globalAllocator.dupe(u8, path),
|
||||
.chunkUpdateQueue = .init(main.globalAllocator, 256),
|
||||
.regionUpdateQueue = .init(main.globalAllocator, 256),
|
||||
};
|
||||
@ -505,45 +504,38 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
if(nullGeneratorSettings) |_generatorSettings| {
|
||||
generatorSettings = _generatorSettings;
|
||||
// Store generator settings:
|
||||
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/generatorSettings.zig.zon", .{name}), generatorSettings);
|
||||
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/generatorSettings.zig.zon", .{path}), generatorSettings);
|
||||
} else { // Read the generator settings:
|
||||
generatorSettings = try files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/generatorSettings.zig.zon", .{name}));
|
||||
generatorSettings = try files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/generatorSettings.zig.zon", .{path}));
|
||||
}
|
||||
self.wio = WorldIO.init(try files.openDir(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}", .{name})), self);
|
||||
self.wio = WorldIO.init(try files.openDir(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}", .{path})), self);
|
||||
errdefer self.wio.deinit();
|
||||
|
||||
const blockPaletteZon = files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/palette.zig.zon", .{name})) catch .null;
|
||||
const blockPaletteZon = files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/palette.zig.zon", .{path})) catch .null;
|
||||
self.blockPalette = try main.assets.Palette.init(main.globalAllocator, blockPaletteZon, "cubyz:air");
|
||||
errdefer self.blockPalette.deinit();
|
||||
std.log.info("Loaded save block palette with {} blocks.", .{self.blockPalette.size()});
|
||||
|
||||
const itemPaletteZon = files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/item_palette.zig.zon", .{name})) catch .null;
|
||||
const itemPaletteZon = files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/item_palette.zig.zon", .{path})) catch .null;
|
||||
self.itemPalette = try main.assets.Palette.init(main.globalAllocator, itemPaletteZon, null);
|
||||
errdefer self.itemPalette.deinit();
|
||||
std.log.info("Loaded save item palette with {} items.", .{self.itemPalette.size()});
|
||||
|
||||
const biomePaletteZon = files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/biome_palette.zig.zon", .{name})) catch .null;
|
||||
const biomePaletteZon = files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/biome_palette.zig.zon", .{path})) catch .null;
|
||||
self.biomePalette = try main.assets.Palette.init(main.globalAllocator, biomePaletteZon, null);
|
||||
errdefer self.biomePalette.deinit();
|
||||
std.log.info("Loaded save biome palette with {} biomes.", .{self.biomePalette.size()});
|
||||
|
||||
errdefer main.assets.unloadAssets();
|
||||
|
||||
if(self.wio.hasWorldData()) {
|
||||
self.seed = try self.wio.loadWorldSeed();
|
||||
self.generated = true;
|
||||
try main.assets.loadWorldAssets(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/assets/", .{name}), self.blockPalette, self.itemPalette, self.biomePalette);
|
||||
} else {
|
||||
self.seed = main.random.nextInt(u48, &main.seed);
|
||||
try main.assets.loadWorldAssets(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/assets/", .{name}), self.blockPalette, self.itemPalette, self.biomePalette);
|
||||
try self.wio.saveWorldData();
|
||||
}
|
||||
self.seed = try self.wio.loadWorldSeed();
|
||||
try main.assets.loadWorldAssets(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/assets/", .{path}), self.blockPalette, self.itemPalette, self.biomePalette);
|
||||
// Store the block palette now that everything is loaded.
|
||||
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/palette.zig.zon", .{name}), self.blockPalette.storeToZon(arenaAllocator));
|
||||
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/biome_palette.zig.zon", .{name}), self.biomePalette.storeToZon(arenaAllocator));
|
||||
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/item_palette.zig.zon", .{name}), self.itemPalette.storeToZon(arenaAllocator));
|
||||
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/palette.zig.zon", .{path}), self.blockPalette.storeToZon(arenaAllocator));
|
||||
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/biome_palette.zig.zon", .{path}), self.biomePalette.storeToZon(arenaAllocator));
|
||||
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/item_palette.zig.zon", .{path}), self.itemPalette.storeToZon(arenaAllocator));
|
||||
|
||||
var gamerules = files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/gamerules.zig.zon", .{name})) catch ZonElement.initObject(arenaAllocator);
|
||||
var gamerules = files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/gamerules.zig.zon", .{path})) catch ZonElement.initObject(arenaAllocator);
|
||||
|
||||
self.defaultGamemode = std.meta.stringToEnum(main.game.Gamemode, gamerules.get([]const u8, "default_gamemode", "creative")) orelse .creative;
|
||||
self.allowCheats = gamerules.get(bool, "cheats", true);
|
||||
@ -573,7 +565,8 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
self.itemPalette.deinit();
|
||||
self.biomePalette.deinit();
|
||||
self.wio.deinit();
|
||||
main.globalAllocator.free(self.name);
|
||||
main.globalAllocator.free(self.path);
|
||||
//main.globalAllocator.free(self.name);
|
||||
main.globalAllocator.destroy(self);
|
||||
}
|
||||
|
||||
@ -666,19 +659,19 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
fn regenerateLOD(self: *ServerWorld, newBiomeCheckSum: i64) !void {
|
||||
std.log.info("Biomes have changed. Regenerating LODs... (this might take some time)", .{});
|
||||
const hasSurfaceMaps = blk: {
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/maps", .{self.name}) catch unreachable;
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/maps", .{self.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
var dir = std.fs.cwd().openDir(path, .{}) catch break :blk false;
|
||||
defer dir.close();
|
||||
break :blk true;
|
||||
};
|
||||
if(hasSurfaceMaps) {
|
||||
try terrain.SurfaceMap.regenerateLOD(self.name);
|
||||
try terrain.SurfaceMap.regenerateLOD(self.path);
|
||||
}
|
||||
// Delete old LODs:
|
||||
for(1..main.settings.highestSupportedLod + 1) |i| {
|
||||
const lod = @as(u32, 1) << @intCast(i);
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/chunks", .{self.name}) catch unreachable;
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/chunks", .{self.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
const dir = std.fmt.allocPrint(main.stackAllocator.allocator, "{}", .{lod}) catch unreachable;
|
||||
defer main.stackAllocator.free(dir);
|
||||
@ -691,7 +684,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
// Find all the stored chunks:
|
||||
var chunkPositions = main.List(ChunkPosition).init(main.stackAllocator);
|
||||
defer chunkPositions.deinit();
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/chunks/1", .{self.name}) catch unreachable;
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/chunks/1", .{self.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
blk: {
|
||||
var dirX = std.fs.cwd().openDir(path, .{.iterate = true}) catch |err| {
|
||||
@ -754,7 +747,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
pub fn generate(self: *ServerWorld) !void {
|
||||
try self.wio.loadWorldData(); // load data here in order for entities to also be loaded.
|
||||
|
||||
if(!self.generated) {
|
||||
if(@reduce(.And, self.spawn == Vec3i{0, 0, 0})) {
|
||||
var seed: u64 = @bitCast(@as(i64, @truncate(std.time.nanoTimestamp())));
|
||||
std.log.info("Finding position..", .{});
|
||||
foundPosition: {
|
||||
@ -812,7 +805,6 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
defer map.decreaseRefCount();
|
||||
self.spawn[2] = map.getHeight(self.spawn[0], self.spawn[1]) + 1;
|
||||
}
|
||||
self.generated = true;
|
||||
const newBiomeCheckSum: i64 = @bitCast(terrain.biomes.getBiomeCheckSum(self.seed));
|
||||
if(newBiomeCheckSum != self.biomeChecksum) {
|
||||
self.regenerateLOD(newBiomeCheckSum) catch |err| {
|
||||
@ -820,7 +812,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
};
|
||||
}
|
||||
try self.wio.saveWorldData();
|
||||
const itemsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/items.zig.zon", .{self.name}) catch unreachable;
|
||||
const itemsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/items.zig.zon", .{self.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(itemsPath);
|
||||
const zon = files.readToZon(main.stackAllocator, itemsPath) catch .null;
|
||||
defer zon.deinit(main.stackAllocator);
|
||||
@ -832,7 +824,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
defer main.stackAllocator.free(dest);
|
||||
const hashedName = std.base64.url_safe.Encoder.encode(dest, user.name);
|
||||
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players/{s}.zig.zon", .{self.name, hashedName}) catch unreachable;
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players/{s}.zig.zon", .{self.path, hashedName}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
|
||||
const playerData = files.readToZon(main.stackAllocator, path) catch .null;
|
||||
@ -854,7 +846,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
defer main.stackAllocator.free(dest);
|
||||
const hashedName = std.base64.url_safe.Encoder.encode(dest, user.name);
|
||||
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players/{s}.zig.zon", .{self.name, hashedName}) catch unreachable;
|
||||
const path = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players/{s}.zig.zon", .{self.path, hashedName}) catch unreachable;
|
||||
defer main.stackAllocator.free(path);
|
||||
|
||||
var playerZon: ZonElement = files.readToZon(main.stackAllocator, path) catch .null;
|
||||
@ -882,7 +874,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
}
|
||||
}
|
||||
|
||||
const playerPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players", .{self.name}) catch unreachable;
|
||||
const playerPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/players", .{self.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(playerPath);
|
||||
|
||||
try files.makeDir(playerPath);
|
||||
@ -907,7 +899,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
|
||||
const itemDropZon = self.itemDropManager.store(main.stackAllocator);
|
||||
defer itemDropZon.deinit(main.stackAllocator);
|
||||
const itemsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/items.zig.zon", .{self.name}) catch unreachable;
|
||||
const itemsPath = std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/items.zig.zon", .{self.path}) catch unreachable;
|
||||
defer main.stackAllocator.free(itemsPath);
|
||||
try files.writeZon(itemsPath, itemDropZon);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user