Repository navigation
Script Mod Guide
github-actions[bot] edited this page Jan 9, 2026
·
2 revisions
Build external tools that communicate with the game via WebSocket.
Script Mods are external programs that:
- Connect to the game via WebSocket
- Query game state (items, machines, recipes)
- Optionally modify data at runtime
Use cases:
- Map viewers
- Statistics dashboards
- Item databases
- Automation scripts
WebSocket server runs on ws://127.0.0.1:9877.
JavaScript (Node.js or browser):
const WebSocket = require('ws'); // Node.js only
const ws = new WebSocket('ws://127.0.0.1:9877');
ws.on('open', () => {
console.log('Connected to game');
// Request game version
ws.send(JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'game.version',
params: {}
}));
});
ws.on('message', (data) => {
const response = JSON.parse(data);
console.log('Response:', response.result);
});Python:
import asyncio
import websockets
import json
async def main():
uri = "ws://127.0.0.1:9877"
async with websockets.connect(uri) as ws:
# Request game version
await ws.send(json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "game.version",
"params": {}
}))
response = json.loads(await ws.recv())
print(f"Game version: {response['result']['version']}")
asyncio.run(main())class GameClient {
constructor(url = 'ws://127.0.0.1:9877') {
this.ws = new WebSocket(url);
this.pending = new Map();
this.nextId = 1;
this.ws.onmessage = (event) => {
const response = JSON.parse(event.data);
const resolve = this.pending.get(response.id);
if (resolve) {
this.pending.delete(response.id);
resolve(response);
}
};
}
async ready() {
return new Promise(resolve => {
if (this.ws.readyState === 1) resolve();
else this.ws.onopen = resolve;
});
}
async call(method, params = {}) {
await this.ready();
const id = this.nextId++;
return new Promise((resolve, reject) => {
this.pending.set(id, (response) => {
if (response.error) reject(response.error);
else resolve(response.result);
});
this.ws.send(JSON.stringify({
jsonrpc: '2.0',
id,
method,
params
}));
});
}
}
// Usage
const client = new GameClient();
const version = await client.call('game.version');
const items = await client.call('item.list');const client = new GameClient();
async function buildItemDatabase() {
const { items } = await client.call('item.list');
const database = {
byId: {},
byCategory: {},
byTag: {}
};
for (const item of items) {
// Index by ID
database.byId[item.id] = item;
// Index by category
if (!database.byCategory[item.category]) {
database.byCategory[item.category] = [];
}
database.byCategory[item.category].push(item);
// Index by tags (if available)
for (const tag of item.tags || []) {
if (!database.byTag[tag]) {
database.byTag[tag] = [];
}
database.byTag[tag].push(item);
}
}
return database;
}
// Usage
const db = await buildItemDatabase();
console.log('Ores:', db.byCategory['ore']);
console.log('Smeltable:', db.byTag['smeltable']);async function analyzeRecipes() {
const { recipes } = await client.call('recipe.list');
const { items } = await client.call('item.list');
const itemMap = Object.fromEntries(items.map(i => [i.id, i]));
for (const recipe of recipes) {
const inputCost = recipe.inputs.reduce((sum, i) => sum + i.count, 0);
const outputYield = recipe.outputs.reduce((sum, o) => sum + o.count, 0);
const efficiency = outputYield / inputCost;
console.log(`${recipe.id}: ${efficiency.toFixed(2)}x efficiency`);
}
}async function monitorGame() {
setInterval(async () => {
const state = await client.call('game.state');
console.log(`Tick: ${state.tick}, Paused: ${state.paused}`);
}, 1000);
}ws.on('close', () => {
console.log('Disconnected, reconnecting...');
setTimeout(() => connect(), 5000);
});
ws.on('error', (err) => {
console.error('WebSocket error:', err);
});// Bad: Many sequential requests
for (const id of itemIds) {
await client.call('item.info', { id });
}
// Good: Single list request
const { items } = await client.call('item.list');
const filtered = items.filter(i => itemIds.includes(i.id));let cachedItems = null;
let cacheTime = 0;
async function getItems() {
if (!cachedItems || Date.now() - cacheTime > 60000) {
cachedItems = await client.call('item.list');
cacheTime = Date.now();
}
return cachedItems;
}See WebSocket API for full reference.
| Method | Description |
|---|---|
game.version |
Get game/API version |
game.state |
Get current game state |
item.list |
List all items |
item.add |
Register new item |
machine.list |
List all machines |
machine.add |
Register new machine |
recipe.list |
List all recipes |
recipe.add |
Register new recipe |
mod.list |
List loaded mods |
mod.info |
Get mod details |
mod.enable/disable |
Toggle mod state |
texture.list |
List textures |
# Using websocat (install: cargo install websocat)
echo '{"jsonrpc":"2.0","id":1,"method":"game.version","params":{}}' | websocat ws://127.0.0.1:9877logs/game.log
WebSocket errors are logged with [WebSocket] prefix.
- WebSocket API - Complete method reference
- Getting Started - Quick tutorial
- Home / ホーム
- Getting Started / はじめに
- Mod Structure / Mod構造
Mod Types
Reference
- Blocks & Items / ブロックとアイテム
- Machines / 機械
- Recipes / レシピ
- Conveyor System / コンベア
- Quest System / クエスト
- Biomes / バイオーム
- Save Format / セーブ形式