Files
oniagent/tools/oni_builder.py

186 lines
6.8 KiB
Python

#!/usr/bin/env python3
"""
ONI Agent — Blueprint Builder
==============================
Pre-built building modules for one-click deployment.
Usage:
python oni_builder.py list List all blueprints
python oni_builder.py show <name> Show blueprint details
python oni_builder.py build <name> <x> <y> Build blueprint at anchor point
"""
import json, sys
from oni_api import api_post, api_get
BLUEPRINTS = {
'spom': {
'name': 'SPOM (Self-Powered Oxygen Module)',
'desc': 'Standard Rodriguez SPOM: electrolyzer + H2 generators + gas pumps',
'size': {'w': 8, 'h': 6},
'dig': {'dx': -1, 'dy': -1, 'w': 10, 'h': 8},
'steps': [
{'type': 'build', 'id': 'Electrolyzer', 'x': 3, 'y': 2},
{'type': 'build', 'id': 'GasPump', 'x': 1, 'y': 2},
{'type': 'build', 'id': 'GasPump', 'x': 5, 'y': 2},
{'type': 'build', 'id': 'HydrogenGenerator', 'x': 1, 'y': 0},
{'type': 'build', 'id': 'HydrogenGenerator', 'x': 4, 'y': 0},
],
},
'spom_mini': {
'name': 'Mini SPOM',
'desc': 'Compact electrolyzer + 1 hydrogen generator for early game',
'size': {'w': 5, 'h': 4},
'dig': {'dx': -1, 'dy': -1, 'w': 7, 'h': 6},
'steps': [
{'type': 'build', 'id': 'Electrolyzer', 'x': 2, 'y': 1},
{'type': 'build', 'id': 'GasPump', 'x': 1, 'y': 1},
{'type': 'build', 'id': 'HydrogenGenerator', 'x': 2, 'y': 0},
],
},
'toilet_loop': {
'name': 'Bathroom Water Loop',
'desc': '2 Lavatories -> Water Purifier closed loop',
'size': {'w': 8, 'h': 4},
'dig': {'dx': -1, 'dy': -1, 'w': 10, 'h': 6},
'steps': [
{'type': 'build', 'id': 'Lavatory', 'x': 1, 'y': 1},
{'type': 'build', 'id': 'Lavatory', 'x': 3, 'y': 1},
{'type': 'build', 'id': 'WaterPurifier', 'x': 6, 'y': 1},
],
},
'farm_mealwood': {
'name': 'Mealwood Farm',
'desc': '5 PlanterBox + 1 StorageLocker',
'size': {'w': 6, 'h': 4},
'dig': {'dx': -1, 'dy': -1, 'w': 8, 'h': 6},
'steps': [
{'type': 'build', 'id': 'PlanterBox', 'x': 1, 'y': 1},
{'type': 'build', 'id': 'PlanterBox', 'x': 3, 'y': 1},
{'type': 'build', 'id': 'PlanterBox', 'x': 5, 'y': 1},
{'type': 'build', 'id': 'PlanterBox', 'x': 1, 'y': 3},
{'type': 'build', 'id': 'PlanterBox', 'x': 3, 'y': 3},
{'type': 'build', 'id': 'StorageLocker', 'x': 5, 'y': 3},
],
},
'bedroom': {
'name': 'Standard Bedroom',
'desc': '4 Cots + decor for bedroom room bonus',
'size': {'w': 8, 'h': 4},
'dig': {'dx': -1, 'dy': -1, 'w': 10, 'h': 6},
'steps': [
{'type': 'build', 'id': 'Cot', 'x': 1, 'y': 1},
{'type': 'build', 'id': 'Cot', 'x': 3, 'y': 1},
{'type': 'build', 'id': 'Cot', 'x': 5, 'y': 1},
{'type': 'build', 'id': 'Cot', 'x': 7, 'y': 1},
],
},
'cooling': {
'name': 'Steam Turbine Cooler',
'desc': 'Aquatuner + Steam Turbine cooling loop',
'size': {'w': 8, 'h': 6},
'dig': {'dx': -1, 'dy': -1, 'w': 10, 'h': 8},
'steps': [
{'type': 'build', 'id': 'SteamTurbine', 'x': 1, 'y': 4},
{'type': 'build', 'id': 'SteamTurbine', 'x': 5, 'y': 4},
{'type': 'build', 'id': 'Aquatuner', 'x': 2, 'y': 1},
],
},
'ranch_hatch': {
'name': 'Hatch Ranch',
'desc': 'RanchStation + Incubator + StorageLocker',
'size': {'w': 10, 'h': 6},
'dig': {'dx': -1, 'dy': -1, 'w': 12, 'h': 8},
'steps': [
{'type': 'build', 'id': 'RanchStation', 'x': 1, 'y': 1},
{'type': 'build', 'id': 'Incubator', 'x': 4, 'y': 1},
{'type': 'build', 'id': 'StorageLocker', 'x': 8, 'y': 1},
],
},
}
def cmd_list(args):
print(f"Available blueprints ({len(BLUEPRINTS)}):")
for name, bp in sorted(BLUEPRINTS.items()):
print(f" {name:15s} {bp['name']}")
print(f" {'':15s} {bp['desc']}")
print(f" {'':15s} Size: {bp['size']['w']}x{bp['size']['h']} | {len(bp['steps'])} buildings")
print()
def cmd_show(args):
if not args:
print("Usage: show <blueprint_name>", file=sys.stderr)
return
name = args[0]
if name not in BLUEPRINTS:
print(f"Unknown blueprint: {name}", file=sys.stderr)
return
bp = BLUEPRINTS[name]
print(f"Blueprint: {bp['name']}")
print(f" {bp['desc']}")
print(f" Size: {bp['size']['w']}x{bp['size']['h']}")
if bp.get('dig'):
d = bp['dig']
print(f" Dig area: offset ({d['dx']},{d['dy']}) {d['w']}x{d['h']}")
print(f" Buildings ({len(bp['steps'])}):")
for s in bp['steps']:
print(f" {s['id']:25s} at anchor+({s['x']},{s['y']})")
def cmd_build(args):
if len(args) < 3:
print("Usage: build <blueprint_name> <anchor_x> <anchor_y>", file=sys.stderr)
return
name, ax, ay = args[0], int(args[1]), int(args[2])
if name not in BLUEPRINTS:
print(f"Unknown blueprint: {name}", file=sys.stderr)
return
bp = BLUEPRINTS[name]
# 1. Dig the area first
if bp.get('dig'):
d = bp['dig']
dx, dy = ax + d['dx'], ay + d['dy']
print(f"Digging area: ({dx},{dy}) {d['w']}x{d['h']}...")
r = api_post('/api/action/dig', {"x": dx, "y": dy, "width": d['w'], "height": d['h']})
if r.get("success"):
info = r.get("data", {})
print(f" Queued {info.get('count', '?')} dig orders")
else:
print(f" Dig warning: {r.get('errorMessage', r.get('error', 'unknown'))}")
# 2. Build each structure
results = []
for step in bp['steps']:
bx, by = ax + step['x'], ay + step['y']
print(f"Building {step['id']} at ({bx},{by})...")
r = api_post('/api/action/build', {"buildingId": step['id'], "x": bx, "y": by})
if r.get("success"):
info = r.get("data", {})
has_mat = info.get('hasAllMaterials', False)
results.append(f"{step['id']} at ({bx},{by}) {'(may wait for materials)' if not has_mat else ''}")
else:
results.append(f"{step['id']} at ({bx},{by}): {r.get('errorMessage', r.get('error', 'unknown'))}")
print(f"\n--- {bp['name']} build results ---")
for r in results:
print(r)
def main():
if len(sys.argv) < 2 or sys.argv[1] in ("-h", "--help", "help"):
print(__doc__)
return
cmd = sys.argv[1]
args = sys.argv[2:]
if cmd == "list":
cmd_list(args)
elif cmd == "show":
cmd_show(args)
elif cmd == "build":
cmd_build(args)
else:
print(f"Unknown: {cmd}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()