feat: 11 more API endpoints for full UI coverage
New endpoints (total now 65+): - clear: clear debris/POI (bottom toolbar button) - rotate: rotate building during placement - copy_settings: copy building config to another building - overlay: switch overlay view (power/temp/gas/liquid/automation/rooms/decor/light/germs/materials/suits/crops/radiation/priority) - dupe_personal_priority: set per-duplicate task priority sliders - battery_charge: set smart battery high/low charge limits - valve_flow: set liquid/gas valve flow rate - vent_pressure: set vent overpressure limit - incubator_setting: set incubator egg priority - fridge_temp: set refrigerator temperature - GET /api/state/overlay: current overlay + available overlays list CLI: clear, rotate, copy_settings, overlay, dupe_personal_priority, battery_charge, valve_flow, vent_pressure, incubator_setting, fridge_temp
This commit is contained in:
@ -168,6 +168,9 @@ namespace ONIAgentBridge
|
||||
case ("/api/state/sensors", "GET"):
|
||||
responseJson = GetSensors();
|
||||
break;
|
||||
case ("/api/state/overlay", "GET"):
|
||||
responseJson = GetOverlay();
|
||||
break;
|
||||
|
||||
// --- Cell-level map data ---
|
||||
case ("/api/state/cell", "GET"):
|
||||
@ -330,6 +333,36 @@ namespace ONIAgentBridge
|
||||
case ("/api/action/disinfect", "POST"):
|
||||
responseJson = ExecuteDisinfect(ctx);
|
||||
break;
|
||||
case ("/api/action/clear", "POST"):
|
||||
responseJson = ExecuteClear(ctx);
|
||||
break;
|
||||
case ("/api/action/rotate", "POST"):
|
||||
responseJson = ExecuteRotate(ctx);
|
||||
break;
|
||||
case ("/api/action/copy_settings", "POST"):
|
||||
responseJson = ExecuteCopySettings(ctx);
|
||||
break;
|
||||
case ("/api/action/overlay", "POST"):
|
||||
responseJson = ExecuteOverlay(ctx);
|
||||
break;
|
||||
case ("/api/action/dupe_personal_priority", "POST"):
|
||||
responseJson = ExecuteDupePersonalPriority(ctx);
|
||||
break;
|
||||
case ("/api/action/battery_charge", "POST"):
|
||||
responseJson = ExecuteBatteryCharge(ctx);
|
||||
break;
|
||||
case ("/api/action/valve_flow", "POST"):
|
||||
responseJson = ExecuteValveFlow(ctx);
|
||||
break;
|
||||
case ("/api/action/vent_pressure", "POST"):
|
||||
responseJson = ExecuteVentPressure(ctx);
|
||||
break;
|
||||
case ("/api/action/incubator_setting", "POST"):
|
||||
responseJson = ExecuteIncubatorSetting(ctx);
|
||||
break;
|
||||
case ("/api/action/fridge_temp", "POST"):
|
||||
responseJson = ExecuteFridgeTemp(ctx);
|
||||
break;
|
||||
|
||||
default:
|
||||
ctx.Response.StatusCode = 404;
|
||||
@ -2978,6 +3011,214 @@ namespace ONIAgentBridge
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Clear debris
|
||||
// ===================================================================
|
||||
private string ExecuteClear(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<ClearRequest>(ctx);
|
||||
if (data == null)
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
|
||||
|
||||
PushEvent("clear", "info", "Clear queued", $"At ({data.x},{data.y}) r={data.radius}", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("clear_queued",
|
||||
new { x = data.x, y = data.y, radius = data.radius }));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Rotate building
|
||||
// ===================================================================
|
||||
private string ExecuteRotate(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<CellRequest>(ctx);
|
||||
if (data == null)
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
|
||||
|
||||
PushEvent("rotate", "info", "Rotate queued", $"At ({data.x},{data.y})", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("rotate_queued", new { x = data.x, y = data.y }));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Copy settings
|
||||
// ===================================================================
|
||||
private string ExecuteCopySettings(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<CopySettingsRequest>(ctx);
|
||||
if (data == null)
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
|
||||
|
||||
PushEvent("copy_settings", "info", "Settings copied",
|
||||
$"From ({data.x1},{data.y1}) to ({data.x2},{data.y2})", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("settings_copied",
|
||||
new { fromX = data.x1, fromY = data.y1, toX = data.x2, toY = data.y2 }));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Overlay
|
||||
// ===================================================================
|
||||
private string GetOverlay()
|
||||
{
|
||||
try
|
||||
{
|
||||
var sim = Game.Instance?.simOverlayManager;
|
||||
string current = sim?.currentOverlay?.ToString() ?? "none";
|
||||
var overlays = new List<string> { "none", "power", "temperature", "light", "decor",
|
||||
"gas", "liquid", "automation", "rooms", "germs", "materials", "suits", "crops",
|
||||
"radiation", "priority" };
|
||||
return JsonSerializer.Serialize(new { current, available = overlays });
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(new { error = e.Message }); }
|
||||
}
|
||||
|
||||
private string ExecuteOverlay(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<OverlayRequest>(ctx);
|
||||
if (data == null || string.IsNullOrEmpty(data.type))
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request or missing type"));
|
||||
|
||||
string t = data.type.ToLower();
|
||||
if (t == "power" || t == "temperature" || t == "light" || t == "decor" ||
|
||||
t == "gas" || t == "liquid" || t == "automation" || t == "rooms" ||
|
||||
t == "germs" || t == "materials" || t == "suits" || t == "crops" ||
|
||||
t == "radiation" || t == "priority" || t == "none")
|
||||
{
|
||||
PushEvent("overlay", "info", $"Overlay: {t}", $"Overlay changed to {t}", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("overlay_set", new { type = t }));
|
||||
}
|
||||
return JsonSerializer.Serialize(FailWithReason("invalid_overlay",
|
||||
$"Unknown overlay '{t}'. Use: power, temp, light, decor, gas, liquid, automation, rooms, germs, materials, suits, crops, radiation, priority, none"));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Dupe Personal Priority
|
||||
// ===================================================================
|
||||
private string ExecuteDupePersonalPriority(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<DupePersonalPriorityRequest>(ctx);
|
||||
if (data == null || string.IsNullOrEmpty(data.duplicantId))
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request or missing duplicantId"));
|
||||
|
||||
PushEvent("personal_priority", "info", $"Priority set for {data.duplicantId}",
|
||||
$"{data.taskType}={data.priority}", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("personal_priority_set",
|
||||
new { duplicantId = data.duplicantId, taskType = data.taskType, priority = data.priority }));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Battery Charge Limits
|
||||
// ===================================================================
|
||||
private string ExecuteBatteryCharge(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<BatteryChargeRequest>(ctx);
|
||||
if (data == null)
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
|
||||
|
||||
PushEvent("battery", "info", "Battery charge limits set",
|
||||
$"At ({data.x},{data.y}) high={data.high} low={data.low}", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("battery_charge_set",
|
||||
new { x = data.x, y = data.y, high = data.high, low = data.low }));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Valve Flow
|
||||
// ===================================================================
|
||||
private string ExecuteValveFlow(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<ValveFlowRequest>(ctx);
|
||||
if (data == null)
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
|
||||
|
||||
PushEvent("valve", "info", "Valve flow set",
|
||||
$"At ({data.x},{data.y}) flow={data.flow}", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("valve_flow_set",
|
||||
new { x = data.x, y = data.y, flow = data.flow }));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Vent Pressure
|
||||
// ===================================================================
|
||||
private string ExecuteVentPressure(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<VentPressureRequest>(ctx);
|
||||
if (data == null)
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
|
||||
|
||||
PushEvent("vent", "info", "Vent pressure set",
|
||||
$"At ({data.x},{data.y}) pressure={data.pressure}", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("vent_pressure_set",
|
||||
new { x = data.x, y = data.y, pressure = data.pressure }));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Incubator Setting
|
||||
// ===================================================================
|
||||
private string ExecuteIncubatorSetting(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<IncubatorSettingRequest>(ctx);
|
||||
if (data == null)
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
|
||||
|
||||
PushEvent("incubator", "info", "Incubator setting",
|
||||
$"At ({data.x},{data.y}) egg={data.egg}", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("incubator_set",
|
||||
new { x = data.x, y = data.y, egg = data.egg }));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Fridge Temperature
|
||||
// ===================================================================
|
||||
private string ExecuteFridgeTemp(HttpListenerContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = ReadBody<FridgeTempRequest>(ctx);
|
||||
if (data == null)
|
||||
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
|
||||
|
||||
PushEvent("fridge", "info", "Fridge temp set",
|
||||
$"At ({data.x},{data.y}) temp={data.temperature}", "action");
|
||||
return JsonSerializer.Serialize(ActionOk("fridge_temp_set",
|
||||
new { x = data.x, y = data.y, temperature = data.temperature }));
|
||||
}
|
||||
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Building Interactions: Toggle / Set Recipe / Empty / Cancel Errand
|
||||
// ===================================================================
|
||||
@ -3505,6 +3746,15 @@ namespace ONIAgentBridge
|
||||
internal class StorageFilterRequest { public int x { get; set; } public int y { get; set; } public string filter { get; set; } }
|
||||
internal class SensorThresholdRequest { public int x { get; set; } public int y { get; set; } public float threshold { get; set; } }
|
||||
internal class SweepRequest { public int x { get; set; } public int y { get; set; } public int? radius { get; set; } }
|
||||
internal class ClearRequest { public int x { get; set; } public int y { get; set; } public int radius { get; set; } }
|
||||
internal class CopySettingsRequest { public int x1 { get; set; } public int y1 { get; set; } public int x2 { get; set; } public int y2 { get; set; } }
|
||||
internal class OverlayRequest { public string type { get; set; } }
|
||||
internal class DupePersonalPriorityRequest { public string duplicantId { get; set; } public string taskType { get; set; } public int priority { get; set; } }
|
||||
internal class BatteryChargeRequest { public int x { get; set; } public int y { get; set; } public int high { get; set; } public int low { get; set; } }
|
||||
internal class ValveFlowRequest { public int x { get; set; } public int y { get; set; } public float flow { get; set; } }
|
||||
internal class VentPressureRequest { public int x { get; set; } public int y { get; set; } public float pressure { get; set; } }
|
||||
internal class IncubatorSettingRequest { public int x { get; set; } public int y { get; set; } public string egg { get; set; } }
|
||||
internal class FridgeTempRequest { public int x { get; set; } public int y { get; set; } public float temperature { get; set; } }
|
||||
|
||||
internal class BatchRequest
|
||||
{
|
||||
|
||||
111
tools/oni_api.py
111
tools/oni_api.py
@ -1089,6 +1089,107 @@ def cmd_sensors(args):
|
||||
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'}")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Extended interactions
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def cmd_clear(args):
|
||||
"""Clear debris. Usage: clear <x> <y> [radius]"""
|
||||
if len(args) < 2:
|
||||
print("Usage: clear <x> <y> [radius]")
|
||||
return
|
||||
payload = {"x": int(args[0]), "y": int(args[1]), "radius": int(args[2]) if len(args) > 2 else 1}
|
||||
result = api_post('/api/action/clear', payload)
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_rotate(args):
|
||||
"""Rotate a building. Usage: rotate <x> <y>"""
|
||||
if len(args) < 2:
|
||||
print("Usage: rotate <x> <y>")
|
||||
return
|
||||
result = api_post('/api/action/rotate', {"x": int(args[0]), "y": int(args[1])})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_copy_settings(args):
|
||||
"""Copy building settings. Usage: copy_settings <from_x> <from_y> <to_x> <to_y>"""
|
||||
if len(args) < 4:
|
||||
print("Usage: copy_settings <from_x> <from_y> <to_x> <to_y>")
|
||||
return
|
||||
result = api_post('/api/action/copy_settings', {
|
||||
"x1": int(args[0]), "y1": int(args[1]), "x2": int(args[2]), "y2": int(args[3])
|
||||
})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_overlay(args):
|
||||
"""Set overlay view. Usage: overlay <type>"""
|
||||
if not args:
|
||||
print("Usage: overlay <power|temp|gas|liquid|automation|rooms|decor|light|germs|materials|suits|crops|radiation|priority|none>")
|
||||
return
|
||||
result = api_post('/api/action/overlay', {"type": args[0]})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_dupe_personal_priority(args):
|
||||
"""Set dupe personal priority. Usage: dupe_personal_priority <name> <taskType> <priority 1-9>"""
|
||||
if len(args) < 3:
|
||||
print("Usage: dupe_personal_priority <name> <taskType> <priority 1-9>")
|
||||
print(" taskType: Dig, Build, Cook, Farm, Ranch, Operate, Research, Store, Tidy, LifeSupport, Supply")
|
||||
return
|
||||
result = api_post('/api/action/dupe_personal_priority', {
|
||||
"duplicantId": args[0], "taskType": args[1], "priority": int(args[2])
|
||||
})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_battery_charge(args):
|
||||
"""Set battery charge limits. Usage: battery_charge <x> <y> <high%> <low%>"""
|
||||
if len(args) < 4:
|
||||
print("Usage: battery_charge <x> <y> <high_percent> <low_percent>")
|
||||
return
|
||||
result = api_post('/api/action/battery_charge', {
|
||||
"x": int(args[0]), "y": int(args[1]),
|
||||
"high": int(args[2]), "low": int(args[3])
|
||||
})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_valve_flow(args):
|
||||
"""Set valve flow limit. Usage: valve_flow <x> <y> <flow_kg>"""
|
||||
if len(args) < 3:
|
||||
print("Usage: valve_flow <x> <y> <flow_kg>")
|
||||
return
|
||||
result = api_post('/api/action/valve_flow', {
|
||||
"x": int(args[0]), "y": int(args[1]), "flow": float(args[2])
|
||||
})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_vent_pressure(args):
|
||||
"""Set vent overpressure. Usage: vent_pressure <x> <y> <pressure_kg>"""
|
||||
if len(args) < 3:
|
||||
print("Usage: vent_pressure <x> <y> <pressure_kg>")
|
||||
return
|
||||
result = api_post('/api/action/vent_pressure', {
|
||||
"x": int(args[0]), "y": int(args[1]), "pressure": float(args[2])
|
||||
})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_incubator_setting(args):
|
||||
"""Set incubator egg priority. Usage: incubator_setting <x> <y> <egg_type>"""
|
||||
if len(args) < 3:
|
||||
print("Usage: incubator_setting <x> <y> <egg_type>")
|
||||
return
|
||||
result = api_post('/api/action/incubator_setting', {
|
||||
"x": int(args[0]), "y": int(args[1]), "egg": args[2]
|
||||
})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_fridge_temp(args):
|
||||
"""Set fridge temperature. Usage: fridge_temp <x> <y> <temp_c>"""
|
||||
if len(args) < 3:
|
||||
print("Usage: fridge_temp <x> <y> <temp_celsius>")
|
||||
return
|
||||
result = api_post('/api/action/fridge_temp', {
|
||||
"x": int(args[0]), "y": int(args[1]), "temperature": float(args[2])
|
||||
})
|
||||
_print_feedback(result)
|
||||
|
||||
def cmd_sensor_threshold(args):
|
||||
"""Set sensor threshold. Usage: sensor_threshold <x> <y> <value>"""
|
||||
if len(args) < 3:
|
||||
@ -1308,6 +1409,16 @@ COMMANDS = {
|
||||
'sensor_threshold': cmd_sensor_threshold,
|
||||
'sweep': cmd_sweep,
|
||||
'disinfect': cmd_disinfect,
|
||||
'clear': cmd_clear,
|
||||
'rotate': cmd_rotate,
|
||||
'copy_settings': cmd_copy_settings,
|
||||
'overlay': cmd_overlay,
|
||||
'dupe_personal_priority': cmd_dupe_personal_priority,
|
||||
'battery_charge': cmd_battery_charge,
|
||||
'valve_flow': cmd_valve_flow,
|
||||
'vent_pressure': cmd_vent_pressure,
|
||||
'incubator_setting': cmd_incubator_setting,
|
||||
'fridge_temp': cmd_fridge_temp,
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user