minecraft-inventory 0.1.28 → 0.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/assets/beacon/diamond.png +0 -0
- package/src/assets/beacon/emerald.png +0 -0
- package/src/assets/beacon/gold_ingot.png +0 -0
- package/src/assets/beacon/iron_ingot.png +0 -0
- package/src/assets/beacon/netherite_ingot.png +0 -0
- package/src/components/InventoryOverlay/InventoryOverlay.tsx +1 -1
- package/src/components/InventoryWindow/BeaconEffects.tsx +350 -0
- package/src/components/InventoryWindow/InventoryWindow.tsx +7 -1
- package/src/connector/mineflayer.ts +13 -7
- package/src/generated/localTextures.ts +36 -0
- package/src/registry/inventories.ts +23 -4
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react'
|
|
2
|
+
import { useInventoryContext } from '../../context/InventoryContext'
|
|
3
|
+
import { useTextures } from '../../context/TextureContext'
|
|
4
|
+
import { useScale } from '../../context/ScaleContext'
|
|
5
|
+
|
|
6
|
+
// Bundled payment item textures (not available via texture provider in the full client)
|
|
7
|
+
import netherite_ingot_png from '../../assets/beacon/netherite_ingot.png'
|
|
8
|
+
import emerald_png from '../../assets/beacon/emerald.png'
|
|
9
|
+
import diamond_png from '../../assets/beacon/diamond.png'
|
|
10
|
+
import gold_ingot_png from '../../assets/beacon/gold_ingot.png'
|
|
11
|
+
import iron_ingot_png from '../../assets/beacon/iron_ingot.png'
|
|
12
|
+
|
|
13
|
+
const SPRITE_BASE = '1.21.11/textures/gui/sprites/container/beacon'
|
|
14
|
+
const MOB_EFFECT_BASE = '1.21.11/textures/mob_effect'
|
|
15
|
+
|
|
16
|
+
// Effect IDs matching vanilla BeaconMenu.encodeEffect: registry_id + 1
|
|
17
|
+
// ContainerData: ≤0 = none, 1+ = effect (1-based)
|
|
18
|
+
// Protocol set_beacon_effect option(varint) uses the same 1-based encoding
|
|
19
|
+
const EFFECTS = {
|
|
20
|
+
NONE: -1,
|
|
21
|
+
SPEED: 1, // registry 0 + 1
|
|
22
|
+
HASTE: 3, // registry 2 + 1
|
|
23
|
+
STRENGTH: 5, // registry 4 + 1
|
|
24
|
+
JUMP_BOOST: 8, // registry 7 + 1
|
|
25
|
+
REGENERATION: 10, // registry 9 + 1
|
|
26
|
+
RESISTANCE: 11, // registry 10 + 1
|
|
27
|
+
} as const
|
|
28
|
+
|
|
29
|
+
const EFFECT_INFO: Record<number, { name: string; sprite: string }> = {
|
|
30
|
+
[EFFECTS.SPEED]: { name: 'Speed', sprite: 'speed' },
|
|
31
|
+
[EFFECTS.HASTE]: { name: 'Haste', sprite: 'haste' },
|
|
32
|
+
[EFFECTS.RESISTANCE]: { name: 'Resistance', sprite: 'resistance' },
|
|
33
|
+
[EFFECTS.JUMP_BOOST]: { name: 'Jump Boost', sprite: 'jump_boost' },
|
|
34
|
+
[EFFECTS.STRENGTH]: { name: 'Strength', sprite: 'strength' },
|
|
35
|
+
[EFFECTS.REGENERATION]: { name: 'Regeneration', sprite: 'regeneration' },
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Primary buttons: 3 tiers of effects
|
|
39
|
+
const PRIMARY_TIERS: { tier: number; y: number; effects: number[] }[] = [
|
|
40
|
+
{ tier: 0, y: 22, effects: [EFFECTS.SPEED, EFFECTS.HASTE] },
|
|
41
|
+
{ tier: 1, y: 47, effects: [EFFECTS.RESISTANCE, EFFECTS.JUMP_BOOST] },
|
|
42
|
+
{ tier: 2, y: 72, effects: [EFFECTS.STRENGTH] },
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
const PRIMARY_CENTER_X = 76
|
|
46
|
+
|
|
47
|
+
// Payment indicator items shown next to the payment slot (vanilla renderBg)
|
|
48
|
+
const PAYMENT_ITEMS: { src: string; x: number }[] = [
|
|
49
|
+
{ src: netherite_ingot_png, x: 20 },
|
|
50
|
+
{ src: emerald_png, x: 41 },
|
|
51
|
+
{ src: diamond_png, x: 63 },
|
|
52
|
+
{ src: gold_ingot_png, x: 86 },
|
|
53
|
+
{ src: iron_ingot_png, x: 108 },
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
interface BeaconEffectsProps {
|
|
57
|
+
properties: Record<string, number>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function BeaconEffects({ properties }: BeaconEffectsProps) {
|
|
61
|
+
const { sendAction, getSlot } = useInventoryContext()
|
|
62
|
+
const textures = useTextures()
|
|
63
|
+
const { scale } = useScale()
|
|
64
|
+
|
|
65
|
+
const levels = properties.levels ?? 0
|
|
66
|
+
// ContainerData: ≤0 means "no effect" (server sends -1 for uninitialized, vanilla sends 0)
|
|
67
|
+
const serverPrimary = (properties.primaryEffect ?? -1) > 0 ? properties.primaryEffect! : EFFECTS.NONE
|
|
68
|
+
const serverSecondary = (properties.secondaryEffect ?? -1) > 0 ? properties.secondaryEffect! : EFFECTS.NONE
|
|
69
|
+
|
|
70
|
+
const [selectedPrimary, setSelectedPrimary] = useState(serverPrimary)
|
|
71
|
+
const [selectedSecondary, setSelectedSecondary] = useState(serverSecondary)
|
|
72
|
+
const [hoveredButton, setHoveredButton] = useState<string | null>(null)
|
|
73
|
+
|
|
74
|
+
// Sync local state when server properties change
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
setSelectedPrimary(serverPrimary)
|
|
77
|
+
setSelectedSecondary(serverSecondary)
|
|
78
|
+
}, [serverPrimary, serverSecondary])
|
|
79
|
+
|
|
80
|
+
// Payment slot is index 0 in the beacon container
|
|
81
|
+
const paymentSlot = getSlot(0)
|
|
82
|
+
const hasPayment = paymentSlot?.item != null
|
|
83
|
+
|
|
84
|
+
// Confirm requires payment AND a primary selection (valid effects are > 0)
|
|
85
|
+
const canConfirm = hasPayment && selectedPrimary > 0
|
|
86
|
+
|
|
87
|
+
// Upgrade button mirrors the LOCAL selected primary (vanilla: BeaconScreen.this.primary)
|
|
88
|
+
const showUpgrade = selectedPrimary > 0
|
|
89
|
+
|
|
90
|
+
const getButtonSprite = (disabled: boolean, selected: boolean, hovered: boolean) => {
|
|
91
|
+
if (disabled) return textures.getGuiTextureUrl(`${SPRITE_BASE}/button_disabled.png`)
|
|
92
|
+
if (selected) return textures.getGuiTextureUrl(`${SPRITE_BASE}/button_selected.png`)
|
|
93
|
+
if (hovered) return textures.getGuiTextureUrl(`${SPRITE_BASE}/button_highlighted.png`)
|
|
94
|
+
return textures.getGuiTextureUrl(`${SPRITE_BASE}/button.png`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const getEffectSprite = (effect: number) => {
|
|
98
|
+
const info = EFFECT_INFO[effect]
|
|
99
|
+
if (!info) return undefined
|
|
100
|
+
return textures.getGuiTextureUrl(`${MOB_EFFECT_BASE}/${info.sprite}.png`)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const handleConfirm = () => {
|
|
104
|
+
if (!canConfirm) return
|
|
105
|
+
sendAction({
|
|
106
|
+
type: 'beacon',
|
|
107
|
+
primaryEffect: selectedPrimary,
|
|
108
|
+
secondaryEffect: selectedSecondary,
|
|
109
|
+
})
|
|
110
|
+
sendAction({ type: 'close' })
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const handleCancel = () => {
|
|
114
|
+
sendAction({ type: 'close' })
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Center buttons around a given X coordinate
|
|
118
|
+
const getButtonX = (centerX: number, index: number, count: number) => {
|
|
119
|
+
const totalWidth = count * 22 + (count - 1) * 2
|
|
120
|
+
return centerX + index * 24 - totalWidth / 2
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const renderEffectButton = (
|
|
124
|
+
effect: number,
|
|
125
|
+
x: number,
|
|
126
|
+
y: number,
|
|
127
|
+
disabled: boolean,
|
|
128
|
+
isSelected: boolean,
|
|
129
|
+
isPrimary: boolean,
|
|
130
|
+
key: string,
|
|
131
|
+
tooltip?: string,
|
|
132
|
+
) => {
|
|
133
|
+
const hovered = hoveredButton === key && !disabled
|
|
134
|
+
const info = EFFECT_INFO[effect]
|
|
135
|
+
const title = tooltip ?? info?.name
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<div
|
|
139
|
+
key={key}
|
|
140
|
+
onClick={() => {
|
|
141
|
+
if (disabled) return
|
|
142
|
+
if (isPrimary) {
|
|
143
|
+
setSelectedPrimary(effect)
|
|
144
|
+
} else {
|
|
145
|
+
setSelectedSecondary(effect)
|
|
146
|
+
}
|
|
147
|
+
}}
|
|
148
|
+
onMouseEnter={() => setHoveredButton(key)}
|
|
149
|
+
onMouseLeave={() => setHoveredButton(null)}
|
|
150
|
+
title={title}
|
|
151
|
+
style={{
|
|
152
|
+
position: 'absolute',
|
|
153
|
+
left: x * scale,
|
|
154
|
+
top: y * scale,
|
|
155
|
+
width: 22 * scale,
|
|
156
|
+
height: 22 * scale,
|
|
157
|
+
cursor: disabled ? 'default' : 'pointer',
|
|
158
|
+
}}
|
|
159
|
+
>
|
|
160
|
+
<img
|
|
161
|
+
src={getButtonSprite(disabled, isSelected, hovered)}
|
|
162
|
+
alt=""
|
|
163
|
+
draggable={false}
|
|
164
|
+
style={{
|
|
165
|
+
position: 'absolute',
|
|
166
|
+
left: 0,
|
|
167
|
+
top: 0,
|
|
168
|
+
width: 22 * scale,
|
|
169
|
+
height: 22 * scale,
|
|
170
|
+
imageRendering: 'pixelated',
|
|
171
|
+
}}
|
|
172
|
+
/>
|
|
173
|
+
{getEffectSprite(effect) && (
|
|
174
|
+
<img
|
|
175
|
+
src={getEffectSprite(effect)}
|
|
176
|
+
alt=""
|
|
177
|
+
draggable={false}
|
|
178
|
+
style={{
|
|
179
|
+
position: 'absolute',
|
|
180
|
+
left: 2 * scale,
|
|
181
|
+
top: 2 * scale,
|
|
182
|
+
width: 18 * scale,
|
|
183
|
+
height: 18 * scale,
|
|
184
|
+
imageRendering: 'pixelated',
|
|
185
|
+
}}
|
|
186
|
+
/>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const labelStyle = (x: number): React.CSSProperties => ({
|
|
193
|
+
position: 'absolute',
|
|
194
|
+
left: x * scale,
|
|
195
|
+
top: 10 * scale,
|
|
196
|
+
fontSize: 8 * scale,
|
|
197
|
+
fontFamily: "'Minecraft', monospace",
|
|
198
|
+
color: '#E0E0E0',
|
|
199
|
+
textShadow: 'none',
|
|
200
|
+
transform: 'translateX(-50%)',
|
|
201
|
+
whiteSpace: 'nowrap',
|
|
202
|
+
pointerEvents: 'none',
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<>
|
|
207
|
+
{/* Labels */}
|
|
208
|
+
<span style={labelStyle(62)}>Primary Power</span>
|
|
209
|
+
<span style={labelStyle(169)}>Secondary Power</span>
|
|
210
|
+
|
|
211
|
+
{/* Payment item indicators (decorative icons showing valid payment items) */}
|
|
212
|
+
{PAYMENT_ITEMS.map(({ src, x }) => (
|
|
213
|
+
<img
|
|
214
|
+
key={`pay-${x}`}
|
|
215
|
+
src={src}
|
|
216
|
+
alt=""
|
|
217
|
+
draggable={false}
|
|
218
|
+
style={{
|
|
219
|
+
position: 'absolute',
|
|
220
|
+
left: x * scale,
|
|
221
|
+
top: 109 * scale,
|
|
222
|
+
width: 16 * scale,
|
|
223
|
+
height: 16 * scale,
|
|
224
|
+
imageRendering: 'pixelated',
|
|
225
|
+
pointerEvents: 'none',
|
|
226
|
+
}}
|
|
227
|
+
/>
|
|
228
|
+
))}
|
|
229
|
+
|
|
230
|
+
{/* Primary effect buttons (3 tiers) */}
|
|
231
|
+
{PRIMARY_TIERS.map(({ tier, y, effects }) =>
|
|
232
|
+
effects.map((effect, idx) => {
|
|
233
|
+
const x = getButtonX(PRIMARY_CENTER_X, idx, effects.length)
|
|
234
|
+
const disabled = tier >= levels
|
|
235
|
+
const isSelected = selectedPrimary === effect
|
|
236
|
+
return renderEffectButton(effect, x, y, disabled, isSelected, true, `primary-${effect}`)
|
|
237
|
+
})
|
|
238
|
+
)}
|
|
239
|
+
|
|
240
|
+
{/* Secondary: Regeneration button (fixed position x=144) */}
|
|
241
|
+
{renderEffectButton(
|
|
242
|
+
EFFECTS.REGENERATION,
|
|
243
|
+
144,
|
|
244
|
+
47,
|
|
245
|
+
3 >= levels,
|
|
246
|
+
selectedSecondary === EFFECTS.REGENERATION,
|
|
247
|
+
false,
|
|
248
|
+
'secondary-regen',
|
|
249
|
+
)}
|
|
250
|
+
|
|
251
|
+
{/* Secondary: Upgrade button (fixed position x=168, mirrors local primary selection) */}
|
|
252
|
+
{showUpgrade && renderEffectButton(
|
|
253
|
+
selectedPrimary,
|
|
254
|
+
168,
|
|
255
|
+
47,
|
|
256
|
+
3 >= levels,
|
|
257
|
+
selectedSecondary === selectedPrimary,
|
|
258
|
+
false,
|
|
259
|
+
'secondary-upgrade',
|
|
260
|
+
`${EFFECT_INFO[selectedPrimary]?.name ?? 'Effect'} II`,
|
|
261
|
+
)}
|
|
262
|
+
|
|
263
|
+
{/* Confirm button */}
|
|
264
|
+
<div
|
|
265
|
+
onClick={handleConfirm}
|
|
266
|
+
onMouseEnter={() => setHoveredButton('confirm')}
|
|
267
|
+
onMouseLeave={() => setHoveredButton(null)}
|
|
268
|
+
title="Done"
|
|
269
|
+
style={{
|
|
270
|
+
position: 'absolute',
|
|
271
|
+
left: 164 * scale,
|
|
272
|
+
top: 107 * scale,
|
|
273
|
+
width: 22 * scale,
|
|
274
|
+
height: 22 * scale,
|
|
275
|
+
cursor: canConfirm ? 'pointer' : 'default',
|
|
276
|
+
}}
|
|
277
|
+
>
|
|
278
|
+
<img
|
|
279
|
+
src={getButtonSprite(!canConfirm, false, hoveredButton === 'confirm' && canConfirm)}
|
|
280
|
+
alt=""
|
|
281
|
+
draggable={false}
|
|
282
|
+
style={{
|
|
283
|
+
position: 'absolute',
|
|
284
|
+
left: 0,
|
|
285
|
+
top: 0,
|
|
286
|
+
width: 22 * scale,
|
|
287
|
+
height: 22 * scale,
|
|
288
|
+
imageRendering: 'pixelated',
|
|
289
|
+
}}
|
|
290
|
+
/>
|
|
291
|
+
<img
|
|
292
|
+
src={textures.getGuiTextureUrl(`${SPRITE_BASE}/confirm.png`)}
|
|
293
|
+
alt=""
|
|
294
|
+
draggable={false}
|
|
295
|
+
style={{
|
|
296
|
+
position: 'absolute',
|
|
297
|
+
left: 2 * scale,
|
|
298
|
+
top: 2 * scale,
|
|
299
|
+
width: 18 * scale,
|
|
300
|
+
height: 18 * scale,
|
|
301
|
+
imageRendering: 'pixelated',
|
|
302
|
+
}}
|
|
303
|
+
/>
|
|
304
|
+
</div>
|
|
305
|
+
|
|
306
|
+
{/* Cancel button */}
|
|
307
|
+
<div
|
|
308
|
+
onClick={handleCancel}
|
|
309
|
+
onMouseEnter={() => setHoveredButton('cancel')}
|
|
310
|
+
onMouseLeave={() => setHoveredButton(null)}
|
|
311
|
+
title="Cancel"
|
|
312
|
+
style={{
|
|
313
|
+
position: 'absolute',
|
|
314
|
+
left: 190 * scale,
|
|
315
|
+
top: 107 * scale,
|
|
316
|
+
width: 22 * scale,
|
|
317
|
+
height: 22 * scale,
|
|
318
|
+
cursor: 'pointer',
|
|
319
|
+
}}
|
|
320
|
+
>
|
|
321
|
+
<img
|
|
322
|
+
src={getButtonSprite(false, false, hoveredButton === 'cancel')}
|
|
323
|
+
alt=""
|
|
324
|
+
draggable={false}
|
|
325
|
+
style={{
|
|
326
|
+
position: 'absolute',
|
|
327
|
+
left: 0,
|
|
328
|
+
top: 0,
|
|
329
|
+
width: 22 * scale,
|
|
330
|
+
height: 22 * scale,
|
|
331
|
+
imageRendering: 'pixelated',
|
|
332
|
+
}}
|
|
333
|
+
/>
|
|
334
|
+
<img
|
|
335
|
+
src={textures.getGuiTextureUrl(`${SPRITE_BASE}/cancel.png`)}
|
|
336
|
+
alt=""
|
|
337
|
+
draggable={false}
|
|
338
|
+
style={{
|
|
339
|
+
position: 'absolute',
|
|
340
|
+
left: 2 * scale,
|
|
341
|
+
top: 2 * scale,
|
|
342
|
+
width: 18 * scale,
|
|
343
|
+
height: 18 * scale,
|
|
344
|
+
imageRendering: 'pixelated',
|
|
345
|
+
}}
|
|
346
|
+
/>
|
|
347
|
+
</div>
|
|
348
|
+
</>
|
|
349
|
+
)
|
|
350
|
+
}
|
|
@@ -13,6 +13,7 @@ import { HotbarExtras } from './HotbarExtras'
|
|
|
13
13
|
import { AnvilInput } from './AnvilInput'
|
|
14
14
|
import { AnvilCost } from './AnvilCost'
|
|
15
15
|
import { EntityDisplay } from './EntityDisplay'
|
|
16
|
+
import { BeaconEffects } from './BeaconEffects'
|
|
16
17
|
|
|
17
18
|
interface InventoryWindowProps {
|
|
18
19
|
type: string
|
|
@@ -67,7 +68,9 @@ export function InventoryWindow({
|
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
// Player inventory: don't show title (it's just the player's own inventory)
|
|
70
|
-
|
|
71
|
+
// Beacon: vanilla overrides renderLabels to show "Primary/Secondary Power" instead of title
|
|
72
|
+
const isBeacon = def?.name === 'beacon'
|
|
73
|
+
const effectiveTitle = (type === 'player' || isBeacon) ? undefined : (title ?? windowState?.title ?? def.title)
|
|
71
74
|
const isVillager = type === 'villager'
|
|
72
75
|
const isEnchanting = def?.name === 'enchanting_table'
|
|
73
76
|
const isHotbar = type === 'hotbar'
|
|
@@ -144,6 +147,9 @@ export function InventoryWindow({
|
|
|
144
147
|
{isAnvil && <AnvilInput x={59} y={20} width={110} height={16} />}
|
|
145
148
|
{isAnvil && <AnvilCost properties={effectiveProperties} backgroundWidth={def.backgroundWidth} />}
|
|
146
149
|
|
|
150
|
+
{/* Beacon effect selection panel */}
|
|
151
|
+
{isBeacon && <BeaconEffects properties={effectiveProperties} />}
|
|
152
|
+
|
|
147
153
|
{/* Hotbar extras: active slot indicator, offhand slot, open-inventory button */}
|
|
148
154
|
{isHotbar && (
|
|
149
155
|
<HotbarExtras
|
|
@@ -654,21 +654,27 @@ export function createMineflayerConnector(bot: MineflayerBot, options?: Mineflay
|
|
|
654
654
|
}
|
|
655
655
|
|
|
656
656
|
if (action.type === 'beacon' && win && isBeaconWindow(win)) {
|
|
657
|
+
// EFFECTS values are 1-based (matching vanilla encodeEffect: registry_id + 1)
|
|
658
|
+
// Protocol option(varint): undefined=absent, varint=1-based effect ID
|
|
659
|
+
// Server ContainerData uses same encoding: ≤0 = none, 1+ = effect
|
|
660
|
+
const protoPrimary = action.primaryEffect > 0 ? action.primaryEffect : undefined
|
|
661
|
+
const protoSecondary = action.secondaryEffect > 0 ? action.secondaryEffect : undefined
|
|
662
|
+
|
|
657
663
|
let handled = false
|
|
658
664
|
if (typeof win.setBeaconEffects === 'function') {
|
|
659
665
|
logHelperIntent(action, 'window.setBeaconEffects', {
|
|
660
|
-
primaryEffect:
|
|
661
|
-
secondaryEffect:
|
|
666
|
+
primaryEffect: protoPrimary,
|
|
667
|
+
secondaryEffect: protoSecondary,
|
|
662
668
|
})
|
|
663
|
-
await win.setBeaconEffects(
|
|
669
|
+
await win.setBeaconEffects(protoPrimary as any, protoSecondary as any)
|
|
664
670
|
handled = true
|
|
665
671
|
} else if (ext._client) {
|
|
666
672
|
const packet = {
|
|
667
|
-
|
|
668
|
-
|
|
673
|
+
primary_effect: protoPrimary,
|
|
674
|
+
secondary_effect: protoSecondary,
|
|
669
675
|
}
|
|
670
|
-
logPacketWrite('
|
|
671
|
-
ext._client.write('
|
|
676
|
+
logPacketWrite('set_beacon_effect', packet)
|
|
677
|
+
ext._client.write('set_beacon_effect', packet)
|
|
672
678
|
handled = true
|
|
673
679
|
}
|
|
674
680
|
if (handled) {
|
|
@@ -44,6 +44,18 @@ import _gui_sprites_container_enchanting_table_level_3 from 'mc-assets/dist/othe
|
|
|
44
44
|
import _gui_sprites_container_enchanting_table_level_1_disabled from 'mc-assets/dist/other-textures/latest/gui/sprites/container/enchanting_table/level_1_disabled.png'
|
|
45
45
|
import _gui_sprites_container_enchanting_table_level_2_disabled from 'mc-assets/dist/other-textures/latest/gui/sprites/container/enchanting_table/level_2_disabled.png'
|
|
46
46
|
import _gui_sprites_container_enchanting_table_level_3_disabled from 'mc-assets/dist/other-textures/latest/gui/sprites/container/enchanting_table/level_3_disabled.png'
|
|
47
|
+
import _gui_sprites_container_beacon_button from 'mc-assets/dist/other-textures/latest/gui/sprites/container/beacon/button.png'
|
|
48
|
+
import _gui_sprites_container_beacon_button_disabled from 'mc-assets/dist/other-textures/latest/gui/sprites/container/beacon/button_disabled.png'
|
|
49
|
+
import _gui_sprites_container_beacon_button_selected from 'mc-assets/dist/other-textures/latest/gui/sprites/container/beacon/button_selected.png'
|
|
50
|
+
import _gui_sprites_container_beacon_button_highlighted from 'mc-assets/dist/other-textures/latest/gui/sprites/container/beacon/button_highlighted.png'
|
|
51
|
+
import _gui_sprites_container_beacon_confirm from 'mc-assets/dist/other-textures/latest/gui/sprites/container/beacon/confirm.png'
|
|
52
|
+
import _gui_sprites_container_beacon_cancel from 'mc-assets/dist/other-textures/latest/gui/sprites/container/beacon/cancel.png'
|
|
53
|
+
import _mob_effect_speed from 'mc-assets/dist/other-textures/latest/mob_effect/speed.png'
|
|
54
|
+
import _mob_effect_haste from 'mc-assets/dist/other-textures/latest/mob_effect/haste.png'
|
|
55
|
+
import _mob_effect_resistance from 'mc-assets/dist/other-textures/latest/mob_effect/resistance.png'
|
|
56
|
+
import _mob_effect_jump_boost from 'mc-assets/dist/other-textures/latest/mob_effect/jump_boost.png'
|
|
57
|
+
import _mob_effect_strength from 'mc-assets/dist/other-textures/latest/mob_effect/strength.png'
|
|
58
|
+
import _mob_effect_regeneration from 'mc-assets/dist/other-textures/latest/mob_effect/regeneration.png'
|
|
47
59
|
|
|
48
60
|
/**
|
|
49
61
|
* Versioned texture path → bundled asset URL (or undefined for remote fallback).
|
|
@@ -93,6 +105,18 @@ export const bundledTextureMap: Record<string, string | undefined> = {
|
|
|
93
105
|
'1.21.11/textures/gui/sprites/container/enchanting_table/level_1_disabled.png': _gui_sprites_container_enchanting_table_level_1_disabled,
|
|
94
106
|
'1.21.11/textures/gui/sprites/container/enchanting_table/level_2_disabled.png': _gui_sprites_container_enchanting_table_level_2_disabled,
|
|
95
107
|
'1.21.11/textures/gui/sprites/container/enchanting_table/level_3_disabled.png': _gui_sprites_container_enchanting_table_level_3_disabled,
|
|
108
|
+
'1.21.11/textures/gui/sprites/container/beacon/button.png': _gui_sprites_container_beacon_button,
|
|
109
|
+
'1.21.11/textures/gui/sprites/container/beacon/button_disabled.png': _gui_sprites_container_beacon_button_disabled,
|
|
110
|
+
'1.21.11/textures/gui/sprites/container/beacon/button_selected.png': _gui_sprites_container_beacon_button_selected,
|
|
111
|
+
'1.21.11/textures/gui/sprites/container/beacon/button_highlighted.png': _gui_sprites_container_beacon_button_highlighted,
|
|
112
|
+
'1.21.11/textures/gui/sprites/container/beacon/confirm.png': _gui_sprites_container_beacon_confirm,
|
|
113
|
+
'1.21.11/textures/gui/sprites/container/beacon/cancel.png': _gui_sprites_container_beacon_cancel,
|
|
114
|
+
'1.21.11/textures/mob_effect/speed.png': _mob_effect_speed,
|
|
115
|
+
'1.21.11/textures/mob_effect/haste.png': _mob_effect_haste,
|
|
116
|
+
'1.21.11/textures/mob_effect/resistance.png': _mob_effect_resistance,
|
|
117
|
+
'1.21.11/textures/mob_effect/jump_boost.png': _mob_effect_jump_boost,
|
|
118
|
+
'1.21.11/textures/mob_effect/strength.png': _mob_effect_strength,
|
|
119
|
+
'1.21.11/textures/mob_effect/regeneration.png': _mob_effect_regeneration,
|
|
96
120
|
}
|
|
97
121
|
|
|
98
122
|
|
|
@@ -143,6 +167,18 @@ export const allTexturePaths: readonly string[] = [
|
|
|
143
167
|
'gui/sprites/container/enchanting_table/level_1_disabled.png',
|
|
144
168
|
'gui/sprites/container/enchanting_table/level_2_disabled.png',
|
|
145
169
|
'gui/sprites/container/enchanting_table/level_3_disabled.png',
|
|
170
|
+
'gui/sprites/container/beacon/button.png',
|
|
171
|
+
'gui/sprites/container/beacon/button_disabled.png',
|
|
172
|
+
'gui/sprites/container/beacon/button_selected.png',
|
|
173
|
+
'gui/sprites/container/beacon/button_highlighted.png',
|
|
174
|
+
'gui/sprites/container/beacon/confirm.png',
|
|
175
|
+
'gui/sprites/container/beacon/cancel.png',
|
|
176
|
+
'mob_effect/speed.png',
|
|
177
|
+
'mob_effect/haste.png',
|
|
178
|
+
'mob_effect/resistance.png',
|
|
179
|
+
'mob_effect/jump_boost.png',
|
|
180
|
+
'mob_effect/strength.png',
|
|
181
|
+
'mob_effect/regeneration.png',
|
|
146
182
|
]
|
|
147
183
|
|
|
148
184
|
/**
|
|
@@ -13,12 +13,12 @@ function withSequentialIndexes(slots: RawSlot[]): SlotDefinition[] {
|
|
|
13
13
|
})
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
function playerInv(yOffset: number): RawSlot[] {
|
|
16
|
+
function playerInv(yOffset: number, xStart = 8): RawSlot[] {
|
|
17
17
|
const slots: RawSlot[] = []
|
|
18
18
|
for (let row = 0; row < 3; row++) {
|
|
19
19
|
for (let col = 0; col < 9; col++) {
|
|
20
20
|
slots.push({
|
|
21
|
-
x:
|
|
21
|
+
x: xStart + col * SLOT_SIZE,
|
|
22
22
|
y: yOffset + row * SLOT_SIZE,
|
|
23
23
|
group: 'inventory',
|
|
24
24
|
})
|
|
@@ -26,7 +26,7 @@ function playerInv(yOffset: number): RawSlot[] {
|
|
|
26
26
|
}
|
|
27
27
|
for (let col = 0; col < 9; col++) {
|
|
28
28
|
slots.push({
|
|
29
|
-
x:
|
|
29
|
+
x: xStart + col * SLOT_SIZE,
|
|
30
30
|
y: yOffset + 58,
|
|
31
31
|
group: 'hotbar',
|
|
32
32
|
})
|
|
@@ -546,9 +546,14 @@ export const inventoryDefinitions = makeInventoryDefinitions({
|
|
|
546
546
|
backgroundTexture: '1.21.11/textures/gui/container/beacon.png',
|
|
547
547
|
backgroundWidth: 230,
|
|
548
548
|
backgroundHeight: 219,
|
|
549
|
+
properties: {
|
|
550
|
+
levels: { dataSlot: 0, description: 'Beacon pyramid level (0-4)' },
|
|
551
|
+
primaryEffect: { dataSlot: 1, description: 'Primary effect (encoded: 0=none, registry_id+1)' },
|
|
552
|
+
secondaryEffect: { dataSlot: 2, description: 'Secondary effect (encoded: 0=none, registry_id+1)' },
|
|
553
|
+
},
|
|
549
554
|
slots: [
|
|
550
555
|
{ x: 136, y: 110, group: 'payment', label: 'Payment' },
|
|
551
|
-
...playerInv(
|
|
556
|
+
...playerInv(137, 36),
|
|
552
557
|
],
|
|
553
558
|
},
|
|
554
559
|
|
|
@@ -759,4 +764,18 @@ export const registryExtraTextures: string[] = [
|
|
|
759
764
|
'1.21.11/textures/gui/sprites/container/enchanting_table/level_1_disabled.png',
|
|
760
765
|
'1.21.11/textures/gui/sprites/container/enchanting_table/level_2_disabled.png',
|
|
761
766
|
'1.21.11/textures/gui/sprites/container/enchanting_table/level_3_disabled.png',
|
|
767
|
+
// Beacon button sprites
|
|
768
|
+
'1.21.11/textures/gui/sprites/container/beacon/button.png',
|
|
769
|
+
'1.21.11/textures/gui/sprites/container/beacon/button_disabled.png',
|
|
770
|
+
'1.21.11/textures/gui/sprites/container/beacon/button_selected.png',
|
|
771
|
+
'1.21.11/textures/gui/sprites/container/beacon/button_highlighted.png',
|
|
772
|
+
'1.21.11/textures/gui/sprites/container/beacon/confirm.png',
|
|
773
|
+
'1.21.11/textures/gui/sprites/container/beacon/cancel.png',
|
|
774
|
+
// Beacon mob effect icons
|
|
775
|
+
'1.21.11/textures/mob_effect/speed.png',
|
|
776
|
+
'1.21.11/textures/mob_effect/haste.png',
|
|
777
|
+
'1.21.11/textures/mob_effect/resistance.png',
|
|
778
|
+
'1.21.11/textures/mob_effect/jump_boost.png',
|
|
779
|
+
'1.21.11/textures/mob_effect/strength.png',
|
|
780
|
+
'1.21.11/textures/mob_effect/regeneration.png',
|
|
762
781
|
]
|