diff --git a/src/assets.zig b/src/assets.zig index fe53965d..86434239 100644 --- a/src/assets.zig +++ b/src/assets.zig @@ -15,18 +15,23 @@ var commonItems: std.StringHashMap(JsonElement) = undefined; var commonRecipes: main.List([]const u8) = undefined; /// Reads json files recursively from all subfolders. -pub fn readAllJsonFilesInAddons(externalAllocator: NeverFailingAllocator, addons: main.List(std.fs.Dir), addonNames: main.List([]const u8), subPath: []const u8, output: *std.StringHashMap(JsonElement)) !void { +pub fn readAllJsonFilesInAddons(externalAllocator: NeverFailingAllocator, addons: main.List(std.fs.Dir), addonNames: main.List([]const u8), subPath: []const u8, output: *std.StringHashMap(JsonElement)) void { for(addons.items, addonNames.items) |addon, addonName| { var dir = addon.openDir(subPath, .{.iterate = true}) catch |err| { - if(err == error.FileNotFound) continue; - return err; + if(err != error.FileNotFound) { + std.log.err("Could not open addon directory {s}: {s}", .{subPath, @errorName(err)}); + } + continue; }; defer dir.close(); - var walker = try dir.walk(main.globalAllocator.allocator); + var walker = dir.walk(main.globalAllocator.allocator) catch unreachable; defer walker.deinit(); - while(try walker.next()) |entry| { + while(walker.next() catch |err| blk: { + std.log.err("Got error while iterating addon directory {s}: {s}", .{subPath, @errorName(err)}); + break :blk null; + }) |entry| { if(entry.kind == .file and std.ascii.endsWithIgnoreCase(entry.basename, ".json")) { const folderName = addonName; const id: []u8 = externalAllocator.alloc(u8, folderName.len + 1 + entry.path.len - 5); @@ -41,30 +46,41 @@ pub fn readAllJsonFilesInAddons(externalAllocator: NeverFailingAllocator, addons } } - const file = try dir.openFile(entry.path, .{}); + const file = dir.openFile(entry.path, .{}) catch |err| { + std.log.err("Could not open {s}/{s}: {s}", .{subPath, entry.path, @errorName(err)}); + continue; + }; defer file.close(); const string = file.readToEndAlloc(main.stackAllocator.allocator, std.math.maxInt(usize)) catch unreachable; defer main.stackAllocator.free(string); - try output.put(id, JsonElement.parseFromString(externalAllocator, string)); + output.put(id, JsonElement.parseFromString(externalAllocator, string)) catch unreachable; } } } } /// Reads text files recursively from all subfolders. -pub fn readAllFilesInAddons(externalAllocator: NeverFailingAllocator, addons: main.List(std.fs.Dir), subPath: []const u8, output: *main.List([]const u8)) !void { +pub fn readAllFilesInAddons(externalAllocator: NeverFailingAllocator, addons: main.List(std.fs.Dir), subPath: []const u8, output: *main.List([]const u8)) void { for(addons.items) |addon| { var dir = addon.openDir(subPath, .{.iterate = true}) catch |err| { - if(err == error.FileNotFound) continue; - return err; + if(err != error.FileNotFound) { + std.log.err("Could not open addon directory {s}: {s}", .{subPath, @errorName(err)}); + } + continue; }; defer dir.close(); - var walker = try dir.walk(main.globalAllocator.allocator); + var walker = dir.walk(main.globalAllocator.allocator) catch unreachable; defer walker.deinit(); - while(try walker.next()) |entry| { + while(walker.next() catch |err| blk: { + std.log.err("Got error while iterating addon directory {s}: {s}", .{subPath, @errorName(err)}); + break :blk null; + }) |entry| { if(entry.kind == .file) { - const file = try dir.openFile(entry.path, .{}); + const file = dir.openFile(entry.path, .{}) catch |err| { + std.log.err("Could not open {s}/{s}: {s}", .{subPath, entry.path, @errorName(err)}); + continue; + }; defer file.close(); const string = file.readToEndAlloc(externalAllocator.allocator, std.math.maxInt(usize)) catch unreachable; output.append(string); @@ -73,19 +89,28 @@ pub fn readAllFilesInAddons(externalAllocator: NeverFailingAllocator, addons: ma } } -pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u8, blocks: *std.StringHashMap(JsonElement), items: *std.StringHashMap(JsonElement), biomes: *std.StringHashMap(JsonElement), recipes: *main.List([]const u8)) !void { +pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u8, blocks: *std.StringHashMap(JsonElement), items: *std.StringHashMap(JsonElement), biomes: *std.StringHashMap(JsonElement), recipes: *main.List([]const u8)) void { var addons = main.List(std.fs.Dir).init(main.globalAllocator); defer addons.deinit(); var addonNames = main.List([]const u8).init(main.globalAllocator); defer addonNames.deinit(); { // Find all the sub-directories to the assets folder. - var dir = try std.fs.cwd().openDir(assetPath, .{.iterate = true}); + var dir = std.fs.cwd().openDir(assetPath, .{.iterate = true}) catch |err| { + std.log.err("Can't open asset path {s}: {s}", .{assetPath, @errorName(err)}); + return; + }; defer dir.close(); var iterator = dir.iterate(); - while(try iterator.next()) |addon| { + while(iterator.next() catch |err| blk: { + std.log.err("Got error while iterating over asset path {s}: {s}", .{assetPath, @errorName(err)}); + break :blk null; + }) |addon| { if(addon.kind == .directory) { - addons.append(try dir.openDir(addon.name, .{})); + addons.append(dir.openDir(addon.name, .{}) catch |err| { + std.log.err("Got error while reading addon {s} from {s}: {s}", .{addon.name, assetPath, @errorName(err)}); + continue; + }); addonNames.append(main.globalAllocator.dupe(u8, addon.name)); } } @@ -95,13 +120,13 @@ pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u main.globalAllocator.free(addonName); }; - try readAllJsonFilesInAddons(externalAllocator, addons, addonNames, "blocks", blocks); - try readAllJsonFilesInAddons(externalAllocator, addons, addonNames, "items", items); - try readAllJsonFilesInAddons(externalAllocator, addons, addonNames, "biomes", biomes); - try readAllFilesInAddons(externalAllocator, addons, "recipes", recipes); + readAllJsonFilesInAddons(externalAllocator, addons, addonNames, "blocks", blocks); + readAllJsonFilesInAddons(externalAllocator, addons, addonNames, "items", items); + readAllJsonFilesInAddons(externalAllocator, addons, addonNames, "biomes", biomes); + readAllFilesInAddons(externalAllocator, addons, "recipes", recipes); } -pub fn init() !void { +pub fn init() void { biomes_zig.init(); blocks_zig.init(); arena = main.utils.NeverFailingArenaAllocator.init(main.globalAllocator); @@ -111,7 +136,7 @@ pub fn init() !void { commonBiomes = std.StringHashMap(JsonElement).init(arenaAllocator.allocator); commonRecipes = main.List([]const u8).init(arenaAllocator); - try readAssets(arenaAllocator, "assets/", &commonBlocks, &commonItems, &commonBiomes, &commonRecipes); + readAssets(arenaAllocator, "assets/", &commonBlocks, &commonItems, &commonBiomes, &commonRecipes); } fn registerItem(assetFolder: []const u8, id: []const u8, json: JsonElement) !*items_zig.BaseItem { @@ -209,7 +234,7 @@ pub fn loadWorldAssets(assetFolder: []const u8, palette: *BlockPalette) !void { recipes.appendSlice(commonRecipes.items); defer recipes.clearAndFree(); - try readAssets(arenaAllocator, assetFolder, &blocks, &items, &biomes, &recipes); + readAssets(arenaAllocator, assetFolder, &blocks, &items, &biomes, &recipes); // blocks: var block: u32 = 0; diff --git a/src/graphics.zig b/src/graphics.zig index 31d2a4be..d178826b 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -1048,7 +1048,7 @@ const TextRendering = struct { } }; -pub fn init() !void { +pub fn init() void { draw.initCircle(); draw.initDrawRect(); draw.initImage(); diff --git a/src/gui/gui.zig b/src/gui/gui.zig index 15eb4d85..efc43cb1 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -124,7 +124,7 @@ pub const Callback = struct { } }; -pub fn init() !void { +pub fn init() void { GuiCommandQueue.init(); windowList = List(*GuiWindow).init(main.globalAllocator); hudWindows = List(*GuiWindow).init(main.globalAllocator); diff --git a/src/main.zig b/src/main.zig index 1844e83c..5de9a907 100644 --- a/src/main.zig +++ b/src/main.zig @@ -48,7 +48,7 @@ fn cacheStringImpl(comptime len: usize, comptime str: [len]u8) []const u8 { fn cacheString(comptime str: []const u8) []const u8 { return cacheStringImpl(str.len, str[0..].*); } -var logFile: std.fs.File = undefined; +var logFile: ?std.fs.File = undefined; var supportsANSIColors: bool = undefined; // overwrite the log function: pub const std_options = struct { @@ -181,6 +181,26 @@ pub const std_options = struct { } }; +fn initLogging() void { + logFile = null; + std.fs.cwd().makePath("logs") catch |err| { + std.log.err("Couldn't create logs folder: {s}", .{@errorName(err)}); + return; + }; + logFile = std.fs.cwd().createFile("logs/latest.log", .{}) catch |err| { + std.log.err("Couldn't create logs/latest.log: {s}", .{@errorName(err)}); + return; + }; + supportsANSIColors = std.io.getStdOut().supportsAnsiEscapeCodes(); +} + +fn deinitLogging() void { + if(logFile) |_logFile| { + _logFile.close(); + logFile = null; + } +} + fn logToFile(comptime format: []const u8, args: anytype) void { var buf: [65536]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&buf); @@ -188,7 +208,7 @@ fn logToFile(comptime format: []const u8, args: anytype) void { const string = std.fmt.allocPrint(allocator, format, args) catch format; defer allocator.free(string); - logFile.writeAll(string) catch {}; + (logFile orelse return).writeAll(string) catch {}; } fn logToStdErr(comptime format: []const u8, args: anytype) void { @@ -587,11 +607,11 @@ pub const Window = struct { c.glfwSetClipboardString(window, nullTerminatedString.ptr); } - fn init() !void { + fn init() void { _ = c.glfwSetErrorCallback(GLFWCallbacks.errorCallback); if(c.glfwInit() == 0) { - return error.GLFWFailed; + @panic("Failed to initialize GLFW"); } if(@import("builtin").mode == .Debug) { @@ -600,7 +620,7 @@ pub const Window = struct { c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MAJOR, 4); c.glfwWindowHint(c.GLFW_CONTEXT_VERSION_MINOR, 6); - window = c.glfwCreateWindow(width, height, "Cubyz", null, null) orelse return error.GLFWFailed; + window = c.glfwCreateWindow(width, height, "Cubyz", null, null) orelse @panic("Failed to create GLFW window"); _ = c.glfwSetKeyCallback(window, GLFWCallbacks.keyCallback); _ = c.glfwSetCharCallback(window, GLFWCallbacks.charCallback); @@ -612,7 +632,7 @@ pub const Window = struct { c.glfwMakeContextCurrent(window); if(c.gladLoadGL() == 0) { - return error.GLADFailed; + @panic("Failed to load OpenGL functions from GLAD"); } reloadSettings(); @@ -657,7 +677,7 @@ pub const Window = struct { pub var lastFrameTime = std.atomic.Value(f64).init(0); -pub fn main() !void { +pub fn main() void { seed = @bitCast(std.time.milliTimestamp()); defer if(global_gpa.deinit() == .leak) { std.log.err("Memory leak", .{}); @@ -666,11 +686,8 @@ pub fn main() !void { defer sta.deinit(); stackAllocator = sta.allocator(); - // init logging. - try std.fs.cwd().makePath("logs"); - logFile = try std.fs.cwd().createFile("logs/latest.log", .{}); - defer logFile.close(); - supportsANSIColors = std.io.getStdOut().supportsAnsiEscapeCodes(); + initLogging(); + defer deinitLogging(); threadPool = utils.ThreadPool.init(globalAllocator, 1 + ((std.Thread.getCpuCount() catch 4) -| 2)); defer threadPool.deinit(); @@ -678,16 +695,16 @@ pub fn main() !void { settings.init(); defer settings.deinit(); - try Window.init(); + Window.init(); defer Window.deinit(); - try graphics.init(); + graphics.init(); defer graphics.deinit(); audio.init() catch std.log.err("Failed to initialize audio. Continuing the game without sounds.", .{}); defer audio.deinit(); - try gui.init(); + gui.init(); defer gui.deinit(); rotation.init(); @@ -702,7 +719,7 @@ pub fn main() !void { itemdrop.ItemDropRenderer.init(); defer itemdrop.ItemDropRenderer.deinit(); - try assets.init(); + assets.init(); defer assets.deinit(); blocks.meshes.init(); @@ -711,7 +728,7 @@ pub fn main() !void { renderer.init(); defer renderer.deinit(); - try network.init(); + network.init(); entity.ClientEntityManager.init(); defer entity.ClientEntityManager.deinit(); diff --git a/src/network.zig b/src/network.zig index d862be6b..92f9ffaa 100644 --- a/src/network.zig +++ b/src/network.zig @@ -26,9 +26,12 @@ const Socket = struct { const os = std.os; socketID: os.socket_t, - fn startup() !void { + fn startup() void { if(builtin.os.tag == .windows) { - _ = try os.windows.WSAStartup(2, 2); + _ = os.windows.WSAStartup(2, 2) catch |err| { + std.log.err("Could not initialize the Windows Socket API: {s}", .{@errorName(err)}); + @panic("Could not init networking."); + }; } } @@ -100,8 +103,8 @@ const Socket = struct { } }; -pub fn init() !void { - try Socket.startup(); +pub fn init() void { + Socket.startup(); inline for(@typeInfo(Protocols).Struct.decls) |decl| { if(@TypeOf(@field(Protocols, decl.name)) == type) { const id = @field(Protocols, decl.name).id; @@ -493,7 +496,7 @@ pub const ConnectionManager = struct { } } - fn onReceive(self: *ConnectionManager, data: []const u8, source: Address) !void { + fn onReceive(self: *ConnectionManager, data: []const u8, source: Address) void { std.debug.assert(self.threadId == std.Thread.getCurrentId()); self.mutex.lock(); @@ -505,7 +508,7 @@ pub const ConnectionManager = struct { } if(conn.remoteAddress.port == source.port) { self.mutex.unlock(); - try conn.receive(data); + conn.receive(data); return; } } @@ -525,7 +528,7 @@ pub const ConnectionManager = struct { std.log.debug("Message: {any}", .{data}); } - pub fn run(self: *ConnectionManager) !void { + pub fn run(self: *ConnectionManager) void { self.threadId = std.Thread.getCurrentId(); var sta = utils.StackAllocator.init(main.globalAllocator, 1 << 23); defer sta.deinit(); @@ -536,12 +539,13 @@ pub const ConnectionManager = struct { self.waitingToFinishReceive.broadcast(); var source: Address = undefined; if(self.socket.receive(&self.receiveBuffer, 100, &source)) |data| { - try self.onReceive(data, source); + self.onReceive(data, source); } else |err| { if(err == error.Timeout) { // No message within the last ~100 ms. } else { - return err; // TODO: Shutdown the game normally. + std.log.err("Got error on receive: {s}", .{@errorName(err)}); + @panic("Network failed."); } } @@ -1635,7 +1639,14 @@ pub const Connection = struct { } } - pub fn receive(self: *Connection, data: []const u8) !void { + pub fn receive(self: *Connection, data: []const u8) void { + self.flawedReceive(data) catch |err| { + std.log.err("Got error while processing received network data: {s}", .{@errorName(err)}); + self.disconnect(); + }; + } + + pub fn flawedReceive(self: *Connection, data: []const u8) !void { std.debug.assert(self.manager.threadId == std.Thread.getCurrentId()); const protocol = data[0]; if(self.handShakeState.load(.Monotonic) != Protocols.handShake.stepComplete and protocol != Protocols.handShake.id and protocol != Protocols.keepAlive and protocol != Protocols.important) { @@ -1683,7 +1694,7 @@ pub const Connection = struct { if(Protocols.list[protocol]) |prot| { try prot(self, data[1..]); } else { - std.log.warn("Received unknown protocol width id {}", .{protocol}); + std.log.warn("Received unknown protocol with id {}", .{protocol}); } } }