From aae66ea77fc59a4d3fcb662f0fb48919ba5d292d Mon Sep 17 00:00:00 2001 From: IntegratedQuantum <43880493+IntegratedQuantum@users.noreply.github.com> Date: Tue, 15 Jul 2025 23:00:29 +0200 Subject: [PATCH] Update Zig to use the new Writergate version (#1664) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For reference: https://github.com/ziglang/zig/pull/24329 some commits have been extracted from #1583, but the x86_64 backend has been disabled due to its horrible performance. Remaining work: - [x] Wait for official builds on ziglang.org and upload them to our repository - [x] Add workaround for https://github.com/ziglang/zig/pull/24466 - [x] Fix TODO comment about ANSI support in stdout - [x] Check for compile-time performance changes → it went from 13.1 to 11.9 seconds :tada: --- .github/workflows/ci.yml | 7 ++-- .zig-version | 2 +- build.zig | 49 ++++++++++++++-------------- scripts/install_compiler_linux.sh | 2 +- scripts/install_compiler_windows.bat | 2 +- src/Inventory.zig | 6 ++-- src/assets.zig | 4 +-- src/audio.zig | 6 ++-- src/formatter/fmt.zig | 29 ++++++++-------- src/graphics.zig | 5 +-- src/graphics/Window.zig | 16 ++++----- src/gui/components/TextInput.zig | 8 ++--- src/gui/windows/invite.zig | 2 +- src/gui/windows/manage_players.zig | 2 +- src/gui/windows/multiplayer.zig | 2 +- src/gui/windows/save_selection.zig | 2 +- src/json.zig | 5 ++- src/main.zig | 10 +++--- src/network.zig | 33 ++++++++++++------- src/renderer/chunk_meshing.zig | 2 +- src/server/server.zig | 2 +- src/server/storage.zig | 2 +- src/server/world.zig | 2 +- src/utils.zig | 8 ++--- src/utils/file_monitor.zig | 2 +- src/utils/heap.zig | 15 +++++---- src/utils/list.zig | 2 +- src/zon.zig | 5 ++- test/runner.zig | 23 +++++++------ 29 files changed, 135 insertions(+), 120 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 740c1dc0..269a9d76 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,11 +14,12 @@ jobs: name: Compilation Check steps: - uses: actions/checkout@v3 - - uses: mlugg/setup-zig@v1 + - uses: mlugg/setup-zig@v2 with: - version: 0.14.0 + version: 0.15.0-dev.1034+bd97b6618 - run: sudo apt install libgl-dev libasound2-dev libx11-dev glslang-tools - - run: wget -O /opt/hostedtoolcache/zig/0.14.0/x64/lib/std/zig/render.zig https://github.com/PixelGuys/Cubyz-std-lib/releases/download/0.14.0/render.zig + - run: echo "zigPath=$(command -v zig | sed 's/.\{3\}$//')" >> $GITHUB_ENV + - run: wget -O $zigPath/lib/std/zig/render.zig https://github.com/PixelGuys/Cubyz-std-lib/releases/download/0.15.0-dev.1034+bd97b6618/render.zig - run: zig build - run: zig build -Dtarget=x86_64-windows-gnu - run: zig build test diff --git a/.zig-version b/.zig-version index 0548fb4e..8bc08821 100644 --- a/.zig-version +++ b/.zig-version @@ -1 +1 @@ -0.14.0 \ No newline at end of file +0.15.0-dev.1034+bd97b6618 \ No newline at end of file diff --git a/build.zig b/build.zig index 386610a6..cbf3ea73 100644 --- a/build.zig +++ b/build.zig @@ -52,6 +52,7 @@ fn linkLibraries(b: *std.Build, exe: *std.Build.Step.Compile, useLocalDeps: bool exe.addObjectFile(subPath.path(b, libName(b, "SPIRV-Tools-opt", t))); if(t.os.tag == .windows) { + exe.linkSystemLibrary("crypt32"); exe.linkSystemLibrary("gdi32"); exe.linkSystemLibrary("opengl32"); exe.linkSystemLibrary("ws2_32"); @@ -168,15 +169,19 @@ pub fn build(b: *std.Build) !void { .install_dir = .{.custom = ".."}, }); - const exe = b.addExecutable(.{ - .name = "Cubyzig", + const mainModule = b.addModule("main", .{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, - //.sanitize_thread = true, - //.use_llvm = false, }); - exe.root_module.addImport("main", exe.root_module); + + const exe = b.addExecutable(.{ + .name = "Cubyzig", + .root_module = mainModule, + //.sanitize_thread = true, + .use_llvm = true, + }); + exe.root_module.addImport("main", mainModule); try addModFeatures(b, exe); linkLibraries(b, exe, useLocalDeps); @@ -193,13 +198,11 @@ pub fn build(b: *std.Build) !void { run_step.dependOn(&run_cmd.step); const exe_tests = b.addTest(.{ - .root_source_file = b.path("src/main.zig"), + .root_module = mainModule, .test_runner = .{.path = b.path("test/runner.zig"), .mode = .simple}, - .target = target, - .optimize = optimize, }); linkLibraries(b, exe_tests, useLocalDeps); - exe_tests.root_module.addImport("main", exe_tests.root_module); + exe_tests.root_module.addImport("main", mainModule); try addModFeatures(b, exe_tests); const run_exe_tests = b.addRunArtifact(exe_tests); @@ -210,16 +213,14 @@ pub fn build(b: *std.Build) !void { const formatter = b.addExecutable(.{ .name = "CubyzigFormatter", - .root_source_file = b.path("src/formatter/format.zig"), - .target = target, - .optimize = optimize, + .root_module = b.addModule("format", .{ + .root_source_file = b.path("src/formatter/format.zig"), + .target = target, + .optimize = optimize, + }), }); // ZLS is stupid and cannot detect which executable is the main one, so we add the import everywhere... - formatter.root_module.addAnonymousImport("main", .{ - .target = target, - .optimize = optimize, - .root_source_file = b.path("src/main.zig"), - }); + formatter.root_module.addImport("main", mainModule); const formatter_install = b.addInstallArtifact(formatter, .{}); @@ -234,16 +235,14 @@ pub fn build(b: *std.Build) !void { const zig_fmt = b.addExecutable(.{ .name = "zig_fmt", - .root_source_file = b.path("src/formatter/fmt.zig"), - .target = target, - .optimize = optimize, + .root_module = b.addModule("fmt", .{ + .root_source_file = b.path("src/formatter/fmt.zig"), + .target = target, + .optimize = optimize, + }), }); // ZLS is stupid and cannot detect which executable is the main one, so we add the import everywhere... - zig_fmt.root_module.addAnonymousImport("main", .{ - .target = target, - .optimize = optimize, - .root_source_file = b.path("src/main.zig"), - }); + zig_fmt.root_module.addImport("main", mainModule); const zig_fmt_install = b.addInstallArtifact(zig_fmt, .{}); diff --git a/scripts/install_compiler_linux.sh b/scripts/install_compiler_linux.sh index b3c50a55..2f4d5adf 100755 --- a/scripts/install_compiler_linux.sh +++ b/scripts/install_compiler_linux.sh @@ -33,7 +33,7 @@ then esac fi -VERSION=zig-$OS-$ARCH-$BASE_VERSION +VERSION=zig-$ARCH-$OS-$BASE_VERSION mkdir -p compiler/zig touch compiler/version.txt diff --git a/scripts/install_compiler_windows.bat b/scripts/install_compiler_windows.bat index 2dd19d13..6305b4c5 100644 --- a/scripts/install_compiler_windows.bat +++ b/scripts/install_compiler_windows.bat @@ -14,7 +14,7 @@ IF "%arch%"=="" ( set arch=x86_64 ) -set version=zig-windows-%arch%-%baseVersion% +set version=zig-%arch%-windows-%baseVersion% if not exist compiler mkdir compiler if not exist compiler\version.txt copy NUL compiler\version.txt >NUL diff --git a/src/Inventory.zig b/src/Inventory.zig index 0be6ad52..a06c7a97 100644 --- a/src/Inventory.zig +++ b/src/Inventory.zig @@ -309,7 +309,7 @@ pub const Sync = struct { // MARK: Sync const typ = try reader.readEnum(Command.PayloadType); @setEvalBranchQuota(100000); const payload: Command.Payload = switch(typ) { - inline else => |_typ| @unionInit(Command.Payload, @tagName(_typ), try std.meta.FieldType(Command.Payload, _typ).deserialize(reader, .server, source)), + inline else => |_typ| @unionInit(Command.Payload, @tagName(_typ), try @FieldType(Command.Payload, @tagName(_typ)).deserialize(reader, .server, source)), }; executeCommand(payload, source); } @@ -2001,7 +2001,7 @@ pub fn save(self: Inventory, allocator: NeverFailingAllocator) ZonElement { for(self._items, 0..) |stack, i| { if(!stack.empty()) { var buf: [1024]u8 = undefined; - zonObject.put(buf[0..std.fmt.formatIntBuf(&buf, i, 10, .lower, .{})], stack.store(allocator)); + zonObject.put(buf[0..std.fmt.printInt(&buf, i, 10, .lower, .{})], stack.store(allocator)); } } return zonObject; @@ -2011,7 +2011,7 @@ pub fn loadFromZon(self: Inventory, zon: ZonElement) void { for(self._items, 0..) |*stack, i| { stack.clear(); var buf: [1024]u8 = undefined; - const stackZon = zon.getChild(buf[0..std.fmt.formatIntBuf(&buf, i, 10, .lower, .{})]); + const stackZon = zon.getChild(buf[0..std.fmt.printInt(&buf, i, 10, .lower, .{})]); if(stackZon == .object) { stack.item = Item.init(stackZon) catch |err| { const msg = stackZon.toStringEfficient(main.stackAllocator, ""); diff --git a/src/assets.zig b/src/assets.zig index 45219de3..7cb3c605 100644 --- a/src/assets.zig +++ b/src/assets.zig @@ -644,7 +644,7 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, itemPale break :blk null; }) |addon| { if(addon.kind == .directory) { - const path = std.fmt.allocPrintZ(main.stackAllocator.allocator, "assets/{s}/blocks/textures", .{addon.name}) catch unreachable; + const path = std.fmt.allocPrintSentinel(main.stackAllocator.allocator, "assets/{s}/blocks/textures", .{addon.name}, 0) catch unreachable; defer main.stackAllocator.free(path); std.fs.cwd().access(path, .{}) catch continue; main.utils.file_monitor.listenToPath(path, main.blocks.meshes.reloadTextures, 0); @@ -680,7 +680,7 @@ pub fn unloadAssets() void { // MARK: unloadAssets() break :blk null; }) |addon| { if(addon.kind == .directory) { - const path = std.fmt.allocPrintZ(main.stackAllocator.allocator, "assets/{s}/blocks/textures", .{addon.name}) catch unreachable; + const path = std.fmt.allocPrintSentinel(main.stackAllocator.allocator, "assets/{s}/blocks/textures", .{addon.name}, 0) catch unreachable; defer main.stackAllocator.free(path); std.fs.cwd().access(path, .{}) catch continue; main.utils.file_monitor.removePath(path); diff --git a/src/audio.zig b/src/audio.zig index abbb5651..1f7505fb 100644 --- a/src/audio.zig +++ b/src/audio.zig @@ -27,11 +27,11 @@ const AudioData = struct { }; const addon = id[0..colonIndex]; const fileName = id[colonIndex + 1 ..]; - const path1 = std.fmt.allocPrintZ(main.stackAllocator.allocator, "assets/{s}/music/{s}.ogg", .{addon, fileName}) catch unreachable; + const path1 = std.fmt.allocPrintSentinel(main.stackAllocator.allocator, "assets/{s}/music/{s}.ogg", .{addon, fileName}, 0) catch unreachable; defer main.stackAllocator.free(path1); var err: c_int = 0; if(c.stb_vorbis_open_filename(path1.ptr, &err, null)) |ogg_stream| return ogg_stream; - const path2 = std.fmt.allocPrintZ(main.stackAllocator.allocator, "serverAssets/{s}/music/{s}.ogg", .{addon, fileName}) catch unreachable; + const path2 = std.fmt.allocPrintSentinel(main.stackAllocator.allocator, "serverAssets/{s}/music/{s}.ogg", .{addon, fileName}, 0) catch unreachable; defer main.stackAllocator.free(path2); if(c.stb_vorbis_open_filename(path2.ptr, &err, null)) |ogg_stream| return ogg_stream; std.log.err("Couldn't find music with id \"{s}\". Searched path \"{s}\" and \"{s}\"", .{id, path1, path2}); @@ -309,7 +309,7 @@ fn miniaudioCallback( output: ?*anyopaque, input: ?*const anyopaque, frameCount: u32, -) callconv(.C) void { +) callconv(.c) void { _ = input; _ = maDevice; const valuesPerBuffer = 2*frameCount; // Stereo diff --git a/src/formatter/fmt.zig b/src/formatter/fmt.zig index bed166b3..d3e5dc9c 100644 --- a/src/formatter/fmt.zig +++ b/src/formatter/fmt.zig @@ -7,7 +7,15 @@ pub fn main() !void { } // zig fmt: off -/// Everything below is a direct copy of fmt.zig from the zig compiler +/// Everything below is a direct copy of src/fmt.zig from the zig compiler + +const std = @import("std"); +const mem = std.mem; +const fs = std.fs; +const process = std.process; +const Allocator = std.mem.Allocator; +const Color = std.zig.Color; +const fatal = std.process.fatal; const usage_fmt = \\Usage: zig fmt [file]... @@ -63,7 +71,7 @@ pub fn run( const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { - const stdout = std.io.getStdOut().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); try stdout.writeAll(usage_fmt); return process.cleanExit(); } else if (mem.eql(u8, arg, "--color")) { @@ -104,7 +112,7 @@ pub fn run( fatal("cannot use --stdin with positional arguments", .{}); } - const stdin = std.io.getStdIn(); + const stdin: fs.File = .stdin(); const source_code = std.zig.readSourceFileToEndAlloc(gpa, stdin, null) catch |err| { fatal("unable to read stdin: {}", .{err}); }; @@ -157,7 +165,7 @@ pub fn run( process.exit(code); } - return std.io.getStdOut().writeAll(formatted); + return std.fs.File.stdout().writeAll(formatted); } if (input_files.items.len == 0) { @@ -213,6 +221,7 @@ const FmtError = error{ DestinationAddressRequired, DiskQuota, FileTooBig, + MessageTooBig, InputOutput, NoSpaceLeft, AccessDenied, @@ -373,7 +382,7 @@ fn fmtPathFile( return; if (check_mode) { - const stdout = std.io.getStdOut().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); try stdout.print("{s}\n", .{file_path}); fmt.any_error = true; } else { @@ -382,15 +391,7 @@ fn fmtPathFile( try af.file.writeAll(fmt.out_buffer.items); try af.finish(); - const stdout = std.io.getStdOut().writer(); + const stdout = std.fs.File.stdout().deprecatedWriter(); try stdout.print("{s}\n", .{file_path}); } } - -const std = @import("std"); -const mem = std.mem; -const fs = std.fs; -const process = std.process; -const Allocator = std.mem.Allocator; -const Color = std.zig.Color; -const fatal = std.process.fatal; diff --git a/src/graphics.zig b/src/graphics.zig index cc00145d..3c7fefe2 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -1900,6 +1900,7 @@ pub fn LargeBuffer(comptime Entry: type) type { // MARK: LargerBuffer } pub fn init(self: *Self, allocator: NeverFailingAllocator, size: u31, binding: c_uint) void { + self.used = 0; self.binding = binding; self.createBuffer(size); self.activeFence = 0; @@ -2512,7 +2513,7 @@ pub const Image = struct { // MARK: Image pub fn readFromFile(allocator: NeverFailingAllocator, path: []const u8) !Image { var result: Image = undefined; var channel: c_int = undefined; - const nullTerminatedPath = std.fmt.allocPrintZ(main.stackAllocator.allocator, "{s}", .{path}) catch unreachable; // TODO: Find a more zig-friendly image loading library. + const nullTerminatedPath = main.stackAllocator.dupeZ(u8, path); // TODO: Find a more zig-friendly image loading library. errdefer main.stackAllocator.free(nullTerminatedPath); stb_image.stbi_set_flip_vertically_on_load(1); const data = stb_image.stbi_load(nullTerminatedPath.ptr, @ptrCast(&result.width), @ptrCast(&result.height), &channel, 4) orelse { @@ -2526,7 +2527,7 @@ pub const Image = struct { // MARK: Image pub fn readUnflippedFromFile(allocator: NeverFailingAllocator, path: []const u8) !Image { var result: Image = undefined; var channel: c_int = undefined; - const nullTerminatedPath = std.fmt.allocPrintZ(main.stackAllocator.allocator, "{s}", .{path}) catch unreachable; // TODO: Find a more zig-friendly image loading library. + const nullTerminatedPath = main.stackAllocator.dupeZ(u8, path); // TODO: Find a more zig-friendly image loading library. errdefer main.stackAllocator.free(nullTerminatedPath); const data = stb_image.stbi_load(nullTerminatedPath.ptr, @ptrCast(&result.width), @ptrCast(&result.height), &channel, 4) orelse { return error.FileNotFound; diff --git a/src/graphics/Window.zig b/src/graphics/Window.zig index 5e0f3b39..43bee7cc 100644 --- a/src/graphics/Window.zig +++ b/src/graphics/Window.zig @@ -434,10 +434,10 @@ pub const Key = struct { // MARK: Key }; pub const GLFWCallbacks = struct { // MARK: GLFWCallbacks - fn errorCallback(errorCode: c_int, description: [*c]const u8) callconv(.C) void { + fn errorCallback(errorCode: c_int, description: [*c]const u8) callconv(.c) void { std.log.err("GLFW Error({}): {s}", .{errorCode, description}); } - fn keyCallback(_: ?*c.GLFWwindow, glfw_key: c_int, scancode: c_int, action: c_int, _mods: c_int) callconv(.C) void { + fn keyCallback(_: ?*c.GLFWwindow, glfw_key: c_int, scancode: c_int, action: c_int, _mods: c_int) callconv(.c) void { const mods: Key.Modifiers = @bitCast(@as(u6, @intCast(_mods))); if(!mods.control and main.gui.selectedTextInput != null and c.glfwGetKeyName(glfw_key, scancode) != null) return; // Don't send events for keys that are used in writing letters. const isGrabbed = grabbed; @@ -465,13 +465,13 @@ pub const GLFWCallbacks = struct { // MARK: GLFWCallbacks } } } - fn charCallback(_: ?*c.GLFWwindow, codepoint: c_uint) callconv(.C) void { + fn charCallback(_: ?*c.GLFWwindow, codepoint: c_uint) callconv(.c) void { if(!grabbed) { main.gui.textCallbacks.char(@intCast(codepoint)); } } - pub fn framebufferSize(_: ?*c.GLFWwindow, newWidth: c_int, newHeight: c_int) callconv(.C) void { + pub fn framebufferSize(_: ?*c.GLFWwindow, newWidth: c_int, newHeight: c_int) callconv(.c) void { std.log.info("Framebuffer: {}, {}", .{newWidth, newHeight}); width = @intCast(newWidth); height = @intCast(newHeight); @@ -485,7 +485,7 @@ pub const GLFWCallbacks = struct { // MARK: GLFWCallbacks var deltaBufferPosition: u2 = 0; var currentPos: Vec2f = Vec2f{0, 0}; var ignoreDataAfterRecentGrab: bool = true; - fn cursorPosition(_: ?*c.GLFWwindow, x: f64, y: f64) callconv(.C) void { + fn cursorPosition(_: ?*c.GLFWwindow, x: f64, y: f64) callconv(.c) void { const newPos = Vec2f{ @floatCast(x), @floatCast(y), @@ -509,7 +509,7 @@ pub const GLFWCallbacks = struct { // MARK: GLFWCallbacks currentPos = newPos; lastUsedMouse = true; } - fn mouseButton(_: ?*c.GLFWwindow, button: c_int, action: c_int, _mods: c_int) callconv(.C) void { + fn mouseButton(_: ?*c.GLFWwindow, button: c_int, action: c_int, _mods: c_int) callconv(.c) void { const mods: Key.Modifiers = @bitCast(@as(u6, @intCast(_mods))); const isGrabbed = grabbed; if(action == c.GLFW_PRESS or action == c.GLFW_RELEASE) { @@ -526,11 +526,11 @@ pub const GLFWCallbacks = struct { // MARK: GLFWCallbacks } } } - fn scroll(_: ?*c.GLFWwindow, xOffset: f64, yOffset: f64) callconv(.C) void { + fn scroll(_: ?*c.GLFWwindow, xOffset: f64, yOffset: f64) callconv(.c) void { _ = xOffset; scrollOffset += @floatCast(yOffset); } - fn glDebugOutput(source: c_uint, typ: c_uint, _: c_uint, severity: c_uint, length: c_int, message: [*c]const u8, _: ?*const anyopaque) callconv(.C) void { + fn glDebugOutput(source: c_uint, typ: c_uint, _: c_uint, severity: c_uint, length: c_int, message: [*c]const u8, _: ?*const anyopaque) callconv(.c) void { const sourceString: []const u8 = switch(source) { c.GL_DEBUG_SOURCE_API => "API", c.GL_DEBUG_SOURCE_APPLICATION => "Application", diff --git a/src/gui/components/TextInput.zig b/src/gui/components/TextInput.zig index 3c1da3cf..9172f8d1 100644 --- a/src/gui/components/TextInput.zig +++ b/src/gui/components/TextInput.zig @@ -168,12 +168,12 @@ fn moveCursorLeft(self: *TextInput, mods: main.Window.Key.Modifiers) void { if(self.cursor.? == 0) return; self.cursor.? -= 1; // Find end of previous "word": - while(!std.ascii.isAlphabetic(text[self.cursor.?]) and std.ascii.isASCII(text[self.cursor.?])) { + while(!std.ascii.isAlphabetic(text[self.cursor.?]) and std.ascii.isAscii(text[self.cursor.?])) { if(self.cursor.? == 0) return; self.cursor.? -= 1; } // Find the start of the previous "word": - while(std.ascii.isAlphabetic(text[self.cursor.?]) or !std.ascii.isASCII(text[self.cursor.?])) { + while(std.ascii.isAlphabetic(text[self.cursor.?]) or !std.ascii.isAscii(text[self.cursor.?])) { if(self.cursor.? == 0) return; self.cursor.? -= 1; } @@ -213,12 +213,12 @@ fn moveCursorRight(self: *TextInput, mods: main.Window.Key.Modifiers) void { if(mods.control) { const text = self.currentString.items; // Find start of next "word": - while(!std.ascii.isAlphabetic(text[self.cursor.?]) and std.ascii.isASCII(text[self.cursor.?])) { + while(!std.ascii.isAlphabetic(text[self.cursor.?]) and std.ascii.isAscii(text[self.cursor.?])) { self.cursor.? += 1; if(self.cursor.? >= self.currentString.items.len) return; } // Find the end of the next "word": - while(std.ascii.isAlphabetic(text[self.cursor.?]) or !std.ascii.isASCII(text[self.cursor.?])) { + while(std.ascii.isAlphabetic(text[self.cursor.?]) or !std.ascii.isAscii(text[self.cursor.?])) { self.cursor.? += 1; if(self.cursor.? >= self.currentString.items.len) return; } diff --git a/src/gui/windows/invite.zig b/src/gui/windows/invite.zig index 4bb5257d..35eb80bd 100644 --- a/src/gui/windows/invite.zig +++ b/src/gui/windows/invite.zig @@ -30,7 +30,7 @@ const width: f32 = 420; fn discoverIpAddress() void { main.server.connectionManager.makeOnline(); - ipAddress = std.fmt.allocPrint(main.globalAllocator.allocator, "{}", .{main.server.connectionManager.externalAddress}) catch unreachable; + ipAddress = std.fmt.allocPrint(main.globalAllocator.allocator, "{f}", .{main.server.connectionManager.externalAddress}) catch unreachable; gotIpAddress.store(true, .release); } diff --git a/src/gui/windows/manage_players.zig b/src/gui/windows/manage_players.zig index 336dc863..f91895a4 100644 --- a/src/gui/windows/manage_players.zig +++ b/src/gui/windows/manage_players.zig @@ -41,7 +41,7 @@ pub fn onOpen() void { row.add(Label.init(.{0, 0}, 200, connection.user.?.name, .left)); row.add(Button.initText(.{0, 0}, 100, "Kick", .{.callback = @ptrCast(&kick), .arg = @intFromPtr(connection)})); } else { - const ip = std.fmt.allocPrint(main.stackAllocator.allocator, "{}", .{connection.remoteAddress}) catch unreachable; + const ip = std.fmt.allocPrint(main.stackAllocator.allocator, "{f}", .{connection.remoteAddress}) catch unreachable; defer main.stackAllocator.free(ip); row.add(Label.init(.{0, 0}, 200, ip, .left)); row.add(Button.initText(.{0, 0}, 100, "Cancel", .{.callback = @ptrCast(&kick), .arg = @intFromPtr(connection)})); diff --git a/src/gui/windows/multiplayer.zig b/src/gui/windows/multiplayer.zig index c2fa5915..c60a5751 100644 --- a/src/gui/windows/multiplayer.zig +++ b/src/gui/windows/multiplayer.zig @@ -34,7 +34,7 @@ fn discoverIpAddress() void { ipAddress = main.globalAllocator.dupe(u8, @errorName(err)); return; }; - ipAddress = std.fmt.allocPrint(main.globalAllocator.allocator, "{}", .{connection.?.externalAddress}) catch unreachable; + ipAddress = std.fmt.allocPrint(main.globalAllocator.allocator, "{f}", .{connection.?.externalAddress}) catch unreachable; gotIpAddress.store(true, .release); } diff --git a/src/gui/windows/save_selection.zig b/src/gui/windows/save_selection.zig index c2c1e7aa..d0d4906b 100644 --- a/src/gui/windows/save_selection.zig +++ b/src/gui/windows/save_selection.zig @@ -62,7 +62,7 @@ pub fn openWorld(name: []const u8) void { }; while(!main.server.running.load(.acquire)) { - std.time.sleep(1_000_000); + std.Thread.sleep(1_000_000); } clientConnection.world = &main.game.testWorld; const ipPort = std.fmt.allocPrint(main.stackAllocator.allocator, "127.0.0.1:{}", .{main.server.connectionManager.localPort}) catch unreachable; diff --git a/src/json.zig b/src/json.zig index 5a93c23f..9be4a0dc 100644 --- a/src/json.zig +++ b/src/json.zig @@ -265,11 +265,10 @@ pub const JsonElement = union(JsonType) { // MARK: JsonElement fn recurseToString(json: JsonElement, list: *List(u8), tabs: u32, comptime visualCharacters: bool) void { switch(json) { .JsonInt => |value| { - std.fmt.formatInt(value, 10, .lower, .{}, list.writer()) catch unreachable; + list.writer().print("{d}", .{value}) catch unreachable; }, .JsonFloat => |value| { - var buf: [std.fmt.format_float.bufferSize(.scientific, @TypeOf(value))]u8 = undefined; - list.appendSlice(std.fmt.format_float.formatFloat(&buf, value, .{.mode = .scientific}) catch unreachable); + list.writer().print("{e}", .{value}) catch unreachable; }, .JsonBool => |value| { if(value) { diff --git a/src/main.zig b/src/main.zig index 5c2f5e8b..094b5159 100644 --- a/src/main.zig +++ b/src/main.zig @@ -231,7 +231,7 @@ fn initLogging() void { return; }; - supportsANSIColors = std.io.getStdOut().supportsAnsiEscapeCodes(); + supportsANSIColors = std.fs.File.stdout().supportsAnsiEscapeCodes(); } fn deinitLogging() void { @@ -264,7 +264,9 @@ fn logToStdErr(comptime format: []const u8, args: anytype) void { const string = std.fmt.allocPrint(allocator, format, args) catch format; defer allocator.free(string); - nosuspend std.io.getStdErr().writeAll(string) catch {}; + const writer = std.debug.lockStderrWriter(&.{}); + defer std.debug.unlockStderrWriter(); + nosuspend writer.writeAll(string) catch {}; } // MARK: Callbacks @@ -682,7 +684,7 @@ pub fn main() void { // MARK: main() c.glClear(c.GL_DEPTH_BUFFER_BIT | c.GL_STENCIL_BUFFER_BIT | c.GL_COLOR_BUFFER_BIT); gui.windowlist.gpu_performance_measuring.stopQuery(); } else { - std.time.sleep(16_000_000); + std.Thread.sleep(16_000_000); } const endRendering = std.time.nanoTimestamp(); @@ -696,7 +698,7 @@ pub fn main() void { // MARK: main() if(settings.fpsCap) |fpsCap| { const minFrameTime = @divFloor(1000*1000*1000, fpsCap); const sleep = @min(minFrameTime, @max(0, minFrameTime - (endRendering -% lastBeginRendering))); - std.time.sleep(sleep); + std.Thread.sleep(sleep); } const begin = std.time.nanoTimestamp(); const deltaTime = @as(f64, @floatFromInt(begin -% lastBeginRendering))/1e9; diff --git a/src/network.zig b/src/network.zig index b3c4c798..98f3f170 100644 --- a/src/network.zig +++ b/src/network.zig @@ -64,10 +64,19 @@ const Socket = struct { .port = @byteSwap(destination.port), .addr = destination.ip, }; - std.debug.assert(data.len == posix.sendto(self.socketID, data, 0, @ptrCast(&addr), @sizeOf(posix.sockaddr.in)) catch |err| { - std.log.info("Got error while sending to {}: {s}", .{destination, @errorName(err)}); - return; - }); + if(builtin.os.tag == .windows) { // TODO: Upstream error, fix after next Zig update after #24466 is merged + const result = posix.system.sendto(self.socketID, data.ptr, data.len, 0, @ptrCast(&addr), @sizeOf(posix.sockaddr.in)); + if(result < 0) { + std.log.info("Got error while sending to {f}: {s}", .{destination, @tagName(std.os.windows.ws2_32.WSAGetLastError())}); + } else { + std.debug.assert(@as(usize, @intCast(result)) == data.len); + } + } else { + std.debug.assert(data.len == posix.sendto(self.socketID, data, 0, @ptrCast(&addr), @sizeOf(posix.sockaddr.in)) catch |err| { + std.log.info("Got error while sending to {f}: {s}", .{destination, @errorName(err)}); + return; + }); + } } fn receive(self: Socket, buffer: []u8, timeout: i32, resultAddress: *Address) ![]u8 { @@ -85,7 +94,7 @@ const Socket = struct { else => |err| return std.os.windows.unexpectedWSAError(err), } } else if(length == 0) { - std.time.sleep(1000000); // Manually sleep, since WSAPoll is blocking. + std.Thread.sleep(1000000); // Manually sleep, since WSAPoll is blocking. return error.Timeout; } } else { @@ -139,7 +148,7 @@ pub const Address = struct { pub const localHost = 0x0100007f; - pub fn format(self: Address, _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + pub fn format(self: Address, writer: anytype) !void { if(self.isSymmetricNAT) { try writer.print("{}.{}.{}.{}:?{}", .{self.ip & 255, self.ip >> 8 & 255, self.ip >> 16 & 255, self.ip >> 24, self.port}); } else { @@ -295,7 +304,7 @@ const STUN = struct { // MARK: STUN continue; }; if(oldAddress) |other| { - std.log.info("{}", .{result}); + std.log.info("{f}", .{result}); if(other.ip == result.ip and other.port == result.port) { return result; } else { @@ -556,17 +565,17 @@ pub const ConnectionManager = struct { // MARK: ConnectionManager } if(self.allowNewConnections.load(.monotonic) or source.ip == Address.localHost) { if(data.len != 0 and data[0] == @intFromEnum(Connection.ChannelId.init)) { - const ip = std.fmt.allocPrint(main.stackAllocator.allocator, "{}", .{source}) catch unreachable; + const ip = std.fmt.allocPrint(main.stackAllocator.allocator, "{f}", .{source}) catch unreachable; defer main.stackAllocator.free(ip); const user = main.server.User.initAndIncreaseRefCount(main.server.connectionManager, ip) catch |err| { - std.log.err("Cannot connect user from external IP {}: {s}", .{source, @errorName(err)}); + std.log.err("Cannot connect user from external IP {f}: {s}", .{source, @errorName(err)}); return; }; user.decreaseRefCount(); } } else { // TODO: Reduce the number of false alarms in the short period after a disconnect. - std.log.warn("Unknown connection from address: {}", .{source}); + std.log.warn("Unknown connection from address: {f}", .{source}); std.log.debug("Message: {any}", .{data}); } } @@ -2025,7 +2034,7 @@ pub const Connection = struct { // MARK: Connection self.tryReceive(data) catch |err| { std.log.err("Got error while processing received network data: {s}", .{@errorName(err)}); if(@errorReturnTrace()) |trace| { - std.log.info("{}", .{trace}); + std.log.info("{f}", .{trace}); } self.disconnect(); }; @@ -2218,7 +2227,7 @@ pub const Connection = struct { // MARK: Connection self.manager.send(&.{@intFromEnum(ChannelId.disconnect)}, self.remoteAddress, null); self.connectionState.store(.disconnectDesired, .unordered); if(builtin.os.tag == .windows and !self.isServerSide() and main.server.world != null) { - std.time.sleep(10000000); // Windows is too eager to close the socket, without waiting here we get a ConnectionResetByPeer on the other side. + std.Thread.sleep(10000000); // Windows is too eager to close the socket, without waiting here we get a ConnectionResetByPeer on the other side. } self.manager.removeConnection(self); if(self.user) |user| { diff --git a/src/renderer/chunk_meshing.zig b/src/renderer/chunk_meshing.zig index 1d0b7741..8f525d92 100644 --- a/src/renderer/chunk_meshing.zig +++ b/src/renderer/chunk_meshing.zig @@ -1717,7 +1717,7 @@ pub const ChunkMesh = struct { // MARK: ChunkMesh } self.culledSortingCount += @intCast(self.blockBreakingFaces.items.len); // Upload: - faceBuffers[std.math.log2_int(u32, self.pos.voxelSize)].uploadData(self.sortingOutputBuffer[0..self.culledSortingCount], &self.transparentMesh.bufferAllocation); + faceBuffers[self.transparentMesh.lod].uploadData(self.sortingOutputBuffer[0..self.culledSortingCount], &self.transparentMesh.bufferAllocation); self.uploadChunkPosition(); } diff --git a/src/server/server.zig b/src/server/server.zig index 9c31e878..ff87fe23 100644 --- a/src/server/server.zig +++ b/src/server/server.zig @@ -444,7 +444,7 @@ pub fn start(name: []const u8, port: ?u16) void { while(running.load(.monotonic)) { const newTime = std.time.nanoTimestamp(); if(newTime -% lastTime < updateNanoTime) { - std.time.sleep(@intCast(lastTime +% updateNanoTime -% newTime)); + std.Thread.sleep(@intCast(lastTime +% updateNanoTime -% newTime)); lastTime +%= updateNanoTime; } else { std.log.warn("The server is lagging behind by {d:.1} ms", .{@as(f32, @floatFromInt(newTime -% lastTime -% updateNanoTime))/1000000.0}); diff --git a/src/server/storage.zig b/src/server/storage.zig index 8e8a50fd..bcba8115 100644 --- a/src/server/storage.zig +++ b/src/server/storage.zig @@ -48,7 +48,7 @@ pub const RegionFile = struct { // MARK: RegionFile defer main.stackAllocator.free(data); self.load(path, data) catch { std.log.err("Corrupted region file: {s}", .{path}); - if(@errorReturnTrace()) |trace| std.log.info("{}", .{trace}); + if(@errorReturnTrace()) |trace| std.log.info("{f}", .{trace}); }; return self; } diff --git a/src/server/world.zig b/src/server/world.zig index 501ae1e5..896914cb 100644 --- a/src/server/world.zig +++ b/src/server/world.zig @@ -751,7 +751,7 @@ pub const ServerWorld = struct { // MARK: ServerWorld updateRequest.region.decreaseRefCount(); } self.mutex.unlock(); - std.time.sleep(1_000_000); + std.Thread.sleep(1_000_000); self.mutex.lock(); if(main.threadPool.queueSize() == 0 and self.chunkUpdateQueue.peek() == null and self.regionUpdateQueue.peek() == null) break; } diff --git a/src/utils.zig b/src/utils.zig index 33c9621d..28794083 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -655,7 +655,7 @@ pub fn BlockingMaxHeap(comptime T: type) type { // MARK: BlockingMaxHeap self.waitingThreads.broadcast(); while(self.waitingThreadCount != 0) { self.mutex.unlock(); - std.time.sleep(1000000); + std.Thread.sleep(1000000); self.mutex.lock(); } self.mutex.unlock(); @@ -899,7 +899,7 @@ pub const ThreadPool = struct { // MARK: ThreadPool // Wait for active tasks: for(self.currentTasks) |*task| { while(task.load(.monotonic) == vtable) { - std.time.sleep(1e6); + std.Thread.sleep(1e6); } } } @@ -966,7 +966,7 @@ pub const ThreadPool = struct { // MARK: ThreadPool break; } } - std.time.sleep(1000000); + std.Thread.sleep(1000000); } } @@ -998,7 +998,7 @@ pub fn DynamicPackedIntArray(size: comptime_int) type { // MARK: DynamicPackedIn pub fn initCapacity(bitSize: u5) Self { std.debug.assert(bitSize == 0 or bitSize & bitSize - 1 == 0); // Must be a power of 2 return .{ - .data = dynamicIntArrayAllocator.allocator().alignedAlloc(u32, 64, @as(usize, @divExact(size, @bitSizeOf(u32)))*bitSize), + .data = dynamicIntArrayAllocator.allocator().alignedAlloc(u32, .@"64", @as(usize, @divExact(size, @bitSizeOf(u32)))*bitSize), .bitSize = bitSize, }; } diff --git a/src/utils/file_monitor.zig b/src/utils/file_monitor.zig index 887b91e5..7ba4ec83 100644 --- a/src/utils/file_monitor.zig +++ b/src/utils/file_monitor.zig @@ -98,7 +98,7 @@ const LinuxImpl = struct { // MARK: LinuxImpl return; }) |entry| { if(entry.kind == .directory) { - const subPath = std.fmt.allocPrintZ(main.stackAllocator.allocator, "{s}/{s}", .{path, entry.name}) catch unreachable; + const subPath = std.fmt.allocPrintSentinel(main.stackAllocator.allocator, "{s}/{s}", .{path, entry.name}, 0) catch unreachable; defer main.stackAllocator.free(subPath); addWatchDescriptor(info, subPath); addWatchDescriptorsRecursive(info, subPath); diff --git a/src/utils/heap.zig b/src/utils/heap.zig index 6903ca85..90540742 100644 --- a/src/utils/heap.zig +++ b/src/utils/heap.zig @@ -17,7 +17,7 @@ pub const StackAllocator = struct { // MARK: StackAllocator pub fn init(backingAllocator: NeverFailingAllocator, size: u31) StackAllocator { return .{ .backingAllocator = backingAllocator, - .buffer = backingAllocator.alignedAlloc(u8, 4096, size), + .buffer = backingAllocator.alignedAlloc(u8, .fromByteUnits(4096), size), .index = 0, }; } @@ -341,9 +341,9 @@ pub const NeverFailingAllocator = struct { // MARK: NeverFailingAllocator self: NeverFailingAllocator, comptime T: type, /// null means naturally aligned - comptime alignment: ?u29, + comptime alignment: ?Alignment, n: usize, - ) []align(alignment orelse @alignOf(T)) T { + ) []align(if(alignment) |a| a.toByteUnits() else @alignOf(T)) T { return self.allocator.alignedAlloc(T, alignment, n) catch unreachable; } @@ -351,10 +351,10 @@ pub const NeverFailingAllocator = struct { // MARK: NeverFailingAllocator self: NeverFailingAllocator, comptime T: type, /// null means naturally aligned - comptime alignment: ?u29, + comptime alignment: ?Alignment, n: usize, return_address: usize, - ) []align(alignment orelse @alignOf(T)) T { + ) []align(if(alignment) |a| a.toByteUnits() else @alignOf(T)) T { return self.allocator.allocAdvancedWithRetAddr(T, alignment, n, return_address) catch unreachable; } @@ -483,6 +483,7 @@ pub const NeverFailingArenaAllocator = struct { // MARK: NeverFailingArena } pub fn shrinkAndFree(self: *NeverFailingArenaAllocator) void { + if(true) return; const node = self.arena.state.buffer_list.first orelse return; const allocBuf = @as([*]u8, @ptrCast(node))[0..node.data]; const dataSize = std.mem.alignForward(usize, @sizeOf(std.SinglyLinkedList(usize).Node) + self.arena.state.end_index, @alignOf(std.SinglyLinkedList(usize).Node)); @@ -570,7 +571,7 @@ pub fn MemoryPool(Item: type) type { // MARK: MemoryPool main.utils.assertLocked(&pool.mutex); pool.totalAllocations += 1; pool.freeAllocations += 1; - const mem = pool.arena.allocator().alignedAlloc(u8, item_alignment, item_size); + const mem = pool.arena.allocator().alignedAlloc(u8, .fromByteUnits(item_alignment), item_size); return mem[0..item_size]; // coerce slice to array pointer } }; @@ -634,7 +635,7 @@ pub fn PowerOfTwoPoolAllocator(minSize: comptime_int, maxSize: comptime_int, max fn allocNew(self: *Bucket, arena: NeverFailingAllocator, size: usize) [*]align(alignment) u8 { self.totalAllocations += 1; self.freeAllocations += 1; - return arena.alignedAlloc(u8, alignment, size).ptr; + return arena.alignedAlloc(u8, .fromByteUnits(alignment), size).ptr; } }; diff --git a/src/utils/list.zig b/src/utils/list.zig index 59c7e7bf..e6dae735 100644 --- a/src/utils/list.zig +++ b/src/utils/list.zig @@ -213,7 +213,7 @@ pub fn List(comptime T: type) type { @compileError("The Writer interface is only defined for ArrayList(u8) " ++ "but the given type is ArrayList(" ++ @typeName(T) ++ ")") else - std.io.Writer(*@This(), error{}, appendWrite); + std.io.GenericWriter(*@This(), error{}, appendWrite); pub fn writer(self: *@This()) Writer { return .{.context = self}; diff --git a/src/zon.zig b/src/zon.zig index d49e5623..36c05040 100644 --- a/src/zon.zig +++ b/src/zon.zig @@ -351,11 +351,10 @@ pub const ZonElement = union(enum) { // MARK: Zon fn recurseToString(zon: ZonElement, list: *List(u8), tabs: u32, comptime visualCharacters: bool) void { switch(zon) { .int => |value| { - std.fmt.formatInt(value, 10, .lower, .{}, list.writer()) catch unreachable; + list.writer().print("{d}", .{value}) catch unreachable; }, .float => |value| { - var buf: [std.fmt.format_float.bufferSize(.scientific, @TypeOf(value))]u8 = undefined; - list.appendSlice(std.fmt.format_float.formatFloat(&buf, value, .{.mode = .scientific}) catch unreachable); + list.writer().print("{e}", .{value}) catch unreachable; }, .bool => |value| { if(value) { diff --git a/test/runner.zig b/test/runner.zig index 23c1120d..11f1b2ff 100644 --- a/test/runner.zig +++ b/test/runner.zig @@ -1,5 +1,5 @@ -//! Default test runner for unit tests. // Source: https://github.com/ziglang/zig/blob/0.14.0/lib/compiler/test_runner.zig +//! Default test runner for unit tests. const builtin = @import("builtin"); const std = @import("std"); @@ -16,7 +16,9 @@ var fba_buffer: [8192]u8 = undefined; var fba = std.heap.FixedBufferAllocator.init(&fba_buffer); const crippled = switch(builtin.zig_backend) { - .stage2_riscv64 => true, + .stage2_powerpc, + .stage2_riscv64, + => true, else => false, }; @@ -68,8 +70,8 @@ fn mainServer() !void { @disableInstrumentation(); var server = try std.zig.Server.init(.{ .gpa = fba.allocator(), - .in = std.io.getStdIn(), - .out = std.io.getStdOut(), + .in = .stdin(), + .out = .stdout(), .zig_version = builtin.zig_version_string, }); defer server.deinit(); @@ -189,7 +191,7 @@ fn mainTerminal() void { .root_name = "Test", .estimated_total_items = test_fn_list.len, }); - const doColors = std.io.getStdErr().supportsAnsiEscapeCodes(); + const doColors = std.fs.File.stderr().supportsAnsiEscapeCodes(); const reset = if(doColors) "\x1b[0m" else ""; const red = if(doColors) "\x1b[31m" else ""; const yellow = if(doColors) "\x1b[33m" else ""; @@ -283,6 +285,7 @@ pub fn mainSimple() anyerror!void { }; // is the backend capable of using std.fmt.format to print a summary at the end? const print_summary = switch(builtin.zig_backend) { + .stage2_riscv64 => true, else => false, }; @@ -291,7 +294,7 @@ pub fn mainSimple() anyerror!void { var failed: u64 = 0; // we don't want to bring in File and Writer if the backend doesn't support it - const stderr = if(comptime enable_print) std.io.getStdErr() else {}; + const stderr = if(comptime enable_print) std.fs.File.stderr() else {}; for(builtin.test_functions) |test_fn| { if(test_fn.func()) |_| { @@ -300,7 +303,7 @@ pub fn mainSimple() anyerror!void { stderr.writeAll("... ") catch {}; stderr.writeAll("PASS\n") catch {}; } - } else |err| if(enable_print) { + } else |err| { if(enable_print) { stderr.writeAll(test_fn.name) catch {}; stderr.writeAll("... ") catch {}; @@ -318,7 +321,7 @@ pub fn mainSimple() anyerror!void { passed += 1; } if(enable_print and print_summary) { - stderr.writer().print("{} passed, {} skipped, {} failed\n", .{passed, skipped, failed}) catch {}; + stderr.deprecatedWriter().print("{} passed, {} skipped, {} failed\n", .{passed, skipped, failed}) catch {}; } if(failed != 0) std.process.exit(1); } @@ -343,7 +346,7 @@ var is_fuzz_test: bool = undefined; extern fn fuzzer_set_name(name_ptr: [*]const u8, name_len: usize) void; extern fn fuzzer_init(cache_dir: FuzzerSlice) void; extern fn fuzzer_init_corpus_elem(input_ptr: [*]const u8, input_len: usize) void; -extern fn fuzzer_start(testOne: *const fn([*]const u8, usize) callconv(.C) void) void; +extern fn fuzzer_start(testOne: *const fn([*]const u8, usize) callconv(.c) void) void; extern fn fuzzer_coverage_id() u64; pub fn fuzz( @@ -375,7 +378,7 @@ pub fn fuzz( const global = struct { var ctx: @TypeOf(context) = undefined; - fn fuzzer_one(input_ptr: [*]const u8, input_len: usize) callconv(.C) void { + fn fuzzer_one(input_ptr: [*]const u8, input_len: usize) callconv(.c) void { @disableInstrumentation(); testing.allocator_instance = .{}; defer if(testing.allocator_instance.deinit() == .leak) std.process.exit(1);