Compare commits
2 Commits
29c136d34c
...
35bbc5cbfd
| Author | SHA1 | Date | |
|---|---|---|---|
| 35bbc5cbfd | |||
| 5a79ae71c0 |
2
.vscode/tasks.json
vendored
2
.vscode/tasks.json
vendored
@ -17,7 +17,7 @@
|
|||||||
"focus": false,
|
"focus": false,
|
||||||
"panel": "shared",
|
"panel": "shared",
|
||||||
"showReuseMessage": true,
|
"showReuseMessage": true,
|
||||||
"clear": false
|
"clear": true,
|
||||||
},
|
},
|
||||||
"problemMatcher": [],
|
"problemMatcher": [],
|
||||||
"group": {
|
"group": {
|
||||||
|
|||||||
41
build.zig
41
build.zig
@ -32,7 +32,7 @@ pub fn build(b: *std.Build) void {
|
|||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{
|
.{
|
||||||
.name = "shared",
|
.name = "shared",
|
||||||
.module = shared
|
.module = shared,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -46,7 +46,10 @@ pub fn build(b: *std.Build) void {
|
|||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{ .name = "shared", .module = shared },
|
.{
|
||||||
|
.name = "shared",
|
||||||
|
.module = shared,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
.use_llvm = true,
|
.use_llvm = true,
|
||||||
@ -62,17 +65,20 @@ pub fn build(b: *std.Build) void {
|
|||||||
.enable_tracy = true,
|
.enable_tracy = true,
|
||||||
.enable_fibers = false,
|
.enable_fibers = false,
|
||||||
.on_demand = false,
|
.on_demand = false,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
client.root_module.addImport("tracy", tracy.module("tracy"));
|
client.root_module.addImport("tracy", tracy.module("tracy"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// freetype
|
// freetype
|
||||||
{
|
{
|
||||||
const freetype = b.dependency("freetype", .{
|
const freetype = b.dependency(
|
||||||
.target = target,
|
"freetype",
|
||||||
.optimize = optimize,
|
.{
|
||||||
});
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
}
|
||||||
|
);
|
||||||
client.root_module.addImport("freetype", freetype.module("freetype"));
|
client.root_module.addImport("freetype", freetype.module("freetype"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,29 +176,32 @@ pub fn build(b: *std.Build) void {
|
|||||||
|
|
||||||
b.getInstallStep().dependOn(&assets.step);
|
b.getInstallStep().dependOn(&assets.step);
|
||||||
|
|
||||||
const run_step = b.step("run", "Run the app");
|
const run_client_step = b.step("run-client", "Run the client");
|
||||||
|
const run_server_step = b.step("run-server", "Run the server");
|
||||||
|
|
||||||
const run_cmd_client = b.addRunArtifact(client);
|
const run_cmd_client = b.addRunArtifact(client);
|
||||||
const run_cmd_server = b.addRunArtifact(server);
|
const run_cmd_server = b.addRunArtifact(server);
|
||||||
run_step.dependOn(&run_cmd_client.step);
|
run_client_step.dependOn(&run_cmd_client.step);
|
||||||
run_step.dependOn(&run_cmd_server.step);
|
run_server_step.dependOn(&run_cmd_server.step);
|
||||||
|
|
||||||
run_cmd_client.step.dependOn(b.getInstallStep());
|
run_cmd_client.step.dependOn(b.getInstallStep());
|
||||||
run_cmd_server.step.dependOn(b.getInstallStep());
|
run_cmd_server.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
if (b.args) |args| {
|
if (b.args) |args| {
|
||||||
run_cmd_client.addArgs(args);
|
run_cmd_client.addArgs(args);
|
||||||
|
run_cmd_server.addArgs(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates an executable that will run `test` blocks from the provided module.
|
// Creates an executable that will run `test` blocks from the provided module.
|
||||||
// Here `mod` needs to define a target, which is why earlier we made sure to
|
// Here `mod` needs to define a target, which is why earlier we made sure to
|
||||||
// set the releative field.
|
// set the releative field.
|
||||||
// const mod_tests = b.addTest(.{
|
const shared_tests = b.addTest(.{
|
||||||
// .root_module = mod,
|
.root_module = shared,
|
||||||
// });
|
.use_llvm = true,
|
||||||
|
});
|
||||||
|
|
||||||
// A run step that will run the test executable.
|
// A run step that will run the test executable.
|
||||||
// const run_mod_tests = b.addRunArtifact(mod_tests);
|
const run_shared_tests = b.addRunArtifact(shared_tests);
|
||||||
|
|
||||||
// Creates an executable that will run `test` blocks from the executable's
|
// Creates an executable that will run `test` blocks from the executable's
|
||||||
// root module. Note that test executables only test one module at a time,
|
// root module. Note that test executables only test one module at a time,
|
||||||
@ -207,8 +216,8 @@ pub fn build(b: *std.Build) void {
|
|||||||
// A top level step for running all tests. dependOn can be called multiple
|
// A top level step for running all tests. dependOn can be called multiple
|
||||||
// times and since the two run steps do not depend on one another, this will
|
// times and since the two run steps do not depend on one another, this will
|
||||||
// make the two of them run in parallel.
|
// make the two of them run in parallel.
|
||||||
// const test_step = b.step("test", "Run tests");
|
const test_step = b.step("test", "Run tests");
|
||||||
// test_step.dependOn(&run_mod_tests.step);
|
test_step.dependOn(&run_shared_tests.step);
|
||||||
// test_step.dependOn(&run_exe_tests.step);
|
// test_step.dependOn(&run_exe_tests.step);
|
||||||
|
|
||||||
// Just like flags, top level steps are also listed in the `--help` menu.
|
// Just like flags, top level steps are also listed in the `--help` menu.
|
||||||
|
|||||||
73
src/client/chunk.zig
Normal file
73
src/client/chunk.zig
Normal file
@ -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;
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const shared = @import("shared");
|
||||||
|
|
||||||
const ConnectState = union(enum) {
|
const ConnectState = union(enum) {
|
||||||
disconnected,
|
disconnected,
|
||||||
|
|||||||
@ -14,8 +14,9 @@ const client = @import("client.zig");
|
|||||||
const entity = @import("entity.zig");
|
const entity = @import("entity.zig");
|
||||||
const misc = @import("misc.zig");
|
const misc = @import("misc.zig");
|
||||||
const font = @import("font.zig");
|
const font = @import("font.zig");
|
||||||
|
const chunk = @import("chunk.zig");
|
||||||
|
|
||||||
const dt : f32 = 1.0 / 200.0;
|
const dt : f32 = 1.0 / 240.0;
|
||||||
var t : f32 = 0;
|
var t : f32 = 0;
|
||||||
var gt : f32 = 0;
|
var gt : f32 = 0;
|
||||||
var accumulator : f32 = 0;
|
var accumulator : f32 = 0;
|
||||||
@ -29,6 +30,8 @@ var running: bool = true;
|
|||||||
|
|
||||||
var dbg_allocator = std.heap.DebugAllocator(.{}){};
|
var dbg_allocator = std.heap.DebugAllocator(.{}){};
|
||||||
|
|
||||||
|
var the_chunk : shared.chunk.Chunk = undefined;
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
const tracy_zone = tracy.ZoneNC(@src(), "main", 0x00_ff_00_00);
|
const tracy_zone = tracy.ZoneNC(@src(), "main", 0x00_ff_00_00);
|
||||||
defer tracy_zone.End();
|
defer tracy_zone.End();
|
||||||
@ -83,14 +86,14 @@ pub fn main() !void {
|
|||||||
const host = enet.enet_host_create(null, 32, 2, 0, 0);
|
const host = enet.enet_host_create(null, 32, 2, 0, 0);
|
||||||
defer enet.enet_host_destroy(host);
|
defer enet.enet_host_destroy(host);
|
||||||
|
|
||||||
var address = enet.ENetAddress{ .port = shared.protocol.SERVER_PORT };
|
var address = enet.ENetAddress{ .port = shared.protocol_v1.SERVER_PORT };
|
||||||
_ = enet.enet_address_set_host(&address, "localhost");
|
_ = enet.enet_address_set_host(&address, "localhost");
|
||||||
|
|
||||||
const peer = enet.enet_host_connect(host, &address, 2, 0);
|
const peer = enet.enet_host_connect(host, &address, 2, 0);
|
||||||
defer enet.enet_peer_reset(peer);
|
defer enet.enet_peer_reset(peer);
|
||||||
|
|
||||||
var the_chunk = try shared.chunk.initChunk(allocator);
|
the_chunk = try shared.chunk.Chunk.init(allocator);
|
||||||
defer shared.chunk.deinitChunk(&the_chunk, allocator);
|
defer the_chunk.deinit(allocator);
|
||||||
|
|
||||||
// const camera = rl.Camera{
|
// const camera = rl.Camera{
|
||||||
// .fovy = 45,
|
// .fovy = 45,
|
||||||
@ -135,13 +138,14 @@ pub fn main() !void {
|
|||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
enet.ENET_EVENT_TYPE_CONNECT => {
|
enet.ENET_EVENT_TYPE_CONNECT => {
|
||||||
std.log.info("A new client connected from {d}:{d}.", .{
|
std.log.info("A new client connected from {d}:{d}.", .{
|
||||||
event.peer.*.address.host,
|
event.peer.*.address.host,
|
||||||
event.peer.*.address.port});
|
event.peer.*.address.port
|
||||||
|
});
|
||||||
|
|
||||||
event.peer.*.data = @constCast(@ptrCast("Client information"));
|
event.peer.*.data = @constCast(@ptrCast("Client information"));
|
||||||
},
|
},
|
||||||
enet.ENET_EVENT_TYPE_RECEIVE => {
|
enet.ENET_EVENT_TYPE_RECEIVE => {
|
||||||
try on_packet(event.packet, event.peer, event.channelID);
|
try on_packet(allocator, event.packet, event.peer, event.channelID);
|
||||||
|
|
||||||
enet.enet_packet_destroy(event.packet);
|
enet.enet_packet_destroy(event.packet);
|
||||||
},
|
},
|
||||||
@ -163,6 +167,7 @@ pub fn main() !void {
|
|||||||
// rl.updateMusicStream(music);
|
// rl.updateMusicStream(music);
|
||||||
|
|
||||||
while (accumulator > dt * k) {
|
while (accumulator > dt * k) {
|
||||||
|
the_chunk.update(dt * k);
|
||||||
accumulator -= dt * k;
|
accumulator -= dt * k;
|
||||||
gt += dt * k;
|
gt += dt * k;
|
||||||
}
|
}
|
||||||
@ -320,7 +325,7 @@ pub fn main() !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_packet(packet: *enet.ENetPacket, peer: *enet.ENetPeer, channelID: i32) !void {
|
fn on_packet(allocator: std.mem.Allocator, packet: *enet.ENetPacket, peer: *enet.ENetPeer, channelID: i32) !void {
|
||||||
// std.log.info("A packet of length {d} containing {s} was received from {s} on channel {d}.", .{
|
// std.log.info("A packet of length {d} containing {s} was received from {s} on channel {d}.", .{
|
||||||
// packet.*.dataLength,
|
// packet.*.dataLength,
|
||||||
// packet.*.data,
|
// packet.*.data,
|
||||||
@ -332,26 +337,71 @@ fn on_packet(packet: *enet.ENetPacket, peer: *enet.ENetPeer, channelID: i32) !vo
|
|||||||
|
|
||||||
const bytes: []const u8 = packet.*.data[0 .. packet.*.dataLength];
|
const bytes: []const u8 = packet.*.data[0 .. packet.*.dataLength];
|
||||||
|
|
||||||
std.log.info("{d} bytes: {s}", .{bytes.len, bytes});
|
var reader = shared.bits.BitReader.init(bytes);
|
||||||
|
|
||||||
// var buffer2: [4096]u8 = undefined;
|
const msg : shared.protocol_v1.Message = try reader.deserialize(allocator, shared.protocol_v1.Message);
|
||||||
// var fixed2 = std.io.Writer.fixed(&buffer2);
|
|
||||||
|
|
||||||
// var inspector = bufzilla.Inspect(.{}).init(encoded, &fixed2, .{});
|
try on_message(allocator, msg);
|
||||||
// try inspector.inspect();
|
}
|
||||||
|
|
||||||
// std.log.info("{s}\n", .{fixed2.buffered()});
|
fn on_message(allocator: std.mem.Allocator, msg: shared.protocol_v1.Message) !void {
|
||||||
|
switch (msg) {
|
||||||
|
.spawn_entity => |se| { try on_spawn_entity(allocator, se); },
|
||||||
|
.update_entity => |ue| { on_update_entity(ue); },
|
||||||
|
.despawn_entity => |de| { on_despawn_entity(allocator, de); },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// var r = bufzilla.Reader(.{}).init(encoded);
|
fn on_spawn_entity(allocator: std.mem.Allocator, se: shared.protocol_v1.SpawnEntity) !void {
|
||||||
|
// _ = allocator; _ = se;
|
||||||
|
switch (se) {
|
||||||
|
.soldier => |s| {
|
||||||
|
const soldier = shared.entity.Soldier{
|
||||||
|
.id = s.id,
|
||||||
|
.hp = s.hp,
|
||||||
|
.pos = s.pos,
|
||||||
|
.vel = s.vel,
|
||||||
|
};
|
||||||
|
_ = try chunk.spawn(&the_chunk, allocator, shared.entity.Soldier, soldier);
|
||||||
|
},
|
||||||
|
.alien => |a| {
|
||||||
|
const alien = shared.entity.Alien{
|
||||||
|
.id = a.id,
|
||||||
|
.hp = a.hp,
|
||||||
|
.pos = a.pos,
|
||||||
|
};
|
||||||
|
_ = try chunk.spawn(&the_chunk, allocator, shared.entity.Alien, alien);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Read values sequentially
|
fn on_update_entity(ue: shared.protocol_v1.UpdateEntity) void {
|
||||||
|
switch (ue) {
|
||||||
|
.soldier => |s| {
|
||||||
|
if (chunk.findT(&the_chunk, shared.entity.Soldier, s.id)) |soldier| {
|
||||||
|
soldier.hp = s.hp;
|
||||||
|
soldier.pos = s.pos;
|
||||||
|
soldier.vel = s.vel;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.alien => |a| {
|
||||||
|
if (chunk.findT(&the_chunk, shared.entity.Alien, a.id)) |alien| {
|
||||||
|
alien.hp = a.hp;
|
||||||
|
alien.pos = a.pos;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// const e = try shared.protocol.Soldier_v1.decode(&r);
|
fn on_despawn_entity(allocator: std.mem.Allocator, de: shared.protocol_v1.DespawnEntity) void {
|
||||||
// _ = e;
|
switch (de) {
|
||||||
|
.soldier => |s| { _ = chunk.despawn(&the_chunk, allocator, s.id); },
|
||||||
|
.alien => |a| { _ = chunk.despawn(&the_chunk, allocator, a.id); },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn connect() !void {
|
fn connect() !void {
|
||||||
// const address = try std.net.Address.parseIp4("127.0.0.1", shared.protocol.SERVER_PORT);
|
// const address = try std.net.Address.parseIp4("127.0.0.1", shared.protocol_v1.SERVER_PORT);
|
||||||
|
|
||||||
// connection = try std.net.tcpConnectToAddress(address);
|
// connection = try std.net.tcpConnectToAddress(address);
|
||||||
|
|
||||||
|
|||||||
@ -5,66 +5,52 @@ const shared = @import("shared");
|
|||||||
const server = @import("server.zig");
|
const server = @import("server.zig");
|
||||||
const enet = @import("c.zig").enet;
|
const enet = @import("c.zig").enet;
|
||||||
|
|
||||||
pub fn spawn(allocator: std.mem.Allocator, host: *enet.ENetHost, chunk: *shared.chunk.Chunk, comptime T: type, value: T) !void {
|
pub fn spawn(self: *shared.chunk.Chunk, allocator: std.mem.Allocator, host: *enet.ENetHost, comptime T: type, value: T) !shared.entity.id {
|
||||||
std.debug.assert(value.id == shared.entity.INVALID_ID);
|
std.debug.assert(value.id == shared.entity.INVALID_ID);
|
||||||
|
|
||||||
const id = server.next_entity_id;
|
const id = server.next_entity_id;
|
||||||
server.next_entity_id += 1;
|
server.next_entity_id += 1;
|
||||||
|
|
||||||
var entity = value;
|
const ptr = try allocator.create(T);
|
||||||
entity.id = id;
|
errdefer allocator.destroy(ptr);
|
||||||
|
|
||||||
|
ptr.* = value;
|
||||||
|
ptr.id = id;
|
||||||
|
|
||||||
|
const ref = shared.entity.makeRef(T, ptr);
|
||||||
|
|
||||||
|
try self.entities.append(allocator, ref);
|
||||||
|
|
||||||
|
_ = host;
|
||||||
|
|
||||||
inline for (@typeInfo(shared.chunk.Chunk).@"struct".fields) |field| {
|
|
||||||
if (field.type == std.ArrayList(T)) {
|
|
||||||
try @field(chunk, field.name).append(allocator, entity);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// std.log.info("{}", .{shared.protocol.makeSpawnMessage(T, entity)});
|
// std.log.info("{}", .{shared.protocol.makeSpawnMessage(T, entity)});
|
||||||
|
|
||||||
// serialize entity
|
// serialize entity
|
||||||
var buffer: [128]u8 = undefined;
|
|
||||||
var fixed = std.io.Writer.fixed(&buffer);
|
|
||||||
|
|
||||||
// const msg = shared.protocol.makeSpawnMessage(T, entity);
|
// const msg = shared.protocol.makeSpawnMessage(T, entity);
|
||||||
|
|
||||||
// var writer = bufzilla.Writer.init(&fixed);
|
// const data = fixed.buffered();
|
||||||
// try writer.writeAny(msg);
|
// const packet = enet.enet_packet_create(data.ptr, data.len + 1, enet.ENET_PACKET_FLAG_RELIABLE);
|
||||||
|
|
||||||
// std.log.info("{s}", .{fixed.buffered()});
|
// enet.enet_host_broadcast(host, 0, packet);
|
||||||
|
|
||||||
// var buffer2: [4096]u8 = undefined;
|
return ptr.id;
|
||||||
// var fixed2 = std.io.Writer.fixed(&buffer2);
|
|
||||||
|
|
||||||
// var inspector = bufzilla.Inspect(.{}).init(fixed.buffered(), &fixed2, .{});
|
|
||||||
// try inspector.inspect();
|
|
||||||
|
|
||||||
// std.log.info("{}", .{msg});
|
|
||||||
|
|
||||||
// std.debug.print("{s}\n", .{fixed2.buffered()});
|
|
||||||
|
|
||||||
const data = fixed.buffered();
|
|
||||||
const packet = enet.enet_packet_create(data.ptr, data.len + 1, enet.ENET_PACKET_FLAG_RELIABLE);
|
|
||||||
|
|
||||||
enet.enet_host_broadcast(host, 0, packet);
|
|
||||||
|
|
||||||
// const encoded = fixed.buffered();
|
|
||||||
|
|
||||||
// const packet = try znet.Packet.init(encoded, 0, .reliable);
|
|
||||||
// var iterator = server.host.iterPeers();
|
|
||||||
|
|
||||||
// while (iterator.next()) |peer| {
|
|
||||||
// if (peer.state() == .connected) {
|
|
||||||
// try peer.send(packet);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn broadcastChanges(chunk: *shared.chunk.Chunk, host: *enet.ENetHost) !void {
|
pub fn broadcastChanges(chunk: *shared.chunk.Chunk, allocator: std.mem.Allocator, host: *enet.ENetHost) !void {
|
||||||
_ = chunk;
|
var aw = try std.ArrayList(u8).initCapacity(allocator, 128);
|
||||||
const data = "packet";
|
defer aw.deinit(allocator);
|
||||||
const packet = enet.enet_packet_create(data, data.len + 1, enet.ENET_PACKET_FLAG_RELIABLE);
|
|
||||||
|
var writer = shared.bits.BitWriter.init(&aw);
|
||||||
|
|
||||||
|
for (chunk.entities.items) |e| {
|
||||||
|
const msg = shared.protocol_v1.makeUpdateMessage(e);
|
||||||
|
try writer.serialize(allocator, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const encoded = writer.written();
|
||||||
|
|
||||||
|
const packet = enet.enet_packet_create(encoded.ptr, encoded.len, enet.ENET_PACKET_FLAG_RELIABLE);
|
||||||
|
|
||||||
enet.enet_host_broadcast(host, 0, packet);
|
enet.enet_host_broadcast(host, 0, packet);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,17 +8,18 @@ const shared = @import("shared");
|
|||||||
const chunk = @import("chunk.zig");
|
const chunk = @import("chunk.zig");
|
||||||
const server = @import("server.zig");
|
const server = @import("server.zig");
|
||||||
|
|
||||||
const dt : f32 = 1.0 / 200.0;
|
const dt : f32 = 1.0 / 240.0;
|
||||||
var t : f32 = 0;
|
var t : f32 = 0;
|
||||||
var gt : f32 = 0;
|
var gt : f32 = 0;
|
||||||
var accumulator : f32 = 0;
|
|
||||||
var k : f32 = 1.0;
|
var k : f32 = 1.0;
|
||||||
var frame : i32 = 0;
|
var frame : i32 = 0;
|
||||||
|
|
||||||
var send_accumulator : f32 = 0;
|
const frame_dt_ns: i128 = std.time.ns_per_s / 10;
|
||||||
|
|
||||||
var dbg_allocator = std.heap.DebugAllocator(.{}){};
|
var dbg_allocator = std.heap.DebugAllocator(.{}){};
|
||||||
|
|
||||||
|
const log = std.log.scoped(.server);
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
|
|
||||||
const allocator = dbg_allocator.allocator();
|
const allocator = dbg_allocator.allocator();
|
||||||
@ -33,46 +34,52 @@ pub fn main() !void {
|
|||||||
_ = try stdout.write("Hello, Server!\n");
|
_ = try stdout.write("Hello, Server!\n");
|
||||||
|
|
||||||
if (enet.enet_initialize() != 0) {
|
if (enet.enet_initialize() != 0) {
|
||||||
std.log.info("Failed to load ENet", .{});
|
log.info("Failed to load ENet", .{});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
defer enet.enet_deinitialize();
|
defer enet.enet_deinitialize();
|
||||||
|
|
||||||
const address = enet.ENetAddress{ .host = enet.ENET_HOST_ANY, .port = shared.protocol.SERVER_PORT };
|
const address = enet.ENetAddress{ .host = enet.ENET_HOST_ANY, .port = shared.protocol_v1.SERVER_PORT };
|
||||||
const host = enet.enet_host_create(&address, 32, 2, 0, 0);
|
const host = enet.enet_host_create(&address, 32, 2, 0, 0);
|
||||||
if (host == null) {
|
if (host == null) {
|
||||||
@panic("host is null");
|
@panic("host is null");
|
||||||
}
|
}
|
||||||
defer enet.enet_host_destroy(host);
|
defer enet.enet_host_destroy(host);
|
||||||
|
|
||||||
var the_chunk = try shared.chunk.initChunk(allocator);
|
var the_chunk = try shared.chunk.Chunk.init(allocator);
|
||||||
defer shared.chunk.deinitChunk(&the_chunk, allocator);
|
defer the_chunk.deinit(allocator);
|
||||||
|
|
||||||
try chunk.spawn(
|
_ = try chunk.spawn(
|
||||||
|
&the_chunk,
|
||||||
allocator,
|
allocator,
|
||||||
host,
|
host,
|
||||||
&the_chunk,
|
|
||||||
shared.entity.Soldier,
|
shared.entity.Soldier,
|
||||||
.{
|
.{
|
||||||
.hp = 10,
|
.hp = 10,
|
||||||
.pos = zm.f32x4(5.0, 0, 0, 0),
|
.pos = zm.f32x4(5.0, 0, 0, 0),
|
||||||
.vel = zm.f32x4(0, 0, 0, 0),
|
.vel = zm.f32x4(0, 0, 0, 0),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
var old_time = std.time.nanoTimestamp();
|
var last_time: i128 = std.time.nanoTimestamp();
|
||||||
|
var next_frame_deadline: i128 = last_time + frame_dt_ns;
|
||||||
|
|
||||||
|
var accumulator: f32 = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const new_time = std.time.nanoTimestamp();
|
const now = std.time.nanoTimestamp();
|
||||||
var frame_time : f32 = @as(f32, @floatFromInt(new_time - old_time)) / 1_000_000_000.0;
|
var delta_ns = now - last_time;
|
||||||
old_time = new_time;
|
last_time = now;
|
||||||
|
|
||||||
if (frame_time > 0.25)
|
if (delta_ns > std.time.ns_per_s / 4)
|
||||||
frame_time = 0.25;
|
delta_ns = std.time.ns_per_s / 4;
|
||||||
|
|
||||||
t += frame_time;
|
const delta_s: f32 = @floatCast(@as(f64, @floatFromInt(delta_ns)) / 1e9);
|
||||||
accumulator += frame_time * k;
|
|
||||||
send_accumulator += frame_time;
|
t += delta_s;
|
||||||
|
accumulator += delta_s * k;
|
||||||
|
|
||||||
|
log.info("Starting a the frame {} at time {}", .{frame, t});
|
||||||
|
|
||||||
var event = enet.ENetEvent{};
|
var event = enet.ENetEvent{};
|
||||||
while (enet.enet_host_service(host, &event, 0) > 0) {
|
while (enet.enet_host_service(host, &event, 0) > 0) {
|
||||||
@ -81,10 +88,10 @@ pub fn main() !void {
|
|||||||
try on_connect(allocator, host, event.peer, &the_chunk);
|
try on_connect(allocator, host, event.peer, &the_chunk);
|
||||||
},
|
},
|
||||||
enet.ENET_EVENT_TYPE_RECEIVE => {
|
enet.ENET_EVENT_TYPE_RECEIVE => {
|
||||||
std.log.info("receive", .{});
|
log.info("receive", .{});
|
||||||
},
|
},
|
||||||
enet.ENET_EVENT_TYPE_DISCONNECT => {
|
enet.ENET_EVENT_TYPE_DISCONNECT => {
|
||||||
std.log.info("disconnect", .{});
|
log.info("disconnect", .{});
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
@ -97,7 +104,7 @@ pub fn main() !void {
|
|||||||
// var reader = connection.stream.reader(&recv_buffer);
|
// var reader = connection.stream.reader(&recv_buffer);
|
||||||
|
|
||||||
// const line = try reader.interface().takeDelimiterExclusive('\n');
|
// const line = try reader.interface().takeDelimiterExclusive('\n');
|
||||||
// std.log.info("Received: {s}", .{line});
|
// log.info("Received: {s}", .{line});
|
||||||
|
|
||||||
// var send_buffer: [4096]u8 = undefined;
|
// var send_buffer: [4096]u8 = undefined;
|
||||||
// var writer = connection.stream.writer(&send_buffer);
|
// var writer = connection.stream.writer(&send_buffer);
|
||||||
@ -115,18 +122,29 @@ pub fn main() !void {
|
|||||||
// }, w);
|
// }, w);
|
||||||
|
|
||||||
while (accumulator > dt * k) {
|
while (accumulator > dt * k) {
|
||||||
shared.chunk.updateChunk(&the_chunk);
|
the_chunk.update(dt * k);
|
||||||
|
|
||||||
accumulator -= dt * k;
|
accumulator -= dt * k;
|
||||||
gt += dt * k;
|
gt += dt * k;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (send_accumulator > 1) {
|
try chunk.broadcastChanges(&the_chunk, allocator, host);
|
||||||
// try chunk.broadcastChanges(&the_chunk, host);
|
|
||||||
|
|
||||||
send_accumulator = 0;
|
const spin_ns: i128 = 100_000; // 0.1 ms
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const _t = std.time.nanoTimestamp();
|
||||||
|
const remaining = next_frame_deadline - _t;
|
||||||
|
|
||||||
|
if (remaining <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (remaining > spin_ns)
|
||||||
|
std.Thread.sleep(@intCast(remaining - spin_ns));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next_frame_deadline += frame_dt_ns;
|
||||||
|
|
||||||
frame += 1;
|
frame += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,74 +155,18 @@ fn on_connect(allocator: std.mem.Allocator, host: *enet.ENetHost, peer: *enet.EN
|
|||||||
|
|
||||||
_ = peer;
|
_ = peer;
|
||||||
|
|
||||||
// var w = bufzilla.Writer.init(&aw.writer);
|
|
||||||
|
|
||||||
var writer = shared.bits.BitWriter.init(&aw);
|
var writer = shared.bits.BitWriter.init(&aw);
|
||||||
|
|
||||||
// Write 3 bits (101)
|
for (the_chunk.entities.items) |e| {
|
||||||
try writer.write(allocator, @as(u3, 0x5));
|
const msg = shared.protocol_v1.makeSpawnMessage(e);
|
||||||
// Write 1 bit (true = 1)
|
try writer.serialize(allocator, msg);
|
||||||
try writer.write(allocator, true);
|
|
||||||
// Write 4 bits (0000)
|
|
||||||
try writer.write(allocator, @as(u3, 0x1));
|
|
||||||
|
|
||||||
try writer.write(allocator, @as(u4, 0xE));
|
|
||||||
|
|
||||||
try writer.write(allocator, @as(u32, 0xFFFFFFFA));
|
|
||||||
|
|
||||||
var reader = shared.bits.BitReader.init(writer.written());
|
|
||||||
|
|
||||||
const _1 : u3 = reader.read(u3);
|
|
||||||
const _2 : bool = reader.read(bool);
|
|
||||||
const _3 : u3 = reader.read(u3);
|
|
||||||
const _4 : u4 = reader.read(u4);
|
|
||||||
const _5 : u32 = reader.read(u32);
|
|
||||||
|
|
||||||
std.log.info("_1: {}", .{_1});
|
|
||||||
std.log.info("_1: {}", .{_2});
|
|
||||||
std.log.info("_1: {}", .{_3});
|
|
||||||
std.log.info("_1: {}", .{_4});
|
|
||||||
std.log.info("_1: {}", .{_5});
|
|
||||||
|
|
||||||
const fields = @typeInfo(shared.chunk.Chunk).@"struct".fields;
|
|
||||||
|
|
||||||
inline for (fields) |field| {
|
|
||||||
const list = &@field(the_chunk, field.name);
|
|
||||||
|
|
||||||
// const itemsType = @FieldType(field.type, "items");
|
|
||||||
// const T = std.meta.Child(itemsType);
|
|
||||||
|
|
||||||
for (list.items) |entity| {
|
|
||||||
|
|
||||||
// const msg = shared.protocol.makeSpawnMessage(T, entity);
|
|
||||||
|
|
||||||
// w.write(entity);
|
|
||||||
|
|
||||||
std.log.info("{}", .{entity});
|
|
||||||
|
|
||||||
// try writer.writeAny(msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// const encoded = aw.written();
|
const encoded = writer.written();
|
||||||
|
|
||||||
// std.log.info("{d} bytes: {s}", .{encoded.len, encoded});
|
const packet = enet.enet_packet_create(encoded.ptr, encoded.len, enet.ENET_PACKET_FLAG_RELIABLE);
|
||||||
|
|
||||||
// var buffer2: [4096]u8 = undefined;
|
enet.enet_host_broadcast(host, 0, packet);
|
||||||
// var fixed2 = std.io.Writer.fixed(&buffer2);
|
|
||||||
|
|
||||||
// var inspector = bufzilla.Inspect(.{}).init(encoded, &fixed2, .{});
|
|
||||||
// try inspector.inspect();
|
|
||||||
|
|
||||||
// std.log.info("{s}\n", .{fixed2.buffered()});
|
|
||||||
|
|
||||||
// const packet = enet.enet_packet_create(encoded.ptr, encoded.len, enet.ENET_PACKET_FLAG_RELIABLE);
|
|
||||||
|
|
||||||
// enet.enet_host_broadcast(host, 0, packet);
|
|
||||||
_ = host;
|
|
||||||
// if (enet.enet_peer_send(peer, 0, packet) != 0) {
|
|
||||||
// std.log.err("Could not send packet to peer.", .{});
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//fn handle_connection(connection: std.net.Server.Connection) !void {}
|
//fn handle_connection(connection: std.net.Server.Connection) !void {}
|
||||||
|
|||||||
@ -1,5 +1,38 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
// pub fn serialize(writer: *BitWriter, allocator: std.mem.Allocator, comptime T: type, value: T) !void {
|
||||||
|
// const info = @typeInfo(T);
|
||||||
|
|
||||||
|
// switch (info) {
|
||||||
|
// .int, .bool => {
|
||||||
|
// try writer.write(allocator, T, value);
|
||||||
|
// },
|
||||||
|
|
||||||
|
// .@"struct" => |s| {
|
||||||
|
// if (!s.is_packed)
|
||||||
|
// @compileError("serialize only supports packed structs (got " ++ @typeName(T) ++ ")");
|
||||||
|
|
||||||
|
// inline for (s.fields) |field| {
|
||||||
|
// const field_value = @field(value, field.name);
|
||||||
|
// try serialize(writer, allocator, field_value);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
// .@"union" => |u| {
|
||||||
|
// if (u.layout != .@"packed")
|
||||||
|
// @compileError("serialize only supports packed structs (got " ++ @typeName(T) ++ ")");
|
||||||
|
|
||||||
|
// inline for (u.fields) |field| {
|
||||||
|
// const field_value = @field(value, field.name);
|
||||||
|
// try serialize(writer, allocator, field_value);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
// else => @compileError("Unsupported type in serialize: " ++ @typeName(T)),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
pub const BitWriter = struct {
|
pub const BitWriter = struct {
|
||||||
// We store a pointer to the ArrayList so we can grow it
|
// We store a pointer to the ArrayList so we can grow it
|
||||||
bytes: *std.ArrayList(u8),
|
bytes: *std.ArrayList(u8),
|
||||||
@ -9,15 +42,54 @@ pub const BitWriter = struct {
|
|||||||
return .{ .bytes = bytes };
|
return .{ .bytes = bytes };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(self: *BitWriter, allocator: std.mem.Allocator, value: anytype) !void {
|
pub fn serialize(self: *BitWriter, allocator: std.mem.Allocator, value: anytype) !void {
|
||||||
const T = @TypeOf(value);
|
const T = @TypeOf(value);
|
||||||
const info = @typeInfo(T);
|
const info = @typeInfo(T);
|
||||||
|
|
||||||
const bit_width = switch (info) {
|
switch (info) {
|
||||||
.int => |int| int.bits,
|
.@"struct" => |s| {
|
||||||
.bool => 1,
|
inline for (s.fields) |f|
|
||||||
else => @compileError("Unsupported type: " ++ @typeName(T)),
|
try self.serialize(allocator, @field(value, f.name));
|
||||||
};
|
},
|
||||||
|
.@"union" => |u| {
|
||||||
|
const E = u.tag_type orelse @compileError(std.fmt.comptimePrint("Union {s} has to tag type.", .{@typeName(T)}));
|
||||||
|
try self.serialize(allocator, @as(E, value));
|
||||||
|
switch (value) {
|
||||||
|
inline else => |f| try self.serialize(allocator, f),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.@"enum" => try self.serialize(allocator, @intFromEnum(value)),
|
||||||
|
.pointer => |p| switch (p.size) {
|
||||||
|
.one => try self.serialize(allocator, value.*),
|
||||||
|
.slice => {
|
||||||
|
try self.serialize(allocator, value.len);
|
||||||
|
for (value) |e|
|
||||||
|
try self.serialize(allocator, e);
|
||||||
|
},
|
||||||
|
.many, .c => @compileError(std.fmt.comptimePrint("Unsupported type: {}", .{T})),
|
||||||
|
},
|
||||||
|
.int, .bool, .float, => try self.write(allocator, value),
|
||||||
|
.void => {},
|
||||||
|
.array => |a| if (@sizeOf(a.child) == 1) {
|
||||||
|
try self.write(allocator, @ptrCast(&value));
|
||||||
|
} else {
|
||||||
|
for (value) |e|
|
||||||
|
try self.serialize(allocator, e);
|
||||||
|
},
|
||||||
|
.optional => if (value) |_t| {
|
||||||
|
try self.serialize(allocator, true);
|
||||||
|
try self.serialize(allocator, _t);
|
||||||
|
} else {
|
||||||
|
try self.serialize(allocator, false);
|
||||||
|
},
|
||||||
|
.vector => |v| try self.serialize(allocator, @as([v.len]v.child, value)),
|
||||||
|
else => @compileError(std.fmt.comptimePrint("Unsupported type: {}", .{T})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(self: *BitWriter, allocator: std.mem.Allocator, value: anytype) !void {
|
||||||
|
const T = @TypeOf(value);
|
||||||
|
const bit_width = @bitSizeOf(T);
|
||||||
|
|
||||||
const UnsignedT = std.meta.Int(.unsigned, bit_width);
|
const UnsignedT = std.meta.Int(.unsigned, bit_width);
|
||||||
const bits_to_write = @as(UnsignedT, @bitCast(value));
|
const bits_to_write = @as(UnsignedT, @bitCast(value));
|
||||||
@ -60,14 +132,64 @@ pub const BitReader = struct {
|
|||||||
return .{ .bytes = bytes };
|
return .{ .bytes = bytes };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(self: *BitReader, comptime T: type) T {
|
pub fn deserialize(self: *BitReader, allocator: std.mem.Allocator, T: type) !T {
|
||||||
const info = @typeInfo(T);
|
return switch (@typeInfo(T)) {
|
||||||
|
.@"struct" => |s| b: {
|
||||||
const bit_width = switch (info) {
|
var data: T = undefined;
|
||||||
.int => |int| int.bits,
|
inline for (s.fields) |f|
|
||||||
.bool => 1,
|
@field(data, f.name) = try self.deserialize(allocator, f.type);
|
||||||
else => @compileError("Unsupported type: " ++ @typeName(T)),
|
break :b data;
|
||||||
|
},
|
||||||
|
.@"union" => |u| switch (try self.deserialize(allocator, u.tag_type.?)) {
|
||||||
|
inline else => |t| b: {
|
||||||
|
var data: T = @unionInit(T, @tagName(t), undefined);
|
||||||
|
const field = &@field(data, @tagName(t));
|
||||||
|
field.* = try self.deserialize(allocator, @TypeOf(field.*));
|
||||||
|
break :b data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.@"enum" => |e| @enumFromInt(try self.deserialize(allocator, e.tag_type)),
|
||||||
|
.pointer => |p| switch (p.size) {
|
||||||
|
.one => b: {
|
||||||
|
const ptr = try allocator.create(p.child);
|
||||||
|
errdefer allocator.destroy(ptr);
|
||||||
|
ptr.* = try self.deserialize(allocator, p.child);
|
||||||
|
break :b ptr;
|
||||||
|
},
|
||||||
|
.slice => b: {
|
||||||
|
const slice = try allocator.alloc(p.child, try self.deserialize(allocator, usize));
|
||||||
|
errdefer allocator.free(slice);
|
||||||
|
for (slice) |*e|
|
||||||
|
e.* = try self.deserialize(allocator, p.child);
|
||||||
|
break :b slice;
|
||||||
|
},
|
||||||
|
.many, .c => @compileError(std.fmt.comptimePrint("Unsupported type: {}", .{T})),
|
||||||
|
},
|
||||||
|
.int, .bool, .float => self.read(T),
|
||||||
|
.void => {},
|
||||||
|
.array => |a| b: {
|
||||||
|
var array: T = undefined;
|
||||||
|
if (@sizeOf(a.child) == 1) {
|
||||||
|
try self.read(&array);
|
||||||
|
} else {
|
||||||
|
for (&array) |*e|
|
||||||
|
e.* = try self.deserialize(allocator, a.child);
|
||||||
|
}
|
||||||
|
break :b array;
|
||||||
|
},
|
||||||
|
.optional => |o| if (try self.deserialize(allocator, bool))
|
||||||
|
try self.deserialize(o.child, allocator)
|
||||||
|
else
|
||||||
|
null,
|
||||||
|
.vector => |v| try self.deserialize(allocator, [v.len]v.child),
|
||||||
|
else => @compileError(std.fmt.comptimePrint("Unsupported type: {}", .{T})),
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(self: *BitReader, comptime T: type) T {
|
||||||
|
// const info = @typeInfo(T);
|
||||||
|
|
||||||
|
const bit_width = @bitSizeOf(T);
|
||||||
|
|
||||||
const UnsignedT = std.meta.Int(.unsigned, bit_width);
|
const UnsignedT = std.meta.Int(.unsigned, bit_width);
|
||||||
|
|
||||||
@ -98,3 +220,67 @@ pub const BitReader = struct {
|
|||||||
return @bitCast(result);
|
return @bitCast(result);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
test "Bit Stream" {
|
||||||
|
std.debug.print("Bit Stream\n", .{});
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
|
||||||
|
var aw = try std.ArrayList(u8).initCapacity(allocator, 128);
|
||||||
|
defer aw.deinit(allocator);
|
||||||
|
|
||||||
|
var writer = BitWriter.init(&aw);
|
||||||
|
|
||||||
|
const _a : u3 = 0x5;
|
||||||
|
const _b : bool = true;
|
||||||
|
const _c : u3 = 0x1;
|
||||||
|
const _d : u4 = 0xE;
|
||||||
|
const _e : u32 = 0xFFFFFFFA;
|
||||||
|
const _f : i32 = -3;
|
||||||
|
const _g : f32 = 6.667;
|
||||||
|
|
||||||
|
const ts = struct {
|
||||||
|
a: i32,
|
||||||
|
n: []const u8,
|
||||||
|
|
||||||
|
pub fn format(self: @This(), w: *std.io.Writer) !void {
|
||||||
|
|
||||||
|
try w.print(".{{ .a = {}, .n = \"{s}\" }}", .{ self.a, self.n });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const _h : ts = .{
|
||||||
|
.a = 44,
|
||||||
|
.n = "hello",
|
||||||
|
};
|
||||||
|
|
||||||
|
try writer.serialize(allocator, _a);
|
||||||
|
try writer.serialize(allocator, _b);
|
||||||
|
try writer.serialize(allocator, _c);
|
||||||
|
try writer.serialize(allocator, _d);
|
||||||
|
try writer.serialize(allocator, _e);
|
||||||
|
try writer.serialize(allocator, _f);
|
||||||
|
try writer.serialize(allocator, _g);
|
||||||
|
try writer.serialize(allocator, _h);
|
||||||
|
|
||||||
|
var reader = BitReader.init(writer.written());
|
||||||
|
|
||||||
|
const _1 : u3 = try reader.deserialize(allocator, u3);
|
||||||
|
const _2 : bool = try reader.deserialize(allocator, bool);
|
||||||
|
const _3 : u3 = try reader.deserialize(allocator, u3);
|
||||||
|
const _4 : u4 = try reader.deserialize(allocator, u4);
|
||||||
|
const _5 : u32 = try reader.deserialize(allocator, u32);
|
||||||
|
const _6 : i32 = try reader.deserialize(allocator, i32);
|
||||||
|
const _7 = try reader.deserialize(allocator, f32);
|
||||||
|
const _8 = try reader.deserialize(allocator, ts);
|
||||||
|
defer allocator.free(_8.n);
|
||||||
|
|
||||||
|
try std.testing.expectEqual(_a, _1);
|
||||||
|
try std.testing.expectEqual(_b, _2);
|
||||||
|
try std.testing.expectEqual(_c, _3);
|
||||||
|
try std.testing.expectEqual(_d, _4);
|
||||||
|
try std.testing.expectEqual(_e, _5);
|
||||||
|
try std.testing.expectEqual(_f, _6);
|
||||||
|
try std.testing.expectEqual(_g, _7);
|
||||||
|
|
||||||
|
try std.testing.expectEqualDeep(_h, _8);
|
||||||
|
}
|
||||||
|
|||||||
@ -26,63 +26,96 @@ const misc = @import("misc.zig");
|
|||||||
// };
|
// };
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub const Chunk = _Chunk();
|
// pub const Chunk = _Chunk();
|
||||||
|
|
||||||
fn _Chunk() type {
|
// fn _Chunk() type {
|
||||||
const FieldCount = entity.EntityKinds.len;
|
// const FieldCount = entity.EntityKinds.len;
|
||||||
|
|
||||||
var fields: [FieldCount]std.builtin.Type.StructField = undefined;
|
// var fields: [FieldCount]std.builtin.Type.StructField = undefined;
|
||||||
|
|
||||||
inline for (entity.EntityKinds, 0..) |T, i| {
|
// inline for (entity.EntityKinds, 0..) |T, i| {
|
||||||
fields[i] = .{
|
// fields[i] = .{
|
||||||
.name = misc.short_type_name(T),
|
// .name = misc.short_type_name(T),
|
||||||
.type = std.ArrayList(T),
|
// .type = std.ArrayList(T),
|
||||||
.default_value_ptr = null,
|
// .default_value_ptr = null,
|
||||||
.is_comptime = false,
|
// .is_comptime = false,
|
||||||
.alignment = @alignOf(std.ArrayList(T)),
|
// .alignment = @alignOf(std.ArrayList(T)),
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return @Type(.{
|
||||||
|
// .@"struct" = .{
|
||||||
|
// .layout = .auto,
|
||||||
|
// .fields = &fields,
|
||||||
|
// .decls = &.{},
|
||||||
|
// .is_tuple = false,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn initChunk(allocator: std.mem.Allocator) !Chunk {
|
||||||
|
// var chunk: Chunk = undefined;
|
||||||
|
|
||||||
|
// inline for (@typeInfo(Chunk).@"struct".fields) |field| {
|
||||||
|
// const ListT = field.type;
|
||||||
|
// @field(chunk, field.name) = try ListT.initCapacity(allocator, 32);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return chunk;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn deinitChunk(chunk: *Chunk, allocator: std.mem.Allocator) void {
|
||||||
|
// switch (@typeInfo(Chunk)) {
|
||||||
|
// .@"struct" => |s| {
|
||||||
|
// inline for (s.fields) |field| {
|
||||||
|
// @field(chunk, field.name).deinit(allocator);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// else => unreachable,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn updateChunk(chunk: *Chunk) void {
|
||||||
|
// inline for (@typeInfo(Chunk).@"struct".fields) |field| {
|
||||||
|
// const list = &@field(chunk, field.name);
|
||||||
|
|
||||||
|
// for (list.items, 0..) |*item, i| {
|
||||||
|
// _ = i;
|
||||||
|
// if (@hasDecl(@TypeOf(item.*), "update"))
|
||||||
|
// item.update();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub const Chunk = struct {
|
||||||
|
entities : std.ArrayList(entity.Ref),
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) !Chunk {
|
||||||
|
return .{
|
||||||
|
.entities = try std.ArrayList(entity.Ref).initCapacity(allocator, 128),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return @Type(.{
|
pub fn deinit(self: *@This(), allocator: std.mem.Allocator) void {
|
||||||
.@"struct" = .{
|
for (self.entities.items) |ref| {
|
||||||
.layout = .auto,
|
switch (ref) {
|
||||||
.fields = &fields,
|
inline else => |ptr| allocator.destroy(ptr),
|
||||||
.decls = &.{},
|
|
||||||
.is_tuple = false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn initChunk(allocator: std.mem.Allocator) !Chunk {
|
|
||||||
var chunk: Chunk = undefined;
|
|
||||||
|
|
||||||
inline for (@typeInfo(Chunk).@"struct".fields) |field| {
|
|
||||||
const ListT = field.type;
|
|
||||||
@field(chunk, field.name) = try ListT.initCapacity(allocator, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
return chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinitChunk(chunk: *Chunk, allocator: std.mem.Allocator) void {
|
|
||||||
switch (@typeInfo(Chunk)) {
|
|
||||||
.@"struct" => |s| {
|
|
||||||
inline for (s.fields) |field| {
|
|
||||||
@field(chunk, field.name).deinit(allocator);
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
else => unreachable,
|
|
||||||
|
self.entities.deinit(allocator);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn updateChunk(chunk: *Chunk) void {
|
pub fn update(self: *@This(), dt: f32) void {
|
||||||
inline for (@typeInfo(Chunk).@"struct".fields) |field| {
|
for (self.entities.items) |e| {
|
||||||
const list = &@field(chunk, field.name);
|
switch (e) {
|
||||||
|
.Soldier => |s| {
|
||||||
for (list.items, 0..) |*item, i| {
|
s.update(dt);
|
||||||
_ = i;
|
},
|
||||||
if (@hasDecl(@TypeOf(item.*), "update"))
|
.Alien => |a| {
|
||||||
item.update();
|
a.update(dt);
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const zm = @import("zmath");
|
const zm = @import("zmath");
|
||||||
const protocol = @import("protocol.zig");
|
const misc = @import("misc.zig");
|
||||||
const misc = @import("misc.zig");
|
|
||||||
|
|
||||||
pub const id = u64;
|
pub const id = u64;
|
||||||
pub const INVALID_ID: id = 0;
|
pub const INVALID_ID: id = 0;
|
||||||
@ -11,39 +10,59 @@ pub const EntityKinds = .{
|
|||||||
Alien,
|
Alien,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Entity = struct {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
pub const Soldier = struct {
|
pub const Soldier = struct {
|
||||||
id: id = INVALID_ID,
|
id: id = INVALID_ID,
|
||||||
hp: i32,
|
hp: i32 = 0,
|
||||||
pos: zm.Vec,
|
pos: zm.Vec = .{0, 0, 0, 0},
|
||||||
vel: zm.Vec,
|
vel: zm.Vec = .{0, 0, 0, 0},
|
||||||
|
|
||||||
pub fn update(self: *Soldier) void {
|
pub fn update(self: *@This(), dt: f32) void {
|
||||||
self.pos += self.vel;
|
self.pos = self.pos + self.vel * zm.splat(zm.Vec, dt);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Alien = struct {
|
pub const Alien = struct {
|
||||||
id: id = INVALID_ID,
|
id: id = INVALID_ID,
|
||||||
pos: zm.Vec,
|
hp: i32 = 0,
|
||||||
vel: zm.Vec,
|
pos: zm.Vec = .{0, 0, 0, 0},
|
||||||
hp: i32,
|
vel: zm.Vec = .{0, 0, 0, 0},
|
||||||
|
|
||||||
pub fn update(self: *Alien) void {
|
pub fn update(self: *@This(), dt: f32) void {
|
||||||
self.pos = self.pos + self.vel;
|
self.pos = self.pos + self.vel * zm.splat(zm.Vec, dt);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn makeUnion() type {
|
fn _Ref() type {
|
||||||
const FieldCount = EntityKinds.len;
|
const FieldCount = EntityKinds.len;
|
||||||
|
|
||||||
|
var tag_fields: [FieldCount]std.builtin.Type.EnumField = undefined;
|
||||||
|
|
||||||
|
inline for (EntityKinds, 0..) |T, i| {
|
||||||
|
tag_fields[i] = .{
|
||||||
|
.name = misc.short_type_name(T),
|
||||||
|
.value = i,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Tag = @Type(.{
|
||||||
|
.@"enum" = .{
|
||||||
|
.tag_type = u8,
|
||||||
|
.fields = &tag_fields,
|
||||||
|
.decls = &.{},
|
||||||
|
.is_exhaustive = true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
var fields: [FieldCount]std.builtin.Type.UnionField = undefined;
|
var fields: [FieldCount]std.builtin.Type.UnionField = undefined;
|
||||||
|
|
||||||
inline for (EntityKinds, 0..) |T, i| {
|
inline for (EntityKinds, 0..) |T, i| {
|
||||||
fields[i] = .{
|
fields[i] = .{
|
||||||
.name = misc.short_type_name(T),
|
.name = misc.short_type_name(T),
|
||||||
.type = *T,
|
.type = *T,
|
||||||
.default_value_ptr = null,
|
|
||||||
.is_comptime = false,
|
|
||||||
.alignment = @alignOf(*T),
|
.alignment = @alignOf(*T),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -53,9 +72,32 @@ fn makeUnion() type {
|
|||||||
.layout = .auto,
|
.layout = .auto,
|
||||||
.fields = &fields,
|
.fields = &fields,
|
||||||
.decls = &.{},
|
.decls = &.{},
|
||||||
.tag_type = u8,
|
.tag_type = Tag,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const EntityRef = makeUnion();
|
pub const Ref = _Ref();
|
||||||
|
|
||||||
|
pub fn setPos(self: Ref, pos: zm.Vec) void {
|
||||||
|
switch (self) {
|
||||||
|
.Soldier => |s| { s.pos = pos; },
|
||||||
|
.Alien => |a| { a.pos = pos; },
|
||||||
|
else => unreachable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn makeRef(comptime T: type, ptr: *T) Ref {
|
||||||
|
inline for (EntityKinds) |U| {
|
||||||
|
if (T == U) {
|
||||||
|
return @unionInit(
|
||||||
|
Ref,
|
||||||
|
misc.short_type_name(U),
|
||||||
|
ptr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@compileError("Type not in EntityKinds: " ++ @typeName(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,129 +0,0 @@
|
|||||||
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;
|
|
||||||
|
|
||||||
pub const Message = union(enum) {
|
|
||||||
spawn_entity: SpawnEntity,
|
|
||||||
// later: despawn_entity, update_entity, snapshot, etc.
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const SpawnEntity = union(enum) {
|
|
||||||
soldier_v1: Soldier_v1,
|
|
||||||
alien_v1: Alien_v1,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn makeSpawnMessage(comptime T: type, e: T) Message {
|
|
||||||
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) } };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub fn write_message(writer: *std.Io.Writer, msg_type: MessageType, payload: []const u8) !void {
|
|
||||||
// try writer.writeByte(@intFromEnum(msg_type));
|
|
||||||
// try writer.writeInt(u32, @intCast(payload.len), .little);
|
|
||||||
// try writer.writeAll(payload);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn read_message(reader: *std.Io.Reader, allocator: std.mem.Allocator) !struct {
|
|
||||||
// msg_type: MessageType,
|
|
||||||
// payload: []u8,
|
|
||||||
// } {
|
|
||||||
// const msg_type = try reader.readByte();
|
|
||||||
// const size = try reader.readInt(u32, .little);
|
|
||||||
|
|
||||||
// const payload = try allocator.alloc(u8, size);
|
|
||||||
// errdefer allocator.free(payload);
|
|
||||||
|
|
||||||
// try reader.readNoEof(payload);
|
|
||||||
|
|
||||||
// return .{
|
|
||||||
// .msg_type = @enumFromInt(msg_type),
|
|
||||||
// .payload = payload,
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub const Soldier_v1 = struct {
|
|
||||||
id: entity.id = entity.INVALID_ID,
|
|
||||||
hp: i32,
|
|
||||||
pos: zm.Vec,
|
|
||||||
vel: zm.Vec,
|
|
||||||
|
|
||||||
pub fn init(soldier: entity.Soldier) Soldier_v1 {
|
|
||||||
return .{
|
|
||||||
.id = soldier.id,
|
|
||||||
.hp = soldier.hp,
|
|
||||||
.pos = soldier.pos,
|
|
||||||
.vel = soldier.vel,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode() !Soldier_v1 {
|
|
||||||
const soldier_v1 : Soldier_v1 = .{
|
|
||||||
.id = 0,
|
|
||||||
.hp = 0,
|
|
||||||
.pos = .{0, 0, 0, 0},
|
|
||||||
.vel = .{0, 0, 0, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// switch (kv.value) {
|
|
||||||
// .i32 => |val| {
|
|
||||||
// if (std.mem.eql(u8, kv.key.bytes, "hp")) soldier_v1.hp = val;
|
|
||||||
// },
|
|
||||||
// else => {}
|
|
||||||
// }
|
|
||||||
|
|
||||||
return soldier_v1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Alien_v1 = struct {
|
|
||||||
id: entity.id = entity.INVALID_ID,
|
|
||||||
pos: zm.Vec,
|
|
||||||
hp: i32,
|
|
||||||
|
|
||||||
pub fn init(alien: entity.Alien) Alien_v1 {
|
|
||||||
return .{
|
|
||||||
.id = alien.id,
|
|
||||||
.pos = alien.pos,
|
|
||||||
.hp = alien.hp,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) !Alien_v1 {
|
|
||||||
return .{
|
|
||||||
.id = try r.readInt(u64, .little),
|
|
||||||
.pos = try readVec4(r),
|
|
||||||
.vel = try readVec4(r),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fn writeVec4(w: *std.Io.Writer, v: zm.Vec) !void {
|
|
||||||
const a = zm.vecToArr4(v);
|
|
||||||
inline for (a) |f| {
|
|
||||||
try w.writeFloat(f32, f, .little);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn readVec4(r: *std.Io.Reader) !zm.Vec4 {
|
|
||||||
var a: [4]f32 = undefined;
|
|
||||||
inline for (&a) |*f| {
|
|
||||||
f.* = try r.readFloat(f32, .little);
|
|
||||||
}
|
|
||||||
return zm.loadArr4(a);
|
|
||||||
}
|
|
||||||
158
src/shared/protocol_v1.zig
Normal file
158
src/shared/protocol_v1.zig
Normal file
@ -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);
|
||||||
|
}
|
||||||
@ -1,5 +1,10 @@
|
|||||||
pub const entity = @import("entity.zig");
|
pub const entity = @import("entity.zig");
|
||||||
pub const chunk = @import("chunk.zig");
|
pub const chunk = @import("chunk.zig");
|
||||||
pub const misc = @import("misc.zig");
|
pub const misc = @import("misc.zig");
|
||||||
pub const protocol = @import("protocol.zig");
|
pub const protocol_v1 = @import("protocol_v1.zig");
|
||||||
pub const bits = @import("bits.zig");
|
pub const bits = @import("bits.zig");
|
||||||
|
|
||||||
|
test {
|
||||||
|
const std = @import("std");
|
||||||
|
std.testing.refAllDecls(@This());
|
||||||
|
}
|
||||||
|
|||||||
1
vendor/freetype/build.zig.zon
vendored
1
vendor/freetype/build.zig.zon
vendored
@ -1,5 +1,6 @@
|
|||||||
.{
|
.{
|
||||||
.name = .freetype,
|
.name = .freetype,
|
||||||
|
.fingerprint = 0xac2059b69e282536,
|
||||||
.version = "0.1.0",
|
.version = "0.1.0",
|
||||||
.minimum_zig_version = "0.15.2",
|
.minimum_zig_version = "0.15.2",
|
||||||
.paths = .{
|
.paths = .{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user