From 3bc3fa8620501a898f32054550b957ceb605e3e4 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 27 Nov 2022 20:19:49 +0100 Subject: [PATCH] Settings loading and storing (using fancy comptime reflection). --- src/game.zig | 3 +- src/json.zig | 6 ++- src/main.zig | 5 ++- src/settings.zig | 114 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 122 insertions(+), 6 deletions(-) diff --git a/src/game.zig b/src/game.zig index b93b2b9b..978a7fe3 100644 --- a/src/game.zig +++ b/src/game.zig @@ -19,6 +19,7 @@ const Mat4f = vec.Mat4f; const graphics = @import("graphics.zig"); const Fog = graphics.Fog; const renderer = @import("renderer.zig"); +const settings = @import("settings.zig"); pub const camera = struct { pub var rotation: Vec3f = Vec3f{0, 0, 0}; @@ -99,7 +100,7 @@ pub const World = struct { // TODO: // super.itemEntityManager = new InterpolatedItemEntityManager(this); // player = new ClientPlayer(this, 0); - try network.Protocols.handShake.clientSide(self.conn, "quanturmdoelvloper"); // TODO: Read name from settings. + try network.Protocols.handShake.clientSide(self.conn, settings.playerName); } pub fn deinit(self: *World) void { diff --git a/src/json.zig b/src/json.zig index 85a9d1ab..5c4828c0 100644 --- a/src/json.zig +++ b/src/json.zig @@ -146,7 +146,6 @@ pub const JsonElement = union(JsonType) { }, .Pointer => |ptr| { if(ptr.child == u8 and ptr.size == .Slice) { - std.log.info("String: {s}", .{value}); return JsonElement{.JsonString=value}; } else { @compileError("Unknown value type."); @@ -163,6 +162,11 @@ pub const JsonElement = union(JsonType) { try self.JsonObject.put(try self.JsonObject.allocator.dupe(u8, key), result); } + pub fn putOwnedString(self: *const JsonElement, key: []const u8, value: []const u8) !void { + const result = JsonElement{.JsonStringOwned = try self.JsonObject.allocator.dupe(u8, value)}; + try self.JsonObject.put(try self.JsonObject.allocator.dupe(u8, key), result); + } + pub fn free(self: *const JsonElement, allocator: Allocator) void { switch(self.*) { JsonType.JsonInt, JsonType.JsonFloat, JsonType.JsonBool, JsonType.JsonNull, JsonType.JsonString => return, diff --git a/src/main.zig b/src/main.zig index e0105a41..0833ad19 100644 --- a/src/main.zig +++ b/src/main.zig @@ -237,6 +237,9 @@ pub fn main() !void { threadPool = try utils.ThreadPool.init(poolgpa.allocator(), 1 + ((std.Thread.getCpuCount() catch 4) -| 3)); defer threadPool.deinit(); + try settings.init(); + defer settings.deinit(); + try Window.init(); defer Window.deinit(); @@ -272,7 +275,7 @@ pub fn main() !void { var manager = try network.ConnectionManager.init(12347, true); defer manager.deinit(); - try game.world.?.init("127.0.0.1", manager); + try game.world.?.init(settings.lastUsedIPAddress, manager); defer game.world.?.deinit(); Window.setMouseGrabbed(true); diff --git a/src/settings.zig b/src/settings.zig index 5d88dae8..b2473dc4 100644 --- a/src/settings.zig +++ b/src/settings.zig @@ -1,21 +1,129 @@ +const std = @import("std"); +const json = @import("json.zig"); +const main = @import("main.zig"); pub const defaultPort: u16 = 47649; pub const connectionTimeout = 60000; pub const entityLookback: i16 = 100; -pub const version = "0.12.0"; +pub const version = "Cubyz α 0.12.0"; pub const highestLOD: u5 = 5; +pub var entityDistance: i32 = 2; -pub var fov: f32 = 45; + +pub var fov: f32 = 70; pub var mouseSensitivity: f32 = 1; +pub var fogCoefficient: f32 = 15; + pub var renderDistance: i32 = 4; pub var LODFactor: f32 = 2.0; -pub var bloom: bool = true; \ No newline at end of file +pub var bloom: bool = true; + +pub var playerName: []const u8 = "quanturmdoelvloper"; + +pub var lastUsedIPAddress: []const u8 = "localhost"; + + +pub fn init() !void { + const jsonObject = blk: { + var file = std.fs.cwd().openFile("settings.json", .{}) catch break :blk json.JsonElement{.JsonNull={}}; + defer file.close(); + const fileString = try file.readToEndAlloc(main.threadAllocator, std.math.maxInt(usize)); + defer main.threadAllocator.free(fileString); + break :blk json.parseFromString(main.threadAllocator, fileString); + }; + defer jsonObject.free(main.threadAllocator); + + inline for(@typeInfo(@This()).Struct.decls) |decl| { + const is_const = @typeInfo(@TypeOf(&@field(@This(), decl.name))).Pointer.is_const; // Sadly there is no direct way to check if a declaration is const. + if(!is_const and decl.is_pub) { + const declType = @TypeOf(@field(@This(), decl.name)); + if(@typeInfo(declType) == .Struct) { + @compileError("Not implemented yet."); + } + @field(@This(), decl.name) = jsonObject.get(declType, decl.name, @field(@This(), decl.name)); + if(@typeInfo(declType) == .Pointer) { + if(@typeInfo(declType).Pointer.size == .Slice) { + @field(@This(), decl.name) = try main.globalAllocator.dupe(@typeInfo(declType).Pointer.child, @field(@This(), decl.name)); + } else { + @compileError("Not implemented yet."); + } + } + } + } +} + +pub fn deinit() void { + const jsonObject = json.JsonElement.initObject(main.threadAllocator) catch |err| { + std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); + return; + }; + defer jsonObject.free(main.threadAllocator); + + inline for(@typeInfo(@This()).Struct.decls) |decl| { + const is_const = @typeInfo(@TypeOf(&@field(@This(), decl.name))).Pointer.is_const; // Sadly there is no direct way to check if a declaration is const. + if(!is_const and decl.is_pub) { + const declType = @TypeOf(@field(@This(), decl.name)); + if(@typeInfo(declType) == .Struct) { + @compileError("Not implemented yet."); + } + if(declType == []const u8) { + jsonObject.putOwnedString(decl.name, @field(@This(), decl.name)) catch |err| { + std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); + }; + } else { + jsonObject.put(decl.name, @field(@This(), decl.name)) catch |err| { + std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); + }; + } + if(@typeInfo(declType) == .Pointer) { + if(@typeInfo(declType).Pointer.size == .Slice) { + main.globalAllocator.free(@field(@This(), decl.name)); + } else { + @compileError("Not implemented yet."); + } + } + } + } + + const string = jsonObject.toStringEfficient(main.threadAllocator, "") catch |err| { + std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); + return; + }; + defer main.threadAllocator.free(string); + + var file = std.fs.cwd().createFile("settings.json", .{}) catch |err| { + std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); + return; + }; + defer file.close(); + + file.writeAll(string) catch |err| { + std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); + return; + }; +} + +// TODO: Check if/how these are needed: +// static Side currentSide = null; +// +// private static Language currentLanguage = null; +// +// public static int GUI_SCALE = 2; +// +// public static boolean musicOnOff = true; //Turn on or off the music +// +// /**Not actually a setting, but stored here anyways.*/ +// public static int EFFECTIVE_RENDER_DISTANCE = calculatedEffectiveRenderDistance(); +// +// public static int calculatedEffectiveRenderDistance() { +// return RENDER_DISTANCE + (((int)(RENDER_DISTANCE*LOD_FACTOR) & ~1) << Constants.HIGHEST_LOD); +// } \ No newline at end of file