From 3a74300a438227d85df2ffc28978b858b2372de5 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 2 Jun 2024 20:09:34 +0200 Subject: [PATCH] JsonElement.get and .put can now handle Vector attributes. fixes #430 --- saves/Development/world.dat | 12 +++++------ src/game.zig | 5 +---- src/itemdrop.zig | 20 ++++-------------- src/json.zig | 38 ++++++++++++++++++++++++++++------- src/network.zig | 14 +++---------- src/server/Entity.zig | 36 ++++++--------------------------- src/server/terrain/biomes.zig | 11 +++------- src/server/world.zig | 11 ++-------- 8 files changed, 56 insertions(+), 91 deletions(-) diff --git a/saves/Development/world.dat b/saves/Development/world.dat index 145e959d8..5f7879330 100644 --- a/saves/Development/world.dat +++ b/saves/Development/world.dat @@ -1,11 +1,11 @@ { - "spawn" : { - "x" : 3198, - "z" : 100, - "y" : 59786 - }, + "spawn" : [ + 3198, + 59786, + 100 + ], "version" : 2, "seed" : 1982878604, - "doGameTimeCycle" : false, + "doGameTimeCycle" : true, "gameTime" : 0 } \ No newline at end of file diff --git a/src/game.zig b/src/game.zig index 05dfabab1..38bcedf5f 100644 --- a/src/game.zig +++ b/src/game.zig @@ -150,10 +150,7 @@ pub const World = struct { // TODO: Consider using a per-world allocator. self.blockPalette = try assets.BlockPalette.init(main.globalAllocator, json.getChild("blockPalette")); errdefer self.blockPalette.deinit(); - const jsonSpawn = json.getChild("spawn"); - self.spawn[0] = jsonSpawn.get(f32, "x", 0); - self.spawn[1] = jsonSpawn.get(f32, "y", 0); - self.spawn[2] = jsonSpawn.get(f32, "z", 0); + self.spawn = json.get(Vec3f, "spawn", .{0, 0, 0}); try assets.loadWorldAssets("serverAssets", self.blockPalette); Player.loadFrom(json.getChild("player")); diff --git a/src/itemdrop.zig b/src/itemdrop.zig index 574794e14..8102ac230 100644 --- a/src/itemdrop.zig +++ b/src/itemdrop.zig @@ -105,16 +105,8 @@ pub const ItemDropManager = struct { return; }; const properties = .{ - Vec3d{ - json.get(f64, "x", 0), - json.get(f64, "y", 0), - json.get(f64, "z", 0), - }, - Vec3d{ - json.get(f64, "vx", 0), - json.get(f64, "vy", 0), - json.get(f64, "vz", 0), - }, + json.get(Vec3d, "pos", .{0, 0, 0}), + json.get(Vec3d, "vel", .{0, 0, 0}), items.ItemStack{.item = item, .amount = json.get(u16, "amount", 1)}, json.get(i32, "despawnTime", 60), 0 @@ -147,12 +139,8 @@ pub const ItemDropManager = struct { const obj = JsonElement.initObject(allocator); const itemDrop = self.list.get(i); obj.put("i", i); - obj.put("x", itemDrop.pos.x); - obj.put("y", itemDrop.pos.y); - obj.put("z", itemDrop.pos.z); - obj.put("vx", itemDrop.vel.x); - obj.put("vy", itemDrop.vel.y); - obj.put("vz", itemDrop.vel.z); + obj.put("pos", itemDrop.pos); + obj.put("vel", itemDrop.vel); itemDrop.itemStack.storeToJson(obj); obj.put("despawnTime", itemDrop.despawnTime); return obj; diff --git a/src/json.zig b/src/json.zig index cc1fa21e2..447e900fb 100644 --- a/src/json.zig +++ b/src/json.zig @@ -84,9 +84,9 @@ pub const JsonElement = union(JsonType) { } } - pub fn as(self: *const JsonElement, comptime _type: type, replacement: _type) _type { - comptime var typeInfo = @typeInfo(_type); - comptime var innerType = _type; + pub fn as(self: *const JsonElement, comptime T: type, replacement: T) T { + comptime var typeInfo : std.builtin.Type = @typeInfo(T); + comptime var innerType = T; inline while(typeInfo == .Optional) { innerType = typeInfo.Optional.child; typeInfo = @typeInfo(innerType); @@ -106,6 +106,21 @@ pub const JsonElement = union(JsonType) { else => return replacement, } }, + .Vector => { + const len = typeInfo.Vector.len; + const elems = self.toSlice(); + if(elems.len != len) return replacement; + var result: innerType = undefined; + if(innerType == T) result = replacement; + inline for(0..len) |i| { + if(innerType == T) { + result[i] = elems[i].as(typeInfo.Vector.child, result[i]); + } else { + result[i] = elems[i].as(?typeInfo.Vector.child, null) orelse return replacement; + } + } + return result; + }, else => { switch(innerType) { []const u8 => { @@ -122,14 +137,14 @@ pub const JsonElement = union(JsonType) { } }, else => { - @compileError("Unsupported type '" ++ @typeName(_type) ++ "'."); + @compileError("Unsupported type '" ++ @typeName(T) ++ "'."); } } }, } } - fn createElementFromRandomType(value: anytype) JsonElement { + fn createElementFromRandomType(value: anytype, allocator: std.mem.Allocator) JsonElement { switch(@typeInfo(@TypeOf(value))) { .Void => return JsonElement{.JsonNull={}}, .Null => return JsonElement{.JsonNull={}}, @@ -157,11 +172,20 @@ pub const JsonElement = union(JsonType) { }, .Optional => { if(value) |val| { - return createElementFromRandomType(val); + return createElementFromRandomType(val, allocator); } else { return JsonElement{.JsonNull={}}; } }, + .Vector => { + const len = @typeInfo(@TypeOf(value)).Vector.len; + const result = initArray(main.utils.NeverFailingAllocator{.allocator = allocator, .IAssertThatTheProvidedAllocatorCantFail = {}}); + result.JsonArray.ensureCapacity(len); + inline for(0..len) |i| { + result.JsonArray.appendAssumeCapacity(createElementFromRandomType(value[i], allocator)); + } + return result; + }, else => { if(@TypeOf(value) == JsonElement) { return value; @@ -173,7 +197,7 @@ pub const JsonElement = union(JsonType) { } pub fn put(self: *const JsonElement, key: []const u8, value: anytype) void { - const result = createElementFromRandomType(value); + const result = createElementFromRandomType(value, self.JsonObject.allocator); self.JsonObject.put(self.JsonObject.allocator.dupe(u8, key) catch unreachable, result) catch unreachable; } diff --git a/src/network.zig b/src/network.zig index 7cbeed972..b7f981ebb 100644 --- a/src/network.zig +++ b/src/network.zig @@ -676,11 +676,7 @@ pub const Protocols = struct { const jsonObject = JsonElement.initObject(main.stackAllocator); defer jsonObject.free(main.stackAllocator); jsonObject.put("player", conn.user.?.player.save(main.stackAllocator)); - const spawn = JsonElement.initObject(main.stackAllocator); - spawn.put("x", main.server.world.?.spawn[0]); - spawn.put("y", main.server.world.?.spawn[1]); - spawn.put("z", main.server.world.?.spawn[2]); - jsonObject.put("spawn", spawn); + jsonObject.put("spawn", main.server.world.?.spawn); jsonObject.put("blockPalette", main.server.world.?.blockPalette.save(main.stackAllocator)); const outData = jsonObject.toStringEfficient(main.stackAllocator, &[1]u8{stepServerData}); @@ -1107,12 +1103,8 @@ pub const Protocols = struct { pub fn itemStackDrop(conn: *Connection, stack: ItemStack, pos: Vec3d, dir: Vec3f, vel: f32) void { const jsonObject = stack.store(main.stackAllocator); defer jsonObject.free(main.stackAllocator); - jsonObject.put("x", pos[0]); - jsonObject.put("y", pos[1]); - jsonObject.put("z", pos[2]); - jsonObject.put("dirX", dir[0]); - jsonObject.put("dirY", dir[1]); - jsonObject.put("dirZ", dir[2]); + jsonObject.put("pos", pos); + jsonObject.put("dir", dir); jsonObject.put("vel", vel); const string = jsonObject.toString(main.stackAllocator); defer main.stackAllocator.free(string); diff --git a/src/server/Entity.zig b/src/server/Entity.zig index 18edbc0b9..ed0c670a7 100644 --- a/src/server/Entity.zig +++ b/src/server/Entity.zig @@ -13,40 +13,16 @@ rot: Vec3f = .{0, 0, 0}, // TODO: Health and hunger // TODO: Name -fn loadVec3f(json: JsonElement) Vec3f { - return .{ - json.get(f32, "x", 0), - json.get(f32, "y", 0), - json.get(f32, "z", 0), - }; -} - -fn loadVec3d(json: JsonElement) Vec3d { - return .{ - json.get(f64, "x", 0), - json.get(f64, "y", 0), - json.get(f64, "z", 0), - }; -} - -fn saveVec3(allocator: NeverFailingAllocator, vector: anytype) JsonElement { - const json = JsonElement.initObject(allocator); - json.put("x", vector[0]); - json.put("y", vector[1]); - json.put("z", vector[2]); - return json; -} - pub fn loadFrom(self: *@This(), json: JsonElement) void { - self.pos = loadVec3d(json.getChild("position")); - self.vel = loadVec3d(json.getChild("velocity")); - self.rot = loadVec3f(json.getChild("rotation")); + self.pos = json.get(Vec3d, "position", .{0, 0, 0}); + self.vel = json.get(Vec3d, "velocity", .{0, 0, 0}); + self.rot = json.get(Vec3f, "rotation", .{0, 0, 0}); } pub fn save(self: *@This(), allocator: NeverFailingAllocator) JsonElement { const json = JsonElement.initObject(allocator); - json.put("position", saveVec3(allocator, self.pos)); - json.put("velocity", saveVec3(allocator, self.vel)); - json.put("rotation", saveVec3(allocator, self.rot)); + json.put("position", self.pos); + json.put("velocity", self.vel); + json.put("rotation", self.rot); return json; } diff --git a/src/server/terrain/biomes.zig b/src/server/terrain/biomes.zig index e83f40a12..c202b410e 100644 --- a/src/server/terrain/biomes.zig +++ b/src/server/terrain/biomes.zig @@ -63,14 +63,9 @@ const Stripe = struct { maxWidth: f64, pub fn init(parameters: JsonElement) Stripe { - const items: []JsonElement = parameters.getChild("direction").toSlice(); - var dir: ?Vec3d = null; - if (items.len == 3) { - const dx = items[0].as(f64, 0); - const dy = items[1].as(f64, 0); - const dz = items[2].as(f64, 0); - const d: Vec3d = .{dx, dy, dz}; - dir = main.vec.normalize(d); + var dir: ?Vec3d = parameters.get(?Vec3d, "direction", null); + if(dir != null) { + dir = main.vec.normalize(dir.?); } const block: u16 = blocks.getByID(parameters.get([]const u8, "block", "")); diff --git a/src/server/world.zig b/src/server/world.zig index e647c6eb4..76afc2c2f 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -287,10 +287,7 @@ const WorldIO = struct { self.world.doGameTimeCycle = worldData.get(bool, "doGameTimeCycle", true); self.world.gameTime = worldData.get(i64, "gameTime", 0); - const spawnData = worldData.getChild("spawn"); - self.world.spawn[0] = spawnData.get(i32, "x", 0); - self.world.spawn[1] = spawnData.get(i32, "y", 0); - self.world.spawn[2] = spawnData.get(i32, "z", 0); + self.world.spawn = worldData.get(Vec3i, "spawn", .{0, 0, 0}); } pub fn saveWorldData(self: WorldIO) !void { @@ -300,11 +297,7 @@ const WorldIO = struct { worldData.put("seed", self.world.seed); worldData.put("doGameTimeCycle", self.world.doGameTimeCycle); worldData.put("gameTime", self.world.gameTime); - const spawnData = JsonElement.initObject(main.stackAllocator); - spawnData.put("x", self.world.spawn[0]); - spawnData.put("y", self.world.spawn[1]); - spawnData.put("z", self.world.spawn[2]); - worldData.put("spawn", spawnData); + worldData.put("spawn", self.world.spawn); // TODO: Save entities try self.dir.writeJson("world.dat", worldData); }