mirror of
https://github.com/MoonlitJolteon/hivemine.git
synced 2025-10-31 21:20:20 +00:00
Last update of the day
Signed-off-by: Moonlit Jolteon <moonlit@munebase.dev>
This commit is contained in:
32
README.md
Normal file
32
README.md
Normal file
@ -0,0 +1,32 @@
|
||||
# HiveMine: A Minecraft hivemind
|
||||
HiveMine is a work in progress bot that employs mineflayer as a primary backend for working within a minecraft world. While MineFlayer is a javascript library, HiveMine uses the javascript package for python to be able to load it
|
||||
|
||||
### Prerequirements
|
||||
- Python 3.8+
|
||||
- Required dependencies listed in requirements.txt
|
||||
### Installation
|
||||
Clone the Repository
|
||||
```bash
|
||||
git https://github.com/MoonlitJolteon/hivemine
|
||||
cd hivemine
|
||||
```
|
||||
Create the virtual environment for it to run in
|
||||
```bash
|
||||
python -m venv venv
|
||||
source venv/bin/activate
|
||||
# On Windows, use `venv\Scripts\activate` instead
|
||||
```
|
||||
Install dependencies
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
To start the program, first ensure that you are running a 1.20.1 minecraft server in offline mode on your local machine. Alternatively, you can also launch a single player world and open it to lan specifying 25565 as the port.<br>
|
||||
Next, simply start the bot by running.
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
You can access the web server based controls at the following addresses (heavily WIP, currently going to the URL activates it)
|
||||
|
||||
- List the tasks currently in queue: [127.0.0.1:5000/tasks](127.0.0.1:5000/tasks)
|
||||
- Add an additional demo task to the queue: [127.0.0.1:5000/add_task](127.0.0.1:5000/add_task)
|
||||
- Add 20 demo tasks to the queue: [127.0.0.1:5000/add_many_tasks](127.0.0.1:5000/add_many_tasks)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
28
main.py
28
main.py
@ -12,25 +12,37 @@ def root():
|
||||
|
||||
@app.route('/tasks')
|
||||
def tasks():
|
||||
return "<br>".join([task.name for task in manager.queue.queue])
|
||||
return "<br>".join([task.name for task in manager.tasks.queue])
|
||||
|
||||
num = 0
|
||||
@app.route('/add_task')
|
||||
def add_tasks():
|
||||
def add_task():
|
||||
global num
|
||||
manager.queue(Task(f"Task {num}", demo_task, num))
|
||||
manager.queue(Task(f"Demo Task {num}", demo_task, num))
|
||||
num += 1
|
||||
return "Done"
|
||||
|
||||
@app.route('/add_many_tasks')
|
||||
def add_many_tasks():
|
||||
global num
|
||||
i = 0
|
||||
while i < 20:
|
||||
manager.queue(Task(f"Demo Task {num}", demo_task, num))
|
||||
i += 1
|
||||
num += 1
|
||||
return "Done"
|
||||
|
||||
|
||||
def run():
|
||||
for i in range(1):
|
||||
MCBot(f"bot{i}", manager, is_king = (i == 0))
|
||||
MCBot(f"HiveMineAgent", manager, is_king = True)
|
||||
print("You can access the task list at 127.0.0.1:5000/tasks") # TODO: figure out how to read url/port dynamically
|
||||
print("You can add a single demo task at 127.0.0.1:5000/add_task")
|
||||
print("You can add 20 demo tasks at 127.0.0.1:5000/add_many_tasks")
|
||||
app.run()
|
||||
|
||||
def demo_task(num):
|
||||
sleep(1)
|
||||
print(f"Task {num}")
|
||||
def demo_task(bot_obj, num):
|
||||
sleep(0.2)
|
||||
bot_obj.bot.chat(f"I have completed the demo task! ({num})")
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
13
manager.py
13
manager.py
@ -3,11 +3,6 @@ class Manager:
|
||||
def __init__(self):
|
||||
self.bots = set()
|
||||
self.tasks = Queue()
|
||||
# self.tasks.put(Task("Task A", lambda: print("Task A")))
|
||||
# self.tasks.put(Task("Task B", lambda: print("Task B")))
|
||||
# self.tasks.put(Task("Task C", lambda: print("Task C")))
|
||||
# self.tasks.put(Task("Task D", lambda: print("Task D")))
|
||||
# self.tasks.put(Task("Task E", lambda: print("Task E")))
|
||||
|
||||
def queue(self, task):
|
||||
self.tasks.put(task)
|
||||
@ -27,5 +22,9 @@ class Task:
|
||||
self.func = func
|
||||
self.args = args
|
||||
|
||||
def perform_task(self):
|
||||
self.func(*self.args)
|
||||
def perform_task(self, bot_obj):
|
||||
try:
|
||||
self.func(bot_obj, *self.args)
|
||||
except Exception as e:
|
||||
self.log(e)
|
||||
|
||||
33
mcbot.py
33
mcbot.py
@ -1,7 +1,8 @@
|
||||
from javascript import require, On, off, AsyncTask
|
||||
from simple_chalk import chalk
|
||||
from manager import Task
|
||||
from task_funcs import come, collect_wood, print_inventory, craft_item, place_crafting_table
|
||||
from task_funcs import come, collect_wood, print_inventory, craft_item
|
||||
from time import sleep
|
||||
mineflayer = require('mineflayer')
|
||||
pathfinder = require('mineflayer-pathfinder').pathfinder
|
||||
mineflayerViewer = require('prismarine-viewer').mineflayer
|
||||
@ -59,38 +60,48 @@ class MCBot:
|
||||
def handle_spawn(this):
|
||||
self.log("I spawned 👋")
|
||||
|
||||
@AsyncTask(start=True)
|
||||
@On(self.bot, 'time')
|
||||
def handle_tick_update(this):
|
||||
task = self.manager.get_next_task()
|
||||
if task:
|
||||
task.perform_task()
|
||||
task.perform_task(self)
|
||||
|
||||
@On(self.bot, 'chat')
|
||||
def handle_chat(this, sender, message, *args):
|
||||
if not self.is_king:
|
||||
return
|
||||
return # The king is here to read chat, no one else should be doing so
|
||||
|
||||
if sender not in self.manager.bots:
|
||||
self.log(f"chat message: {sender}> {message}")
|
||||
|
||||
if 'how do you feel about finals' in message.lower():
|
||||
sleep(0.75)
|
||||
self.bot.chat("Honestly?")
|
||||
sleep(1.5)
|
||||
self.bot.chat("Stressed. Can I just skip to Christmas instead?")
|
||||
|
||||
if sender and (sender != self.bot_name) and (message.startswith(f"~")):
|
||||
args = message.split(' ')
|
||||
if 'come' in message:
|
||||
self.manager.queue(Task(f"Come to {sender}", come, self, sender))
|
||||
self.manager.queue(Task(f"Come to {sender}", come, sender))
|
||||
|
||||
if 'collect-wood' in message:
|
||||
self.manager.queue(Task(f"Collect {args[1]} wood", collect_wood, self, args[1]))
|
||||
self.manager.queue(Task(f"Collect {args[1]} wood", collect_wood, args[1]))
|
||||
|
||||
if 'list-inv' in message:
|
||||
self.manager.queue(Task(f"Listing inventory", print_inventory, self))
|
||||
|
||||
if 'place-table' in message:
|
||||
self.manager.queue(Task(f"Placing crafting table", place_crafting_table, self))
|
||||
self.manager.queue(Task(f"Listing inventory", print_inventory))
|
||||
|
||||
if 'craft' in message:
|
||||
self.manager.queue(Task(f"Attempting to craft {args[1]}", craft_item, self, args[1]))
|
||||
self.manager.queue(Task(f"Attempting to craft {args[1]}", craft_item, args[1]))
|
||||
|
||||
if 'wait' in message:
|
||||
def tmp(bot_obj, sleep_time):
|
||||
sleep(sleep_time)
|
||||
bot_obj.bot.chat("Has it been long enough?!")
|
||||
self.manager.queue(Task(f"Waiting for {args[1]} seconds..", tmp, int(args[1])))
|
||||
|
||||
if 'quit' in message:
|
||||
self.bot.chat("Goodbye!")
|
||||
self.reconnect = False
|
||||
self.bot.quit()
|
||||
|
||||
|
||||
@ -1 +1,9 @@
|
||||
blinker==1.9.0
|
||||
click==8.1.7
|
||||
Flask==3.1.0
|
||||
itsdangerous==2.2.0
|
||||
javascript==1!1.2.1
|
||||
Jinja2==3.1.4
|
||||
MarkupSafe==3.0.2
|
||||
simple-chalk==0.1.0
|
||||
Werkzeug==3.1.3
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
from math import sin, cos
|
||||
from javascript import require
|
||||
from simple_chalk import chalk
|
||||
from time import sleep
|
||||
import threading
|
||||
pathfinder = require('mineflayer-pathfinder')
|
||||
|
||||
Vec3 = require('vec3').Vec3
|
||||
def dig_with_wait(bot, block):
|
||||
finished = threading.Event()
|
||||
def on_dig_complete(err):
|
||||
@ -26,8 +27,8 @@ def collect_wood(bot_obj, quantity):
|
||||
for block in blockPoints:
|
||||
bot.chat(f"Found oak log at {block.position}")
|
||||
pos = block.position
|
||||
bot.pathfinder.goto(pathfinder.goals.GoalNear(pos.x, pos.y, pos.z), lambda: dig_with_wait(bot, block))
|
||||
sleep(5)
|
||||
bot.pathfinder.goto(pathfinder.goals.GoalNear(pos.x, pos.y, pos.z), lambda: dig_with_wait(bot, block), timeout=100000)
|
||||
|
||||
|
||||
|
||||
bot_obj.log(chalk.magenta(f"Collecting {quantity} oak wood..."))
|
||||
@ -44,30 +45,6 @@ def print_inventory(bot_obj):
|
||||
bot.chat(f"Item {i+1}: {inv[i].displayName} x{inv[i].count}")
|
||||
bot.chat("]")
|
||||
|
||||
def place_crafting_table(bot_obj):
|
||||
bot = bot_obj.bot
|
||||
# Check if the bot has a crafting table in its inventory
|
||||
crafting_table_id = bot.registry.itemsByName["crafting_table"].id
|
||||
crafting_table_count = bot.inventory.count(crafting_table_id)
|
||||
|
||||
if crafting_table_count > 0:
|
||||
# Get the bot's current position
|
||||
pos = bot.entity.position
|
||||
# Define the position directly below the bot (y - 1)
|
||||
target_pos = {'x': pos.x, 'y': pos.y - 1, 'z': pos.z}
|
||||
|
||||
# Get the block at the target position
|
||||
target_block = bot.world.getBlock(target_pos)
|
||||
|
||||
# If the block below is empty (not a solid block), place the crafting table
|
||||
if target_block and target_block.name == 'air':
|
||||
# Place the crafting table at the target position
|
||||
bot.placeBlock(target_pos, bot.registry.itemsByName["crafting_table"], None, lambda err: place_callback(err, bot))
|
||||
else:
|
||||
bot.chat("Cannot place crafting table, position is blocked.")
|
||||
else:
|
||||
bot.chat("No crafting table in inventory to place.")
|
||||
|
||||
|
||||
def craft_item(bot_obj, item_name, quantity=1):
|
||||
bot = bot_obj.bot
|
||||
@ -105,8 +82,6 @@ def craft_item(bot_obj, item_name, quantity=1):
|
||||
except Exception as e:
|
||||
bot.chat(f"Error during crafting: {str(e)}")
|
||||
|
||||
|
||||
|
||||
|
||||
def come(bot_obj, sender):
|
||||
bot = bot_obj.bot
|
||||
@ -121,4 +96,4 @@ def come(bot_obj, sender):
|
||||
movements = pathfinder.Movements(bot)
|
||||
movements.canDig = False
|
||||
bot.pathfinder.setMovements(movements)
|
||||
bot.pathfinder.setGoal(pathfinder.goals.GoalNear(pos.x, pos.y, pos.z, 2))
|
||||
bot.pathfinder.setGoal(pathfinder.goals.GoalNear(pos.x, pos.y, pos.z, 2))
|
||||
|
||||
Reference in New Issue
Block a user