diff --git a/.gitignore b/.gitignore index a849fe3f..d0626df8 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ saves/ zig-out/ zig-cache/ serverAssets/ -settings.json \ No newline at end of file +settings.json +gui_layout.json \ No newline at end of file diff --git a/src/gui/GuiWindow.zig b/src/gui/GuiWindow.zig index f79c9eac..73f296c0 100644 --- a/src/gui/GuiWindow.zig +++ b/src/gui/GuiWindow.zig @@ -16,10 +16,10 @@ const GuiComponent = gui.GuiComponent; const GuiWindow = @This(); -const AttachmentPoint = enum { - lower, - middle, - upper, +pub const AttachmentPoint = enum(u8) { + lower = 0, + middle = 1, + upper = 2, }; const OrientationLine = struct { diff --git a/src/gui/gui.zig b/src/gui/gui.zig index b0c973f1..0703a632 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator; const main = @import("root"); const graphics = main.graphics; const draw = graphics.draw; +const JsonElement = main.JsonElement; const settings = main.settings; const vec = main.vec; const Vec2f = vec.Vec2f; @@ -42,9 +43,13 @@ pub fn init(_allocator: Allocator) !void { try ScrollBar.__init(); try Slider.__init(); try TextInput.__init(); + try load(); } pub fn deinit() void { + save() catch |err| { + std.log.err("Got error while saving gui layout: {s}", .{@errorName(err)}); + }; windowList.deinit(); hudWindows.deinit(); for(openWindows.items) |window| { @@ -59,6 +64,103 @@ pub fn deinit() void { TextInput.__deinit(); } +fn save() !void { + const guiJson = try JsonElement.initObject(main.threadAllocator); + defer guiJson.free(main.threadAllocator); + for(windowList.items) |window| { + const windowJson = try JsonElement.initObject(main.threadAllocator); + for(window.relativePosition, 0..) |relPos, i| { + const relPosJson = try JsonElement.initObject(main.threadAllocator); + switch(relPos) { + .ratio => |ratio| { + try relPosJson.put("type", "ratio"); + try relPosJson.put("ratio", ratio); + }, + .attachedToFrame => |attachedToFrame| { + try relPosJson.put("type", "attachedToFrame"); + try relPosJson.put("selfAttachmentPoint", @enumToInt(attachedToFrame.selfAttachmentPoint)); + try relPosJson.put("otherAttachmentPoint", @enumToInt(attachedToFrame.otherAttachmentPoint)); + }, + .relativeToWindow => |relativeToWindow| { + try relPosJson.put("type", "relativeToWindow"); + try relPosJson.put("reference", relativeToWindow.reference.id); + try relPosJson.put("ratio", relativeToWindow.ratio); + }, + .attachedToWindow => |attachedToWindow| { + try relPosJson.put("type", "attachedToWindow"); + try relPosJson.put("reference", attachedToWindow.reference.id); + try relPosJson.put("selfAttachmentPoint", @enumToInt(attachedToWindow.selfAttachmentPoint)); + try relPosJson.put("otherAttachmentPoint", @enumToInt(attachedToWindow.otherAttachmentPoint)); + }, + } + try windowJson.put(([_][]const u8{"relPos0", "relPos1"})[i], relPosJson); + } + try windowJson.put("scale", window.scale); + try guiJson.put(window.id, windowJson); + } + + const string = try guiJson.toStringEfficient(main.threadAllocator, ""); + defer main.threadAllocator.free(string); + + var file = try std.fs.cwd().createFile("gui_layout.json", .{}); + defer file.close(); + + try file.writeAll(string); +} + +fn load() !void { + const json: JsonElement = blk: { + var file = std.fs.cwd().openFile("gui_layout.json", .{}) catch break :blk JsonElement{.JsonNull={}}; + defer file.close(); + const fileString = try file.readToEndAlloc(main.threadAllocator, std.math.maxInt(usize)); + defer main.threadAllocator.free(fileString); + break :blk JsonElement.parseFromString(main.threadAllocator, fileString); + }; + defer json.free(main.threadAllocator); + + for(windowList.items) |window| { + const windowJson = json.getChild(window.id); + for(&window.relativePosition, 0..) |*relPos, i| { + const relPosJson = windowJson.getChild(([_][]const u8{"relPos0", "relPos1"})[i]); + const typ = relPosJson.get([]const u8, "type", "ratio"); + if(std.mem.eql(u8, typ, "ratio")) { + relPos.* = .{.ratio = relPosJson.get(f32, "ratio", 0.5)}; + } else if(std.mem.eql(u8, typ, "attachedToFrame")) { + relPos.* = .{.attachedToFrame = .{ + .selfAttachmentPoint = @intToEnum(GuiWindow.AttachmentPoint, relPosJson.get(u8, "selfAttachmentPoint", 0)), + .otherAttachmentPoint = @intToEnum(GuiWindow.AttachmentPoint, relPosJson.get(u8, "otherAttachmentPoint", 0)), + }}; + } else if(std.mem.eql(u8, typ, "relativeToWindow")) { + const reference = getWindowById(relPosJson.get([]const u8, "reference", "")) orelse continue; + relPos.* = .{.relativeToWindow = .{ + .reference = reference, + .ratio = relPosJson.get(f32, "ratio", 0.5), + }}; + } else if(std.mem.eql(u8, typ, "attachedToWindow")) { + const reference = getWindowById(relPosJson.get([]const u8, "reference", "")) orelse continue; + relPos.* = .{.attachedToWindow = .{ + .reference = reference, + .selfAttachmentPoint = @intToEnum(GuiWindow.AttachmentPoint, relPosJson.get(u8, "selfAttachmentPoint", 0)), + .otherAttachmentPoint = @intToEnum(GuiWindow.AttachmentPoint, relPosJson.get(u8, "otherAttachmentPoint", 0)), + }}; + } else { + std.log.warn("Unknown window attachment type: {s}", .{typ}); + } + } + window.scale = windowJson.get(f32, "scale", 1); + } +} + +fn getWindowById(id: []const u8) ?*GuiWindow { + for(windowList.items) |window| { + if(std.mem.eql(u8, id, window.id)) { + return window; + } + } + std.log.warn("Could not find window with id: {s}", .{id}); + return null; +} + pub fn updateGuiScale() void { if(settings.guiScale) |guiScale| { scale = guiScale; diff --git a/src/json.zig b/src/json.zig index 9401d7fe..7054f62e 100644 --- a/src/json.zig +++ b/src/json.zig @@ -37,7 +37,7 @@ pub const JsonElement = union(JsonType) { return JsonElement{.JsonArray=list}; } - pub fn getAtIndex(self: *const JsonElement, comptime _type: type, index: usize, replacement: _type) @TypeOf(replacement) { + pub fn getAtIndex(self: *const JsonElement, comptime _type: type, index: usize, replacement: _type) _type { if(self.* != .JsonArray) { return replacement; } else { @@ -61,7 +61,7 @@ pub const JsonElement = union(JsonType) { } } - pub fn get(self: *const JsonElement, comptime _type: type, key: []const u8, replacement: _type) @TypeOf(replacement) { + pub fn get(self: *const JsonElement, comptime _type: type, key: []const u8, replacement: _type) _type { if(self.* != .JsonObject) { return replacement; } else { @@ -148,7 +148,12 @@ pub const JsonElement = union(JsonType) { if(ptr.child == u8 and ptr.size == .Slice) { return JsonElement{.JsonString=value}; } else { - @compileError("Unknown value type."); + const childInfo = @typeInfo(ptr.child); + if(ptr.size == .One and childInfo == .Array and childInfo.Array.child == u8) { + return JsonElement{.JsonString=value}; + } else { + @compileError("Unknown value type."); + } } }, .Optional => { diff --git a/src/main.zig b/src/main.zig index 56a960f6..bb433011 100644 --- a/src/main.zig +++ b/src/main.zig @@ -10,7 +10,7 @@ pub const game = @import("game.zig"); pub const graphics = @import("graphics.zig"); pub const itemdrop = @import("itemdrop.zig"); pub const items = @import("items.zig"); -pub const JsonElement = @import("json.zig"); +pub const JsonElement = @import("json.zig").JsonElement; pub const models = @import("models.zig"); pub const network = @import("network.zig"); pub const random = @import("random.zig"); diff --git a/src/settings.zig b/src/settings.zig index 3ffc8314..9c21a7a5 100644 --- a/src/settings.zig +++ b/src/settings.zig @@ -75,11 +75,8 @@ pub fn init() !void { } } -pub fn deinit() void { - const jsonObject = JsonElement.initObject(main.threadAllocator) catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - return; - }; +fn flawedDeinit() !void { + const jsonObject = try JsonElement.initObject(main.threadAllocator); defer jsonObject.free(main.threadAllocator); inline for(@typeInfo(@This()).Struct.decls) |decl| { @@ -90,13 +87,9 @@ pub fn deinit() void { @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)}); - }; + try jsonObject.putOwnedString(decl.name, @field(@This(), decl.name)); } else { - jsonObject.put(decl.name, @field(@This(), decl.name)) catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - }; + try jsonObject.put(decl.name, @field(@This(), decl.name)); } if(@typeInfo(declType) == .Pointer) { if(@typeInfo(declType).Pointer.size == .Slice) { @@ -109,48 +102,30 @@ pub fn deinit() void { } // keyboard settings: - const keyboard = JsonElement.initObject(main.threadAllocator) catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - return; - }; + const keyboard = try JsonElement.initObject(main.threadAllocator); inline for(comptime std.meta.fieldNames(@TypeOf(main.keyboard))) |keyName| { - const keyJson = JsonElement.initObject(main.threadAllocator) catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - return; - }; + const keyJson = try JsonElement.initObject(main.threadAllocator); const key = &@field(main.keyboard, keyName); - keyJson.put("key", key.key) catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - }; - keyJson.put("mouseButton", key.mouseButton) catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - }; - keyJson.put("scancode", key.scancode) catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - }; - keyboard.put(keyName, keyJson) catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - }; + try keyJson.put("key", key.key); + try keyJson.put("mouseButton", key.mouseButton); + try keyJson.put("scancode", key.scancode); + try keyboard.put(keyName, keyJson); } - jsonObject.put("keyboard", keyboard) catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - }; + try jsonObject.put("keyboard", keyboard); // Write to file: - const string = jsonObject.toStringEfficient(main.threadAllocator, "") catch |err| { - std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); - return; - }; + const string = try jsonObject.toStringEfficient(main.threadAllocator, ""); 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; - }; + var file = try std.fs.cwd().createFile("settings.json", .{}); defer file.close(); - file.writeAll(string) catch |err| { + try file.writeAll(string); +} + +pub fn deinit() void { + flawedDeinit() catch |err| { std.log.err("Error in settings.deinit(): {s}", .{@errorName(err)}); return; };