{module,ecs}: Mach ECS becomes the Mach' module system
This moves the bulk of the ECS code into `src/module`. It also makes types like `mach.ecs.EntityID` accessible at the top-level `mach.EntityID` instead. The motivation of this change is to make the Mach module system a first-class property of Mach. Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
679a05faf4
commit
f578e1f5e2
15 changed files with 23 additions and 52 deletions
|
|
@ -1,6 +1,5 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mach = @import("mach");
|
const mach = @import("mach");
|
||||||
const ecs = mach.ecs;
|
|
||||||
const core = mach.core;
|
const core = mach.core;
|
||||||
const math = mach.math;
|
const math = mach.math;
|
||||||
const Renderer = @import("Renderer.zig");
|
const Renderer = @import("Renderer.zig");
|
||||||
|
|
@ -12,7 +11,7 @@ const Vec3 = math.Vec3;
|
||||||
|
|
||||||
// Global state for our game module.
|
// Global state for our game module.
|
||||||
timer: mach.Timer,
|
timer: mach.Timer,
|
||||||
player: ecs.EntityID,
|
player: mach.EntityID,
|
||||||
direction: Vec2 = vec2(0, 0),
|
direction: Vec2 = vec2(0, 0),
|
||||||
spawning: bool = false,
|
spawning: bool = false,
|
||||||
spawn_timer: mach.Timer,
|
spawn_timer: mach.Timer,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ const std = @import("std");
|
||||||
const mach = @import("mach");
|
const mach = @import("mach");
|
||||||
const core = mach.core;
|
const core = mach.core;
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
const ecs = mach.ecs;
|
|
||||||
const Sprite = mach.gfx.Sprite;
|
const Sprite = mach.gfx.Sprite;
|
||||||
const math = mach.math;
|
const math = mach.math;
|
||||||
const vec2 = math.vec2;
|
const vec2 = math.vec2;
|
||||||
|
|
@ -16,7 +15,7 @@ const Mat4x4 = math.Mat4x4;
|
||||||
const Text = @import("Text.zig");
|
const Text = @import("Text.zig");
|
||||||
|
|
||||||
timer: mach.Timer,
|
timer: mach.Timer,
|
||||||
player: mach.ecs.EntityID,
|
player: mach.EntityID,
|
||||||
direction: Vec2 = vec2(0, 0),
|
direction: Vec2 = vec2(0, 0),
|
||||||
spawning: bool = false,
|
spawning: bool = false,
|
||||||
spawn_timer: mach.Timer,
|
spawn_timer: mach.Timer,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// TODO(important): review all code in this file in-depth
|
// TODO(important): review all code in this file in-depth
|
||||||
const mach = @import("mach");
|
const mach = @import("mach");
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
const ecs = mach.ecs;
|
|
||||||
const ft = @import("freetype");
|
const ft = @import("freetype");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assets = @import("assets");
|
const assets = @import("assets");
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ const assets = @import("assets");
|
||||||
const mach = @import("mach");
|
const mach = @import("mach");
|
||||||
const core = mach.core;
|
const core = mach.core;
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
const ecs = mach.ecs;
|
|
||||||
const Sprite = mach.gfx.Sprite;
|
const Sprite = mach.gfx.Sprite;
|
||||||
const math = mach.math;
|
const math = mach.math;
|
||||||
|
|
||||||
|
|
@ -19,7 +18,7 @@ const Mat4x4 = math.Mat4x4;
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
|
||||||
timer: mach.Timer,
|
timer: mach.Timer,
|
||||||
player: mach.ecs.EntityID,
|
player: mach.EntityID,
|
||||||
direction: Vec2 = vec2(0, 0),
|
direction: Vec2 = vec2(0, 0),
|
||||||
spawning: bool = false,
|
spawning: bool = false,
|
||||||
spawn_timer: mach.Timer,
|
spawn_timer: mach.Timer,
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ const mach = @import("mach");
|
||||||
const core = mach.core;
|
const core = mach.core;
|
||||||
const gfx = mach.gfx;
|
const gfx = mach.gfx;
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
const ecs = mach.ecs;
|
|
||||||
const Text = mach.gfx.Text;
|
const Text = mach.gfx.Text;
|
||||||
const math = mach.math;
|
const math = mach.math;
|
||||||
|
|
||||||
|
|
@ -21,7 +20,7 @@ const Mat4x4 = math.Mat4x4;
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
|
|
||||||
timer: mach.Timer,
|
timer: mach.Timer,
|
||||||
player: mach.ecs.EntityID,
|
player: mach.EntityID,
|
||||||
direction: Vec2 = vec2(0, 0),
|
direction: Vec2 = vec2(0, 0),
|
||||||
spawning: bool = false,
|
spawning: bool = false,
|
||||||
spawn_timer: mach.Timer,
|
spawn_timer: mach.Timer,
|
||||||
|
|
@ -30,7 +29,7 @@ frame_count: usize,
|
||||||
texts: usize,
|
texts: usize,
|
||||||
rand: std.rand.DefaultPrng,
|
rand: std.rand.DefaultPrng,
|
||||||
time: f32,
|
time: f32,
|
||||||
style1: mach.ecs.EntityID,
|
style1: mach.EntityID,
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
const d0 = 0.000001;
|
const d0 = 0.000001;
|
||||||
|
|
@ -106,7 +105,7 @@ fn init(
|
||||||
// TODO: better storage mechanism for this
|
// TODO: better storage mechanism for this
|
||||||
// TODO: this is a leak
|
// TODO: this is a leak
|
||||||
const allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
const styles = try allocator.alloc(mach.ecs.EntityID, 3);
|
const styles = try allocator.alloc(mach.EntityID, 3);
|
||||||
styles[0] = style1;
|
styles[0] = style1;
|
||||||
styles[1] = style2;
|
styles[1] = style2;
|
||||||
styles[2] = style3;
|
styles[2] = style3;
|
||||||
|
|
@ -189,7 +188,7 @@ fn tick(
|
||||||
|
|
||||||
// TODO: better storage mechanism for this
|
// TODO: better storage mechanism for this
|
||||||
// TODO: this is a leak
|
// TODO: this is a leak
|
||||||
const styles = try game.state().allocator.alloc(mach.ecs.EntityID, 1);
|
const styles = try game.state().allocator.alloc(mach.EntityID, 1);
|
||||||
styles[0] = game.state().style1;
|
styles[0] = game.state().style1;
|
||||||
try text_mod.set(new_entity, .text, text2);
|
try text_mod.set(new_entity, .text, text2);
|
||||||
try text_mod.set(new_entity, .style, styles);
|
try text_mod.set(new_entity, .style, styles);
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,6 @@ const std = @import("std");
|
||||||
const mach = @import("main.zig");
|
const mach = @import("main.zig");
|
||||||
const core = mach.core;
|
const core = mach.core;
|
||||||
const gpu = mach.core.gpu;
|
const gpu = mach.core.gpu;
|
||||||
const ecs = mach.ecs;
|
|
||||||
const module = @import("module.zig");
|
|
||||||
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
const allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ const std = @import("std");
|
||||||
const mach = @import("../main.zig");
|
const mach = @import("../main.zig");
|
||||||
const core = mach.core;
|
const core = mach.core;
|
||||||
const gpu = mach.core.gpu;
|
const gpu = mach.core.gpu;
|
||||||
const ecs = mach.ecs;
|
|
||||||
const Engine = mach.Engine;
|
const Engine = mach.Engine;
|
||||||
|
|
||||||
const math = mach.math;
|
const math = mach.math;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ const std = @import("std");
|
||||||
const mach = @import("../main.zig");
|
const mach = @import("../main.zig");
|
||||||
const core = mach.core;
|
const core = mach.core;
|
||||||
const gpu = mach.gpu;
|
const gpu = mach.gpu;
|
||||||
const ecs = mach.ecs;
|
|
||||||
const Engine = mach.Engine;
|
const Engine = mach.Engine;
|
||||||
const gfx = mach.gfx;
|
const gfx = mach.gfx;
|
||||||
|
|
||||||
|
|
@ -49,7 +48,7 @@ pub const components = .{
|
||||||
\\ Expected to match the length of the style component.
|
\\ Expected to match the length of the style component.
|
||||||
},
|
},
|
||||||
|
|
||||||
.style = .{ .type = []const mach.ecs.EntityID, .description =
|
.style = .{ .type = []const mach.EntityID, .description =
|
||||||
\\ The style to apply to each segment of text.
|
\\ The style to apply to each segment of text.
|
||||||
\\
|
\\
|
||||||
\\ Expected to match the length of the text component.
|
\\ Expected to match the length of the text component.
|
||||||
|
|
|
||||||
12
src/main.zig
12
src/main.zig
|
|
@ -8,7 +8,6 @@ pub const gpu = if (build_options.want_core) core.gpu else struct {};
|
||||||
pub const sysjs = if (build_options.want_core) @import("mach-sysjs") else struct {};
|
pub const sysjs = if (build_options.want_core) @import("mach-sysjs") else struct {};
|
||||||
|
|
||||||
// Mach standard library
|
// Mach standard library
|
||||||
pub const ecs = @import("ecs/main.zig");
|
|
||||||
// gamemode requires libc on linux
|
// gamemode requires libc on linux
|
||||||
pub const gamemode = if (builtin.os.tag != .linux or builtin.link_libc) @import("gamemode.zig");
|
pub const gamemode = if (builtin.os.tag != .linux or builtin.link_libc) @import("gamemode.zig");
|
||||||
pub const gfx = if (build_options.want_mach) @import("gfx/main.zig") else struct {};
|
pub const gfx = if (build_options.want_mach) @import("gfx/main.zig") else struct {};
|
||||||
|
|
@ -21,17 +20,19 @@ pub const sysgpu = if (build_options.want_sysgpu) @import("sysgpu/main.zig") els
|
||||||
// Engine exports
|
// Engine exports
|
||||||
pub const App = @import("engine.zig").App;
|
pub const App = @import("engine.zig").App;
|
||||||
pub const Engine = @import("engine.zig").Engine;
|
pub const Engine = @import("engine.zig").Engine;
|
||||||
pub const ModSet = @import("module.zig").ModSet;
|
|
||||||
|
|
||||||
// TODO: perhaps this could be a comptime var rather than @import("root")?
|
// Module system
|
||||||
|
pub const ModSet = @import("module/main.zig").ModSet;
|
||||||
pub const modules = blk: {
|
pub const modules = blk: {
|
||||||
if (!@hasDecl(@import("root"), "modules")) {
|
if (!@hasDecl(@import("root"), "modules")) {
|
||||||
@compileError("expected `pub const modules = .{};` in root file");
|
@compileError("expected `pub const modules = .{};` in root file");
|
||||||
}
|
}
|
||||||
break :blk @import("root").modules;
|
break :blk @import("root").modules;
|
||||||
};
|
};
|
||||||
pub const Modules = @import("module.zig").Modules(modules);
|
pub const Modules = @import("module/main.zig").Modules(modules);
|
||||||
pub const Mod = ModSet(modules).Mod;
|
pub const Mod = ModSet(modules).Mod;
|
||||||
|
pub const EntityID = @import("module/main.zig").EntityID;
|
||||||
|
pub const Archetype = @import("module/main.zig").Archetype;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
@ -44,8 +45,7 @@ test {
|
||||||
_ = gfx;
|
_ = gfx;
|
||||||
_ = math;
|
_ = math;
|
||||||
_ = testing;
|
_ = testing;
|
||||||
std.testing.refAllDeclsRecursive(@import("module.zig"));
|
std.testing.refAllDeclsRecursive(@import("module/main.zig"));
|
||||||
std.testing.refAllDeclsRecursive(ecs);
|
|
||||||
std.testing.refAllDeclsRecursive(gamemode);
|
std.testing.refAllDeclsRecursive(gamemode);
|
||||||
std.testing.refAllDeclsRecursive(math);
|
std.testing.refAllDeclsRecursive(math);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ const assert = std.debug.assert;
|
||||||
const query_mod = @import("query.zig");
|
const query_mod = @import("query.zig");
|
||||||
const Archetype = @import("Archetype.zig");
|
const Archetype = @import("Archetype.zig");
|
||||||
const StringTable = @import("StringTable.zig");
|
const StringTable = @import("StringTable.zig");
|
||||||
const ComponentTypesByName = @import("../module.zig").ComponentTypesByName;
|
const ComponentTypesByName = @import("module.zig").ComponentTypesByName;
|
||||||
|
|
||||||
/// An entity ID uniquely identifies an entity globally within an Entities set.
|
/// An entity ID uniquely identifies an entity globally within an Entities set.
|
||||||
pub const EntityID = u64;
|
pub const EntityID = u64;
|
||||||
|
|
@ -1,16 +1,3 @@
|
||||||
//! mach/ecs is an Entity component system implementation.
|
|
||||||
//!
|
|
||||||
//! ## Design principles:
|
|
||||||
//!
|
|
||||||
//! * Initially a 100% clean-room implementation, working from first-principles. Later informed by
|
|
||||||
//! 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.
|
|
||||||
//! * 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.
|
|
||||||
//! * Enable other libraries to provide tracing, editors, visualizers, profilers, etc.
|
|
||||||
//!
|
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mach = @import("../main.zig");
|
const mach = @import("../main.zig");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
|
@ -18,15 +5,8 @@ const testing = std.testing;
|
||||||
pub const EntityID = @import("entities.zig").EntityID;
|
pub const EntityID = @import("entities.zig").EntityID;
|
||||||
pub const Entities = @import("entities.zig").Entities;
|
pub const Entities = @import("entities.zig").Entities;
|
||||||
pub const Archetype = @import("Archetype.zig");
|
pub const Archetype = @import("Archetype.zig");
|
||||||
|
pub const ModSet = @import("module.zig").ModSet;
|
||||||
pub const Modules = @import("../module.zig").Modules;
|
pub const Modules = @import("module.zig").Modules;
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// * Iteration
|
|
||||||
// * Querying
|
|
||||||
// * Multi threading
|
|
||||||
// * Multiple entities having one value
|
|
||||||
// * Sparse storage?
|
|
||||||
|
|
||||||
test {
|
test {
|
||||||
std.testing.refAllDeclsRecursive(@This());
|
std.testing.refAllDeclsRecursive(@This());
|
||||||
|
|
@ -36,7 +16,7 @@ test {
|
||||||
std.testing.refAllDeclsRecursive(@import("StringTable.zig"));
|
std.testing.refAllDeclsRecursive(@import("StringTable.zig"));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "example" {
|
test "entities DB" {
|
||||||
const allocator = testing.allocator;
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
const root = struct {
|
const root = struct {
|
||||||
|
|
@ -61,11 +61,11 @@
|
||||||
|
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const testing = @import("testing.zig");
|
const testing = @import("../testing.zig");
|
||||||
|
|
||||||
const Entities = @import("ecs/entities.zig").Entities;
|
const Entities = @import("entities.zig").Entities;
|
||||||
const EntityID = @import("ecs/entities.zig").EntityID;
|
const EntityID = @import("entities.zig").EntityID;
|
||||||
const is_debug = @import("ecs/Archetype.zig").is_debug;
|
const is_debug = @import("Archetype.zig").is_debug;
|
||||||
|
|
||||||
/// Verifies that M matches the basic layout of a Mach module
|
/// Verifies that M matches the basic layout of a Mach module
|
||||||
fn ModuleInterface(comptime M: type) type {
|
fn ModuleInterface(comptime M: type) type {
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const ComponentTypesByName = @import("../module.zig").ComponentTypesByName;
|
const ComponentTypesByName = @import("module.zig").ComponentTypesByName;
|
||||||
|
|
||||||
pub const QueryTag = enum {
|
pub const QueryTag = enum {
|
||||||
any,
|
any,
|
||||||
Loading…
Add table
Add a link
Reference in a new issue