# 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.