diff --git a/src/Inventory.zig b/src/Inventory.zig index c0ce1a1a..0be6ad52 100644 --- a/src/Inventory.zig +++ b/src/Inventory.zig @@ -15,6 +15,7 @@ const Vec3i = vec.Vec3i; const ZonElement = main.ZonElement; const Neighbor = main.chunk.Neighbor; const BaseItemIndex = main.items.BaseItemIndex; +const ToolTypeIndex = main.items.ToolTypeIndex; const Gamemode = main.game.Gamemode; @@ -1137,7 +1138,7 @@ pub const Command = struct { // MARK: Command switch(self.inv.type) { .normal, .creative, .crafting => {}, .workbench => { - writer.writeSlice(self.inv.type.workbench.id); + writer.writeSlice(self.inv.type.workbench.id()); }, } } @@ -1180,7 +1181,7 @@ pub const Command = struct { // MARK: Command }; const typ: Type = switch(typeEnum) { inline .normal, .creative, .crafting => |tag| tag, - .workbench => .{.workbench = main.items.getToolTypeByID(reader.remaining) orelse return error.Invalid}, + .workbench => .{.workbench = ToolTypeIndex.fromId(reader.remaining) orelse return error.Invalid}, }; Sync.ServerSide.createInventory(user.?, id, len, typ, source); return .{ @@ -1231,7 +1232,7 @@ pub const Command = struct { // MARK: Command cmd.tryCraftingTo(allocator, self.source, self.dest, side, user); return; } - if(self.dest.inv.type == .workbench and self.dest.slot != 25 and self.dest.inv.type.workbench.slotInfos[self.dest.slot].disabled) return; + if(self.dest.inv.type == .workbench and self.dest.slot != 25 and self.dest.inv.type.workbench.slotInfos()[self.dest.slot].disabled) return; if(self.dest.inv.type == .workbench and self.dest.slot == 25) { if(self.source.ref().item == null and self.dest.ref().item != null) { cmd.executeBaseOperation(allocator, .{.move = .{ @@ -1288,7 +1289,7 @@ pub const Command = struct { // MARK: Command std.debug.assert(self.source.inv.type == .normal); if(self.dest.inv.type == .creative) return; if(self.dest.inv.type == .crafting) return; - if(self.dest.inv.type == .workbench and (self.dest.slot == 25 or self.dest.inv.type.workbench.slotInfos[self.dest.slot].disabled)) return; + if(self.dest.inv.type == .workbench and (self.dest.slot == 25 or self.dest.inv.type.workbench.slotInfos()[self.dest.slot].disabled)) return; if(self.dest.inv.type == .workbench and !canPutIntoWorkbench(self.source)) return; const itemSource = self.source.ref().item orelse return; if(self.dest.ref().item) |itemDest| { @@ -1342,7 +1343,7 @@ pub const Command = struct { // MARK: Command cmd.tryCraftingTo(allocator, self.dest, self.source, side, user); return; } - if(self.source.inv.type == .workbench and self.source.slot != 25 and self.source.inv.type.workbench.slotInfos[self.source.slot].disabled) return; + if(self.source.inv.type == .workbench and self.source.slot != 25 and self.source.inv.type.workbench.slotInfos()[self.source.slot].disabled) return; if(self.source.inv.type == .workbench and self.source.slot == 25) { if(self.dest.ref().item == null and self.source.ref().item != null) { cmd.executeBaseOperation(allocator, .{.move = .{ @@ -1413,7 +1414,7 @@ pub const Command = struct { // MARK: Command } return; } - if(self.source.inv.type == .workbench and self.source.slot != 25 and self.source.inv.type.workbench.slotInfos[self.source.slot].disabled) return; + if(self.source.inv.type == .workbench and self.source.slot != 25 and self.source.inv.type.workbench.slotInfos()[self.source.slot].disabled) return; if(self.source.inv.type == .workbench and self.source.slot == 25) { cmd.removeToolCraftingIngredients(allocator, self.source.inv, side); } @@ -1449,7 +1450,7 @@ pub const Command = struct { // MARK: Command amount: u16 = 0, fn run(self: FillFromCreative, allocator: NeverFailingAllocator, cmd: *Command, side: Side, user: ?*main.server.User, mode: Gamemode) error{serverFailure}!void { - if(self.dest.inv.type == .workbench and (self.dest.slot == 25 or self.dest.inv.type.workbench.slotInfos[self.dest.slot].disabled)) return; + if(self.dest.inv.type == .workbench and (self.dest.slot == 25 or self.dest.inv.type.workbench.slotInfos()[self.dest.slot].disabled)) return; if(side == .server and user != null and mode != .creative) return; if(side == .client and mode != .creative) return; @@ -1847,7 +1848,7 @@ const Type = union(TypeEnum) { normal: void, creative: void, crafting: void, - workbench: *const main.items.ToolType, + workbench: ToolTypeIndex, pub fn shouldDepositToUserOnClose(self: Type) bool { return self == .workbench; @@ -1905,7 +1906,7 @@ fn update(self: Inventory) void { self._items[self._items.len - 1].deinit(); self._items[self._items.len - 1].clear(); var availableItems: [25]?BaseItemIndex = undefined; - const slotInfos = self.type.workbench.slotInfos; + const slotInfos = self.type.workbench.slotInfos(); for(0..25) |i| { if(self._items[i].item != null and self._items[i].item.? == .baseItem) { diff --git a/src/gui/windows/workbench.zig b/src/gui/windows/workbench.zig index 35f9a8a3..985e2751 100644 --- a/src/gui/windows/workbench.zig +++ b/src/gui/windows/workbench.zig @@ -6,6 +6,8 @@ const BaseItem = items.BaseItem; const Inventory = items.Inventory; const Item = items.Item; const Tool = items.Tool; +const ToolType = items.ToolType; +const ToolTypeIndex = items.ToolTypeIndex; const Player = main.game.Player; const Texture = main.graphics.Texture; const Vec2f = main.vec.Vec2f; @@ -37,7 +39,7 @@ var inv: Inventory = undefined; var itemSlots: [25]*ItemSlot = undefined; -var toolTypes: main.ListUnmanaged(*const main.items.ToolType) = .{}; +var toolTypes: main.ListUnmanaged(ToolTypeIndex) = undefined; var currentToolType: usize = 0; var toolButton: *Button = undefined; @@ -47,7 +49,7 @@ var needsUpdate: bool = false; fn toggleTool(_: usize) void { currentToolType += 1; currentToolType %= toolTypes.items.len; - toolButton.child.label.updateText(toolTypes.items[currentToolType].id); + toolButton.child.label.updateText(toolTypes.items[currentToolType].id()); needsUpdate = true; } @@ -61,7 +63,7 @@ fn openInventory() void { const row = HorizontalList.init(); for(0..5) |x| { const index = x + y*5; - const slotInfo = toolTypes.items[currentToolType].slotInfos[index]; + const slotInfo = toolTypes.items[currentToolType].slotInfos()[index]; const slot = ItemSlot.init(.{0, 0}, inv, @intCast(index), if(slotInfo.disabled) .invisible else if(slotInfo.optional) .immutable else .default, if(slotInfo.disabled) .immutable else .normal); itemSlots[index] = slot; row.add(slot); @@ -72,7 +74,7 @@ fn openInventory() void { list.add(grid); } const verticalThing = VerticalList.init(.{0, 0}, 300, padding); - toolButton = Button.initText(.{8, 0}, 116, toolTypes.items[currentToolType].id, .{.callback = &toggleTool}); + toolButton = Button.initText(.{8, 0}, 116, toolTypes.items[currentToolType].id(), .{.callback = &toggleTool}); verticalThing.add(toolButton); const buttonHeight = verticalThing.size[1]; const craftingResultList = HorizontalList.init(); @@ -119,15 +121,17 @@ pub fn render() void { pub fn onOpen() void { currentToolType = 0; - var iterator = main.items.toolTypeIterator(); + toolTypes = .{}; + var iterator = ToolTypeIndex.iterator(); while(iterator.next()) |toolType| { toolTypes.append(main.globalAllocator, toolType); } + openInventory(); } pub fn onClose() void { + toolTypes.deinit(main.globalAllocator); closeInventory(); - toolTypes.clearAndFree(main.globalAllocator); } diff --git a/src/items.zig b/src/items.zig index 3fbaf780..afe27fa7 100644 --- a/src/items.zig +++ b/src/items.zig @@ -16,6 +16,7 @@ const Vec2i = vec.Vec2i; const Vec3i = vec.Vec3i; const Vec3f = vec.Vec3f; const NeverFailingAllocator = main.heap.NeverFailingAllocator; +const ListUnmanaged = main.ListUnmanaged; const modifierList = @import("tool/modifiers/_list.zig"); const modifierRestrictionList = @import("tool/modifiers/restrictions/_list.zig"); @@ -340,8 +341,8 @@ const TextureGenerator = struct { // MARK: TextureGenerator const img = tool.image; for(0..16) |x| { for(0..16) |y| { - const source = tool.type.pixelSources[x][y]; - const sourceOverlay = tool.type.pixelSourcesOverlay[x][y]; + const source = tool.type.pixelSources()[x][y]; + const sourceOverlay = tool.type.pixelSourcesOverlay()[x][y]; if(sourceOverlay < 25 and tool.craftingGrid[sourceOverlay] != null) { tool.materialGrid[x][y] = tool.craftingGrid[sourceOverlay]; } else if(source < 25) { @@ -389,7 +390,7 @@ const ToolPhysics = struct { // MARK: ToolPhysics } var tempModifiers: main.List(Modifier) = .init(main.stackAllocator); defer tempModifiers.deinit(); - for(tool.type.properties) |property| { + for(tool.type.properties()) |property| { var sum: f32 = 0; var weight: f32 = 0; for(0..25) |i| { @@ -504,6 +505,45 @@ const PropertyMatrix = struct { // MARK: PropertyMatrix }; }; +pub const ToolTypeIndex = packed struct { + index: u16, + + const ToolTypeIterator = struct { + i: u16 = 0, + + pub fn next(self: *ToolTypeIterator) ?ToolTypeIndex { + if(self.i >= toolTypeList.items.len) return null; + defer self.i += 1; + return ToolTypeIndex{.index = self.i}; + } + }; + + pub fn iterator() ToolTypeIterator { + return .{}; + } + pub fn fromId(_id: []const u8) ?ToolTypeIndex { + return toolTypeIdToIndex.get(_id); + } + pub fn id(self: ToolTypeIndex) []const u8 { + return toolTypeList.items[self.index].id; + } + pub fn blockTags(self: ToolTypeIndex) []const Tag { + return toolTypeList.items[self.index].blockTags; + } + pub fn properties(self: ToolTypeIndex) []const PropertyMatrix { + return toolTypeList.items[self.index].properties; + } + pub fn slotInfos(self: ToolTypeIndex) *const [25]SlotInfo { + return &toolTypeList.items[self.index].slotInfos; + } + pub fn pixelSources(self: ToolTypeIndex) *const [16][16]u8 { + return &toolTypeList.items[self.index].pixelSources; + } + pub fn pixelSourcesOverlay(self: ToolTypeIndex) *const [16][16]u8 { + return &toolTypeList.items[self.index].pixelSourcesOverlay; + } +}; + pub const ToolType = struct { // MARK: ToolType id: []const u8, blockTags: []main.Tag, @@ -534,7 +574,7 @@ pub const Tool = struct { // MARK: Tool image: graphics.Image, texture: ?graphics.Texture, seed: u32, - type: *const ToolType, + type: ToolTypeIndex, damage: f32, @@ -600,7 +640,7 @@ pub const Tool = struct { // MARK: Tool return result; } - pub fn initFromCraftingGrid(craftingGrid: [25]?BaseItemIndex, seed: u32, typ: *const ToolType) *Tool { + pub fn initFromCraftingGrid(craftingGrid: [25]?BaseItemIndex, seed: u32, typ: ToolTypeIndex) *Tool { const self = init(); self.seed = seed; self.craftingGrid = craftingGrid; @@ -613,9 +653,9 @@ pub const Tool = struct { // MARK: Tool } pub fn initFromZon(zon: ZonElement) *Tool { - const self = initFromCraftingGrid(extractItemsFromZon(zon.getChild("grid")), zon.get(u32, "seed", 0), getToolTypeByID(zon.get([]const u8, "type", "cubyz:pickaxe")) orelse blk: { + const self = initFromCraftingGrid(extractItemsFromZon(zon.getChild("grid")), zon.get(u32, "seed", 0), ToolTypeIndex.fromId(zon.get([]const u8, "type", "cubyz:pickaxe")) orelse blk: { std.log.err("Couldn't find tool with type {s}. Replacing it with cubyz:pickaxe", .{zon.get([]const u8, "type", "cubyz:pickaxe")}); - break :blk getToolTypeByID("cubyz:pickaxe") orelse @panic("cubyz:pickaxe tool not found. Did you load the game with the correct assets?"); + break :blk ToolTypeIndex.fromId("cubyz:pickaxe") orelse @panic("cubyz:pickaxe tool not found. Did you load the game with the correct assets?"); }); self.durability = zon.get(u32, "durability", std.math.lossyCast(u32, self.maxDurability)); return self; @@ -643,7 +683,7 @@ pub const Tool = struct { // MARK: Tool zonObject.put("grid", zonArray); zonObject.put("durability", self.durability); zonObject.put("seed", self.seed); - zonObject.put("type", self.type.id); + zonObject.put("type", self.type.id()); return zonObject; } @@ -685,7 +725,7 @@ pub const Tool = struct { // MARK: Tool \\Damage: {d:.2} \\Durability: {}/{} , .{ - self.type.id, + self.type.id(), self.swingTime, self.damage, self.durability, @@ -708,7 +748,7 @@ pub const Tool = struct { // MARK: Tool damage = modifier.changeBlockDamage(damage, block); } for(block.blockTags()) |blockTag| { - for(self.type.blockTags) |toolTag| { + for(self.type.blockTags()) |toolTag| { if(toolTag == blockTag) return damage; } } @@ -874,7 +914,10 @@ pub const Recipe = struct { // MARK: Recipe }; var arena: main.heap.NeverFailingArenaAllocator = undefined; -var toolTypes: std.StringHashMap(ToolType) = undefined; + +var toolTypeList: ListUnmanaged(ToolType) = undefined; +var toolTypeIdToIndex: std.StringHashMapUnmanaged(ToolTypeIndex) = undefined; + var reverseIndices: std.StringHashMap(BaseItemIndex) = undefined; var modifiers: std.StringHashMap(*const Modifier.VTable) = undefined; var modifierRestrictions: std.StringHashMap(*const ModifierRestriction.VTable) = undefined; @@ -888,11 +931,7 @@ pub fn hasRegistered(id: []const u8) bool { } pub fn hasRegisteredTool(id: []const u8) bool { - return toolTypes.contains(id); -} - -pub fn toolTypeIterator() std.StringHashMap(ToolType).ValueIterator { - return toolTypes.valueIterator(); + return toolTypeIdToIndex.contains(id); } pub fn iterator() std.StringHashMap(BaseItemIndex).ValueIterator { @@ -905,7 +944,10 @@ pub fn recipes() []Recipe { pub fn globalInit() void { arena = .init(main.globalAllocator); - toolTypes = .init(arena.allocator().allocator); + + toolTypeList = .{}; + toolTypeIdToIndex = .{}; + reverseIndices = .init(arena.allocator().allocator); recipeList = .init(arena.allocator()); itemListSize = 0; @@ -982,7 +1024,7 @@ fn loadPixelSources(assetFolder: []const u8, id: []const u8, layerPostfix: []con } pub fn registerTool(assetFolder: []const u8, id: []const u8, zon: ZonElement) void { - if(toolTypes.contains(id)) { + if(toolTypeIdToIndex.contains(id)) { std.log.err("Registered tool type with id {s} twice!", .{id}); } var slotInfos: [25]SlotInfo = @splat(.{}); @@ -1000,9 +1042,9 @@ pub fn registerTool(assetFolder: []const u8, id: []const u8, zon: ZonElement) vo } slotInfos[i].optional = zonDisabled.as(usize, 0) != 0; } - var parameterMatrics: main.List(PropertyMatrix) = .init(arena.allocator()); + var parameterMatrices: main.List(PropertyMatrix) = .init(arena.allocator()); for(zon.getChild("parameters").toSlice()) |paramZon| { - const val = parameterMatrics.addOne(); + const val = parameterMatrices.addOne(); val.source = MaterialProperty.fromString(paramZon.get([]const u8, "source", "not specified")); val.destination = ToolProperty.fromString(paramZon.get([]const u8, "destination", "not specified")); val.resultScale = paramZon.get(f32, "factor", 1.0); @@ -1016,15 +1058,17 @@ pub fn registerTool(assetFolder: []const u8, id: []const u8, zon: ZonElement) vo loadPixelSources(assetFolder, id, "", &pixelSources); var pixelSourcesOverlay: [16][16]u8 = undefined; loadPixelSources(assetFolder, id, "_overlay", &pixelSourcesOverlay); + const idDupe = arena.allocator().dupe(u8, id); - toolTypes.put(idDupe, .{ + toolTypeList.append(arena.allocator(), .{ .id = idDupe, .blockTags = Tag.loadTagsFromZon(arena.allocator(), zon.getChild("blockTags")), .slotInfos = slotInfos, - .properties = parameterMatrics.toOwnedSlice(), + .properties = parameterMatrices.toOwnedSlice(), .pixelSources = pixelSources, .pixelSourcesOverlay = pixelSourcesOverlay, - }) catch unreachable; + }); + toolTypeIdToIndex.put(arena.allocator().allocator, idDupe, .{.index = @intCast(toolTypeList.items.len - 1)}) catch unreachable; std.log.debug("Registered tool: '{s}'", .{id}); } @@ -1071,7 +1115,8 @@ pub fn registerRecipes(zon: ZonElement) void { } pub fn reset() void { - toolTypes.clearAndFree(); + toolTypeList.clearAndFree(arena.allocator()); + toolTypeIdToIndex.clearAndFree(arena.allocator().allocator); reverseIndices.clearAndFree(); for(recipeList.items) |recipe| { if(recipe.cachedInventory) |inv| { @@ -1084,7 +1129,8 @@ pub fn reset() void { } pub fn deinit() void { - toolTypes.clearAndFree(); + toolTypeList.deinit(arena.allocator()); + toolTypeIdToIndex.deinit(arena.allocator().allocator); reverseIndices.clearAndFree(); for(recipeList.items) |recipe| { if(recipe.cachedInventory) |inv| { @@ -1097,12 +1143,3 @@ pub fn deinit() void { arena.deinit(); Inventory.Sync.ClientSide.deinit(); } - -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; - } -}