This commit is contained in:
Peter Li 2025-11-02 00:44:21 -07:00
parent 7aa70eb5d5
commit 35562ab6d7
10 changed files with 194 additions and 7 deletions

View File

@ -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" } },

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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