diff --git a/src/main.zig b/src/main.zig index 255d758..3a1d86b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -12,59 +12,203 @@ pub const DbVector2 = struct { y: f32, }; -pub const person: spacetime.Table = .{ .schema = Person, }; -pub const Person = struct{ +pub const config: spacetime.Table = .{ .schema = Config, .primary_key = "id", .access = .Public, }; +pub const Config = struct { + //#[primary_key] + id: u32, + world_size: u64, +}; + +pub const entity: spacetime.Table = .{ .schema = Entity, .primary_key = "entity_id", .access = .Public }; +pub const Entity = struct { + //#[auto_inc] + //#[primary_key] + entity_id: u32, + position: DbVector2, + mass: u32, +}; + +pub const circles: spacetime.Table = .{ + .schema = Circle, + .primary_key = "entity_id", + .access = .Public, + .indexes = &.{ .{ .name = "player_id", .layout = .BTree } }, +}; +pub const Circle = struct { + //#[auto_inc] + //#[primary_key] + entity_id: u32, + //#[index(btree)] + player_id: u32, + direction: DbVector2, + speed: f32, + last_split_time: spacetime.Timestamp, +}; + +pub const players: spacetime.Table = .{ + .schema = Player, + .primary_key = "identity", + .access = .Public, + .unique = &.{ "player_id" }, + .autoinc = &.{ "player_id" }, +}; +pub const logged_out_players: spacetime.Table = .{ + .schema = Player, + .primary_key = "identity", + .unique = &.{ "player_id" } +}; +pub const Player = struct { + //#[primary_key] + identity: spacetime.Identity, + //#[unique] + //#[auto_inc] + player_id: u32, name: []const u8, - pos: DbVector2, - schedule: spacetime.ScheduleAt, + + pub fn destroy(self: *@This(), allocator: std.mem.Allocator) void { + allocator.free(self.name); + allocator.destroy(self); + } }; -pub const Init: spacetime.Reducer = .{ - .func_type = @TypeOf(InitReducer), - .func = @ptrCast(&InitReducer), - .lifecycle = .Init, +pub const food: spacetime.Table = .{ .schema = Food, .primary_key = "entity_id", .access = .Public }; +pub const Food = struct { + //#[primary_key] + entity_id: u32, }; -pub fn InitReducer(_: *spacetime.ReducerContext) void { - // Called when the module is initially published - spacetime.print("[Init]"); +//#[spacetimedb::table(name = spawn_food_timer, scheduled(spawn_food))] +pub const spawn_food_timer: spacetime.Table = .{ .schema = SpawnFoodTimer, .primary_key = "scheduled_id" }; +pub const SpawnFoodTimer = struct { + //#[primary_key] + //#[auto_inc] + scheduled_id: u64, + scheduled_at: spacetime.ScheduleAt, +}; + +//#[spacetimedb::table(name = circle_decay_timer, scheduled(circle_decay))] +pub const circle_decay_timer: spacetime.Table = .{ .schema = CircleDecayTimer, .primary_key = "scheduled_id" }; +pub const CircleDecayTimer = struct { + //#[primary_key] + //#[auto_inc] + scheduled_id: u64, + scheduled_at: spacetime.ScheduleAt, +}; + +//#[spacetimedb::table(name = circle_recombine_timer, scheduled(circle_recombine))] +pub const circle_recombine_timer: spacetime.Table = .{ .schema = CircleRecombineTimer, .primary_key = "scheduled_id" }; +pub const CircleRecombineTimer = struct { + //#[primary_key] + //#[auto_inc] + scheduled_id: u64, + scheduled_at: spacetime.ScheduleAt, + player_id: u32, +}; + +pub const consume_entity_timer: spacetime.Table = .{ .schema = ConsumeEntityTimer, .primary_key = "scheduled_id" }; +pub const ConsumeEntityTimer = struct { + //#[primary_key] + //#[auto_inc] + scheduled_id: u64, + scheduled_at: spacetime.ScheduleAt, + consumed_entity_id: u32, + consumer_entity_id: u32, +}; + +pub const Init: spacetime.Reducer = .{ .func_type = @TypeOf(InitReducer), .func = @ptrCast(&InitReducer), .lifecycle = .Init, }; +pub fn InitReducer(ctx: *spacetime.ReducerContext) !void { + std.log.info("Initializing...", .{}); + try ctx.db.get("config").insert(Config { + .id = 0, + .world_size = 1000, + }); + try ctx.db.get("circle_decay_timer").insert(CircleDecayTimer { + .scheduled_id = 0, + .scheduled_at = .{ .Interval = .{ .__time_duration_micros__ = 5 * std.time.us_per_s }}, + }); + try ctx.db.get("spawn_food_timer").insert(SpawnFoodTimer { + .scheduled_id = 0, + .scheduled_at = .{ .Interval = .{ .__time_duration_micros__ = 500 * std.time.us_per_ms }} + }); + try ctx.db.get("move_all_players_timer").insert(MoveAllPlayersTimer { + .scheduled_id = 0, + .scheduled_at = .{ .Interval = .{ .__time_duration_micros__ = 50 * std.time.us_per_ms }} + }); } pub const OnConnect = spacetime.Reducer{ .func_type = @TypeOf(OnConnectReducer), .func = @ptrCast(&OnConnectReducer), .lifecycle = .OnConnect, }; -pub fn OnConnectReducer(_: *spacetime.ReducerContext) void { +pub fn OnConnectReducer(ctx: *spacetime.ReducerContext) !void { // Called everytime a new client connects - spacetime.print("[OnConnect]"); + std.log.info("[OnConnect]", .{}); + const nPlayer = try ctx.db.get("logged_out_players").col("identity").find(.{ .identity = ctx.sender }); + if (nPlayer) |player| { + try ctx.db.get("players").insert(player.*); + try ctx.db.get("logged_out_players").col("identity").delete(.{ .identity = player.identity }); + } else { + try ctx.db.get("players").insert(Player { + .identity = ctx.sender, + .player_id = 0, + .name = "", + }); + } } pub const OnDisconnect = spacetime.Reducer{ .func_type = @TypeOf(OnDisconnectReducer), .func = @ptrCast(&OnDisconnectReducer), .lifecycle = .OnDisconnect, }; -pub fn OnDisconnectReducer(_: *spacetime.ReducerContext) void { +pub fn OnDisconnectReducer(ctx: *spacetime.ReducerContext) !void { // Called everytime a client disconnects - spacetime.print("[OnDisconnect]"); -} - -pub const add = spacetime.Reducer{ .func_type = @TypeOf(addReducer), .func = @ptrCast(&addReducer), .params = &.{ "name", "time" }}; -pub fn addReducer(ctx: *spacetime.ReducerContext, name: []const u8, time: i64) void { - const personTable = ctx.*.db.get("person"); - personTable.insert(Person{ - .name = name, - .pos = DbVector2{ .x = 10.4, .y = 20.6 }, - .schedule = .{ .Interval = .{ .__time_duration_micros__ = time, }, }, - }); - - var buf: [128]u8 = undefined; - spacetime.print(std.fmt.bufPrint(&buf, "[add] {{{s}}}!", .{ name }) catch "[add] Error: name to long"); -} - -pub const say_hello = spacetime.Reducer{ .func_type = @TypeOf(say_helloReducer), .func = @ptrCast(&say_helloReducer), }; -pub fn say_helloReducer(ctx: *spacetime.ReducerContext) void { - //_ = ctx; - var personIter = ctx.*.db.get("person").iter(); - while(personIter.next() catch { - @panic("person Iter errored!"); - }) |item| { - var buffer: [512]u8 = undefined; - const msg = std.fmt.bufPrint(&buffer, "Hello, {s} (pos: {{{d}, {d}}}) (time: {})!", .{ item.name, item.pos.x, item.pos.y, item.schedule.Interval.__time_duration_micros__ }) catch ""; - spacetime.print(msg); + std.log.info("[OnDisconnect]", .{}); + const nPlayer = try ctx.db.get("players").col("identity").find(.{ .identity = ctx.sender}); + if(nPlayer == null) { + std.log.err("Disconnecting player doesn't have a valid players row!",.{}); + return; } - spacetime.print("Hello, World!"); -} \ No newline at end of file + const player = nPlayer.?; + //std.log.info("{?}", .{player}); + const player_id = player.player_id; + try ctx.db.get("logged_out_players").insert(player.*); + try ctx.db.get("players").col("identity").delete(.{ .identity = ctx.sender}); + + // Remove any circles from the arena + var iter = ctx.db.get("circles").col("player_id").filter(.{ .player_id = player_id }); + //_ = player_id; + _ = &iter; + // std.log.info("blag", .{}); + // while (try iter.next()) |circle_val| { + // try ctx.db.get("entity").col("entity_id").delete(.{ .entity_id = circle_val.entity_id, }); + // try ctx.db.get("circle").col("entity_id").delete(.{ .entity_id = circle_val.entity_id, }); + // } +} + +//#[spacetimedb::table(name = move_all_players_timer, scheduled(move_all_players))] +pub const move_all_players_timer: spacetime.Table = .{ + .schema = MoveAllPlayersTimer, + .primary_key = "scheduled_id", + .schedule_reducer = &move_all_players +}; +pub const MoveAllPlayersTimer = struct { + //#[primary_key] + //#[auto_inc] + scheduled_id: u64, + scheduled_at: spacetime.ScheduleAt, +}; + +pub const move_all_players = spacetime.Reducer{ + .func_type = @TypeOf(move_all_players_reducer), + .func = @ptrCast(&move_all_players_reducer), + .params = &.{ "_timer" } +}; +pub fn move_all_players_reducer(ctx: *spacetime.ReducerContext, _timer: MoveAllPlayersTimer) !void { + _ = ctx; + _ = _timer; + //std.log.info("Move Players!", .{}); + return; +} + +pub const say_hello = spacetime.Reducer{ .func_type = @TypeOf(say_hello_reducer), .func = @ptrCast(&say_hello_reducer)}; + +pub fn say_hello_reducer(ctx: *spacetime.ReducerContext) !void { + _ = ctx; + std.log.info("Hello!", .{}); + return; +} + diff --git a/src/spacetime.zig b/src/spacetime.zig index 3794b4c..37340ae 100644 --- a/src/spacetime.zig +++ b/src/spacetime.zig @@ -265,10 +265,14 @@ pub fn zigTypeToSpacetimeType(comptime param: ?type) AlgebraicType { []const u8 => .{ .String = {} }, i32 => .{ .I32 = {}, }, i64 => .{ .I64 = {}, }, + i128 => .{ .I128 = {}, }, + i256 => .{ .I258 = {}, }, u32 => .{ .U32 = {}, }, u64 => .{ .U64 = {}, }, - f32 => .{ .F32 = {}, }, + u128 => .{ .U128 = {}, }, u256 => .{ .U256 = {}, }, + f32 => .{ .F32 = {}, }, + f64 => .{ .F64 = {}, }, else => blk: { if(@typeInfo(param.?) == .@"struct") { var elements: []const ProductTypeElement = &.{}; @@ -446,6 +450,28 @@ pub fn compile(comptime moduleTables : []const Table, comptime moduleReducers : } }; } + if(table.indexes) |_indexes| { + inline for(_indexes) |index| { + + const fieldIndex = std.meta.fieldIndex(table.schema, index.name).?; + + const indexAlgo: RawIndexAlgorithm = blk: { + switch(index.layout) { + .BTree => break :blk .{ .BTree = &.{ fieldIndex } }, + .Hash => break :blk .{ .Hash = &.{ fieldIndex } }, + .Direct => break :blk .{ .Direct = fieldIndex }, + } + }; + + indexes = indexes ++ &[_]RawIndexDefV9{ + RawIndexDefV9{ + .name = null, + .accessor_name = index.name, + .algorithm = indexAlgo + } + }; + } + } var constraints: []const RawConstraintDefV9 = &[_]RawConstraintDefV9{}; if(table.primary_key) |_| { @@ -657,6 +683,11 @@ pub const Reducer = struct { func: *const fn()void, }; +pub const Index = struct { + name: []const u8, + layout: std.meta.Tag(RawIndexAlgorithm), +}; + pub const Table = struct { name: ?[]const u8 = null, schema: type, @@ -664,7 +695,7 @@ pub const Table = struct { access: TableAccess = .Private, primary_key: ?[]const u8 = null, schedule_reducer: ?*const Reducer = null, - indexes: ?[]const []const u8 = null, + indexes: ?[]const Index = null, unique: ?[]const []const u8 = null, autoinc: ?[]const []const u8 = null, }; @@ -771,7 +802,7 @@ pub export fn __call_reducer__( comptime var argCount = 1; comptime var argList: []const std.builtin.Type.StructField = &[_]std.builtin.Type.StructField{ std.builtin.Type.StructField{ - .alignment = 0, + .alignment = @alignOf(*ReducerContext), .default_value = null, .is_comptime = false, .name = "0", @@ -783,7 +814,7 @@ pub export fn __call_reducer__( _ = name; argList = argList ++ &[_]std.builtin.Type.StructField{ std.builtin.Type.StructField{ - .alignment = 0, + .alignment = @alignOf(param.type.?), .default_value = null, .is_comptime = false, .name = comptime utils.itoa(argCount), diff --git a/src/spacetime/FFI.zig b/src/spacetime/FFI.zig new file mode 100644 index 0000000..78535f8 --- /dev/null +++ b/src/spacetime/FFI.zig @@ -0,0 +1,33 @@ +const spacetime = @import("../spacetime.zig"); + +const BytesSink = spacetime.BytesSink; +const BytesSource = spacetime.BytesSource; +const TableId = spacetime.TableId; +const RowIter = spacetime.RowIter; +const IndexId = spacetime.IndexId; +const ColId = spacetime.ColId; + +extern "spacetime_10.0" fn bytes_sink_write(sink: BytesSink, buffer_ptr: [*c]const u8, buffer_len_ptr: *usize) u16; +extern "spacetime_10.0" fn bytes_source_read(source: BytesSource, buffer_ptr: [*c]u8, buffer_len_ptr: *usize) i16; +extern "spacetime_10.0" fn table_id_from_name(name: [*c]const u8, name_len: usize, out: *TableId) u16; +extern "spacetime_10.0" fn datastore_insert_bsatn(table_id: TableId, row_ptr: [*c]const u8, row_len_ptr: *usize) u16; +extern "spacetime_10.0" fn row_iter_bsatn_advance(iter: RowIter, buffer_ptr: [*c]u8, buffer_len_ptr: *usize) i16; +extern "spacetime_10.0" fn datastore_table_scan_bsatn(table_id: TableId, out: [*c]RowIter) u16; +extern "spacetime_10.0" fn index_id_from_name(name_ptr: [*c]const u8, name_len: usize, out: *IndexId) u16; +extern "spacetime_10.0" fn datastore_index_scan_range_bsatn( index_id: IndexId, prefix_ptr: [*c]const u8, prefix_len: usize, prefix_elems: ColId, rstart_ptr: [*c]const u8, rstart_len: usize, rend_ptr: [*c]const u8, rend_len: usize, out: *RowIter) u16; + +pub fn tableIdFromName(name: []const u8, out: *TableId) u16 { + return spacetime.retMap(table_id_from_name(name.ptr, name.len, out)); +} + +pub fn datastoreTableScanBsatn(table_id: TableId, out: [*c]RowIter) u16 { + return spacetime.retMap(datastore_table_scan_bsatn(table_id, out)); +} + +pub fn indexIdFromName(name: []const u8, out: *IndexId) u16 { + return spacetime.retMap(index_id_from_name(name.ptr, name.len, out)); +} + +pub fn datastoreIndexScanRangeBsatn( index_id: IndexId, prefix: []const u8, prefix_elems: ColId, rstart: []const u8, rend: []const u8, out: *RowIter) u16 { + return spacetime.retMap(datastore_index_scan_range_bsatn( index_id, prefix.ptr, prefix.len, prefix_elems, rstart.ptr, rstart.len, rend.ptr, rend.len, out)); +} diff --git a/src/spacetime/types.zig b/src/spacetime/types.zig index f2b288a..fb6a785 100644 --- a/src/spacetime/types.zig +++ b/src/spacetime/types.zig @@ -346,39 +346,28 @@ pub fn Iter(struct_type: type) type { last_ret: SpacetimeValue = .OK, pub fn next(self: *@This()) spacetime.ReducerError!?*struct_type { - std.log.debug("line: {} (handle: {})", .{358, self.handle}); var buffer_len: usize = undefined; - //while(true) - //{ var ret: spacetime.SpacetimeValue = self.last_ret; if(self.contents == null or self.contents.?.len == 0) { - std.log.debug("line: {} (contents: {any})", .{364, self.contents}); if(self.handle._inner == spacetime.RowIter.INVALID._inner) { - std.log.debug("line: {}", .{366}); - self.contents = null; return null; } - std.log.debug("line: {}", .{371}); buffer_len = self.buffer.len; - std.log.debug("line: {}", .{374}); ret = try spacetime.retMap(spacetime.row_iter_bsatn_advance(self.handle, @constCast(@ptrCast(&self.buffer)), &buffer_len)); - std.log.debug("ret: {}", .{ret}); - std.log.debug("self.buffer[0..buffer_len]: {any} {any} {any}", .{(&self.buffer).ptr, self.buffer.len, buffer_len}); self.contents = self.buffer[0..buffer_len]; - std.log.debug("line: {}", .{379}); if(ret == .EXHAUSTED) { - std.log.debug("line: {}", .{382}); self.handle = spacetime.RowIter.INVALID; } - std.log.debug("line: {}", .{385}); + self.last_ret = ret; + } + if(self.contents == null or self.contents.?.len == 0) { + return null; } - std.log.debug("{}", .{struct_type}); return StructDeserializer(struct_type)(self.allocator, &(self.contents.?)); - //} } pub fn one_or_null(self: *@This()) ?*struct_type { @@ -428,7 +417,7 @@ pub fn Column2ORM(comptime table_name: []const u8, comptime column_name: [:0]con allocator: std.mem.Allocator, pub fn filter(self: @This(), val: wrapped_type) !Iter(struct_type) { - const temp_name: []const u8 = table_name ++ "_" ++ column_name ++ "_idx_btree"; + const temp_name: []const u8 = comptime table_name ++ "_" ++ column_name ++ "_idx_btree"; var id = spacetime.IndexId{ ._inner = std.math.maxInt(u32)}; const err = try spacetime.retMap(spacetime.index_id_from_name(temp_name.ptr, temp_name.len, &id)); std.log.debug("index_id_from_name({}): {x}", .{err, id._inner});