import type { InventoryTypeDefinition, SlotDefinition } from '../types' const SLOT_SIZE = 18 type RawSlot = Omit & { index?: number } function withSequentialIndexes(slots: RawSlot[]): SlotDefinition[] { let next = 0 return slots.map((slot) => { const index = slot.index !== undefined ? slot.index : next next = index + 1 return { ...slot, index } }) } function playerInv(yOffset: number, xStart = 8): RawSlot[] { const slots: RawSlot[] = [] for (let row = 0; row < 3; row++) { for (let col = 0; col < 9; col++) { slots.push({ x: xStart + col * SLOT_SIZE, y: yOffset + row * SLOT_SIZE, group: 'inventory', }) } } for (let col = 0; col < 9; col++) { slots.push({ x: xStart + col * SLOT_SIZE, y: yOffset + 58, group: 'hotbar', }) } return slots } function hotbarSlots(yOffset: number, xOffset = 8): RawSlot[] { return Array.from({ length: 9 }, (_, col) => ({ x: xOffset + col * SLOT_SIZE, y: yOffset, group: 'hotbar', })) } function gridSlots( cols: number, rows: number, x: number, y: number, group: string, ): RawSlot[] { const slots: RawSlot[] = [] for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { slots.push({ x: x + col * SLOT_SIZE, y: y + row * SLOT_SIZE, group, }) } } return slots } // Slot positions within gui/widgets hotbar texture — matches vanilla Gui.java: // item area at x: 3, y: 3, 20px per slot (16 item + 4 border/separator) const HUD_SLOT_STEP = 20 function hudHotbarSlots(): RawSlot[] { return Array.from({ length: 9 }, (_, col) => ({ // First slot carries explicit index: 36 so the running counter starts there ...(col === 0 ? { index: 36 } : {}), x: 3 + col * HUD_SLOT_STEP, y: 3, group: 'hotbar', })) } type RawInventoryDefinition = Omit & { slots: RawSlot[] } const makeInventoryDefinitions = ( inv: Record, ): Record => Object.fromEntries( Object.entries(inv).map(([k, v]) => [ k, { ...(v as RawInventoryDefinition), slots: withSequentialIndexes((v as RawInventoryDefinition).slots) }, ]), ) as Record /** * Canonical inventory GUIs. Optional `aliases` lists protocol / prismarine-windows * names that map to each `name` (see {@link getInventoryType} in `./index.ts`). */ export const inventoryDefinitions = makeInventoryDefinitions({ player: { name: 'player', aliases: ['inventory'], title: 'Inventory', backgroundTexture: '1.21.11/textures/gui/container/inventory.png', backgroundWidth: 176, backgroundHeight: 166, entityDisplay: { x: 26, y: 8, width: 49, height: 70 }, entityPlaceholder: 'player', slots: [ // Result (0) { x: 154, y: 28, group: 'result', resultSlot: true }, // Crafting 2x2 (1-4) ...gridSlots(2, 2, 98, 18, 'crafting'), // Armor head-to-feet (5-8) { x: 8, y: 8, group: 'armor', label: 'Head' }, { x: 8, y: 26, group: 'armor', label: 'Chest' }, { x: 8, y: 44, group: 'armor', label: 'Legs' }, { x: 8, y: 62, group: 'armor', label: 'Feet' }, // Player inventory 9-35, hotbar 36-44 ...playerInv(84), // Offhand (45) — must come after playerInv so auto-index lands at 45 { x: 77, y: 62, group: 'offhand', label: 'Offhand' }, ], }, chest: { name: 'chest', title: 'Chest', backgroundTexture: '1.21.11/textures/gui/container/shulker_box.png', backgroundWidth: 176, backgroundHeight: 166, playerInventoryOffset: { x: 8, y: 84 }, slots: [ ...gridSlots(9, 3, 8, 18, 'container'), ...playerInv(84), ], }, // generic_9x1..9x6 all use generic_54.png (the 6-row chest texture, 176×222). // InventoryBackground canvas-stitches rows < 6: takes the top N rows from the source // (y=0..topH-1, where topH = N*18+17) then the player-inventory section starting at // y=SRC_PLAYER_Y=125 and composites them. // Output height formula: N*18+17 + (222-125) = N*18+17+97 = N*18+114. // Slot formula: container at y=18, player at y = N*18+30 (13px frame into player section). generic_9x1: { name: 'generic_9x1', title: 'Container', backgroundTexture: '1.21.11/textures/gui/container/generic_54.png', backgroundWidth: 176, backgroundHeight: 132, // 1*18 + 114 containerRows: 1, slots: [ ...gridSlots(9, 1, 8, 18, 'container'), ...playerInv(50), // 1*18 + 30 + 2px offset below ], }, generic_9x2: { name: 'generic_9x2', title: 'Container', backgroundTexture: '1.21.11/textures/gui/container/generic_54.png', backgroundWidth: 176, backgroundHeight: 150, // 2*18 + 114 containerRows: 2, slots: [ ...gridSlots(9, 2, 8, 18, 'container'), ...playerInv(68), // 2*18 + 30 + 2px offset below ], }, generic_9x3: { name: 'generic_9x3', title: 'Container', backgroundTexture: '1.21.11/textures/gui/container/generic_54.png', backgroundWidth: 176, backgroundHeight: 168, // 3*18 + 114 containerRows: 3, playerInventoryOffset: { x: 8, y: 82 }, slots: [ ...gridSlots(9, 3, 8, 18, 'container'), ...playerInv(86), // 3*18 + 30 + 2px offset below ], }, generic_9x4: { name: 'generic_9x4', title: 'Container', backgroundTexture: '1.21.11/textures/gui/container/generic_54.png', backgroundWidth: 176, backgroundHeight: 186, // 4*18 + 114 containerRows: 4, slots: [ ...gridSlots(9, 4, 8, 18, 'container'), ...playerInv(104), // 4*18 + 30 + 2px offset below ], }, generic_9x5: { name: 'generic_9x5', title: 'Container', backgroundTexture: '1.21.11/textures/gui/container/generic_54.png', backgroundWidth: 176, backgroundHeight: 204, // 5*18 + 114 containerRows: 5, slots: [ ...gridSlots(9, 5, 8, 18, 'container'), ...playerInv(122), // 5*18 + 30 + 2px offset below ], }, generic_9x6: { name: 'generic_9x6', title: 'Container', backgroundTexture: '1.21.11/textures/gui/container/generic_54.png', backgroundWidth: 176, backgroundHeight: 222, // full 6-row texture, no stitching needed (N*18+114 = 222) playerInventoryOffset: { x: 8, y: 140 }, containerRows: 6, slots: [ ...gridSlots(9, 6, 8, 18, 'container'), ...playerInv(140), // matches large_chest ], }, large_chest: { name: 'large_chest', title: 'Large Chest', backgroundTexture: '1.21.11/textures/gui/container/generic_54.png', backgroundWidth: 176, backgroundHeight: 222, containerRows: 6, playerInventoryOffset: { x: 8, y: 138 }, slots: [ ...gridSlots(9, 6, 8, 18, 'container'), ...playerInv(140), ], }, crafting_table: { name: 'crafting_table', aliases: ['crafting', 'crafting3x3'], title: 'Crafting', backgroundTexture: '1.21.11/textures/gui/container/crafting_table.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ { x: 124, y: 35, group: 'result', resultSlot: true }, ...gridSlots(3, 3, 30, 17, 'crafting'), ...playerInv(84), ], }, furnace: { name: 'furnace', title: 'Furnace', backgroundTexture: '1.21.11/textures/gui/container/furnace.png', backgroundWidth: 176, backgroundHeight: 166, properties: { litTime: { dataSlot: 0, description: 'Fuel burn time remaining' }, litDuration: { dataSlot: 1, description: 'Max fuel burn time' }, cookingProgress: { dataSlot: 2, description: 'Cook progress (0-200)' }, totalCookTime: { dataSlot: 3, description: 'Total cook time' }, }, progressBars: [ { id: 'fire', x: 56, y: 36, width: 14, height: 14, direction: 'up', textureX: 0, textureY: 0, spriteTexture: '1.21.11/textures/gui/sprites/container/furnace/lit_progress.png', getValue: (p) => p.litTime ?? 0, getMax: (p) => p.litDuration || 200, }, { id: 'arrow', x: 79, y: 34, width: 24, height: 16, direction: 'right', textureX: 0, textureY: 0, spriteTexture: '1.21.11/textures/gui/sprites/container/furnace/burn_progress.png', getValue: (p) => p.cookingProgress ?? 0, getMax: (p) => p.totalCookTime || 200, }, ], slots: [ { x: 56, y: 17, group: 'input' }, { x: 56, y: 53, group: 'fuel', fuelSlot: true }, { x: 116, y: 35, group: 'result', resultSlot: true }, ...playerInv(84), ], }, blast_furnace: { name: 'blast_furnace', title: 'Blast Furnace', backgroundTexture: '1.21.11/textures/gui/container/blast_furnace.png', backgroundWidth: 176, backgroundHeight: 166, properties: { litTime: { dataSlot: 0, description: 'Fuel burn time remaining' }, litDuration: { dataSlot: 1, description: 'Max fuel burn time' }, cookingProgress: { dataSlot: 2, description: 'Cook progress (0-200)' }, totalCookTime: { dataSlot: 3, description: 'Total cook time' }, }, progressBars: [ { id: 'fire', x: 56, y: 36, width: 14, height: 14, direction: 'up', textureX: 0, textureY: 0, spriteTexture: '1.21.11/textures/gui/sprites/container/blast_furnace/lit_progress.png', getValue: (p) => p.litTime ?? 0, getMax: (p) => p.litDuration || 200, }, { id: 'arrow', x: 79, y: 34, width: 24, height: 16, direction: 'right', textureX: 0, textureY: 0, spriteTexture: '1.21.11/textures/gui/sprites/container/blast_furnace/burn_progress.png', getValue: (p) => p.cookingProgress ?? 0, getMax: (p) => p.totalCookTime || 200, }, ], slots: [ { x: 56, y: 17, group: 'input' }, { x: 56, y: 53, group: 'fuel', fuelSlot: true }, { x: 116, y: 35, group: 'result', resultSlot: true }, ...playerInv(84), ], }, smoker: { name: 'smoker', title: 'Smoker', backgroundTexture: '1.21.11/textures/gui/container/smoker.png', backgroundWidth: 176, backgroundHeight: 166, properties: { litTime: { dataSlot: 0, description: 'Fuel burn time remaining' }, litDuration: { dataSlot: 1, description: 'Max fuel burn time' }, cookingProgress: { dataSlot: 2, description: 'Cook progress (0-200)' }, totalCookTime: { dataSlot: 3, description: 'Total cook time' }, }, progressBars: [ { id: 'fire', x: 56, y: 36, width: 14, height: 14, direction: 'up', textureX: 0, textureY: 0, spriteTexture: '1.21.11/textures/gui/sprites/container/smoker/lit_progress.png', getValue: (p) => p.litTime ?? 0, getMax: (p) => p.litDuration || 200, }, { id: 'arrow', x: 79, y: 34, width: 24, height: 16, direction: 'right', textureX: 0, textureY: 0, spriteTexture: '1.21.11/textures/gui/sprites/container/smoker/burn_progress.png', getValue: (p) => p.cookingProgress ?? 0, getMax: (p) => p.totalCookTime || 200, }, ], slots: [ { x: 56, y: 17, group: 'input' }, { x: 56, y: 53, group: 'fuel', fuelSlot: true }, { x: 116, y: 35, group: 'result', resultSlot: true }, ...playerInv(84), ], }, brewing_stand: { name: 'brewing_stand', title: 'Brewing Stand', backgroundTexture: '1.21.11/textures/gui/container/brewing_stand.png', backgroundWidth: 176, backgroundHeight: 166, properties: { brewTime: { dataSlot: 0, description: 'Brew time remaining (0-400)' }, fuelLevel: { dataSlot: 1, description: 'Fuel level (0-20)' }, }, progressBars: [ { id: 'brew_arrow', x: 97, y: 16, width: 9, height: 28, direction: 'down', textureX: 0, textureY: 0, spriteTexture: '1.21.11/textures/gui/sprites/container/brewing_stand/brew_progress.png', getValue: (p) => 400 - (p.brewTime ?? 400), getMax: () => 400, }, { id: 'fuel', x: 18, y: 44, width: 18, height: 4, direction: 'right', textureX: 0, textureY: 0, spriteTexture: '1.21.11/textures/gui/sprites/container/brewing_stand/fuel_length.png', getValue: (p) => p.fuelLevel ?? 0, getMax: () => 20, }, ], slots: [ { x: 56, y: 51, group: 'bottle', label: 'Left' }, { x: 79, y: 58, group: 'bottle', label: 'Center' }, { x: 102, y: 51, group: 'bottle', label: 'Right' }, { x: 79, y: 17, group: 'ingredient' }, { x: 17, y: 17, group: 'fuel', fuelSlot: true }, ...playerInv(84), ], }, anvil: { name: 'anvil', title: 'Repair & Name', backgroundTexture: '1.21.11/textures/gui/container/anvil.png', backgroundWidth: 176, backgroundHeight: 166, titleOffset: { x: 52, y: 0 }, properties: { repairCost: { dataSlot: 0, description: 'Level cost' }, }, slots: [ { x: 27, y: 47, group: 'input' }, { x: 76, y: 47, group: 'input' }, { x: 134, y: 47, group: 'result', resultSlot: true }, ...playerInv(84), ], }, grindstone: { name: 'grindstone', title: 'Repair & Disenchant', backgroundTexture: '1.21.11/textures/gui/container/grindstone.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ { x: 49, y: 19, group: 'input' }, { x: 49, y: 40, group: 'input' }, { x: 129, y: 34, group: 'result', resultSlot: true }, ...playerInv(84), ], }, enchanting_table: { name: 'enchanting_table', aliases: ['enchantment'], title: 'Enchant', backgroundTexture: '1.21.11/textures/gui/container/enchanting_table.png', backgroundWidth: 176, backgroundHeight: 166, properties: { topEnchantLevel: { dataSlot: 0, description: 'Top enchantment level' }, middleEnchantLevel: { dataSlot: 1, description: 'Middle enchantment level' }, bottomEnchantLevel: { dataSlot: 2, description: 'Bottom enchantment level' }, seed: { dataSlot: 3, description: 'Random seed' }, topEnchantId: { dataSlot: 4, description: 'Top enchantment ID' }, middleEnchantId: { dataSlot: 5, description: 'Middle enchantment ID' }, bottomEnchantId: { dataSlot: 6, description: 'Bottom enchantment ID' }, topLevelClue: { dataSlot: 7, description: 'Top enchantment level clue (e.g. III)' }, middleLevelClue: { dataSlot: 8, description: 'Middle enchantment level clue (e.g. II)' }, bottomLevelClue: { dataSlot: 9, description: 'Bottom enchantment level clue (e.g. I)' }, }, slots: [ { x: 15, y: 47, group: 'enchant' }, { x: 35, y: 47, group: 'lapis', label: 'Lapis Lazuli' }, ...playerInv(84), ], }, smithing_table: { name: 'smithing_table', aliases: ['smithing'], title: 'Upgrade Gear', backgroundTexture: '1.21.11/textures/gui/container/smithing.png', backgroundWidth: 176, backgroundHeight: 166, titleOffset: { x: 40, y: 13, }, slots: [ { x: 8, y: 48, group: 'template', label: 'Template' }, { x: 26, y: 48, group: 'input', label: 'Base' }, { x: 44, y: 48, group: 'addition', label: 'Material' }, { x: 98, y: 48, group: 'result', resultSlot: true }, ...playerInv(84), ], }, smithing_table_legacy: { name: 'smithing_table_legacy', title: 'Upgrade Gear', backgroundTexture: '1.16.4/textures/gui/container/smithing.png', backgroundWidth: 176, backgroundHeight: 166, titleOffset: { x: 50, y: 13, }, slots: [ { x: 27, y: 47, group: 'input', label: 'Base' }, { x: 76, y: 47, group: 'addition', label: 'Material' }, { x: 134, y: 47, group: 'result', resultSlot: true }, ...playerInv(84), ], }, hopper: { name: 'hopper', title: 'Item Hopper', backgroundTexture: '1.21.11/textures/gui/container/hopper.png', backgroundWidth: 176, backgroundHeight: 133, slots: [ ...gridSlots(5, 1, 44, 20, 'container'), ...gridSlots(9, 3, 8, 51, 'inventory'), ...hotbarSlots(109), ], }, dispenser: { name: 'dispenser', /** wiki `generic_3x3`; same 3×3 + player layout as dropper */ aliases: ['generic_3x3'], title: 'Dispenser', backgroundTexture: '1.21.11/textures/gui/container/dispenser.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ ...gridSlots(3, 3, 62, 17, 'container'), ...playerInv(84), ], }, dropper: { name: 'dropper', title: 'Dropper', backgroundTexture: '1.21.11/textures/gui/container/dispenser.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ ...gridSlots(3, 3, 62, 17, 'container'), ...playerInv(84), ], }, beacon: { name: 'beacon', title: '', backgroundTexture: '1.21.11/textures/gui/container/beacon.png', backgroundWidth: 230, backgroundHeight: 219, properties: { levels: { dataSlot: 0, description: 'Beacon pyramid level (0-4)' }, primaryEffect: { dataSlot: 1, description: 'Primary effect (encoded: 0=none, registry_id+1)' }, secondaryEffect: { dataSlot: 2, description: 'Secondary effect (encoded: 0=none, registry_id+1)' }, }, slots: [ { x: 136, y: 110, group: 'payment', label: 'Payment' }, ...playerInv(137, 36), ], }, horse: { name: 'horse', aliases: ['EntityHorse'], title: 'Horse', backgroundTexture: '1.21.11/textures/gui/container/horse.png', backgroundWidth: 176, backgroundHeight: 166, entityDisplay: { x: 26, y: 18, width: 52, height: 52 }, entityPlaceholder: 'horse', slots: [ { x: 8, y: 18, group: 'saddle', label: 'Saddle' }, { x: 8, y: 36, group: 'armor', label: 'Horse Armor' }, ...playerInv(84), ], }, donkey: { name: 'donkey', title: 'Donkey', backgroundTexture: '1.21.11/textures/gui/container/horse.png', backgroundWidth: 176, backgroundHeight: 166, entityDisplay: { x: 26, y: 18, width: 52, height: 52 }, entityPlaceholder: 'horse', slots: [ // Saddle (0); slot 1 (horse armor) is absent for donkeys — gap is intentional { x: 8, y: 18, group: 'saddle', label: 'Saddle' }, // Chest items start at index 2; explicit index jumps the counter over the gap ...gridSlots(5, 3, 80, 18, 'chest').map((s, i) => i === 0 ? { ...s, index: 2 } : s), ...playerInv(84), ], }, llama: { name: 'llama', title: 'Llama', backgroundTexture: '1.21.11/textures/gui/container/horse.png', backgroundWidth: 176, backgroundHeight: 166, entityDisplay: { x: 26, y: 18, width: 52, height: 52 }, entityPlaceholder: 'llama', slots: [ { x: 8, y: 18, group: 'saddle', label: 'Carpet' }, ...gridSlots(5, 3, 80, 18, 'chest').map((s, i) => i === 0 ? { ...s, index: 2 } : s), ...playerInv(84), ], }, villager: { name: 'villager', aliases: ['merchant'], title: 'Villager', backgroundTexture: '1.14/textures/gui/container/villager2.png', backgroundWidth: 276, backgroundHeight: 166, slots: [ { x: 136, y: 37, group: 'trade_input1' }, { x: 162, y: 37, group: 'trade_input2' }, { x: 216, y: 37, group: 'trade_result', resultSlot: true }, ...gridSlots(9, 3, 108, 84, 'inventory'), ...hotbarSlots(142, 108), ], }, shulker_box: { name: 'shulker_box', title: 'Shulker Box', backgroundTexture: '1.21.11/textures/gui/container/shulker_box.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ ...gridSlots(9, 3, 8, 18, 'container'), ...playerInv(84), ], }, barrel: { name: 'barrel', title: 'Barrel', backgroundTexture: '1.21.11/textures/gui/container/shulker_box.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ ...gridSlots(9, 3, 8, 18, 'container'), ...playerInv(84), ], }, cartography_table: { name: 'cartography_table', aliases: ['cartography'], title: 'Cartography Table', backgroundTexture: '1.21.11/textures/gui/container/cartography_table.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ { x: 15, y: 15, group: 'input', label: 'Map' }, { x: 15, y: 52, group: 'input', label: 'Paper/Map' }, { x: 145, y: 39, group: 'result', resultSlot: true }, ...playerInv(84), ], }, loom: { name: 'loom', title: 'Loom', backgroundTexture: '1.21.11/textures/gui/container/loom.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ { x: 13, y: 26, group: 'input', label: 'Banner' }, { x: 33, y: 26, group: 'input', label: 'Dye' }, { x: 23, y: 45, group: 'input', label: 'Pattern' }, { x: 143, y: 58, group: 'result', resultSlot: true }, ...playerInv(84), ], }, stonecutter: { name: 'stonecutter', title: 'Stonecutter', backgroundTexture: '1.21.11/textures/gui/container/stonecutter.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ { x: 20, y: 33, group: 'input' }, { x: 143, y: 33, group: 'result', resultSlot: true }, ...playerInv(84), ], }, crafter: { name: 'crafter', aliases: ['crafter_3x3'], title: 'Crafter', backgroundTexture: '1.21.11/textures/gui/container/crafter.png', backgroundWidth: 176, backgroundHeight: 166, slots: [ ...gridSlots(3, 3, 26, 17, 'crafting'), { x: 134, y: 35, group: 'result', resultSlot: true }, ...playerInv(84), ], }, creative: { name: 'creative', title: 'Creative Inventory', backgroundTexture: '1.21.11/textures/gui/container/creative_inventory/tab_items.png', backgroundWidth: 195, backgroundHeight: 136, slots: [ ...gridSlots(9, 5, 9, 48, 'body'), // Creative hotbar indices start at 0 (separate window mapping), explicit to override counter ...hotbarSlots(142).map((s, i) => ({ ...s, index: i })), ], }, // Standalone hotbar HUD container — mirrors layouts.mjs `Hotbar` // Background: gui/widgets (182×22 hotbar strip), slots at HUD pixel coords // Indices 36–44 are the standard player hotbar hotbar: { name: 'hotbar', title: '', backgroundTexture: '1.15/textures/gui/widgets.png', backgroundWidth: 182, backgroundHeight: 22, slots: [ // 9 hotbar slots (36–44) within the 182×22 hotbar strip. // index: 36 on the first slot starts the running counter at 36. ...hudHotbarSlots(), ], }, }) /** * Extra mc-assets texture paths that must be bundled by `scripts/generate-texture-imports.mjs` * beyond the `backgroundTexture` fields already found in `inventoryDefinitions`. * * Add paths here when a component uses `textures.getGuiTextureUrl(path)` for a texture * that is NOT already a `backgroundTexture` in any inventory definition (e.g. UI sprites). * * Format: versioned mc-assets path, e.g. "1.21.11/textures/gui/sprites/container/anvil/text_field.png" */ export const registryExtraTextures: string[] = [ // Anvil rename input field sprites (used by AnvilInput component) '1.21.11/textures/gui/sprites/container/anvil/text_field.png', '1.21.11/textures/gui/sprites/container/anvil/text_field_disabled.png', // Furnace / blast furnace / smoker progress bar sprites '1.21.11/textures/gui/sprites/container/furnace/lit_progress.png', '1.21.11/textures/gui/sprites/container/furnace/burn_progress.png', '1.21.11/textures/gui/sprites/container/blast_furnace/lit_progress.png', '1.21.11/textures/gui/sprites/container/blast_furnace/burn_progress.png', '1.21.11/textures/gui/sprites/container/smoker/lit_progress.png', '1.21.11/textures/gui/sprites/container/smoker/burn_progress.png', // Brewing stand progress bar sprites '1.21.11/textures/gui/sprites/container/brewing_stand/brew_progress.png', '1.21.11/textures/gui/sprites/container/brewing_stand/fuel_length.png', // Enchanting table slot backgrounds & level icons '1.21.11/textures/gui/sprites/container/enchanting_table/enchantment_slot.png', '1.21.11/textures/gui/sprites/container/enchanting_table/enchantment_slot_disabled.png', '1.21.11/textures/gui/sprites/container/enchanting_table/enchantment_slot_highlighted.png', '1.21.11/textures/gui/sprites/container/enchanting_table/level_1.png', '1.21.11/textures/gui/sprites/container/enchanting_table/level_2.png', '1.21.11/textures/gui/sprites/container/enchanting_table/level_3.png', '1.21.11/textures/gui/sprites/container/enchanting_table/level_1_disabled.png', '1.21.11/textures/gui/sprites/container/enchanting_table/level_2_disabled.png', '1.21.11/textures/gui/sprites/container/enchanting_table/level_3_disabled.png', // Beacon button sprites '1.21.11/textures/gui/sprites/container/beacon/button.png', '1.21.11/textures/gui/sprites/container/beacon/button_disabled.png', '1.21.11/textures/gui/sprites/container/beacon/button_selected.png', '1.21.11/textures/gui/sprites/container/beacon/button_highlighted.png', '1.21.11/textures/gui/sprites/container/beacon/confirm.png', '1.21.11/textures/gui/sprites/container/beacon/cancel.png', // Beacon mob effect icons '1.21.11/textures/mob_effect/speed.png', '1.21.11/textures/mob_effect/haste.png', '1.21.11/textures/mob_effect/resistance.png', '1.21.11/textures/mob_effect/jump_boost.png', '1.21.11/textures/mob_effect/strength.png', '1.21.11/textures/mob_effect/regeneration.png', ]