70 lines
4.4 KiB
Markdown
70 lines
4.4 KiB
Markdown
# Bot Development Notes
|
||
|
||
- Target **Minecraft 26.3 / protocol 777 only**. Do not add old-version compatibility.
|
||
- Put protocol-777 changes in the main modules; do not create `*_26_3.py` copies.
|
||
- Entry point: `python mosfet.py` from this repository root; use `.venv` dependencies.
|
||
- Use the editable sibling `../pyCraft` checkout for shared protocol packet support.
|
||
- Keep packet IDs and layouts aligned with `PROTOCOL_777.html` and the local 26.3 server; do not infer them from older protocol versions.
|
||
- You can test bots on the Minecraft server running locally: `SERVER=127.0.0.1`.
|
||
- The local server runs out of `~/tmp/minecraft`. Read `server.properties` for the RCON password.
|
||
- Use offline test accounts `mosfet1` and, when an observer is needed, `mosfet2`; read passwords from environment variables, never hard-code them.
|
||
- If `python mosfet.py` is already running, feel free to kill the script.
|
||
- Stop test bots and confirm no bot process remains afterward.
|
||
- Don’t change existing job sequencing/behavior unless the request asks for it; port packet and data handling in place.
|
||
- Check README and command gates before assuming a legacy command is available on 26.3.
|
||
- Run tests with `.venv/bin/python -m unittest discover -s tests -v`.
|
||
- Run a syntax check with `.venv/bin/python -m compileall -q mosfet tests` and `git diff --check`.
|
||
- Add regression tests for packet encodings, world-state behavior, and migrated job state transitions.
|
||
- Do not git commit changes until explicitly asked each time.
|
||
- If changes span both repositories, commit bot and pyCraft changes separately.
|
||
|
||
## Theory
|
||
|
||
- **Runtime flow:** `mosfet.py` owns global state, the dashboard, and hot reload; it calls `mosfet/connect.py` to connect and initialize the 26.3 runtime.
|
||
- **Connection setup:** `connect.py` handles offline login/AuthMe and wires the current world, entity, inventory, chat, command, game, and job adapters.
|
||
- **Packet-to-state flow:** `../pyCraft/minecraft/networking/modern.py` defines protocol-777 wire packets; `mosfet/protocol/modern.py` and `packets.py` add bot-specific packet classes; `mosfet/protocol/managers.py` updates cached world, entities, and inventory.
|
||
- **Tick flow:** `mosfet/bot.py` advances movement/physics, then ticks the active job and game actions. `mosfet/path.py` supplies A* navigation over `mosfet/world.py` and the loaded block-state cache.
|
||
- **Commands and jobs:** `mosfet/commands.py` parses chat commands; `mosfet/job.py` selects existing job sequences; each `mosfet/jobs/*.py` module implements a state machine. Keep job sequencing intact unless requested.
|
||
- **Game actions:** `mosfet/game.py` sends current-protocol actions such as block breaking, inventory selection, item use, and punches/arm swings.
|
||
- **Data:** `mosfet/info/data/26.3/` contains checked-in Minecraft data; `mosfet/info/{blocks,items,mobs,mcdata}.py` exposes it to runtime code. `PROTOCOL_777.html` is the local packet reference.
|
||
- **Validation:** `tests/` contains offline regression tests; use the test and compile commands above before committing.
|
||
|
||
## Live Checks
|
||
|
||
- For one-off live checks, start `mosfet.py` inside a Python heredoc so the test can inspect `app.g` and shut the bot down cleanly. Run from the repo root, keep `SERVER=127.0.0.1`.
|
||
|
||
```sh
|
||
SERVER=127.0.0.1 PLAYER_NAME=mosfet1 .venv/bin/python - <<'PY'
|
||
import importlib.util, os, threading, time
|
||
|
||
spec = importlib.util.spec_from_file_location(
|
||
"mosfet_runtime", os.path.abspath("mosfet.py"))
|
||
app = importlib.util.module_from_spec(spec)
|
||
spec.loader.exec_module(app)
|
||
g = app.g
|
||
runner = threading.Thread(target=app.main, name="mosfet-test", daemon=True)
|
||
runner.start()
|
||
try:
|
||
deadline = time.monotonic() + 20
|
||
while time.monotonic() < deadline:
|
||
if g.get("connected") and g.get("pos") and g.chunks.check_loaded(2):
|
||
break
|
||
time.sleep(0.1)
|
||
else:
|
||
raise TimeoutError("bot did not finish joining/loading nearby chunks")
|
||
print(time.monotonic(), "mosfet1 position:", tuple(g.pos))
|
||
g.commands.handle_chat(("CHAT", "test", "tester: 1ping"))
|
||
finally:
|
||
if g.get("job") and g.get("connection") and g.connection.connected:
|
||
g.job.stop()
|
||
g.running = False
|
||
runner.join(timeout=5)
|
||
if runner.is_alive():
|
||
raise RuntimeError("bot test thread did not stop")
|
||
PY
|
||
```
|
||
|
||
- Give enough time for the bot and world to load.
|
||
- Always include the `finally` cleanup.
|
||
- When printing during live checks, include `time.monotonic()` to better understand the timing of events.
|