Merge All ItemSlot types into one struct.

Fixes #240
This commit is contained in:
IntegratedQuantum 2024-01-26 00:14:51 +01:00
parent 3c6147dc6a
commit 178489b044
12 changed files with 108 additions and 287 deletions

View File

@ -1,111 +0,0 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const main = @import("root");
const ItemStack = main.items.ItemStack;
const graphics = main.graphics;
const draw = graphics.draw;
const Texture = graphics.Texture;
const TextBuffer = graphics.TextBuffer;
const vec = main.vec;
const Vec2f = vec.Vec2f;
const gui = @import("../gui.zig");
const GuiComponent = gui.GuiComponent;
const CraftingResultSlot = @This();
var texture: Texture = undefined;
const border: f32 = 3;
pos: Vec2f,
size: Vec2f = .{24 + 2*border, 24 + 2*border},
itemStack: ItemStack,
text: TextBuffer,
textSize: Vec2f = .{0, 0},
onTake: gui.Callback,
hovered: bool = false,
pressed: bool = false,
pub fn __init() !void {
texture = try Texture.initFromFile("assets/cubyz/ui/inventory/crafting_result_slot.png");
}
pub fn __deinit() void {
texture.deinit();
}
pub fn init(pos: Vec2f, itemStack: ItemStack, onTake: gui.Callback) Allocator.Error!*CraftingResultSlot {
const self = try main.globalAllocator.create(CraftingResultSlot);
var buf: [16]u8 = undefined;
self.* = CraftingResultSlot {
.itemStack = itemStack,
.pos = pos,
.text = try TextBuffer.init(main.globalAllocator, std.fmt.bufPrint(&buf, "{}", .{self.itemStack.amount}) catch "", .{}, false, .right),
.onTake = onTake,
};
self.textSize = try self.text.calculateLineBreaks(8, self.size[0] - 2*border);
return self;
}
pub fn deinit(self: *const CraftingResultSlot) void {
self.text.deinit();
main.globalAllocator.destroy(self);
}
pub fn toComponent(self: *CraftingResultSlot) GuiComponent {
return GuiComponent{
.craftingResultSlot = self
};
}
pub fn updateHovered(self: *CraftingResultSlot, _: Vec2f) void {
self.hovered = true;
gui.hoveredCraftingSlot = self;
}
pub fn mainButtonPressed(self: *CraftingResultSlot, _: Vec2f) void {
self.pressed = true;
}
pub fn mainButtonReleased(self: *CraftingResultSlot, mousePosition: Vec2f) void {
if(self.pressed) {
self.pressed = false;
if(GuiComponent.contains(self.pos, self.size, mousePosition)) {
if(self.itemStack.item == null) return;
if(gui.inventory.carriedItemStack.item == null or std.meta.eql(self.itemStack.item, gui.inventory.carriedItemStack.item)) {
if(std.math.add(u16, gui.inventory.carriedItemStack.amount, self.itemStack.amount) catch null) |nextAmount| if(nextAmount <= self.itemStack.item.?.stackSize()) {
const itemStack = self.itemStack;
self.onTake.run();
gui.inventory.carriedItemStack.item = itemStack.item;
gui.inventory.carriedItemStack.amount += itemStack.amount;
};
}
}
}
}
pub fn render(self: *CraftingResultSlot, _: Vec2f) !void {
draw.setColor(0xffffffff);
texture.bindTo(0);
draw.boundImage(self.pos, self.size);
if(self.itemStack.item) |item| {
const itemTexture = try item.getTexture();
itemTexture.bindTo(0);
draw.setColor(0xff000000);
draw.boundImage(self.pos + @as(Vec2f, @splat(border)) + Vec2f{1.0, 1.0}, self.size - @as(Vec2f, @splat(2*border)));
draw.setColor(0xffffffff);
draw.boundImage(self.pos + @as(Vec2f, @splat(border)), self.size - @as(Vec2f, @splat(2*border)));
if(self.itemStack.amount != 1) {
try self.text.render(self.pos[0] + self.size[0] - self.textSize[0] - border, self.pos[1] + self.size[1] - self.textSize[1] - border, 8);
}
}
if(self.pressed) {
draw.setColor(0x80808080);
draw.rect(self.pos, self.size);
} else if(self.hovered) {
self.hovered = false;
draw.setColor(0x300000ff);
draw.rect(self.pos, self.size);
}
}

View File

@ -1,73 +0,0 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const main = @import("root");
const BaseItem = main.items.BaseItem;
const graphics = main.graphics;
const draw = graphics.draw;
const Texture = graphics.Texture;
const TextBuffer = graphics.TextBuffer;
const vec = main.vec;
const Vec2f = vec.Vec2f;
const gui = @import("../gui.zig");
const GuiComponent = gui.GuiComponent;
const ImmutableItemSlot = @This();
var texture: Texture = undefined;
const border: f32 = 3;
pos: Vec2f,
size: Vec2f = .{24 + 2*border, 24 + 2*border},
item: *BaseItem,
amount: u32,
text: TextBuffer,
textSize: Vec2f = .{0, 0},
pub fn __init() !void {
texture = try Texture.initFromFile("assets/cubyz/ui/inventory/immutable_slot.png");
}
pub fn __deinit() void {
texture.deinit();
}
pub fn init(pos: Vec2f, item: *BaseItem, amount: u32) Allocator.Error!*ImmutableItemSlot {
const self = try main.globalAllocator.create(ImmutableItemSlot);
var buf: [16]u8 = undefined;
self.* = ImmutableItemSlot {
.item = item,
.amount = amount,
.pos = pos,
.text = try TextBuffer.init(main.globalAllocator, std.fmt.bufPrint(&buf, "{}", .{amount}) catch "", .{}, false, .right),
};
self.textSize = try self.text.calculateLineBreaks(8, self.size[0] - 2*border);
return self;
}
pub fn deinit(self: *const ImmutableItemSlot) void {
self.text.deinit();
main.globalAllocator.destroy(self);
}
pub fn toComponent(self: *ImmutableItemSlot) GuiComponent {
return GuiComponent{
.immutableItemSlot = self
};
}
pub fn render(self: *ImmutableItemSlot, _: Vec2f) !void {
draw.setColor(0xffffffff);
texture.bindTo(0);
draw.boundImage(self.pos, self.size);
const itemTexture = try self.item.getTexture();
itemTexture.bindTo(0);
draw.setColor(0xff000000);
draw.boundImage(self.pos + @as(Vec2f, @splat(border)) + Vec2f{1.0, 1.0}, self.size - @as(Vec2f, @splat(2*border)));
draw.setColor(0xffffffff);
draw.boundImage(self.pos + @as(Vec2f, @splat(border)), self.size - @as(Vec2f, @splat(2*border)));
if(self.amount != 1) {
try self.text.render(self.pos[0] + self.size[0] - self.textSize[0] - border, self.pos[1] + self.size[1] - self.textSize[1] - border, 8);
}
}

View File

@ -16,13 +16,22 @@ const GuiComponent = gui.GuiComponent;
const ItemSlot = @This();
var texture: Texture = undefined;
const border: f32 = 2;
pub const VTable = struct {
tryAddingItems: *const fn(usize, *ItemStack, u16) void,
tryTakingItems: *const fn(usize, *ItemStack, u16) void,
trySwappingItems: *const fn(usize, *ItemStack) void,
tryAddingItems: *const fn(usize, *ItemStack, u16) void = &defaultAddingItems,
tryTakingItems: *const fn(usize, *ItemStack, u16) void = &defaultTakingItems,
trySwappingItems: *const fn(usize, *ItemStack) void = &defaultSwappingItems,
fn defaultAddingItems(_: usize, _: *ItemStack, _: u16) void {}
fn defaultTakingItems(_: usize, _: *ItemStack, _: u16) void {}
fn defaultSwappingItems(_: usize, _: *ItemStack) void {}
};
const Mode = enum {
normal,
takeOnly,
immutable,
};
pos: Vec2f,
@ -35,16 +44,40 @@ pressed: bool = false,
renderFrame: bool = true,
userData: usize,
vtable: *const VTable,
texture: Texture,
mode: Mode,
var defaultTexture: Texture = undefined;
var immutableTexture: Texture = undefined;
var craftingResultTexture: Texture = undefined;
const TextureParamType = union(enum) {
default: void,
immutable: void,
craftingResult: void,
custom: Texture,
fn value(self: TextureParamType) Texture {
return switch(self) {
.default => defaultTexture,
.immutable => immutableTexture,
.craftingResult => craftingResultTexture,
.custom => |t| t,
};
}
};
pub fn __init() !void {
texture = try Texture.initFromFile("assets/cubyz/ui/inventory/slot.png");
defaultTexture = try Texture.initFromFile("assets/cubyz/ui/inventory/slot.png");
immutableTexture = try Texture.initFromFile("assets/cubyz/ui/inventory/immutable_slot.png");
craftingResultTexture = try Texture.initFromFile("assets/cubyz/ui/inventory/crafting_result_slot.png");
}
pub fn __deinit() void {
texture.deinit();
defaultTexture.deinit();
immutableTexture.deinit();
craftingResultTexture.deinit();
}
pub fn init(pos: Vec2f, itemStack: ItemStack, vtable: *const VTable, userData: usize) Allocator.Error!*ItemSlot {
pub fn init(pos: Vec2f, itemStack: ItemStack, vtable: *const VTable, userData: usize, texture: TextureParamType, mode: Mode) Allocator.Error!*ItemSlot {
const self = try main.globalAllocator.create(ItemSlot);
var buf: [16]u8 = undefined;
self.* = ItemSlot {
@ -53,6 +86,8 @@ pub fn init(pos: Vec2f, itemStack: ItemStack, vtable: *const VTable, userData: u
.userData = userData,
.pos = pos,
.text = try TextBuffer.init(main.globalAllocator, std.fmt.bufPrint(&buf, "{}", .{self.itemStack.amount}) catch "", .{}, false, .right),
.texture = texture.value(),
.mode = mode,
};
self.textSize = try self.text.calculateLineBreaks(8, self.size[0] - 2*border);
return self;
@ -63,14 +98,14 @@ pub fn deinit(self: *const ItemSlot) void {
main.globalAllocator.destroy(self);
}
pub fn tryAddingItems(self: *ItemSlot, source: *ItemStack, amount: u16) void {
pub fn tryAddingItems(self: *ItemSlot, source: *ItemStack, desiredAmount: u16) void {
std.debug.assert(source.item != null);
std.debug.assert(amount <= source.amount);
self.vtable.tryAddingItems(self.userData, source, amount);
std.debug.assert(desiredAmount <= source.amount);
self.vtable.tryAddingItems(self.userData, source, desiredAmount);
}
pub fn tryTakingItems(self: *ItemSlot, destination: *ItemStack, amount: u16) void {
self.vtable.tryTakingItems(self.userData, destination, amount);
pub fn tryTakingItems(self: *ItemSlot, destination: *ItemStack, desiredAmount: u16) void {
self.vtable.tryTakingItems(self.userData, destination, desiredAmount);
}
pub fn trySwappingItems(self: *ItemSlot, destination: *ItemStack) void {
@ -122,7 +157,7 @@ pub fn mainButtonReleased(self: *ItemSlot, _: Vec2f) void {
pub fn render(self: *ItemSlot, _: Vec2f) !void {
draw.setColor(0xffffffff);
if(self.renderFrame) {
texture.bindTo(0);
self.texture.bindTo(0);
draw.boundImage(self.pos, self.size);
}
if(self.itemStack.item) |item| {
@ -140,8 +175,10 @@ pub fn render(self: *ItemSlot, _: Vec2f) !void {
draw.setColor(0x80808080);
draw.rect(self.pos, self.size);
} else if(self.hovered) {
self.hovered = false;
draw.setColor(0x300000ff);
draw.rect(self.pos, self.size);
if(self.mode != .immutable) {
self.hovered = false;
draw.setColor(0x300000ff);
draw.rect(self.pos, self.size);
}
}
}

View File

@ -11,8 +11,6 @@ const Vec2f = vec.Vec2f;
const Button = @import("components/Button.zig");
const CheckBox = @import("components/CheckBox.zig");
const CraftingResultSlot = @import("components/CraftingResultSlot.zig");
const ImmutableItemSlot = @import("components/ImmutableItemSlot.zig");
const ItemSlot = @import("components/ItemSlot.zig");
const ScrollBar = @import("components/ScrollBar.zig");
const ContinuousSlider = @import("components/ContinuousSlider.zig");
@ -33,7 +31,6 @@ var hoveredAWindow: bool = false;
pub var scale: f32 = undefined;
pub var hoveredItemSlot: ?*ItemSlot = null;
pub var hoveredCraftingSlot: ?*CraftingResultSlot = null;
const GuiCommandQueue = struct {
const Action = enum {
@ -147,8 +144,6 @@ pub fn init() !void {
try GuiWindow.__init();
try Button.__init();
try CheckBox.__init();
try CraftingResultSlot.__init();
try ImmutableItemSlot.__init();
try ItemSlot.__init();
try ScrollBar.__init();
try ContinuousSlider.__init();
@ -171,8 +166,6 @@ pub fn deinit() void {
GuiWindow.__deinit();
Button.__deinit();
CheckBox.__deinit();
CraftingResultSlot.__deinit();
ImmutableItemSlot.__deinit();
ItemSlot.__deinit();
ScrollBar.__deinit();
ContinuousSlider.__deinit();
@ -444,12 +437,6 @@ pub fn mainButtonPressed() void {
inventory.update() catch |err| {
std.log.err("Encountered error while updating inventory: {s}", .{@errorName(err)});
};
if(inventory.carriedItemStack.amount != 0) {
if(hoveredCraftingSlot) |hovered| {
hovered.mainButtonPressed(undefined);
}
return;
}
selectedWindow = null;
selectedTextInput = null;
var selectedI: usize = 0;
@ -527,7 +514,6 @@ pub fn updateAndRenderGui() !void {
try selected.updateSelected(mousePos);
}
hoveredItemSlot = null;
hoveredCraftingSlot = null;
var i: usize = openWindows.items.len;
while(i != 0) {
i -= 1;
@ -568,7 +554,7 @@ pub const inventory = struct {
pub fn init() !void {
deliveredItemSlots = std.ArrayList(*ItemSlot).init(main.globalAllocator);
deliveredItemStacksAmountAdded = std.ArrayList(u16).init(main.globalAllocator);
carriedItemSlot = try ItemSlot.init(.{0, 0}, carriedItemStack, undefined, undefined);
carriedItemSlot = try ItemSlot.init(.{0, 0}, carriedItemStack, undefined, undefined, .default, .normal);
carriedItemSlot.renderFrame = false;
}
@ -584,6 +570,7 @@ pub const inventory = struct {
initialAmount = carriedItemStack.amount;
}
if(hoveredItemSlot) |itemSlot| {
if(itemSlot.mode != .normal) return;
if(initialAmount == 0) return;
if(!std.meta.eql(itemSlot.itemStack.item, carriedItemStack.item) and itemSlot.itemStack.item != null) return;
@ -619,7 +606,6 @@ pub const inventory = struct {
}
}
}
try carriedItemSlot.updateItemStack(carriedItemStack);
}
fn applyChanges(leftClick: bool) void {
@ -633,11 +619,15 @@ pub const inventory = struct {
} else if(hoveredItemSlot) |hovered| {
if(carriedItemStack.amount != 0) {
if(leftClick) {
hovered.trySwappingItems(&carriedItemStack);
if(std.meta.eql(carriedItemStack.item, hovered.itemStack.item)) {
hovered.tryTakingItems(&carriedItemStack, hovered.itemStack.amount);
} else {
hovered.trySwappingItems(&carriedItemStack);
}
}
} else {
if(leftClick) {
hovered.tryTakingItems(&carriedItemStack, std.math.maxInt(u16));
hovered.tryTakingItems(&carriedItemStack, hovered.itemStack.amount);
} else {
hovered.tryTakingItems(&carriedItemStack, hovered.itemStack.amount/2);
}
@ -652,12 +642,13 @@ pub const inventory = struct {
main.network.Protocols.genericUpdate.itemStackDrop(main.game.world.?.conn, .{.item = carriedItemStack.item, .amount = 1}, @floatCast(main.game.Player.getPosBlocking()), main.game.camera.direction, 20) catch |err| {
std.log.err("Error while dropping itemStack: {s}", .{@errorName(err)});
};
_ = carriedItemStack.add(@as(i32, -1));
_ = carriedItemStack.add(carriedItemStack.item.?, @as(i32, -1));
}
}
}
fn render(mousePos: Vec2f) !void {
try carriedItemSlot.updateItemStack(carriedItemStack);
carriedItemSlot.pos = mousePos - Vec2f{12, 12};
try carriedItemSlot.render(.{0, 0});
// Draw tooltip:

View File

@ -8,10 +8,8 @@ pub const GuiComponent = union(enum) {
pub const Button = @import("components/Button.zig");
pub const CheckBox = @import("components/CheckBox.zig");
pub const CraftingResultSlot = @import("components/CraftingResultSlot.zig");
pub const HorizontalList = @import("components/HorizontalList.zig");
pub const Icon = @import("components/Icon.zig");
pub const ImmutableItemSlot = @import("components/ImmutableItemSlot.zig");
pub const ItemSlot = @import("components/ItemSlot.zig");
pub const Label = @import("components/Label.zig");
pub const MutexComponent = @import("components/MutexComponent.zig");
@ -24,10 +22,8 @@ pub const GuiComponent = union(enum) {
button: *Button,
checkBox: *CheckBox,
craftingResultSlot: *CraftingResultSlot,
horizontalList: *HorizontalList,
icon: *Icon,
immutableItemSlot: *ImmutableItemSlot,
itemSlot: *ItemSlot,
label: *Label,
mutexComponent: *MutexComponent,

View File

@ -26,26 +26,12 @@ pub var window = GuiWindow {
const padding: f32 = 8;
var items: std.ArrayList(Item) = undefined;
pub fn tryAddingItems(_: usize, _: *ItemStack, _: u16) void {
return;
}
pub fn tryTakingItems(index: usize, destination: *ItemStack, amount: u16) void {
pub fn tryTakingItems(index: usize, destination: *ItemStack, _: u16) void {
if(destination.item != null and !std.meta.eql(destination.item.?, items.items[index])) return;
destination.item = items.items[index];
_ = destination.add(amount);
destination.amount = destination.item.?.stackSize();
}
pub fn trySwappingItems(_: usize, _: *ItemStack) void {
return;
}
const vtable = ItemSlot.VTable {
.tryAddingItems = &tryAddingItems,
.tryTakingItems = &tryTakingItems,
.trySwappingItems = &trySwappingItems,
};
pub fn onOpen() Allocator.Error!void {
items = std.ArrayList(Item).init(main.globalAllocator);
var itemIterator = main.items.iterator();
@ -60,7 +46,7 @@ pub fn onOpen() Allocator.Error!void {
for(0..8) |_| {
if(i >= items.items.len) break;
const item = items.items[i];
try row.add(try ItemSlot.init(.{0, 0}, .{.item = item, .amount = item.stackSize()}, &vtable, i));
try row.add(try ItemSlot.init(.{0, 0}, .{.item = item, .amount = item.stackSize()}, &.{.tryTakingItems = &tryTakingItems}, i, .default, .takeOnly));
i += 1;
}
try list.add(row);

View File

@ -29,13 +29,12 @@ pub var window = GuiWindow {
var itemSlots: [8]*ItemSlot = undefined;
pub fn tryAddingItems(index: usize, source: *ItemStack, amount: u16) void {
pub fn tryAddingItems(index: usize, source: *ItemStack, desiredAmount: u16) void {
Player.mutex.lock();
defer Player.mutex.unlock();
const destination = &Player.inventory__SEND_CHANGES_TO_SERVER.items[index];
if(destination.item != null and !std.meta.eql(source.item, destination.item)) return;
destination.item = source.item;
const actual = destination.add(amount);
const actual = destination.add(source.item.?, desiredAmount);
source.amount -= actual;
if(source.amount == 0) source.item = null;
main.network.Protocols.genericUpdate.sendInventory_full(main.game.world.?.conn, Player.inventory__SEND_CHANGES_TO_SERVER) catch |err| { // TODO(post-java): Add better options to the protocol.
@ -43,16 +42,15 @@ pub fn tryAddingItems(index: usize, source: *ItemStack, amount: u16) void {
};
}
pub fn tryTakingItems(index: usize, destination: *ItemStack, _amount: u16) void {
var amount = _amount;
pub fn tryTakingItems(index: usize, destination: *ItemStack, desiredAmount: u16) void {
var amount = desiredAmount;
Player.mutex.lock();
defer Player.mutex.unlock();
const source = &Player.inventory__SEND_CHANGES_TO_SERVER.items[index];
if(destination.item != null and !std.meta.eql(source.item, destination.item)) return;
if(source.item == null) return;
amount = @min(amount, source.amount);
destination.item = source.item;
const actual = destination.add(amount);
const actual = destination.add(source.item.?, amount);
source.amount -= actual;
if(source.amount == 0) source.item = null;
main.network.Protocols.genericUpdate.sendInventory_full(main.game.world.?.conn, Player.inventory__SEND_CHANGES_TO_SERVER) catch |err| { // TODO(post-java): Add better options to the protocol.
@ -81,7 +79,7 @@ const vtable = ItemSlot.VTable {
pub fn onOpen() Allocator.Error!void {
const list = try HorizontalList.init();
for(0..8) |i| {
itemSlots[i] = try ItemSlot.init(.{0, 0}, Player.inventory__SEND_CHANGES_TO_SERVER.items[i], &vtable, i);
itemSlots[i] = try ItemSlot.init(.{0, 0}, Player.inventory__SEND_CHANGES_TO_SERVER.items[i], &vtable, i, .default, .normal);
try list.add(itemSlots[i]);
}
list.finish(.{0, 0}, .center);

View File

@ -40,13 +40,12 @@ pub fn deinit() void {
var itemSlots: [24]*ItemSlot = undefined;
pub fn tryAddingItems(index: usize, source: *ItemStack, amount: u16) void {
pub fn tryAddingItems(index: usize, source: *ItemStack, desiredAmount: u16) void {
Player.mutex.lock();
defer Player.mutex.unlock();
const destination = &Player.inventory__SEND_CHANGES_TO_SERVER.items[index];
if(destination.item != null and !std.meta.eql(source.item, destination.item)) return;
destination.item = source.item;
const actual = destination.add(amount);
const actual = destination.add(source.item.?, desiredAmount);
source.amount -= actual;
if(source.amount == 0) source.item = null;
main.network.Protocols.genericUpdate.sendInventory_full(main.game.world.?.conn, Player.inventory__SEND_CHANGES_TO_SERVER) catch |err| { // TODO(post-java): Add better options to the protocol.
@ -54,16 +53,15 @@ pub fn tryAddingItems(index: usize, source: *ItemStack, amount: u16) void {
};
}
pub fn tryTakingItems(index: usize, destination: *ItemStack, _amount: u16) void {
var amount = _amount;
pub fn tryTakingItems(index: usize, destination: *ItemStack, desiredAmount: u16) void {
var amount = desiredAmount;
Player.mutex.lock();
defer Player.mutex.unlock();
const source = &Player.inventory__SEND_CHANGES_TO_SERVER.items[index];
if(destination.item != null and !std.meta.eql(source.item, destination.item)) return;
if(source.item == null) return;
amount = @min(amount, source.amount);
destination.item = source.item;
const actual = destination.add(amount);
const actual = destination.add(source.item.?, amount);
source.amount -= actual;
if(source.amount == 0) source.item = null;
main.network.Protocols.genericUpdate.sendInventory_full(main.game.world.?.conn, Player.inventory__SEND_CHANGES_TO_SERVER) catch |err| { // TODO(post-java): Add better options to the protocol.
@ -103,7 +101,7 @@ pub fn onOpen() Allocator.Error!void {
const row = try HorizontalList.init();
for(0..8) |x| {
const index: usize = y*8 + x;
const slot = try ItemSlot.init(.{0, 0}, Player.inventory__SEND_CHANGES_TO_SERVER.items[index], &vtable, index);
const slot = try ItemSlot.init(.{0, 0}, Player.inventory__SEND_CHANGES_TO_SERVER.items[index], &vtable, index, .default, .normal);
itemSlots[index - 8] = slot;
try row.add(slot);
}

View File

@ -16,8 +16,7 @@ const Button = GuiComponent.Button;
const HorizontalList = GuiComponent.HorizontalList;
const VerticalList = GuiComponent.VerticalList;
const Icon = GuiComponent.Icon;
const CraftingResultSlot = GuiComponent.CraftingResultSlot;
const ImmutableItemSlot = GuiComponent.ImmutableItemSlot;
const ItemSlot = GuiComponent.ItemSlot;
const inventory = @import("inventory.zig");
@ -62,10 +61,12 @@ fn addItemStackToAvailable(itemStack: ItemStack) Allocator.Error!void {
}
}
fn onTake(recipeIndex: usize) void {
fn tryTakingItems(recipeIndex: usize, destination: *ItemStack, _: u16) void {
const recipe = items.recipes()[recipeIndex];
const resultItem = recipe.resultItem;
if(!destination.canAddAll(resultItem.item.?, resultItem.amount)) return;
for(recipe.sourceItems, recipe.sourceAmounts) |item, _amount| {
var amount: u32 = _amount;
var amount = _amount;
for(main.game.Player.inventory__SEND_CHANGES_TO_SERVER.items) |*itemStack| {
if(itemStack.item) |invItem| {
if(invItem == .baseItem and invItem.baseItem == item) {
@ -84,6 +85,7 @@ fn onTake(recipeIndex: usize) void {
std.log.warn("Congratulations, you just managed to cheat {}*{s}, thanks to my lazy coding. Have fun with that :D", .{amount, item.id});
}
}
std.debug.assert(destination.add(resultItem.item.?, resultItem.amount) == resultItem.amount);
}
fn findAvailableRecipes(list: *VerticalList) Allocator.Error!bool {
@ -127,14 +129,14 @@ fn findAvailableRecipes(list: *VerticalList) Allocator.Error!bool {
if(col < remainder) itemsThisColumn += 1;
const columnList = try VerticalList.init(.{0, 0}, std.math.inf(f32), 0);
for(0..itemsThisColumn) |_| {
try columnList.add(try ImmutableItemSlot.init(.{0, 0}, recipe.sourceItems[i], recipe.sourceAmounts[i]));
try columnList.add(try ItemSlot.init(.{0, 0}, .{.item = .{.baseItem = recipe.sourceItems[i]}, .amount = recipe.sourceAmounts[i]}, &.{}, 0, .immutable, .immutable));
i += 1;
}
columnList.finish(.center);
try rowList.add(columnList);
}
try rowList.add(try Icon.init(.{8, 0}, .{32, 32}, arrowTexture, false));
const itemSlot = try CraftingResultSlot.init(.{8, 0}, recipe.resultItem, .{.callback = &onTake, .arg = recipeIndex});
const itemSlot = try ItemSlot.init(.{8, 0}, recipe.resultItem, &.{.tryTakingItems = &tryTakingItems}, recipeIndex, .craftingResult, .takeOnly);
try rowList.add(itemSlot);
rowList.finish(.{0, 0}, .center);
try list.add(rowList);

View File

@ -19,8 +19,6 @@ const HorizontalList = GuiComponent.HorizontalList;
const VerticalList = GuiComponent.VerticalList;
const Icon = GuiComponent.Icon;
const ItemSlot = GuiComponent.ItemSlot;
const CraftingResultSlot = GuiComponent.CraftingResultSlot;
const ImmutableItemSlot = GuiComponent.ImmutableItemSlot;
const inventory = @import("inventory.zig");
const inventory_crafting = @import("inventory_crafting.zig");
@ -40,7 +38,7 @@ var availableItems: [25]?*const BaseItem = undefined;
var craftingGrid: [25]ItemStack = undefined;
var craftingResult: *CraftingResultSlot = undefined;
var craftingResult: *ItemSlot = undefined;
var seed: u32 = undefined;
@ -52,8 +50,7 @@ pub fn tryAddingItems(index: usize, source: *ItemStack, amount: u16) void {
if(source.item.?.baseItem.material == null) return;
const destination = &craftingGrid[index];
if(destination.item != null and !std.meta.eql(source.item, destination.item)) return;
destination.item = source.item;
const actual = destination.add(amount);
const actual = destination.add(source.item.?, amount);
source.amount -= actual;
if(source.amount == 0) source.item = null;
}
@ -64,8 +61,7 @@ pub fn tryTakingItems(index: usize, destination: *ItemStack, _amount: u16) void
if(destination.item != null and !std.meta.eql(source.item, destination.item)) return;
if(source.item == null) return;
amount = @min(amount, source.amount);
destination.item = source.item;
const actual = destination.add(amount);
const actual = destination.add(source.item.?, amount);
source.amount -= actual;
if(source.amount == 0) source.item = null;
}
@ -83,10 +79,12 @@ const vtable = ItemSlot.VTable {
.trySwappingItems = &trySwappingItems,
};
fn onTake(_: usize) void {
fn onTake(_: usize, destination: *ItemStack, _: u16) void {
if(destination.item != null) return;
destination.* = craftingResult.itemStack;
for(&craftingGrid) |*itemStack| {
if(itemStack.item != null and itemStack.item.? == .baseItem and itemStack.item.?.baseItem.material != null) {
_ = itemStack.add(@as(i32, -1));
_ = itemStack.add(itemStack.item.?, @as(i32, -1));
}
}
craftingResult.itemStack = .{};
@ -137,7 +135,7 @@ pub fn onOpen() Allocator.Error!void {
const row = try HorizontalList.init();
for(0..5) |x| {
const index = x + y*5;
const slot = try ItemSlot.init(.{0, 0}, craftingGrid[index], &vtable, index);
const slot = try ItemSlot.init(.{0, 0}, craftingGrid[index], &vtable, index, .default, .normal);
itemSlots[index] = slot;
try row.add(slot);
}
@ -147,7 +145,7 @@ pub fn onOpen() Allocator.Error!void {
try list.add(grid);
}
try list.add(try Icon.init(.{8, 0}, .{32, 32}, inventory_crafting.arrowTexture, false));
craftingResult = try CraftingResultSlot.init(.{8, 0}, .{}, .{.callback = &onTake});
craftingResult = try ItemSlot.init(.{8, 0}, .{}, &.{.tryTakingItems = &onTake}, 0, .craftingResult, .takeOnly);
try list.add(craftingResult);
list.finish(.{padding, padding + 16}, .center);
window.rootComponent = list.toComponent();

View File

@ -1154,8 +1154,8 @@ pub const ItemStack = struct {
}
/// Returns the number of items actually added/removed.
pub fn add(self: *ItemStack, number: anytype) @TypeOf(number) {
std.debug.assert(self.item != null);
pub fn add(self: *ItemStack, item: Item, number: anytype) @TypeOf(number) {
if(self.item == null) self.item = item;
var newAmount = self.amount + number;
var returnValue = number;
if(newAmount < 0) {
@ -1173,9 +1173,9 @@ pub const ItemStack = struct {
}
/// whether the given number of items can be added to this stack.
pub fn canAddAll(self: *const ItemStack, number: u16) bool {
std.debug.assert(self.item);
return @as(u32, self.amount) + number <= self.item.?.stackSize();
pub fn canAddAll(self: *const ItemStack, item: Item, number: u16) bool {
if(self.item != null and !std.meta.eql(self.item.?, item)) return false;
return @as(u32, self.amount) + number <= item.stackSize();
}
pub fn clear(self: *ItemStack) void {
@ -1225,14 +1225,13 @@ pub const Inventory = struct {
var amount = _amount;
for(self.items) |*stack| {
if(!stack.empty() and std.meta.eql(stack.item, item) and !stack.filled()) {
amount -= stack.add(amount);
amount -= stack.add(item, amount);
if(amount == 0) return 0;
}
}
for(self.items) |*stack| {
if(stack.empty()) {
stack.item = item;
amount -= stack.add(amount);
amount -= stack.add(item, amount);
if(amount == 0) return 0;
}
}
@ -1288,7 +1287,7 @@ pub const Inventory = struct {
const Recipe = struct {
sourceItems: []*BaseItem,
sourceAmounts: []u32,
sourceAmounts: []u16,
resultItem: ItemStack,
};
@ -1337,7 +1336,7 @@ pub fn registerRecipes(file: []const u8) !void {
}
var items = std.ArrayList(*BaseItem).init(main.globalAllocator);
defer items.deinit();
var itemAmounts = std.ArrayList(u32).init(main.globalAllocator);
var itemAmounts = std.ArrayList(u16).init(main.globalAllocator);
defer itemAmounts.deinit();
var string = std.ArrayList(u8).init(main.globalAllocator);
defer string.deinit();
@ -1369,7 +1368,7 @@ pub fn registerRecipes(file: []const u8) !void {
const item = shortcuts.get(id) orelse getByID(id) orelse continue;
const recipe = Recipe {
.sourceItems = try arena.allocator().dupe(*BaseItem, items.items),
.sourceAmounts = try arena.allocator().dupe(u32, itemAmounts.items),
.sourceAmounts = try arena.allocator().dupe(u16, itemAmounts.items),
.resultItem = ItemStack{.item = Item{.baseItem = item}, .amount = amount},
};
try recipeList.append(recipe);

View File

@ -782,7 +782,7 @@ pub const MeshSelection = struct {
if(rotationMode.generateData(main.game.world.?, selectedPos, relPos, lastDir, neighborDir, &block, false)) {
// TODO: world.updateBlock(bi.x, bi.y, bi.z, block.data); ( Sending it over the network)
try mesh_storage.updateBlock(selectedPos[0], selectedPos[1], selectedPos[2], block);
_ = inventoryStack.add(@as(i32, -1));
_ = inventoryStack.add(item, @as(i32, -1));
return;
}
}
@ -795,7 +795,7 @@ pub const MeshSelection = struct {
if(rotationMode.generateData(main.game.world.?, neighborPos, relPos, lastDir, neighborDir, &block, false)) {
// TODO: world.updateBlock(bi.x, bi.y, bi.z, block.data); ( Sending it over the network)
try mesh_storage.updateBlock(neighborPos[0], neighborPos[1], neighborPos[2], block);
_ = inventoryStack.add(@as(i32, -1));
_ = inventoryStack.add(item, @as(i32, -1));
return;
}
} else {
@ -815,7 +815,7 @@ pub const MeshSelection = struct {
if(rotationMode.generateData(main.game.world.?, neighborPos, relPos, lastDir, neighborDir, &block, true)) {
// TODO: world.updateBlock(bi.x, bi.y, bi.z, block.data); ( Sending it over the network)
try mesh_storage.updateBlock(neighborPos[0], neighborPos[1], neighborPos[2], block);
_ = inventoryStack.add(@as(i32, -1));
_ = inventoryStack.add(item, @as(i32, -1));
return;
}
}