mindcraft 0.1.4-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.
- package/FAQ.md +38 -0
- package/LICENSE +21 -0
- package/README.md +255 -0
- package/andy.json +6 -0
- package/bin/mindcraft.js +80 -0
- package/keys.example.json +19 -0
- package/main.js +80 -0
- package/package.json +78 -0
- package/patches/minecraft-data+3.97.0.patch +13 -0
- package/patches/mineflayer+4.33.0.patch +54 -0
- package/patches/mineflayer-pathfinder+2.4.5.patch +265 -0
- package/patches/mineflayer-pvp+1.3.2.patch +13 -0
- package/patches/prismarine-viewer+1.33.0.patch +13 -0
- package/patches/protodef+1.19.0.patch +15 -0
- package/profiles/andy-4-reasoning.json +14 -0
- package/profiles/andy-4.json +7 -0
- package/profiles/azure.json +19 -0
- package/profiles/claude.json +7 -0
- package/profiles/claude_thinker.json +15 -0
- package/profiles/deepseek.json +7 -0
- package/profiles/defaults/_default.json +256 -0
- package/profiles/defaults/assistant.json +14 -0
- package/profiles/defaults/creative.json +14 -0
- package/profiles/defaults/god_mode.json +14 -0
- package/profiles/defaults/survival.json +14 -0
- package/profiles/freeguy.json +7 -0
- package/profiles/gemini.json +9 -0
- package/profiles/gpt.json +12 -0
- package/profiles/grok.json +7 -0
- package/profiles/llama.json +10 -0
- package/profiles/mercury.json +9 -0
- package/profiles/mistral.json +5 -0
- package/profiles/qwen.json +17 -0
- package/profiles/tasks/construction_profile.json +42 -0
- package/profiles/tasks/cooking_profile.json +11 -0
- package/profiles/tasks/crafting_profile.json +71 -0
- package/profiles/vllm.json +10 -0
- package/settings.js +64 -0
- package/src/agent/action_manager.js +177 -0
- package/src/agent/agent.js +561 -0
- package/src/agent/coder.js +229 -0
- package/src/agent/commands/actions.js +504 -0
- package/src/agent/commands/index.js +259 -0
- package/src/agent/commands/queries.js +347 -0
- package/src/agent/connection_handler.js +96 -0
- package/src/agent/conversation.js +353 -0
- package/src/agent/history.js +122 -0
- package/src/agent/library/full_state.js +89 -0
- package/src/agent/library/index.js +23 -0
- package/src/agent/library/lockdown.js +32 -0
- package/src/agent/library/skill_library.js +93 -0
- package/src/agent/library/skills.js +2093 -0
- package/src/agent/library/world.js +431 -0
- package/src/agent/memory_bank.js +25 -0
- package/src/agent/mindserver_proxy.js +136 -0
- package/src/agent/modes.js +446 -0
- package/src/agent/npc/build_goal.js +80 -0
- package/src/agent/npc/construction/dirt_shelter.json +38 -0
- package/src/agent/npc/construction/large_house.json +230 -0
- package/src/agent/npc/construction/small_stone_house.json +42 -0
- package/src/agent/npc/construction/small_wood_house.json +42 -0
- package/src/agent/npc/controller.js +261 -0
- package/src/agent/npc/data.js +50 -0
- package/src/agent/npc/item_goal.js +355 -0
- package/src/agent/npc/utils.js +126 -0
- package/src/agent/self_prompter.js +146 -0
- package/src/agent/settings.js +7 -0
- package/src/agent/speak.js +150 -0
- package/src/agent/tasks/construction_tasks.js +1104 -0
- package/src/agent/tasks/cooking_tasks.js +358 -0
- package/src/agent/tasks/tasks.js +594 -0
- package/src/agent/templates/execTemplate.js +6 -0
- package/src/agent/templates/lintTemplate.js +10 -0
- package/src/agent/vision/browser_viewer.js +8 -0
- package/src/agent/vision/camera.js +78 -0
- package/src/agent/vision/vision_interpreter.js +82 -0
- package/src/mindcraft/index.js +28 -0
- package/src/mindcraft/mcserver.js +154 -0
- package/src/mindcraft/mindcraft.js +111 -0
- package/src/mindcraft/mindserver.js +328 -0
- package/src/mindcraft/public/index.html +1253 -0
- package/src/mindcraft/public/settings_spec.json +145 -0
- package/src/mindcraft/userconfig.js +72 -0
- package/src/mindcraft-py/example.py +27 -0
- package/src/mindcraft-py/init-mindcraft.js +24 -0
- package/src/mindcraft-py/mindcraft.py +99 -0
- package/src/models/_model_map.js +89 -0
- package/src/models/azure.js +32 -0
- package/src/models/cerebras.js +61 -0
- package/src/models/claude.js +87 -0
- package/src/models/deepseek.js +59 -0
- package/src/models/gemini.js +176 -0
- package/src/models/glhf.js +71 -0
- package/src/models/gpt.js +147 -0
- package/src/models/grok.js +82 -0
- package/src/models/groq.js +95 -0
- package/src/models/huggingface.js +86 -0
- package/src/models/hyperbolic.js +114 -0
- package/src/models/lmstudio.js +74 -0
- package/src/models/mercury.js +95 -0
- package/src/models/mistral.js +94 -0
- package/src/models/novita.js +71 -0
- package/src/models/ollama.js +115 -0
- package/src/models/openrouter.js +77 -0
- package/src/models/prompter.js +366 -0
- package/src/models/qwen.js +80 -0
- package/src/models/replicate.js +60 -0
- package/src/models/vllm.js +81 -0
- package/src/process/agent_process.js +84 -0
- package/src/process/init_agent.js +54 -0
- package/src/utils/examples.js +83 -0
- package/src/utils/keys.js +34 -0
- package/src/utils/math.js +13 -0
- package/src/utils/mcdata.js +572 -0
- package/src/utils/text.js +78 -0
- package/src/utils/translator.js +30 -0
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import pf from 'mineflayer-pathfinder';
|
|
2
|
+
import * as mc from '../../utils/mcdata.js';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export function getNearestFreeSpace(bot, size=1, distance=8) {
|
|
6
|
+
/**
|
|
7
|
+
* Get the nearest empty space with solid blocks beneath it of the given size.
|
|
8
|
+
* @param {Bot} bot - The bot to get the nearest free space for.
|
|
9
|
+
* @param {number} size - The (size x size) of the space to find, default 1.
|
|
10
|
+
* @param {number} distance - The maximum distance to search, default 8.
|
|
11
|
+
* @returns {Vec3} - The south west corner position of the nearest free space.
|
|
12
|
+
* @example
|
|
13
|
+
* let position = world.getNearestFreeSpace(bot, 1, 8);
|
|
14
|
+
**/
|
|
15
|
+
let empty_pos = bot.findBlocks({
|
|
16
|
+
matching: (block) => {
|
|
17
|
+
return block && block.name == 'air';
|
|
18
|
+
},
|
|
19
|
+
maxDistance: distance,
|
|
20
|
+
count: 1000
|
|
21
|
+
});
|
|
22
|
+
for (let i = 0; i < empty_pos.length; i++) {
|
|
23
|
+
let empty = true;
|
|
24
|
+
for (let x = 0; x < size; x++) {
|
|
25
|
+
for (let z = 0; z < size; z++) {
|
|
26
|
+
let top = bot.blockAt(empty_pos[i].offset(x, 0, z));
|
|
27
|
+
let bottom = bot.blockAt(empty_pos[i].offset(x, -1, z));
|
|
28
|
+
if (!top || !top.name == 'air' || !bottom || bottom.drops.length == 0 || !bottom.diggable) {
|
|
29
|
+
empty = false;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (!empty) break;
|
|
34
|
+
}
|
|
35
|
+
if (empty) {
|
|
36
|
+
return empty_pos[i];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
export function getBlockAtPosition(bot, x=0, y=0, z=0) {
|
|
43
|
+
/**
|
|
44
|
+
* Get a block from the bot's relative position
|
|
45
|
+
* @param {Bot} bot - The bot to get the block for.
|
|
46
|
+
* @param {number} x - The relative x offset to serach, default 0.
|
|
47
|
+
* @param {number} y - The relative y offset to serach, default 0.
|
|
48
|
+
* @param {number} y - The relative z offset to serach, default 0.
|
|
49
|
+
* @returns {Block} - The nearest block.
|
|
50
|
+
* @example
|
|
51
|
+
* let blockBelow = world.getBlockAtPosition(bot, 0, -1, 0);
|
|
52
|
+
* let blockAbove = world.getBlockAtPosition(bot, 0, 2, 0); since minecraft position is at the feet
|
|
53
|
+
**/
|
|
54
|
+
let block = bot.blockAt(bot.entity.position.offset(x, y, z));
|
|
55
|
+
if (!block) block = {name: 'air'};
|
|
56
|
+
|
|
57
|
+
return block;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
export function getSurroundingBlocks(bot) {
|
|
62
|
+
/**
|
|
63
|
+
* Get the surrounding blocks from the bot's environment.
|
|
64
|
+
* @param {Bot} bot - The bot to get the block for.
|
|
65
|
+
* @returns {string[]} - A list of block results as strings.
|
|
66
|
+
* @example
|
|
67
|
+
**/
|
|
68
|
+
// Create a list of block position results that can be unpacked.
|
|
69
|
+
let res = [];
|
|
70
|
+
res.push(`Block Below: ${getBlockAtPosition(bot, 0, -1, 0).name}`);
|
|
71
|
+
res.push(`Block at Legs: ${getBlockAtPosition(bot, 0, 0, 0).name}`);
|
|
72
|
+
res.push(`Block at Head: ${getBlockAtPosition(bot, 0, 1, 0).name}`);
|
|
73
|
+
|
|
74
|
+
return res;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
export function getFirstBlockAboveHead(bot, ignore_types=null, distance=32) {
|
|
79
|
+
/**
|
|
80
|
+
* Searches a column from the bot's position for the first solid block above its head
|
|
81
|
+
* @param {Bot} bot - The bot to get the block for.
|
|
82
|
+
* @param {string[]} ignore_types - The names of the blocks to ignore.
|
|
83
|
+
* @param {number} distance - The maximum distance to search, default 32.
|
|
84
|
+
* @returns {string} - The fist block above head.
|
|
85
|
+
* @example
|
|
86
|
+
* let firstBlockAboveHead = world.getFirstBlockAboveHead(bot, null, 32);
|
|
87
|
+
**/
|
|
88
|
+
// if ignore_types is not a list, make it a list.
|
|
89
|
+
let ignore_blocks = [];
|
|
90
|
+
if (ignore_types === null) ignore_blocks = ['air', 'cave_air'];
|
|
91
|
+
else {
|
|
92
|
+
if (!Array.isArray(ignore_types))
|
|
93
|
+
ignore_types = [ignore_types];
|
|
94
|
+
for(let ignore_type of ignore_types) {
|
|
95
|
+
if (mc.getBlockId(ignore_type)) ignore_blocks.push(ignore_type);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// The block above, stops when it finds a solid block .
|
|
99
|
+
let block_above = {name: 'air'};
|
|
100
|
+
let height = 0
|
|
101
|
+
for (let i = 0; i < distance; i++) {
|
|
102
|
+
let block = bot.blockAt(bot.entity.position.offset(0, i+2, 0));
|
|
103
|
+
if (!block) block = {name: 'air'};
|
|
104
|
+
// Ignore and continue
|
|
105
|
+
if (ignore_blocks.includes(block.name)) continue;
|
|
106
|
+
// Defaults to any block
|
|
107
|
+
block_above = block;
|
|
108
|
+
height = i;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (ignore_blocks.includes(block_above.name)) return 'none';
|
|
113
|
+
|
|
114
|
+
return `${block_above.name} (${height} blocks up)`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
export function getNearestBlocks(bot, block_types=null, distance=8, count=10000) {
|
|
119
|
+
/**
|
|
120
|
+
* Get a list of the nearest blocks of the given types.
|
|
121
|
+
* @param {Bot} bot - The bot to get the nearest block for.
|
|
122
|
+
* @param {string[]} block_types - The names of the blocks to search for.
|
|
123
|
+
* @param {number} distance - The maximum distance to search, default 16.
|
|
124
|
+
* @param {number} count - The maximum number of blocks to find, default 10000.
|
|
125
|
+
* @returns {Block[]} - The nearest blocks of the given type.
|
|
126
|
+
* @example
|
|
127
|
+
* let woodBlocks = world.getNearestBlocks(bot, ['oak_log', 'birch_log'], 16, 1);
|
|
128
|
+
**/
|
|
129
|
+
// if blocktypes is not a list, make it a list
|
|
130
|
+
let block_ids = [];
|
|
131
|
+
if (block_types === null) {
|
|
132
|
+
block_ids = mc.getAllBlockIds(['air']);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
if (!Array.isArray(block_types))
|
|
136
|
+
block_types = [block_types];
|
|
137
|
+
for(let block_type of block_types) {
|
|
138
|
+
block_ids.push(mc.getBlockId(block_type));
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return getNearestBlocksWhere(bot, block_ids, distance, count);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function getNearestBlocksWhere(bot, predicate, distance=8, count=10000) {
|
|
145
|
+
/**
|
|
146
|
+
* Get a list of the nearest blocks that satisfy the given predicate.
|
|
147
|
+
* @param {Bot} bot - The bot to get the nearest blocks for.
|
|
148
|
+
* @param {function} predicate - The predicate to filter the blocks.
|
|
149
|
+
* @param {number} distance - The maximum distance to search, default 16.
|
|
150
|
+
* @param {number} count - The maximum number of blocks to find, default 10000.
|
|
151
|
+
* @returns {Block[]} - The nearest blocks that satisfy the given predicate.
|
|
152
|
+
* @example
|
|
153
|
+
* let waterBlocks = world.getNearestBlocksWhere(bot, block => block.name === 'water', 16, 10);
|
|
154
|
+
**/
|
|
155
|
+
let positions = bot.findBlocks({matching: predicate, maxDistance: distance, count: count});
|
|
156
|
+
let blocks = positions.map(position => bot.blockAt(position));
|
|
157
|
+
return blocks;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
export function getNearestBlock(bot, block_type, distance=16) {
|
|
162
|
+
/**
|
|
163
|
+
* Get the nearest block of the given type.
|
|
164
|
+
* @param {Bot} bot - The bot to get the nearest block for.
|
|
165
|
+
* @param {string} block_type - The name of the block to search for.
|
|
166
|
+
* @param {number} distance - The maximum distance to search, default 16.
|
|
167
|
+
* @returns {Block} - The nearest block of the given type.
|
|
168
|
+
* @example
|
|
169
|
+
* let coalBlock = world.getNearestBlock(bot, 'coal_ore', 16);
|
|
170
|
+
**/
|
|
171
|
+
let blocks = getNearestBlocks(bot, block_type, distance, 1);
|
|
172
|
+
if (blocks.length > 0) {
|
|
173
|
+
return blocks[0];
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
export function getNearbyEntities(bot, maxDistance=16) {
|
|
180
|
+
let entities = [];
|
|
181
|
+
for (const entity of Object.values(bot.entities)) {
|
|
182
|
+
const distance = entity.position.distanceTo(bot.entity.position);
|
|
183
|
+
if (distance > maxDistance) continue;
|
|
184
|
+
entities.push({ entity: entity, distance: distance });
|
|
185
|
+
}
|
|
186
|
+
entities.sort((a, b) => a.distance - b.distance);
|
|
187
|
+
let res = [];
|
|
188
|
+
for (let i = 0; i < entities.length; i++) {
|
|
189
|
+
res.push(entities[i].entity);
|
|
190
|
+
}
|
|
191
|
+
return res;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function getNearestEntityWhere(bot, predicate, maxDistance=16) {
|
|
195
|
+
return bot.nearestEntity(entity => predicate(entity) && bot.entity.position.distanceTo(entity.position) < maxDistance);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
export function getNearbyPlayers(bot, maxDistance) {
|
|
200
|
+
if (maxDistance == null) maxDistance = 16;
|
|
201
|
+
let players = [];
|
|
202
|
+
for (const entity of Object.values(bot.entities)) {
|
|
203
|
+
const distance = entity.position.distanceTo(bot.entity.position);
|
|
204
|
+
if (distance > maxDistance) continue;
|
|
205
|
+
if (entity.type == 'player' && entity.username != bot.username) {
|
|
206
|
+
players.push({ entity: entity, distance: distance });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
players.sort((a, b) => a.distance - b.distance);
|
|
210
|
+
let res = [];
|
|
211
|
+
for (let i = 0; i < players.length; i++) {
|
|
212
|
+
res.push(players[i].entity);
|
|
213
|
+
}
|
|
214
|
+
return res;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Helper function to get villager profession from metadata
|
|
218
|
+
export function getVillagerProfession(entity) {
|
|
219
|
+
// Villager profession mapping based on metadata
|
|
220
|
+
const professions = {
|
|
221
|
+
0: 'Unemployed',
|
|
222
|
+
1: 'Armorer',
|
|
223
|
+
2: 'Butcher',
|
|
224
|
+
3: 'Cartographer',
|
|
225
|
+
4: 'Cleric',
|
|
226
|
+
5: 'Farmer',
|
|
227
|
+
6: 'Fisherman',
|
|
228
|
+
7: 'Fletcher',
|
|
229
|
+
8: 'Leatherworker',
|
|
230
|
+
9: 'Librarian',
|
|
231
|
+
10: 'Mason',
|
|
232
|
+
11: 'Nitwit',
|
|
233
|
+
12: 'Shepherd',
|
|
234
|
+
13: 'Toolsmith',
|
|
235
|
+
14: 'Weaponsmith'
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
if (entity.metadata && entity.metadata[18]) {
|
|
239
|
+
// Check if metadata[18] is an object with villagerProfession property
|
|
240
|
+
if (typeof entity.metadata[18] === 'object' && entity.metadata[18].villagerProfession !== undefined) {
|
|
241
|
+
const professionId = entity.metadata[18].villagerProfession;
|
|
242
|
+
const level = entity.metadata[18].level || 1;
|
|
243
|
+
const professionName = professions[professionId] || 'Unknown';
|
|
244
|
+
return `${professionName} L${level}`;
|
|
245
|
+
}
|
|
246
|
+
// Fallback for direct profession ID
|
|
247
|
+
else if (typeof entity.metadata[18] === 'number') {
|
|
248
|
+
const professionId = entity.metadata[18];
|
|
249
|
+
return professions[professionId] || 'Unknown';
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// If we can't determine profession but it's an adult villager
|
|
254
|
+
if (entity.metadata && entity.metadata[16] !== 1) { // Not a baby
|
|
255
|
+
return 'Adult';
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return 'Unknown';
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
export function getInventoryCounts(bot) {
|
|
263
|
+
/**
|
|
264
|
+
* Get an object representing the bot's inventory.
|
|
265
|
+
* @param {Bot} bot - The bot to get the inventory for.
|
|
266
|
+
* @returns {object} - An object with item names as keys and counts as values.
|
|
267
|
+
* @example
|
|
268
|
+
* let inventory = world.getInventoryCounts(bot);
|
|
269
|
+
* let oakLogCount = inventory['oak_log'];
|
|
270
|
+
* let hasWoodenPickaxe = inventory['wooden_pickaxe'] > 0;
|
|
271
|
+
**/
|
|
272
|
+
let inventory = {};
|
|
273
|
+
for (const slot of bot.inventory.slots) {
|
|
274
|
+
if (slot != null && slot.name) {
|
|
275
|
+
if (inventory[slot.name] == null) {
|
|
276
|
+
inventory[slot.name] = 0;
|
|
277
|
+
}
|
|
278
|
+
inventory[slot.name] += slot.count;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return inventory;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
export function getCraftableItems(bot) {
|
|
286
|
+
/**
|
|
287
|
+
* Get a list of all items that can be crafted with the bot's current inventory.
|
|
288
|
+
* @param {Bot} bot - The bot to get the craftable items for.
|
|
289
|
+
* @returns {string[]} - A list of all items that can be crafted.
|
|
290
|
+
* @example
|
|
291
|
+
* let craftableItems = world.getCraftableItems(bot);
|
|
292
|
+
**/
|
|
293
|
+
let table = getNearestBlock(bot, 'crafting_table');
|
|
294
|
+
if (!table) {
|
|
295
|
+
for (const item of bot.inventory.items()) {
|
|
296
|
+
if (item != null && item.name === 'crafting_table') {
|
|
297
|
+
table = item;
|
|
298
|
+
break;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
let res = [];
|
|
303
|
+
for (const item of mc.getAllItems()) {
|
|
304
|
+
let recipes = bot.recipesFor(item.id, null, 1, table);
|
|
305
|
+
if (recipes.length > 0)
|
|
306
|
+
res.push(item.name);
|
|
307
|
+
}
|
|
308
|
+
return res;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
export function getPosition(bot) {
|
|
313
|
+
/**
|
|
314
|
+
* Get your position in the world (Note that y is vertical).
|
|
315
|
+
* @param {Bot} bot - The bot to get the position for.
|
|
316
|
+
* @returns {Vec3} - An object with x, y, and x attributes representing the position of the bot.
|
|
317
|
+
* @example
|
|
318
|
+
* let position = world.getPosition(bot);
|
|
319
|
+
* let x = position.x;
|
|
320
|
+
**/
|
|
321
|
+
return bot.entity.position;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
export function getNearbyEntityTypes(bot) {
|
|
326
|
+
/**
|
|
327
|
+
* Get a list of all nearby mob types.
|
|
328
|
+
* @param {Bot} bot - The bot to get nearby mobs for.
|
|
329
|
+
* @returns {string[]} - A list of all nearby mobs.
|
|
330
|
+
* @example
|
|
331
|
+
* let mobs = world.getNearbyEntityTypes(bot);
|
|
332
|
+
**/
|
|
333
|
+
let mobs = getNearbyEntities(bot, 16);
|
|
334
|
+
let found = [];
|
|
335
|
+
for (let i = 0; i < mobs.length; i++) {
|
|
336
|
+
if (!found.includes(mobs[i].name)) {
|
|
337
|
+
found.push(mobs[i].name);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return found;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export function isEntityType(name) {
|
|
344
|
+
/**
|
|
345
|
+
* Check if a given name is a valid entity type.
|
|
346
|
+
* @param {string} name - The name of the entity type to check.
|
|
347
|
+
* @returns {boolean} - True if the name is a valid entity type, false otherwise.
|
|
348
|
+
*/
|
|
349
|
+
return mc.getEntityId(name) !== null;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export function getNearbyPlayerNames(bot) {
|
|
353
|
+
/**
|
|
354
|
+
* Get a list of all nearby player names.
|
|
355
|
+
* @param {Bot} bot - The bot to get nearby players for.
|
|
356
|
+
* @returns {string[]} - A list of all nearby players.
|
|
357
|
+
* @example
|
|
358
|
+
* let players = world.getNearbyPlayerNames(bot);
|
|
359
|
+
**/
|
|
360
|
+
let players = getNearbyPlayers(bot, 64);
|
|
361
|
+
let found = [];
|
|
362
|
+
for (let i = 0; i < players.length; i++) {
|
|
363
|
+
if (!found.includes(players[i].username) && players[i].username != bot.username) {
|
|
364
|
+
found.push(players[i].username);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return found;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
export function getNearbyBlockTypes(bot, distance=16) {
|
|
372
|
+
/**
|
|
373
|
+
* Get a list of all nearby block names.
|
|
374
|
+
* @param {Bot} bot - The bot to get nearby blocks for.
|
|
375
|
+
* @param {number} distance - The maximum distance to search, default 16.
|
|
376
|
+
* @returns {string[]} - A list of all nearby blocks.
|
|
377
|
+
* @example
|
|
378
|
+
* let blocks = world.getNearbyBlockTypes(bot);
|
|
379
|
+
**/
|
|
380
|
+
let blocks = getNearestBlocks(bot, null, distance);
|
|
381
|
+
let found = [];
|
|
382
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
383
|
+
if (!found.includes(blocks[i].name)) {
|
|
384
|
+
found.push(blocks[i].name);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return found;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export async function isClearPath(bot, target) {
|
|
391
|
+
/**
|
|
392
|
+
* Check if there is a path to the target that requires no digging or placing blocks.
|
|
393
|
+
* @param {Bot} bot - The bot to get the path for.
|
|
394
|
+
* @param {Entity} target - The target to path to.
|
|
395
|
+
* @returns {boolean} - True if there is a clear path, false otherwise.
|
|
396
|
+
*/
|
|
397
|
+
let movements = new pf.Movements(bot)
|
|
398
|
+
movements.canDig = false;
|
|
399
|
+
movements.canPlaceOn = false;
|
|
400
|
+
movements.canOpenDoors = false;
|
|
401
|
+
let goal = new pf.goals.GoalNear(target.position.x, target.position.y, target.position.z, 1);
|
|
402
|
+
let path = await bot.pathfinder.getPathTo(movements, goal, 100);
|
|
403
|
+
return path.status === 'success';
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export function shouldPlaceTorch(bot) {
|
|
407
|
+
if (!bot.modes.isOn('torch_placing') || bot.interrupt_code) return false;
|
|
408
|
+
const pos = getPosition(bot);
|
|
409
|
+
// TODO: check light level instead of nearby torches, block.light is broken
|
|
410
|
+
let nearest_torch = getNearestBlock(bot, 'torch', 6);
|
|
411
|
+
if (!nearest_torch)
|
|
412
|
+
nearest_torch = getNearestBlock(bot, 'wall_torch', 6);
|
|
413
|
+
if (!nearest_torch) {
|
|
414
|
+
const block = bot.blockAt(pos);
|
|
415
|
+
let has_torch = bot.inventory.findInventoryItem('torch');
|
|
416
|
+
return has_torch && block?.name === 'air';
|
|
417
|
+
}
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export function getBiomeName(bot) {
|
|
422
|
+
/**
|
|
423
|
+
* Get the name of the biome the bot is in.
|
|
424
|
+
* @param {Bot} bot - The bot to get the biome for.
|
|
425
|
+
* @returns {string} - The name of the biome.
|
|
426
|
+
* @example
|
|
427
|
+
* let biome = world.getBiomeName(bot);
|
|
428
|
+
**/
|
|
429
|
+
const biomeId = bot.world.getBiome(bot.entity.position);
|
|
430
|
+
return mc.getAllBiomes()[biomeId].name;
|
|
431
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export class MemoryBank {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.memory = {};
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
rememberPlace(name, x, y, z) {
|
|
7
|
+
this.memory[name] = [x, y, z];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
recallPlace(name) {
|
|
11
|
+
return this.memory[name];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getJson() {
|
|
15
|
+
return this.memory
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
loadJson(json) {
|
|
19
|
+
this.memory = json;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getKeys() {
|
|
23
|
+
return Object.keys(this.memory).join(', ')
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { io } from 'socket.io-client';
|
|
2
|
+
import convoManager from './conversation.js';
|
|
3
|
+
import { setSettings } from './settings.js';
|
|
4
|
+
import { getFullState } from './library/full_state.js';
|
|
5
|
+
|
|
6
|
+
// agent's individual connection to the mindserver
|
|
7
|
+
// always connect to localhost
|
|
8
|
+
|
|
9
|
+
class MindServerProxy {
|
|
10
|
+
constructor() {
|
|
11
|
+
if (MindServerProxy.instance) {
|
|
12
|
+
return MindServerProxy.instance;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
this.socket = null;
|
|
16
|
+
this.connected = false;
|
|
17
|
+
this.agents = [];
|
|
18
|
+
MindServerProxy.instance = this;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async connect(name, port) {
|
|
22
|
+
if (this.connected) return;
|
|
23
|
+
|
|
24
|
+
this.name = name;
|
|
25
|
+
this.socket = io(`http://localhost:${port}`);
|
|
26
|
+
|
|
27
|
+
await new Promise((resolve, reject) => {
|
|
28
|
+
this.socket.on('connect', resolve);
|
|
29
|
+
this.socket.on('connect_error', (err) => {
|
|
30
|
+
console.error('Connection failed:', err);
|
|
31
|
+
reject(err);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
this.connected = true;
|
|
36
|
+
console.log(name, 'connected to MindServer');
|
|
37
|
+
|
|
38
|
+
this.socket.on('disconnect', () => {
|
|
39
|
+
console.log('Disconnected from MindServer');
|
|
40
|
+
this.connected = false;
|
|
41
|
+
if (this.agent) {
|
|
42
|
+
this.agent.cleanKill('Disconnected from MindServer. Killing agent process.');
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
this.socket.on('chat-message', (agentName, json) => {
|
|
47
|
+
convoManager.receiveFromBot(agentName, json);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
this.socket.on('agents-status', (agents) => {
|
|
51
|
+
this.agents = agents;
|
|
52
|
+
convoManager.updateAgents(agents);
|
|
53
|
+
if (this.agent?.task) {
|
|
54
|
+
console.log(this.agent.name, 'updating available agents');
|
|
55
|
+
this.agent.task.updateAvailableAgents(agents);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
this.socket.on('restart-agent', (agentName) => {
|
|
60
|
+
console.log(`Restarting agent: ${agentName}`);
|
|
61
|
+
this.agent.cleanKill();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
this.socket.on('send-message', (data) => {
|
|
65
|
+
try {
|
|
66
|
+
this.agent.respondFunc(data.from, data.message);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error('Error: ', JSON.stringify(error, Object.getOwnPropertyNames(error)));
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
this.socket.on('get-full-state', (callback) => {
|
|
73
|
+
try {
|
|
74
|
+
const state = getFullState(this.agent);
|
|
75
|
+
callback(state);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
console.error('Error getting full state:', error);
|
|
78
|
+
callback(null);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Request settings and wait for response
|
|
83
|
+
await new Promise((resolve, reject) => {
|
|
84
|
+
const timeout = setTimeout(() => {
|
|
85
|
+
reject(new Error('Settings request timed out after 5 seconds'));
|
|
86
|
+
}, 5000);
|
|
87
|
+
|
|
88
|
+
this.socket.emit('get-settings', name, (response) => {
|
|
89
|
+
clearTimeout(timeout);
|
|
90
|
+
if (response.error) {
|
|
91
|
+
return reject(new Error(response.error));
|
|
92
|
+
}
|
|
93
|
+
setSettings(response.settings);
|
|
94
|
+
this.socket.emit('connect-agent-process', name);
|
|
95
|
+
resolve();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
setAgent(agent) {
|
|
101
|
+
this.agent = agent;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
getAgents() {
|
|
105
|
+
return this.agents;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
getNumOtherAgents() {
|
|
109
|
+
return this.agents.length - 1;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
login() {
|
|
113
|
+
this.socket.emit('login-agent', this.agent.name);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
shutdown() {
|
|
117
|
+
this.socket.emit('shutdown');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
getSocket() {
|
|
121
|
+
return this.socket;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Create and export a singleton instance
|
|
126
|
+
export const serverProxy = new MindServerProxy();
|
|
127
|
+
|
|
128
|
+
// for chatting with other bots
|
|
129
|
+
export function sendBotChatToServer(agentName, json) {
|
|
130
|
+
serverProxy.getSocket().emit('chat-message', agentName, json);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// for sending general output to server for display
|
|
134
|
+
export function sendOutputToServer(agentName, message) {
|
|
135
|
+
serverProxy.getSocket().emit('bot-output', agentName, message);
|
|
136
|
+
}
|