You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
5.2 KiB
140 lines
5.2 KiB
const std = @import("std"); |
|
const Allocator = std.mem.Allocator; |
|
|
|
const flecs = @import("./main.zig"); |
|
const c = flecs.c; |
|
const err = @import("./error.zig"); |
|
const util = @import("./util.zig"); |
|
|
|
const Lookup = @import("./main.zig").Lookup; |
|
const Entity = @import("./entity.zig").Entity; |
|
const EntityError = @import("./entity.zig").EntityError; |
|
const Iter = @import("./iter.zig").Iter; |
|
|
|
pub fn World(comptime ctx: anytype) type { |
|
return struct { |
|
raw: *c.ecs_world_t, |
|
|
|
const Self = @This(); |
|
|
|
pub fn init() !*Self { |
|
std.debug.assert(flecs.is_initialized); |
|
var result = try flecs.allocator.create(Self); |
|
result.raw = c.ecs_init().?; |
|
return result; |
|
} |
|
|
|
pub fn initWithArgs(args: [][*:0]const u8) !*Self { |
|
std.debug.assert(flecs.is_initialized); |
|
var result = try flecs.allocator.create(Self); |
|
result.raw = c.ecs_init_w_args(args.len, args.ptr).?; |
|
return result; |
|
} |
|
|
|
pub fn initMinimal() !*Self { |
|
std.debug.assert(flecs.is_initialized); |
|
var result = try flecs.allocator.create(Self); |
|
result.raw = c.ecs_mini().?; |
|
return result; |
|
} |
|
|
|
pub fn deinit(self: *Self) void { |
|
_ = c.ecs_fini(self.raw); |
|
flecs.allocator.destroy(self); |
|
} |
|
|
|
pub fn progress(self: *Self, delta_time: f32) bool { |
|
return c.ecs_progress(self.raw, delta_time); |
|
} |
|
|
|
/// Returns an `Entity` for the specified `ecs_entity_t` value, or an |
|
/// error if the entity is invalid or not alive in this `World`. |
|
pub fn lookupAlive(self: *Self, id: c.ecs_entity_t) !Entity(ctx) { |
|
const result = Entity(ctx).fromRaw(self, id); |
|
try result.ensureAlive(); |
|
return result; |
|
} |
|
|
|
/// Returns the component `Entity` registered for the specified |
|
/// type `T`, or an error if an association has not been made. |
|
pub fn lookupByType(self: *Self, comptime T: type) !Entity(ctx) { |
|
return lookupAlive(self, Lookup(ctx, T).id); |
|
} |
|
|
|
/// Creates a new `Entity` in this `World`. |
|
/// See `Entity.new(...)` for more information. |
|
pub fn entity(self: *Self, config: Entity(ctx).Config, add: anytype) !Entity(ctx) { |
|
return Entity(ctx).new(self, config, add); |
|
} |
|
|
|
pub fn component(self: *Self, comptime T: type) !Entity(ctx) { |
|
const name = util.simpleTypeName(T); |
|
const entity2 = try self.entity(.{ .name = name, .symbol = name, .use_low_id = true }, .{}); |
|
|
|
const desc = std.mem.zeroInit(c.ecs_component_desc_t, .{ |
|
.entity = entity2.raw, |
|
.type = .{ .size = @sizeOf(T), .alignment = @alignOf(T) }, |
|
}); |
|
|
|
var result = c.ecs_component_init(self.raw, &desc); |
|
if (result == 0) return err.getLastErrorOrUnknown(); |
|
Lookup(ctx, T).id = result; |
|
return Entity(ctx).fromRaw(self, result); |
|
} |
|
|
|
pub fn system( |
|
self: *Self, |
|
name: [:0]const u8, |
|
callback: SystemCallback, |
|
phase: anytype, |
|
expr: [:0]const u8, |
|
) !Entity(ctx) { |
|
const phase2 = util.anyToEntity(ctx, phase); |
|
const entity2 = try if (phase2 != 0) |
|
self.entity(.{ .name = name }, .{ .{ c.EcsDependsOn, phase2 }, phase2 }) |
|
else |
|
self.entity(.{ .name = name }, .{}); |
|
|
|
var context = try SystemCallbackContext.init(self, callback); |
|
var desc = std.mem.zeroInit(c.ecs_system_desc_t, .{ |
|
.entity = entity2.raw, |
|
.callback = &SystemCallbackContext.invoke, |
|
.binding_ctx = context, |
|
.binding_ctx_free = &SystemCallbackContext.free, |
|
}); |
|
desc.query.filter.expr = expr; |
|
|
|
const result = c.ecs_system_init(self.raw, &desc); |
|
if (result == 0) return err.getLastErrorOrUnknown(); |
|
return Entity(ctx).fromRaw(self, result); |
|
} |
|
|
|
const SystemCallback = *const fn (Iter(ctx)) void; |
|
const SystemCallbackContext = struct { |
|
world: *Self, |
|
func: SystemCallback, |
|
|
|
pub fn init(world: *Self, callback: SystemCallback) !*SystemCallbackContext { |
|
var result = try flecs.allocator.create(SystemCallbackContext); |
|
result.world = world; |
|
result.func = callback; |
|
return result; |
|
} |
|
|
|
fn free(context: ?*anyopaque) callconv(.C) void { |
|
const self: *SystemCallbackContext = @alignCast(@ptrCast(context)); |
|
flecs.allocator.destroy(self); |
|
} |
|
|
|
// FIXME: Dependency loop. |
|
// Currently needs manual changing of the generated C code. |
|
// fn invoke(it: ?*c.ecs_iter_t) callconv(.C) void { |
|
fn invoke(it2: *anyopaque) callconv(.C) void { |
|
const it: ?*c.ecs_iter_t = @alignCast(@ptrCast(it2)); |
|
const context: *SystemCallbackContext = @alignCast(@ptrCast(it.?.binding_ctx)); |
|
var iter = Iter(ctx).fromRawPtr(context.world, it.?); |
|
context.func(iter); |
|
} |
|
}; |
|
}; |
|
}
|
|
|