186 lines
6.5 KiB
Zig
186 lines
6.5 KiB
Zig
// ok
|
|
//
|
|
// lets really cook a good API here
|
|
|
|
pub const SpawnObjectResult = struct { ptr: *anyopaque, entity: core.Entity };
|
|
|
|
pub const ObjectCreateFn = *const fn (allocator: std.mem.Allocator, entity: core.Entity, parameters: SpawnParameters) ObjectError!*anyopaque;
|
|
pub const MessageHandlerFunc = *const fn (*anyopaque, *const MessageInfo, *anyopaque) void;
|
|
|
|
pub const GameObjectInterfaceVTable = struct {
|
|
destroy: *const fn (*anyopaque, std.mem.Allocator) void,
|
|
tick: ?*const fn (*anyopaque, f64) void,
|
|
objectTypeName: core.Name = core.DefineName("UnknownType"),
|
|
objectBaseName: core.Name = core.DefineName("UnknownObject"),
|
|
create: ObjectCreateFn,
|
|
messageHandlers: std.AutoHashMapUnmanaged(u32, MessageHandlerFunc) = .{},
|
|
|
|
pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
|
|
self.messageHandlers.deinit(allocator);
|
|
}
|
|
};
|
|
|
|
pub const ObjectError = error{
|
|
OutOfMemory,
|
|
BadInit,
|
|
UnknownState,
|
|
UnknownObject,
|
|
};
|
|
|
|
pub const MessageInfo = struct {
|
|
tag: core.Name,
|
|
sourceEntity: ?core.Entity = null,
|
|
sourceSystem: ?core.Name = null,
|
|
// maybe add like a filter type? or an invoker?
|
|
};
|
|
|
|
pub const GameObjectRef = struct {
|
|
table: *GameObjectInterfaceVTable,
|
|
ptr: *anyopaque,
|
|
};
|
|
|
|
pub const GameObject = struct {
|
|
pub var BaseContainer: *core.SparseSet(GameObject) = undefined;
|
|
pub const ComponentName = "GameObjectComponent";
|
|
pub const ScriptExports: []const []const u8 = &.{};
|
|
|
|
// set by GameObjectSystem when it calls Entity
|
|
objectRef: GameObjectRef = undefined,
|
|
destroyed: bool = false,
|
|
|
|
pub fn deinitECS(self: *@This(), handle: core.ObjectHandle) void {
|
|
_ = handle;
|
|
if (!self.destroyed) {
|
|
self.objectRef.table.destroy(self.objectRef.ptr, core.get(GameObjectSystem).allocator);
|
|
self.destroyed = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
pub const SpawnParameters = struct {
|
|
posRot: core.ScenePosRot = .{},
|
|
scale: core.Vectorf = .{ .z = 1.0, .y = 1.0, .x = 1.0 },
|
|
};
|
|
|
|
pub const SpawnEvent = struct {
|
|
interface: GameObjectInterfaceVTable,
|
|
};
|
|
|
|
pub const GameObjectSystem = struct {
|
|
|
|
// this is the new one, GameObjectList should be deleted after this passes initial usability
|
|
pub var NeonObjectTable = core.EngineObjectVTable.from(@This(), "core.GameObjectSystem");
|
|
|
|
allocator: std.mem.Allocator = undefined,
|
|
objectDefinitions: std.AutoHashMapUnmanaged(u32, GameObjectInterfaceVTable) = .{},
|
|
typesArena: std.heap.ArenaAllocator = undefined,
|
|
|
|
objectSpawnEvents: std.ArrayListUnmanaged(SpawnEvent) = .{},
|
|
|
|
pub fn create(self: *@This(), allocator: std.mem.Allocator, first: bool) !void {
|
|
if (!first)
|
|
return;
|
|
|
|
self.* = .{
|
|
.allocator = allocator,
|
|
.typesArena = std.heap.ArenaAllocator.init(self.allocator),
|
|
};
|
|
}
|
|
|
|
pub fn spawnObject(self: *@This(), comptime T: type, objectName: []const u8, parameters: SpawnParameters) !*T {
|
|
var n = core.MakeName(objectName);
|
|
return self.spawnObjectByName(T, &n, parameters);
|
|
}
|
|
|
|
pub fn spawnObjectByName(self: *@This(), comptime T: type, objectName: *core.Name, parameters: SpawnParameters) !*T {
|
|
return @ptrCast(@alignCast((try self.spawnObjectFromTableByName(objectName, parameters)).ptr));
|
|
}
|
|
|
|
pub fn spawnObjectFromTableByName(self: *@This(), objectName: *core.Name, parameters: SpawnParameters) !SpawnObjectResult {
|
|
const interface: *GameObjectInterfaceVTable = self.objectDefinitions.getPtr(objectName.handle()) orelse {
|
|
return ObjectError.UnknownObject;
|
|
};
|
|
|
|
const entity = try core.createEntity();
|
|
const objectComponent = entity.addComponent(GameObject).?;
|
|
const rv = SpawnObjectResult{ .ptr = try interface.create(self.allocator, entity, parameters), .entity = entity };
|
|
|
|
objectComponent.objectRef = .{
|
|
.table = interface,
|
|
.ptr = rv.ptr,
|
|
};
|
|
|
|
return rv;
|
|
}
|
|
|
|
// registers an object for spawning with the object name
|
|
pub fn registerObject(self: *@This(), objectName: []const u8, comptime T: type) !void {
|
|
try self.registerObjectAdvanced(objectName, T, "create");
|
|
}
|
|
|
|
pub fn registerObjectAdvanced(self: *@This(), name: []const u8, comptime T: type, comptime createFunctionName: []const u8) !void {
|
|
var n = core.MakeName(name);
|
|
|
|
const Wrap = struct {
|
|
pub fn create(allocator: std.mem.Allocator, entity: core.Entity, parameters: SpawnParameters) ObjectError!*anyopaque {
|
|
return @field(T, createFunctionName)(allocator, entity, parameters) catch {
|
|
return ObjectError.BadInit;
|
|
};
|
|
}
|
|
|
|
pub fn destroy(p: *anyopaque, alloc: std.mem.Allocator) void {
|
|
T.destroy(@ptrCast(@alignCast(p)), alloc);
|
|
}
|
|
|
|
pub fn tick(p: *anyopaque, dt: f64) void {
|
|
T.tick(@ptrCast(@alignCast(p)), dt);
|
|
}
|
|
};
|
|
|
|
var interface = GameObjectInterfaceVTable{
|
|
.create = Wrap.create,
|
|
.tick = if (@hasDecl(T, "tick")) Wrap.tick else null,
|
|
.destroy = Wrap.destroy,
|
|
.objectTypeName = core.MakeTypeName(T),
|
|
.objectBaseName = n,
|
|
.messageHandlers = .{},
|
|
};
|
|
|
|
if (@hasDecl(T, "MessageHandlers")) {
|
|
inline for (T.MessageHandlers) |handlerName| {
|
|
var messageHandlerName = core.MakeName(handlerName);
|
|
// const handlerFunc = @field(T, handlerName);
|
|
// const handlerTypeInfo = @typeInfo(@TypeOf(handlerFunc));
|
|
// const M = @typeInfo(handlerTypeInfo.@"fn".params[3].type.?).pointer.child;
|
|
|
|
const HandlerWrap = struct {
|
|
pub fn messageHandler(p: *anyopaque, info: *const MessageInfo, message: *anyopaque) void {
|
|
@field(T, handlerName)(@ptrCast(@alignCast(p)), info, @ptrCast(@alignCast(message)));
|
|
}
|
|
};
|
|
|
|
try interface.messageHandlers.put(self.typesArena.allocator(), messageHandlerName.handle(), HandlerWrap.messageHandler);
|
|
}
|
|
}
|
|
|
|
try self.objectDefinitions.put(self.typesArena.allocator(), n.handle(), interface);
|
|
}
|
|
|
|
pub fn tick(self: *@This(), dt: f64) void {
|
|
// for (self.objects.items) |object| {
|
|
// if (object.vtable.tick) |tick_fn| {
|
|
// tick_fn(object.ptr, dt);
|
|
// }
|
|
// }
|
|
_ = self;
|
|
_ = dt;
|
|
}
|
|
|
|
pub fn destroy(self: *@This()) void {
|
|
self.typesArena.deinit();
|
|
}
|
|
};
|
|
|
|
const core = @import("core.zig");
|
|
const std = @import("std");
|