Skip to content
Open
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
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
41 changes: 40 additions & 1 deletion src/gui/windows/inventory_crafting.zig
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,32 @@ const padding: f32 = 8;
var availableItems: main.ListManaged(BaseItemIndex) = undefined;
var itemAmount: main.ListManaged(u32) = undefined;
var inventories: main.ListManaged(ClientInventory) = undefined;
var craftableFromTags: main.ListManaged(main.Tag) = undefined;
var foundNewTags: bool = false;
var defaultCraftingTags: []main.Tag = undefined;

pub var arrowTexture: Texture = undefined;

pub fn init() void {
arrowTexture = Texture.initFromFile("assets/cubyz/ui/inventory/crafting_arrow.png");
defaultCraftingTags = main.globalAllocator.alloc(main.Tag, 1);
defaultCraftingTags[0] = main.Tag.handCraftable;
craftableFromTags = .init(main.globalAllocator);
changeCraftingTags(defaultCraftingTags);
}

pub fn deinit() void {
arrowTexture.deinit();
craftableFromTags.clearAndFree();
craftableFromTags.deinit();
main.globalAllocator.free(defaultCraftingTags);
}

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

fn addItemStackToAvailable(itemStack: ItemStack) void {
Expand All @@ -70,7 +87,8 @@ fn findAvailableRecipes(list: *VerticalList) bool {
for (0..main.game.Player.inventory.size()) |i| {
addItemStackToAvailable(main.game.Player.inventory.getStack(i));
}
if (std.mem.eql(u32, oldAmounts, itemAmount.items)) return false;
if (std.mem.eql(u32, oldAmounts, itemAmount.items) and (!foundNewTags)) return false;
foundNewTags = false;
// Remove no longer present items:
var i: u32 = 0;
while (i < availableItems.items.len) : (i += 1) {
Expand All @@ -93,6 +111,14 @@ fn findAvailableRecipes(list: *VerticalList) bool {
}
continue :outer; // Ingredient not found.
}
middle: for (recipe.craftingTags) |tag| {
for (craftableFromTags.items) |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 +197,19 @@ pub fn onClose() void {
inventories.deinit();
}

pub fn onToggleWindow() void {
changeCraftingTags(defaultCraftingTags);
refresh();
}

pub fn update() void {
refresh();
}

fn changeCraftingTags(newCraftingTags: []main.Tag) void {
foundNewTags = true;
if (std.mem.eql(main.Tag, craftableFromTags.items, newCraftingTags)) return;
craftableFromTags.deinit();
craftableFromTags = .initCapacity(main.globalAllocator, newCraftingTags.len);
craftableFromTags.appendSlice(newCraftingTags);
}
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