Add minimal connection example for 26.3 and AuthMe Plugin
This commit is contained in:
@@ -44,6 +44,25 @@ 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.
|
||||
|
||||
## Usage
|
||||
|
||||
[How to Cache Items](docs/cache_items.md)
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
"""Minimal current-protocol connection mode for AuthMe / offline servers.
|
||||
|
||||
Run with SERVER=... PLAYER_NAME=mosfet1 GAME_PASSWORD=... python -m mosfet.connect
|
||||
"""
|
||||
import os
|
||||
from minecraft.networking.connection import Connection
|
||||
from minecraft.networking.modern import (
|
||||
CancelPostjoinDialog, ChatCommand, PlayShowDialog,
|
||||
SubmitPostjoinLoginDialog, SystemChat, TeleportPosition,
|
||||
)
|
||||
|
||||
|
||||
def component_text(value):
|
||||
"""Best-effort flattening of modern anonymous-NBT chat components."""
|
||||
if value is None:
|
||||
return ''
|
||||
if isinstance(value, (str, int, float)):
|
||||
return str(value)
|
||||
if isinstance(value, (list, tuple)):
|
||||
return ''.join(component_text(item) for item in value)
|
||||
raw = getattr(value, 'value', None)
|
||||
if isinstance(raw, (str, int, float)):
|
||||
return str(raw)
|
||||
if raw is not None and raw is not value and hasattr(raw, 'items'):
|
||||
value = raw
|
||||
tags = getattr(value, 'tags', None)
|
||||
if tags is not None:
|
||||
value = tags
|
||||
if hasattr(value, 'items'):
|
||||
fields = dict(value.items())
|
||||
if 'text' in fields:
|
||||
return component_text(fields['text']) + component_text(fields.get('extra', []))
|
||||
if 'translate' in fields:
|
||||
return component_text(fields['translate']) + component_text(fields.get('with', []))
|
||||
return ''.join(component_text(v) for v in fields.values())
|
||||
if isinstance(value, (list, tuple)):
|
||||
return ''.join(component_text(item) for item in value)
|
||||
return str(value)
|
||||
|
||||
|
||||
def main():
|
||||
server = os.environ.get('SERVER', 'games.protospace.ca')
|
||||
port = int(os.environ.get('PORT', '25565'))
|
||||
username = os.environ.get('PLAYER_NAME', 'mosfet1')
|
||||
password = os.environ.get('GAME_PASSWORD', 'mosfetbot')
|
||||
|
||||
connection = Connection(server, port, username=username,
|
||||
allowed_versions=['26.3'])
|
||||
connection.authme_password = password
|
||||
sent_auth_commands = set()
|
||||
|
||||
def send_auth_command(action):
|
||||
if action in sent_auth_commands:
|
||||
return
|
||||
sent_auth_commands.add(action)
|
||||
command = '/register {0} {0}'.format(password) if action == 'register' \
|
||||
else '/login ' + password
|
||||
print('[AuthMe] sending ' + command.split()[0], flush=True)
|
||||
connection.write_packet(ChatCommand(command=command.lstrip('/')),
|
||||
force=True)
|
||||
|
||||
@connection.listener(TeleportPosition)
|
||||
def on_spawn(packet):
|
||||
if getattr(connection, 'authme_mode', 'register') == 'register':
|
||||
send_auth_command('register')
|
||||
|
||||
@connection.listener(PlayShowDialog)
|
||||
def on_authme_dialog(packet):
|
||||
is_login = b'login' in packet.payload.lower()
|
||||
print('[AuthMe] dismissing the post-join dialog to use /commands.',
|
||||
flush=True)
|
||||
if is_login:
|
||||
connection.write_packet(SubmitPostjoinLoginDialog(
|
||||
password=password), force=True)
|
||||
else:
|
||||
connection.write_packet(CancelPostjoinDialog(), force=True)
|
||||
send_auth_command('register')
|
||||
|
||||
@connection.listener(SystemChat)
|
||||
def on_system_chat(packet):
|
||||
message = component_text(packet.content)
|
||||
print('[server] ' + message, flush=True)
|
||||
lowered = message.lower()
|
||||
if 'already registered' in lowered:
|
||||
send_auth_command('login')
|
||||
elif 'register' in lowered and any(word in lowered for word in
|
||||
('password', 'account', '/register')):
|
||||
send_auth_command('register')
|
||||
elif any(word in lowered for word in
|
||||
('please login', 'please log in', 'log in', '/login',
|
||||
'authenticate', 'authentication required')):
|
||||
send_auth_command('login')
|
||||
|
||||
connection.connect()
|
||||
print('Connected as {} to {}:{} using offline protocol 777.'.format(
|
||||
username, server, port), flush=True)
|
||||
try:
|
||||
while connection.connected:
|
||||
thread = connection.networking_thread
|
||||
if thread is None:
|
||||
break
|
||||
thread.join(timeout=0.5)
|
||||
if connection.exception:
|
||||
raise connection.exception
|
||||
print('Connection ended.', flush=True)
|
||||
except KeyboardInterrupt:
|
||||
print('Disconnecting...', flush=True)
|
||||
connection.disconnect()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+1
-1
@@ -29,7 +29,7 @@ pep517==0.10.0
|
||||
pkg-resources==0.0.0
|
||||
progress==1.5
|
||||
pycparser==2.20
|
||||
git+https://github.com/ammaraskar/pyCraft.git@2813d02ae7fb8182c3e5227a73de2240b09878d9
|
||||
-e ../pyCraft
|
||||
PyNBT==3.1.0
|
||||
pyparsing==2.4.7
|
||||
pytoml==0.1.21
|
||||
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user