From 05769cc76513ce44c27caf1d76574b78c39dd7c2 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Wed, 31 Jan 2024 15:35:15 +0100 Subject: [PATCH] Some improvements to error handling --- src/assets.zig | 4 +- src/gui/components/TextInput.zig | 2 +- src/gui/windows/multiplayer.zig | 14 ++--- src/gui/windows/save_selection.zig | 56 +++++++++---------- src/json.zig | 21 +++---- src/main.zig | 2 +- src/network.zig | 2 +- src/renderer.zig | 2 +- src/renderer/chunk_meshing.zig | 2 +- src/renderer/mesh_storage.zig | 10 +--- src/server/server.zig | 4 +- src/server/terrain/biomes.zig | 2 +- .../terrain/cavegen/NoiseCaveGenerator.zig | 2 +- src/server/terrain/noise/ValueNoise.zig | 4 +- src/server/world.zig | 4 +- 15 files changed, 60 insertions(+), 71 deletions(-) diff --git a/src/assets.zig b/src/assets.zig index 2c607a8c..fe53965d 100644 --- a/src/assets.zig +++ b/src/assets.zig @@ -30,6 +30,7 @@ pub fn readAllJsonFilesInAddons(externalAllocator: NeverFailingAllocator, addons 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); + errdefer externalAllocator.free(id); @memcpy(id[0..folderName.len], folderName); id[folderName.len] = ':'; for(0..entry.path.len-5) |i| { @@ -219,9 +220,8 @@ pub fn loadWorldAssets(assetFolder: []const u8, palette: *BlockPalette) !void { json = value; } else { std.log.err("Missing block: {s}. Replacing it with default block.", .{id}); - json = JsonElement.initObject(main.globalAllocator); + json = .{.JsonNull={}}; } - defer if(nullValue == null) json.free(main.globalAllocator); try registerBlock(assetFolder, id, json); block += 1; } diff --git a/src/gui/components/TextInput.zig b/src/gui/components/TextInput.zig index 22fd492d..42e9a2e2 100644 --- a/src/gui/components/TextInput.zig +++ b/src/gui/components/TextInput.zig @@ -206,7 +206,7 @@ fn moveCursorRight(self: *TextInput, mods: main.Key.Modifiers) void { if(self.cursor.? >= self.currentString.items.len) return; } } else { - self.cursor.? += std.unicode.utf8ByteSequenceLength(self.currentString.items[self.cursor.?]) catch unreachable; + self.cursor.? += std.unicode.utf8ByteSequenceLength(self.currentString.items[self.cursor.?]) catch 0; } } } diff --git a/src/gui/windows/multiplayer.zig b/src/gui/windows/multiplayer.zig index 4c8be73a..a746917f 100644 --- a/src/gui/windows/multiplayer.zig +++ b/src/gui/windows/multiplayer.zig @@ -28,18 +28,16 @@ var gotIpAddress: std.atomic.Value(bool) = std.atomic.Value(bool).init(false); var thread: ?std.Thread = null; const width: f32 = 420; -fn flawedDiscoverIpAddress() !void { - connection = try ConnectionManager.init(12347, true); // TODO: default port +fn discoverIpAddress() void { + connection = ConnectionManager.init(12347, true) catch |err| { + std.log.err("Could not open Connection: {s}", .{@errorName(err)}); + ipAddress = main.globalAllocator.dupe(u8, @errorName(err)); + return; + }; // TODO: default port ipAddress = std.fmt.allocPrint(main.globalAllocator.allocator, "{}", .{connection.?.externalAddress}) catch unreachable; gotIpAddress.store(true, .Release); } -fn discoverIpAddress() void { - flawedDiscoverIpAddress() catch |err| { - std.log.err("Encountered error {s} while discovering the ip address for multiplayer.", .{@errorName(err)}); - }; -} - fn discoverIpAddressFromNewThread() void { var sta = main.utils.StackAllocator.init(main.globalAllocator, 1 << 23); defer sta.deinit(); diff --git a/src/gui/windows/save_selection.zig b/src/gui/windows/save_selection.zig index 65e36d03..ae462c13 100644 --- a/src/gui/windows/save_selection.zig +++ b/src/gui/windows/save_selection.zig @@ -25,7 +25,7 @@ const width: f32 = 128; var buttonNameArena: main.utils.NeverFailingArenaAllocator = undefined; pub fn openWorld(name: []const u8) void { - std.log.info("TODO: Open world {s}", .{name}); + std.log.info("Opening world {s}", .{name}); main.server.thread = std.Thread.spawn(.{}, main.server.start, .{name}) catch |err| { std.log.err("Encountered error while starting server thread: {s}", .{@errorName(err)}); return; @@ -44,14 +44,6 @@ pub fn openWorld(name: []const u8) void { gui.closeWindow(openWindow); } gui.openHud(); -// while(Server.world == null) { -// try { -// Thread.sleep(10); -// } catch(InterruptedException e) {} -// } -// try { -// GameLauncher.logic.loadWorld(new ClientWorld("127.0.0.1", new UDPConnectionManager(Constants.DEFAULT_PORT+1, false))); // TODO: Don't go over the local network in singleplayer. -// } catch(InterruptedException e) {} } fn openWorldWrap(namePtr: usize) void { // TODO: Improve this situation. Maybe it makes sense to always use 2 arguments in the Callback. @@ -109,29 +101,33 @@ pub fn onOpen() void { const list = VerticalList.init(.{padding, 16 + padding}, 300, 8); // TODO: list.add(Button.initText(.{0, 0}, 128, "Create World", gui.openWindowCallback("save_creation"))); - var dir = std.fs.cwd().makeOpenPath("saves", .{.iterate = true}) catch |err| { - std.log.err("Encountered error while trying to open folder \"saves\": {s}", .{@errorName(err)}); - return; - }; - defer dir.close(); + readingSaves: { + var dir = std.fs.cwd().makeOpenPath("saves", .{.iterate = true}) catch |err| { + list.add(Label.init(.{0, 0}, 128, "Encountered error while trying to open saves folder:", .center)); + list.add(Label.init(.{0, 0}, 128, @errorName(err), .center)); + break :readingSaves; + }; + defer dir.close(); - var iterator = dir.iterate(); - while(iterator.next() catch |err| { - std.log.err("Encountered error while iterating over folder \"saves\": {s}", .{@errorName(err)}); - return; - }) |entry| { - if(entry.kind == .directory) { - const row = HorizontalList.init(); + var iterator = dir.iterate(); + while(iterator.next() catch |err| { + list.add(Label.init(.{0, 0}, 128, "Encountered error while iterating over saves folder:", .center)); + list.add(Label.init(.{0, 0}, 128, @errorName(err), .center)); + break :readingSaves; + }) |entry| { + if(entry.kind == .directory) { + const row = HorizontalList.init(); - const decodedName = parseEscapedFolderName(main.stackAllocator, entry.name); - defer main.stackAllocator.free(decodedName); - const name = buttonNameArena.allocator().dupeZ(u8, entry.name); // Null terminate, so we can later recover the string from just the pointer. - const buttonName = std.fmt.allocPrint(buttonNameArena.allocator().allocator, "Play {s}", .{decodedName}) catch unreachable; - - row.add(Button.initText(.{0, 0}, 128, buttonName, .{.callback = &openWorldWrap, .arg = @intFromPtr(name.ptr)})); - row.add(Button.initText(.{8, 0}, 64, "delete", .{.callback = &deleteWorld, .arg = @intFromPtr(name.ptr)})); - row.finish(.{0, 0}, .center); - list.add(row); + const decodedName = parseEscapedFolderName(main.stackAllocator, entry.name); + defer main.stackAllocator.free(decodedName); + const name = buttonNameArena.allocator().dupeZ(u8, entry.name); // Null terminate, so we can later recover the string from just the pointer. + const buttonName = std.fmt.allocPrint(buttonNameArena.allocator().allocator, "Play {s}", .{decodedName}) catch unreachable; + + row.add(Button.initText(.{0, 0}, 128, buttonName, .{.callback = &openWorldWrap, .arg = @intFromPtr(name.ptr)})); + row.add(Button.initText(.{8, 0}, 64, "delete", .{.callback = &deleteWorld, .arg = @intFromPtr(name.ptr)})); + row.finish(.{0, 0}, .center); + list.add(row); + } } } diff --git a/src/json.zig b/src/json.zig index 2bdd5be0..8ce3ffb2 100644 --- a/src/json.zig +++ b/src/json.zig @@ -237,13 +237,13 @@ pub const JsonElement = union(JsonType) { list.append('\t'); } } - fn recurseToString(json: JsonElement, list: *List(u8), tabs: u32, comptime visualCharacters: bool) !void { + fn recurseToString(json: JsonElement, list: *List(u8), tabs: u32, comptime visualCharacters: bool) void { switch(json) { .JsonInt => |value| { - try std.fmt.formatInt(value, 10, .lower, .{}, list.writer()); + std.fmt.formatInt(value, 10, .lower, .{}, list.writer()) catch unreachable; }, .JsonFloat => |value| { - try std.fmt.formatFloatScientific(value, .{}, list.writer()); + std.fmt.formatFloatScientific(value, .{}, list.writer()) catch unreachable; }, .JsonBool => |value| { if(value) { @@ -268,7 +268,7 @@ pub const JsonElement = union(JsonType) { } if(visualCharacters) list.append('\n'); if(visualCharacters) writeTabs(list, tabs + 1); - try recurseToString(elem, list, tabs + 1, visualCharacters); + recurseToString(elem, list, tabs + 1, visualCharacters); } if(visualCharacters) list.append('\n'); if(visualCharacters) writeTabs(list, tabs); @@ -292,7 +292,7 @@ pub const JsonElement = union(JsonType) { list.append(':'); if(visualCharacters) list.append(' '); - try recurseToString(elem.value_ptr.*, list, tabs + 1, visualCharacters); + recurseToString(elem.value_ptr.*, list, tabs + 1, visualCharacters); first = false; } if(visualCharacters) list.append('\n'); @@ -303,7 +303,7 @@ pub const JsonElement = union(JsonType) { } pub fn toString(json: JsonElement, allocator: NeverFailingAllocator) []const u8 { var string = List(u8).init(allocator); - recurseToString(json, &string, 0, true) catch unreachable; + recurseToString(json, &string, 0, true); return string.toOwnedSlice(); } @@ -311,7 +311,7 @@ pub const JsonElement = union(JsonType) { pub fn toStringEfficient(json: JsonElement, allocator: NeverFailingAllocator, prefix: []const u8) []const u8 { var string = List(u8).init(allocator); string.appendSlice(prefix); - recurseToString(json, &string, 0, false) catch unreachable; + recurseToString(json, &string, 0, false); return string.toOwnedSlice(); } @@ -505,10 +505,11 @@ const Parser = struct { index.* += 1; skipWhitespaces(chars, index); const value: JsonElement = parseElement(allocator, chars, index); - map.putNoClobber(key, value) catch { + if(map.fetchPut(key, value) catch unreachable) |old| { printError(chars, index.*, "Duplicate key."); - allocator.free(key); - }; + allocator.free(old.key); + old.value.free(allocator); + } skipWhitespaces(chars, index); if(index.* < chars.len and chars[index.*] == ',') { index.* += 1; diff --git a/src/main.zig b/src/main.zig index b13435dc..1844e83c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -668,7 +668,7 @@ pub fn main() !void { // init logging. try std.fs.cwd().makePath("logs"); - logFile = std.fs.cwd().createFile("logs/latest.log", .{}) catch unreachable; + logFile = try std.fs.cwd().createFile("logs/latest.log", .{}); defer logFile.close(); supportsANSIColors = std.io.getStdOut().supportsAnsiEscapeCodes(); diff --git a/src/network.zig b/src/network.zig index 07b43cb4..d862be6b 100644 --- a/src/network.zig +++ b/src/network.zig @@ -288,7 +288,7 @@ const STUN = struct { std.log.err("Cannot resolve stun server address: {s}, error: {s}", .{ip, @errorName(err)}); continue; }, - .port=std.fmt.parseUnsigned(u16, splitter.rest(), 10) catch 3478 + .port=std.fmt.parseUnsigned(u16, splitter.rest(), 10) catch 3478, }; if(connection.sendRequest(main.globalAllocator, &data, serverAddress, 500*1000000)) |answer| { defer main.globalAllocator.free(answer); diff --git a/src/renderer.zig b/src/renderer.zig index baccc98d..33329f44 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -482,6 +482,7 @@ pub const MenuBackGround = struct { c.glBufferData(c.GL_ELEMENT_ARRAY_BUFFER, @intCast(indices.len*@sizeOf(c_int)), &indices, c.GL_STATIC_DRAW); // Load a random texture from the backgrounds folder. The player may make their own pictures which can be chosen as well. + texture = .{.textureID = 0}; var dir = try std.fs.cwd().makeOpenPath("assets/backgrounds", .{.iterate = true}); defer dir.close(); @@ -502,7 +503,6 @@ pub const MenuBackGround = struct { } if(fileList.items.len == 0) { std.log.warn("Couldn't find any background scene images in \"assets/backgrounds\".", .{}); - texture = .{.textureID = 0}; return; } const theChosenOne = main.random.nextIntBounded(u32, &main.seed, @as(u32, @intCast(fileList.items.len))); diff --git a/src/renderer/chunk_meshing.zig b/src/renderer/chunk_meshing.zig index 7733b182..c6e75555 100644 --- a/src/renderer/chunk_meshing.zig +++ b/src/renderer/chunk_meshing.zig @@ -610,7 +610,7 @@ pub const ChunkMesh = struct { } } - pub fn generateLightingData(self: *ChunkMesh) !void { + pub fn generateLightingData(self: *ChunkMesh) error{AlreadyStored}!void { self.mutex.lock(); self.opaqueMesh.reset(); self.transparentMesh.reset(); diff --git a/src/renderer/mesh_storage.zig b/src/renderer/mesh_storage.zig index f790b505..f0fd8038 100644 --- a/src/renderer/mesh_storage.zig +++ b/src/renderer/mesh_storage.zig @@ -963,7 +963,7 @@ pub fn addToUpdateListAndDecreaseRefCount(mesh: *chunk_meshing.ChunkMesh) void { } } -pub fn addMeshToStorage(mesh: *chunk_meshing.ChunkMesh) !void { +pub fn addMeshToStorage(mesh: *chunk_meshing.ChunkMesh) error{AlreadyStored}!void { mutex.lock(); defer mutex.unlock(); if(isInRenderDistance(mesh.pos)) { @@ -1018,13 +1018,7 @@ pub const MeshGenerationTask = struct { const mesh = main.globalAllocator.create(chunk_meshing.ChunkMesh); mesh.init(pos, self.mesh); defer mesh.decreaseRefCount(); - mesh.generateLightingData() catch |err| { - switch(err) { - error.AlreadyStored => { - return; - }, - } - }; + mesh.generateLightingData() catch return; } pub fn clean(self: *MeshGenerationTask) void { diff --git a/src/server/server.zig b/src/server/server.zig index 6b2c1f95..2ab04bd0 100644 --- a/src/server/server.zig +++ b/src/server/server.zig @@ -117,7 +117,7 @@ fn init(name: []const u8) void { users = main.List(*User).init(main.globalAllocator); lastTime = std.time.nanoTimestamp(); connectionManager = ConnectionManager.init(main.settings.defaultPort, false) catch |err| { - std.log.err("Couldn't create connection from port: {s}", .{@errorName(err)}); + std.log.err("Couldn't create socket: {s}", .{@errorName(err)}); @panic("Could not open Server."); }; // TODO Configure the second argument in the server settings. // TODO: Load the assets. @@ -128,7 +128,7 @@ fn init(name: []const u8) void { }; if(true) blk: { // singleplayer // TODO: Configure this in the server settings. const user = User.init(connectionManager, "127.0.0.1:47650") catch |err| { - std.log.err("Cannot create user {s}", .{@errorName(err)}); + std.log.err("Cannot create singleplayer user {s}", .{@errorName(err)}); break :blk; }; user.isLocal = true; diff --git a/src/server/terrain/biomes.zig b/src/server/terrain/biomes.zig index 4ca6f785..46ca889e 100644 --- a/src/server/terrain/biomes.zig +++ b/src/server/terrain/biomes.zig @@ -204,7 +204,7 @@ pub const BlockStructure = struct { }; for(blockStackDescriptions, self.structure) |jsonString, *blockStack| { blockStack.init(jsonString.as([]const u8, "That's not a json string.")) catch |err| { - std.log.warn("Couldn't parse blockStack '{s}': {s} Removing it.", .{jsonString.as([]const u8, "That's not a json string."), @errorName(err)}); + std.log.warn("Couldn't parse blockStack '{s}': {s} Removing it.", .{jsonString.as([]const u8, "(not a json string)"), @errorName(err)}); blockStack.* = .{}; }; } diff --git a/src/server/terrain/cavegen/NoiseCaveGenerator.zig b/src/server/terrain/cavegen/NoiseCaveGenerator.zig index 4e0fb136..b8ae29be 100644 --- a/src/server/terrain/cavegen/NoiseCaveGenerator.zig +++ b/src/server/terrain/cavegen/NoiseCaveGenerator.zig @@ -42,7 +42,7 @@ pub fn generate(map: *CaveMapFragment, worldSeed: u64) void { const outerSize = @max(map.pos.voxelSize, interpolatedPart); const outerSizeShift = std.math.log2_int(u31, outerSize); const outerSizeFloat: f32 = @floatFromInt(outerSize); - const noise = FractalNoise3D.generateAligned(main.stackAllocator, map.pos.wx, map.pos.wy, map.pos.wz, outerSize, CaveMapFragment.width*map.pos.voxelSize/outerSize + 1, CaveMapFragment.height*map.pos.voxelSize/outerSize + 1, CaveMapFragment.width*map.pos.voxelSize/outerSize + 1, worldSeed, scale);//try Cached3DFractalNoise.init(map.pos.wx, map.pos.wy & ~@as(i32, CaveMapFragment.width*map.pos.voxelSize - 1), map.pos.wz, outerSize, map.pos.voxelSize*CaveMapFragment.width, worldSeed, scale); + const noise = FractalNoise3D.generateAligned(main.stackAllocator, map.pos.wx, map.pos.wy, map.pos.wz, outerSize, CaveMapFragment.width*map.pos.voxelSize/outerSize + 1, CaveMapFragment.height*map.pos.voxelSize/outerSize + 1, CaveMapFragment.width*map.pos.voxelSize/outerSize + 1, worldSeed, scale); defer noise.deinit(main.stackAllocator); biomeMap.bulkInterpolateValue("caves", map.pos.wx, map.pos.wy, map.pos.wz, outerSize, noise, .addToMap, scale); var x: u31 = 0; diff --git a/src/server/terrain/noise/ValueNoise.zig b/src/server/terrain/noise/ValueNoise.zig index 08628778..587eaba9 100644 --- a/src/server/terrain/noise/ValueNoise.zig +++ b/src/server/terrain/noise/ValueNoise.zig @@ -39,7 +39,7 @@ pub fn samplePoint2D(x: f32, _y: f32, worldSeed: u64) f32 { const percentileTable = [_]f32 {0.0e+00, 9.20569300e-02, 1.18748918e-01, 1.38117700e-01, 1.53936773e-01, 1.67584523e-01, 1.79740771e-01, 1.90797567e-01, 2.01004371e-01, 2.10530936e-01, 2.19498828e-01, 2.27998286e-01, 2.36098647e-01, 2.43854254e-01, 2.51308768e-01, 2.58497864e-01, 2.65450924e-01, 2.72192806e-01, 2.78744399e-01, 2.85123795e-01, 2.91346460e-01, 2.97426044e-01, 3.03374379e-01, 3.09202045e-01, 3.14918369e-01, 3.20531696e-01, 3.26049506e-01, 3.31478625e-01, 3.36825191e-01, 3.42094779e-01, 3.47292482e-01, 3.52423042e-01, 3.57490718e-01, 3.62499535e-01, 3.67453157e-01, 3.72355014e-01, 3.77208292e-01, 3.82015973e-01, 3.86780887e-01, 3.91505628e-01, 3.96192669e-01, 4.00844365e-01, 4.05462920e-01, 4.10050421e-01, 4.14608865e-01, 4.19140160e-01, 4.23646122e-01, 4.28128510e-01, 4.32588934e-01, 4.37029063e-01, 4.41450417e-01, 4.45854485e-01, 4.50242727e-01, 4.54616576e-01, 4.58977371e-01, 4.63326483e-01, 4.67665165e-01, 4.71994757e-01, 4.76316481e-01, 4.80631619e-01, 4.84941333e-01, 4.89246904e-01, 4.93549466e-01, 4.97850269e-01, 5.02150475e-01, 5.06451249e-01, 5.10753810e-01, 5.15059411e-01, 5.19369125e-01, 5.23684263e-01, 5.28005957e-01, 5.32335579e-01, 5.36674261e-01, 5.41023373e-01, 5.45384168e-01, 5.49758017e-01, 5.54146230e-01, 5.58550298e-01, 5.62971651e-01, 5.67411780e-01, 5.71872234e-01, 5.76354622e-01, 5.80860555e-01, 5.85391879e-01, 5.89950323e-01, 5.94537794e-01, 5.99156379e-01, 6.03808045e-01, 6.08495116e-01, 6.13219857e-01, 6.17984771e-01, 6.22792422e-01, 6.27645730e-01, 6.32547557e-01, 6.37501180e-01, 6.42509996e-01, 6.47577702e-01, 6.52708232e-01, 6.57905936e-01, 6.63175523e-01, 6.68522059e-01, 6.73951208e-01, 6.79469048e-01, 6.85082376e-01, 6.90798640e-01, 6.96626305e-01, 7.02574670e-01, 7.08654224e-01, 7.14876949e-01, 7.21256315e-01, 7.27807879e-01, 7.34549760e-01, 7.41502821e-01, 7.48691916e-01, 7.56146430e-01, 7.63902068e-01, 7.72002398e-01, 7.80501842e-01, 7.89469778e-01, 7.98996329e-01, 8.09203147e-01, 8.20259928e-01, 8.32416176e-01, 8.46063911e-01, 8.61882984e-01, 8.81251752e-01, 9.07943725e-01, 1.0e+00}; -fn preGeneratePercentileTable() !void { +fn preGeneratePercentileTable() void { const randomNumbers = 4096; const positions = 4096; const totalValues = randomNumbers*positions; @@ -66,7 +66,7 @@ fn preGeneratePercentileTable() !void { } var samples: u128 = 0; for(&amount2D) |val| { - samples = try std.math.add(u128, samples, val); + samples = std.math.add(u128, samples, val) catch @panic("Number too big"); } std.log.info("{}", .{samples}); diff --git a/src/server/world.zig b/src/server/world.zig index 8e96fcd4..caaa7717 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -463,7 +463,7 @@ pub const ServerWorld = struct { // for(MetaChunk chunk : metaChunks.values().toArray(new MetaChunk[0])) { // if (chunk != null) chunk.save(); // } - self.wio.saveWorldData(); + try self.wio.saveWorldData(); // TODO: // savePlayers(); // chunkManager.forceSave(); @@ -471,7 +471,7 @@ pub const ServerWorld = struct { const itemDropJson = self.itemDropManager.store(main.globalAllocator); defer itemDropJson.free(main.globalAllocator); var buf: [32768]u8 = undefined; - files.writeJson(try std.fmt.bufPrint(&buf, "saves/{s}/items.json", .{self.name}), itemDropJson); + try files.writeJson(try std.fmt.bufPrint(&buf, "saves/{s}/items.json", .{self.name}), itemDropJson); } // TODO: // public void addEntity(Entity ent) {