-
Notifications
You must be signed in to change notification settings - Fork 0
Getting Started
git clone https://github.com/killerboyyy777/Machine-Learning-mmo.git
cd Machine-Learning-mmo
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python3 server.pyStarts the world on ws://0.0.0.0:8765. Edit world.json to define your
own rooms, NPCs, and items before starting the server (loaded once at
startup). On Windows you can also just run start.bat — it starts the
engine, shows where to find the game and the dashboard, and turns on live
console logging.
Dungeons are instanced: a private, 50-floor staircase is created
per party the first time someone uses the enter doorway on the
graveyard — see Game-Systems Parties & the dungeon.
Any client is a WebSocket connection speaking JSON (see
Protocol for the full reference). Manual clients exist for learning
and debugging the protocol — inhabitants are scripted. Telnet and netcat
cannot speak WebSocket, so talk to the server with Python (websockets
ships with the requirements file) or straight from a browser console:
import asyncio, json, websockets
async def main():
async with websockets.connect("ws://localhost:8765") as ws:
await ws.send(json.dumps({"cmd": "login", "name": "YourName"}))
print(await ws.recv()) # stake message + welcome
await ws.send(json.dumps({"cmd": "look"}))
print(await ws.recv()) # room snapshot
# from here, send any command and print each reply:
# await ws.send(json.dumps({"cmd": "attack rat"}))
asyncio.run(main())// same, in a browser console (no install needed):
const ws = new WebSocket("ws://localhost:8765");
ws.onmessage = e => console.log(JSON.parse(e.data));
ws.onopen = () => ws.send(JSON.stringify({cmd: "login", name: "YourName"}));
// then: ws.send(JSON.stringify({cmd: "look"}))Type commands like look, north, attack rat, take sword,
equip sword — scripted directly, or interactively in your own client
while learning.
See First-Session for a guided first ten minutes.
The server also runs a browser dashboard on port 8766 (stdlib only, no
extra dependencies). Start the engine, then open
http://localhost:8766/. See Dashboard for the panels.
Any client is just a WebSocket connection speaking JSON. Three steps:
1. Connect and log in.
import asyncio, json, websockets
async def main():
async with websockets.connect("ws://localhost:8765") as ws:
await ws.send(json.dumps({"cmd": "login", "name": "MyBot"}))
event = json.loads(await ws.recv()) # first message is always a room snapshot
print(event)2. Send commands, receive responses.
Every command is a JSON object with a "cmd" field. The server always
replies with a JSON object that has a "type" field. The most important
type is "room" — the full state of your current room (exits, NPCs,
items, other players), pushed after every move, look, login, and whenever
the room changes.
await ws.send(json.dumps({"cmd": "look"}))
event = json.loads(await ws.recv())
await ws.send(json.dumps({"cmd": "move", "dir": "north"}))
event = json.loads(await ws.recv())
await ws.send(json.dumps({"cmd": "attack", "target": "rat"}))
event = json.loads(await ws.recv())
await ws.send(json.dumps({"cmd": "take", "item": "sword"}))
event = json.loads(await ws.recv())3. Handle the main loop.
Read responses in a loop, update state from "room" and "stats"
events, and decide what to do next. On "error", send a "look" to
resync — never assume cached state is still valid after an error. On
"death" the character respawned: look to re-orient.
async def main():
async with websockets.connect("ws://localhost:8765") as ws:
await ws.send(json.dumps({"cmd": "login", "name": "MyBot"}))
while True:
event = json.loads(await ws.recv())
t = event.get("type")
if t == "room":
print(f"In: {event['name']}")
elif t == "stats":
print(f"HP {event['hp']}/{event['max_hp']} Gold {event['gold']}")
elif t == "combat":
print(event["text"]) # pattern-match "dies" for kills
elif t == "error":
await ws.send(json.dumps({"cmd": "look"})) # resync
elif t == "death":
await ws.send(json.dumps({"cmd": "look"}))An LLM agent speaks the same WebSocket protocol as any other client. Give the LLM a system prompt describing the game and let it issue JSON commands directly:
You are a character in a text-based MMO. You communicate by sending JSON
commands over a WebSocket connection. The server responds with JSON messages.
Available commands (skeleton — full command list with quest, market,
party, and commission commands: see [[Protocol]]):
{"cmd": "login", "name": "YourName"}
{"cmd": "look"}
{"cmd": "move", "dir": "north"}
{"cmd": "attack", "target": "goblin"}
After each server response, decide your next action and send one JSON command.
Key messages: "room" (full state), "combat" (check "dies" for kills),
"stats" (HP/gold/score), "error" (look again to resync), "death" (respawned).
Quick-start Python bridge:
async def run_llm_agent(name="LLMAgent"):
async with websockets.connect("ws://localhost:8765") as ws:
await ws.send(json.dumps({"cmd": "login", "name": name}))
resp = json.loads(await ws.recv())
while True:
prompt = build_prompt(resp) # feed to your LLM
action = call_llm(prompt) # parse LLM output into a dict
await ws.send(json.dumps(action))
resp = json.loads(await ws.recv())The LLM sees the same snapshots, combat text, and errors as everyone
else. Treat error responses as a cue to look again and resync state.