Skip to content
14 changes: 14 additions & 0 deletions assets/cubyz/blocks/transmutation_workbench.zig.zon
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.{
.tags = .{.diggable},
.blockHealth = 6.5,
.drops = .{
.{.items = .{.auto}},
},
.model = "cubyz:cube",
.rotation = "cubyz:stairs",
.texture = "cubyz:aerosoil",
.onInteract = .{
.type = .open_crafting_window,
.craftingTags = .{.alchemy},
},
}
6 changes: 6 additions & 0 deletions assets/cubyz/recipes/cloth_recipes.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,10 @@
.output = "cubyz:cloth/block/{color}",
.reversible = true,
},
.{
.inputs = .{"4 cubyz:copper_ingot"},
.output = "cubyz:silver_ingot",
.reversible = true,
.craftingTags = .{.alchemy},
},
}
1 change: 1 addition & 0 deletions src/callbacks/block/client/_list.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub const edit_sign = @import("edit_sign.zig");
pub const open_chest = @import("open_chest.zig");
pub const open_window = @import("open_window.zig");
pub const open_crafting_window = @import("open_crafting_window.zig");
2 changes: 1 addition & 1 deletion src/callbacks/block/client/edit_sign.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub fn init(_: ZonElement, _: main.callbacks.Creator) ?*anyopaque {

pub fn run(_: *anyopaque, params: main.callbacks.ClientBlockCallback.Params) main.callbacks.Result {
if (params.block.blockEntity() == null or !std.mem.eql(u8, params.block.blockEntity().?.id, "cubyz:sign")) {
std.log.err("Can only edit sign if block entity of the block is a sign.", .{});
std.log.err("Error: Can only edit sign if block entity of the block is a sign.", .{});
return .ignored;
}
main.block_entity.BlockEntityTypes.@"cubyz:sign".StorageClient.mutex.lock();
Expand Down
2 changes: 1 addition & 1 deletion src/callbacks/block/client/open_chest.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub fn init(_: ZonElement, _: main.callbacks.Creator) ?*anyopaque {

pub fn run(_: *anyopaque, params: main.callbacks.ClientBlockCallback.Params) main.callbacks.Result {
if (params.block.blockEntity() == null or !std.mem.eql(u8, params.block.blockEntity().?.id, "cubyz:chest")) {
std.log.err("Can only open chest if block entity of the block is a chest.", .{});
std.log.err("Error: Can only open chest if block entity of the block is a chest.", .{});
return .ignored;
}
main.network.protocols.blockEntityUpdate.sendClientDataUpdateToServer(main.game.world.?.conn, params.blockPos);
Expand Down
25 changes: 25 additions & 0 deletions src/callbacks/block/client/open_crafting_window.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const std = @import("std");

const main = @import("main");
const Block = main.blocks.Block;
const vec = main.vec;
const Vec3i = vec.Vec3i;
const ZonElement = main.ZonElement;

craftingTags: []main.Tag,

pub fn init(zon: ZonElement, _: main.callbacks.Creator) ?*@This() {
const result = main.worldArena.create(@This());
const craftingTags = main.Tag.loadTagsFromZon(main.worldArena, zon.getChild("craftingTags"));
if (craftingTags.len == 0) std.log.err("Error: Missing craftingTags \"name\" for open_crafting_window event.", .{});
result.* = .{
.craftingTags = craftingTags,
};
return result;
}

pub fn run(self: *@This(), _: main.callbacks.ClientBlockCallback.Params) main.callbacks.Result {
main.gui.windowlist.inventory_crafting.openFromCallback(self.craftingTags);
main.Window.setMouseGrabbed(false);
return .handled;
}
2 changes: 1 addition & 1 deletion src/callbacks/block/client/open_window.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub fn init(zon: ZonElement, _: main.callbacks.Creator) ?*@This() {
const result = main.worldArena.create(@This());
result.* = .{
.windowName = main.worldArena.dupe(u8, zon.get([]const u8, "name") orelse {
std.log.err("Missing field \"name\" for open_window event.", .{});
std.log.err("Error: Missing field \"name\" for open_window event.", .{});
return null;
}),
};
Expand Down
2 changes: 2 additions & 0 deletions src/gui/GuiWindow.zig
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ onOpenFn: *const fn () void = &defaultFunction,

onCloseFn: *const fn () void = &defaultFunction,

onToggleWindowFn: *const fn () void = &defaultFunction,

var grabbedWindow: *const GuiWindow = undefined;
var windowMoving: bool = false;
var grabPosition: ?Vec2f = null;
Expand Down
3 changes: 2 additions & 1 deletion src/gui/gui.zig
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ pub fn initWindowList() void {
const windowStruct = @field(windowlist, decl.name);
windowStruct.window.id = decl.name;
addWindow(&windowStruct.window);
const functionNames = [_][]const u8{"render", "update", "updateSelected", "updateHovered", "onOpen", "onClose"};
const functionNames = [_][]const u8{"render", "update", "updateSelected", "updateHovered", "onOpen", "onClose", "onToggleWindow"};
inline for (functionNames) |function| {
if (@hasDecl(windowStruct, function)) {
@field(windowStruct.window, function ++ "Fn") = &@field(windowStruct, function);
Expand Down Expand Up @@ -642,6 +642,7 @@ pub fn toggleGameMenu() void {
_ = openWindows.swapRemove(i);
window.onCloseFn();
} else {
window.onToggleWindowFn();
i += 1;
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/gui/windows/inventory_crafting.zig
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,24 @@ var itemAmount: main.ListManaged(u32) = undefined;
var inventories: main.ListManaged(ClientInventory) = undefined;

pub var arrowTexture: Texture = undefined;
pub var craftableFromTags: []main.Tag = undefined;

pub fn init() void {
arrowTexture = Texture.initFromFile("assets/cubyz/ui/inventory/crafting_arrow.png");
craftableFromTags = .{main.Tag.handCraftable};
}

pub fn deinit() void {
arrowTexture.deinit();
}

pub fn openFromCallback(craftingTags: []main.Tag) void {
gui.closeWindowFromRef(&window);
gui.openWindowFromRef(&window);
craftableFromTags = craftingTags;
main.Window.setMouseGrabbed(false);
}

fn addItemStackToAvailable(itemStack: ItemStack) void {
if (itemStack.item == .baseItem) {
const baseItem = itemStack.item.baseItem;
Expand Down Expand Up @@ -93,6 +102,14 @@ fn findAvailableRecipes(list: *VerticalList) bool {
}
continue :outer; // Ingredient not found.
}
middle: for (recipe.craftingTags) |tag| {
for (craftableFromTags) |craftingStationTag| {
if (tag == craftingStationTag) {
continue :middle;
}
}
continue :outer; // Recipe not craftable by this.
}
// All ingredients found: Add it to the list.
const inv = ClientInventory.init(main.globalAllocator, recipe.sourceItems.len + 1, .{.crafting = recipe}, .other, .{});

Expand Down Expand Up @@ -171,6 +188,12 @@ pub fn onClose() void {
inventories.deinit();
}

pub fn onToggleWindow() void {
craftableFromTags[0] = .{main.Tag.handCraftable};
std.log.debug("hello", .{});
refresh();
}

pub fn update() void {
refresh();
}
19 changes: 18 additions & 1 deletion src/items.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1300,16 +1300,21 @@ pub const Recipe = struct { // MARK: Recipe
sourceAmounts: []u16,
resultItem: BaseItemIndex,
resultAmount: u16,
craftingTags: []Tag,

fn getValidRecipe(self: Recipe) error{Invalid}!*Recipe {
outer: for (main.items.getRecipes()) |*recipe| {
if (recipe.resultItem != self.resultItem) continue;
if (recipe.resultAmount != self.resultAmount) continue;
if (recipe.sourceItems.len != self.sourceItems.len) continue;
if (recipe.craftingTags.len != self.craftingTags.len) continue;
for (recipe.sourceItems, recipe.sourceAmounts, self.sourceItems, self.sourceAmounts) |recipeItem, recipeAmount, selfItem, selfAmount| {
if (recipeItem != selfItem) continue :outer;
if (recipeAmount != selfAmount) continue :outer;
}
for (recipe.craftingTags, self.craftingTags) |recipeCraftingTag, selfCraftingTag| {
if (recipeCraftingTag != selfCraftingTag) continue :outer;
}
return recipe;
}
return error.Invalid;
Expand All @@ -1323,6 +1328,10 @@ pub const Recipe = struct { // MARK: Recipe
writer.writeEnum(BaseItemIndex, item);
writer.writeVarInt(u16, amount);
}
writer.writeVarInt(usize, self.craftingTags.len);
for (self.craftingTags) |tag| {
writer.writeEnum(Tag, tag);
}
}

pub fn fromBytes(reader: *BinaryReader) !*Recipe {
Expand All @@ -1340,7 +1349,15 @@ pub const Recipe = struct { // MARK: Recipe
sourceAmounts.append(main.stackAllocator, try reader.readVarInt(u16));
}

return getValidRecipe(.{.sourceItems = sourceItems.items, .sourceAmounts = sourceAmounts.items, .resultItem = resultItem, .resultAmount = resultAmount});
const tagCount = try reader.readVarInt(usize);
var craftingTagTypes: main.List(Tag) = .initCapacity(main.stackAllocator, @min(256, tagCount));
defer craftingTagTypes.deinit(main.stackAllocator);

while (reader.remaining.len > 0 and craftingTagTypes.items.len < tagCount) {
craftingTagTypes.append(main.stackAllocator, try reader.readEnum(Tag));
}

return getValidRecipe(.{.sourceItems = sourceItems.items, .sourceAmounts = sourceAmounts.items, .resultItem = resultItem, .resultAmount = resultAmount, .craftingTags = craftingTagTypes.items});
}
};

Expand Down
15 changes: 12 additions & 3 deletions src/items/recipes.zig
Original file line number Diff line number Diff line change
Expand Up @@ -190,19 +190,23 @@ fn generateItemCombos(allocator: NeverFailingAllocator, recipe: []const ZonEleme
return newInputCombos;
}

pub fn addRecipe(itemCombo: []const ItemWithAmount, list: *main.ListManaged(Recipe)) void {
pub fn addRecipe(itemCombo: []const ItemWithAmount, list: *main.ListManaged(Recipe), craftingTags: []Tag) void {
const inputs = itemCombo[0 .. itemCombo.len - 1];
const output = itemCombo[itemCombo.len - 1];
const recipe = Recipe{
.sourceItems = main.worldArena.alloc(BaseItemIndex, inputs.len),
.sourceAmounts = main.worldArena.alloc(u16, inputs.len),
.resultItem = output.item,
.resultAmount = output.amount,
.craftingTags = main.worldArena.alloc(Tag, craftingTags.len),
};
for (inputs, 0..) |input, i| {
recipe.sourceItems[i] = input.item;
recipe.sourceAmounts[i] = input.amount;
}
for (craftingTags, 0..) |tag, i| {
recipe.craftingTags[i] = tag;
}
list.append(recipe);
}

Expand All @@ -218,11 +222,16 @@ pub fn parseRecipe(zon: ZonElement, list: *main.ListManaged(Recipe)) !void {
return error.InvalidReversibleRecipe;
}

var defaultCraftingTags = arena.alloc(main.Tag, 1);
defaultCraftingTags[0] = main.Tag.handCraftable;
const foundCraftingTags = Tag.loadTagsFromZon(arena, zon.getChild("craftingTags"));
const craftingTags = if (foundCraftingTags.len != 0) foundCraftingTags else defaultCraftingTags;

const itemCombos = try generateItemCombos(arena, recipeItems);
for (itemCombos) |itemCombo| {
addRecipe(itemCombo, list);
addRecipe(itemCombo, list, craftingTags);
if (reversible) {
addRecipe(&.{itemCombo[1], itemCombo[0]}, list);
addRecipe(&.{itemCombo[1], itemCombo[0]}, list, craftingTags);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/tag.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub const Tag = enum(u32) {
fluidPlaceable = 3,
chiselable = 4,
playerModel = 5,
handCraftable = 6,
_,

pub fn initTags() void {
Expand Down
Loading