diff --git a/src/client/chunk.zig b/src/client/chunk.zig new file mode 100644 index 0000000..3a8de97 --- /dev/null +++ b/src/client/chunk.zig @@ -0,0 +1,73 @@ +const std = @import("std"); + +const shared = @import("shared"); +const enet = @import("c.zig").enet; + +pub fn spawn(self: *shared.chunk.Chunk, allocator: std.mem.Allocator, comptime T: type, value: T) !shared.entity.id { + std.debug.assert(value.id != shared.entity.INVALID_ID); + + const ptr = try allocator.create(T); + errdefer allocator.destroy(ptr); + + ptr.* = value; + + const ref = shared.entity.makeRef(T, ptr); + + try self.entities.append(allocator, ref); + + return ptr.id; +} + +pub fn find(self: *shared.chunk.Chunk, id: shared.entity.id) ?shared.entity.Ref { + for (self.entities.items) |ref| { + switch (ref) { + inline else => |ptr| { + if (ptr.id == id) { + return ref; + } + } + } + } + + return null; +} + +pub fn findT(self: *shared.chunk.Chunk, comptime T: type, id: shared.entity.id) ?*T { + for (self.entities.items) |ref| { + switch (ref) { + inline else => |ptr| { + if (ptr.id == id and @TypeOf(ptr) == *T) { + return ptr; + } + } + } + } + + return null; +} + +pub fn despawn(self: *shared.chunk.Chunk, allocator: std.mem.Allocator, id: shared.entity.id) bool { + var i: usize = 0; + while (i < self.entities.items.len) { + const ref = self.entities.items[i]; + + var found = false; + + switch (ref) { + inline else => |ptr| { + if (ptr.id == id) { + allocator.destroy(ptr); + found = true; + } + }, + } + + if (found) { + _ = self.entities.swapRemove(i); + return true; + } + + i += 1; + } + return false; +} diff --git a/src/shared/protocol_v1.zig b/src/shared/protocol_v1.zig new file mode 100644 index 0000000..4bf062b --- /dev/null +++ b/src/shared/protocol_v1.zig @@ -0,0 +1,158 @@ +const std = @import("std"); +const zm = @import("zmath"); +// const bufzilla = @import("bufzilla"); + +const entity = @import("entity.zig"); +const bits = @import("bits.zig"); + +pub const SERVER_PORT: u16 = 1337; + +const MessageKind = enum(c_char) { + spawn_entity, + update_entity, + despawn_entity, +}; + +pub const Message = union(MessageKind) { + spawn_entity: SpawnEntity, + update_entity: UpdateEntity, + despawn_entity: DespawnEntity, +}; + +const EntityKind = enum(c_char) { + soldier, + alien, +}; + +pub const SpawnEntity = union(EntityKind) { + soldier: Soldier, + alien: Alien, +}; + +pub const UpdateEntity = union(EntityKind) { + soldier: Soldier, + alien: Alien, +}; + +pub const DespawnEntity = union(EntityKind) { + soldier: Soldier, + alien: Alien, +}; + +pub fn makeSpawnMessage(e: entity.Ref) Message { + switch (e) { + .Soldier => |s| { return Soldier.makeSpawn(s.*); }, + .Alien => |a| { return Alien.makeSpawn(a.*); }, + } +} + +pub fn makeUpdateMessage(e: entity.Ref) Message { + switch (e) { + .Soldier => |s| { return Soldier.makeUpdate(s.*); }, + .Alien => |a| { return Alien.makeUpdate(a.*); }, + } +} + +pub fn makeDespawnMessage(e: entity.Ref) Message { + switch (e) { + .Soldier => |s| { return Soldier.makeDespawn(s.*); }, + .Alien => |a| { return Alien.makeDespawn(a.*); }, + } +} + +pub const Soldier = struct { + id: entity.id = entity.INVALID_ID, + hp: i32, + pos: zm.Vec, + vel: zm.Vec, + + pub fn init(soldier: entity.Soldier) Soldier { + return .{ + .id = soldier.id, + .hp = soldier.hp, + .pos = soldier.pos, + .vel = soldier.vel, + }; + } + + pub fn makeSpawn(soldier: entity.Soldier) Message { + return .{ + .spawn_entity = .{ .soldier = init(soldier) } + }; + } + + pub fn makeUpdate(soldier: entity.Soldier) Message { + return .{ + .update_entity = .{ .soldier = init(soldier) } + }; + } + + pub fn makeDespawn(soldier: entity.Soldier) Message { + return .{ + .despawn_entity = .{ .soldier = init(soldier) } + }; + } +}; + +pub const Alien = struct { + id: entity.id = entity.INVALID_ID, + hp: i32, + pos: zm.Vec, + + pub fn init(alien: entity.Alien) Alien { + return .{ + .id = alien.id, + .pos = alien.pos, + .hp = alien.hp, + }; + } + + pub fn makeSpawn(alien: entity.Alien) Message { + return .{ + .spawn_entity = .{ .alien = init(alien) } + }; + } + + pub fn makeUpdate(alien: entity.Alien) Message { + return .{ + .update_entity = .{ .alien = init(alien) } + }; + } + + pub fn makeDespawn(alien: entity.Alien) Message { + return .{ + .despawn_entity = .{ .alien = init(alien) } + }; + } +}; + +test "Protocol" { + std.debug.print("Protocol\n", .{}); + + const s = entity.Soldier{ + .hp = 66, + .pos = .{1, 2, 3, 4}, + .vel = .{5, 6, 7, 8}, + }; + + const msg = makeSpawnMessage(s); + + const allocator = std.testing.allocator; + + var aw = try std.ArrayList(u8).initCapacity(allocator, 128); + defer aw.deinit(allocator); + + var writer = bits.BitWriter.init(&aw); + + try writer.serialize(allocator, msg); + + var reader = bits.BitReader.init(writer.written()); + + const recv = try reader.deserialize(allocator, Message); + + std.debug.print("msg: {}\n", .{msg}); + + std.debug.print("recv: {}\n", .{recv}); + + try std.testing.expectEqual(msg, recv); +}