mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-08-03 11:17:05 -04:00
Introduce a BinaryReader/Writer to make working with binary protocols easier especially with regards to error handling.
fixes #762 fixes #264
This commit is contained in:
parent
72a68d6b6d
commit
f3b508bf47
@ -6,7 +6,8 @@ const Block = main.blocks.Block;
|
||||
const Item = main.items.Item;
|
||||
const ItemStack = main.items.ItemStack;
|
||||
const Tool = main.items.Tool;
|
||||
const NeverFailingAllocator = main.utils.NeverFailingAllocator;
|
||||
const utils = main.utils;
|
||||
const NeverFailingAllocator = utils.NeverFailingAllocator;
|
||||
const vec = main.vec;
|
||||
const Vec3d = vec.Vec3d;
|
||||
const Vec3f = vec.Vec3f;
|
||||
@ -35,7 +36,10 @@ pub const Sync = struct { // MARK: Sync
|
||||
pub fn deinit() void {
|
||||
mutex.lock();
|
||||
while(commands.dequeue()) |cmd| {
|
||||
cmd.finalize(main.globalAllocator, .client, &.{});
|
||||
var reader = utils.BinaryReader.init(&.{}, main.network.networkEndian);
|
||||
cmd.finalize(main.globalAllocator, .client, &reader) catch |err| {
|
||||
std.log.err("Got error while cleaning remaining inventory commands: {s}", .{@errorName(err)});
|
||||
};
|
||||
}
|
||||
mutex.unlock();
|
||||
commands.deinit();
|
||||
@ -98,10 +102,10 @@ pub const Sync = struct { // MARK: Sync
|
||||
return serverToClientMap.get(serverId);
|
||||
}
|
||||
|
||||
pub fn receiveConfirmation(data: []const u8) void {
|
||||
pub fn receiveConfirmation(reader: *utils.BinaryReader) !void {
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
commands.dequeue().?.finalize(main.globalAllocator, .client, data);
|
||||
try commands.dequeue().?.finalize(main.globalAllocator, .client, reader);
|
||||
}
|
||||
|
||||
pub fn receiveFailure() void {
|
||||
@ -116,7 +120,10 @@ pub const Sync = struct { // MARK: Sync
|
||||
}
|
||||
if(tempData.popOrNull()) |_cmd| {
|
||||
var cmd = _cmd;
|
||||
cmd.finalize(main.globalAllocator, .client, &.{});
|
||||
var reader = utils.BinaryReader.init(&.{}, main.network.networkEndian);
|
||||
cmd.finalize(main.globalAllocator, .client, &reader) catch |err| {
|
||||
std.log.err("Got error while cleaning rejected inventory command: {s}", .{@errorName(err)});
|
||||
};
|
||||
}
|
||||
while(tempData.popOrNull()) |_cmd| {
|
||||
var cmd = _cmd;
|
||||
@ -125,7 +132,7 @@ pub const Sync = struct { // MARK: Sync
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receiveSyncOperation(data: []const u8) !void {
|
||||
pub fn receiveSyncOperation(reader: *utils.BinaryReader) !void {
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
var tempData = main.List(Command).init(main.stackAllocator);
|
||||
@ -135,7 +142,7 @@ pub const Sync = struct { // MARK: Sync
|
||||
cmd.undo();
|
||||
tempData.append(cmd);
|
||||
}
|
||||
try Command.SyncOperation.executeFromData(data);
|
||||
try Command.SyncOperation.executeFromData(reader);
|
||||
while(tempData.popOrNull()) |_cmd| {
|
||||
var cmd = _cmd;
|
||||
cmd.do(main.globalAllocator, .client, null, main.game.Player.gamemode.raw) catch unreachable;
|
||||
@ -284,16 +291,19 @@ pub const Sync = struct { // MARK: Sync
|
||||
}
|
||||
}
|
||||
}
|
||||
command.finalize(main.globalAllocator, .server, &.{});
|
||||
var reader = utils.BinaryReader.init(&.{}, main.network.networkEndian);
|
||||
command.finalize(main.globalAllocator, .server, &reader) catch |err| {
|
||||
std.log.err("Got error while finalizing command on the server side: {s}", .{@errorName(err)});
|
||||
};
|
||||
}
|
||||
|
||||
pub fn receiveCommand(source: *main.server.User, data: []const u8) !void {
|
||||
pub fn receiveCommand(source: *main.server.User, reader: *utils.BinaryReader) !void {
|
||||
mutex.lock();
|
||||
defer mutex.unlock();
|
||||
const typ: Command.PayloadType = @enumFromInt(data[0]);
|
||||
const typ = try reader.readEnum(Command.PayloadType);
|
||||
@setEvalBranchQuota(100000);
|
||||
const payload: Command.Payload = switch(typ) {
|
||||
inline else => |_typ| @unionInit(Command.Payload, @tagName(_typ), try std.meta.FieldType(Command.Payload, _typ).deserialize(data[1..], .server, source)),
|
||||
inline else => |_typ| @unionInit(Command.Payload, @tagName(_typ), try std.meta.FieldType(Command.Payload, _typ).deserialize(reader, .server, source)),
|
||||
};
|
||||
executeCommand(payload, source);
|
||||
}
|
||||
@ -486,16 +496,16 @@ pub const Command = struct { // MARK: Command
|
||||
return &self.inv._items[self.slot];
|
||||
}
|
||||
|
||||
fn write(self: InventoryAndSlot, data: *[8]u8) void {
|
||||
std.mem.writeInt(u32, data[0..4], self.inv.id, .big);
|
||||
std.mem.writeInt(u32, data[4..8], self.slot, .big);
|
||||
fn write(self: InventoryAndSlot, writer: *utils.BinaryWriter) void {
|
||||
writer.writeInt(u32, self.inv.id);
|
||||
writer.writeInt(u32, self.slot);
|
||||
}
|
||||
|
||||
fn read(data: *const [8]u8, side: Side, user: ?*main.server.User) !InventoryAndSlot {
|
||||
const id = std.mem.readInt(u32, data[0..4], .big);
|
||||
fn read(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !InventoryAndSlot {
|
||||
const id = try reader.readInt(u32);
|
||||
return .{
|
||||
.inv = Sync.getInventory(id, side, user) orelse return error.Invalid,
|
||||
.slot = std.mem.readInt(u32, data[4..8], .big),
|
||||
.slot = try reader.readInt(u32),
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -565,10 +575,8 @@ pub const Command = struct { // MARK: Command
|
||||
target: ?*main.server.User,
|
||||
},
|
||||
|
||||
pub fn executeFromData(data: []const u8) !void {
|
||||
std.debug.assert(data.len >= 1);
|
||||
|
||||
switch(try deserialize(data)) {
|
||||
pub fn executeFromData(reader: *utils.BinaryReader) !void {
|
||||
switch(try deserialize(reader)) {
|
||||
.create => |create| {
|
||||
if(create.item) |item| {
|
||||
create.inv.ref().item = item;
|
||||
@ -632,28 +640,19 @@ pub const Command = struct { // MARK: Command
|
||||
};
|
||||
}
|
||||
|
||||
fn deserialize(fullData: []const u8) !SyncOperation {
|
||||
if(fullData.len == 0) {
|
||||
return error.Invalid;
|
||||
}
|
||||
|
||||
const typ: SyncOperationType = @enumFromInt(fullData[0]);
|
||||
|
||||
const data = fullData[1..];
|
||||
fn deserialize(reader: *utils.BinaryReader) !SyncOperation {
|
||||
const typ = try reader.readEnum(SyncOperationType);
|
||||
|
||||
switch(typ) {
|
||||
.create => {
|
||||
if(data.len < 10) {
|
||||
return error.Invalid;
|
||||
}
|
||||
var out: SyncOperation = .{.create = .{
|
||||
.inv = try InventoryAndSlot.read(data[0..8], .client, null),
|
||||
.amount = std.mem.readInt(u16, data[8..10], .big),
|
||||
.inv = try InventoryAndSlot.read(reader, .client, null),
|
||||
.amount = try reader.readInt(u16),
|
||||
.item = null,
|
||||
}};
|
||||
|
||||
if(data.len > 10) {
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, data[10..]);
|
||||
if(reader.remaining.len != 0) {
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, reader.remaining);
|
||||
defer zon.deinit(main.stackAllocator);
|
||||
out.create.item = try Item.init(zon);
|
||||
}
|
||||
@ -661,42 +660,28 @@ pub const Command = struct { // MARK: Command
|
||||
return out;
|
||||
},
|
||||
.delete => {
|
||||
if(data.len != 10) {
|
||||
return error.Invalid;
|
||||
}
|
||||
const out: SyncOperation = .{.delete = .{
|
||||
.inv = try InventoryAndSlot.read(data[0..8], .client, null),
|
||||
.amount = std.mem.readInt(u16, data[8..10], .big),
|
||||
.inv = try InventoryAndSlot.read(reader, .client, null),
|
||||
.amount = try reader.readInt(u16),
|
||||
}};
|
||||
|
||||
return out;
|
||||
},
|
||||
.useDurability => {
|
||||
if(data.len != 12) {
|
||||
return error.Invalid;
|
||||
}
|
||||
const out: SyncOperation = .{.useDurability = .{
|
||||
.inv = try InventoryAndSlot.read(data[0..8], .client, null),
|
||||
.durability = std.mem.readInt(u32, data[8..12], .big),
|
||||
.inv = try InventoryAndSlot.read(reader, .client, null),
|
||||
.durability = try reader.readInt(u32),
|
||||
}};
|
||||
|
||||
return out;
|
||||
},
|
||||
.health => {
|
||||
if(data.len != 4) {
|
||||
return error.Invalid;
|
||||
}
|
||||
|
||||
return .{.health = .{
|
||||
.target = null,
|
||||
.health = @bitCast(std.mem.readInt(u32, data[0..4], .big)),
|
||||
.health = @bitCast(try reader.readInt(u32)),
|
||||
}};
|
||||
},
|
||||
.kill => {
|
||||
if(data.len != 0) {
|
||||
return error.Invalid;
|
||||
}
|
||||
|
||||
return .{.kill = .{
|
||||
.target = null,
|
||||
}};
|
||||
@ -705,35 +690,35 @@ pub const Command = struct { // MARK: Command
|
||||
}
|
||||
|
||||
pub fn serialize(self: SyncOperation, allocator: NeverFailingAllocator) []const u8 {
|
||||
var data = main.List(u8).initCapacity(allocator, 13);
|
||||
data.append(@intFromEnum(self));
|
||||
var writer = utils.BinaryWriter.initCapacity(allocator, main.network.networkEndian, 13);
|
||||
writer.writeEnum(SyncOperationType, self);
|
||||
switch(self) {
|
||||
.create => |create| {
|
||||
create.inv.write(data.addMany(8)[0..8]);
|
||||
std.mem.writeInt(u16, data.addMany(2)[0..2], create.amount, .big);
|
||||
create.inv.write(&writer);
|
||||
writer.writeInt(u16, create.amount);
|
||||
if(create.item) |item| {
|
||||
const zon = ZonElement.initObject(main.stackAllocator);
|
||||
defer zon.deinit(main.stackAllocator);
|
||||
item.insertIntoZon(main.stackAllocator, zon);
|
||||
const string = zon.toStringEfficient(main.stackAllocator, &.{});
|
||||
defer main.stackAllocator.free(string);
|
||||
data.appendSlice(string);
|
||||
writer.writeSlice(string);
|
||||
}
|
||||
},
|
||||
.delete => |delete| {
|
||||
delete.inv.write(data.addMany(8)[0..8]);
|
||||
std.mem.writeInt(u16, data.addMany(2)[0..2], delete.amount, .big);
|
||||
delete.inv.write(&writer);
|
||||
writer.writeInt(u16, delete.amount);
|
||||
},
|
||||
.useDurability => |durability| {
|
||||
durability.inv.write(data.addMany(8)[0..8]);
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], durability.durability, .big);
|
||||
durability.inv.write(&writer);
|
||||
writer.writeInt(u32, durability.durability);
|
||||
},
|
||||
.health => |health| {
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], @bitCast(health.health), .big);
|
||||
writer.writeInt(u32, @bitCast(health.health));
|
||||
},
|
||||
.kill => {},
|
||||
}
|
||||
return data.toOwnedSlice();
|
||||
return writer.data.toOwnedSlice();
|
||||
}
|
||||
};
|
||||
|
||||
@ -742,13 +727,14 @@ pub const Command = struct { // MARK: Command
|
||||
syncOperations: main.ListUnmanaged(SyncOperation) = .{},
|
||||
|
||||
fn serializePayload(self: *Command, allocator: NeverFailingAllocator) []const u8 {
|
||||
var list = main.List(u8).init(allocator);
|
||||
var writer = utils.BinaryWriter.init(allocator, main.network.networkEndian);
|
||||
defer writer.deinit();
|
||||
switch(self.payload) {
|
||||
inline else => |payload| {
|
||||
payload.serialize(&list);
|
||||
payload.serialize(&writer);
|
||||
},
|
||||
}
|
||||
return list.toOwnedSlice();
|
||||
return writer.data.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn do(self: *Command, allocator: NeverFailingAllocator, side: Side, user: ?*main.server.User, gamemode: main.game.Gamemode) error{serverFailure}!void { // MARK: do()
|
||||
@ -811,7 +797,7 @@ pub const Command = struct { // MARK: Command
|
||||
}
|
||||
}
|
||||
|
||||
fn finalize(self: Command, allocator: NeverFailingAllocator, side: Side, data: []const u8) void {
|
||||
fn finalize(self: Command, allocator: NeverFailingAllocator, side: Side, reader: *utils.BinaryReader) !void {
|
||||
for(self.baseOperations.items) |step| {
|
||||
switch(step) {
|
||||
.move, .swap, .create, .addHealth => {},
|
||||
@ -835,7 +821,7 @@ pub const Command = struct { // MARK: Command
|
||||
switch(self.payload) {
|
||||
inline else => |payload| {
|
||||
if(@hasDecl(@TypeOf(payload), "finalize")) {
|
||||
payload.finalize(side, data);
|
||||
try payload.finalize(side, reader);
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -1047,37 +1033,35 @@ pub const Command = struct { // MARK: Command
|
||||
|
||||
fn run(_: Open, _: NeverFailingAllocator, _: *Command, _: Side, _: ?*main.server.User, _: Gamemode) error{serverFailure}!void {}
|
||||
|
||||
fn finalize(self: Open, side: Side, data: []const u8) void {
|
||||
fn finalize(self: Open, side: Side, reader: *utils.BinaryReader) !void {
|
||||
if(side != .client) return;
|
||||
if(data.len >= 4) {
|
||||
const serverId = std.mem.readInt(u32, data[0..4], .big);
|
||||
if(reader.remaining.len != 0) {
|
||||
const serverId = try reader.readInt(u32);
|
||||
Sync.ClientSide.mapServerId(serverId, self.inv);
|
||||
}
|
||||
}
|
||||
|
||||
fn confirmationData(self: Open, allocator: NeverFailingAllocator) []const u8 {
|
||||
const data = allocator.alloc(u8, 4);
|
||||
std.mem.writeInt(u32, data[0..4], self.inv.id, .big);
|
||||
return data;
|
||||
var writer = utils.BinaryWriter.initCapacity(allocator, main.network.networkEndian, 4);
|
||||
writer.writeInt(u32, self.inv.id);
|
||||
return writer.data.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn serialize(self: Open, data: *main.List(u8)) void {
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], self.inv.id, .big);
|
||||
std.mem.writeInt(usize, data.addMany(8)[0..8], self.inv._items.len, .big);
|
||||
data.append(@intFromEnum(std.meta.activeTag(self.inv.type)));
|
||||
data.append(@intFromEnum(self.source));
|
||||
fn serialize(self: Open, writer: *utils.BinaryWriter) void {
|
||||
writer.writeInt(u32, self.inv.id);
|
||||
writer.writeInt(usize, self.inv._items.len);
|
||||
writer.writeEnum(TypeEnum, self.inv.type);
|
||||
writer.writeEnum(SourceType, self.source);
|
||||
switch(self.source) {
|
||||
.playerInventory, .hand => |val| {
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], val, .big);
|
||||
writer.writeInt(u32, val);
|
||||
},
|
||||
.recipe => |val| {
|
||||
std.mem.writeInt(u16, data.addMany(2)[0..2], val.resultAmount, .big);
|
||||
data.appendSlice(val.resultItem.id);
|
||||
data.append(0);
|
||||
writer.writeInt(u16, val.resultAmount);
|
||||
writer.writeWithDelimiter(val.resultItem.id, 0);
|
||||
for(0..val.sourceItems.len) |i| {
|
||||
std.mem.writeInt(u16, data.addMany(2)[0..2], val.sourceAmounts[i], .big);
|
||||
data.appendSlice(val.sourceItems[i].id);
|
||||
data.append(0);
|
||||
writer.writeInt(u16, val.sourceAmounts[i]);
|
||||
writer.writeWithDelimiter(val.sourceItems[i].id, 0);
|
||||
}
|
||||
},
|
||||
.sharedTestingInventory, .other => {},
|
||||
@ -1086,35 +1070,29 @@ pub const Command = struct { // MARK: Command
|
||||
switch(self.inv.type) {
|
||||
.normal, .creative, .crafting => {},
|
||||
.workbench => {
|
||||
data.appendSlice(self.inv.type.workbench.id);
|
||||
writer.writeSlice(self.inv.type.workbench.id);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !Open {
|
||||
if(data.len < 14) return error.Invalid;
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !Open {
|
||||
if(side != .server or user == null) return error.Invalid;
|
||||
const id = std.mem.readInt(u32, data[0..4], .big);
|
||||
const len = std.mem.readInt(usize, data[4..12], .big);
|
||||
const typeEnum: TypeEnum = @enumFromInt(data[12]);
|
||||
const sourceType: SourceType = @enumFromInt(data[13]);
|
||||
const id = try reader.readInt(u32);
|
||||
const len = try reader.readInt(u64);
|
||||
const typeEnum = try reader.readEnum(TypeEnum);
|
||||
const sourceType = try reader.readEnum(SourceType);
|
||||
const source: Source = switch(sourceType) {
|
||||
.playerInventory => .{.playerInventory = std.mem.readInt(u32, data[14..18], .big)},
|
||||
.playerInventory => .{.playerInventory = try reader.readInt(u32)},
|
||||
.sharedTestingInventory => .{.sharedTestingInventory = {}},
|
||||
.hand => .{.hand = std.mem.readInt(u32, data[14..18], .big)},
|
||||
.hand => .{.hand = try reader.readInt(u32)},
|
||||
.recipe => .{
|
||||
.recipe = blk: {
|
||||
var itemList = main.List(struct {amount: u16, item: *const main.items.BaseItem}).initCapacity(main.stackAllocator, len);
|
||||
defer itemList.deinit();
|
||||
var index: usize = 14;
|
||||
while(index + 2 < data.len) {
|
||||
const resultAmount = std.mem.readInt(u16, data[index..][0..2], .big);
|
||||
index += 2;
|
||||
const resultItem = if(std.mem.indexOfScalarPos(u8, data, index, 0)) |endIndex| blk2: {
|
||||
const itemId = data[index..endIndex];
|
||||
index = endIndex + 1;
|
||||
break :blk2 main.items.getByID(itemId) orelse return error.Invalid;
|
||||
} else return error.Invalid;
|
||||
while(reader.remaining.len >= 2) {
|
||||
const resultAmount = try reader.readInt(u16);
|
||||
const itemId = try reader.readUntilDelimiter(0);
|
||||
const resultItem = main.items.getByID(itemId) orelse return error.Invalid;
|
||||
itemList.append(.{.amount = resultAmount, .item = resultItem});
|
||||
}
|
||||
if(itemList.items.len != len) return error.Invalid;
|
||||
@ -1133,15 +1111,9 @@ pub const Command = struct { // MARK: Command
|
||||
.other => .{.other = {}},
|
||||
.alreadyFreed => unreachable,
|
||||
};
|
||||
const remainingLen: usize = switch(sourceType) {
|
||||
.playerInventory, .hand => 18,
|
||||
.sharedTestingInventory, .other => 14,
|
||||
.recipe => data.len,
|
||||
.alreadyFreed => unreachable,
|
||||
};
|
||||
const typ: Type = switch(typeEnum) {
|
||||
inline .normal, .creative, .crafting => |tag| tag,
|
||||
.workbench => .{.workbench = main.items.getToolTypeByID(data[remainingLen..]) orelse return error.Invalid},
|
||||
.workbench => .{.workbench = main.items.getToolTypeByID(reader.remaining) orelse return error.Invalid},
|
||||
};
|
||||
Sync.ServerSide.createInventory(user.?, id, len, typ, source);
|
||||
return .{
|
||||
@ -1157,23 +1129,22 @@ pub const Command = struct { // MARK: Command
|
||||
|
||||
fn run(_: Close, _: NeverFailingAllocator, _: *Command, _: Side, _: ?*main.server.User, _: Gamemode) error{serverFailure}!void {}
|
||||
|
||||
fn finalize(self: Close, side: Side, data: []const u8) void {
|
||||
fn finalize(self: Close, side: Side, reader: *utils.BinaryReader) !void {
|
||||
if(side != .client) return;
|
||||
self.inv._deinit(self.allocator, .client);
|
||||
if(data.len >= 4) {
|
||||
const serverId = std.mem.readInt(u32, data[0..4], .big);
|
||||
if(reader.remaining.len != 0) {
|
||||
const serverId = try reader.readInt(u32);
|
||||
Sync.ClientSide.unmapServerId(serverId, self.inv.id);
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(self: Close, data: *main.List(u8)) void {
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], self.inv.id, .big);
|
||||
fn serialize(self: Close, writer: *utils.BinaryWriter) void {
|
||||
writer.writeInt(u32, self.inv.id);
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !Close {
|
||||
if(data.len != 4) return error.Invalid;
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !Close {
|
||||
if(side != .server or user == null) return error.Invalid;
|
||||
const id = std.mem.readInt(u32, data[0..4], .big);
|
||||
const id = try reader.readInt(u32);
|
||||
try Sync.ServerSide.closeInventory(user.?, id);
|
||||
return undefined;
|
||||
}
|
||||
@ -1228,16 +1199,15 @@ pub const Command = struct { // MARK: Command
|
||||
}}, side);
|
||||
}
|
||||
|
||||
fn serialize(self: DepositOrSwap, data: *main.List(u8)) void {
|
||||
self.dest.write(data.addMany(8)[0..8]);
|
||||
self.source.write(data.addMany(8)[0..8]);
|
||||
fn serialize(self: DepositOrSwap, writer: *utils.BinaryWriter) void {
|
||||
self.dest.write(writer);
|
||||
self.source.write(writer);
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !DepositOrSwap {
|
||||
if(data.len != 16) return error.Invalid;
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !DepositOrSwap {
|
||||
return .{
|
||||
.dest = try InventoryAndSlot.read(data[0..8], side, user),
|
||||
.source = try InventoryAndSlot.read(data[8..16], side, user),
|
||||
.dest = try InventoryAndSlot.read(reader, side, user),
|
||||
.source = try InventoryAndSlot.read(reader, side, user),
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -1273,18 +1243,17 @@ pub const Command = struct { // MARK: Command
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(self: Deposit, data: *main.List(u8)) void {
|
||||
self.dest.write(data.addMany(8)[0..8]);
|
||||
self.source.write(data.addMany(8)[0..8]);
|
||||
std.mem.writeInt(u16, data.addMany(2)[0..2], self.amount, .big);
|
||||
fn serialize(self: Deposit, writer: *utils.BinaryWriter) void {
|
||||
self.dest.write(writer);
|
||||
self.source.write(writer);
|
||||
writer.writeInt(u16, self.amount);
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !Deposit {
|
||||
if(data.len != 18) return error.Invalid;
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !Deposit {
|
||||
return .{
|
||||
.dest = try InventoryAndSlot.read(data[0..8], side, user),
|
||||
.source = try InventoryAndSlot.read(data[8..16], side, user),
|
||||
.amount = std.mem.readInt(u16, data[16..18], .big),
|
||||
.dest = try InventoryAndSlot.read(reader, side, user),
|
||||
.source = try InventoryAndSlot.read(reader, side, user),
|
||||
.amount = try reader.readInt(u16),
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -1339,16 +1308,15 @@ pub const Command = struct { // MARK: Command
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(self: TakeHalf, data: *main.List(u8)) void {
|
||||
self.dest.write(data.addMany(8)[0..8]);
|
||||
self.source.write(data.addMany(8)[0..8]);
|
||||
fn serialize(self: TakeHalf, writer: *utils.BinaryWriter) void {
|
||||
self.dest.write(writer);
|
||||
self.source.write(writer);
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !TakeHalf {
|
||||
if(data.len != 16) return error.Invalid;
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !TakeHalf {
|
||||
return .{
|
||||
.dest = try InventoryAndSlot.read(data[0..8], side, user),
|
||||
.source = try InventoryAndSlot.read(data[8..16], side, user),
|
||||
.dest = try InventoryAndSlot.read(reader, side, user),
|
||||
.source = try InventoryAndSlot.read(reader, side, user),
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -1393,18 +1361,17 @@ pub const Command = struct { // MARK: Command
|
||||
}}, side);
|
||||
}
|
||||
|
||||
fn serialize(self: Drop, data: *main.List(u8)) void {
|
||||
self.source.write(data.addMany(8)[0..8]);
|
||||
fn serialize(self: Drop, writer: *utils.BinaryWriter) void {
|
||||
self.source.write(writer);
|
||||
if(self.desiredAmount != 0xffff) {
|
||||
std.mem.writeInt(u16, data.addMany(2)[0..2], self.desiredAmount, .big);
|
||||
writer.writeInt(u16, self.desiredAmount);
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !Drop {
|
||||
if(data.len != 8 and data.len != 10) return error.Invalid;
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !Drop {
|
||||
return .{
|
||||
.source = try InventoryAndSlot.read(data[0..8], side, user),
|
||||
.desiredAmount = if(data.len == 10) std.mem.readInt(u16, data[8..10], .big) else 0xffff,
|
||||
.source = try InventoryAndSlot.read(reader, side, user),
|
||||
.desiredAmount = reader.readInt(u16) catch 0xffff,
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -1434,30 +1401,30 @@ pub const Command = struct { // MARK: Command
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(self: FillFromCreative, data: *main.List(u8)) void {
|
||||
self.dest.write(data.addMany(8)[0..8]);
|
||||
std.mem.writeInt(u16, data.addMany(2)[0..2], self.amount, .big);
|
||||
fn serialize(self: FillFromCreative, writer: *utils.BinaryWriter) void {
|
||||
self.dest.write(writer);
|
||||
writer.writeInt(u16, self.amount);
|
||||
if(self.item) |item| {
|
||||
const zon = ZonElement.initObject(main.stackAllocator);
|
||||
defer zon.deinit(main.stackAllocator);
|
||||
item.insertIntoZon(main.stackAllocator, zon);
|
||||
const string = zon.toStringEfficient(main.stackAllocator, &.{});
|
||||
defer main.stackAllocator.free(string);
|
||||
data.appendSlice(string);
|
||||
writer.writeSlice(string);
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !FillFromCreative {
|
||||
if(data.len < 10) return error.Invalid;
|
||||
const amount = std.mem.readInt(u16, data[8..10], .big);
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !FillFromCreative {
|
||||
const dest = try InventoryAndSlot.read(reader, side, user);
|
||||
const amount = try reader.readInt(u16);
|
||||
var item: ?Item = null;
|
||||
if(data.len > 10) {
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, data[10..]);
|
||||
if(reader.remaining.len != 0) {
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, reader.remaining);
|
||||
defer zon.deinit(main.stackAllocator);
|
||||
item = try Item.init(zon);
|
||||
}
|
||||
return .{
|
||||
.dest = try InventoryAndSlot.read(data[0..8], side, user),
|
||||
.dest = dest,
|
||||
.item = item,
|
||||
.amount = amount,
|
||||
};
|
||||
@ -1509,15 +1476,14 @@ pub const Command = struct { // MARK: Command
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(self: DepositOrDrop, data: *main.List(u8)) void {
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], self.dest.id, .big);
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], self.source.id, .big);
|
||||
fn serialize(self: DepositOrDrop, writer: *utils.BinaryWriter) void {
|
||||
writer.writeInt(u32, self.dest.id);
|
||||
writer.writeInt(u32, self.source.id);
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !DepositOrDrop {
|
||||
if(data.len != 8) return error.Invalid;
|
||||
const destId = std.mem.readInt(u32, data[0..4], .big);
|
||||
const sourceId = std.mem.readInt(u32, data[4..8], .big);
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !DepositOrDrop {
|
||||
const destId = try reader.readInt(u32);
|
||||
const sourceId = try reader.readInt(u32);
|
||||
return .{
|
||||
.dest = Sync.getInventory(destId, side, user) orelse return error.Invalid,
|
||||
.source = Sync.getInventory(sourceId, side, user) orelse return error.Invalid,
|
||||
@ -1543,13 +1509,12 @@ pub const Command = struct { // MARK: Command
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(self: Clear, data: *main.List(u8)) void {
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], self.inv.id, .big);
|
||||
fn serialize(self: Clear, writer: *utils.BinaryWriter) void {
|
||||
writer.writeInt(u32, self.inv.id);
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !Clear {
|
||||
if(data.len != 4) return error.Invalid;
|
||||
const invId = std.mem.readInt(u32, data[0..4], .big);
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !Clear {
|
||||
const invId = try reader.readInt(u32);
|
||||
return .{
|
||||
.inv = Sync.getInventory(invId, side, user) orelse return error.Invalid,
|
||||
};
|
||||
@ -1639,26 +1604,25 @@ pub const Command = struct { // MARK: Command
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(self: UpdateBlock, data: *main.List(u8)) void {
|
||||
self.source.write(data.addMany(8)[0..8]);
|
||||
std.mem.writeInt(i32, data.addMany(4)[0..4], self.pos[0], .big);
|
||||
std.mem.writeInt(i32, data.addMany(4)[0..4], self.pos[1], .big);
|
||||
std.mem.writeInt(i32, data.addMany(4)[0..4], self.pos[2], .big);
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], @as(u32, @bitCast(self.oldBlock)), .big);
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], @as(u32, @bitCast(self.newBlock)), .big);
|
||||
fn serialize(self: UpdateBlock, writer: *utils.BinaryWriter) void {
|
||||
self.source.write(writer);
|
||||
writer.writeInt(i32, self.pos[0]);
|
||||
writer.writeInt(i32, self.pos[1]);
|
||||
writer.writeInt(i32, self.pos[2]);
|
||||
writer.writeInt(u32, @as(u32, @bitCast(self.oldBlock)));
|
||||
writer.writeInt(u32, @as(u32, @bitCast(self.newBlock)));
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, side: Side, user: ?*main.server.User) !UpdateBlock {
|
||||
if(data.len != 28) return error.Invalid;
|
||||
fn deserialize(reader: *utils.BinaryReader, side: Side, user: ?*main.server.User) !UpdateBlock {
|
||||
return .{
|
||||
.source = try InventoryAndSlot.read(data[0..8], side, user),
|
||||
.source = try InventoryAndSlot.read(reader, side, user),
|
||||
.pos = .{
|
||||
std.mem.readInt(i32, data[8..12], .big),
|
||||
std.mem.readInt(i32, data[12..16], .big),
|
||||
std.mem.readInt(i32, data[16..20], .big),
|
||||
try reader.readInt(i32),
|
||||
try reader.readInt(i32),
|
||||
try reader.readInt(i32),
|
||||
},
|
||||
.oldBlock = @bitCast(std.mem.readInt(u32, data[20..24], .big)),
|
||||
.newBlock = @bitCast(std.mem.readInt(u32, data[24..28], .big)),
|
||||
.oldBlock = @bitCast(try reader.readInt(u32)),
|
||||
.newBlock = @bitCast(try reader.readInt(u32)),
|
||||
};
|
||||
}
|
||||
};
|
||||
@ -1696,19 +1660,17 @@ pub const Command = struct { // MARK: Command
|
||||
}}, side);
|
||||
}
|
||||
|
||||
fn serialize(self: AddHealth, data: *main.List(u8)) void {
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], self.target, .big);
|
||||
std.mem.writeInt(u32, data.addMany(4)[0..4], @bitCast(self.health), .big);
|
||||
data.append(@intFromEnum(self.cause));
|
||||
fn serialize(self: AddHealth, writer: *utils.BinaryWriter) void {
|
||||
writer.writeInt(u32, self.target);
|
||||
writer.writeInt(u32, @bitCast(self.health));
|
||||
writer.writeEnum(main.game.DamageType, self.cause);
|
||||
}
|
||||
|
||||
fn deserialize(data: []const u8, _: Side, _: ?*main.server.User) !AddHealth {
|
||||
if(data.len != 9) return error.Invalid;
|
||||
|
||||
fn deserialize(reader: *utils.BinaryReader, _: Side, _: ?*main.server.User) !AddHealth {
|
||||
return .{
|
||||
.target = std.mem.readInt(u32, data[0..4], .big),
|
||||
.health = @bitCast(std.mem.readInt(u32, data[4..8], .big)),
|
||||
.cause = @enumFromInt(data[8]),
|
||||
.target = try reader.readInt(u32),
|
||||
.health = @bitCast(try reader.readInt(u32)),
|
||||
.cause = try reader.readEnum(main.game.DamageType),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
380
src/network.zig
380
src/network.zig
@ -21,6 +21,8 @@ const Vec3f = vec.Vec3f;
|
||||
const Vec3i = vec.Vec3i;
|
||||
const NeverFailingAllocator = main.utils.NeverFailingAllocator;
|
||||
|
||||
pub const networkEndian: std.builtin.Endian = .big;
|
||||
|
||||
//TODO: Might want to use SSL or something similar to encode the message
|
||||
|
||||
const Socket = struct {
|
||||
@ -632,7 +634,7 @@ const UnconfirmedPacket = struct {
|
||||
pub var bytesReceived: [256]Atomic(usize) = .{Atomic(usize).init(0)} ** 256;
|
||||
pub var packetsReceived: [256]Atomic(usize) = .{Atomic(usize).init(0)} ** 256;
|
||||
pub const Protocols = struct {
|
||||
pub var list: [256]?*const fn(*Connection, []const u8) anyerror!void = [_]?*const fn(*Connection, []const u8) anyerror!void{null} ** 256;
|
||||
pub var list: [256]?*const fn(*Connection, *utils.BinaryReader) anyerror!void = [_]?*const fn(*Connection, *utils.BinaryReader) anyerror!void{null} ** 256;
|
||||
pub var isAsynchronous: [256]bool = .{false} ** 256;
|
||||
|
||||
pub const keepAlive: u8 = 0;
|
||||
@ -646,12 +648,13 @@ pub const Protocols = struct {
|
||||
const stepServerData: u8 = 3;
|
||||
pub const stepComplete: u8 = 255;
|
||||
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
if(conn.handShakeState.load(.monotonic) < data[0]) {
|
||||
conn.handShakeState.store(data[0], .monotonic);
|
||||
switch(data[0]) {
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
const newState = try reader.readInt(u8);
|
||||
if(conn.handShakeState.load(.monotonic) < newState) {
|
||||
conn.handShakeState.store(newState, .monotonic);
|
||||
switch(newState) {
|
||||
stepUserData => {
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, data[1..]);
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, reader.remaining);
|
||||
defer zon.deinit(main.stackAllocator);
|
||||
const name = zon.get([]const u8, "name", "unnamed");
|
||||
if(name.len > 500 or main.graphics.TextBuffer.Parser.countVisibleCharacters(name) > 50) {
|
||||
@ -696,10 +699,10 @@ pub const Protocols = struct {
|
||||
std.fs.cwd().deleteTree("serverAssets") catch {}; // Delete old assets.
|
||||
var dir = try std.fs.cwd().makeOpenPath("serverAssets", .{});
|
||||
defer dir.close();
|
||||
try utils.Compression.unpack(dir, data[1..]);
|
||||
try utils.Compression.unpack(dir, reader.remaining);
|
||||
},
|
||||
stepServerData => {
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, data[1..]);
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, reader.remaining);
|
||||
defer zon.deinit(main.stackAllocator);
|
||||
try conn.manager.world.?.finishHandshake(zon);
|
||||
conn.handShakeState.store(stepComplete, .monotonic);
|
||||
@ -707,7 +710,7 @@ pub const Protocols = struct {
|
||||
},
|
||||
stepComplete => {},
|
||||
else => {
|
||||
std.log.err("Unknown state in HandShakeProtocol {}", .{data[0]});
|
||||
std.log.err("Unknown state in HandShakeProtocol {}", .{newState});
|
||||
},
|
||||
}
|
||||
} else {
|
||||
@ -738,66 +741,63 @@ pub const Protocols = struct {
|
||||
pub const chunkRequest = struct {
|
||||
pub const id: u8 = 2;
|
||||
pub const asynchronous = false;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
var remaining = data[0..];
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
const basePosition = Vec3i{
|
||||
std.mem.readInt(i32, remaining[0..4], .big),
|
||||
std.mem.readInt(i32, remaining[4..8], .big),
|
||||
std.mem.readInt(i32, remaining[8..12], .big),
|
||||
try reader.readInt(i32),
|
||||
try reader.readInt(i32),
|
||||
try reader.readInt(i32),
|
||||
};
|
||||
conn.user.?.clientUpdatePos = basePosition;
|
||||
conn.user.?.renderDistance = std.mem.readInt(u16, remaining[12..14], .big);
|
||||
remaining = remaining[14..];
|
||||
while(remaining.len >= 4) {
|
||||
const voxelSizeShift: u5 = @intCast(remaining[3]);
|
||||
conn.user.?.renderDistance = try reader.readInt(u16);
|
||||
while(reader.remaining.len >= 4) {
|
||||
const x: i32 = try reader.readInt(i8);
|
||||
const y: i32 = try reader.readInt(i8);
|
||||
const z: i32 = try reader.readInt(i8);
|
||||
const voxelSizeShift: u5 = try reader.readInt(u5);
|
||||
const positionMask = ~((@as(i32, 1) << voxelSizeShift + chunk.chunkShift) - 1);
|
||||
const request = chunk.ChunkPosition{
|
||||
.wx = (@as(i32, @as(i8, @bitCast(remaining[0]))) << voxelSizeShift + chunk.chunkShift) +% (basePosition[0] & positionMask),
|
||||
.wy = (@as(i32, @as(i8, @bitCast(remaining[1]))) << voxelSizeShift + chunk.chunkShift) +% (basePosition[1] & positionMask),
|
||||
.wz = (@as(i32, @as(i8, @bitCast(remaining[2]))) << voxelSizeShift + chunk.chunkShift) +% (basePosition[2] & positionMask),
|
||||
.wx = (x << voxelSizeShift + chunk.chunkShift) +% (basePosition[0] & positionMask),
|
||||
.wy = (y << voxelSizeShift + chunk.chunkShift) +% (basePosition[1] & positionMask),
|
||||
.wz = (z << voxelSizeShift + chunk.chunkShift) +% (basePosition[2] & positionMask),
|
||||
.voxelSize = @as(u31, 1) << voxelSizeShift,
|
||||
};
|
||||
if(conn.user) |user| {
|
||||
user.increaseRefCount();
|
||||
main.server.world.?.queueChunkAndDecreaseRefCount(request, user);
|
||||
}
|
||||
remaining = remaining[4..];
|
||||
}
|
||||
}
|
||||
pub fn sendRequest(conn: *Connection, requests: []chunk.ChunkPosition, basePosition: Vec3i, renderDistance: u16) void {
|
||||
if(requests.len == 0) return;
|
||||
const data = main.stackAllocator.alloc(u8, 14 + 4*requests.len);
|
||||
defer main.stackAllocator.free(data);
|
||||
var remaining = data;
|
||||
std.mem.writeInt(i32, remaining[0..4], basePosition[0], .big);
|
||||
std.mem.writeInt(i32, remaining[4..8], basePosition[1], .big);
|
||||
std.mem.writeInt(i32, remaining[8..12], basePosition[2], .big);
|
||||
std.mem.writeInt(u16, remaining[12..14], renderDistance, .big);
|
||||
remaining = remaining[14..];
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, 14 + 4*requests.len);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(i32, basePosition[0]);
|
||||
writer.writeInt(i32, basePosition[1]);
|
||||
writer.writeInt(i32, basePosition[2]);
|
||||
writer.writeInt(u16, renderDistance);
|
||||
for(requests) |req| {
|
||||
const voxelSizeShift: u5 = std.math.log2_int(u31, req.voxelSize);
|
||||
const positionMask = ~((@as(i32, 1) << voxelSizeShift + chunk.chunkShift) - 1);
|
||||
remaining[0] = @bitCast(@as(i8, @intCast((req.wx -% (basePosition[0] & positionMask)) >> voxelSizeShift + chunk.chunkShift)));
|
||||
remaining[1] = @bitCast(@as(i8, @intCast((req.wy -% (basePosition[1] & positionMask)) >> voxelSizeShift + chunk.chunkShift)));
|
||||
remaining[2] = @bitCast(@as(i8, @intCast((req.wz -% (basePosition[2] & positionMask)) >> voxelSizeShift + chunk.chunkShift)));
|
||||
remaining[3] = voxelSizeShift;
|
||||
remaining = remaining[4..];
|
||||
writer.writeInt(i8, @intCast((req.wx -% (basePosition[0] & positionMask)) >> voxelSizeShift + chunk.chunkShift));
|
||||
writer.writeInt(i8, @intCast((req.wy -% (basePosition[1] & positionMask)) >> voxelSizeShift + chunk.chunkShift));
|
||||
writer.writeInt(i8, @intCast((req.wz -% (basePosition[2] & positionMask)) >> voxelSizeShift + chunk.chunkShift));
|
||||
writer.writeInt(u5, voxelSizeShift);
|
||||
}
|
||||
conn.sendImportant(id, data);
|
||||
conn.sendImportant(id, writer.data.items);
|
||||
}
|
||||
};
|
||||
pub const chunkTransmission = struct {
|
||||
pub const id: u8 = 3;
|
||||
pub const asynchronous = true;
|
||||
fn receive(_: *Connection, data: []const u8) !void {
|
||||
fn receive(_: *Connection, reader: *utils.BinaryReader) !void {
|
||||
const pos = chunk.ChunkPosition{
|
||||
.wx = std.mem.readInt(i32, data[0..4], .big),
|
||||
.wy = std.mem.readInt(i32, data[4..8], .big),
|
||||
.wz = std.mem.readInt(i32, data[8..12], .big),
|
||||
.voxelSize = @intCast(std.mem.readInt(i32, data[12..16], .big)),
|
||||
.wx = try reader.readInt(i32),
|
||||
.wy = try reader.readInt(i32),
|
||||
.wz = try reader.readInt(i32),
|
||||
.voxelSize = try reader.readInt(u31),
|
||||
};
|
||||
const ch = chunk.Chunk.init(pos);
|
||||
try main.server.storage.ChunkCompression.decompressChunk(ch, data[16..]);
|
||||
try main.server.storage.ChunkCompression.decompressChunk(ch, reader.remaining);
|
||||
renderer.mesh_storage.updateChunkMesh(ch);
|
||||
}
|
||||
fn sendChunkOverTheNetwork(conn: *Connection, ch: *chunk.ServerChunk) void {
|
||||
@ -805,14 +805,14 @@ pub const Protocols = struct {
|
||||
const chunkData = main.server.storage.ChunkCompression.compressChunk(main.stackAllocator, &ch.super, ch.super.pos.voxelSize != 1);
|
||||
ch.mutex.unlock();
|
||||
defer main.stackAllocator.free(chunkData);
|
||||
const data = main.stackAllocator.alloc(u8, chunkData.len + 16);
|
||||
defer main.stackAllocator.free(data);
|
||||
std.mem.writeInt(i32, data[0..4], ch.super.pos.wx, .big);
|
||||
std.mem.writeInt(i32, data[4..8], ch.super.pos.wy, .big);
|
||||
std.mem.writeInt(i32, data[8..12], ch.super.pos.wz, .big);
|
||||
std.mem.writeInt(i32, data[12..16], ch.super.pos.voxelSize, .big);
|
||||
@memcpy(data[16..], chunkData);
|
||||
conn.sendImportant(id, data);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, chunkData.len + 16);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(i32, ch.super.pos.wx);
|
||||
writer.writeInt(i32, ch.super.pos.wy);
|
||||
writer.writeInt(i32, ch.super.pos.wz);
|
||||
writer.writeInt(u31, ch.super.pos.voxelSize);
|
||||
writer.writeSlice(chunkData);
|
||||
conn.sendImportant(id, writer.data.items);
|
||||
}
|
||||
fn sendChunkLocally(ch: *chunk.ServerChunk) void {
|
||||
const chunkCopy = chunk.Chunk.init(ch.super.pos);
|
||||
@ -831,8 +831,8 @@ pub const Protocols = struct {
|
||||
pub const playerPosition = struct {
|
||||
pub const id: u8 = 4;
|
||||
pub const asynchronous = false;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
conn.user.?.receiveData(data);
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
conn.user.?.receiveData(reader.remaining);
|
||||
}
|
||||
var lastPositionSent: u16 = 0;
|
||||
pub fn send(conn: *Connection, playerPos: Vec3d, playerVel: Vec3d, time: u16) void {
|
||||
@ -840,24 +840,25 @@ pub const Protocols = struct {
|
||||
return; // Only send at most once every 50 ms.
|
||||
}
|
||||
lastPositionSent = time;
|
||||
var data: [62]u8 = undefined;
|
||||
std.mem.writeInt(u64, data[0..8], @as(u64, @bitCast(playerPos[0])), .big);
|
||||
std.mem.writeInt(u64, data[8..16], @as(u64, @bitCast(playerPos[1])), .big);
|
||||
std.mem.writeInt(u64, data[16..24], @as(u64, @bitCast(playerPos[2])), .big);
|
||||
std.mem.writeInt(u64, data[24..32], @as(u64, @bitCast(playerVel[0])), .big);
|
||||
std.mem.writeInt(u64, data[32..40], @as(u64, @bitCast(playerVel[1])), .big);
|
||||
std.mem.writeInt(u64, data[40..48], @as(u64, @bitCast(playerVel[2])), .big);
|
||||
std.mem.writeInt(u32, data[48..52], @as(u32, @bitCast(game.camera.rotation[0])), .big);
|
||||
std.mem.writeInt(u32, data[52..56], @as(u32, @bitCast(game.camera.rotation[1])), .big);
|
||||
std.mem.writeInt(u32, data[56..60], @as(u32, @bitCast(game.camera.rotation[2])), .big);
|
||||
std.mem.writeInt(u16, data[60..62], time, .big);
|
||||
conn.sendUnimportant(id, &data);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, 62);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(u64, @bitCast(playerPos[0]));
|
||||
writer.writeInt(u64, @bitCast(playerPos[1]));
|
||||
writer.writeInt(u64, @bitCast(playerPos[2]));
|
||||
writer.writeInt(u64, @bitCast(playerVel[0]));
|
||||
writer.writeInt(u64, @bitCast(playerVel[1]));
|
||||
writer.writeInt(u64, @bitCast(playerVel[2]));
|
||||
writer.writeInt(u32, @bitCast(game.camera.rotation[0]));
|
||||
writer.writeInt(u32, @bitCast(game.camera.rotation[1]));
|
||||
writer.writeInt(u32, @bitCast(game.camera.rotation[2]));
|
||||
writer.writeInt(u16, time);
|
||||
conn.sendUnimportant(id, writer.data.items);
|
||||
}
|
||||
};
|
||||
pub const disconnect = struct {
|
||||
pub const id: u8 = 5;
|
||||
pub const asynchronous = false;
|
||||
fn receive(conn: *Connection, _: []const u8) !void {
|
||||
fn receive(conn: *Connection, _: *utils.BinaryReader) !void {
|
||||
conn.disconnect();
|
||||
if(conn.user) |user| {
|
||||
main.server.disconnect(user);
|
||||
@ -875,44 +876,45 @@ pub const Protocols = struct {
|
||||
pub const asynchronous = false;
|
||||
const type_entity: u8 = 0;
|
||||
const type_item: u8 = 1;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
if(conn.manager.world) |world| {
|
||||
const time = std.mem.readInt(i16, data[1..3], .big);
|
||||
if(data[0] == type_entity) {
|
||||
main.entity.ClientEntityManager.serverUpdate(time, data[3..]);
|
||||
} else if(data[0] == type_item) {
|
||||
world.itemDrops.readPosition(data[3..], time);
|
||||
const typ = try reader.readInt(u8);
|
||||
const time = try reader.readInt(i16);
|
||||
if(typ == type_entity) {
|
||||
main.entity.ClientEntityManager.serverUpdate(time, reader.remaining);
|
||||
} else if(typ == type_item) {
|
||||
world.itemDrops.readPosition(reader.remaining, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn send(conn: *Connection, entityData: []const u8, itemData: []const u8) void {
|
||||
if(entityData.len != 0) {
|
||||
const fullEntityData = main.stackAllocator.alloc(u8, entityData.len + 3);
|
||||
defer main.stackAllocator.free(fullEntityData);
|
||||
fullEntityData[0] = type_entity;
|
||||
std.mem.writeInt(i16, fullEntityData[1..3], @as(i16, @truncate(std.time.milliTimestamp())), .big);
|
||||
@memcpy(fullEntityData[3..], entityData);
|
||||
conn.sendUnimportant(id, fullEntityData);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, entityData.len + 3);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(u8, type_entity);
|
||||
writer.writeInt(i16, @truncate(std.time.milliTimestamp()));
|
||||
writer.writeSlice(entityData);
|
||||
conn.sendUnimportant(id, writer.data.items);
|
||||
}
|
||||
|
||||
if(itemData.len != 0) {
|
||||
const fullItemData = main.stackAllocator.alloc(u8, itemData.len + 3);
|
||||
defer main.stackAllocator.free(fullItemData);
|
||||
fullItemData[0] = type_item;
|
||||
std.mem.writeInt(i16, fullItemData[1..3], @as(i16, @truncate(std.time.milliTimestamp())), .big);
|
||||
@memcpy(fullItemData[3..], itemData);
|
||||
conn.sendUnimportant(id, fullItemData);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, itemData.len + 3);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(u8, type_item);
|
||||
writer.writeInt(i16, @truncate(std.time.milliTimestamp()));
|
||||
writer.writeSlice(itemData);
|
||||
conn.sendUnimportant(id, writer.data.items);
|
||||
}
|
||||
}
|
||||
};
|
||||
pub const blockUpdate = struct {
|
||||
pub const id: u8 = 7;
|
||||
pub const asynchronous = false;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
const x = std.mem.readInt(i32, data[0..4], .big);
|
||||
const y = std.mem.readInt(i32, data[4..8], .big);
|
||||
const z = std.mem.readInt(i32, data[8..12], .big);
|
||||
const newBlock = Block.fromInt(std.mem.readInt(u32, data[12..16], .big));
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
const x = try reader.readInt(i32);
|
||||
const y = try reader.readInt(i32);
|
||||
const z = try reader.readInt(i32);
|
||||
const newBlock = Block.fromInt(try reader.readInt(u32));
|
||||
if(conn.user != null) {
|
||||
return error.InvalidPacket;
|
||||
} else {
|
||||
@ -920,19 +922,20 @@ pub const Protocols = struct {
|
||||
}
|
||||
}
|
||||
pub fn send(conn: *Connection, x: i32, y: i32, z: i32, newBlock: Block) void {
|
||||
var data: [16]u8 = undefined;
|
||||
std.mem.writeInt(i32, data[0..4], x, .big);
|
||||
std.mem.writeInt(i32, data[4..8], y, .big);
|
||||
std.mem.writeInt(i32, data[8..12], z, .big);
|
||||
std.mem.writeInt(u32, data[12..16], newBlock.toInt(), .big);
|
||||
conn.sendImportant(id, &data);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, 16);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(i32, x);
|
||||
writer.writeInt(i32, y);
|
||||
writer.writeInt(i32, z);
|
||||
writer.writeInt(u32, newBlock.toInt());
|
||||
conn.sendImportant(id, writer.data.items);
|
||||
}
|
||||
};
|
||||
pub const entity = struct {
|
||||
pub const id: u8 = 8;
|
||||
pub const asynchronous = false;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
const zonArray = ZonElement.parseFromString(main.stackAllocator, null, data);
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
const zonArray = ZonElement.parseFromString(main.stackAllocator, null, reader.remaining);
|
||||
defer zonArray.deinit(main.stackAllocator);
|
||||
var i: u32 = 0;
|
||||
while(i < zonArray.array.items.len) : (i += 1) {
|
||||
@ -949,7 +952,7 @@ pub const Protocols = struct {
|
||||
break;
|
||||
},
|
||||
else => {
|
||||
std.log.err("Unrecognized zon parameters for protocol {}: {s}", .{id, data});
|
||||
std.log.err("Unrecognized zon parameters for protocol {}: {s}", .{id, reader.remaining});
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -980,18 +983,17 @@ pub const Protocols = struct {
|
||||
const type_reserved5: u8 = 6;
|
||||
const type_reserved6: u8 = 7;
|
||||
const type_timeAndBiome: u8 = 8;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
switch(data[0]) {
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
switch(try reader.readInt(u8)) {
|
||||
type_gamemode => {
|
||||
if(conn.user != null) return error.InvalidPacket;
|
||||
if(data.len != 2) return error.InvalidPacket;
|
||||
main.items.Inventory.Sync.setGamemode(null, @enumFromInt(data[1]));
|
||||
main.items.Inventory.Sync.setGamemode(null, try reader.readEnum(main.game.Gamemode));
|
||||
},
|
||||
type_teleport => {
|
||||
game.Player.setPosBlocking(Vec3d{
|
||||
@bitCast(std.mem.readInt(u64, data[1..9], .big)),
|
||||
@bitCast(std.mem.readInt(u64, data[9..17], .big)),
|
||||
@bitCast(std.mem.readInt(u64, data[17..25], .big)),
|
||||
@bitCast(try reader.readInt(u64)),
|
||||
@bitCast(try reader.readInt(u64)),
|
||||
@bitCast(try reader.readInt(u64)),
|
||||
});
|
||||
},
|
||||
type_cure => {
|
||||
@ -1004,7 +1006,7 @@ pub const Protocols = struct {
|
||||
type_reserved6 => {},
|
||||
type_timeAndBiome => {
|
||||
if(conn.manager.world) |world| {
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, data[1..]);
|
||||
const zon = ZonElement.parseFromString(main.stackAllocator, null, reader.remaining);
|
||||
defer zon.deinit(main.stackAllocator);
|
||||
const expectedTime = zon.get(i64, "time", 0);
|
||||
var curTime = world.gameTime.load(.monotonic);
|
||||
@ -1027,7 +1029,8 @@ pub const Protocols = struct {
|
||||
}
|
||||
},
|
||||
else => |unrecognizedType| {
|
||||
std.log.err("Unrecognized type for genericUpdateProtocol: {}. Data: {any}", .{unrecognizedType, data});
|
||||
std.log.err("Unrecognized type for genericUpdateProtocol: {}. Data: {any}", .{unrecognizedType, reader.remaining});
|
||||
return error.Invalid;
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1053,12 +1056,13 @@ pub const Protocols = struct {
|
||||
}
|
||||
|
||||
pub fn sendTPCoordinates(conn: *Connection, pos: Vec3d) void {
|
||||
var data: [1 + 24]u8 = undefined;
|
||||
data[0] = type_teleport;
|
||||
std.mem.writeInt(u64, data[1..9], @as(u64, @bitCast(pos[0])), .big);
|
||||
std.mem.writeInt(u64, data[9..17], @as(u64, @bitCast(pos[1])), .big);
|
||||
std.mem.writeInt(u64, data[17..25], @as(u64, @bitCast(pos[2])), .big);
|
||||
conn.sendImportant(id, &data);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, 25);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(u8, type_teleport);
|
||||
writer.writeInt(u64, @bitCast(pos[0]));
|
||||
writer.writeInt(u64, @bitCast(pos[1]));
|
||||
writer.writeInt(u64, @bitCast(pos[2]));
|
||||
conn.sendImportant(id, writer.data.items);
|
||||
}
|
||||
|
||||
pub fn sendCure(conn: *Connection) void {
|
||||
@ -1081,131 +1085,135 @@ pub const Protocols = struct {
|
||||
pub const chat = struct {
|
||||
pub const id: u8 = 10;
|
||||
pub const asynchronous = false;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
const msg = reader.remaining;
|
||||
if(conn.user) |user| {
|
||||
if(data.len > 10000 or main.graphics.TextBuffer.Parser.countVisibleCharacters(data) > 1000) {
|
||||
std.log.err("Received too long chat message with {}/{} characters.", .{main.graphics.TextBuffer.Parser.countVisibleCharacters(data), data.len});
|
||||
if(msg.len > 10000 or main.graphics.TextBuffer.Parser.countVisibleCharacters(msg) > 1000) {
|
||||
std.log.err("Received too long chat message with {}/{} characters.", .{main.graphics.TextBuffer.Parser.countVisibleCharacters(msg), msg.len});
|
||||
return error.Invalid;
|
||||
}
|
||||
main.server.messageFrom(data, user);
|
||||
main.server.messageFrom(msg, user);
|
||||
} else {
|
||||
main.gui.windowlist.chat.addMessage(data);
|
||||
main.gui.windowlist.chat.addMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(conn: *Connection, data: []const u8) void {
|
||||
conn.sendImportant(id, data);
|
||||
pub fn send(conn: *Connection, msg: []const u8) void {
|
||||
conn.sendImportant(id, msg);
|
||||
}
|
||||
};
|
||||
pub const lightMapRequest = struct {
|
||||
pub const id: u8 = 11;
|
||||
pub const asynchronous = false;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
var remaining = data[0..];
|
||||
while(remaining.len >= 9) {
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
while(reader.remaining.len >= 9) {
|
||||
const wx = try reader.readInt(i32);
|
||||
const wy = try reader.readInt(i32);
|
||||
const voxelSizeShift = try reader.readInt(u5);
|
||||
const request = main.server.terrain.SurfaceMap.MapFragmentPosition{
|
||||
.wx = std.mem.readInt(i32, remaining[0..4], .big),
|
||||
.wy = std.mem.readInt(i32, remaining[4..8], .big),
|
||||
.voxelSize = @as(u31, 1) << @intCast(std.mem.readInt(u8, remaining[8..9], .big)),
|
||||
.voxelSizeShift = @intCast(std.mem.readInt(u8, remaining[8..9], .big)),
|
||||
.wx = wx,
|
||||
.wy = wy,
|
||||
.voxelSize = @as(u31, 1) << voxelSizeShift,
|
||||
.voxelSizeShift = voxelSizeShift,
|
||||
};
|
||||
if(conn.user) |user| {
|
||||
user.increaseRefCount();
|
||||
main.server.world.?.queueLightMapAndDecreaseRefCount(request, user);
|
||||
}
|
||||
remaining = remaining[9..];
|
||||
}
|
||||
}
|
||||
pub fn sendRequest(conn: *Connection, requests: []main.server.terrain.SurfaceMap.MapFragmentPosition) void {
|
||||
if(requests.len == 0) return;
|
||||
const data = main.stackAllocator.alloc(u8, 9*requests.len);
|
||||
defer main.stackAllocator.free(data);
|
||||
var remaining = data;
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, 9*requests.len);
|
||||
defer writer.deinit();
|
||||
for(requests) |req| {
|
||||
std.mem.writeInt(i32, remaining[0..4], req.wx, .big);
|
||||
std.mem.writeInt(i32, remaining[4..8], req.wy, .big);
|
||||
std.mem.writeInt(u8, remaining[8..9], req.voxelSizeShift, .big);
|
||||
remaining = remaining[9..];
|
||||
writer.writeInt(i32, req.wx);
|
||||
writer.writeInt(i32, req.wy);
|
||||
writer.writeInt(u8, req.voxelSizeShift);
|
||||
}
|
||||
conn.sendImportant(id, data);
|
||||
conn.sendImportant(id, writer.data.items);
|
||||
}
|
||||
};
|
||||
pub const lightMapTransmission = struct {
|
||||
pub const id: u8 = 12;
|
||||
pub const asynchronous = true;
|
||||
fn receive(_: *Connection, _data: []const u8) !void {
|
||||
var data = _data;
|
||||
fn receive(_: *Connection, reader: *utils.BinaryReader) !void {
|
||||
const wx = try reader.readInt(i32);
|
||||
const wy = try reader.readInt(i32);
|
||||
const voxelSizeShift = try reader.readInt(u5);
|
||||
const pos = main.server.terrain.SurfaceMap.MapFragmentPosition{
|
||||
.wx = std.mem.readInt(i32, data[0..4], .big),
|
||||
.wy = std.mem.readInt(i32, data[4..8], .big),
|
||||
.voxelSize = @as(u31, 1) << @intCast(std.mem.readInt(u8, data[8..9], .big)),
|
||||
.voxelSizeShift = @intCast(std.mem.readInt(u8, data[8..9], .big)),
|
||||
.wx = wx,
|
||||
.wy = wy,
|
||||
.voxelSize = @as(u31, 1) << voxelSizeShift,
|
||||
.voxelSizeShift = voxelSizeShift,
|
||||
};
|
||||
const _inflatedData = main.stackAllocator.alloc(u8, main.server.terrain.LightMap.LightMapFragment.mapSize*main.server.terrain.LightMap.LightMapFragment.mapSize*2);
|
||||
defer main.stackAllocator.free(_inflatedData);
|
||||
const _inflatedLen = try utils.Compression.inflateTo(_inflatedData, data[9..]);
|
||||
const _inflatedLen = try utils.Compression.inflateTo(_inflatedData, reader.remaining);
|
||||
if(_inflatedLen != main.server.terrain.LightMap.LightMapFragment.mapSize*main.server.terrain.LightMap.LightMapFragment.mapSize*2) {
|
||||
std.log.err("Transmission of light map has invalid size: {}. Input data: {any}, After inflate: {any}", .{_inflatedLen, data, _inflatedData[0.._inflatedLen]});
|
||||
std.log.err("Transmission of light map has invalid size: {}. Input data: {any}, After inflate: {any}", .{_inflatedLen, reader.remaining, _inflatedData[0.._inflatedLen]});
|
||||
return error.Invalid;
|
||||
}
|
||||
data = _inflatedData;
|
||||
var ligthMapReader = utils.BinaryReader.init(_inflatedData, networkEndian);
|
||||
const map = main.globalAllocator.create(main.server.terrain.LightMap.LightMapFragment);
|
||||
map.init(pos.wx, pos.wy, pos.voxelSize);
|
||||
_ = map.refCount.fetchAdd(1, .monotonic);
|
||||
for(&map.startHeight) |*val| {
|
||||
val.* = std.mem.readInt(i16, data[0..2], .big);
|
||||
data = data[2..];
|
||||
val.* = try ligthMapReader.readInt(i16);
|
||||
}
|
||||
renderer.mesh_storage.updateLightMap(map);
|
||||
}
|
||||
pub fn sendLightMap(conn: *Connection, map: *main.server.terrain.LightMap.LightMapFragment) void {
|
||||
var uncompressedData: [@sizeOf(@TypeOf(map.startHeight))]u8 = undefined; // TODO: #15280
|
||||
for(&map.startHeight, 0..) |val, i| {
|
||||
std.mem.writeInt(i16, uncompressedData[2*i ..][0..2], val, .big);
|
||||
var ligthMapWriter = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, @sizeOf(@TypeOf(map.startHeight)));
|
||||
defer ligthMapWriter.deinit();
|
||||
for(&map.startHeight) |val| {
|
||||
ligthMapWriter.writeInt(i16, val);
|
||||
}
|
||||
const compressedData = utils.Compression.deflate(main.stackAllocator, &uncompressedData, .default);
|
||||
const compressedData = utils.Compression.deflate(main.stackAllocator, ligthMapWriter.data.items, .default);
|
||||
defer main.stackAllocator.free(compressedData);
|
||||
const data = main.stackAllocator.alloc(u8, 9 + compressedData.len);
|
||||
defer main.stackAllocator.free(data);
|
||||
@memcpy(data[9..], compressedData);
|
||||
std.mem.writeInt(i32, data[0..4], map.pos.wx, .big);
|
||||
std.mem.writeInt(i32, data[4..8], map.pos.wy, .big);
|
||||
std.mem.writeInt(u8, data[8..9], map.pos.voxelSizeShift, .big);
|
||||
conn.sendImportant(id, data);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, 9 + compressedData.len);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(i32, map.pos.wx);
|
||||
writer.writeInt(i32, map.pos.wy);
|
||||
writer.writeInt(u8, map.pos.voxelSizeShift);
|
||||
writer.writeSlice(compressedData);
|
||||
conn.sendImportant(id, writer.data.items);
|
||||
}
|
||||
};
|
||||
pub const inventory = struct {
|
||||
pub const id: u8 = 13;
|
||||
pub const asynchronous = false;
|
||||
fn receive(conn: *Connection, data: []const u8) !void {
|
||||
fn receive(conn: *Connection, reader: *utils.BinaryReader) !void {
|
||||
if(conn.user) |user| {
|
||||
if(data[0] == 0xff) return error.InvalidPacket;
|
||||
try items.Inventory.Sync.ServerSide.receiveCommand(user, data);
|
||||
if(reader.remaining[0] == 0xff) return error.InvalidPacket;
|
||||
try items.Inventory.Sync.ServerSide.receiveCommand(user, reader);
|
||||
} else {
|
||||
if(data[0] == 0xff) { // Confirmation
|
||||
items.Inventory.Sync.ClientSide.receiveConfirmation(data[1..]);
|
||||
} else if(data[0] == 0xfe) { // Failure
|
||||
const typ = try reader.readInt(u8);
|
||||
if(typ == 0xff) { // Confirmation
|
||||
try items.Inventory.Sync.ClientSide.receiveConfirmation(reader);
|
||||
} else if(typ == 0xfe) { // Failure
|
||||
items.Inventory.Sync.ClientSide.receiveFailure();
|
||||
} else {
|
||||
try items.Inventory.Sync.ClientSide.receiveSyncOperation(data[1..]);
|
||||
try items.Inventory.Sync.ClientSide.receiveSyncOperation(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn sendCommand(conn: *Connection, payloadType: items.Inventory.Command.PayloadType, _data: []const u8) void {
|
||||
std.debug.assert(conn.user == null);
|
||||
var data = main.stackAllocator.alloc(u8, _data.len + 1);
|
||||
defer main.stackAllocator.free(data);
|
||||
data[0] = @intFromEnum(payloadType);
|
||||
std.debug.assert(data[0] != 0xff);
|
||||
@memcpy(data[1..], _data);
|
||||
conn.sendImportant(id, data);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, _data.len + 1);
|
||||
defer writer.deinit();
|
||||
writer.writeEnum(items.Inventory.Command.PayloadType, payloadType);
|
||||
std.debug.assert(writer.data.items[0] != 0xff);
|
||||
writer.writeSlice(_data);
|
||||
conn.sendImportant(id, writer.data.items);
|
||||
}
|
||||
pub fn sendConfirmation(conn: *Connection, _data: []const u8) void {
|
||||
std.debug.assert(conn.user != null);
|
||||
var data = main.stackAllocator.alloc(u8, _data.len + 1);
|
||||
defer main.stackAllocator.free(data);
|
||||
data[0] = 0xff;
|
||||
@memcpy(data[1..], _data);
|
||||
conn.sendImportant(id, data);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, _data.len + 1);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(u8, 0xff);
|
||||
writer.writeSlice(_data);
|
||||
conn.sendImportant(id, writer.data.items);
|
||||
}
|
||||
pub fn sendFailure(conn: *Connection) void {
|
||||
std.debug.assert(conn.user != null);
|
||||
@ -1213,11 +1221,11 @@ pub const Protocols = struct {
|
||||
}
|
||||
pub fn sendSyncOperation(conn: *Connection, _data: []const u8) void {
|
||||
std.debug.assert(conn.user != null);
|
||||
var data = main.stackAllocator.alloc(u8, _data.len + 1);
|
||||
defer main.stackAllocator.free(data);
|
||||
data[0] = 0;
|
||||
@memcpy(data[1..], _data);
|
||||
conn.sendImportant(id, data);
|
||||
var writer = utils.BinaryWriter.initCapacity(main.stackAllocator, networkEndian, _data.len + 1);
|
||||
defer writer.deinit();
|
||||
writer.writeInt(u8, 0);
|
||||
writer.writeSlice(_data);
|
||||
conn.sendImportant(id, writer.data.items);
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -1680,7 +1688,8 @@ pub const Connection = struct { // MARK: Connection
|
||||
if(Protocols.isAsynchronous[protocol]) {
|
||||
ProtocolTask.schedule(self, protocol, data);
|
||||
} else {
|
||||
try prot(self, data);
|
||||
var reader = utils.BinaryReader.init(data, networkEndian);
|
||||
try prot(self, &reader);
|
||||
}
|
||||
} else {
|
||||
std.log.err("Received unknown important protocol with id {}", .{protocol});
|
||||
@ -1721,7 +1730,7 @@ pub const Connection = struct { // MARK: Connection
|
||||
}
|
||||
}
|
||||
if(id - @as(i33, self.lastIncompletePacket) >= 65536) {
|
||||
std.log.warn("Many incomplete packages. Cannot process any more packages for now.", .{});
|
||||
std.log.warn("Many incomplete packets. Cannot process any more packets for now.", .{});
|
||||
return;
|
||||
}
|
||||
self.receivedPackets[0].append(id);
|
||||
@ -1737,9 +1746,11 @@ pub const Connection = struct { // MARK: Connection
|
||||
self.receiveKeepAlive(data[1..]);
|
||||
} else {
|
||||
if(Protocols.list[protocol]) |prot| {
|
||||
try prot(self, data[1..]);
|
||||
var reader = utils.BinaryReader.init(data[1..], networkEndian);
|
||||
try prot(self, &reader);
|
||||
} else {
|
||||
std.log.err("Received unknown protocol with id {}", .{protocol});
|
||||
return error.Invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1791,7 +1802,8 @@ const ProtocolTask = struct {
|
||||
|
||||
pub fn run(self: *ProtocolTask) void {
|
||||
defer self.clean();
|
||||
Protocols.list[self.protocol].?(self.conn, self.data) catch |err| {
|
||||
var reader = utils.BinaryReader.init(self.data, networkEndian);
|
||||
Protocols.list[self.protocol].?(self.conn, &reader) catch |err| {
|
||||
std.log.err("Got error {s} while executing protocol {} with data {any}", .{@errorName(err), self.protocol, self.data}); // TODO: Maybe disconnect on error
|
||||
};
|
||||
}
|
||||
|
@ -1843,3 +1843,77 @@ pub const Side = enum {
|
||||
client,
|
||||
server,
|
||||
};
|
||||
|
||||
pub const BinaryReader = struct {
|
||||
remaining: []const u8,
|
||||
endian: std.builtin.Endian,
|
||||
|
||||
pub fn init(data: []const u8, endian: std.builtin.Endian) BinaryReader {
|
||||
return .{.remaining = data, .endian = endian};
|
||||
}
|
||||
|
||||
pub fn readInt(self: *BinaryReader, T: type) error{OutOfBounds, IntOutOfBounds}!T {
|
||||
if(@mod(@typeInfo(T).int.bits, 8) != 0) {
|
||||
const fullBits = comptime std.mem.alignForward(u16, @typeInfo(T).int.bits, 8);
|
||||
const FullType = std.meta.Int(@typeInfo(T).int.signedness, fullBits);
|
||||
const val = try self.readInt(FullType);
|
||||
return std.math.cast(T, val) orelse return error.IntOutOfBounds;
|
||||
}
|
||||
const bufSize = @divExact(@typeInfo(T).int.bits, 8);
|
||||
if(self.remaining.len < bufSize) return error.OutOfBounds;
|
||||
defer self.remaining = self.remaining[bufSize..];
|
||||
return std.mem.readInt(T, self.remaining[0..bufSize], self.endian);
|
||||
}
|
||||
|
||||
pub fn readEnum(self: *BinaryReader, T: type) error{OutOfBounds, IntOutOfBounds, InvalidEnumTag}!T {
|
||||
const int = try self.readInt(@typeInfo(T).@"enum".tag_type);
|
||||
return std.meta.intToEnum(T, int);
|
||||
}
|
||||
|
||||
pub fn readUntilDelimiter(self: *BinaryReader, comptime delimiter: u8) ![:delimiter]const u8 {
|
||||
const len = std.mem.indexOfScalar(u8, self.remaining, delimiter) orelse return error.OutOfBounds;
|
||||
defer self.remaining = self.remaining[len+1..];
|
||||
return self.remaining[0..len:delimiter];
|
||||
}
|
||||
};
|
||||
|
||||
pub const BinaryWriter = struct {
|
||||
data: main.List(u8),
|
||||
endian: std.builtin.Endian,
|
||||
|
||||
pub fn init(allocator: NeverFailingAllocator, endian: std.builtin.Endian) BinaryWriter {
|
||||
return .{.data = .init(allocator), .endian = endian};
|
||||
}
|
||||
|
||||
pub fn initCapacity(allocator: NeverFailingAllocator, endian: std.builtin.Endian, capacity: usize) BinaryWriter {
|
||||
return .{.data = .initCapacity(allocator, capacity), .endian = endian};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *BinaryWriter) void {
|
||||
self.data.deinit();
|
||||
}
|
||||
|
||||
pub fn writeInt(self: *BinaryWriter, T: type, value: T) void {
|
||||
if(@mod(@typeInfo(T).int.bits, 8) != 0) {
|
||||
const fullBits = comptime std.mem.alignForward(u16, @typeInfo(T).int.bits, 8);
|
||||
const FullType = std.meta.Int(@typeInfo(T).int.signedness, fullBits);
|
||||
return self.writeInt(FullType, value);
|
||||
}
|
||||
const bufSize = @divExact(@typeInfo(T).int.bits, 8);
|
||||
std.mem.writeInt(T, self.data.addMany(bufSize)[0..bufSize], value, self.endian);
|
||||
}
|
||||
|
||||
pub fn writeEnum(self: *BinaryWriter, T: type, value: T) void {
|
||||
self.writeInt(@typeInfo(T).@"enum".tag_type, @intFromEnum(value));
|
||||
}
|
||||
|
||||
pub fn writeSlice(self: *BinaryWriter, slice: []const u8) void {
|
||||
self.data.appendSlice(slice);
|
||||
}
|
||||
|
||||
pub fn writeWithDelimiter(self: *BinaryWriter, slice: []const u8, delimiter: u8) void {
|
||||
std.debug.assert(!std.mem.containsAtLeast(u8, slice, 1, &.{delimiter}));
|
||||
self.writeSlice(slice);
|
||||
self.data.append(delimiter);
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user