minecraft-inventory 0.1.20 → 0.1.22
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
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { useScale } from '../../context/ScaleContext'
|
|
3
|
+
import { useInventoryContext } from '../../context/InventoryContext'
|
|
4
|
+
|
|
5
|
+
interface AnvilCostProps {
|
|
6
|
+
properties: Record<string, number>
|
|
7
|
+
backgroundWidth: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function AnvilCost({ properties, backgroundWidth }: AnvilCostProps) {
|
|
11
|
+
const { scale } = useScale()
|
|
12
|
+
const { windowState } = useInventoryContext()
|
|
13
|
+
|
|
14
|
+
const cost = properties.repairCost ?? 0
|
|
15
|
+
const hasResult = windowState?.slots.some((s) => s.index === 2 && s.item !== null) ?? false
|
|
16
|
+
if (cost <= 0) return null
|
|
17
|
+
if (!hasResult) return null
|
|
18
|
+
|
|
19
|
+
const tooExpensive = cost >= 40
|
|
20
|
+
const label = tooExpensive ? 'Too Expensive!' : `Enchantment Cost: ${cost}`
|
|
21
|
+
const color = tooExpensive ? '#FF6060' : '#80FF20'
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div
|
|
25
|
+
style={{
|
|
26
|
+
position: 'absolute',
|
|
27
|
+
right: 8 * scale,
|
|
28
|
+
top: 67 * scale,
|
|
29
|
+
height: 12 * scale,
|
|
30
|
+
display: 'flex',
|
|
31
|
+
alignItems: 'center',
|
|
32
|
+
justifyContent: 'flex-end',
|
|
33
|
+
padding: `0 ${2 * scale}px`,
|
|
34
|
+
background: 'rgba(0, 0, 0, 0.3)',
|
|
35
|
+
fontSize: 7 * scale,
|
|
36
|
+
fontFamily: "'Minecraftia', 'Minecraft', monospace",
|
|
37
|
+
color,
|
|
38
|
+
whiteSpace: 'nowrap',
|
|
39
|
+
pointerEvents: 'none',
|
|
40
|
+
}}
|
|
41
|
+
>
|
|
42
|
+
{label}
|
|
43
|
+
</div>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
@@ -11,6 +11,7 @@ import { VillagerTradeList } from './VillagerTradeList'
|
|
|
11
11
|
import { EnchantmentOptions } from './EnchantmentOptions'
|
|
12
12
|
import { HotbarExtras } from './HotbarExtras'
|
|
13
13
|
import { AnvilInput } from './AnvilInput'
|
|
14
|
+
import { AnvilCost } from './AnvilCost'
|
|
14
15
|
import { EntityDisplay } from './EntityDisplay'
|
|
15
16
|
|
|
16
17
|
interface InventoryWindowProps {
|
|
@@ -139,8 +140,9 @@ export function InventoryWindow({
|
|
|
139
140
|
/>
|
|
140
141
|
)}
|
|
141
142
|
|
|
142
|
-
{/* Anvil rename input */}
|
|
143
|
+
{/* Anvil rename input + cost display */}
|
|
143
144
|
{isAnvil && <AnvilInput x={59} y={20} width={110} height={16} />}
|
|
145
|
+
{isAnvil && <AnvilCost properties={effectiveProperties} backgroundWidth={def.backgroundWidth} />}
|
|
144
146
|
|
|
145
147
|
{/* Hotbar extras: active slot indicator, offhand slot, open-inventory button */}
|
|
146
148
|
{isHotbar && (
|
|
@@ -52,6 +52,26 @@ export interface MineflayerConnectorOptions {
|
|
|
52
52
|
* Return a human-readable string for display.
|
|
53
53
|
*/
|
|
54
54
|
formatTitle?: (rawTitle: any) => string
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Optional client-side anvil cost calculator. Called when items in an anvil
|
|
58
|
+
* window change to compute repairCost instantly (before the server's
|
|
59
|
+
* craft_progress_bar packet arrives). Receives the two input slot items.
|
|
60
|
+
* Return the XP cost, or null/0 to clear. Server packets will override this.
|
|
61
|
+
*
|
|
62
|
+
* @example Using prismarine-item:
|
|
63
|
+
* ```ts
|
|
64
|
+
* const Item = require('prismarine-item')(bot.registry)
|
|
65
|
+
* createMineflayerConnector(bot, {
|
|
66
|
+
* computeAnvilCost: (item1, item2) => {
|
|
67
|
+
* if (!item1) return null
|
|
68
|
+
* const { xpCost } = Item.anvil(item1, item2, bot.game.gameMode === 'creative')
|
|
69
|
+
* return xpCost
|
|
70
|
+
* },
|
|
71
|
+
* })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
computeAnvilCost?: (itemOne: RawSlot | null, itemTwo: RawSlot | null) => number | null
|
|
55
75
|
}
|
|
56
76
|
|
|
57
77
|
function makeSlotConverter(itemMapper?: MineflayerConnectorOptions['itemMapper']) {
|
|
@@ -138,6 +158,7 @@ export function createMineflayerConnector(bot: MineflayerBot, options?: Mineflay
|
|
|
138
158
|
const convert = makeSlotConverter(options?.itemMapper)
|
|
139
159
|
const hotbarOnly = options?.hotbarOnly ?? false
|
|
140
160
|
const formatTitle = options?.formatTitle
|
|
161
|
+
const computeAnvilCost = options?.computeAnvilCost
|
|
141
162
|
|
|
142
163
|
// Track window properties (furnace progress, enchant levels, etc.)
|
|
143
164
|
const windowProperties: Record<string, number> = {}
|
|
@@ -297,6 +318,27 @@ export function createMineflayerConnector(bot: MineflayerBot, options?: Mineflay
|
|
|
297
318
|
}
|
|
298
319
|
}
|
|
299
320
|
|
|
321
|
+
/** Compute anvil cost client-side if callback is provided and window is anvil. */
|
|
322
|
+
function tryComputeAnvilCost() {
|
|
323
|
+
if (!computeAnvilCost || !currentWindowType) return
|
|
324
|
+
const resolved = getInventoryType(currentWindowType)
|
|
325
|
+
if (resolved?.name !== 'anvil') return
|
|
326
|
+
const win = bot.currentWindow
|
|
327
|
+
if (!win) return
|
|
328
|
+
const item1 = (win.slots[0] as RawSlot | null) ?? null
|
|
329
|
+
const item2 = (win.slots[1] as RawSlot | null) ?? null
|
|
330
|
+
try {
|
|
331
|
+
const cost = item1 ? computeAnvilCost(item1, item2) : null
|
|
332
|
+
// Only SET client cost, never delete server-provided values.
|
|
333
|
+
// The server's craft_progress_bar will send 0 to clear when appropriate.
|
|
334
|
+
if (cost != null && cost > 0) {
|
|
335
|
+
windowProperties.repairCost = cost
|
|
336
|
+
}
|
|
337
|
+
} catch (err) {
|
|
338
|
+
// Client-side computation failed — rely on server cost
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
300
342
|
const onWindowOpen = () => {
|
|
301
343
|
const state = buildWindowState()
|
|
302
344
|
if (state) emit({ type: 'windowOpen', state })
|
|
@@ -307,6 +349,7 @@ export function createMineflayerConnector(bot: MineflayerBot, options?: Mineflay
|
|
|
307
349
|
}
|
|
308
350
|
|
|
309
351
|
const onSetSlot = () => {
|
|
352
|
+
tryComputeAnvilCost()
|
|
310
353
|
const state = buildWindowState()
|
|
311
354
|
if (state) emit({ type: 'windowUpdate', state })
|
|
312
355
|
emit({ type: 'playerUpdate', state: buildPlayerState() })
|
|
@@ -496,11 +539,17 @@ export function createMineflayerConnector(bot: MineflayerBot, options?: Mineflay
|
|
|
496
539
|
return
|
|
497
540
|
}
|
|
498
541
|
|
|
499
|
-
if (action.type === 'rename' && win && isAnvilWindow(win)) {
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (
|
|
542
|
+
if (action.type === 'rename' && win && isAnvilWindow(win) && ext._client) {
|
|
543
|
+
// Send name_item packet directly — don't use mineflayer's win.rename()
|
|
544
|
+
// because it tries to transfer items from player inventory into anvil,
|
|
545
|
+
// which fails when the user already placed items via the UI.
|
|
546
|
+
if (ext.supportFeature?.('useMCItemName')) {
|
|
547
|
+
if (!ext._client.registerChannel) return
|
|
548
|
+
ext._client.registerChannel('MC|ItemName', 'string')
|
|
549
|
+
ext._client.writeChannel?.('MC|ItemName', action.text)
|
|
550
|
+
} else {
|
|
551
|
+
ext._client.write('name_item', { name: action.text })
|
|
552
|
+
}
|
|
504
553
|
return
|
|
505
554
|
}
|
|
506
555
|
|