module: components are written in the same style as events

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
Stephen Gutekanst 2024-03-26 13:19:58 -07:00 committed by Stephen Gutekanst
parent f50a27b83d
commit 7e0b9dde68
10 changed files with 265 additions and 123 deletions

View file

@ -42,16 +42,18 @@ pub fn ArchetypeSlicer(comptime all_components: anytype) type {
pub fn slice(
slicer: @This(),
// TODO: cleanup comptime
comptime namespace_name: std.meta.FieldEnum(@TypeOf(all_components)),
comptime component_name: std.meta.DeclEnum(@field(all_components, @tagName(namespace_name))),
comptime component_name: std.meta.FieldEnum(@TypeOf(@field(all_components, @tagName(namespace_name)))),
) []@field(
@field(all_components, @tagName(namespace_name)),
@tagName(component_name),
) {
).type {
// TODO: cleanup comptime
const Type = @field(
@field(all_components, @tagName(namespace_name)),
@tagName(component_name),
);
).type;
if (namespace_name == .entity and component_name == .id) {
const name_id = slicer.archetype.component_names.index("id").?;
return slicer.archetype.getColumnValues(name_id, Type).?[0..slicer.archetype.len];

View file

@ -281,12 +281,13 @@ pub fn Entities(comptime all_components: anytype) type {
pub fn setComponent(
entities: *Self,
entity: EntityID,
// TODO: cleanup comptime
comptime namespace_name: std.meta.FieldEnum(@TypeOf(all_components)),
comptime component_name: std.meta.DeclEnum(@field(all_components, @tagName(namespace_name))),
comptime component_name: std.meta.FieldEnum(@TypeOf(@field(all_components, @tagName(namespace_name)))),
component: @field(
@field(all_components, @tagName(namespace_name)),
@tagName(component_name),
),
).type,
) !void {
const name_str = @tagName(namespace_name) ++ "." ++ @tagName(component_name);
const name_id = try entities.component_names.indexOrPut(entities.allocator, name_str);
@ -483,16 +484,19 @@ pub fn Entities(comptime all_components: anytype) type {
pub fn getComponent(
entities: *Self,
entity: EntityID,
// TODO: cleanup comptime
comptime namespace_name: std.meta.FieldEnum(@TypeOf(all_components)),
comptime component_name: std.meta.DeclEnum(@field(all_components, @tagName(namespace_name))),
comptime component_name: std.meta.FieldEnum(@TypeOf(@field(all_components, @tagName(namespace_name)))),
) ?@field(
@field(all_components, @tagName(namespace_name)),
@tagName(component_name),
) {
).type {
// TODO: cleanup comptime
const Component = comptime @field(
@field(all_components, @tagName(namespace_name)),
@tagName(component_name),
);
).type;
const name_str = @tagName(namespace_name) ++ "." ++ @tagName(component_name);
const name_id = entities.component_names.index(name_str) orelse return null;
@ -523,8 +527,9 @@ pub fn Entities(comptime all_components: anytype) type {
pub fn removeComponent(
entities: *Self,
entity: EntityID,
// TODO: cleanup comptime
comptime namespace_name: std.meta.FieldEnum(@TypeOf(all_components)),
comptime component_name: std.meta.DeclEnum(@field(all_components, @tagName(namespace_name))),
comptime component_name: std.meta.FieldEnum(@TypeOf(@field(all_components, @tagName(namespace_name)))),
) !void {
const name_str = @tagName(namespace_name) ++ "." ++ @tagName(component_name);
const name_id = try entities.component_names.indexOrPut(entities.allocator, name_str);

View file

@ -47,8 +47,8 @@ test "example" {
pointer: u8,
pub const name = .physics;
pub const components = struct {
pub const id = u32;
pub const components = .{
.{ .name = .id, .type = u32 },
};
pub const events = .{
.{ .global = .tick, .handler = tick },
@ -61,8 +61,8 @@ test "example" {
const Renderer = struct {
pub const name = .renderer;
pub const components = struct {
pub const id = u16;
pub const components = .{
.{ .name = .ud, .type = u16 },
};
pub const events = .{
.{ .global = .tick, .handler = tick },

View file

@ -9,23 +9,27 @@ pub const QueryTag = enum {
/// A complex query for entities matching a given criteria
pub fn Query(comptime all_components: anytype) type {
return union(QueryTag) {
// TODO: cleanup comptime
/// Enum matching a namespace. e.g. `.game` or `.physics2d`
pub const Namespace = std.meta.FieldEnum(@TypeOf(all_components));
// TODO: cleanup comptime
/// Enum matching a component within a namespace
/// e.g. `var a: Component(.physics2d) = .location`
pub fn Component(comptime namespace: Namespace) type {
const components = @field(all_components, @tagName(namespace));
if (@typeInfo(components).Struct.decls.len == 0) return enum {};
return std.meta.DeclEnum(components);
if (@typeInfo(@TypeOf(components)).Struct.fields.len == 0) return enum {};
return std.meta.FieldEnum(@TypeOf(components));
}
// TODO: cleanup comptime
/// Slice of enums matching a component within a namespace
/// e.g. `&.{.location, .rotation}`
pub fn ComponentList(comptime namespace: Namespace) type {
return []const Component(namespace);
}
// TODO: cleanup comptime
/// Tagged union of namespaces matching lists of components
/// e.g. `.physics2d = &.{ .location, .rotation }`
pub const NamespaceComponent = T: {

View file

@ -7,6 +7,7 @@ const Entities = @import("entities.zig").Entities;
const EntityID = @import("entities.zig").EntityID;
const comp = @import("comptime.zig");
const Module = @import("../module.zig").Module;
const NamespacedComponents = @import("../module.zig").NamespacedComponents;
pub fn World(comptime mods: anytype) type {
const StateT = NamespacedState(mods);
@ -37,8 +38,9 @@ pub fn World(comptime mods: anytype) type {
pub inline fn set(
m: *@This(),
entity: EntityID,
comptime component_name: std.meta.DeclEnum(components),
component: @field(components, @tagName(component_name)),
// TODO: cleanup comptime
comptime component_name: std.meta.FieldEnum(@TypeOf(components)),
component: @field(components, @tagName(component_name)).type,
) !void {
const mod_ptr: *Mods = @alignCast(@fieldParentPtr(Mods, @tagName(module_tag), m));
const world = @fieldParentPtr(WorldT, "mod", mod_ptr);
@ -50,8 +52,9 @@ pub fn World(comptime mods: anytype) type {
pub inline fn get(
m: *@This(),
entity: EntityID,
comptime component_name: std.meta.DeclEnum(components),
) ?@field(components, @tagName(component_name)) {
// TODO: cleanup comptime
comptime component_name: std.meta.FieldEnum(@TypeOf(components)),
) ?@field(components, @tagName(component_name)).type {
const mod_ptr: *Mods = @alignCast(@fieldParentPtr(Mods, @tagName(module_tag), m));
const world = @fieldParentPtr(WorldT, "mod", mod_ptr);
return world.entities.getComponent(entity, module_tag, component_name);
@ -61,7 +64,8 @@ pub fn World(comptime mods: anytype) type {
pub inline fn remove(
m: *@This(),
entity: EntityID,
comptime component_name: std.meta.DeclEnum(components),
// TODO: cleanup comptime
comptime component_name: std.meta.FieldEnum(@TypeOf(components)),
) !void {
const mod_ptr: *Mods = @alignCast(@fieldParentPtr(Mods, @tagName(module_tag), m));
const world = @fieldParentPtr(WorldT, "mod", mod_ptr);
@ -80,6 +84,7 @@ pub fn World(comptime mods: anytype) type {
world.modules.sendGlobal(module_tag, event_name, args);
}
// TODO: eliminate this
pub fn dispatchNoError(m: *@This()) void {
const mod_ptr: *Mods = @alignCast(@fieldParentPtr(Mods, @tagName(module_tag), m));
const world = @fieldParentPtr(WorldT, "mod", mod_ptr);
@ -173,42 +178,6 @@ pub fn World(comptime mods: anytype) type {
};
}
// TODO: reconsider components concept
fn NamespacedComponents(comptime modules: anytype) type {
var fields: []const std.builtin.Type.StructField = &[0]std.builtin.Type.StructField{};
inline for (modules) |M| {
const components = if (@hasDecl(M, "components")) M.components else struct {};
fields = fields ++ [_]std.builtin.Type.StructField{.{
.name = @tagName(M.name),
.type = type,
.default_value = &components,
.is_comptime = true,
.alignment = @alignOf(@TypeOf(components)),
}};
}
// Builtin components
const entity_components = struct {
pub const id = EntityID;
};
fields = fields ++ [_]std.builtin.Type.StructField{.{
.name = "entity",
.type = type,
.default_value = &entity_components,
.is_comptime = true,
.alignment = @alignOf(@TypeOf(entity_components)),
}};
return @Type(.{
.Struct = .{
.layout = .Auto,
.is_tuple = false,
.fields = fields,
.decls = &[_]std.builtin.Type.Declaration{},
},
});
}
// TODO: reconsider state concept
fn NamespacedState(comptime modules: anytype) type {
var fields: []const std.builtin.Type.StructField = &[0]std.builtin.Type.StructField{};