Files
minecraft-ai-god/README.md
T
Seth 8ee8be9cc0 Initial commit — Minecraft AI God plugin
- mc_aigod.py: main watcher script (log tail, RCON, two-call LLM)
- Two-call LLM split: qwen3-coder:30b for commands, gemma3:12b for messages
- Divine intervention timer (Poisson process, configurable avg/day)
- Prayer memory (persistent, last 10 exchanges)
- Rolling server log context (last 20 min events)
- Live player context (inventory with rarity, health, food, pos, XP)
- /pray and bible chat detection (no slash — vanilla 1.21 compatible)
- Login notice, bible help system
- debug_commands toggle (in-game command display via tellraw)
- Auto-fix for transposed give command syntax
- JSON repair fallback for truncated LLM responses
- Sentence-aware message chunking for long responses
- mc-aigod.service systemd unit
- mc_aigod_shrink.json example config
- README.md full implementation guide
- Minecraft_Ai_God.md full design document
2026-03-15 19:02:16 -04:00

315 lines
11 KiB
Markdown

# Minecraft AI God
A Python-based "plugin" for vanilla Minecraft servers that integrates a locally-hosted LLM as an in-game God character. Players interact by typing `pray <message>` in chat. God responds with dramatic prose and optionally executes server commands via RCON.
No mods, no plugins, no server restarts required. Works with any vanilla Minecraft 1.21+ server.
---
## How It Works
```
Player types: pray <message>
latest.log ←─ tailed by mc_aigod.py
RCON: immediate acknowledgment to player ("The heavens stir...")
RCON: fetch live server context
- Online players, time of day, weather, world border
RCON: fetch praying player's state
- Full inventory (with rarity annotations), position, health, food, XP, deaths
Call 1 — command_model (qwen3-coder:30b or similar)
- Decides what server commands to execute (JSON only, no prose)
- Low temperature (0.3) for precise structured output
Call 2 — model (gemma3:12b or similar)
- Writes God's spoken message knowing what was decided
- No token competition with commands — full creative freedom
RCON: execute commands + broadcast message
```
**Divine Intervention Timer** — a background thread fires at random intervals (Poisson process, user-defined average per day). If players are online, God acts unprompted. LLM can choose silence (`commands: []`) and nothing happens.
**Memory** — last 10 prayer exchanges stored as conversation history and passed to every LLM call. Persists across service restarts via JSON file. God remembers.
**Server log context** — last 20 minutes of meaningful server events (chat, deaths, joins, leaves) included with every prayer. God knows what's been happening.
---
## Requirements
- Python 3.11+
- `requests` library (`apt install python3-requests`)
- Ollama instance with at least one model pulled
- Minecraft vanilla server with RCON enabled
- Server running on Linux (systemd for service management)
### Minecraft server.properties requirements
```properties
enable-rcon=true
rcon.port=25575
rcon.password=yourpassword
broadcast-rcon-to-ops=false
```
---
## File Structure
```
mc_aigod.py # Main script — deploy to /usr/local/bin/
mc_aigod_shrink.json # Example config — deploy to /etc/mc_aigod.json
mc-aigod.service # Systemd unit — deploy to /etc/systemd/system/
Minecraft_Ai_God.md # Full design document with architecture details
```
---
## Configuration
`/etc/mc_aigod.json`:
| Key | Type | Default | Description |
|---|---|---|---|
| `server_name` | string | required | Server name passed to God's persona |
| `log_path` | string | required | Absolute path to `logs/latest.log` |
| `rcon_host` | string | `"127.0.0.1"` | RCON host |
| `rcon_port` | int | `25575` | RCON port |
| `rcon_password` | string | required | RCON password |
| `ollama_url` | string | required | Ollama base URL e.g. `http://192.168.0.1:11434` |
| `model` | string | required | Message model — creative writing (e.g. `gemma3:12b`) |
| `command_model` | string | falls back to `model` | Commands model — structured JSON (e.g. `qwen3-coder:30b`) |
| `temperature` | float | `0.85` | Message model temperature |
| `max_tokens` | int | `600` | Max tokens for message call |
| `cooldown_seconds` | int | `20` | Per-player prayer cooldown |
| `max_commands_per_response` | int | `6` | Max commands God can issue per prayer |
| `interventions_per_day` | float | `4` | Avg unprompted interventions per 24h. `0` to disable |
| `debug_commands` | bool | `false` | Show executed commands in-game via dark gray tellraw |
| `memory_path` | string | see below | Path to persist prayer memory JSON |
| `god_chat_prefix` | string | `"[GOD]"` | Chat prefix (supports Minecraft color codes) |
Default memory path: `<instance_data_dir>/aigod_memory.json`
### Example config
```json
{
"server_name": "my-server",
"log_path": "/path/to/minecraft/logs/latest.log",
"rcon_host": "127.0.0.1",
"rcon_port": 25575,
"rcon_password": "yourpassword",
"ollama_url": "http://localhost:11434",
"model": "gemma3:12b",
"command_model": "qwen3-coder:30b",
"temperature": 0.85,
"max_tokens": 600,
"cooldown_seconds": 20,
"max_commands_per_response": 6,
"interventions_per_day": 4,
"debug_commands": false,
"memory_path": "/path/to/minecraft/aigod_memory.json",
"god_chat_prefix": "[§6§lGOD§r]"
}
```
---
## Player Usage
Type in chat (no slash — vanilla 1.21 rejects unknown slash commands client-side):
```
pray <message> — send a prayer to God
bible — show help/guidance
```
On login players see:
```
[GOD] GOD ENABLED — Type "bible" in chat for guidance. Type "pray <message>" to pray.
```
---
## God's Capabilities
### Commands God can issue
**Give any item:**
```
give <player> minecraft:<item_id> <count>
give <player> minecraft:<item_id>[enchantments={sharpness:4,unbreaking:3}] 1
xp add <player> <amount> levels
```
**Effects (positive/negative):** regeneration, strength, speed, night_vision, fire_resistance, water_breathing, instant_health, blindness, slowness, weakness, hunger, nausea, levitation, effect clear
**Movement:** `tp <player> <x> <y> <z>`
**World:** `time set day/night`, `weather clear/thunder/rain <duration>`
**Punishment:** `execute at <player> run summon minecraft:lightning_bolt ~ ~ ~`, `kill <player>`
**Mobs:** `execute at <player> run summon minecraft:creeper ~ ~ ~3`
### Item naming rules (Minecraft 1.21)
- Always use `minecraft:` namespace prefix
- Beds: `white_bed`, `red_bed` etc — there is no `minecraft:bed`
- Logs: `oak_log`, `spruce_log` etc — there is no `minecraft:log`
- Wool: `white_wool`, `red_wool` etc — there is no `minecraft:wool`
- Enchantments use component syntax: `item[enchantments={sharpness:5,unbreaking:3}]`
- Give syntax: `give <player> minecraft:<item> <count>` — count is LAST
### God's persona
- Benevolent but just, theatrical and dramatic (Old Testament style)
- Aware of player inventory, health, food, position, deaths
- Aware of server state: time, weather, world border, online players
- Aware of recent server events: deaths, chat, joins, leaves (last 20 min)
- Remembers last 10 prayer exchanges across all players
- Acts on own accord via intervention timer — may choose silence
- Not obligated to grant requests — may reward someone else, punish the requester, or do something unexpected
---
## Model Recommendations
**Command model** — needs reliable structured JSON output and Minecraft syntax knowledge:
- `qwen3-coder:30b` (recommended, ~19GB Q4)
- `qwen2.5:1.5b` (fast/small, acceptable for commands)
**Message model** — needs creative writing, roleplay, dramatic biblical prose:
- `gemma3:12b` (recommended, ~8GB)
- `llama3.1:8b` (good alternative)
Avoid coding models for the message role. Avoid general models for the command role.
Both calls go to the same Ollama instance. If both models fit in VRAM simultaneously there is no swap overhead. If not, Ollama swaps them — adds a few seconds per prayer.
---
## Deployment
```bash
# Install dependencies
apt install python3-requests
# Deploy files
cp mc_aigod.py /usr/local/bin/mc_aigod.py
chmod +x /usr/local/bin/mc_aigod.py
cp mc_aigod_shrink.json /etc/mc_aigod.json # edit as needed
cp mc-aigod.service /etc/systemd/system/mc-aigod.service
# Enable and start
systemctl daemon-reload
systemctl enable --now mc-aigod.service
# Monitor
journalctl -fu mc-aigod.service
tail -f /var/log/mc_aigod.log
tail -f /var/log/mc_aigod_responses.log # full untruncated LLM responses
```
---
## Debugging
**`debug_commands: true` in config** — shows executed commands in-game as dark gray italic text:
```
[~] give slingshooter08 minecraft:spruce_log 64 | weather thunder 6000
```
Never appears in `latest.log`. Toggle off by setting `false` and restarting.
**Log files:**
- `/var/log/mc_aigod.log` — startup, prayers received, RCON results, errors
- `/var/log/mc_aigod_responses.log` — full untruncated LLM responses with commands and messages
**Common issues:**
| Symptom | Cause | Fix |
|---|---|---|
| `Unknown item 'minecraft:64'` | LLM put count before item | Auto-fixed by `fix_give_command()`, also update command model |
| `Unknown item 'minecraft:bed'` | Missing colour prefix | Item library includes warning; auto-namespaced |
| Message truncated | Token limit hit | Increase `max_tokens`; two-call split helps |
| `commands: []` but message says it will give something | LLM treating message as action | CRITICAL rule in prompt: commands array is the only way things happen |
| Prayer not detected | Typed as `/pray` (slash command) | Must type `pray` in chat without slash |
---
## Architecture Notes
### Why no Minecraft plugin?
No Java plugin required. The script tails `latest.log` for chat lines matching `pray ` and `bible`, then acts via RCON. This means:
- Works with any vanilla server version that has RCON
- No server restart required to install or update
- Script restarts independently of the server
### Log detection patterns
```python
# Chat messages in vanilla 1.21:
# [HH:MM:SS] [Server thread/INFO]: <playername> pray message here
# [HH:MM:SS] [Server thread/INFO]: <playername> bible
PRAY_PATTERN = re.compile(r'\[.*?\]: <(\w+)> [Pp]ray (.+)')
BIBLE_PATTERN = re.compile(r'\[.*?\]: <(\w+)> [Bb]ible\s*$')
JOIN_PATTERN = re.compile(r'\[.*?\]: (\w+) joined the game')
```
Note: `/pray` as a slash command does NOT work — vanilla 1.21 rejects unknown commands client-side before they reach the server log.
### Two-call LLM architecture
```
Prayer received
├─► Command call (command_model, temp=0.3, max_tokens=200, format=json)
│ System: terse spec, command palette, item rules
│ Returns: {"commands": [...]}
└─► Message call (model, temp=0.85, max_tokens=600, no format constraint)
System: God persona only
User: prayer + context + "You decided to execute: [commands]"
Returns: plain prose, any length
```
Separating the calls means:
- Commands are never truncated by a long message
- Message has full token budget for dramatic prose
- Each model does what it's best at
### Prayer memory format
Stored as a list of `[player, prayer, god_message]` tuples in JSON. Loaded at startup, appended after every successful prayer, capped at 10 entries. Injected into the message call as alternating `user`/`assistant` messages so the LLM sees genuine conversation history.
### Divine intervention timing
Uses exponential distribution (`random.expovariate`) — the correct model for Poisson arrivals. `interventions_per_day=4` means an average gap of 6 hours but intervals are random and memoryless. Could be 3 in one hour, then nothing for 18 hours.
---
## Sethpc Infrastructure Context
This was developed and deployed on:
- MCSManager on CT 644 (Proxmox, Debian 12, node-112)
- Minecraft shrink-world server: port 25566, RCON 25576
- Ollama on steel141 (192.168.0.141:11434)
- Models: `gemma3:12b` (messages), `qwen3-coder:30b` (commands)
- Service: `mc-aigod.service` on CT 644
- Config: `/etc/mc_aigod.json`
- Script: `/usr/local/bin/mc_aigod.py`