embark-ai 1.0.0

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.
@@ -0,0 +1,105 @@
1
+ // state.js — Grounded State Builder
2
+ // ONLY returns facts verifiable from bot APIs. No inference. No assumptions.
3
+
4
+ const SCAN_TYPES = [
5
+ 'oak_log','birch_log','spruce_log','jungle_log','acacia_log','dark_oak_log','mangrove_log','cherry_log',
6
+ 'sand','gravel','stone','iron_ore','coal_ore','water','crafting_table','chest','dirt','grass_block',
7
+ ]
8
+
9
+ const HOSTILE_MOB_NAMES = new Set([
10
+ 'zombie','skeleton','creeper','spider','cave_spider','witch','phantom','drowned','husk','stray',
11
+ 'pillager','evoker','vex','vindicator','slime','magma_cube','silverfish','endermite',
12
+ 'guardian','elder_guardian','warden','hoglin','piglin_brute','zoglin','blaze','ghast',
13
+ 'ravager','shulker','zombified_piglin','enderman',
14
+ ])
15
+
16
+ function buildGroundedState(bot, state, memory, anger = new Map(), perception = null) {
17
+ const pos = bot.entity.position
18
+
19
+ // REAL inventory — only what bot.inventory.items() returns right now
20
+ const rawItems = bot.inventory.items()
21
+ const inventory = rawItems.slice(0, 10).map(i => `${i.name}x${i.count}`)
22
+
23
+ // REAL nearby blocks — only what bot.findBlock() can confirm
24
+ const nearbyBlocks = []
25
+ for (const typeName of SCAN_TYPES) {
26
+ const id = bot.registry.blocksByName[typeName]?.id
27
+ if (!id) continue
28
+ const block = bot.findBlock({ matching: [id], maxDistance: 20 })
29
+ if (block) {
30
+ nearbyBlocks.push({
31
+ type: typeName,
32
+ dist: Math.floor(block.position.distanceTo(pos)),
33
+ })
34
+ }
35
+ }
36
+ nearbyBlocks.sort((a, b) => a.dist - b.dist)
37
+
38
+ // REAL visible entities — only from bot.entities
39
+ const entities = Object.values(bot.entities)
40
+ .filter(e => e !== bot.entity && e.name && e.position.distanceTo(pos) < 20)
41
+ .sort((a, b) => a.position.distanceTo(pos) - b.position.distanceTo(pos))
42
+ .slice(0, 5)
43
+ .map(e => ({ name: e.name, dist: Math.floor(e.position.distanceTo(pos)) }))
44
+
45
+ // REAL hostile mobs — confirmed from bot.entities
46
+ const hostileMobs = Object.values(bot.entities)
47
+ .filter(e => e.name && HOSTILE_MOB_NAMES.has(e.name) && e.position.distanceTo(pos) < 20)
48
+ .sort((a, b) => a.position.distanceTo(pos) - b.position.distanceTo(pos))
49
+ .slice(0, 3)
50
+ .map(e => ({ name: e.name, dist: Math.floor(e.position.distanceTo(pos)) }))
51
+
52
+ // REAL dropped items on ground — item entities from server
53
+ const droppedItems = Object.values(bot.entities)
54
+ .filter(e => e.type === 'object' && e.objectType === 'Item' && e.position.distanceTo(pos) < 20)
55
+ const droppedCount = droppedItems.length
56
+
57
+ // Environmental perception — scan on demand; null if unavailable or errors
58
+ let envScan = null
59
+ if (perception) {
60
+ try {
61
+ envScan = perception.scan()
62
+ } catch (err) {
63
+ // Gracefully degrade if perception scan fails
64
+ envScan = null
65
+ }
66
+ }
67
+
68
+ return {
69
+ self: {
70
+ hp: bot.health, // real Minecraft HP (0–20)
71
+ food: bot.food, // real Minecraft food (0–20)
72
+ energy: Math.floor(state.energy), // hp mapped to 0-100 for engine compatibility
73
+ hunger: Math.floor(state.hunger), // food mapped to 0-100 for engine compatibility
74
+ goal: state.goal,
75
+ pos: { x: Math.floor(pos.x), y: Math.floor(pos.y), z: Math.floor(pos.z) },
76
+ },
77
+ inventory, // from bot.inventory.items() — real
78
+ nearbyBlocks, // from bot.findBlock() — real
79
+ entities, // from bot.entities — real
80
+ hostileMobs, // filtered to known hostile names — real
81
+ droppedCount, // item entities on ground count — real
82
+ anger: Array.from(anger.entries()).map(([name, rec]) => ({ name, level: rec.level })),
83
+ knownLocations: memory.locations.slice(-5).map(l => ({ name: l.name, pos: l.pos })),
84
+ environment: envScan, // real-time spatial perception (null if unavailable)
85
+ }
86
+ }
87
+
88
+ // One-line text summary for autonomous narration
89
+ function chatSummary(gs) {
90
+ const parts = []
91
+ if (gs.nearbyBlocks.length) {
92
+ parts.push(gs.nearbyBlocks.slice(0, 3).map(b => `${b.type}@${b.dist}m`).join(', '))
93
+ } else {
94
+ parts.push('nothing notable nearby')
95
+ }
96
+ if (gs.hostileMobs.length) {
97
+ parts.push(`HOSTILE: ${gs.hostileMobs.map(m => `${m.name}@${m.dist}m`).join(', ')}`)
98
+ } else if (gs.entities.length) {
99
+ parts.push(gs.entities.map(e => `${e.name}@${e.dist}m`).join(', '))
100
+ }
101
+ if (gs.droppedCount > 0) parts.push(`${gs.droppedCount} item(s) on ground`)
102
+ return parts.join('; ')
103
+ }
104
+
105
+ module.exports = { buildGroundedState, chatSummary, HOSTILE_MOB_NAMES }