diff --git a/src/Inventory.zig b/src/Inventory.zig index 3eb18717..5b3017f9 100644 --- a/src/Inventory.zig +++ b/src/Inventory.zig @@ -1057,7 +1057,7 @@ pub const Command = struct { // MARK: Command fn serialize(self: Open, data: *main.List(u8)) void { std.mem.writeInt(u32, data.addMany(4)[0..4], self.inv.id, .big); std.mem.writeInt(usize, data.addMany(8)[0..8], self.inv._items.len, .big); - data.append(@intFromEnum(self.inv.type)); + data.append(@intFromEnum(std.meta.activeTag(self.inv.type))); data.append(@intFromEnum(self.source)); switch (self.source) { .playerInventory, .hand => |val| { @@ -1065,6 +1065,12 @@ pub const Command = struct { // MARK: Command }, else => {} } + switch(self.inv.type) { + .normal, .creative, .crafting => {}, + .workbench => { + data.appendSlice(self.inv.type.workbench.id); + }, + } switch(self.source) { .playerInventory, .sharedTestingInventory, .hand, .other => {}, .alreadyFreed => unreachable, @@ -1076,7 +1082,7 @@ pub const Command = struct { // MARK: Command if(side != .server or user == null) return error.Invalid; const id = std.mem.readInt(u32, data[0..4], .big); const len = std.mem.readInt(usize, data[4..12], .big); - const typ: Inventory.Type = @enumFromInt(data[12]); + const typeEnum: TypeEnum = @enumFromInt(data[12]); const sourceType: SourceType = @enumFromInt(data[13]); const source: Source = switch(sourceType) { .playerInventory => .{.playerInventory = std.mem.readInt(u32, data[14..18], .big)}, @@ -1085,6 +1091,15 @@ pub const Command = struct { // MARK: Command .other => .{.other = {}}, .alreadyFreed => unreachable, }; + const remainingLen: usize = switch(sourceType) { + .playerInventory, .hand => 18, + .sharedTestingInventory, .other => 14, + .alreadyFreed => unreachable, + }; + const typ: Type = switch(typeEnum) { + inline .normal, .creative, .crafting => |tag| tag, + .workbench => .{.workbench = main.items.getToolTypeByID(data[remainingLen..]) orelse return error.Invalid}, + }; Sync.ServerSide.createInventory(user.?, id, len, typ, source); return .{ .inv = Sync.ServerSide.getInventory(user.?, id) orelse return error.Invalid, @@ -1667,12 +1682,18 @@ const Source = union(SourceType) { const Inventory = @This(); // MARK: Inventory -const Type = enum(u8) { +const TypeEnum = enum(u8) { normal = 0, creative = 1, crafting = 2, workbench = 3, }; +const Type = union(TypeEnum) { + normal: void, + creative: void, + crafting: void, + workbench: *const main.items.ToolType, +}; type: Type, id: u32, _items: []ItemStack, diff --git a/src/assets.zig b/src/assets.zig index 5a84e451..144cf6f0 100644 --- a/src/assets.zig +++ b/src/assets.zig @@ -12,6 +12,7 @@ var arenaAllocator: NeverFailingAllocator = undefined; var commonBlocks: std.StringHashMap(ZonElement) = undefined; var commonBiomes: std.StringHashMap(ZonElement) = undefined; var commonItems: std.StringHashMap(ZonElement) = undefined; +var commonTools: std.StringHashMap(ZonElement) = undefined; var commonRecipes: std.StringHashMap(ZonElement) = undefined; var commonModels: std.StringHashMap([]const u8) = undefined; @@ -181,7 +182,7 @@ pub fn readAllObjFilesInAddonsHashmap(externalAllocator: NeverFailingAllocator, } } -pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u8, blocks: *std.StringHashMap(ZonElement), items: *std.StringHashMap(ZonElement), biomes: *std.StringHashMap(ZonElement), recipes: *std.StringHashMap(ZonElement), models: *std.StringHashMap([]const u8)) void { +pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u8, blocks: *std.StringHashMap(ZonElement), items: *std.StringHashMap(ZonElement), tools: *std.StringHashMap(ZonElement), biomes: *std.StringHashMap(ZonElement), recipes: *std.StringHashMap(ZonElement), models: *std.StringHashMap([]const u8)) void { var addons = main.List(std.fs.Dir).init(main.stackAllocator); defer addons.deinit(); var addonNames = main.List([]const u8).init(main.stackAllocator); @@ -214,6 +215,7 @@ pub fn readAssets(externalAllocator: NeverFailingAllocator, assetPath: []const u readAllZonFilesInAddons(externalAllocator, addons, addonNames, "blocks", true, blocks); readAllZonFilesInAddons(externalAllocator, addons, addonNames, "items", true, items); + readAllZonFilesInAddons(externalAllocator, addons, addonNames, "tools", true, tools); readAllZonFilesInAddons(externalAllocator, addons, addonNames, "biomes", true, biomes); readAllZonFilesInAddons(externalAllocator, addons, addonNames, "recipes", false, recipes); readAllObjFilesInAddonsHashmap(externalAllocator, addons, addonNames, "models", models); @@ -226,11 +228,12 @@ pub fn init() void { arenaAllocator = arena.allocator(); commonBlocks = .init(arenaAllocator.allocator); commonItems = .init(arenaAllocator.allocator); + commonTools = .init(arenaAllocator.allocator); commonBiomes = .init(arenaAllocator.allocator); commonRecipes = .init(arenaAllocator.allocator); commonModels = .init(arenaAllocator.allocator); - readAssets(arenaAllocator, "assets/", &commonBlocks, &commonItems, &commonBiomes, &commonRecipes, &commonModels); + readAssets(arenaAllocator, "assets/", &commonBlocks, &commonItems, &commonTools, &commonBiomes, &commonRecipes, &commonModels); } fn registerItem(assetFolder: []const u8, id: []const u8, zon: ZonElement) !*items_zig.BaseItem { @@ -247,6 +250,10 @@ fn registerItem(assetFolder: []const u8, id: []const u8, zon: ZonElement) !*item return items_zig.register(assetFolder, texturePath, replacementTexturePath, id, zon); } +fn registerTool(assetFolder: []const u8, id: []const u8, zon: ZonElement) void { + items_zig.registerTool(assetFolder, id, zon); +} + fn registerBlock(assetFolder: []const u8, id: []const u8, zon: ZonElement) !void { const block = blocks_zig.register(assetFolder, id, zon); blocks_zig.meshes.register(assetFolder, id, zon); @@ -322,6 +329,8 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, biomePal defer blocks.clearAndFree(); var items = commonItems.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable; defer items.clearAndFree(); + var tools = commonTools.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable; + defer tools.clearAndFree(); var biomes = commonBiomes.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable; defer biomes.clearAndFree(); var recipes = commonRecipes.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable; @@ -329,7 +338,7 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, biomePal var models = commonModels.cloneWithAllocator(main.stackAllocator.allocator) catch unreachable; defer models.clearAndFree(); - readAssets(arenaAllocator, assetFolder, &blocks, &items, &biomes, &recipes, &models); + readAssets(arenaAllocator, assetFolder, &blocks, &items, &tools, &biomes, &recipes, &models); errdefer unloadAssets(); var modelIterator = models.iterator(); @@ -363,6 +372,12 @@ pub fn loadWorldAssets(assetFolder: []const u8, blockPalette: *Palette, biomePal _ = try registerItem(assetFolder, entry.key_ptr.*, entry.value_ptr.*); } + // tools: + iterator = tools.iterator(); + while(iterator.next()) |entry| { + registerTool(assetFolder, entry.key_ptr.*, entry.value_ptr.*); + } + // block drops: blocks_zig.finishBlocks(blocks); diff --git a/src/gui/windows/workbench.zig b/src/gui/windows/workbench.zig index f6275785..b7e4af75 100644 --- a/src/gui/windows/workbench.zig +++ b/src/gui/windows/workbench.zig @@ -37,13 +37,24 @@ var inv: Inventory = undefined; var craftingResult: *ItemSlot = undefined; -var seed: u32 = undefined; - var itemSlots: [25]*ItemSlot = undefined; -pub fn onOpen() void { - seed = @truncate(@as(u128, @bitCast(std.time.nanoTimestamp()))); - inv = Inventory.init(main.globalAllocator, 26, .workbench, .other); +var toolTypes: main.ListUnmanaged(*const main.items.ToolType) = .{}; +var currentToolType: usize = 0; + +var toolButton: *Button = undefined; + +var needsUpdate: bool = false; + +fn toggleTool(_: usize) void { + currentToolType += 1; + currentToolType %= toolTypes.items.len; + toolButton.child.label.updateText(toolTypes.items[currentToolType].id); + needsUpdate = true; +} + +fn openInventory() void { + inv = Inventory.init(main.globalAllocator, 26, .{.workbench = toolTypes.items[currentToolType]}, .other); const list = HorizontalList.init(); { // crafting grid const grid = VerticalList.init(.{0, 0}, 300, 0); @@ -61,15 +72,25 @@ pub fn onOpen() void { grid.finish(.center); list.add(grid); } - list.add(Icon.init(.{8, 0}, .{32, 32}, inventory_crafting.arrowTexture, false)); - list.add(ItemSlot.init(.{8, 0}, inv, 25, .craftingResult, .takeOnly)); + const verticalThing = VerticalList.init(.{0, 0}, 300, padding); + toolButton = Button.initText(.{8, 0}, 116, toolTypes.items[currentToolType].id, .{.callback = &toggleTool}); + verticalThing.add(toolButton); + const buttonHeight = verticalThing.size[1]; + const craftingResultList = HorizontalList.init(); + craftingResultList.add(Icon.init(.{0, 0}, .{32, 32}, inventory_crafting.arrowTexture, false)); + craftingResultList.add(ItemSlot.init(.{8, 0}, inv, 25, .craftingResult, .takeOnly)); + craftingResultList.finish(.{padding, padding}, .center); + verticalThing.add(craftingResultList); + verticalThing.size[1] += buttonHeight + 2*padding; // Centering the thing + verticalThing.finish(.center); + list.add(verticalThing); list.finish(.{padding, padding + 16}, .center); window.rootComponent = list.toComponent(); window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding)); gui.updateWindowPositions(); } -pub fn onClose() void { +fn closeInventory() void { main.game.Player.inventory.depositOrDrop(inv); inv.deinit(main.globalAllocator); if(window.rootComponent) |*comp| { @@ -77,3 +98,26 @@ pub fn onClose() void { window.rootComponent = null; } } + +pub fn update() void { + if(needsUpdate) { + needsUpdate = false; + closeInventory(); + openInventory(); + } +} + +pub fn onOpen() void { + currentToolType = 0; + var iterator = main.items.toolTypeIterator(); + + while(iterator.next()) |toolType| { + toolTypes.append(main.globalAllocator, toolType); + } + openInventory(); +} + +pub fn onClose() void { + closeInventory(); + toolTypes.clearAndFree(main.globalAllocator); +} diff --git a/src/items.zig b/src/items.zig index 776c5b9f..0399afbb 100644 --- a/src/items.zig +++ b/src/items.zig @@ -862,6 +862,12 @@ const ToolPhysics = struct { // MARK: ToolPhysics } }; +pub const ToolType = struct { // MARK: ToolType + id: []const u8, + blockClass: main.blocks.BlockClass, + // TODO +}; + pub const Tool = struct { // MARK: Tool craftingGrid: [25]?*const BaseItem, materialGrid: [16][16]?*const BaseItem, @@ -1191,12 +1197,17 @@ const Recipe = struct { // MARK: Recipe }; var arena: main.utils.NeverFailingArenaAllocator = undefined; +var toolTypes: std.StringHashMap(ToolType) = undefined; var reverseIndices: std.StringHashMap(*BaseItem) = undefined; pub var itemList: [65536]BaseItem = undefined; pub var itemListSize: u16 = 0; var recipeList: main.List(Recipe) = undefined; +pub fn toolTypeIterator() std.StringHashMap(ToolType).ValueIterator { + return toolTypes.valueIterator(); +} + pub fn iterator() std.StringHashMap(*BaseItem).ValueIterator { return reverseIndices.valueIterator(); } @@ -1207,6 +1218,7 @@ pub fn recipes() []Recipe { pub fn globalInit() void { arena = .init(main.globalAllocator); + toolTypes = .init(arena.allocator().allocator); reverseIndices = .init(arena.allocator().allocator); recipeList = .init(arena.allocator()); itemListSize = 0; @@ -1225,6 +1237,18 @@ pub fn register(_: []const u8, texturePath: []const u8, replacementTexturePath: return newItem; } +pub fn registerTool(_: []const u8, id: []const u8, zon: ZonElement) void { + std.log.info("Registering tool type {s}", .{id}); + if(toolTypes.contains(id)) { + std.log.err("Registered tool type with id {s} twice!", .{id}); + } + const idDupe = arena.allocator().dupe(u8, id); + toolTypes.put(idDupe, .{ + .id = idDupe, + .blockClass = std.meta.stringToEnum(main.blocks.BlockClass, zon.get([]const u8, "blockClass", "none")) orelse .air, + }) catch unreachable; +} + fn parseRecipeItem(zon: ZonElement) !ItemStack { var id = zon.as([]const u8, ""); id = std.mem.trim(u8, id, &std.ascii.whitespace); @@ -1266,6 +1290,7 @@ pub fn registerRecipes(zon: ZonElement) void { } pub fn reset() void { + toolTypes.clearAndFree(); reverseIndices.clearAndFree(); recipeList.clearAndFree(); itemListSize = 0; @@ -1273,6 +1298,7 @@ pub fn reset() void { } pub fn deinit() void { + toolTypes.clearAndFree(); reverseIndices.clearAndFree(); recipeList.clearAndFree(); arena.deinit(); @@ -1287,3 +1313,12 @@ pub fn getByID(id: []const u8) ?*BaseItem { return null; } } + +pub fn getToolTypeByID(id: []const u8) ?*const ToolType { + if(toolTypes.getPtr(id)) |result| { + return result; + } else { + std.log.err("Couldn't find item {s}.", .{id}); + return null; + } +}