From 25a8e2959aa9ecdd67353da4957f8fabfbcf092d Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 17 Nov 2024 13:40:28 +0100 Subject: [PATCH] Add /clear to clear the inventory. fixes #781 --- src/Inventory.zig | 100 +++++++++++++++++++++++++---------- src/server/command/_list.zig | 1 + src/server/command/clear.zig | 15 ++++++ 3 files changed, 89 insertions(+), 27 deletions(-) create mode 100644 src/server/command/clear.zig diff --git a/src/Inventory.zig b/src/Inventory.zig index 951f91d9..ff429843 100644 --- a/src/Inventory.zig +++ b/src/Inventory.zig @@ -202,21 +202,16 @@ pub const Sync = struct { // MARK: Sync freeIdList.append(id); } - pub fn receiveCommand(source: *main.server.User, data: []const u8) !void { - mutex.lock(); - defer mutex.unlock(); - const typ: Command.PayloadType = @enumFromInt(data[0]); - @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)), - }; + fn executeCommand(payload: Command.Payload, source: ?*main.server.User) void { var command = Command { .payload = payload, }; command.do(main.globalAllocator, .server, source); - const confirmationData = command.confirmationData(main.stackAllocator); - defer main.stackAllocator.free(confirmationData); - main.network.Protocols.inventory.sendConfirmation(source.conn, confirmationData); + if(source != null) { + const confirmationData = command.confirmationData(main.stackAllocator); + defer main.stackAllocator.free(confirmationData); + main.network.Protocols.inventory.sendConfirmation(source.?.conn, confirmationData); + } for(command.syncOperations.items) |op| { const syncData = op.serialize(main.stackAllocator); defer main.stackAllocator.free(syncData); @@ -225,7 +220,7 @@ pub const Sync = struct { // MARK: Sync main.network.Protocols.inventory.sendSyncOperation(otherUser.conn, syncData); } } - if(command.payload == .open) { // Send initial items + if(source != null and command.payload == .open) { // Send initial items for(command.payload.open.inv._items, 0..) |stack, slot| { if(stack.item != null) { const syncOp = Command.SyncOperation { @@ -235,13 +230,24 @@ pub const Sync = struct { // MARK: Sync }; const syncData = syncOp.serialize(main.stackAllocator); defer main.stackAllocator.free(syncData); - main.network.Protocols.inventory.sendSyncOperation(source.conn, syncData); + main.network.Protocols.inventory.sendSyncOperation(source.?.conn, syncData); } } } command.finalize(main.globalAllocator, .server, &.{}); } + pub fn receiveCommand(source: *main.server.User, data: []const u8) !void { + mutex.lock(); + defer mutex.unlock(); + const typ: Command.PayloadType = @enumFromInt(data[0]); + @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)), + }; + executeCommand(payload, source); + } + fn createInventory(user: *main.server.User, clientId: u32, len: usize, typ: Inventory.Type, source: Source) void { main.utils.assertLocked(&mutex); switch(source) { @@ -272,11 +278,18 @@ pub const Sync = struct { // MARK: Sync const serverId = user.inventoryClientToServerIdMap.get(clientId) orelse return null; return inventories.items[serverId].inv; } - }; - pub fn executeCommand(payload: Command.Payload) void { - ClientSide.executeCommand(payload); - } + pub fn clearPlayerInventory(user: *main.server.User) void { + mutex.lock(); + defer mutex.unlock(); + var inventoryIdIterator = user.inventoryClientToServerIdMap.valueIterator(); + while(inventoryIdIterator.next()) |inventoryId| { + if(inventories.items[inventoryId.*].source == .playerInventory) { + executeCommand(.{.clear = .{.inv = inventories.items[inventoryId.*].inv}}, null); + } + } + } + }; pub fn getInventory(id: u32, side: Side, user: ?*main.server.User) ?Inventory { return switch(side) { @@ -296,6 +309,7 @@ pub const Command = struct { // MARK: Command drop = 5, fillFromCreative = 6, depositOrDrop = 7, + clear = 8, }; pub const Payload = union(PayloadType) { open: Open, @@ -306,6 +320,7 @@ pub const Command = struct { // MARK: Command drop: Drop, fillFromCreative: FillFromCreative, depositOrDrop: DepositOrDrop, + clear: Clear, }; const BaseOperationType = enum(u8) { @@ -1081,6 +1096,37 @@ pub const Command = struct { // MARK: Command }; } }; + + const Clear = struct { + inv: Inventory, + + pub fn run(self: Clear, allocator: NeverFailingAllocator, cmd: *Command, side: Side, _: ?*main.server.User) void { + if(self.inv.type == .creative) return; + if(self.inv.type == .crafting) return; + var items = self.inv._items; + if(self.inv.type == .workbench) items = self.inv._items[0..25]; + for(items, 0..) |stack, slot| { + if(stack.item == null) continue; + + cmd.executeBaseOperation(allocator, .{.delete = .{ + .source = .{.inv = self.inv, .slot = @intCast(slot)}, + .amount = stack.amount, + }}, side); + } + } + + fn serialize(self: Clear, data: *main.List(u8)) void { + std.mem.writeInt(u32, data.addMany(4)[0..4], self.inv.id, .big); + } + + 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); + return .{ + .inv = Sync.getInventory(invId, side, user) orelse return error.Invalid, + }; + } + }; }; const SourceType = enum(u8) { @@ -1110,7 +1156,7 @@ _items: []ItemStack, pub fn init(allocator: NeverFailingAllocator, _size: usize, _type: Type, source: Source) Inventory { const self = _init(allocator, _size, _type, .client); - Sync.executeCommand(.{.open = .{.inv = self, .source = source}}); + Sync.ClientSide.executeCommand(.{.open = .{.inv = self, .source = source}}); return self; } @@ -1131,7 +1177,7 @@ fn _init(allocator: NeverFailingAllocator, _size: usize, _type: Type, side: Side } pub fn deinit(self: Inventory, allocator: NeverFailingAllocator) void { - Sync.executeCommand(.{.close = .{.inv = self, .allocator = allocator}}); + Sync.ClientSide.executeCommand(.{.close = .{.inv = self, .allocator = allocator}}); } fn _deinit(self: Inventory, allocator: NeverFailingAllocator, side: Side) void { @@ -1167,15 +1213,15 @@ fn update(self: Inventory) void { } pub fn depositOrSwap(dest: Inventory, destSlot: u32, carried: Inventory) void { - Sync.executeCommand(.{.depositOrSwap = .{.dest = .{.inv = dest, .slot = destSlot}, .source = .{.inv = carried, .slot = 0}}}); + Sync.ClientSide.executeCommand(.{.depositOrSwap = .{.dest = .{.inv = dest, .slot = destSlot}, .source = .{.inv = carried, .slot = 0}}}); } pub fn deposit(dest: Inventory, destSlot: u32, carried: Inventory, amount: u16) void { - Sync.executeCommand(.{.deposit = .{.dest = .{.inv = dest, .slot = destSlot}, .source = .{.inv = carried, .slot = 0}, .amount = amount}}); + Sync.ClientSide.executeCommand(.{.deposit = .{.dest = .{.inv = dest, .slot = destSlot}, .source = .{.inv = carried, .slot = 0}, .amount = amount}}); } pub fn takeHalf(source: Inventory, sourceSlot: u32, carried: Inventory) void { - Sync.executeCommand(.{.takeHalf = .{.dest = .{.inv = carried, .slot = 0}, .source = .{.inv = source, .slot = sourceSlot}}}); + Sync.ClientSide.executeCommand(.{.takeHalf = .{.dest = .{.inv = carried, .slot = 0}, .source = .{.inv = source, .slot = sourceSlot}}}); } pub fn distribute(carried: Inventory, destinationInventories: []const Inventory, destinationSlots: []const u32) void { @@ -1187,23 +1233,23 @@ pub fn distribute(carried: Inventory, destinationInventories: []const Inventory, } pub fn depositOrDrop(dest: Inventory, source: Inventory) void { - Sync.executeCommand(.{.depositOrDrop = .{.dest = dest, .source = source}}); + Sync.ClientSide.executeCommand(.{.depositOrDrop = .{.dest = dest, .source = source}}); } pub fn dropStack(source: Inventory, sourceSlot: u32) void { - Sync.executeCommand(.{.drop = .{.source = .{.inv = source, .slot = sourceSlot}}}); + Sync.ClientSide.executeCommand(.{.drop = .{.source = .{.inv = source, .slot = sourceSlot}}}); } pub fn dropOne(source: Inventory, sourceSlot: u32) void { - Sync.executeCommand(.{.drop = .{.source = .{.inv = source, .slot = sourceSlot}, .desiredAmount = 1}}); + Sync.ClientSide.executeCommand(.{.drop = .{.source = .{.inv = source, .slot = sourceSlot}, .desiredAmount = 1}}); } pub fn fillFromCreative(dest: Inventory, destSlot: u32, item: ?Item) void { - Sync.executeCommand(.{.fillFromCreative = .{.dest = .{.inv = dest, .slot = destSlot}, .item = item}}); + Sync.ClientSide.executeCommand(.{.fillFromCreative = .{.dest = .{.inv = dest, .slot = destSlot}, .item = item}}); } pub fn fillAmountFromCreative(dest: Inventory, destSlot: u32, item: ?Item, amount: u16) void { - Sync.executeCommand(.{.fillFromCreative = .{.dest = .{.inv = dest, .slot = destSlot}, .item = item, .amount = amount}}); + Sync.ClientSide.executeCommand(.{.fillFromCreative = .{.dest = .{.inv = dest, .slot = destSlot}, .item = item, .amount = amount}}); } pub fn placeBlock(self: Inventory, slot: u32, unlimitedBlocks: bool) void { diff --git a/src/server/command/_list.zig b/src/server/command/_list.zig index eb240428..2e6a3196 100644 --- a/src/server/command/_list.zig +++ b/src/server/command/_list.zig @@ -1,5 +1,6 @@ +pub const clear = @import("clear.zig"); pub const help = @import("help.zig"); pub const invite = @import("invite.zig"); pub const time = @import("time.zig"); diff --git a/src/server/command/clear.zig b/src/server/command/clear.zig new file mode 100644 index 00000000..7fe442b1 --- /dev/null +++ b/src/server/command/clear.zig @@ -0,0 +1,15 @@ +const std = @import("std"); + +const main = @import("root"); +const User = main.server.User; + +pub const description = "Clears your inventory"; +pub const usage = "/clear"; + +pub fn execute(args: []const u8, source: *User) void { + if(args.len != 0) { + source.sendMessage("#ff0000Too many arguments for command /clear. Expected no arguments."); + return; + } + main.items.Inventory.Sync.ServerSide.clearPlayerInventory(source); +}