Add tool palette (#1494)

## Description

This pull request adds a tool palette to allow using stable indexes for
binary storage.

## Links

Related to: #1290 
Related to: #1478
Related to: #1473
This commit is contained in:
Krzysztof Wiśniewski 2025-05-23 19:06:24 +02:00 committed by GitHub
parent 5a3a125730
commit c13d9415d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 40 additions and 14 deletions

View File

@ -473,7 +473,7 @@ pub const Palette = struct { // MARK: Palette
var loadedAssets: bool = false;
pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, itemPalette: *Palette, biomePalette: *Palette) !void { // MARK: loadWorldAssets()
pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, itemPalette: *Palette, toolPalette: *Palette, biomePalette: *Palette) !void { // MARK: loadWorldAssets()
if(loadedAssets) return; // The assets already got loaded by the server.
loadedAssets = true;
@ -575,10 +575,17 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, itemPale
try assignBlockItem(stringId);
}
for(toolPalette.palette.items) |id| {
registerTool(assetFolder, id, worldAssets.tools.get(id) orelse .null);
}
// tools:
iterator = worldAssets.tools.iterator();
while(iterator.next()) |entry| {
registerTool(assetFolder, entry.key_ptr.*, entry.value_ptr.*);
const id = entry.key_ptr.*;
if(items_zig.hasRegisteredTool(id)) continue;
registerTool(assetFolder, id, entry.value_ptr.*);
toolPalette.add(id);
}
// block drops:

View File

@ -655,6 +655,7 @@ pub const World = struct { // MARK: World
connected: bool = true,
blockPalette: *assets.Palette = undefined,
itemPalette: *assets.Palette = undefined,
toolPalette: *assets.Palette = undefined,
biomePalette: *assets.Palette = undefined,
itemDrops: ClientItemDropManager = undefined,
playerBiome: Atomic(*const main.server.terrain.biomes.Biome) = undefined,
@ -692,6 +693,7 @@ pub const World = struct { // MARK: World
self.itemDrops.deinit();
self.blockPalette.deinit();
self.itemPalette.deinit();
self.toolPalette.deinit();
self.biomePalette.deinit();
self.manager.deinit();
main.server.stop();
@ -713,9 +715,11 @@ pub const World = struct { // MARK: World
errdefer self.biomePalette.deinit();
self.itemPalette = try assets.Palette.init(main.globalAllocator, zon.getChild("itemPalette"), null);
errdefer self.itemPalette.deinit();
self.toolPalette = try assets.Palette.init(main.globalAllocator, zon.getChild("toolPalette"), null);
errdefer self.toolPalette.deinit();
self.spawn = zon.get(Vec3f, "spawn", .{0, 0, 0});
try assets.loadWorldAssets("serverAssets", self.blockPalette, self.itemPalette, self.biomePalette);
try assets.loadWorldAssets("serverAssets", self.blockPalette, self.itemPalette, self.toolPalette, self.biomePalette);
Player.id = zon.get(u32, "player_id", std.math.maxInt(u32));
Player.inventory = Inventory.init(main.globalAllocator, 32, .normal, .{.playerInventory = Player.id});
Player.loadFrom(zon.getChild("player"));

View File

@ -828,6 +828,10 @@ pub fn hasRegistered(id: []const u8) bool {
return reverseIndices.contains(id);
}
pub fn hasRegisteredTool(id: []const u8) bool {
return toolTypes.contains(id);
}
pub fn toolTypeIterator() std.StringHashMap(ToolType).ValueIterator {
return toolTypes.valueIterator();
}

View File

@ -686,6 +686,7 @@ pub const Protocols = struct {
zonObject.put("spawn", main.server.world.?.spawn);
zonObject.put("blockPalette", main.server.world.?.blockPalette.storeToZon(main.stackAllocator));
zonObject.put("itemPalette", main.server.world.?.itemPalette.storeToZon(main.stackAllocator));
zonObject.put("toolPalette", main.server.world.?.toolPalette.storeToZon(main.stackAllocator));
zonObject.put("biomePalette", main.server.world.?.biomePalette.storeToZon(main.stackAllocator));
const outData = zonObject.toStringEfficient(main.stackAllocator, &[1]u8{stepServerData});

View File

@ -16,6 +16,7 @@ const Vec3i = vec.Vec3i;
const Vec3d = vec.Vec3d;
const Vec3f = vec.Vec3f;
const terrain = server.terrain;
const NeverFailingAllocator = main.heap.NeverFailingAllocator;
const server = @import("server.zig");
const User = server.User;
@ -419,6 +420,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
itemDropManager: ItemDropManager = undefined,
blockPalette: *main.assets.Palette = undefined,
itemPalette: *main.assets.Palette = undefined,
toolPalette: *main.assets.Palette = undefined,
biomePalette: *main.assets.Palette = undefined,
chunkManager: ChunkManager = undefined,
@ -515,29 +517,27 @@ pub const ServerWorld = struct { // MARK: ServerWorld
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", .{path})) catch .null;
self.blockPalette = try main.assets.Palette.init(main.globalAllocator, blockPaletteZon, "cubyz:air");
self.blockPalette = try loadPalette(arenaAllocator, path, "palette", "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", .{path})) catch .null;
self.itemPalette = try main.assets.Palette.init(main.globalAllocator, itemPaletteZon, null);
self.itemPalette = try loadPalette(arenaAllocator, path, "item_palette", 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", .{path})) catch .null;
self.biomePalette = try main.assets.Palette.init(main.globalAllocator, biomePaletteZon, null);
self.toolPalette = try loadPalette(arenaAllocator, path, "tool_palette", null);
errdefer self.toolPalette.deinit();
self.biomePalette = try loadPalette(arenaAllocator, path, "biome_palette", null);
errdefer self.biomePalette.deinit();
std.log.info("Loaded save biome palette with {} biomes.", .{self.biomePalette.size()});
errdefer main.assets.unloadAssets();
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);
try main.assets.loadWorldAssets(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/assets/", .{path}), self.blockPalette, self.itemPalette, self.toolPalette, 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", .{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));
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/tool_palette.zig.zon", .{path}), self.toolPalette.storeToZon(arenaAllocator));
try files.writeZon(try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/biome_palette.zig.zon", .{path}), self.biomePalette.storeToZon(arenaAllocator));
var gamerules = files.readToZon(arenaAllocator, try std.fmt.allocPrint(arenaAllocator.allocator, "saves/{s}/gamerules.zig.zon", .{path})) catch ZonElement.initObject(arenaAllocator);
@ -549,6 +549,15 @@ pub const ServerWorld = struct { // MARK: ServerWorld
return self;
}
pub fn loadPalette(allocator: NeverFailingAllocator, worldName: []const u8, paletteName: []const u8, firstEntry: ?[]const u8) !*Palette {
const path = try std.fmt.allocPrint(main.stackAllocator.allocator, "saves/{s}/{s}.zig.zon", .{worldName, paletteName});
defer main.stackAllocator.allocator.free(path);
const paletteZon = files.readToZon(allocator, path) catch .null;
const palette = try main.assets.Palette.init(main.globalAllocator, paletteZon, firstEntry);
std.log.info("Loaded {s} with {} entries.", .{paletteName, palette.size()});
return palette;
}
pub fn deinit(self: *ServerWorld) void {
self.forceSave() catch |err| {
std.log.err("Error while saving the world: {s}", .{@errorName(err)});
@ -567,6 +576,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
self.itemDropManager.deinit();
self.blockPalette.deinit();
self.itemPalette.deinit();
self.toolPalette.deinit();
self.biomePalette.deinit();
self.wio.deinit();
main.globalAllocator.free(self.path);