Add rcon.py for running server commands (op, gamemode, etc)
No interactive console exists since lazymc/systemd run the server in the background, and mcrcon isn't packaged for Debian 13. Plain Python3 RCON client instead, reads the password straight from server.properties. setup-server.sh now copies it into mcserver/.
This commit is contained in:
+14
@@ -37,6 +37,20 @@ Useful commands during the party:
|
|||||||
- `sudo journalctl -u mc-lazymc -f` — watch it wake/sleep live
|
- `sudo journalctl -u mc-lazymc -f` — watch it wake/sleep live
|
||||||
- `sudo systemctl restart mc-lazymc` — pick up new mods or a config change
|
- `sudo systemctl restart mc-lazymc` — pick up new mods or a config change
|
||||||
|
|
||||||
|
### Running server commands (op, gamemode, whitelist, etc.)
|
||||||
|
|
||||||
|
The server has RCON enabled (`rcon.password` auto-generated in `mcserver/server.properties`), but there's no interactive console since lazymc/systemd run the Java process in the background. Use `mcserver/rcon.py` (plain Python3, no install needed — `mcrcon` isn't packaged for Debian 13):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh server
|
||||||
|
cd ~/lan-minecraft/repo/server/mcserver
|
||||||
|
python3 rcon.py "op <name>"
|
||||||
|
python3 rcon.py "gamemode creative <name>"
|
||||||
|
python3 rcon.py "op <name>" "gamemode creative <name>" # multiple commands in one call
|
||||||
|
```
|
||||||
|
|
||||||
|
Works for any server command — `list`, `whitelist add <name>`, `tp`, `weather clear`, `/chunky`-era commands if relevant, etc. The script reads the password straight from `server.properties`, nothing to copy/paste. Note it only works while the real server is awake — if lazymc has it asleep, wake it first (connect once, or `python3 rcon.py "list"` will just fail to connect).
|
||||||
|
|
||||||
### Resource sizing for the venue box (5–15 players)
|
### Resource sizing for the venue box (5–15 players)
|
||||||
|
|
||||||
Create is the dominant cost here — it's heavier on the server **tick thread (CPU)** than on RAM, because kinetic networks and contraptions get simulated every tick regardless of how many players are nearby. Farmer's Delight/its addons are cheap by comparison. Numbers below assume this modpack (~10 mods) and are *total host box* numbers, not just the JVM heap:
|
Create is the dominant cost here — it's heavier on the server **tick thread (CPU)** than on RAM, because kinetic networks and contraptions get simulated every tick regardless of how many players are nearby. Farmer's Delight/its addons are cheap by comparison. Numbers below assume this modpack (~10 mods) and are *total host box* numbers, not just the JVM heap:
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Minimal Minecraft RCON client. Usage: rcon.py "<command>" ["<command2>" ...]"""
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
HOST = "127.0.0.1"
|
||||||
|
PORT = 25575
|
||||||
|
PASSWORD_FILE = "server.properties"
|
||||||
|
|
||||||
|
|
||||||
|
def read_password():
|
||||||
|
with open(PASSWORD_FILE) as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith("rcon.password="):
|
||||||
|
return line.strip().split("=", 1)[1]
|
||||||
|
raise SystemExit("rcon.password not found in server.properties")
|
||||||
|
|
||||||
|
|
||||||
|
def send_packet(sock, req_id, pkt_type, payload):
|
||||||
|
data = struct.pack("<ii", req_id, pkt_type) + payload.encode() + b"\x00\x00"
|
||||||
|
sock.sendall(struct.pack("<i", len(data)) + data)
|
||||||
|
|
||||||
|
|
||||||
|
def read_packet(sock):
|
||||||
|
length = struct.unpack("<i", sock.recv(4))[0]
|
||||||
|
data = b""
|
||||||
|
while len(data) < length:
|
||||||
|
data += sock.recv(length - len(data))
|
||||||
|
req_id, pkt_type = struct.unpack("<ii", data[:8])
|
||||||
|
payload = data[8:-2].decode(errors="replace")
|
||||||
|
return req_id, pkt_type, payload
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
password = read_password()
|
||||||
|
sock = socket.create_connection((HOST, PORT), timeout=10)
|
||||||
|
send_packet(sock, 1, 3, password) # SERVERDATA_AUTH
|
||||||
|
req_id, _, _ = read_packet(sock)
|
||||||
|
if req_id == -1:
|
||||||
|
raise SystemExit("RCON auth failed")
|
||||||
|
|
||||||
|
for i, cmd in enumerate(sys.argv[1:], start=2):
|
||||||
|
send_packet(sock, i, 2, cmd) # SERVERDATA_EXECCOMMAND
|
||||||
|
_, _, response = read_packet(sock)
|
||||||
|
print(f"> {cmd}\n{response}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -66,6 +66,9 @@ done
|
|||||||
mkdir -p "$SERVER_DIR/mods"
|
mkdir -p "$SERVER_DIR/mods"
|
||||||
echo "==> NOTE: copy the same mod jars from your client modpack's mods/ folder into $SERVER_DIR/mods/ (Create, Flywheel, Farmer's Delight + addons, JEI, etc.) before first boot."
|
echo "==> NOTE: copy the same mod jars from your client modpack's mods/ folder into $SERVER_DIR/mods/ (Create, Flywheel, Farmer's Delight + addons, JEI, etc.) before first boot."
|
||||||
|
|
||||||
|
cp "$BASE_DIR/rcon.py" "$SERVER_DIR/rcon.py"
|
||||||
|
echo "==> Copied rcon.py into $SERVER_DIR — use it to run server commands (op, gamemode, etc), see ../HOSTING.md."
|
||||||
|
|
||||||
# ---- 2. Install lazymc ----
|
# ---- 2. Install lazymc ----
|
||||||
# Pinned to v0.2.10, NOT "latest" — v0.2.11 has a confirmed, still-open upstream
|
# Pinned to v0.2.10, NOT "latest" — v0.2.11 has a confirmed, still-open upstream
|
||||||
# regression where it never detects a Forge server as ready (timvisee/lazymc#65,
|
# regression where it never detects a Forge server as ready (timvisee/lazymc#65,
|
||||||
|
|||||||
Reference in New Issue
Block a user