Handle errors locally instead of letting them bubble up into the main functions.

This commit is contained in:
IntegratedQuantum 2024-01-31 22:42:20 +01:00
parent 05769cc765
commit 74c896c969
5 changed files with 107 additions and 54 deletions

View File

@ -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;

View File

@ -1048,7 +1048,7 @@ const TextRendering = struct {
}
};
pub fn init() !void {
pub fn init() void {
draw.initCircle();
draw.initDrawRect();
draw.initImage();

View File

@ -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);

View File

@ -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();

View File

@ -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});
}
}
}