diff --git a/build.zig b/build.zig index f9d7664..87ed1e4 100644 --- a/build.zig +++ b/build.zig @@ -131,6 +131,7 @@ pub fn build(b: *std.Build) void { .optimize = optimize, }); + // shared.linkLibrary(enet.artifact("enet")); client.root_module.linkLibrary(enet.artifact("enet")); server.root_module.linkLibrary(enet.artifact("enet")); } diff --git a/build.zig.zon b/build.zig.zon index 2600b76..12fa983 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -44,8 +44,8 @@ .path = "vendor/enet", }, .bufzilla = .{ - .url = "https://github.com/theseyan/bufzilla/archive/refs/tags/v0.3.2.tar.gz", - .hash = "bufzilla-0.3.0-gU6dXi67AQAg3WIFrNQ0iafrvexj3iBwVcczrVzrN3Ir", + .url = "https://github.com/theseyan/bufzilla/archive/refs/tags/v0.3.3.tar.gz", + .hash = "bufzilla-0.3.0-gU6dXie7AQDTXB7ptRjLa1plj3txaUVKFvT39e3v-pop", }, .tracy = .{ .path = "vendor/tracy", diff --git a/src/client/main.zig b/src/client/main.zig index 7ab875a..1994c52 100644 --- a/src/client/main.zig +++ b/src/client/main.zig @@ -134,10 +134,20 @@ pub fn main() !void { while (enet.enet_host_service(host, &event, 0) > 0) { switch (event.type) { enet.ENET_EVENT_TYPE_CONNECT => { - std.log.info("connect", .{}); + std.log.info("A new client connected from {d}:{d}.", .{ + event.peer.*.address.host, + event.peer.*.address.port}); + + event.peer.*.data = @constCast(@ptrCast("Client information")); }, enet.ENET_EVENT_TYPE_RECEIVE => { - std.log.info("receive", .{}); + std.log.info("A packet of length {d} containing {s} was received from {s} on channel {d}.", .{ + event.packet.*.dataLength, + event.packet.*.data, + @as([*:0]const u8, @ptrCast(event.peer.*.data.?)), + event.channelID}); + + enet.enet_packet_destroy(event.packet); }, enet.ENET_EVENT_TYPE_DISCONNECT => { std.log.info("disconnect", .{}); @@ -304,7 +314,7 @@ pub fn main() !void { rl.EndDrawing(); drawing_zone.End(); - const swap_zone = tracy.ZoneNC(@src(), "swapScreenBuffer", 0x00_ff_00_00); + const swap_zone = tracy.ZoneNC(@src(), "SwapScreenBuffer", 0x00_ff_00_00); rl.SwapScreenBuffer(); swap_zone.End(); diff --git a/src/server/chunk.zig b/src/server/chunk.zig index 8d4e041..93fe91f 100644 --- a/src/server/chunk.zig +++ b/src/server/chunk.zig @@ -3,6 +3,7 @@ const bufzilla = @import("bufzilla"); const shared = @import("shared"); const server = @import("server.zig"); +const enet = @import("c.zig").enet; pub fn spawn(chunk: *shared.chunk.Chunk, comptime T: type, allocator: std.mem.Allocator, value: T) !void { std.debug.assert(value.id == shared.entity.INVALID_ID); @@ -14,12 +15,14 @@ pub fn spawn(chunk: *shared.chunk.Chunk, comptime T: type, allocator: std.mem.Al entity.id = id; inline for (@typeInfo(shared.chunk.Chunk).@"struct".fields) |field| { - if (field.type == shared.chunk.Storage(T)) { - try @field(chunk, field.name).items.append(allocator, entity); + if (field.type == std.ArrayList(T)) { + try @field(chunk, field.name).append(allocator, entity); break; } } + std.log.info("{}", .{entity.to_message()}); + // serialize entity var buffer: [128]u8 = undefined; var fixed = std.io.Writer.fixed(&buffer); @@ -40,3 +43,11 @@ pub fn spawn(chunk: *shared.chunk.Chunk, comptime T: type, allocator: std.mem.Al // } // } } + +pub fn broadcastChanges(chunk: *shared.chunk.Chunk, host: *enet.ENetHost) !void { + _ = chunk; + const data = "packet"; + const packet = enet.enet_packet_create(data, data.len + 1, enet.ENET_PACKET_FLAG_RELIABLE); + + enet.enet_host_broadcast(host, 0, packet); +} diff --git a/src/server/main.zig b/src/server/main.zig index 4c83b2d..77be332 100644 --- a/src/server/main.zig +++ b/src/server/main.zig @@ -14,6 +14,8 @@ var accumulator : f32 = 0; var k : f32 = 1.0; var frame : i32 = 0; +var send_accumulator : f32 = 0; + var dbg_allocator = std.heap.DebugAllocator(.{}){}; pub fn main() !void { @@ -45,6 +47,13 @@ pub fn main() !void { var the_chunk = try shared.chunk.initChunk(allocator); defer shared.chunk.deinitChunk(&the_chunk, allocator); + try chunk.spawn(&the_chunk, shared.entity.Soldier, allocator, .{ + .pos = zm.f32x4(1, 0, 0, 0), + .vel = zm.f32x4(0, 0, 0, 0), + .hp = 10, + + }); + var old_time = std.time.nanoTimestamp(); while (true) { @@ -57,6 +66,7 @@ pub fn main() !void { t += frame_time; accumulator += frame_time * k; + send_accumulator += frame_time; var event = enet.ENetEvent{}; while (enet.enet_host_service(host, &event, 0) > 0) { @@ -70,7 +80,7 @@ pub fn main() !void { enet.ENET_EVENT_TYPE_DISCONNECT => { std.log.info("disconnect", .{}); }, - else => {} + else => {}, } } @@ -88,13 +98,6 @@ pub fn main() !void { // const w = &writer.interface; // try shared.protocol.sendHello(w, .{ .msg = "Hello from server!" }); - try chunk.spawn(&the_chunk, shared.entity.Elf, allocator, .{ - .pos = zm.f32x4(1, 0, 0, 0), - .vel = zm.f32x4(0, 0, 0, 0), - .hp = 10, - - }); - // try chunk.spawn(&the_chunk, shared.entity.Monster, allocator, .{ // .pos = zm.f32x4(1, 1, 0, 0), // .hp = 20, @@ -105,7 +108,20 @@ pub fn main() !void { // .vel = zm.f32x4(0.2, 0, 0, 0), // }, w); - shared.chunk.updateChunk(&the_chunk); + while (accumulator > dt * k) { + shared.chunk.updateChunk(&the_chunk); + + accumulator -= dt * k; + gt += dt * k; + } + + if (send_accumulator > 1) { + try chunk.broadcastChanges(&the_chunk, host); + + send_accumulator = 0; + } + + frame += 1; } } diff --git a/src/shared/c.zig b/src/shared/c.zig new file mode 100644 index 0000000..808aaf0 --- /dev/null +++ b/src/shared/c.zig @@ -0,0 +1,3 @@ +pub const enet = @cImport({ + @cInclude("enet/enet.h"); +}); diff --git a/src/shared/chunk.zig b/src/shared/chunk.zig index a42656a..c1764f2 100644 --- a/src/shared/chunk.zig +++ b/src/shared/chunk.zig @@ -1,30 +1,30 @@ -const std = @import("std"); +const std = @import("std"); const entity = @import("entity.zig"); -const misc = @import("misc.zig"); +const misc = @import("misc.zig"); -pub fn Storage(comptime T: type) type { - return struct { - items: std.ArrayList(T), +// pub fn Storage(comptime T: type) type { +// return struct { +// items: std.ArrayList(T), - pub fn init(allocator: std.mem.Allocator) !@This() { - return .{ - .items = try std.ArrayList(T).initCapacity(allocator, 32), - }; - } +// pub fn init(allocator: std.mem.Allocator) !@This() { +// return .{ +// .items = try std.ArrayList(T).initCapacity(allocator, 32), +// }; +// } - pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void { - self.items.deinit(allocator); - } +// pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void { +// self.items.deinit(allocator); +// } - pub fn update(self: *@This()) void { - for (self.items.items, 0..) |*item, i| { - _ = i; - if (@hasDecl(T, "update")) - item.update(); - } - } - }; -} +// pub fn update(self: *@This()) void { +// for (self.items.items, 0..) |*item, i| { +// _ = i; +// if (@hasDecl(T, "update")) +// item.update(); +// } +// } +// }; +// } pub const Chunk = _Chunk(); @@ -36,10 +36,10 @@ fn _Chunk() type { inline for (entity.EntityKinds, 0..) |T, i| { fields[i] = .{ .name = misc.short_type_name(T), - .type = Storage(T), + .type = std.ArrayList(T), .default_value_ptr = null, .is_comptime = false, - .alignment = @alignOf(Storage(T)), + .alignment = @alignOf(std.ArrayList(T)), }; } @@ -56,14 +56,9 @@ fn _Chunk() type { pub fn initChunk(allocator: std.mem.Allocator) !Chunk { var chunk: Chunk = undefined; - switch (@typeInfo(Chunk)) { - .@"struct" => |s| { - inline for (s.fields) |field| { - const StorageT = field.type; - @field(chunk, field.name) = try StorageT.init(allocator); - } - }, - else => unreachable, + inline for (@typeInfo(Chunk).@"struct".fields) |field| { + const ListT = field.type; + @field(chunk, field.name) = try ListT.initCapacity(allocator, 32); } return chunk; @@ -81,14 +76,13 @@ pub fn deinitChunk(chunk: *Chunk, allocator: std.mem.Allocator) void { } pub fn updateChunk(chunk: *Chunk) void { - const info = @typeInfo(Chunk); + inline for (@typeInfo(Chunk).@"struct".fields) |field| { + const list = &@field(chunk, field.name); - switch (info) { - .@"struct" => |s| { - inline for (s.fields) |field| { - @field(chunk, field.name).update(); - } - }, - else => unreachable, + for (list.items, 0..) |*item, i| { + _ = i; + if (@hasDecl(@TypeOf(item.*), "update")) + item.update(); + } } } diff --git a/src/shared/entity.zig b/src/shared/entity.zig index 7d1f77a..b3fc682 100644 --- a/src/shared/entity.zig +++ b/src/shared/entity.zig @@ -1,49 +1,61 @@ -const std = @import("std"); -const zm = @import("zmath"); +const std = @import("std"); +const zm = @import("zmath"); const protocol = @import("protocol.zig"); +const misc = @import("misc.zig"); pub const id = u64; pub const INVALID_ID: id = 0; pub const EntityKinds = .{ - Elf, - Cow, - Pig, + Soldier, + Alien, }; -pub const Elf = struct { +pub const Soldier = struct { id: id = INVALID_ID, pos: zm.Vec, vel: zm.Vec, hp: i32, - pub fn update(self: *Elf) void { + pub fn update(self: *Soldier) void { self.pos += self.pos + self.vel; } - - pub fn to_message(self: *Elf) protocol.Elf_v1 { - return protocol.Elf_v1.init(self); - } }; -pub const Cow = struct { +pub const Alien = struct { id: id = INVALID_ID, pos: zm.Vec, vel: zm.Vec, hp: i32, - pub fn update(self: *Cow) void { + pub fn update(self: *Alien) void { self.pos = self.pos + self.vel; } }; -pub const Pig = struct { - id: id = INVALID_ID, - pos: zm.Vec, - vel: zm.Vec, - hp: i32, +fn makeUnion() type { + const FieldCount = EntityKinds.len; - pub fn update(self: *Pig) void { - self.pos = self.pos + self.vel; + var fields: [FieldCount]std.builtin.Type.UnionField = undefined; + + inline for (EntityKinds, 0..) |T, i| { + fields[i] = .{ + .name = misc.short_type_name(T), + .type = *T, + .default_value_ptr = null, + .is_comptime = false, + .alignment = @alignOf(*T), + }; } -}; + + return @Type(.{ + .@"union" = .{ + .layout = .auto, + .fields = &fields, + .decls = &.{}, + .tag_type = u8, + }, + }); +} + +const EntityRef = makeUnion(); diff --git a/src/shared/protocol.zig b/src/shared/protocol.zig index 810da48..82891b2 100644 --- a/src/shared/protocol.zig +++ b/src/shared/protocol.zig @@ -12,18 +12,15 @@ pub const Message = union(enum) { }; pub const SpawnEntity = union(enum) { - elf_v1: Elf_v1, - cow_v1: Cow_v1, - pig_v1: Pig_v1, + soldier_v1: Soldier_v1, + alien_v1: Alien_v1, }; pub fn makeSpawnMessage(comptime T: type, e: T) Message { - if (T == entity.Elf) { - return .{ .spawn_entity = .{ .elf_v1 = Elf_v1.init(e) } }; - } else if (T == entity.Cow) { - return .{ .spawn_entity = .{ .cow_v1 = Cow_v1.init(e) } }; - } else if (T == entity.Pig) { - return .{ .spawn_entity = .{ .pig_v1 = Pig_v1.init(e) } }; + if (T == entity.Soldier) { + return .{ .spawn_entity = .{ .soldier_v1 = Soldier_v1.init(e) } }; + } else if (T == entity.Alien) { + return .{ .spawn_entity = .{ .alien_v1 = Alien_v1.init(e) } }; } } @@ -51,20 +48,26 @@ pub fn makeSpawnMessage(comptime T: type, e: T) Message { // }; // } -pub const Elf_v1 = struct { +pub const Soldier_v1 = struct { id: entity.id = entity.INVALID_ID, pos: zm.Vec, hp: i32, - pub fn init(elf: entity.Elf) Elf_v1 { + pub fn init(soldier: entity.Soldier) Soldier_v1 { return .{ - .id = elf.id, - .pos = elf.pos, - .hp = elf.hp, + .id = soldier.id, + .pos = soldier.pos, + .hp = soldier.hp, }; } - pub fn decode(r: *bufzilla.Reader) !Elf_v1 { + pub fn encode(self: Soldier_v1, w: *std.Io.Writer) !void { + try w.writeInt(u64, self.id, .little); + try writeVec4(w, self.pos); + try writeVec4(w, self.vel); + } + + pub fn decode(r: *bufzilla.Reader) !Soldier_v1 { _ = r; return .{ // .id = try r.readInt(u64, .little), @@ -74,54 +77,26 @@ pub const Elf_v1 = struct { } }; -pub const Cow_v1 = struct { +pub const Alien_v1 = struct { id: entity.id = entity.INVALID_ID, pos: zm.Vec, hp: i32, - pub fn init(cow: entity.Cow) Cow_v1 { + pub fn init(alien: entity.Alien) Alien_v1 { return .{ - .id = cow.id, - .pos = cow.pos, - .hp = cow.hp, + .id = alien.id, + .pos = alien.pos, + .hp = alien.hp, }; } - // pub fn encode(self: Cow_v1, w: *std.Io.Writer) !void { + // pub fn encode(self: Alien_v1, w: *std.Io.Writer) !void { // try w.writeInt(u64, self.id, .little); // try writeVec4(w, self.pos); // try writeVec4(w, self.vel); // } - pub fn decode(r: *std.Io.Reader) !Cow_v1 { - return .{ - .id = try r.readInt(u64, .little), - .pos = try readVec4(r), - .vel = try readVec4(r), - }; - } -}; - -pub const Pig_v1 = struct { - id: entity.id = entity.INVALID_ID, - pos: zm.Vec, - vel: zm.Vec, - - pub fn init(pig: entity.Pig) Pig_v1 { - return .{ - .id = pig.id, - .pos = pig.pos, - .vel = pig.vel, - }; - } - - // pub fn encode(self: Pig_v1, w: *std.Io.Writer) !void { - // try w.writeInt(u64, self.id, .little); - // try writeVec4(w, self.pos); - // try writeVec4(w, self.vel); - // } - - pub fn decode(r: *std.Io.Reader) !Pig_v1 { + pub fn decode(r: *std.Io.Reader) !Alien_v1 { return .{ .id = try r.readInt(u64, .little), .pos = try readVec4(r),