ecs: rename module globals -> state
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
e6cfbbe82a
commit
fcf9943d0f
2 changed files with 30 additions and 29 deletions
|
|
@ -2,8 +2,9 @@
|
||||||
//!
|
//!
|
||||||
//! ## Design principles:
|
//! ## Design principles:
|
||||||
//!
|
//!
|
||||||
//! * Clean-room implementation (author has not read any other ECS implementation code, just working
|
//! * Initially a 100% clean-room implementation, working from first-principles. Later informed by
|
||||||
//! from first-principles)
|
//! research into how other ECS work, with advice from e.g. Bevy and Flecs authors at different
|
||||||
|
//! points (thank you!)
|
||||||
//! * Solve the problems ECS solves, in a way that is natural to Zig and leverages Zig comptime.
|
//! * Solve the problems ECS solves, in a way that is natural to Zig and leverages Zig comptime.
|
||||||
//! * Fast. Optimal for CPU caches, multi-threaded, leverage comptime as much as is reasonable.
|
//! * Fast. Optimal for CPU caches, multi-threaded, leverage comptime as much as is reasonable.
|
||||||
//! * Simple. Small API footprint, should be natural and fun - not like you're writing boilerplate.
|
//! * Simple. Small API footprint, should be natural and fun - not like you're writing boilerplate.
|
||||||
|
|
@ -71,7 +72,7 @@ test "example" {
|
||||||
var world = try World(modules).init(allocator);
|
var world = try World(modules).init(allocator);
|
||||||
defer world.deinit();
|
defer world.deinit();
|
||||||
|
|
||||||
// Initialize globals.
|
// Initialize module state.
|
||||||
world.set(.physics, .pointer, 123);
|
world.set(.physics, .pointer, 123);
|
||||||
_ = world.get(.physics, .pointer); // == 123
|
_ = world.get(.physics, .pointer); // == 123
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ const Entities = @import("entities.zig").Entities;
|
||||||
|
|
||||||
/// Validates that a module matches the expected type layout.
|
/// Validates that a module matches the expected type layout.
|
||||||
///
|
///
|
||||||
/// An ECS module has components, systems, global values & more.
|
/// An ECS module has components, systems, state & more.
|
||||||
pub fn Module(comptime M: anytype) type {
|
pub fn Module(comptime M: anytype) type {
|
||||||
if (@hasDecl(M, "name")) {
|
if (@hasDecl(M, "name")) {
|
||||||
_ = @tagName(M.name);
|
_ = @tagName(M.name);
|
||||||
|
|
@ -25,7 +25,7 @@ pub fn Module(comptime M: anytype) type {
|
||||||
|
|
||||||
/// Validates that a list of module matches the expected type layout.
|
/// Validates that a list of module matches the expected type layout.
|
||||||
///
|
///
|
||||||
/// ECS modules have components, systems, global values & more.
|
/// ECS modules have components, systems, state & more.
|
||||||
pub fn Modules(comptime modules: anytype) @TypeOf(modules) {
|
pub fn Modules(comptime modules: anytype) @TypeOf(modules) {
|
||||||
inline for (modules) |m| _ = Module(m);
|
inline for (modules) |m| _ = Module(m);
|
||||||
return modules;
|
return modules;
|
||||||
|
|
@ -99,7 +99,7 @@ pub fn MessagesTag(comptime messages: anytype) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
const NoComponents = @TypeOf(.{});
|
const NoComponents = @TypeOf(.{});
|
||||||
const NoGlobals = @TypeOf(.{});
|
const NoState = @TypeOf(.{});
|
||||||
|
|
||||||
/// Returns the namespaced components struct **type**.
|
/// Returns the namespaced components struct **type**.
|
||||||
//
|
//
|
||||||
|
|
@ -168,7 +168,7 @@ fn namespacedComponents(comptime modules: anytype) NamespacedComponents(modules)
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts namespaced globals from modules (a module is said to have globals if the struct has
|
/// Extracts namespaced state from modules (a module is said to have state if the struct has
|
||||||
/// any fields), returning a type like e.g.:
|
/// any fields), returning a type like e.g.:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
|
|
@ -183,26 +183,26 @@ fn namespacedComponents(comptime modules: anytype) NamespacedComponents(modules)
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
fn NamespacedGlobals(comptime modules: anytype) type {
|
fn NamespacedState(comptime modules: anytype) type {
|
||||||
var fields: []const StructField = &[0]StructField{};
|
var fields: []const StructField = &[0]StructField{};
|
||||||
inline for (std.meta.fields(@TypeOf(modules))) |module_field| {
|
inline for (std.meta.fields(@TypeOf(modules))) |module_field| {
|
||||||
const module = @field(modules, module_field.name);
|
const module = @field(modules, module_field.name);
|
||||||
const module_name = @tagName(@field(module, "name"));
|
const module_name = @tagName(@field(module, "name"));
|
||||||
const global_fields = std.meta.fields(module);
|
const state_fields = std.meta.fields(module);
|
||||||
const Globals = if (global_fields.len > 0) @Type(.{
|
const State = if (state_fields.len > 0) @Type(.{
|
||||||
.Struct = .{
|
.Struct = .{
|
||||||
.layout = .Auto,
|
.layout = .Auto,
|
||||||
.is_tuple = false,
|
.is_tuple = false,
|
||||||
.fields = global_fields,
|
.fields = state_fields,
|
||||||
.decls = &[_]std.builtin.Type.Declaration{},
|
.decls = &[_]std.builtin.Type.Declaration{},
|
||||||
},
|
},
|
||||||
}) else NoGlobals;
|
}) else NoState;
|
||||||
fields = fields ++ [_]std.builtin.Type.StructField{.{
|
fields = fields ++ [_]std.builtin.Type.StructField{.{
|
||||||
.name = module_name,
|
.name = module_name,
|
||||||
.type = Globals,
|
.type = State,
|
||||||
.default_value = null,
|
.default_value = null,
|
||||||
.is_comptime = false,
|
.is_comptime = false,
|
||||||
.alignment = @alignOf(Globals),
|
.alignment = @alignOf(State),
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
return @Type(.{
|
return @Type(.{
|
||||||
|
|
@ -220,7 +220,7 @@ pub fn World(comptime modules: anytype) type {
|
||||||
return struct {
|
return struct {
|
||||||
allocator: Allocator,
|
allocator: Allocator,
|
||||||
entities: Entities(all_components),
|
entities: Entities(all_components),
|
||||||
globals: NamespacedGlobals(modules),
|
state: NamespacedState(modules),
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
|
|
@ -228,7 +228,7 @@ pub fn World(comptime modules: anytype) type {
|
||||||
return Self{
|
return Self{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.entities = try Entities(all_components).init(allocator),
|
.entities = try Entities(all_components).init(allocator),
|
||||||
.globals = undefined,
|
.state = undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,34 +236,34 @@ pub fn World(comptime modules: anytype) type {
|
||||||
world.entities.deinit();
|
world.entities.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets a global value called `.global_tag` from the module named `.module_tag`
|
/// Gets a state value called `.state_tag` from the module named `.module_tag`
|
||||||
pub fn get(world: *Self, comptime module_tag: anytype, comptime global_tag: anytype) @TypeOf(@field(
|
pub fn get(world: *Self, comptime module_tag: anytype, comptime state_tag: anytype) @TypeOf(@field(
|
||||||
@field(world.globals, @tagName(module_tag)),
|
@field(world.state, @tagName(module_tag)),
|
||||||
@tagName(global_tag),
|
@tagName(state_tag),
|
||||||
)) {
|
)) {
|
||||||
return comptime @field(
|
return comptime @field(
|
||||||
@field(world.globals, @tagName(module_tag)),
|
@field(world.state, @tagName(module_tag)),
|
||||||
@tagName(global_tag),
|
@tagName(state_tag),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a global value called `.global_tag` in the module named `.module_tag`
|
/// Sets a state value called `.state_tag` in the module named `.module_tag`
|
||||||
pub fn set(
|
pub fn set(
|
||||||
world: *Self,
|
world: *Self,
|
||||||
comptime module_tag: anytype,
|
comptime module_tag: anytype,
|
||||||
comptime global_tag: anytype,
|
comptime state_tag: anytype,
|
||||||
value: @TypeOf(@field(
|
value: @TypeOf(@field(
|
||||||
@field(world.globals, @tagName(module_tag)),
|
@field(world.state, @tagName(module_tag)),
|
||||||
@tagName(global_tag),
|
@tagName(state_tag),
|
||||||
)),
|
)),
|
||||||
) void {
|
) void {
|
||||||
comptime @field(
|
comptime @field(
|
||||||
@field(world.globals, @tagName(module_tag)),
|
@field(world.state, @tagName(module_tag)),
|
||||||
@tagName(global_tag),
|
@tagName(state_tag),
|
||||||
) = value;
|
) = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Broadcasts a global message to all modules that are subscribed to it.
|
/// Broadcasts a state message to all modules that are subscribed to it.
|
||||||
pub fn send(world: *Self, comptime msg_tag: anytype) !void {
|
pub fn send(world: *Self, comptime msg_tag: anytype) !void {
|
||||||
inline for (std.meta.fields(@TypeOf(modules))) |module_field| {
|
inline for (std.meta.fields(@TypeOf(modules))) |module_field| {
|
||||||
const module = @field(modules, module_field.name);
|
const module = @field(modules, module_field.name);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue