Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/game.zig
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,11 @@ pub fn update(deltaTime: f64) void { // MARK: update()
if (world.?.shouldRestart.load(.acquire)) {
restart();
}
main.sync.client.update() catch |err| {
std.log.err("Got error while processing server sync commands: {s}. Disconnecting", .{@errorName(err)});
main.exitToMenu();
return;
};

physics.calculateVolumeProperties(.client, &Player.volumeProperties, Player.super.pos, Player.outerBoundingBox, physics.playerAirTerminalVelocity);
if (Player.isFlying.load(.monotonic)) {
Expand Down
6 changes: 3 additions & 3 deletions src/network/protocols.zig
Original file line number Diff line number Diff line change
Expand Up @@ -959,11 +959,11 @@ pub const inventory = struct { // MARK: inventory
fn clientReceive(_: *Connection, reader: *utils.BinaryReader) !void {
const typ = try reader.readInt(u8);
if (typ == 0xff) { // Confirmation
try main.sync.client.receiveConfirmation(reader);
main.sync.client.receiveSyncOperation(.init(.confirmation, reader.remaining));
} else if (typ == 0xfe) { // Failure
main.sync.client.receiveFailure();
main.sync.client.receiveSyncOperation(.init(.failure, &.{}));
} else {
try main.sync.client.receiveSyncOperation(reader);
main.sync.client.receiveSyncOperation(.init(.sync, reader.remaining));
}
}
fn serverReceive(conn: *Connection, reader: *utils.BinaryReader) !void {
Expand Down
86 changes: 55 additions & 31 deletions src/sync.zig
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,22 @@ pub const Side = enum { client, server };
pub const client = struct { // MARK: client
pub var mutex: main.utils.Mutex = .{};
var commands: utils.CircularBufferQueue(Command) = undefined;
var syncCommands: main.ListManaged(ClientSyncOperation) = .init(main.globalAllocator);
const ClientSyncOperation = struct {
const Type = enum { confirmation, failure, sync };
typ: Type,
data: []const u8,

pub fn init(typ: Type, data: []const u8) ClientSyncOperation {
return .{
.typ = typ,
.data = main.globalAllocator.dupe(u8, data),
};
}
fn deinit(self: ClientSyncOperation) void {
main.globalAllocator.free(self.data);
}
};

pub fn init() void {
commands = utils.CircularBufferQueue(Command).init(main.globalAllocator, 256);
Expand All @@ -35,6 +51,7 @@ pub const client = struct { // MARK: client
pub fn deinit() void {
reset();
commands.deinit();
syncCommands.deinit();
}

pub fn reset() void {
Expand All @@ -45,6 +62,9 @@ pub const client = struct { // MARK: client
std.log.err("Got error while cleaning remaining inventory commands: {s}", .{@errorName(err)});
};
}
while (syncCommands.popOrNull()) |sync| {
sync.deinit();
}
mutex.unlock();
}

Expand All @@ -62,52 +82,55 @@ pub const client = struct { // MARK: client
commands.pushBack(cmd);
}

pub fn receiveConfirmation(reader: *BinaryReader) !void {
pub fn receiveSyncOperation(sync: ClientSyncOperation) void {
mutex.lock();
defer mutex.unlock();
if (commands.popFront()) |cmd| {
try cmd.finalize(main.globalAllocator, .client, reader);
} else {
std.log.err("Received unexpected confirmation sync. Disconnecting", .{});
return error.Invalid;
}
syncCommands.append(sync);
}

pub fn receiveFailure() void {
pub fn update() !void {
mutex.lock();
defer mutex.unlock();
if (syncCommands.items.len == 0) return;

var tempData: main.List(Command) = .empty;
defer tempData.deinit(main.stackAllocator);
while (commands.popBack()) |_cmd| {
var cmd = _cmd;
cmd.undo();
tempData.append(main.stackAllocator, cmd);
}
if (tempData.popOrNull()) |_cmd| {
var cmd = _cmd;
var reader = BinaryReader.init(&.{});
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;
cmd.do(main.globalAllocator, .client, null, main.game.Player.gamemode.raw) catch unreachable;
commands.pushBack(cmd);
}
}

pub fn receiveSyncOperation(reader: *BinaryReader) !void {
mutex.lock();
defer mutex.unlock();
var tempData: main.List(Command) = .empty;
defer tempData.deinit(main.stackAllocator);
while (commands.popBack()) |_cmd| {
var cmd = _cmd;
cmd.undo();
tempData.append(main.stackAllocator, cmd);
for (syncCommands.items) |sync| {
defer sync.deinit();
var reader = BinaryReader.init(sync.data);

switch (sync.typ) {
.confirmation => {
if (tempData.popOrNull()) |_cmd| {
var cmd = _cmd;
cmd.do(main.globalAllocator, .client, null, main.game.Player.gamemode.raw) catch unreachable;
try cmd.finalize(main.globalAllocator, .client, &reader);
} else {
std.log.err("Received unexpected confirmation sync. Disconnecting", .{});
return error.Invalid;
}
},
.failure => {
if (tempData.popOrNull()) |cmd| {
try cmd.finalize(main.globalAllocator, .client, &reader);
} else {
std.log.err("Received unexpected failure sync. Disconnecting", .{});
return error.Invalid;
}
},
.sync => {
try Command.SyncOperation.executeFromData(&reader);
},
}
}
try Command.SyncOperation.executeFromData(reader);
syncCommands.clearRetainingCapacity();

while (tempData.popOrNull()) |_cmd| {
var cmd = _cmd;
cmd.do(main.globalAllocator, .client, null, main.game.Player.gamemode.raw) catch unreachable;
Expand Down Expand Up @@ -621,6 +644,7 @@ pub const Command = struct { // MARK: Command
info.dest.inv.update();
},
.moveToBag => |info| {
if (info.amount == 0) continue;
const item = info.dest.peek(0).item;
std.debug.assert(std.meta.eql(info.source.ref().item, item) or info.source.ref().item == .null);

Expand Down
Loading