Rename to mosfet.py, delete linux bash scripts
This commit is contained in:
@@ -7,61 +7,34 @@ Mosfet is able to farm wood by cutting trees, farm crops, gather sand, farm
|
||||
netherwart, and trade with villagers to get emeralds. He can eat, sleep, and
|
||||
flee from threats.
|
||||
|
||||
## Requirements
|
||||
## Requirements and setup
|
||||
|
||||
- Python >= 3.6
|
||||
- pip, virtualenv, git, wget, unzip
|
||||
- Python 3.11+
|
||||
- The locally updated pyCraft checkout at `../pyCraft`
|
||||
|
||||
## Linux Setup
|
||||
|
||||
Assuming Debian / Ubuntu based distro:
|
||||
From the repository root, create and activate a virtual environment, then
|
||||
install the connection-mode dependencies:
|
||||
|
||||
```
|
||||
$ sudo apt update
|
||||
$ sudo apt install build-essential python3 python3-dev python3-pip virtualenv git wget unzip
|
||||
|
||||
$ git clone https://git.tannercollin.com/tanner/minecraft-bot.git
|
||||
$ cd minecraft-bot/
|
||||
$ python3 -m venv .venv
|
||||
$ source .venv/bin/activate
|
||||
$ python -m pip install flask flask-cors munch watchdog -e ../pyCraft
|
||||
```
|
||||
|
||||
## Running
|
||||
|
||||
If you want to use the built-in burner account (Minecraft name `mattstack`):
|
||||
Run the bot directly with Python. For the Protospace offline-mode server:
|
||||
|
||||
```
|
||||
$ SERVER=minecraft.example.com ./run_linux.sh
|
||||
$ SERVER=games.protospace.ca python mosfet.py
|
||||
```
|
||||
|
||||
Or, use `PORT` to specify a custom port to connect to:
|
||||
`mosfet.py` defaults to that server, player name `mosfet1`, and the current
|
||||
AuthMe password. Override `SERVER`, `PORT`, `PLAYER_NAME`, or `GAME_PASSWORD`
|
||||
through environment variables as needed. Microsoft authentication is not used.
|
||||
|
||||
```
|
||||
$ SERVER=localhost PORT=12345 ./run_linux.sh
|
||||
```
|
||||
|
||||
Or, if you have your own alt account for the bot:
|
||||
|
||||
```
|
||||
$ EMAIL=you@domain.com PASSWORD=supersecret SERVER=minecraft.example.com ./run_linux.sh
|
||||
```
|
||||
|
||||
### Current offline servers (Minecraft 26.3)
|
||||
|
||||
The legacy automation in `main.py` uses 1.16-era world/chunk packet handling.
|
||||
For an offline-mode server running Minecraft 26.3, use the minimal current-
|
||||
protocol connection mode instead. It joins as `mosfet1` by default, answers
|
||||
AuthMe registration/login prompts using `GAME_PASSWORD`, and stays connected;
|
||||
world automation is not enabled in this mode.
|
||||
|
||||
The locally updated pyCraft checkout is expected at `../pyCraft`:
|
||||
|
||||
```
|
||||
$ ./run_connect.sh
|
||||
```
|
||||
|
||||
You can override `SERVER`, `PORT`, `PLAYER_NAME`, or `GAME_PASSWORD` through
|
||||
environment variables. The current AuthMe default is `mosfetbot`. pyCraft is
|
||||
being extended locally for protocol 777; no Microsoft authentication is used
|
||||
in this mode.
|
||||
The current entry point connects and handles AuthMe, but world automation is
|
||||
not enabled yet: those modules still depend on 1.16-era packet and world data.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
+32
-16
@@ -1,8 +1,8 @@
|
||||
import importlib
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
import json
|
||||
|
||||
import logging
|
||||
log = logging.getLogger('werkzeug')
|
||||
@@ -18,11 +18,15 @@ from munch import Munch
|
||||
from watchdog.observers import Observer
|
||||
from watchdog.events import PatternMatchingEventHandler
|
||||
|
||||
from mosfet import bot
|
||||
from mosfet import connect
|
||||
|
||||
global_state = Munch()
|
||||
g = global_state
|
||||
g.connection = False
|
||||
g.connected = False
|
||||
g.connection_status = 'disconnected'
|
||||
g.player_position = None
|
||||
g.last_chat = None
|
||||
g.name = None
|
||||
g.mcdata = False
|
||||
g.pos = False
|
||||
@@ -57,20 +61,27 @@ def api_global():
|
||||
def root():
|
||||
return app.send_static_file('index.html')
|
||||
|
||||
reload_timeout = time.time()
|
||||
|
||||
def main():
|
||||
"""Connect using the current offline/AuthMe protocol bootstrap.
|
||||
|
||||
The legacy automation loop is deliberately not started yet: its packet
|
||||
handlers still target Minecraft 1.16 and will be migrated incrementally.
|
||||
"""
|
||||
reload_timeout = time.time()
|
||||
reload_requested = False
|
||||
|
||||
def reload_bot(event):
|
||||
global reload_timeout
|
||||
nonlocal reload_timeout, reload_requested
|
||||
if time.time() - reload_timeout > 2.0:
|
||||
reload_timeout = time.time()
|
||||
reload_requested = True
|
||||
print('Reloading...')
|
||||
g.running = False
|
||||
|
||||
event_handler = PatternMatchingEventHandler(patterns=['*.py'], ignore_patterns=['./main.py'])
|
||||
event_handler.on_any_event = reload_bot
|
||||
|
||||
observer = Observer()
|
||||
event_handler = PatternMatchingEventHandler(
|
||||
patterns=['*.py'], ignore_patterns=['./mosfet.py'])
|
||||
event_handler.on_any_event = reload_bot
|
||||
observer.schedule(event_handler, 'mosfet', recursive=True)
|
||||
observer.start()
|
||||
|
||||
@@ -78,16 +89,23 @@ def main():
|
||||
while True:
|
||||
try:
|
||||
g.running = True
|
||||
bot.bot(global_state)
|
||||
importlib.reload(bot)
|
||||
except BaseException as e:
|
||||
connect.main(global_state)
|
||||
if not reload_requested:
|
||||
break
|
||||
reload_requested = False
|
||||
importlib.reload(connect)
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
except BaseException:
|
||||
g.running = True
|
||||
traceback.print_exc()
|
||||
print('Locking...')
|
||||
while g.running:
|
||||
time.sleep(1)
|
||||
importlib.reload(bot)
|
||||
except KeyboardInterrupt:
|
||||
reload_requested = False
|
||||
importlib.reload(connect)
|
||||
finally:
|
||||
g.running = False
|
||||
observer.stop()
|
||||
observer.join()
|
||||
|
||||
@@ -106,7 +124,5 @@ def run_api():
|
||||
port += 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
threading.Thread(target=run_api).start()
|
||||
time.sleep(1)
|
||||
|
||||
threading.Thread(target=run_api, daemon=True).start()
|
||||
main()
|
||||
+4
-7
@@ -1,5 +1,5 @@
|
||||
if __name__ == '__main__':
|
||||
print('Run main.py instead.')
|
||||
print('Run mosfet.py instead.')
|
||||
exit(1)
|
||||
|
||||
import os
|
||||
@@ -251,11 +251,8 @@ def bot(global_state):
|
||||
if not SERVER:
|
||||
print()
|
||||
print('You must specify a server to connect to. For example:')
|
||||
print('SERVER=minecraft.example.com ./run_linux.sh')
|
||||
print('SERVER=localhost PORT=12345 ./run_linux.sh')
|
||||
print()
|
||||
print('If you want to use your own account:')
|
||||
print('EMAIL=you@domain.com PASSWORD=supersecret SERVER=minecraft.example.com ./run_linux.sh')
|
||||
print('SERVER=minecraft.example.com python mosfet.py')
|
||||
print('SERVER=localhost PORT=12345 python mosfet.py')
|
||||
os._exit(0)
|
||||
elif not g.connection:
|
||||
if EMAIL and PASSWORD:
|
||||
@@ -274,7 +271,7 @@ def bot(global_state):
|
||||
print('')
|
||||
print('Did you forget to specify an email?')
|
||||
print('If you want to use your own account:')
|
||||
print('EMAIL=you@domain.com PASSWORD=supersecret SERVER=minecraft.example.com ./run_linux.sh')
|
||||
print('Set SERVER and run python mosfet.py.')
|
||||
os._exit(0)
|
||||
else:
|
||||
print('No username or password provided, using burner minecraft account...')
|
||||
|
||||
+30
-2
@@ -6,7 +6,7 @@ import os
|
||||
from minecraft.networking.connection import Connection
|
||||
from minecraft.networking.modern import (
|
||||
CancelPostjoinDialog, ChatCommand, PlayShowDialog,
|
||||
SubmitPostjoinLoginDialog, SystemChat, TeleportPosition,
|
||||
PlayLogin, SubmitPostjoinLoginDialog, SystemChat, TeleportPosition,
|
||||
)
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ def component_text(value):
|
||||
return str(value)
|
||||
|
||||
|
||||
def main():
|
||||
def main(global_state=None):
|
||||
server = os.environ.get('SERVER', 'games.protospace.ca')
|
||||
port = int(os.environ.get('PORT', '25565'))
|
||||
username = os.environ.get('PLAYER_NAME', 'mosfet1')
|
||||
@@ -48,6 +48,19 @@ def main():
|
||||
allowed_versions=['26.3'])
|
||||
connection.authme_password = password
|
||||
sent_auth_commands = set()
|
||||
if global_state is not None:
|
||||
global_state.connection = connection
|
||||
global_state.name = username
|
||||
global_state.connected = False
|
||||
global_state.connection_status = 'connecting'
|
||||
global_state.player_position = None
|
||||
|
||||
@connection.listener(PlayLogin)
|
||||
def on_play_login(packet):
|
||||
if global_state is not None:
|
||||
global_state.connected = True
|
||||
global_state.connection_status = 'in_game'
|
||||
|
||||
|
||||
def send_auth_command(action):
|
||||
if action in sent_auth_commands:
|
||||
@@ -61,6 +74,8 @@ def main():
|
||||
|
||||
@connection.listener(TeleportPosition)
|
||||
def on_spawn(packet):
|
||||
if global_state is not None:
|
||||
global_state.player_position = (packet.x, packet.y, packet.z)
|
||||
if getattr(connection, 'authme_mode', 'register') == 'register':
|
||||
send_auth_command('register')
|
||||
|
||||
@@ -79,6 +94,8 @@ def main():
|
||||
@connection.listener(SystemChat)
|
||||
def on_system_chat(packet):
|
||||
message = component_text(packet.content)
|
||||
if global_state is not None:
|
||||
global_state.last_chat = message
|
||||
print('[server] ' + message, flush=True)
|
||||
lowered = message.lower()
|
||||
if 'already registered' in lowered:
|
||||
@@ -96,16 +113,27 @@ def main():
|
||||
username, server, port), flush=True)
|
||||
try:
|
||||
while connection.connected:
|
||||
if global_state is not None and not global_state.get('running', True):
|
||||
break
|
||||
thread = connection.networking_thread
|
||||
if thread is None:
|
||||
break
|
||||
thread.join(timeout=0.5)
|
||||
if connection.connected:
|
||||
connection.disconnect()
|
||||
if connection.exception:
|
||||
raise connection.exception
|
||||
print('Connection ended.', flush=True)
|
||||
except KeyboardInterrupt:
|
||||
print('Disconnecting...', flush=True)
|
||||
connection.disconnect()
|
||||
finally:
|
||||
if connection.connected:
|
||||
connection.disconnect()
|
||||
if global_state is not None:
|
||||
global_state.connection = False
|
||||
global_state.connected = False
|
||||
global_state.connection_status = 'disconnected'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
if ! command -v uv >/dev/null 2>&1; then
|
||||
echo "Install uv to create the local Python environment." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x .venv/bin/python ]; then
|
||||
uv venv .venv
|
||||
fi
|
||||
uv pip install --python .venv/bin/python -e ../pyCraft
|
||||
|
||||
export SERVER="${SERVER:-games.protospace.ca}"
|
||||
export PORT="${PORT:-25565}"
|
||||
export PLAYER_NAME="${PLAYER_NAME:-mosfet1}"
|
||||
export GAME_PASSWORD="${GAME_PASSWORD:-mosfetbot}"
|
||||
exec .venv/bin/python -m mosfet.connect
|
||||
@@ -1,79 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
if [ ! -d "mosfet" ]
|
||||
then
|
||||
echo "You must run this from the mosfet-minecraft-bot directory."
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v virtualenv &> /dev/null
|
||||
then
|
||||
echo "virtualenv could not be found, please install with:"
|
||||
echo "sudo apt install virtualenv"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v wget &> /dev/null
|
||||
then
|
||||
echo "wget could not be found, please install with:"
|
||||
echo "sudo apt install wget"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v unzip &> /dev/null
|
||||
then
|
||||
echo "unzip could not be found, please install with:"
|
||||
echo "sudo apt install unzip"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v python3 &> /dev/null
|
||||
then
|
||||
echo "python3 could not be found, please install with:"
|
||||
echo "sudo apt install python3"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v pip3 &> /dev/null
|
||||
then
|
||||
echo "pip3 could not be found, please install with:"
|
||||
echo "sudo apt install pip3"
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
# download minecraft data
|
||||
|
||||
if [ ! -d "minecraft_data" ]
|
||||
then
|
||||
echo "Grabbing minecraft data..."
|
||||
|
||||
VERSION="1.16.4"
|
||||
|
||||
wget -Omcdata.zip "https://apimon.de/mcdata/$VERSION/$VERSION.zip"
|
||||
mkdir minecraft_data
|
||||
unzip mcdata.zip -d minecraft_data
|
||||
rm mcdata.zip
|
||||
fi
|
||||
|
||||
# https://github.com/pypa/virtualenv/issues/1029
|
||||
PS1=${PS1:-}
|
||||
|
||||
# create virtual environment
|
||||
|
||||
if [ ! -d "env" ]
|
||||
then
|
||||
echo "Installing Python requirements..."
|
||||
|
||||
virtualenv -p python3 env
|
||||
source env/bin/activate
|
||||
pip install -r requirements.txt
|
||||
else
|
||||
source env/bin/activate
|
||||
fi
|
||||
|
||||
echo "Running bot..."
|
||||
|
||||
python main.py
|
||||
@@ -1,88 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
if [ ! -d "mosfet" ]
|
||||
then
|
||||
echo "You must run this from the mosfet-minecraft-bot directory."
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v virtualenv &> /dev/null
|
||||
then
|
||||
echo "virtualenv could not be found, please install with:"
|
||||
echo "sudo apt install virtualenv"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v wget &> /dev/null
|
||||
then
|
||||
echo "wget could not be found, please install with:"
|
||||
echo "sudo apt install wget"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v unzip &> /dev/null
|
||||
then
|
||||
echo "unzip could not be found, please install with:"
|
||||
echo "sudo apt install unzip"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v python3 &> /dev/null
|
||||
then
|
||||
echo "python3 could not be found, please install with:"
|
||||
echo "sudo apt install python3"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v pip3 &> /dev/null
|
||||
then
|
||||
echo "pip3 could not be found, please install with:"
|
||||
echo "sudo apt install pip3"
|
||||
exit
|
||||
fi
|
||||
|
||||
if ! command -v git &> /dev/null
|
||||
then
|
||||
echo "git could not be found, please install with:"
|
||||
echo "sudo apt install pip3"
|
||||
exit
|
||||
fi
|
||||
|
||||
|
||||
# download minecraft data
|
||||
|
||||
echo "Grabbing minecraft data..."
|
||||
|
||||
VERSION="1.16.4"
|
||||
|
||||
wget -Omcdata.zip "https://apimon.de/mcdata/$VERSION/$VERSION.zip"
|
||||
rm -r minecraft_data || true
|
||||
mkdir minecraft_data
|
||||
unzip mcdata.zip -d minecraft_data
|
||||
rm mcdata.zip
|
||||
|
||||
|
||||
# update code
|
||||
|
||||
git stash
|
||||
git pull --rebase
|
||||
git stash pop || true
|
||||
|
||||
|
||||
# https://github.com/pypa/virtualenv/issues/1029
|
||||
PS1=${PS1:-}
|
||||
|
||||
# create virtual environment
|
||||
|
||||
echo "Installing Python requirements..."
|
||||
|
||||
rm -r env || true
|
||||
rm -r __pycache__ || true
|
||||
virtualenv -p python3 env
|
||||
source env/bin/activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
|
||||
echo "Done."
|
||||
Reference in New Issue
Block a user