diff --git a/assets/cubyz/blocks/basalt/_defaults.zig.zon b/assets/cubyz/blocks/basalt/_defaults.zig.zon index a00d0417db..b99d8271ca 100644 --- a/assets/cubyz/blocks/basalt/_defaults.zig.zon +++ b/assets/cubyz/blocks/basalt/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.stone, .mineable, .basalt}, + .tags = .{.mineable, .stone, .basalt}, .blockHealth = 30, .blockResistance = 1, .drops = .{ diff --git a/assets/cubyz/blocks/chalk/_defaults.zig.zon b/assets/cubyz/blocks/chalk/_defaults.zig.zon index f6465e573a..f3200610a8 100644 --- a/assets/cubyz/blocks/chalk/_defaults.zig.zon +++ b/assets/cubyz/blocks/chalk/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.stone, .mineable}, + .tags = .{.mineable, .stone, .chalk}, .blockHealth = 12, .drops = .{ .{.items = .{.auto}}, diff --git a/assets/cubyz/blocks/ferrock/_defaults.zig.zon b/assets/cubyz/blocks/ferrock/_defaults.zig.zon index 854d6bd802..e9050de7bf 100644 --- a/assets/cubyz/blocks/ferrock/_defaults.zig.zon +++ b/assets/cubyz/blocks/ferrock/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.stone, .mineable, .ferrock}, + .tags = .{.mineable, .stone, .ferrock}, .blockHealth = 32.5, .blockResistance = 1, .drops = .{ diff --git a/assets/cubyz/blocks/glacite/_defaults.zig.zon b/assets/cubyz/blocks/glacite/_defaults.zig.zon index 33c406bff3..d750edf0c4 100644 --- a/assets/cubyz/blocks/glacite/_defaults.zig.zon +++ b/assets/cubyz/blocks/glacite/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.stone, .mineable, .glacite}, + .tags = .{.mineable, .stone, .glacite}, .blockHealth = 25, .blockResistance = 1, .drops = .{ diff --git a/assets/cubyz/blocks/glass/_defaults.zig.zon b/assets/cubyz/blocks/glass/_defaults.zig.zon index 8658e98332..5172fb6058 100644 --- a/assets/cubyz/blocks/glass/_defaults.zig.zon +++ b/assets/cubyz/blocks/glass/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.mineable}, + .tags = .{.mineable, .glass}, .blockHealth = 2.5, .drops = .{ .{.items = .{.auto}}, diff --git a/assets/cubyz/blocks/glow_crystal/_defaults.zig.zon b/assets/cubyz/blocks/glow_crystal/_defaults.zig.zon index be18503c28..8ee007b54d 100644 --- a/assets/cubyz/blocks/glow_crystal/_defaults.zig.zon +++ b/assets/cubyz/blocks/glow_crystal/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.mineable}, + .tags = .{.mineable, .glow_crystal}, .blockHealth = 5, .drops = .{ .{.items = .{.auto}}, diff --git a/assets/cubyz/blocks/limestone/_defaults.zig.zon b/assets/cubyz/blocks/limestone/_defaults.zig.zon index 95f5cf7cb7..a39201f542 100644 --- a/assets/cubyz/blocks/limestone/_defaults.zig.zon +++ b/assets/cubyz/blocks/limestone/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.stone, .mineable, .limestone}, + .tags = .{.limestone, .stone, .mineable}, .blockHealth = 27.5, .blockResistance = 1, .drops = .{ diff --git a/assets/cubyz/blocks/marble/_defaults.zig.zon b/assets/cubyz/blocks/marble/_defaults.zig.zon index 8429253d55..f3526d4229 100644 --- a/assets/cubyz/blocks/marble/_defaults.zig.zon +++ b/assets/cubyz/blocks/marble/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.stone, .mineable, .marble}, + .tags = .{.mineable, .stone, .marble}, .blockHealth = 28, .drops = .{ .{.items = .{.auto}}, diff --git a/assets/cubyz/blocks/pyrolite/_defaults.zig.zon b/assets/cubyz/blocks/pyrolite/_defaults.zig.zon index ad667e7363..d9cdc264a9 100644 --- a/assets/cubyz/blocks/pyrolite/_defaults.zig.zon +++ b/assets/cubyz/blocks/pyrolite/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.mineable, .pyrolite}, + .tags = .{.mineable, .stone, .pyrolite}, .blockHealth = 40, .blockResistance = 25, .drops = .{ diff --git a/assets/cubyz/blocks/sandstone/_defaults.zig.zon b/assets/cubyz/blocks/sandstone/_defaults.zig.zon index afb82ce52b..03ae0c9d29 100644 --- a/assets/cubyz/blocks/sandstone/_defaults.zig.zon +++ b/assets/cubyz/blocks/sandstone/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.stone, .mineable, .sandstone}, + .tags = .{.mineable, .stone, .sandstone}, .blockHealth = 20, .drops = .{ .{.items = .{.auto}}, diff --git a/assets/cubyz/blocks/slate/_defaults.zig.zon b/assets/cubyz/blocks/slate/_defaults.zig.zon index b1952ed7c6..37d0dc24d1 100644 --- a/assets/cubyz/blocks/slate/_defaults.zig.zon +++ b/assets/cubyz/blocks/slate/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.stone, .mineable, .slate}, + .tags = .{.mineable, .stone, .slate}, .blockHealth = 30, .blockResistance = 1, .drops = .{ diff --git a/assets/cubyz/blocks/terracotta/_defaults.zig.zon b/assets/cubyz/blocks/terracotta/_defaults.zig.zon index a761dedf99..5593e60c8b 100644 --- a/assets/cubyz/blocks/terracotta/_defaults.zig.zon +++ b/assets/cubyz/blocks/terracotta/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.mineable}, + .tags = .{.mineable, .terracotta}, .blockHealth = 20, .blockResistance = 1, .drops = .{ diff --git a/assets/cubyz/blocks/voidstone/_defaults.zig.zon b/assets/cubyz/blocks/voidstone/_defaults.zig.zon index d217646ba0..d109becfe0 100644 --- a/assets/cubyz/blocks/voidstone/_defaults.zig.zon +++ b/assets/cubyz/blocks/voidstone/_defaults.zig.zon @@ -1,5 +1,5 @@ .{ - .tags = .{.stone, .mineable, .voidStone}, + .tags = .{.voidstone, .stone, .mineable}, .blockHealth = 60, .blockResistance = 5, .drops = .{ diff --git a/src/gui/windows/inventory.zig b/src/gui/windows/inventory.zig index 44ff54009f..33998de05b 100644 --- a/src/gui/windows/inventory.zig +++ b/src/gui/windows/inventory.zig @@ -41,12 +41,19 @@ pub fn deinit() void { var itemSlots: [20]*ItemSlot = undefined; +pub fn sortItems(target: main.items.Inventory.ClientInventory) void { + const convertedInv: main.items.Inventory.InventoryAndSlot = .{.inv = target.super, .slot = 0}; + main.sync.client.executeCommand(.{.sortItems = .{.target = convertedInv}}); +} + pub fn onOpen() void { const list = VerticalList.init(.{padding, padding + 16}, 300, 0); // Some miscellanious slots and buttons: // TODO: armor slots, backpack slot + stack-based backpack inventory, other items maybe? { const row = HorizontalList.init(); + const sortCallback: main.callbacks.SimpleCallback = .{.inner = @ptrCast(&sortItems), .data = &Player.inventory}; + row.add(Button.initIcon(.{32, 0}, .{32, 32}, craftingIcon, true, sortCallback)); blk: { row.add(GuiComponent.BagSlot.init(.{0, 0}, main.entity.components.@"cubyz:bag".client.getBag(main.game.Player.id) orelse break :blk)); } diff --git a/src/sync.zig b/src/sync.zig index 3dbcc26d27..49cc02fd9e 100644 --- a/src/sync.zig +++ b/src/sync.zig @@ -237,6 +237,7 @@ pub const Command = struct { // MARK: Command takeFromPlayerBag = 17, craftFrom = 13, craftProceduralItem = 15, + sortItems = 18, clear = 8, updateBlock = 9, addHealth = 10, @@ -257,6 +258,7 @@ pub const Command = struct { // MARK: Command takeFromPlayerBag: TakeFromPlayerBag, craftFrom: CraftFrom, craftProceduralItem: CraftProceduralItem, + sortItems: SortItems, clear: Clear, updateBlock: UpdateBlock, addHealth: AddHealth, @@ -1771,6 +1773,159 @@ pub const Command = struct { // MARK: Command }; } }; + + const SortItems = struct { // MARK: SortItems + target: InventoryAndSlot, + + fn compressItems(self: SortItems, ctx: Context) void { + for (self.target.inv._items, 0..) |invStack, slot| { + if (invStack.item != .null) { + for (self.target.inv._items, 0..) |checkedInvStack, checkedSlot| { + if (checkedInvStack.item != .null) { + if (std.meta.eql(invStack.item, checkedInvStack.item)) { + if (self.target.ref().amount >= invStack.item.stackSize()) continue; + if (slot <= checkedSlot) continue; + const amount = @min(checkedInvStack.item.stackSize() - checkedInvStack.amount, invStack.amount); + const dest: InventoryAndSlot = .{.inv = self.target.inv, .slot = @intCast(checkedSlot)}; + const source: InventoryAndSlot = .{.inv = self.target.inv, .slot = @intCast(slot)}; + std.log.debug("Moving objects", .{}); + std.log.debug("{}", .{invStack.item.stackSize() - invStack.amount}); + ctx.execute(.{.move = .{ + .dest = dest, + .source = source, + .amount = amount, + }}); + } + } + } + } + } + } + + fn sortProceduralItems(self: SortItems, ctx: Context) void { + for (self.target.inv._items, 0..) |invStack, slot| { + if (invStack.item == .proceduralItem) { + var dest: InventoryAndSlot = .{.inv = self.target.inv, .slot = 0}; + var source: InventoryAndSlot = .{.inv = self.target.inv, .slot = 0}; + for (self.target.inv._items, 0..) |checkedInvStack, checkedSlot| { + if (checkedInvStack.item != .proceduralItem) { + dest.slot = @intCast(checkedSlot); + source.slot = @intCast(slot); + break; + } + } + ctx.execute(.{.swap = .{ + .dest = dest, + .source = source, + }}); + } + } + for (self.target.inv._items, 0..) |invStack, slot| { + if (invStack.item != .proceduralItem) break; + var dest: InventoryAndSlot = .{.inv = self.target.inv, .slot = 0}; + var source: InventoryAndSlot = .{.inv = self.target.inv, .slot = 0}; + var foundSimilarTag = false; + if (invStack.item.proceduralItem.type.tags().len == 0) continue; + for (self.target.inv._items, 0..) |checkedInvStack, checkedSlot| { + if ((foundSimilarTag)) { + if (checkedInvStack.item == .proceduralItem) { + if (checkedInvStack.item.proceduralItem.hasTag(invStack.item.proceduralItem.type.tags()[0])) continue; + } else { + continue; + } + dest.slot = @intCast(checkedSlot); + source.slot = @intCast(slot); + break; + } + if (checkedInvStack.item == .proceduralItem) { + if (checkedInvStack.item.proceduralItem.type.tags().len == 0) continue; + std.log.debug("{}", .{(invStack.item.proceduralItem.type.tags()[0])}); + if (checkedInvStack.item.proceduralItem.hasTag(invStack.item.proceduralItem.type.tags()[0])) foundSimilarTag = true; + } + } + ctx.execute(.{.swap = .{ + .dest = dest, + .source = source, + }}); + } + } + + fn sortBaseItems(self: SortItems, ctx: Context) void { + for (self.target.inv._items, 0..) |invStack, slot| { + if (invStack.item == .baseItem) { + var dest: InventoryAndSlot = .{.inv = self.target.inv, .slot = 0}; + var source: InventoryAndSlot = .{.inv = self.target.inv, .slot = 0}; + for (self.target.inv._items, 0..) |checkedInvStack, checkedSlot| { + if (checkedInvStack.item == .proceduralItem) continue; + if (checkedInvStack.item != .baseItem) { + dest.slot = @intCast(checkedSlot); + source.slot = @intCast(slot); + break; + } + } + ctx.execute(.{.swap = .{ + .dest = dest, + .source = source, + }}); + } + } + for (self.target.inv._items, 0..) |invStack, slot| { + if (invStack.item == .proceduralItem) continue; + if (invStack.item != .baseItem) break; + std.log.debug("trying sort", .{}); + var dest: InventoryAndSlot = .{.inv = self.target.inv, .slot = 0}; + var source: InventoryAndSlot = .{.inv = self.target.inv, .slot = 0}; + var foundSimilarTag = false; + std.log.debug("trying sort 2 {}", .{invStack.item}); + std.log.debug("trying sort 2 {}", .{invStack.item.baseItem.tags()}); + if (invStack.item.baseItem.tags().len == 0) continue; + std.log.debug("trying sort 3", .{}); + for (self.target.inv._items, 0..) |checkedInvStack, checkedSlot| { + if ((foundSimilarTag)) { + if (checkedInvStack.item == .baseItem) { + if (checkedInvStack.item.baseItem.hasTag(invStack.item.baseItem.tags()[0])) continue; + } else { + continue; + } + std.log.debug("found a proper swap for the items", .{}); + dest.slot = @intCast(checkedSlot); + source.slot = @intCast(slot); + break; + } + if (checkedInvStack.item == .baseItem) { + if (checkedInvStack.item.baseItem.tags().len == 0) continue; + std.log.debug("{}", .{(invStack.item.baseItem.tags()[0])}); + if (checkedInvStack.item.baseItem.hasTag(invStack.item.baseItem.tags()[0])) foundSimilarTag = true; + } + } + std.log.debug("swapping {} {}", .{source.slot, dest.slot}); + ctx.execute(.{.swap = .{ + .dest = dest, + .source = source, + }}); + } + } + + fn run(self: SortItems, ctx: Context) error{serverFailure}!void { + std.log.debug("Running Sort", .{}); + // first compresses items before sorting + // we sort out procedural tools second then generally try to put items with similar tags together + // then we sort normal items + compressItems(self, ctx); + sortProceduralItems(self, ctx); + sortBaseItems(self, ctx); + } + + fn serialize(self: SortItems, writer: *BinaryWriter) void { + self.target.write(writer); + } + + fn deserialize(reader: *BinaryReader, side: Side, user: ?*main.server.User) !SortItems { + return .{ + .target = try InventoryAndSlot.read(reader, side, user), + }; + } + }; }; pub threadlocal var threadContext: ThreadContext = .other;