Files
2026-11-05 17:44:52 +00:00

4.4 KiB
Raw Permalink Blame History

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