mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 03:06:55 -04:00
Add list palettes and item palette (#1190)
* Add list palettes and item palette * Fix block-item assignments * Remove initEmpty * Replace This() with Palette * Update src/assets.zig Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com> * Fix duplicated keys in legacy palette issue * Remove redundant errdefer * Some more figuring out order of registering * Remove assertion breaking migrations 2to1 * Apply review suggestions * Add error log for block and item ID conflict * Remove migrations file * Update src/assets.zig --------- Co-authored-by: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com>
This commit is contained in:
parent
9226d51a8f
commit
f0eb9f4f5a
218
src/assets.zig
218
src/assets.zig
@ -260,7 +260,7 @@ pub fn readAssets(
|
||||
readAllObjFilesInAddonsHashmap(externalAllocator, addons, addonNames, "models", models);
|
||||
}
|
||||
|
||||
fn registerItem(assetFolder: []const u8, id: []const u8, zon: ZonElement) !*items_zig.BaseItem {
|
||||
fn registerItem(assetFolder: []const u8, id: []const u8, zon: ZonElement) !void {
|
||||
var split = std.mem.splitScalar(u8, id, ':');
|
||||
const mod = split.first();
|
||||
var texturePath: []const u8 = &[0]u8{};
|
||||
@ -271,7 +271,7 @@ fn registerItem(assetFolder: []const u8, id: []const u8, zon: ZonElement) !*item
|
||||
texturePath = try std.fmt.bufPrint(&buf1, "{s}/{s}/items/textures/{s}", .{assetFolder, mod, texture});
|
||||
replacementTexturePath = try std.fmt.bufPrint(&buf2, "assets/{s}/items/textures/{s}", .{mod, texture});
|
||||
}
|
||||
return items_zig.register(assetFolder, texturePath, replacementTexturePath, id, zon);
|
||||
_ = items_zig.register(assetFolder, texturePath, replacementTexturePath, id, zon);
|
||||
}
|
||||
|
||||
fn registerTool(assetFolder: []const u8, id: []const u8, zon: ZonElement) void {
|
||||
@ -279,13 +279,21 @@ fn registerTool(assetFolder: []const u8, id: []const u8, zon: ZonElement) void {
|
||||
}
|
||||
|
||||
fn registerBlock(assetFolder: []const u8, id: []const u8, zon: ZonElement) !void {
|
||||
const block = blocks_zig.register(assetFolder, id, zon);
|
||||
blocks_zig.meshes.register(assetFolder, id, zon);
|
||||
if(zon == .null) std.log.err("Missing block: {s}. Replacing it with default block.", .{id});
|
||||
|
||||
if(zon.get(bool, "hasItem", true)) {
|
||||
const item = try registerItem(assetFolder, id, zon.getChild("item"));
|
||||
item.block = block;
|
||||
}
|
||||
_ = blocks_zig.register(assetFolder, id, zon);
|
||||
blocks_zig.meshes.register(assetFolder, id, zon);
|
||||
}
|
||||
|
||||
fn assignBlockItem(stringId: []const u8) !void {
|
||||
const block = blocks_zig.getTypeById(stringId);
|
||||
const item = items_zig.getByID(stringId) orelse unreachable;
|
||||
item.block = block;
|
||||
}
|
||||
|
||||
fn registerBiome(numericId: u32, stringId: []const u8, zon: ZonElement) void {
|
||||
if(zon == .null) std.log.err("Missing biome: {s}. Replacing it with default biome.", .{stringId});
|
||||
biomes_zig.register(stringId, numericId, zon);
|
||||
}
|
||||
|
||||
fn registerRecipesFromZon(zon: ZonElement) void {
|
||||
@ -294,29 +302,68 @@ fn registerRecipesFromZon(zon: ZonElement) void {
|
||||
|
||||
pub const Palette = struct { // MARK: Palette
|
||||
palette: main.List([]const u8),
|
||||
|
||||
pub fn init(allocator: NeverFailingAllocator, zon: ZonElement, firstElement: ?[]const u8) !*Palette {
|
||||
const self = switch(zon) {
|
||||
.object => try loadFromZonLegacy(allocator, zon),
|
||||
.array, .null => try loadFromZon(allocator, zon),
|
||||
else => return error.InvalidPaletteFormat,
|
||||
};
|
||||
|
||||
if(firstElement) |elem| {
|
||||
if(self.palette.items.len == 0) {
|
||||
self.palette.append(allocator.dupe(u8, elem));
|
||||
}
|
||||
if(!std.mem.eql(u8, self.palette.items[0], elem)) {
|
||||
return error.FistItemMismatch;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
fn loadFromZon(allocator: NeverFailingAllocator, zon: ZonElement) !*Palette {
|
||||
const items = zon.toSlice();
|
||||
|
||||
const self = allocator.create(Palette);
|
||||
self.* = Palette{
|
||||
.palette = .init(allocator),
|
||||
.palette = .initCapacity(allocator, items.len),
|
||||
};
|
||||
errdefer self.deinit();
|
||||
if(zon != .object or zon.object.count() == 0) {
|
||||
if(firstElement) |elem| self.palette.append(allocator.dupe(u8, elem));
|
||||
} else {
|
||||
const palette = main.stackAllocator.alloc(?[]const u8, zon.object.count());
|
||||
defer main.stackAllocator.free(palette);
|
||||
for(palette) |*val| {
|
||||
val.* = null;
|
||||
}
|
||||
var iterator = zon.object.iterator();
|
||||
while(iterator.next()) |entry| {
|
||||
palette[entry.value_ptr.as(usize, std.math.maxInt(usize))] = entry.key_ptr.*;
|
||||
}
|
||||
if(firstElement) |elem| std.debug.assert(std.mem.eql(u8, palette[0].?, elem));
|
||||
for(palette) |val| {
|
||||
std.log.info("palette[{}]: {s}", .{self.palette.items.len, val.?});
|
||||
self.palette.append(allocator.dupe(u8, val orelse return error.MissingKeyInPalette));
|
||||
|
||||
for(items) |name| {
|
||||
const stringId = name.as(?[]const u8, null) orelse return error.InvalidPaletteFormat;
|
||||
self.palette.appendAssumeCapacity(allocator.dupe(u8, stringId));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
fn loadFromZonLegacy(allocator: NeverFailingAllocator, zon: ZonElement) !*Palette {
|
||||
// Using zon.object.count() here has the implication that array can not be sparse.
|
||||
const paletteLength = zon.object.count();
|
||||
const translationPalette = main.stackAllocator.alloc(?[]const u8, paletteLength);
|
||||
defer main.stackAllocator.free(translationPalette);
|
||||
|
||||
@memset(translationPalette, null);
|
||||
|
||||
var iterator = zon.object.iterator();
|
||||
while(iterator.next()) |entry| {
|
||||
const numericId = entry.value_ptr.as(?usize, null) orelse return error.InvalidPaletteFormat;
|
||||
const name = entry.key_ptr.*;
|
||||
|
||||
if(numericId >= translationPalette.len) {
|
||||
std.log.err("ID {} ('{s}') out of range. This can be caused by palette having missing block IDs.", .{numericId, name});
|
||||
return error.SparsePaletteNotAllowed;
|
||||
}
|
||||
translationPalette[numericId] = name;
|
||||
}
|
||||
|
||||
const self = allocator.create(Palette);
|
||||
self.* = Palette{
|
||||
.palette = .initCapacity(allocator, paletteLength),
|
||||
};
|
||||
errdefer self.deinit();
|
||||
|
||||
for(translationPalette) |val| {
|
||||
self.palette.appendAssumeCapacity(allocator.dupe(u8, val orelse return error.MissingKeyInPalette));
|
||||
std.log.info("palette[{}]: {s}", .{self.palette.items.len, val.?});
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -334,11 +381,13 @@ pub const Palette = struct { // MARK: Palette
|
||||
self.palette.append(self.palette.allocator.dupe(u8, id));
|
||||
}
|
||||
|
||||
pub fn save(self: *Palette, allocator: NeverFailingAllocator) ZonElement {
|
||||
const zon = ZonElement.initObject(allocator);
|
||||
errdefer zon.free(allocator);
|
||||
for(self.palette.items, 0..) |item, i| {
|
||||
zon.put(item, i);
|
||||
pub fn storeToZon(self: *Palette, allocator: NeverFailingAllocator) ZonElement {
|
||||
const zon = ZonElement.initArray(allocator);
|
||||
|
||||
zon.array.ensureCapacity(self.palette.items.len);
|
||||
|
||||
for(self.palette.items) |item| {
|
||||
zon.append(item);
|
||||
}
|
||||
return zon;
|
||||
}
|
||||
@ -355,7 +404,7 @@ pub const Palette = struct { // MARK: Palette
|
||||
|
||||
var loadedAssets: bool = false;
|
||||
|
||||
pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, biomePalette: *Palette) !void { // MARK: loadWorldAssets()
|
||||
pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, itemPalette: *Palette, biomePalette: *Palette) !void { // MARK: loadWorldAssets()
|
||||
if(loadedAssets) return; // The assets already got loaded by the server.
|
||||
loadedAssets = true;
|
||||
|
||||
@ -402,30 +451,81 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, biomePal
|
||||
_ = main.models.registerModel(entry.key_ptr.*, entry.value_ptr.*);
|
||||
}
|
||||
|
||||
// blocks:
|
||||
blocks_zig.meshes.registerBlockBreakingAnimation(assetFolder);
|
||||
for(blockPalette.palette.items) |id| {
|
||||
const nullValue = blocks.get(id);
|
||||
var zon: ZonElement = undefined;
|
||||
if(nullValue) |value| {
|
||||
zon = value;
|
||||
} else {
|
||||
std.log.err("Missing block: {s}. Replacing it with default block.", .{id});
|
||||
zon = .null;
|
||||
}
|
||||
try registerBlock(assetFolder, id, zon);
|
||||
}
|
||||
var iterator = blocks.iterator();
|
||||
while(iterator.next()) |entry| {
|
||||
if(blocks_zig.hasRegistered(entry.key_ptr.*)) continue;
|
||||
try registerBlock(assetFolder, entry.key_ptr.*, entry.value_ptr.*);
|
||||
blockPalette.add(entry.key_ptr.*);
|
||||
|
||||
// Blocks:
|
||||
// First blocks from the palette to enforce ID values.
|
||||
for(blockPalette.palette.items) |stringId| {
|
||||
try registerBlock(assetFolder, stringId, blocks.get(stringId) orelse .null);
|
||||
}
|
||||
|
||||
// items:
|
||||
// Then all the blocks that were missing in palette but are present in the game.
|
||||
var iterator = blocks.iterator();
|
||||
while(iterator.next()) |entry| {
|
||||
const stringId = entry.key_ptr.*;
|
||||
const zon = entry.value_ptr.*;
|
||||
|
||||
if(blocks_zig.hasRegistered(stringId)) continue;
|
||||
|
||||
try registerBlock(assetFolder, stringId, zon);
|
||||
blockPalette.add(stringId);
|
||||
}
|
||||
|
||||
// Items:
|
||||
// First from the palette to enforce ID values.
|
||||
for(itemPalette.palette.items) |stringId| {
|
||||
std.debug.assert(!items_zig.hasRegistered(stringId));
|
||||
|
||||
// Some items are created automatically from blocks.
|
||||
if(blocks.get(stringId)) |zon| {
|
||||
if(!zon.get(bool, "hasItem", true)) continue;
|
||||
try registerItem(assetFolder, stringId, zon.getChild("item"));
|
||||
if(items.get(stringId) != null) {
|
||||
std.log.err("Item {s} appears as standalone item and as block item.", .{stringId});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Items not related to blocks should appear in items hash map.
|
||||
if(items.get(stringId)) |zon| {
|
||||
try registerItem(assetFolder, stringId, zon);
|
||||
continue;
|
||||
}
|
||||
std.log.err("Missing item: {s}. Replacing it with default item.", .{stringId});
|
||||
try registerItem(assetFolder, stringId, .null);
|
||||
}
|
||||
|
||||
// Then missing block-items to keep backwards compatibility of ID order.
|
||||
for(blockPalette.palette.items) |stringId| {
|
||||
const zon = blocks.get(stringId) orelse .null;
|
||||
|
||||
if(!zon.get(bool, "hasItem", true)) continue;
|
||||
if(items_zig.hasRegistered(stringId)) continue;
|
||||
|
||||
try registerItem(assetFolder, stringId, zon.getChild("item"));
|
||||
itemPalette.add(stringId);
|
||||
}
|
||||
|
||||
// And finally normal items.
|
||||
iterator = items.iterator();
|
||||
while(iterator.next()) |entry| {
|
||||
_ = try registerItem(assetFolder, entry.key_ptr.*, entry.value_ptr.*);
|
||||
const stringId = entry.key_ptr.*;
|
||||
const zon = entry.value_ptr.*;
|
||||
|
||||
if(items_zig.hasRegistered(stringId)) continue;
|
||||
std.debug.assert(zon != .null);
|
||||
|
||||
try registerItem(assetFolder, stringId, zon);
|
||||
itemPalette.add(stringId);
|
||||
}
|
||||
|
||||
// After we have registered all items and all blocks, we can assign block references to those that come from blocks.
|
||||
for(blockPalette.palette.items) |stringId| {
|
||||
const zon = blocks.get(stringId) orelse .null;
|
||||
|
||||
if(!zon.get(bool, "hasItem", true)) continue;
|
||||
std.debug.assert(items_zig.hasRegistered(stringId));
|
||||
|
||||
try assignBlockItem(stringId);
|
||||
}
|
||||
|
||||
// tools:
|
||||
@ -443,25 +543,17 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, biomePal
|
||||
}
|
||||
|
||||
// Biomes:
|
||||
var i: u32 = 0;
|
||||
var nextBiomeNumericId: u32 = 0;
|
||||
for(biomePalette.palette.items) |id| {
|
||||
const nullValue = biomes.get(id);
|
||||
var zon: ZonElement = undefined;
|
||||
if(nullValue) |value| {
|
||||
zon = value;
|
||||
} else {
|
||||
std.log.err("Missing biomes: {s}. Replacing it with default biomes.", .{id});
|
||||
zon = .null;
|
||||
}
|
||||
biomes_zig.register(id, i, zon);
|
||||
i += 1;
|
||||
registerBiome(nextBiomeNumericId, id, biomes.get(id) orelse .null);
|
||||
nextBiomeNumericId += 1;
|
||||
}
|
||||
iterator = biomes.iterator();
|
||||
while(iterator.next()) |entry| {
|
||||
if(biomes_zig.hasRegistered(entry.key_ptr.*)) continue;
|
||||
biomes_zig.register(entry.key_ptr.*, i, entry.value_ptr.*);
|
||||
registerBiome(nextBiomeNumericId, entry.key_ptr.*, entry.value_ptr.*);
|
||||
biomePalette.add(entry.key_ptr.*);
|
||||
i += 1;
|
||||
nextBiomeNumericId += 1;
|
||||
}
|
||||
biomes_zig.finishLoading();
|
||||
|
||||
|
@ -645,6 +645,7 @@ pub const World = struct { // MARK: World
|
||||
spawn: Vec3f = undefined,
|
||||
connected: bool = true,
|
||||
blockPalette: *assets.Palette = undefined,
|
||||
itemPalette: *assets.Palette = undefined,
|
||||
biomePalette: *assets.Palette = undefined,
|
||||
itemDrops: ClientItemDropManager = undefined,
|
||||
playerBiome: Atomic(*const main.server.terrain.biomes.Biome) = undefined,
|
||||
@ -682,6 +683,7 @@ pub const World = struct { // MARK: World
|
||||
main.threadPool.clear();
|
||||
self.itemDrops.deinit();
|
||||
self.blockPalette.deinit();
|
||||
self.itemPalette.deinit();
|
||||
self.biomePalette.deinit();
|
||||
self.manager.deinit();
|
||||
main.server.stop();
|
||||
@ -701,9 +703,11 @@ pub const World = struct { // MARK: World
|
||||
errdefer self.blockPalette.deinit();
|
||||
self.biomePalette = try assets.Palette.init(main.globalAllocator, zon.getChild("biomePalette"), null);
|
||||
errdefer self.biomePalette.deinit();
|
||||
self.itemPalette = try assets.Palette.init(main.globalAllocator, zon.getChild("itemPalette"), null);
|
||||
errdefer self.itemPalette.deinit();
|
||||
self.spawn = zon.get(Vec3f, "spawn", .{0, 0, 0});
|
||||
|
||||
try assets.loadWorldAssets("serverAssets", self.blockPalette, self.biomePalette);
|
||||
try assets.loadWorldAssets("serverAssets", self.blockPalette, self.itemPalette, 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"));
|
||||
|
@ -756,6 +756,10 @@ pub var itemListSize: u16 = 0;
|
||||
|
||||
var recipeList: main.List(Recipe) = undefined;
|
||||
|
||||
pub fn hasRegistered(id: []const u8) bool {
|
||||
return reverseIndices.contains(id);
|
||||
}
|
||||
|
||||
pub fn toolTypeIterator() std.StringHashMap(ToolType).ValueIterator {
|
||||
return toolTypes.valueIterator();
|
||||
}
|
||||
|
@ -682,8 +682,9 @@ pub const Protocols = struct {
|
||||
zonObject.put("player", conn.user.?.player.save(main.stackAllocator));
|
||||
zonObject.put("player_id", conn.user.?.id);
|
||||
zonObject.put("spawn", main.server.world.?.spawn);
|
||||
zonObject.put("blockPalette", main.server.world.?.blockPalette.save(main.stackAllocator));
|
||||
zonObject.put("biomePalette", main.server.world.?.biomePalette.save(main.stackAllocator));
|
||||
zonObject.put("blockPalette", main.server.world.?.blockPalette.storeToZon(main.stackAllocator));
|
||||
zonObject.put("itemPalette", main.server.world.?.itemPalette.storeToZon(main.stackAllocator));
|
||||
zonObject.put("biomePalette", main.server.world.?.biomePalette.storeToZon(main.stackAllocator));
|
||||
|
||||
const outData = zonObject.toStringEfficient(main.stackAllocator, &[1]u8{stepServerData});
|
||||
defer main.stackAllocator.free(outData);
|
||||
|
@ -20,6 +20,7 @@ const terrain = server.terrain;
|
||||
const server = @import("server.zig");
|
||||
const User = server.User;
|
||||
const Entity = server.Entity;
|
||||
const Palette = main.assets.Palette;
|
||||
|
||||
const storage = @import("storage.zig");
|
||||
|
||||
@ -415,6 +416,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
|
||||
itemDropManager: ItemDropManager = undefined,
|
||||
blockPalette: *main.assets.Palette = undefined,
|
||||
itemPalette: *main.assets.Palette = undefined,
|
||||
biomePalette: *main.assets.Palette = undefined,
|
||||
chunkManager: ChunkManager = undefined,
|
||||
|
||||
@ -510,35 +512,37 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
}
|
||||
self.wio = WorldIO.init(try files.openDir(try std.fmt.bufPrint(&buf, "saves/{s}", .{name})), self);
|
||||
errdefer self.wio.deinit();
|
||||
|
||||
const blockPaletteZon = files.readToZon(arenaAllocator, try std.fmt.bufPrint(&buf, "saves/{s}/palette.zig.zon", .{name})) 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()},
|
||||
);
|
||||
std.log.info("Loaded save block palette with {} blocks.", .{self.blockPalette.size()});
|
||||
|
||||
const itemPaletteZon = files.readToZon(arenaAllocator, try std.fmt.bufPrint(&buf, "saves/{s}/item_palette.zig.zon", .{name})) 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.bufPrint(&buf, "saves/{s}/biome_palette.zig.zon", .{name})) 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()},
|
||||
);
|
||||
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.bufPrint(&buf, "saves/{s}/assets/", .{name}), self.blockPalette, self.biomePalette);
|
||||
try main.assets.loadWorldAssets(try std.fmt.bufPrint(&buf, "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.bufPrint(&buf, "saves/{s}/assets/", .{name}), self.blockPalette, self.biomePalette);
|
||||
try main.assets.loadWorldAssets(try std.fmt.bufPrint(&buf, "saves/{s}/assets/", .{name}), self.blockPalette, self.itemPalette, self.biomePalette);
|
||||
try self.wio.saveWorldData();
|
||||
}
|
||||
// Store the block palette now that everything is loaded.
|
||||
try files.writeZon(try std.fmt.bufPrint(&buf, "saves/{s}/palette.zig.zon", .{name}), self.blockPalette.save(arenaAllocator));
|
||||
try files.writeZon(try std.fmt.bufPrint(&buf, "saves/{s}/biome_palette.zig.zon", .{name}), self.biomePalette.save(arenaAllocator));
|
||||
try files.writeZon(try std.fmt.bufPrint(&buf, "saves/{s}/palette.zig.zon", .{name}), self.blockPalette.storeToZon(arenaAllocator));
|
||||
try files.writeZon(try std.fmt.bufPrint(&buf, "saves/{s}/biome_palette.zig.zon", .{name}), self.biomePalette.storeToZon(arenaAllocator));
|
||||
try files.writeZon(try std.fmt.bufPrint(&buf, "saves/{s}/item_palette.zig.zon", .{name}), self.itemPalette.storeToZon(arenaAllocator));
|
||||
|
||||
var gamerules = files.readToZon(arenaAllocator, try std.fmt.bufPrint(&buf, "saves/{s}/gamerules.zig.zon", .{name})) catch ZonElement.initObject(arenaAllocator);
|
||||
|
||||
@ -567,6 +571,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld
|
||||
self.chunkManager.deinit();
|
||||
self.itemDropManager.deinit();
|
||||
self.blockPalette.deinit();
|
||||
self.itemPalette.deinit();
|
||||
self.biomePalette.deinit();
|
||||
self.wio.deinit();
|
||||
main.globalAllocator.free(self.name);
|
||||
|
@ -250,6 +250,10 @@ pub const ZonElement = union(enum) { // MARK: Zon
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append(self: *const ZonElement, value: anytype) void {
|
||||
self.array.append(createElementFromRandomType(value, self.array.allocator.allocator));
|
||||
}
|
||||
|
||||
pub fn put(self: *const ZonElement, key: []const u8, value: anytype) void {
|
||||
const result = createElementFromRandomType(value, self.object.allocator);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user