YuShu commited on
Commit
36ba3ef
·
1 Parent(s): df4b2dc

Initial commit

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +2 -0
  2. .gitignore +1 -0
  3. Adam/ADAM.py +505 -0
  4. Adam/ActionLib/craftCraftingTable.js +31 -0
  5. Adam/ActionLib/craftDiamondAxe.js +6 -0
  6. Adam/ActionLib/craftDiamondHoe.js +6 -0
  7. Adam/ActionLib/craftDiamondPickaxe.js +6 -0
  8. Adam/ActionLib/craftDiamondShovel.js +6 -0
  9. Adam/ActionLib/craftDiamondSword.js +6 -0
  10. Adam/ActionLib/craftFence.js +15 -0
  11. Adam/ActionLib/craftFenceGate.js +15 -0
  12. Adam/ActionLib/craftFurnace.js +6 -0
  13. Adam/ActionLib/craftGoldenAxe.js +6 -0
  14. Adam/ActionLib/craftGoldenHoe.js +6 -0
  15. Adam/ActionLib/craftGoldenPickaxe.js +6 -0
  16. Adam/ActionLib/craftGoldenShovel.js +6 -0
  17. Adam/ActionLib/craftGoldenSword.js +6 -0
  18. Adam/ActionLib/craftIronAxe.js +6 -0
  19. Adam/ActionLib/craftIronHoe.js +6 -0
  20. Adam/ActionLib/craftIronPickaxe.js +6 -0
  21. Adam/ActionLib/craftIronShovel.js +6 -0
  22. Adam/ActionLib/craftIronSword.js +6 -0
  23. Adam/ActionLib/craftPlanks.js +11 -0
  24. Adam/ActionLib/craftSticks.js +11 -0
  25. Adam/ActionLib/craftStoneAxe.js +6 -0
  26. Adam/ActionLib/craftStoneHoe.js +6 -0
  27. Adam/ActionLib/craftStonePickaxe.js +6 -0
  28. Adam/ActionLib/craftStoneShovel.js +6 -0
  29. Adam/ActionLib/craftStoneSword.js +6 -0
  30. Adam/ActionLib/craftWoodenAxe.js +6 -0
  31. Adam/ActionLib/craftWoodenHoe.js +6 -0
  32. Adam/ActionLib/craftWoodenPickaxe.js +6 -0
  33. Adam/ActionLib/craftWoodenShovel.js +6 -0
  34. Adam/ActionLib/craftWoodenSword.js +6 -0
  35. Adam/ActionLib/gatherCoalOre.js +24 -0
  36. Adam/ActionLib/gatherDirt.js +16 -0
  37. Adam/ActionLib/gatherSand.js +16 -0
  38. Adam/ActionLib/gatherStone.js +16 -0
  39. Adam/ActionLib/gatherWoodLog.js +20 -0
  40. Adam/ActionLib/mineDiamondOre.js +26 -0
  41. Adam/ActionLib/mineGoldOre.js +24 -0
  42. Adam/ActionLib/mineIronOre.js +24 -0
  43. Adam/ActionLib/moveBackward.js +15 -0
  44. Adam/ActionLib/moveDown.js +12 -0
  45. Adam/ActionLib/moveForward.js +15 -0
  46. Adam/ActionLib/moveLeft.js +16 -0
  47. Adam/ActionLib/moveRight.js +16 -0
  48. Adam/ActionLib/moveUp.js +12 -0
  49. Adam/ActionLib/smeltRawGold.js +28 -0
  50. Adam/ActionLib/smeltRawIron.js +28 -0
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.png filter=lfs diff=lfs merge=lfs -text
37
+ *.mp4 filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ .DS_Store
Adam/ADAM.py ADDED
@@ -0,0 +1,505 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import os
3
+ import re
4
+ import sys
5
+ import time
6
+ import threading
7
+
8
+ import openai
9
+ import Adam.util_info
10
+ from concurrent.futures import ThreadPoolExecutor, as_completed
11
+ from env.bridge import VoyagerEnv
12
+ from env.process_monitor import SubprocessMonitor
13
+ from typing import Dict
14
+ from Adam.skill_loader import skill_loader
15
+ from Adam.module_utils import *
16
+ from Adam.infer_API import get_response, get_local_response
17
+ from Adam.MLLM_API import get_image_description
18
+
19
+ lock = threading.Lock()
20
+
21
+
22
+ class ADAM:
23
+ def __init__(
24
+ self,
25
+ mc_port: int = None,
26
+ azure_login: Dict[str, str] = None,
27
+ game_server_port: int = 3000,
28
+ local_llm_port: int = 6000,
29
+ local_mllm_port: int = 7000,
30
+ game_visual_server_port: int = 9000,
31
+ env_request_timeout: int = 180,
32
+ env_wait_ticks: int = 10,
33
+ max_infer_loop_num: int = 2,
34
+ infer_sampling_num: int = 2,
35
+ max_llm_answer_num: int = 2,
36
+ max_try=2,
37
+ prompt_folder_path: str = r'prompts',
38
+ tmp_image_path: str = 'game_image',
39
+ llm_model_type: str = 'gpt-4-turbo-preview',
40
+ use_local_llm_service: bool = False,
41
+ openai_api_key: str = '',
42
+ load_ckpt_path: str = '',
43
+ auto_load_ckpt: bool = False,
44
+ parallel: bool = False,
45
+ ):
46
+ self.env = VoyagerEnv(
47
+ mc_port=mc_port,
48
+ azure_login=azure_login,
49
+ server_port=game_server_port,
50
+ request_timeout=env_request_timeout,
51
+ visual_server_port=game_visual_server_port
52
+ )
53
+ self.default_server_port = game_server_port
54
+ self.local_llm_port = local_llm_port
55
+ self.local_mllm_port = local_mllm_port
56
+ self.parallel = parallel
57
+ if parallel:
58
+ self.env_vector = {game_server_port: self.env}
59
+ for i in range(1, max([infer_sampling_num, max_try])):
60
+ self.env_vector[game_server_port + i] = VoyagerEnv(
61
+ mc_port=mc_port,
62
+ azure_login=azure_login,
63
+ server_port=game_server_port + i,
64
+ request_timeout=env_request_timeout,
65
+ )
66
+ self.env_wait_ticks = env_wait_ticks
67
+ self.max_infer_loop_num = max_infer_loop_num
68
+ self.infer_sampling_num = infer_sampling_num
69
+ self.tmp_image_path = tmp_image_path
70
+ self.dataset_path = U.f_mkdir(os.path.abspath(os.path.dirname(__file__)), "causal_datasets", llm_model_type)
71
+ U.f_mkdir(self.dataset_path, 'causal_result')
72
+ U.f_mkdir(self.dataset_path, 'llm_steps_log')
73
+ U.f_mkdir(self.dataset_path, 'log_data')
74
+ self.ckpt_path = U.f_mkdir(self.dataset_path, 'ckpt', get_time())
75
+ with open(prompt_folder_path + '/LLM_CD_prompt.txt', 'r') as prompt_file:
76
+ self.CD_prompt = prompt_file.read()
77
+ with open(prompt_folder_path + '/planner_prompt.txt', 'r') as prompt_file:
78
+ self.planner_prompt = prompt_file.read()
79
+ with open(prompt_folder_path + '/actor_prompt.txt', 'r') as prompt_file:
80
+ self.actor_prompt = prompt_file.read()
81
+ self.max_try = max_try
82
+ self.max_llm_answer_num = max_llm_answer_num
83
+ self.llm_model_type = llm_model_type
84
+ self.use_local_llm_service = use_local_llm_service
85
+ self.record = None
86
+ self.loop_record = None
87
+ # Observation Item Space S
88
+ self.observation_item_space = []
89
+ self.unlocked_actions = ['A']
90
+ # Learned causal subgraph is represented as {action : [[causes],[effects]]}
91
+ self.learned_causal_subgraph = {}
92
+ self.learned_items = set()
93
+ self.goal = ([], [])
94
+ self.goal_item_letters = translate_item_name_list_to_letter(self.goal[0])
95
+ self.memory = []
96
+ if load_ckpt_path:
97
+ self.load_state(load_ckpt_path)
98
+ if auto_load_ckpt:
99
+ self.auto_load_state()
100
+ openai.api_key = openai_api_key
101
+
102
+ def get_llm_answer(self, prompt):
103
+ if self.use_local_llm_service:
104
+ response_text = get_local_response(prompt, self.local_llm_port)
105
+ else:
106
+ response_text = get_response(prompt, self.llm_model_type)
107
+ return response_text
108
+
109
+ def check_llm_answer(self, prompt_text):
110
+ for _ in range(self.max_llm_answer_num):
111
+ try:
112
+ response_text = self.get_llm_answer(prompt_text)
113
+ extracted_response = re.search(r'{(.*?)}', response_text).group(1)
114
+ cause, effect = extracted_response.strip("{}").replace(" ", "").split(";")
115
+ except Exception as e:
116
+ print("\033[91mLLM inference failed:" + str(e) + '\033[0m')
117
+ continue
118
+ if cause == '':
119
+ cause = []
120
+ else:
121
+ cause = cause.split(",")
122
+ if effect == '':
123
+ effect = []
124
+ else:
125
+ effect = effect.split(",")
126
+ if check_len_valid(cause) and check_len_valid(effect):
127
+ self.loop_record["llm_answer_checks_num"] = _ + 1
128
+ self.loop_record["llm_answer_success"] = True
129
+ self.loop_record["llm_answer_record"].append([cause, effect])
130
+ self.loop_record["llm_answer_content"] = response_text
131
+ return True, cause, effect
132
+ return False, None, None
133
+
134
+ def init_record_structure(self, action_name):
135
+ return {
136
+ "loop_num": 0,
137
+ "infer_sampling_num": self.infer_sampling_num,
138
+ "successful": False,
139
+ "action_type": action_name,
140
+ "loop_list": [],
141
+ }
142
+
143
+ def update_available_knowledge(self, item_key):
144
+ self.learned_items.update([item_key])
145
+ if item_key in Adam.util_info.unlock.keys():
146
+ self.unlocked_actions.extend(Adam.util_info.unlock[item_key])
147
+
148
+ def update_material_dict(self, end_item):
149
+ current_max_key = max(Adam.util_info.material_names_dict.keys(), key=key_cmp_func)
150
+ for item in end_item.keys():
151
+ item = rename_item(item)
152
+ if item not in Adam.util_info.material_names_dict.values():
153
+ current_max_key = generate_next_key(current_max_key)
154
+ Adam.util_info.material_names_dict[current_max_key] = item
155
+ Adam.util_info.material_names_rev_dict[item] = current_max_key
156
+ item_key = Adam.util_info.material_names_rev_dict[item]
157
+ if item_key not in self.observation_item_space:
158
+ self.observation_item_space.append(item_key)
159
+
160
+ def save_state(self):
161
+ state = {
162
+ 'observation_item_space': self.observation_item_space,
163
+ 'unlocked_actions': self.unlocked_actions,
164
+ 'learned_causal_subgraph': self.learned_causal_subgraph,
165
+ 'learned_items': list(self.learned_items),
166
+ 'memory': self.memory, # serve as log
167
+ 'goal': self.goal,
168
+ 'goal_item_letters': self.goal_item_letters,
169
+ 'material_names_dict': Adam.util_info.material_names_dict,
170
+ 'material_names_rev_dict': Adam.util_info.material_names_rev_dict
171
+ }
172
+ filepath = U.f_join(self.ckpt_path, get_time() + '.json')
173
+ with open(filepath, 'w') as f:
174
+ json.dump(state, f, indent=4)
175
+
176
+ def load_state(self, filepath):
177
+ with open(filepath, 'r') as f:
178
+ state = json.load(f)
179
+ self.observation_item_space = state['observation_item_space']
180
+ self.unlocked_actions = state['unlocked_actions']
181
+ self.learned_causal_subgraph = state['learned_causal_subgraph']
182
+ self.learned_items = set(state['learned_items'])
183
+ self.goal = tuple(state['goal'])
184
+ self.goal_item_letters = state['goal_item_letters']
185
+ Adam.util_info.material_names_dict = state['material_names_dict']
186
+ Adam.util_info.material_names_rev_dict = state['material_names_rev_dict']
187
+
188
+ def auto_load_state(self):
189
+ ckpt = U.f_listdir(self.dataset_path, 'ckpt', full_path=True, recursive=True)
190
+ if ckpt:
191
+ self.load_state(ckpt[-1])
192
+
193
+ def get_causal_graph(self):
194
+ return '\n'.join([f"Action: {key}; Cause: {value[0]}; Effect {value[1]}" for key, value in
195
+ self.learned_causal_subgraph.items()])
196
+
197
+ def sample_action_once(self, env, action):
198
+ options = {"inventory": {}, "mode": "hard"}
199
+ for material in self.observation_item_space:
200
+ options["inventory"] = get_inventory_number(options["inventory"], material)
201
+ env.reset(options=options)
202
+ time.sleep(1)
203
+ result = env.step(skill_loader(action))
204
+ time.sleep(1)
205
+ start_item = result[0][1]['inventory']
206
+ result = env.step('')
207
+ time.sleep(1)
208
+ end_item = result[0][1]['inventory']
209
+ consumed_items, added_items = get_item_changes(start_item, end_item)
210
+ if not added_items:
211
+ return False
212
+ with lock:
213
+ recorder(start_item, end_item, consumed_items, added_items, action, self.dataset_path)
214
+ self.update_material_dict(end_item)
215
+ env.close()
216
+ time.sleep(1)
217
+ return True
218
+
219
+ # Interaction module, sampling and recording
220
+ def sampling_and_recording_action(self, action):
221
+ if self.parallel:
222
+ success_count = 0
223
+ while success_count < self.infer_sampling_num:
224
+ with ThreadPoolExecutor(max_workers=self.infer_sampling_num) as executor:
225
+ futures = []
226
+ for idx in range(self.infer_sampling_num):
227
+ futures.append(
228
+ executor.submit(self.sample_action_once, self.env_vector[self.default_server_port + idx],
229
+ action))
230
+ time.sleep(0.5)
231
+ results = [future.result() for future in futures]
232
+ success_count += results.count(True)
233
+ else:
234
+ for i in range(self.infer_sampling_num):
235
+ print(f'Sampling {i + 1} started')
236
+ while not self.sample_action_once(self.env, action):
237
+ ...
238
+
239
+ def causal_verification_once(self, env, options_orig, action, effect_item):
240
+ try:
241
+ print(f'Verification of action {action}, inventory: {options_orig["inventory"]}')
242
+ env.reset(options=options_orig)
243
+ time.sleep(1)
244
+ result = env.step(skill_loader(action))
245
+ time.sleep(1)
246
+ start_item = result[0][1]['inventory']
247
+ result = env.step('')
248
+ time.sleep(1)
249
+ end_item = result[0][1]['inventory']
250
+ consumed_items, added_items = get_item_changes(start_item, end_item)
251
+ with lock:
252
+ recorder(start_item, end_item, consumed_items, added_items, action, self.dataset_path)
253
+ env.close()
254
+ time.sleep(1)
255
+ return check_in_material(added_items, effect_item)
256
+ except Exception as e:
257
+ print(f"Error during causal verification: {e}")
258
+ return False
259
+
260
+ # Causal model module verification method
261
+ def causal_verification(self, options_orig, action, effect_item):
262
+ if self.parallel:
263
+ with ThreadPoolExecutor(max_workers=self.max_try) as executor:
264
+ futures = []
265
+ for idx in range(self.max_try):
266
+ futures.append(
267
+ executor.submit(self.causal_verification_once, self.env_vector[self.default_server_port + idx],
268
+ options_orig, action, effect_item))
269
+ time.sleep(0.5)
270
+ results = [future.result() for future in as_completed(futures)]
271
+ if any(results):
272
+ return True
273
+ return False
274
+ else:
275
+ for i in range(self.max_try):
276
+ if self.causal_verification_once(self.env, options_orig, action, effect_item):
277
+ return True
278
+ return False
279
+
280
+ # Causal model module: LLM-based CD and Intervention-based CD
281
+ def causal_learning(self, action):
282
+ record_json_path = U.f_join(self.dataset_path, 'log_data', action + '.json')
283
+ for loop_index in range(self.max_infer_loop_num):
284
+ self.record["loop_num"] += 1
285
+ self.loop_record = {"loop_id": loop_index + 1,
286
+ "llm_answer_record": [],
287
+ "llm_answer_checks_num": self.max_llm_answer_num,
288
+ "llm_answer_success": False,
289
+ "llm_answer_verification_success": False,
290
+ }
291
+
292
+ print(f'Start action {action}')
293
+ self.sampling_and_recording_action(action)
294
+
295
+ with open(record_json_path, 'r') as file:
296
+ data = json.load(file)
297
+ CD_prompt = copy.deepcopy(self.CD_prompt)
298
+ dict_string = '\n'.join(
299
+ [f"'{key}': '{Adam.util_info.material_names_dict[key]}'" for key in self.observation_item_space])
300
+ CD_prompt = CD_prompt.replace("{mapping}", dict_string, 1)
301
+ for i, item in enumerate(data[(-self.infer_sampling_num):], start=1):
302
+ initial_items = ', '.join(item['Start item'])
303
+ consumed_items = ', '.join(item['Consumed items'])
304
+ added_items = ', '.join(item['Added items'])
305
+ sampling_result = f"{i}. Initial items: {initial_items}; Consumed items: {consumed_items}; Added items: {added_items}\n"
306
+ CD_prompt += sampling_result
307
+ CD_prompt += "\nYour inference:\n"
308
+
309
+ flag, cause, effect = self.check_llm_answer(CD_prompt)
310
+ if not flag:
311
+ self.record["loop_list"].append(self.loop_record)
312
+ print('LLM inference failed')
313
+ continue
314
+ print(f'Causal assumption: Cause:{cause}, Effect:{effect}')
315
+ self.loop_record["cause_llm"] = cause
316
+ self.loop_record['effect_llm'] = effect
317
+ for effect_item in effect:
318
+ options_orig = {"inventory": {}, "mode": "hard"}
319
+ for item in cause:
320
+ options_orig["inventory"] = get_inventory_number(options_orig["inventory"], item)
321
+ try:
322
+ if not self.causal_verification(options_orig, action, effect_item):
323
+ self.record["loop_list"].append(self.loop_record)
324
+ break
325
+ except Exception as e:
326
+ print("Error: ", str(e))
327
+ break
328
+ self.loop_record["llm_answer_verification_success"] = True
329
+
330
+ # Implement do() operation for each variable in cause
331
+ items_to_remove = []
332
+ for item in cause:
333
+ options_modified = copy.deepcopy(options_orig)
334
+ item_name = rename_item_rev(translate_item_letter_to_name(item))
335
+ del options_modified["inventory"][item_name]
336
+ if self.causal_verification(options_modified, action, effect_item):
337
+ options_orig = options_modified
338
+ items_to_remove.append(item)
339
+
340
+ self.loop_record['items_to_remove'] = items_to_remove
341
+ self.loop_record['items_to_remove_length'] = len(items_to_remove)
342
+ for item in items_to_remove:
343
+ cause.remove(item)
344
+
345
+ print('Causal relation found!')
346
+ print('Cause:', cause)
347
+ print('Effect:', effect_item)
348
+ self.loop_record["cause_found"] = cause
349
+ self.loop_record["effect_found"] = effect_item
350
+ with open(U.f_join(self.dataset_path, 'causal_result', action + '.json'), 'w') as json_file:
351
+ json.dump([cause, effect_item], json_file)
352
+ self.record["successful"] = True
353
+ self.record["loop_list"].append(self.loop_record)
354
+ llm_steps_path = U.f_join(self.dataset_path, 'llm_steps_log', action + '.json')
355
+ try:
356
+ with open(llm_steps_path, 'r') as file:
357
+ try:
358
+ logs = json.load(file)
359
+ except json.JSONDecodeError:
360
+ logs = []
361
+ except FileNotFoundError:
362
+ logs = []
363
+ logs.append(self.record)
364
+ with open(llm_steps_path, 'w') as file:
365
+ json.dump(logs, file, indent=4)
366
+ action_key = translate_action_name_to_letter(action)
367
+ if action_key not in self.learned_causal_subgraph:
368
+ self.learned_causal_subgraph[action_key] = [cause, [effect_item]]
369
+ else:
370
+ self.learned_causal_subgraph[action_key][1].append(effect_item)
371
+ self.update_available_knowledge(effect_item)
372
+ self.save_state()
373
+ return True
374
+ return False
375
+
376
+ def planner(self, current_inventory):
377
+ inventory_name_and_num = copy.deepcopy(current_inventory)
378
+ current_inventory = translate_item_name_list_to_letter(current_inventory)
379
+ not_obtained_items = [item for item in self.goal_item_letters if item not in current_inventory]
380
+ planner_prompt = copy.deepcopy(self.planner_prompt)
381
+ replacements = {
382
+ "{goal}": ', '.join(translate_item_name_list_to_letter(self.goal[0])),
383
+ "{mapping}": str(Adam.util_info.material_names_dict),
384
+ "{current inventory}": ', '.join(current_inventory),
385
+ "{inventory name and num}": str(inventory_name_and_num),
386
+ "{lacked inventory}": ', '.join(not_obtained_items),
387
+ "{causal graph}": self.get_causal_graph(),
388
+ }
389
+ for key, value in replacements.items():
390
+ planner_prompt = planner_prompt.replace(key, value, 1)
391
+ subtask = self.get_llm_answer(planner_prompt)
392
+ print('\033[94m' + '-' * 20 + 'Planner' + '-' * 20 + '\n' + subtask + '\033[0m')
393
+ return subtask
394
+
395
+ def actor(self, subtask, perception):
396
+ max_attempts = 3
397
+ attempts = 0
398
+ while attempts < max_attempts:
399
+ try:
400
+ actor_prompt = copy.deepcopy(self.actor_prompt)
401
+ replacements = {
402
+ "{causal graph}": self.get_causal_graph(),
403
+ "{available actions}": ', '.join(self.unlocked_actions),
404
+ "{goal items}": ', '.join(translate_item_name_list_to_letter(self.goal[0])),
405
+ "{environmental factors}": ', '.join(self.goal[1]),
406
+ "{memory}": self.get_memory(),
407
+ "{subtasks}": subtask,
408
+ "{perception}": perception,
409
+ }
410
+ for key, value in replacements.items():
411
+ actor_prompt = actor_prompt.replace(key, value, 1)
412
+ action_response = self.get_llm_answer(actor_prompt)
413
+ print('\033[32m' + '-' * 20 + 'Actor' + '-' * 20 + '\n' + action_response + '\033[0m')
414
+ action = translate_action_letter_to_name(re.search(r'{(.*?)}', action_response).group(1))
415
+ break
416
+ except Exception as e:
417
+ attempts += 1
418
+ print(f"Attempt {attempts}: An error occurred - {e}")
419
+ if attempts == max_attempts:
420
+ return 'moveForward'
421
+ return action
422
+
423
+ def update_memory(self, action_letter, consumed_items, added_items, environment_description):
424
+ self.memory.append([action_letter, consumed_items, added_items, environment_description])
425
+
426
+ def get_memory(self):
427
+ recent_memory = self.memory[-3:]
428
+ formatted_prompt = []
429
+
430
+ for entry in recent_memory:
431
+ action_letter, consumed_items, added_items, environment_description = entry
432
+ formatted_entry = f"Action: {action_letter}\n" \
433
+ f"Consumed Items: {', '.join(translate_item_name_list_to_letter(consumed_items))}\n" \
434
+ f"Added Items: {', '.join(translate_item_name_list_to_letter(added_items))}\n" \
435
+ f"Environment: {environment_description}\n" \
436
+ "----"
437
+ formatted_prompt.append(formatted_entry)
438
+
439
+ return f"The most recent {len(recent_memory)} records\n----\n" + "\n".join(formatted_prompt)
440
+
441
+ def controller(self):
442
+ # initial Minecraft instance
443
+ options = {"mode": "hard"}
444
+ self.env.reset(options=options)
445
+ result = self.env.step('')
446
+ self.run_visual_API()
447
+ while True:
448
+ environment_description = get_image_description(local_mllm_port=self.local_mllm_port)
449
+ if all(item in translate_item_name_list_to_letter(result[0][1]['inventory'].keys()) for item in
450
+ self.goal_item_letters):
451
+ subtask = 'Achieve the environmental factors.'
452
+ else:
453
+ subtask = self.planner(result[0][1]['inventory'])
454
+ action = self.actor(subtask, environment_description)
455
+ print('Action:', action)
456
+ result = self.env.step(skill_loader(action))
457
+ start_item = result[0][1]['inventory']
458
+ result = self.env.step('')
459
+ end_item = result[0][1]['inventory']
460
+ print('Inventory now:', str(result[0][1]['inventory']))
461
+ print('Voxels around:', str(result[0][1]['voxels']))
462
+ consumed_items, added_items = get_item_changes(start_item, end_item)
463
+ recorder(start_item, end_item, consumed_items, added_items, action, self.dataset_path)
464
+ self.update_material_dict(end_item)
465
+ self.update_memory(action, consumed_items, added_items, environment_description)
466
+ if self.check_goal_completed(result):
467
+ return
468
+
469
+ def check_goal_completed(self, result):
470
+ return all(item in translate_item_name_list_to_letter(result[0][1]['inventory'].keys()) for item in
471
+ self.goal_item_letters) and all(item in result[0][1]['voxels'] for item in self.goal[1])
472
+
473
+ def learn_new_actions(self):
474
+ for action in reversed(self.unlocked_actions):
475
+ if action not in self.learned_causal_subgraph.keys():
476
+ self.record = self.init_record_structure(action)
477
+ self.causal_learning(translate_action_letter_to_name(action))
478
+ break
479
+
480
+ def explore(self, goal_item, goal_environment):
481
+ self.goal = (goal_item, goal_environment)
482
+ self.goal_item_letters = translate_item_name_list_to_letter(self.goal[0])
483
+ while True:
484
+ if all(item in self.learned_items for item in self.goal_item_letters):
485
+ break
486
+ self.learn_new_actions()
487
+
488
+ self.controller()
489
+ while len(self.learned_causal_subgraph.keys()) < len(self.unlocked_actions):
490
+ self.learn_new_actions()
491
+
492
+ def run_visual_API(self):
493
+ python_executable = sys.executable
494
+ script_path = os.path.join(os.getcwd(), 'Adam', "visual_API.py")
495
+ commands = [python_executable, script_path]
496
+ monitor = SubprocessMonitor(
497
+ commands=commands,
498
+ name="VisualAPIMonitor",
499
+ ready_match=r"Visual API Ready",
500
+ log_path="logs",
501
+ callback_match=r"Error",
502
+ callback=lambda: print("Error detected in subprocess!"),
503
+ finished_callback=lambda: print("Subprocess has finished.")
504
+ )
505
+ monitor.run()
Adam/ActionLib/craftCraftingTable.js ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function craftCraftingTable(bot) {
2
+ bot.chat("Start crafting Crafting Table");
3
+
4
+ const plankTypes = ["oak_planks", "birch_planks", "spruce_planks", "jungle_planks", "acacia_planks", "dark_oak_planks", "mangrove_planks"];
5
+ let totalPlanks = 0;
6
+ let planksToToss = [];
7
+
8
+ for (let plankType of plankTypes) {
9
+ let plank = bot.inventory.findInventoryItem(mcData.itemsByName[plankType].id);
10
+ if (plank) {
11
+ totalPlanks += bot.inventory.count(mcData.itemsByName[plankType].id);
12
+ planksToToss.push(plankType);
13
+ }
14
+ }
15
+
16
+ if (totalPlanks < 4) {
17
+ bot.chat("Not enough planks to craft a crafting table.");
18
+ return;
19
+ }
20
+
21
+ let planksDiscarded = 0;
22
+ for (let plankType of planksToToss) {
23
+ if (planksDiscarded >= 4) break;
24
+ let toToss = Math.min(bot.inventory.count(mcData.itemsByName[plankType].id), 4 - planksDiscarded);
25
+ await bot.toss(mcData.itemsByName[plankType].id, null, toToss);
26
+ planksDiscarded += toToss;
27
+ }
28
+
29
+ bot.chat("/give @s crafting_table");
30
+ bot.chat("Crafted a crafting_table");
31
+ }
Adam/ActionLib/craftDiamondAxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftDiamondAxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "diamond_axe", 1);
5
+ bot.chat("Crafted a diamond axe.");
6
+ }
Adam/ActionLib/craftDiamondHoe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftDiamondHoe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "diamond_hoe", 1);
5
+ bot.chat("Crafted a diamond hoe.");
6
+ }
Adam/ActionLib/craftDiamondPickaxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftDiamondPickaxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "diamond_pickaxe", 1);
5
+ bot.chat("Crafted a diamond pickaxe.");
6
+ }
Adam/ActionLib/craftDiamondShovel.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftDiamondShovel(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "diamond_shovel", 1);
5
+ bot.chat("Crafted a diamond shovel.");
6
+ }
Adam/ActionLib/craftDiamondSword.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftDiamondSword(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "diamond_sword", 1);
5
+ bot.chat("Crafted a diamond sword.");
6
+ }
Adam/ActionLib/craftFence.js ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function craftFence(bot) {
2
+ const planksTypes = ["oak_planks", "birch_planks", "spruce_planks", "jungle_planks", "acacia_planks", "dark_oak_planks", "mangrove_planks"];
3
+ const position = bot.entity.position.offset(1, 0, 0);
4
+ await placeItem(bot, "crafting_table", position);
5
+
6
+ for (let planksType of planksTypes) {
7
+ let planks = bot.inventory.findInventoryItem(mcData.itemsByName[planksType].id);
8
+ if (planks) {
9
+ let fenceType = planksType.replace('_planks', '_fence');
10
+ await craftItem(bot, fenceType, 1);
11
+ bot.chat(`Crafted ${fenceType.replace('_', ' ')}.`);
12
+ return;
13
+ }
14
+ }
15
+ }
Adam/ActionLib/craftFenceGate.js ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function craftFenceGate(bot) {
2
+ const planksTypes = ["oak_planks", "birch_planks", "spruce_planks", "jungle_planks", "acacia_planks", "dark_oak_planks", "mangrove_planks"];
3
+ const position = bot.entity.position.offset(1, 0, 0);
4
+ await placeItem(bot, "crafting_table", position);
5
+
6
+ for (let planksType of planksTypes) {
7
+ let planks = bot.inventory.findInventoryItem(mcData.itemsByName[planksType].id);
8
+ if (planks) {
9
+ let fence_gateType = planksType.replace('_planks', '_fence_gate');
10
+ await craftItem(bot, fence_gateType, 1);
11
+ bot.chat(`Crafted ${fence_gateType.replace('_', ' ')}.`);
12
+ return;
13
+ }
14
+ }
15
+ }
Adam/ActionLib/craftFurnace.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftFurnace(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "furnace", 1);
5
+ bot.chat("Crafted a furnace");
6
+ }
Adam/ActionLib/craftGoldenAxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftGoldenAxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "golden_axe", 1);
5
+ bot.chat("Crafted a golden axe.");
6
+ }
Adam/ActionLib/craftGoldenHoe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftGoldenHoe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "golden_hoe", 1);
5
+ bot.chat("Crafted a golden hoe.");
6
+ }
Adam/ActionLib/craftGoldenPickaxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftGoldenPickaxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "golden_pickaxe", 1);
5
+ bot.chat("Crafted a golden pickaxe.");
6
+ }
Adam/ActionLib/craftGoldenShovel.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftGoldenShovel(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "golden_shovel", 1);
5
+ bot.chat("Crafted a golden shovel.");
6
+ }
Adam/ActionLib/craftGoldenSword.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftGoldenSword(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "golden_sword", 1);
5
+ bot.chat("Crafted a golden sword.");
6
+ }
Adam/ActionLib/craftIronAxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftIronAxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "iron_axe", 1);
5
+ bot.chat("Crafted a iron axe.");
6
+ }
Adam/ActionLib/craftIronHoe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftIronHoe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "iron_hoe", 1);
5
+ bot.chat("Crafted a iron hoe.");
6
+ }
Adam/ActionLib/craftIronPickaxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftIronPickaxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "iron_pickaxe", 1);
5
+ bot.chat("Crafted an iron pickaxe.");
6
+ }
Adam/ActionLib/craftIronShovel.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftIronShovel(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "iron_shovel", 1);
5
+ bot.chat("Crafted a iron shovel.");
6
+ }
Adam/ActionLib/craftIronSword.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftIronSword(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "iron_sword", 1);
5
+ bot.chat("Crafted a iron sword.");
6
+ }
Adam/ActionLib/craftPlanks.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function craftPlanks(bot) {
2
+ const logTypes = ["oak_log", "birch_log", "spruce_log", "jungle_log", "acacia_log", "dark_oak_log", "mangrove_log"];
3
+ for (let logType of logTypes) {
4
+ let log = bot.inventory.count(mcData.itemsByName[logType].id);
5
+ if (log) {
6
+ let plankType = logType.replace('_log', '_planks');
7
+ await craftItem(bot, plankType, 10);
8
+ bot.chat(`Crafted ${plankType.replace('_', ' ')}.`);
9
+ }
10
+ }
11
+ }
Adam/ActionLib/craftSticks.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function craftSticks(bot) {
2
+ const plankTypes = ["oak_planks", "birch_planks", "spruce_planks", "jungle_planks", "acacia_planks", "dark_oak_planks", "mangrove_planks"];
3
+ for (let plankType of plankTypes) {
4
+ let plank = bot.inventory.findInventoryItem(mcData.itemsByName[plankType].id);
5
+ if (plank) {
6
+ await craftItem(bot, "stick", 8);
7
+ bot.chat(`Crafted sticks from ${plankType.replace('_', ' ')}.`);
8
+ return;
9
+ }
10
+ }
11
+ }
Adam/ActionLib/craftStoneAxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftStoneAxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "stone_axe", 1);
5
+ bot.chat("Crafted a stone axe.");
6
+ }
Adam/ActionLib/craftStoneHoe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftStoneHoe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "stone_hoe", 1);
5
+ bot.chat("Crafted a stone hoe.");
6
+ }
Adam/ActionLib/craftStonePickaxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftStonePickaxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "stone_pickaxe", 1);
5
+ bot.chat("Crafted a stone pickaxe.");
6
+ }
Adam/ActionLib/craftStoneShovel.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftStoneShovel(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "stone_shovel", 1);
5
+ bot.chat("Crafted a stone shovel.");
6
+ }
Adam/ActionLib/craftStoneSword.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftStoneSword(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "stone_sword", 1);
5
+ bot.chat("Crafted a stone sword.");
6
+ }
Adam/ActionLib/craftWoodenAxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftWoodenAxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "wooden_axe", 1);
5
+ bot.chat("Crafted a wooden axe.");
6
+ }
Adam/ActionLib/craftWoodenHoe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftWoodenHoe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "wooden_hoe", 1);
5
+ bot.chat("Crafted a wooden hoe.");
6
+ }
Adam/ActionLib/craftWoodenPickaxe.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftWoodenPickaxe(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "wooden_pickaxe", 1);
5
+ bot.chat("Crafted a wooden pickaxe.");
6
+ }
Adam/ActionLib/craftWoodenShovel.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftWoodenShovel(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "wooden_shovel", 1);
5
+ bot.chat("Crafted a wooden shovel.");
6
+ }
Adam/ActionLib/craftWoodenSword.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ async function craftWoodenSword(bot) {
2
+ const position = bot.entity.position.offset(1, 0, 0);
3
+ await placeItem(bot, "crafting_table", position);
4
+ await craftItem(bot, "wooden_sword", 1);
5
+ bot.chat("Crafted a wooden sword.");
6
+ }
Adam/ActionLib/gatherCoalOre.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function mineCoalOre(bot) {
2
+ bot.chat('Gathering coal ore started');
3
+ const woodenPickaxeCount = bot.inventory.count(mcData.itemsByName.wooden_pickaxe.id);
4
+
5
+ if (woodenPickaxeCount < 1) {
6
+ bot.chat("No wooden_pickaxe. Mining coal ore failed");
7
+ return;
8
+ }
9
+ // Find an coal ore block
10
+ const coalOreBlock = await exploreUntil(bot, new Vec3(0, -1, 0), 60, () => {
11
+ const coalOre = bot.findBlock({
12
+ matching: mcData.blocksByName["coal_ore"].id,
13
+ maxDistance: 32
14
+ });
15
+ return coalOre;
16
+ });
17
+ if (!coalOreBlock) {
18
+ bot.chat("No coal ore found.");
19
+ return;
20
+ }
21
+ // Mine the coal ore block
22
+ await mineBlock(bot, "coal_ore", 5);
23
+ bot.chat("Mined 5 coal ore.");
24
+ }
Adam/ActionLib/gatherDirt.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function gatherDirt(bot) {
2
+ bot.chat('Gathering dirt started');
3
+ const dirtBlock = await exploreUntil(bot, new Vec3(1, -1, 1), 60, () => {
4
+ const dirt = bot.findBlock({
5
+ matching: mcData.blocksByName["dirt"].id,
6
+ maxDistance: 32
7
+ });
8
+ return dirt;
9
+ });
10
+ if (!dirtBlock) {
11
+ bot.chat("No dirt block found.");
12
+ return;
13
+ }
14
+ await mineBlock(bot, "dirt", 16);
15
+ bot.chat("Mined 16 dirt blocks.");
16
+ }
Adam/ActionLib/gatherSand.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function gatherSand(bot) {
2
+ bot.chat('Gathering sand started');
3
+ const sandBlock = await exploreUntil(bot, new Vec3(1, -1, 1), 60, () => {
4
+ const sand = bot.findBlock({
5
+ matching: mcData.blocksByName["sand"].id,
6
+ maxDistance: 32
7
+ });
8
+ return sand;
9
+ });
10
+ if (!sandBlock) {
11
+ bot.chat("No sand block found.");
12
+ return;
13
+ }
14
+ await mineBlock(bot, "sand", 16);
15
+ bot.chat("Mined 16 sand blocks.");
16
+ }
Adam/ActionLib/gatherStone.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function gatherStone(bot) {
2
+ bot.chat('Gathering stone started');
3
+ const stoneBlock = await exploreUntil(bot, new Vec3(1, -1, 1), 60, () => {
4
+ const stone = bot.findBlock({
5
+ matching: mcData.blocksByName["stone"].id,
6
+ maxDistance: 32
7
+ });
8
+ return stone;
9
+ });
10
+ if (!stoneBlock) {
11
+ bot.chat("No stone block found.");
12
+ return;
13
+ }
14
+ await mineBlock(bot, "stone", 16);
15
+ bot.chat("Mined 16 stone blocks.");
16
+ }
Adam/ActionLib/gatherWoodLog.js ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function gatherWoodLog(bot) {
2
+ bot.chat('Gathering wood logs started');
3
+
4
+ // Find a wood log block
5
+ const woodLogBlock = await exploreUntil(bot, new Vec3(1, 0, 1), 120, () => {
6
+ const woodLog = bot.findBlock({
7
+ matching: block => ["oak_log", "birch_log", "spruce_log", "jungle_log", "acacia_log", "dark_oak_log", "mangrove_log"].includes(block.name),
8
+ maxDistance: 32
9
+ });
10
+ return woodLog;
11
+ });
12
+
13
+ if (!woodLogBlock) {
14
+ bot.chat("No wood log found.");
15
+ return;
16
+ }
17
+ // Mine the wood log block
18
+ await mineBlock(bot, woodLogBlock.name, 12);
19
+ bot.chat("Gathered 12 wood logs.");
20
+ }
Adam/ActionLib/mineDiamondOre.js ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function mineDiamondOre(bot) {
2
+ bot.chat('Mining diamond ore started');
3
+ const ironPickaxeCount = bot.inventory.count(mcData.itemsByName.iron_pickaxe.id);
4
+
5
+ if (ironPickaxeCount < 1) {
6
+ bot.chat("No iron_pickaxe. Mining diamond ore failed");
7
+ return;
8
+ }
9
+
10
+ // Find a diamond ore block
11
+ const diamondOreBlock = await exploreUntil(bot, new Vec3(0, -1, 0), 120, () => {
12
+ const diamondOre = bot.findBlock({
13
+ matching: mcData.blocksByName["deepslate_diamond_ore"].id,
14
+ maxDistance: 32
15
+ });
16
+ return diamondOre;
17
+ });
18
+
19
+ if (!diamondOreBlock) {
20
+ bot.chat("No diamond ore found.");
21
+ return;
22
+ }
23
+ // Mine the diamond ore block
24
+ await mineBlock(bot, "deepslate_diamond_ore", 1);
25
+ bot.chat("Mined 1 diamond ore.");
26
+ }
Adam/ActionLib/mineGoldOre.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function mineGoldOre(bot) {
2
+ bot.chat('Gathering gold ore started');
3
+ const ironPickaxeCount = bot.inventory.count(mcData.itemsByName.iron_pickaxe.id);
4
+
5
+ if (ironPickaxeCount < 1) {
6
+ bot.chat("No iron_pickaxe. Mining gold ore failed");
7
+ return;
8
+ }
9
+ // Find an gold ore block
10
+ const goldOreBlock = await exploreUntil(bot, new Vec3(0, -1, 0), 60, () => {
11
+ const goldOre = bot.findBlock({
12
+ matching: mcData.blocksByName["deepslate_gold_ore"].id,
13
+ maxDistance: 32
14
+ });
15
+ return goldOre;
16
+ });
17
+ if (!goldOreBlock) {
18
+ bot.chat("No gold ore found.");
19
+ return;
20
+ }
21
+ // Mine the gold ore block
22
+ await mineBlock(bot, "deepslate_gold_ore", 1);
23
+ bot.chat("Mined 1 gold ore.");
24
+ }
Adam/ActionLib/mineIronOre.js ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function mineIronOre(bot) {
2
+ bot.chat('Gathering iron ore started');
3
+ const stonePickaxeCount = bot.inventory.count(mcData.itemsByName.stone_pickaxe.id);
4
+
5
+ if (stonePickaxeCount < 1) {
6
+ bot.chat("No stone_pickaxe. Mining iron ore failed");
7
+ return;
8
+ }
9
+ // Find an iron ore block
10
+ const ironOreBlock = await exploreUntil(bot, new Vec3(0, -1, 0), 120, () => {
11
+ const ironOre = bot.findBlock({
12
+ matching: mcData.blocksByName["iron_ore"].id,
13
+ maxDistance: 32
14
+ });
15
+ return ironOre;
16
+ });
17
+ if (!ironOreBlock) {
18
+ bot.chat("No iron ore found.");
19
+ return;
20
+ }
21
+ // Mine the iron ore block
22
+ await mineBlock(bot, "iron_ore", 3);
23
+ bot.chat("Mined 3 iron ore.");
24
+ }
Adam/ActionLib/moveBackward.js ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function moveBackward(bot) {
2
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
3
+ const mcData = require('minecraft-data')(bot.version);
4
+ const defaultMove = new Movements(bot, mcData);
5
+ bot.pathfinder.setMovements(defaultMove);
6
+
7
+ let pos = bot.entity.position;
8
+ let yaw = bot.entity.yaw;
9
+
10
+ let newX = pos.x + 10 * Math.sin(yaw);
11
+ let newZ = pos.z + 10 * Math.cos(yaw);
12
+
13
+ await bot.pathfinder.setGoal(new GoalXZ(newX, newZ));
14
+ await delay(5000);
15
+ }
Adam/ActionLib/moveDown.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function moveUp(bot) {
2
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
3
+ const mcData = require('minecraft-data')(bot.version);
4
+ const defaultMove = new Movements(bot, mcData);
5
+ bot.pathfinder.setMovements(defaultMove);
6
+
7
+ let pos = bot.entity.position;
8
+ let yaw = bot.entity.yaw;
9
+
10
+ await bot.pathfinder.setGoal(new GoalBlock(pos.x, pos.y -20, pos.z));
11
+ await delay(5000);
12
+ }
Adam/ActionLib/moveForward.js ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function moveForward(bot) {
2
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
3
+ const mcData = require('minecraft-data')(bot.version);
4
+ const defaultMove = new Movements(bot, mcData);
5
+ bot.pathfinder.setMovements(defaultMove);
6
+
7
+ let pos = bot.entity.position;
8
+ let yaw = bot.entity.yaw;
9
+
10
+ let newX = pos.x - 10 * Math.sin(yaw);
11
+ let newZ = pos.z - 10 * Math.cos(yaw);
12
+
13
+ await bot.pathfinder.setGoal(new GoalXZ(newX, newZ));
14
+ await delay(5000);
15
+ }
Adam/ActionLib/moveLeft.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function moveLeft(bot) {
2
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
3
+ const mcData = require('minecraft-data')(bot.version);
4
+ const defaultMove = new Movements(bot, mcData);
5
+ bot.pathfinder.setMovements(defaultMove);
6
+
7
+ let pos = bot.entity.position;
8
+ let yaw = bot.entity.yaw;
9
+
10
+ let newX = pos.x - 10 * Math.cos(yaw);
11
+ let newZ = pos.z + 10 * Math.sin(yaw);
12
+
13
+ await bot.chat(`Old Coordinates: (${pos.x.toFixed(2)}, ${pos.z.toFixed(2)}), Yaw: ${yaw}, New Coordinates: (${newX.toFixed(2)}, ${newZ.toFixed(2)})`);
14
+ await bot.pathfinder.setGoal(new GoalXZ(newX, newZ));
15
+ await delay(5000);
16
+ }
Adam/ActionLib/moveRight.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function moveRight(bot) {
2
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
3
+ const mcData = require('minecraft-data')(bot.version);
4
+ const defaultMove = new Movements(bot, mcData);
5
+ bot.pathfinder.setMovements(defaultMove);
6
+
7
+ let pos = bot.entity.position;
8
+ let yaw = bot.entity.yaw;
9
+
10
+ let newX = pos.x + 10 * Math.cos(yaw);
11
+ let newZ = pos.z - 10 * Math.sin(yaw);
12
+
13
+ await bot.chat(`Old Coordinates: (${pos.x.toFixed(2)}, ${pos.z.toFixed(2)}), Yaw: ${yaw}, New Coordinates: (${newX.toFixed(2)}, ${newZ.toFixed(2)})`);
14
+ await bot.pathfinder.setGoal(new GoalXZ(newX, newZ));
15
+ await delay(5000);
16
+ }
Adam/ActionLib/moveUp.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function moveUp(bot) {
2
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
3
+ const mcData = require('minecraft-data')(bot.version);
4
+ const defaultMove = new Movements(bot, mcData);
5
+ bot.pathfinder.setMovements(defaultMove);
6
+
7
+ let pos = bot.entity.position;
8
+ let yaw = bot.entity.yaw;
9
+
10
+ await bot.pathfinder.setGoal(new GoalBlock(pos.x, pos.y +20, pos.z));
11
+ await delay(5000);
12
+ }
Adam/ActionLib/smeltRawGold.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function smeltRawGold(bot) {
2
+ const rawGoldCount = bot.inventory.count(mcData.itemsByName.raw_gold.id);
3
+
4
+ if (rawGoldCount < 3) {
5
+ bot.chat("No enough raw iron. Smelting failed");
6
+ return;
7
+ }
8
+
9
+ const furnaceCount = bot.inventory.count(mcData.itemsByName.furnace.id);
10
+
11
+ if (furnaceCount < 1) {
12
+ bot.chat("No furnace. Smelting failed");
13
+ return;
14
+ }
15
+
16
+ const logTypes = ["oak_log", "birch_log", "spruce_log", "jungle_log", "acacia_log", "dark_oak_log", "mangrove_log"];
17
+ const plankTypes = logTypes.map(logType => logType.replace('_log', '_planks'));
18
+ const position = bot.entity.position.offset(1, 0, 0);
19
+ await placeItem(bot, "furnace", position);
20
+
21
+ for (let plankType of plankTypes) {
22
+ let plank = bot.inventory.findInventoryItem(mcData.itemsByName[plankType].id);
23
+ if (plank) {
24
+ await smeltItem(bot, "raw_gold", plankType, 3);
25
+ bot.chat(`Smelted 3 raw iron into 3 iron ingots using ${plankType.replace('_', ' ')}.`);
26
+ }
27
+ }
28
+ }
Adam/ActionLib/smeltRawIron.js ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function smeltRawIron(bot) {
2
+ const rawIronCount = bot.inventory.count(mcData.itemsByName.raw_iron.id);
3
+
4
+ if (rawIronCount < 3) {
5
+ bot.chat("No enough raw iron. Smelting failed");
6
+ return;
7
+ }
8
+
9
+ const furnaceCount = bot.inventory.count(mcData.itemsByName.furnace.id);
10
+
11
+ if (furnaceCount < 1) {
12
+ bot.chat("No furnace. Smelting failed");
13
+ return;
14
+ }
15
+
16
+ const logTypes = ["oak_log", "birch_log", "spruce_log", "jungle_log", "acacia_log", "dark_oak_log", "mangrove_log"];
17
+ const plankTypes = logTypes.map(logType => logType.replace('_log', '_planks'));
18
+ const position = bot.entity.position.offset(1, 0, 0);
19
+ await placeItem(bot, "furnace", position);
20
+
21
+ for (let plankType of plankTypes) {
22
+ let plank = bot.inventory.findInventoryItem(mcData.itemsByName[plankType].id);
23
+ if (plank) {
24
+ await smeltItem(bot, "raw_iron", plankType, 3);
25
+ bot.chat(`Smelted 3 raw iron into 3 iron ingots using ${plankType.replace('_', ' ')}.`);
26
+ }
27
+ }
28
+ }