module: *World is no longer an injectable parameter
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
3bfafe102d
commit
15d9efcf26
5 changed files with 44 additions and 38 deletions
|
|
@ -55,7 +55,6 @@ fn init(
|
||||||
sprite_mod: *Sprite.Mod,
|
sprite_mod: *Sprite.Mod,
|
||||||
text_mod: *Text.Mod,
|
text_mod: *Text.Mod,
|
||||||
game: *Mod,
|
game: *Mod,
|
||||||
world: *mach.World,
|
|
||||||
) !void {
|
) !void {
|
||||||
// The Mach .core is where we set window options, etc.
|
// The Mach .core is where we set window options, etc.
|
||||||
core.setTitle("gfx.Sprite example");
|
core.setTitle("gfx.Sprite example");
|
||||||
|
|
@ -65,17 +64,18 @@ fn init(
|
||||||
|
|
||||||
// Tell sprite_mod to use the texture
|
// Tell sprite_mod to use the texture
|
||||||
sprite_mod.send(.init, .{});
|
sprite_mod.send(.init, .{});
|
||||||
world.dispatchNoError(); // TODO: no dispatch in user code
|
engine.dispatchNoError(); // TODO: no dispatch in user code
|
||||||
|
const texture = text_mod.state.texture;
|
||||||
sprite_mod.send(.initPipeline, .{Sprite.PipelineOptions{
|
sprite_mod.send(.initPipeline, .{Sprite.PipelineOptions{
|
||||||
.pipeline = @intFromEnum(Pipeline.text),
|
.pipeline = @intFromEnum(Pipeline.text),
|
||||||
.texture = text_mod.state.texture,
|
.texture = texture,
|
||||||
}});
|
}});
|
||||||
world.dispatchNoError(); // TODO: no dispatch in user code
|
|
||||||
|
|
||||||
// We can create entities, and set components on them. Note that components live in a module
|
// We can create entities, and set components on them. Note that components live in a module
|
||||||
// namespace, e.g. the `Sprite` module could have a 3D `.location` component with a different
|
// namespace, e.g. the `Sprite` module could have a 3D `.location` component with a different
|
||||||
// type than the `.physics2d` module's `.location` component if you desire.
|
// type than the `.physics2d` module's `.location` component if you desire.
|
||||||
|
|
||||||
|
engine.dispatchNoError(); // TODO: no dispatch in user code
|
||||||
const r = text_mod.state.regions.get('?').?;
|
const r = text_mod.state.regions.get('?').?;
|
||||||
const player = try engine.newEntity();
|
const player = try engine.newEntity();
|
||||||
try sprite_mod.set(player, .transform, Mat4x4.translate(vec3(-0.02, 0, 0)));
|
try sprite_mod.set(player, .transform, Mat4x4.translate(vec3(-0.02, 0, 0)));
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ fn init(
|
||||||
engine: *mach.Engine.Mod,
|
engine: *mach.Engine.Mod,
|
||||||
text_mod: *Text.Mod,
|
text_mod: *Text.Mod,
|
||||||
game: *Mod,
|
game: *Mod,
|
||||||
world: *mach.World,
|
|
||||||
) !void {
|
) !void {
|
||||||
// The Mach .core is where we set window options, etc.
|
// The Mach .core is where we set window options, etc.
|
||||||
core.setTitle("gfx.Text example");
|
core.setTitle("gfx.Text example");
|
||||||
|
|
@ -113,7 +112,7 @@ fn init(
|
||||||
text_mod.send(.initPipeline, .{Text.PipelineOptions{
|
text_mod.send(.initPipeline, .{Text.PipelineOptions{
|
||||||
.pipeline = @intFromEnum(Pipeline.default),
|
.pipeline = @intFromEnum(Pipeline.default),
|
||||||
}});
|
}});
|
||||||
world.dispatchNoError(); // TODO: no dispatch in user code
|
engine.dispatchNoError(); // TODO: no dispatch in user code
|
||||||
|
|
||||||
game.state = .{
|
game.state = .{
|
||||||
.timer = try mach.Timer.start(),
|
.timer = try mach.Timer.start(),
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,6 @@ pub fn World(comptime mods: anytype) type {
|
||||||
|
|
||||||
const Modules = mach.Modules(mods);
|
const Modules = mach.Modules(mods);
|
||||||
|
|
||||||
pub const IsInjectedArgument = void;
|
|
||||||
|
|
||||||
const WorldT = @This();
|
const WorldT = @This();
|
||||||
pub fn Mod(comptime M: anytype) type {
|
pub fn Mod(comptime M: anytype) type {
|
||||||
const module_tag = M.name;
|
const module_tag = M.name;
|
||||||
|
|
@ -76,6 +74,18 @@ pub fn World(comptime mods: anytype) type {
|
||||||
world.modules.sendToModule(module_tag, event_name, args);
|
world.modules.sendToModule(module_tag, event_name, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn sendGlobal(m: *@This(), comptime event_name: anytype, args: anytype) void {
|
||||||
|
const mod_ptr: *Mods = @alignCast(@fieldParentPtr(Mods, @tagName(module_tag), m));
|
||||||
|
const world = @fieldParentPtr(WorldT, "mod", mod_ptr);
|
||||||
|
world.modules.send(event_name, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dispatchNoError(m: *@This()) void {
|
||||||
|
const mod_ptr: *Mods = @alignCast(@fieldParentPtr(Mods, @tagName(module_tag), m));
|
||||||
|
const world = @fieldParentPtr(WorldT, "mod", mod_ptr);
|
||||||
|
world.modules.dispatch(world.injectable()) catch |err| @panic(@errorName(err));
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a new entity.
|
/// Returns a new entity.
|
||||||
pub fn newEntity(m: *@This()) !EntityID {
|
pub fn newEntity(m: *@This()) !EntityID {
|
||||||
const mod_ptr: *Mods = @alignCast(@fieldParentPtr(Mods, @tagName(module_tag), m));
|
const mod_ptr: *Mods = @alignCast(@fieldParentPtr(Mods, @tagName(module_tag), m));
|
||||||
|
|
@ -115,7 +125,6 @@ pub fn World(comptime mods: anytype) type {
|
||||||
|
|
||||||
const Injectable = blk: {
|
const Injectable = blk: {
|
||||||
var types: []const type = &[0]type{};
|
var types: []const type = &[0]type{};
|
||||||
types = types ++ [_]type{*@This()};
|
|
||||||
for (@typeInfo(Mods).Struct.fields) |field| {
|
for (@typeInfo(Mods).Struct.fields) |field| {
|
||||||
const ModPtr = @TypeOf(@as(*field.type, undefined));
|
const ModPtr = @TypeOf(@as(*field.type, undefined));
|
||||||
types = types ++ [_]type{ModPtr};
|
types = types ++ [_]type{ModPtr};
|
||||||
|
|
@ -125,19 +134,14 @@ pub fn World(comptime mods: anytype) type {
|
||||||
fn injectable(world: *@This()) Injectable {
|
fn injectable(world: *@This()) Injectable {
|
||||||
var v: Injectable = undefined;
|
var v: Injectable = undefined;
|
||||||
outer: inline for (@typeInfo(Injectable).Struct.fields) |field| {
|
outer: inline for (@typeInfo(Injectable).Struct.fields) |field| {
|
||||||
if (field.type == *@This()) {
|
inline for (@typeInfo(Mods).Struct.fields) |injectable_field| {
|
||||||
@field(v, field.name) = world;
|
if (*injectable_field.type == field.type) {
|
||||||
continue :outer;
|
@field(v, field.name) = &@field(world.mod, injectable_field.name);
|
||||||
} else {
|
|
||||||
inline for (@typeInfo(Mods).Struct.fields) |injectable_field| {
|
|
||||||
if (*injectable_field.type == field.type) {
|
|
||||||
@field(v, field.name) = &@field(world.mod, injectable_field.name);
|
|
||||||
|
|
||||||
// TODO: better module initialization location
|
// TODO: better module initialization location
|
||||||
@field(v, field.name).entities = &world.entities;
|
@field(v, field.name).entities = &world.entities;
|
||||||
@field(v, field.name).allocator = world.allocator;
|
@field(v, field.name).allocator = world.allocator;
|
||||||
continue :outer;
|
continue :outer;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@compileError("failed to initialize Injectable field (this is a bug): " ++ field.name ++ " " ++ @typeName(field.type));
|
@compileError("failed to initialize Injectable field (this is a bug): " ++ field.name ++ " " ++ @typeName(field.type));
|
||||||
|
|
@ -149,10 +153,6 @@ pub fn World(comptime mods: anytype) type {
|
||||||
try world.modules.dispatch(world.injectable());
|
try world.modules.dispatch(world.injectable());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispatchNoError(world: *@This()) void {
|
|
||||||
world.modules.dispatch(world.injectable()) catch |err| @panic(@errorName(err));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn init(world: *@This(), allocator: mem.Allocator) !void {
|
pub fn init(world: *@This(), allocator: mem.Allocator) !void {
|
||||||
// TODO: switch Entities to stack allocation like Modules and World
|
// TODO: switch Entities to stack allocation like Modules and World
|
||||||
var entities = try Entities(ns_components).init(allocator);
|
var entities = try Entities(ns_components).init(allocator);
|
||||||
|
|
|
||||||
|
|
@ -29,34 +29,31 @@ pub const Engine = struct {
|
||||||
.{ .global = .exit, .handler = fn () void },
|
.{ .global = .exit, .handler = fn () void },
|
||||||
};
|
};
|
||||||
|
|
||||||
fn init(world: *World) !void {
|
fn init(engine: *Mod) !void {
|
||||||
core.allocator = allocator;
|
core.allocator = allocator;
|
||||||
try core.init(.{});
|
try core.init(.{});
|
||||||
const state = &world.mod.engine.state;
|
const state = &engine.state;
|
||||||
state.device = core.device;
|
state.device = core.device;
|
||||||
state.queue = core.device.getQueue();
|
state.queue = core.device.getQueue();
|
||||||
state.should_exit = false;
|
state.should_exit = false;
|
||||||
state.encoder = state.device.createCommandEncoder(&gpu.CommandEncoder.Descriptor{
|
state.encoder = state.device.createCommandEncoder(&gpu.CommandEncoder.Descriptor{
|
||||||
.label = "engine.state.encoder",
|
.label = "engine.state.encoder",
|
||||||
});
|
});
|
||||||
|
engine.sendGlobal(.init, .{});
|
||||||
world.modules.send(.init, .{});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(world: *World, engine: *Mod) void {
|
fn deinit(engine: *Mod) void {
|
||||||
// TODO: this triggers a device loss error, which we should handle correctly
|
// TODO: this triggers a device loss error, which we should handle correctly
|
||||||
// engine.state.device.release();
|
// engine.state.device.release();
|
||||||
engine.state.queue.release();
|
engine.state.queue.release();
|
||||||
world.modules.send(.deinit, .{});
|
engine.sendGlobal(.deinit, .{});
|
||||||
core.deinit();
|
core.deinit();
|
||||||
world.deinit();
|
|
||||||
_ = gpa.deinit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Engine module's exit handler
|
// Engine module's exit handler
|
||||||
fn exit(world: *World) void {
|
fn exit(engine: *Mod) void {
|
||||||
world.modules.send(.exit, .{});
|
engine.sendGlobal(.exit, .{});
|
||||||
world.mod.engine.state.should_exit = true;
|
engine.state.should_exit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn beginPass(engine: *Mod, clear_color: gpu.Color) void {
|
fn beginPass(engine: *Mod, clear_color: gpu.Color) void {
|
||||||
|
|
@ -110,6 +107,10 @@ pub const App = struct {
|
||||||
|
|
||||||
pub fn deinit(app: *@This()) void {
|
pub fn deinit(app: *@This()) void {
|
||||||
app.world.modules.sendToModule(.engine, .deinit, .{});
|
app.world.modules.sendToModule(.engine, .deinit, .{});
|
||||||
|
// TODO: improve error handling
|
||||||
|
app.world.dispatch() catch |err| @panic(@errorName(err)); // dispatch .deinit
|
||||||
|
app.world.deinit();
|
||||||
|
_ = gpa.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(app: *@This()) !bool {
|
pub fn update(app: *@This()) !bool {
|
||||||
|
|
@ -134,5 +135,7 @@ fn modules() Modules() {
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
// TODO: verify modules (causes loop currently)
|
||||||
|
// _ = @import("module.zig").Modules(@import("root").modules);
|
||||||
return @import("root").modules;
|
return @import("root").modules;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,11 @@ pub fn Modules(comptime mods: anytype) type {
|
||||||
},
|
},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
return UninjectedArgsTuple(std.meta.Tuple, Handler);
|
|
||||||
|
// TODO: passing std.meta.Tuple here instead of TupleHACK results in a compiler
|
||||||
|
// segfault. The only difference is that TupleHACk does not produce a real tuple,
|
||||||
|
// `@Type(.{.Struct = .{ .is_tuple = false }})` instead of `.is_tuple = true`.
|
||||||
|
return UninjectedArgsTuple(TupleHACK, Handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@compileError("No global event handler ." ++ @tagName(event_name) ++ " is defined in any module.");
|
@compileError("No global event handler ." ++ @tagName(event_name) ++ " is defined in any module.");
|
||||||
|
|
@ -986,7 +990,7 @@ test "dispatch" {
|
||||||
// Global events which are not handled by anyone yet can be written as `pub const fooBar = fn() void;`
|
// Global events which are not handled by anyone yet can be written as `pub const fooBar = fn() void;`
|
||||||
// within a module, which allows pre-declaring that `fooBar` is a valid global event, and enables
|
// within a module, which allows pre-declaring that `fooBar` is a valid global event, and enables
|
||||||
// its arguments to be inferred still like this:
|
// its arguments to be inferred still like this:
|
||||||
modules.send(.frame_done, .{1337});
|
modules.send(.frame_done, .{ .@"0" = 1337 });
|
||||||
|
|
||||||
// Local events
|
// Local events
|
||||||
modules.sendToModule(.engine_renderer, .update, .{});
|
modules.sendToModule(.engine_renderer, .update, .{});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue