feat: comprehensive API coverage — dupe move/cancel, critter wrangle, plant uproot, storage filter, door open, sensors, sweep, disinfect

New state endpoints:
- GET /api/state/sensors: list all automation sensors with thresholds

New action endpoints (10 total):
- dupe_move: move duplicant to coordinates
- dupe_cancel_task: cancel a dupe's current chore
- critter_wrangle: catch and relocate a critter
- plant_uproot: dig up a plant
- storage_filter: set what a storage bin accepts
- door_open: manually open/close a door
- sensor_threshold: set automation sensor value
- sweep: mark resources for sweeping pickup
- disinfect: disinfect a cell/building

CLI: dupe_move, dupe_cancel_task, critter_wrangle, plant_uproot,
storage_filter, door_open, sensors, sensor_threshold, sweep, disinfect

Total API endpoints: 50+ covering all ONI player interactions
This commit is contained in:
root
2026-05-22 09:50:23 +08:00
parent bbde9acadd
commit aa0519c1ed
2 changed files with 418 additions and 0 deletions

View File

@ -1015,6 +1015,109 @@ def cmd_door_one_way(args):
})
_print_feedback(result)
# ---------------------------------------------------------------------------
# Dupe / Critter / Plant / Sensor / Storage / Sweep / Disinfect
# ---------------------------------------------------------------------------
def cmd_dupe_move(args):
"""Move a duplicant. Usage: dupe_move <name> <x> <y>"""
if len(args) < 3:
print("Usage: dupe_move <dupe_name> <x> <y>")
return
result = api_post('/api/action/dupe_move', {
"duplicantId": args[0], "x": int(args[1]), "y": int(args[2])
})
_print_feedback(result)
def cmd_dupe_cancel_task(args):
"""Cancel a dupe's current task. Usage: dupe_cancel_task <name>"""
if not args:
print("Usage: dupe_cancel_task <dupe_name>")
return
result = api_post('/api/action/dupe_cancel_task', {"duplicantId": args[0]})
_print_feedback(result)
def cmd_critter_wrangle(args):
"""Wrangle a critter. Usage: critter_wrangle <x> <y>"""
if len(args) < 2:
print("Usage: critter_wrangle <x> <y>")
return
result = api_post('/api/action/critter_wrangle', {"x": int(args[0]), "y": int(args[1])})
_print_feedback(result)
def cmd_plant_uproot(args):
"""Uproot a plant. Usage: plant_uproot <x> <y>"""
if len(args) < 2:
print("Usage: plant_uproot <x> <y>")
return
result = api_post('/api/action/plant_uproot', {"x": int(args[0]), "y": int(args[1])})
_print_feedback(result)
def cmd_storage_filter(args):
"""Set storage filter. Usage: storage_filter <x> <y> <filter_tag>"""
if len(args) < 3:
print("Usage: storage_filter <x> <y> <filter_tag>")
return
result = api_post('/api/action/storage_filter', {
"x": int(args[0]), "y": int(args[1]), "filter": args[2]
})
_print_feedback(result)
def cmd_door_open(args):
"""Open/close a door. Usage: door_open <x> <y> <on|off>"""
if len(args) < 3:
print("Usage: door_open <x> <y> <on|off>")
return
open_door = args[2].lower() in ('on', 'true', '1', 'open', 'yes')
result = api_post('/api/action/door_open', {
"x": int(args[0]), "y": int(args[1]), "open": open_door
})
_print_feedback(result)
def cmd_sensors(args):
"""List all sensors. Usage: sensors [filter]"""
filt = args[0].lower() if args else ""
data = api_get('/api/state/sensors')
if 'error' in data:
print(f"Error: {data['error']}")
return
print(f"Sensors: {data.get('sensorCount', 0)}")
for s in data.get('sensors', []):
sname = f"{s.get('type', '?')}Sensor"
if filt and filt not in sname.lower() and filt not in str(s.get('threshold', '')):
continue
thr = f" threshold={s.get('threshold')}" if s.get('threshold') is not None else ""
print(f" {sname:15s} at ({s.get('x', '?')},{s.get('y', '?')}){thr} {'ON' if s.get('isOperational') else 'OFF'}")
def cmd_sensor_threshold(args):
"""Set sensor threshold. Usage: sensor_threshold <x> <y> <value>"""
if len(args) < 3:
print("Usage: sensor_threshold <x> <y> <value>")
return
result = api_post('/api/action/sensor_threshold', {
"x": int(args[0]), "y": int(args[1]), "threshold": float(args[2])
})
_print_feedback(result)
def cmd_sweep(args):
"""Mark for sweeping. Usage: sweep <x> <y> [radius]"""
if len(args) < 2:
print("Usage: sweep <x> <y> [radius]")
return
payload = {"x": int(args[0]), "y": int(args[1])}
if len(args) > 2:
payload["radius"] = int(args[2])
result = api_post('/api/action/sweep', payload)
_print_feedback(result)
def cmd_disinfect(args):
"""Disinfect a cell. Usage: disinfect <x> <y>"""
if len(args) < 2:
print("Usage: disinfect <x> <y>")
return
result = api_post('/api/action/disinfect', {"x": int(args[0]), "y": int(args[1])})
_print_feedback(result)
# ---------------------------------------------------------------------------
# Screenshot / Camera
# ---------------------------------------------------------------------------
@ -1195,6 +1298,16 @@ COMMANDS = {
'critter_attack': cmd_critter_attack,
'door_lock': cmd_door_lock,
'door_one_way': cmd_door_one_way,
'dupe_move': cmd_dupe_move,
'dupe_cancel_task': cmd_dupe_cancel_task,
'critter_wrangle': cmd_critter_wrangle,
'plant_uproot': cmd_plant_uproot,
'storage_filter': cmd_storage_filter,
'door_open': cmd_door_open,
'sensors': cmd_sensors,
'sensor_threshold': cmd_sensor_threshold,
'sweep': cmd_sweep,
'disinfect': cmd_disinfect,
}
if __name__ == '__main__':
@ -1226,9 +1339,25 @@ if __name__ == '__main__':
print("=== Door / Critter / Suits ===")
print(" door_lock <x> <y> on|off Lock/unlock a door")
print(" door_one_way <x> <y> <dir> Set door to one-way (left/right/up/down/none)")
print(" door_open <x> <y> on|off Open/close a door manually")
print(" critter_attack <x> <y> Toggle critter attack mode")
print(" critter_wrangle <x> <y> Wrangle a critter")
print(" atmo_suits Check atmo suit dock status")
print("")
print("=== Duplicant / Plant ===")
print(" dupe_move <name> <x> <y> Move a duplicant to coordinates")
print(" dupe_cancel_task <name> Cancel a dupe's current task")
print(" plant_uproot <x> <y> Uproot a plant")
print("")
print("=== Sensors / Automation ===")
print(" sensors [filter] List all sensors and thresholds")
print(" sensor_threshold <x> <y> <v> Set sensor threshold")
print("")
print("=== Storage / Cleaning ===")
print(" storage_filter <x> <y> <tag> Set storage building filter")
print(" sweep <x> <y> [r] Mark area for sweeping")
print(" disinfect <x> <y> Disinfect a cell/building")
print(" empty <x> <y> Empty building storage")
print(" events [since] [limit] Poll new game events")
print(" printing_pod Check Printing Pod status (ready/options)")
print(" printing_pod_select <0|1|2> Select Printing Pod option")