From 3b8ea60141259d6f4e482b2c0352e520dc8a6328 Mon Sep 17 00:00:00 2001 From: luccie Date: Mon, 11 Aug 2025 23:07:52 +0200 Subject: [PATCH] [MODS/VM]: Get calls to deinit working and call deinit on sideros_cleanup --- assets/mods/core.tar | Bin 10240 -> 10240 bytes src/mods/Parser.zig | 5 +++ src/mods/vm.zig | 9 ++++ src/mods/wasm.zig | 7 --- src/sideros.zig | 103 +++++++++++++++++++++++++++---------------- 5 files changed, 80 insertions(+), 44 deletions(-) diff --git a/assets/mods/core.tar b/assets/mods/core.tar index b44f5d051a12def0c2f9a755c40f8d5d9a203dcb..d34f5f87fdd50bf0d42aad64af3849a817e1ba4f 100644 GIT binary patch delta 120 zcmZn&Xb70lDq(KGU}$P!VrF7wYHno8U|?uuY;4Y;U@+N`F=aC&BL|}c7gGXbJ!4%0 z17jUCGZOEa502?Pz%(0>200TF>6f;|HYHof}B@+WnW?p6q0|Q%1Dwx5@wSkdo TvNh8xRu%>)2JX!tnK)Dd?-v<< delta 103 zcmZn&Xb70lDq&*EU}$P!VrFb=Xl`P}U|?uuY;4A$U@+N`F=aC&BL|}q8)E`vJ!2g+ z6C(pFGb4il8z+$K*wAo*fty{Bi7huZH@~QoiGd|EFSCS!fonA*<77{!Rht=^|Eo+? GkO2T-krsad diff --git a/src/mods/Parser.zig b/src/mods/Parser.zig index 1b6c1c0..63ba62c 100644 --- a/src/mods/Parser.zig +++ b/src/mods/Parser.zig @@ -330,6 +330,9 @@ pub fn parseModule(self: *Parser) !void { if (self.exports.init != null and self.exports.init.? != 0){ self.exports.init.? -= self.importCount; } + if (self.exports.deinit != null and self.exports.deinit.? != 0){ + self.exports.deinit.? -= self.importCount; + } } fn parseCustomsec(self: *Parser) !void { @@ -559,6 +562,8 @@ fn parseExportsec(self: *Parser) !void { .func => { if (std.mem.eql(u8, e.name, "init")) { self.exports.init = e.exportdesc.func + self.importCount; + } else if (std.mem.eql(u8, e.name, "deinit")) { + self.exports.deinit = e.exportdesc.func + self.importCount; } else { std.log.warn("exported function {s} not supported\n", .{e.name}); } diff --git a/src/mods/vm.zig b/src/mods/vm.zig index d291ae4..0ed0530 100644 --- a/src/mods/vm.zig +++ b/src/mods/vm.zig @@ -34,6 +34,7 @@ pub const Function = struct { func_type: Functype, typ: union(enum) { pub const ExportFunction = enum { init, + deinit, logErr, logWarn, logInfo, @@ -41,6 +42,7 @@ pub const ExportFunction = enum { }; pub const Exports = struct { init: ?u32 = null, + deinit: ?u32 = null, logErr: ?u32 = null, logWarn: ?u32 = null, logInfo: ?u32 = null, @@ -647,6 +649,13 @@ pub const Runtime = struct { std.debug.panic("Function init unavailable\n", .{}); } }, + .deinit => { + if (self.module.exports.deinit) |func| { + try self.call(allocator, func, parameters); + } else { + std.debug.panic("Function deinit unavailable\n", .{}); + } + }, else => { std.debug.panic("Function {any} not handled\n", .{name}); }, diff --git a/src/mods/wasm.zig b/src/mods/wasm.zig index 5b68c6c..1fa00d4 100644 --- a/src/mods/wasm.zig +++ b/src/mods/wasm.zig @@ -12,28 +12,21 @@ pub const Type = enum(u8) { }; pub const GlobalRuntime = struct { - functions: std.StringHashMap(*const fn (stack: *std.ArrayList(vm.Value)) void), globals: std.AutoHashMap(u32, Parser.Globaltype), globalExprs: std.AutoHashMap(u32, vm.Value), pub fn init(allocator: Allocator) GlobalRuntime { return GlobalRuntime{ - .functions = std.StringHashMap(*const fn (stack: *std.ArrayList(vm.Value)) void).init(allocator), .globals = std.AutoHashMap(u32, Parser.Globaltype).init(allocator), .globalExprs = std.AutoHashMap(u32, vm.Value).init(allocator) }; } pub fn deinit(self: *GlobalRuntime) void { - self.functions.deinit(); self.globals.deinit(); self.globalExprs.deinit(); } - pub fn addFunction(self: *GlobalRuntime, name: []const u8, function: *const fn (stack: *std.ArrayList(vm.Value)) void) !void { - try self.functions.put(name, function); - } - pub fn addGlobal(self: *GlobalRuntime, index: u32, @"type": Parser.Globaltype, initValue: vm.Value) !void { try self.globals.put(index, @"type"); try self.globalExprs.put(index, initValue); diff --git a/src/sideros.zig b/src/sideros.zig index 03c8f98..6069430 100644 --- a/src/sideros.zig +++ b/src/sideros.zig @@ -23,7 +23,7 @@ var input: ecs.Input = .{ .key_pressed = .{false} ** @intFromEnum(ecs.Input.KeyC var resources: ecs.Resources = undefined; const ModInfo = struct { name: []const u8, - runtime: mods.Runtime, + runtime: *mods.Runtime, modIdx: u32, }; var loadedMods: std.ArrayListUnmanaged(ModInfo) = .{}; @@ -42,20 +42,72 @@ fn openOrCreateDir(fs: std.fs.Dir, path: []const u8) !std.fs.Dir { return dir; } -fn untarToDirAndGetFile(fs: std.fs.Dir, name: []const u8) !std.fs.File { - var modDir = try openOrCreateDir(fs,name); - defer modDir.close(); +fn untarToDirAndGetFile(fs: std.fs.Dir, name: []const u8, unpack: []const u8) !std.fs.File { var buffer: [1024]u8 = undefined; + var modDir = try openOrCreateDir(fs,unpack); + defer modDir.close(); var tarFile = try fs.openFile(try std.fmt.bufPrint(&buffer, "{s}.tar", .{name}), .{}); defer tarFile.close(); const tarData = try tarFile.readToEndAlloc(allocator, 1_000_000); + defer allocator.free(tarData); var tarReader = std.io.Reader.fixed(tarData); try std.tar.pipeToFileSystem(modDir, &tarReader, .{}); - return try fs.openFile(try std.fmt.bufPrint(&buffer, "{s}/main.wasm", .{name}), .{}); + return try fs.openFile(try std.fmt.bufPrint(&buffer, "{s}/main.wasm", .{unpack}), .{}); +} + +fn loadMod(entry: std.fs.Dir.Entry) !void { + const modName = entry.name.ptr[0..entry.name.len - 4]; + const fullDir = std.fmt.allocPrint(allocator, "assets/mods/{s}", .{modName}) catch @panic("Failed to allocate for fullDir"); + defer allocator.free(fullDir); + const modDir = try std.fmt.allocPrint(allocator, "{s}_siderosmod__", .{fullDir}); + const global_runtime = allocator.create(mods.GlobalRuntime) catch @panic("Failed to create global runtime"); + global_runtime.* = mods.GlobalRuntime.init(allocator); + + std.fs.cwd().deleteTree(modDir) catch |err| { + std.debug.panic("Failed to delete {s} (reason: {any})", .{modDir, err}); + }; + var file = untarToDirAndGetFile(std.fs.cwd(), fullDir, modDir) catch |err| { + return err; + }; + defer std.fs.cwd().deleteTree(modDir) catch |err| { + std.debug.panic("Failed to delete {s} (reason: {any})", .{modDir, err}); + }; + defer file.close(); + const all = file.readToEndAlloc(allocator, 1_000_000) catch @panic("Unable to read main file"); + defer allocator.free(all); + var parser = mods.Parser.init(allocator, all) catch @panic("Failed to init parser"); + defer parser.deinit(); + parser.parseModule() catch |err| { + std.debug.print("[ERROR]: error {any} at byte {x}(0x{x})\n", .{ err, parser.byte_idx, parser.bytes[parser.byte_idx] }); + return err; + }; + const module = parser.module(); + + for (0..parser.globalTypes.len) |i| { + global_runtime.addGlobal(@intCast(i), parser.globalTypes[i], parser.globalValues[i]) catch @panic("Failed to add runtime global"); + } + + var runtime = allocator.create(mods.Runtime) catch |err| { + std.debug.print("Failed to create runtime", .{}); + return err; + }; + runtime.* = mods.Runtime.init(allocator, module, global_runtime) catch |err| { + std.debug.print("Failed to init runtime", .{}); + return err; + }; + + const modIdx: u32 = @intCast(loadedMods.items.len); + var parameters = [_]mods.VM.Value{.{ .i32 = @intCast(modIdx) }}; + runtime.externalCall(allocator, .init, ¶meters) catch @panic("Failed to call to init"); + const result = runtime.stack.pop().?.i64; + if (result != 0){ + std.debug.print("[ERROR]: Mod {s} init returned {d}\n", .{modName, result}); + return error.Failure; + } + loadedMods.append(allocator, .{.name = try allocator.dupe(u8, modName), .runtime = runtime, .modIdx = modIdx}) catch @panic("Failed to append to loadedMods"); } fn init_mods() void { - var modsDir = std.fs.cwd().openDir("./assets/mods", .{.iterate = true}) catch @panic("Failed to open assets/mods"); defer modsDir.close(); @@ -69,33 +121,7 @@ fn init_mods() void { std.debug.print("[WARNING]: Found non tar extension in mods directory\n", .{}); continue; } - const fullDir = std.fmt.allocPrint(allocator, "assets/mods/{s}", .{entry.name.ptr[0..entry.name.len - 4]}) catch @panic("Failed to allocate for fullDir"); - var global_runtime = mods.GlobalRuntime.init(allocator); - - var file = untarToDirAndGetFile(std.fs.cwd(), fullDir) catch @panic("Failed to load mod"); - defer file.close(); - const all = file.readToEndAlloc(allocator, 1_000_000) catch @panic("Unable to read main file"); - defer allocator.free(all); - var parser = mods.Parser.init(allocator, all) catch @panic("Failed to init parser"); - defer parser.deinit(); - parser.parseModule() catch |err| { - std.debug.panic("[ERROR]: error {any} at byte {x}(0x{x})\n", .{ err, parser.byte_idx, parser.bytes[parser.byte_idx] }); - }; - const module = parser.module(); - - for (0..parser.globalTypes.len) |i| { - global_runtime.addGlobal(@intCast(i), parser.globalTypes[i], parser.globalValues[i]) catch @panic("Failed to add runtime global"); - } - - var runtime = mods.Runtime.init(allocator, module, &global_runtime) catch @panic("Failed to init runtime"); - - const modIdx: u32 = @intCast(loadedMods.items.len); - var parameters = [_]mods.VM.Value{.{ .i32 = @intCast(modIdx) }}; - runtime.externalCall(allocator, .init, ¶meters) catch @panic("Failed to call to init"); - const result = runtime.stack.pop().?; - std.debug.print("Result of {s} init: {any}\n", .{fullDir, result}); - loadedMods.append(allocator, .{.name = fullDir, .runtime = runtime, .modIdx = modIdx}) catch @panic("Failed to append to loadedMods"); - std.fs.cwd().deleteTree(fullDir) catch std.debug.panic("Failed to delete {s}", .{fullDir}); + loadMod(entry) catch @panic("Failed to load mod"); } } @@ -123,10 +149,13 @@ export fn sideros_update(gameUpdate: api.GameUpdate) callconv(.c) void { export fn sideros_cleanup() callconv(.c) void { for (loadedMods.items) |info| { var runtime = info.runtime; - // runtime.externalCall(allocator, .deinit, &.{}); - // const result = runtime.stack.pop().?; - // std.debug.print("Result of {s} init: {any}\n", .{info.name, result}); - runtime.deinit(allocator); + runtime.externalCall(allocator, .deinit, &.{}) catch @panic("Failed to call deinit"); + const result = runtime.stack.pop().?.i64; + if (result != 0){ + std.debug.panic("[ERROR]: Mod {s} deinit returned {d}\n", .{info.name, result}); + } + defer runtime.deinit(allocator); + defer allocator.free(info.name); } loadedMods.deinit(allocator); renderer.deinit();