From 35562ab6d7db0500b2191377ceccafe53edf0919 Mon Sep 17 00:00:00 2001 From: Peter Li Date: Sun, 2 Nov 2025 00:44:21 -0700 Subject: [PATCH] saving --- engine/core/build.zig | 1 + engine/core/src/core.zig | 2 + engine/core/src/machinery/machinery.zig | 56 +++++++++++++++++++ engine/core/tests/SceneApiHand.zig | 26 +++++++++ engine/core/tests/exampleScene.zig | 43 ++++++++++++++ engine/core/tests/externalModule.zig | 20 +++++-- engine/core/tests/samplesubsystem.zig | 24 ++++++++ engine/core/tests/testmodule.zig | 12 ++++ engine/core/tests/tests.zig | 15 ++++- projects/sampleGame/externGame/externGame.zig | 2 + 10 files changed, 194 insertions(+), 7 deletions(-) create mode 100644 engine/core/src/machinery/machinery.zig create mode 100644 engine/core/tests/SceneApiHand.zig create mode 100644 engine/core/tests/exampleScene.zig create mode 100644 engine/core/tests/samplesubsystem.zig create mode 100644 engine/core/tests/testmodule.zig diff --git a/engine/core/build.zig b/engine/core/build.zig index 55d98ed..b9d564a 100644 --- a/engine/core/build.zig +++ b/engine/core/build.zig @@ -42,6 +42,7 @@ pub fn build(b: *std.Build) void { .linkage = .dynamic, .name = "external", }); + sampleGameExtern.root_module.addImport("core", mod); const installExtern = b.addInstallArtifact(sampleGameExtern, .{ .dest_dir = .{ .override = .{ .custom = "modules" } }, diff --git a/engine/core/src/core.zig b/engine/core/src/core.zig index 9b0447f..1739f08 100644 --- a/engine/core/src/core.zig +++ b/engine/core/src/core.zig @@ -1,6 +1,8 @@ // main public facing root file for core const std = @import("std"); +pub const machinery = @import("machinery/machinery.zig"); + pub const gameObjectList = @import("utils/gameObjectList.zig"); pub const GameObjectList = gameObjectList.GameObjectList; pub const GameObjectInterface = gameObjectList.GameObjectInterface; diff --git a/engine/core/src/machinery/machinery.zig b/engine/core/src/machinery/machinery.zig new file mode 100644 index 0000000..f5a5466 --- /dev/null +++ b/engine/core/src/machinery/machinery.zig @@ -0,0 +1,56 @@ +pub const StructApi = struct { + fields: []const StructField, +}; + +pub const StructField = struct { + name: [:0]const u8, + offset: usize, + alignment: usize, + size: usize, +}; + +fn generateStructApi(comptime T: type) StructApi { + return .{ + .fields = &generateFieldsList(T), + }; +} + +fn generateFieldsList(comptime T: type) [std.meta.fields(T).len]StructField { + var flist: [std.meta.fields(T).len]StructField = undefined; + + const E = std.meta.FieldEnum(T); + + inline for (std.meta.fields(T)) |field| { + const fieldIndex = @intFromEnum(@field(E, field.name)); + + flist[fieldIndex].name = field.name; + flist[fieldIndex].size = @sizeOf(field.type); + flist[fieldIndex].alignment = @alignOf(field.type); + flist[fieldIndex].offset = @offsetOf(T, field.name); + } + + return flist; +} + +pub fn ComponentApi(comptime T: type) type { + return struct { + pub const Api = generateStructApi(T); + }; +} + +pub fn listApi(structApi: StructApi) void { + for (structApi.fields) |field| { + core.engine_log("field: {s} offset: {d} name: {d} size: {d}", field); + } +} + +// example function call via api +pub fn callInner(func: anytype, args: []const u8) void { + const Args = std.meta.ArgsTuple(@typeInfo(@TypeOf(func)).pointer.child); + + const asArgsTuple: *const Args = @ptrCast(@alignCast(args.ptr)); + @call(.auto, func, asArgsTuple.*); +} + +const std = @import("std"); +const core = @import("../core.zig"); diff --git a/engine/core/tests/SceneApiHand.zig b/engine/core/tests/SceneApiHand.zig new file mode 100644 index 0000000..b188da8 --- /dev/null +++ b/engine/core/tests/SceneApiHand.zig @@ -0,0 +1,26 @@ +// this is generated zig code. +pub const SceneAPI = struct { + pub const Api: machinery.StructApi = .{ + .fields = &.{ + .{ + .name = "handle", + .offset = 0, + .alignment = @alignOf(core.ObjectHandle), + .size = @sizeOf(core.ObjectHandle), + }, + .{ + .name = "testField", + .offset = 4, + .alignment = @alignOf(u32), + .size = @sizeOf(u32), + }, + }, + }; + + pub var setPosition: *const fn (*anyopaque, core.Vectorf) void = undefined; + pub const setPositionArgs = std.meta.ArgsTuple(@typeInfo(@TypeOf(setPosition)).pointer.child); +}; + +const core = @import("core"); +const machinery = core.machinery; +const std = @import("std"); diff --git a/engine/core/tests/exampleScene.zig b/engine/core/tests/exampleScene.zig new file mode 100644 index 0000000..d457f39 --- /dev/null +++ b/engine/core/tests/exampleScene.zig @@ -0,0 +1,43 @@ +pub const Scene = extern struct { + pub const ApiGen = machinery.ComponentApi(@This()); + + handle: core.ObjectHandle = .{}, + testField: u32 = 0, + position: core.Vectorf = .{}, + + pub fn init(self: *@This()) void { + _ = self; + } + + pub fn setPosition(self: *@This(), vector: core.Vectorf) void { + self.position = vector; + core.engine_log("position set: x={d} y={d} z={d}", self.position); + } + + pub fn deinit(self: *@This()) void { + _ = self; + } +}; + +const hand = @import("SceneApiHand.zig"); +const SceneAPI = hand.SceneAPI; + +pub fn doTest() !void { + machinery.listApi(SceneAPI.Api); + machinery.listApi(Scene.ApiGen.Api); + + var scene: Scene = .{}; + + // from this point on, we're larping like we're a different DLL that + // has no direct reference to the 'Scene' type + // load function pointers + SceneAPI.setPosition = @ptrCast(@alignCast(&Scene.setPosition)); + + // takes it as an opaque ptr + testmodule.callWithNoDirectLinking(&scene); +} + +const testmodule = @import("testmodule.zig"); +const core = @import("core"); +const machinery = core.machinery; +const std = @import("std"); diff --git a/engine/core/tests/externalModule.zig b/engine/core/tests/externalModule.zig index 6264181..44eb3c8 100644 --- a/engine/core/tests/externalModule.zig +++ b/engine/core/tests/externalModule.zig @@ -1,20 +1,28 @@ var gAllocator: std.mem.Allocator = undefined; pub export fn startup_module(p_allocator: *anyopaque, args: ?*anyopaque) bool { - _ = args; - - gAllocator = @as(*std.mem.Allocator, @ptrCast(@alignCast(p_allocator))).*; - - const allocator = gAllocator; + const allocator = core.modulePreamble(p_allocator, args) catch return false; // do some test allocations and let it leak - const t = std.fmt.allocPrint(gAllocator, "Lmao 2 nova {d}", .{2}) catch unreachable; + const t = std.fmt.allocPrint(allocator, "Lmao 2 nova {d}", .{2}) catch unreachable; std.debug.print("external module started allocated string: {s}\n", .{t}); allocator.free(t); + const subsystem = core.get(SampleSubsystem); + SceneAPI.setPosition = @ptrCast(@alignCast(subsystem.setPositionPtr)); + + const a: SceneAPI.setPositionArgs = .{ subsystem.scene, core.Vectorf{ .y = 12, .z = 13 } }; + const argsAsBytes = std.mem.asBytes(&a); + machinery.callInner(SceneAPI.setPosition, argsAsBytes); return true; } pub export fn shutdown_module() void {} +const hand = @import("SceneApiHand.zig"); +const SceneAPI = hand.SceneAPI; +const SampleSubsystem = @import("samplesubsystem.zig"); + +const core = @import("core"); const std = @import("std"); +const machinery = core.machinery; diff --git a/engine/core/tests/samplesubsystem.zig b/engine/core/tests/samplesubsystem.zig new file mode 100644 index 0000000..4892c2f --- /dev/null +++ b/engine/core/tests/samplesubsystem.zig @@ -0,0 +1,24 @@ +pub var NeonObjectTable: core.EngineObjectVTable = core.EngineObjectVTable.from(@This(), "testing.sampleSubsystem"); + +allocator: std.mem.Allocator, +scene: *anyopaque, +setPositionPtr: *const anyopaque, + +pub fn create(allocator: std.mem.Allocator) !*@This() { + const self = try allocator.create(@This()); + self.* = .{ + .allocator = allocator, + .scene = undefined, + .setPositionPtr = undefined, + }; + + return self; +} + +pub fn destroy(self: *@This()) void { + self.allocator.destroy(self); +} + +const exampleScene = @import("exampleScene.zig"); +const core = @import("core"); +const std = @import("std"); diff --git a/engine/core/tests/testmodule.zig b/engine/core/tests/testmodule.zig new file mode 100644 index 0000000..9c90868 --- /dev/null +++ b/engine/core/tests/testmodule.zig @@ -0,0 +1,12 @@ +pub fn callWithNoDirectLinking(scene: *anyopaque) void { + const args: SceneAPI.setPositionArgs = .{ scene, core.Vectorf{} }; + const argsAsBytes = std.mem.asBytes(&args); + machinery.callInner(SceneAPI.setPosition, argsAsBytes); +} + +const hand = @import("SceneApiHand.zig"); +const SceneAPI = hand.SceneAPI; + +const core = @import("core"); +const machinery = core.machinery; +const std = @import("std"); diff --git a/engine/core/tests/tests.zig b/engine/core/tests/tests.zig index 01bb619..a9b752c 100644 --- a/engine/core/tests/tests.zig +++ b/engine/core/tests/tests.zig @@ -5,6 +5,9 @@ const memory = core.MemoryTracker; const engine_log = core.engine_log; const engine_logs = core.engine_logs; +const exampleScene = @import("exampleScene.zig"); +const SampleSubsystem = @import("samplesubsystem.zig"); + test "simple systems setup for core" { std.testing.refAllDecls(core.algorithm); @@ -22,9 +25,15 @@ test "simple systems setup for core" { try core.start_module(&map, .{ .unitTest = true }, allocator); defer core.shutdown_module(allocator); + const subsystem = try core.createObject(SampleSubsystem, .{}); + const scene = try allocator.create(exampleScene.Scene); + defer allocator.destroy(scene); + + subsystem.scene = scene; + subsystem.setPositionPtr = @ptrCast(&exampleScene.Scene.setPosition); + engine_logs("systems started, shutting down"); - engine_logs("this is a new print added to the test function"); engine_logs("this is a new print added to the test function"); memory.MTPrintStatsDelta(); @@ -186,7 +195,11 @@ fn test_gameObjects(allocator: std.mem.Allocator) !void { const spawnFunc = core.GameObjectList.spawnObjectFunction(GameObject); const interface = spawnFunc(objList).?; + core.engine_log("lol", .{}); + core.engine_log("handle = {x}", .{interface.vtable.getEntity.?(interface.ptr).handle.index}); objList.tick(0.016); + + try exampleScene.doTest(); } diff --git a/projects/sampleGame/externGame/externGame.zig b/projects/sampleGame/externGame/externGame.zig index 79ea41f..7ae45ae 100644 --- a/projects/sampleGame/externGame/externGame.zig +++ b/projects/sampleGame/externGame/externGame.zig @@ -33,6 +33,8 @@ pub fn start_module(args: core.ModuleLoaderArgs) !void { core.PatchOrCreateObject(imgui.utils.ConsoleWindow, .{}); core.PatchOrCreateObject(@import("fpgame/fpgame.zig"), .{}); + core.engine_log("hmm", .{}); + _ = args; core.logDisplay("externGame", "accessing old object at {x} same object? {d}", .{ @intFromPtr(core.EngineObject(ExternGameObject).get()), @sizeOf(ExternGameObject) }); }