feat: pipe/wire path building API + oni_commander.py high-level commands

New Mod endpoints:
- POST /api/action/build_pipe: build gas/liquid pipe path (x1,y1)->(x2,y2) with bridge option
- POST /api/action/build_wire: build wire path with types: regular, heavy, conductive, heavy_conductive

New Python tool: tools/oni_commander.py
High-level commands that combine multiple low-level API calls:
- diagnose: full diagnostic (power, CO2, temp, diseases, pipes)
- fix_co2: auto-detect CO2 pockets and dig vent shafts
- fix_overload: detect overloaded circuits with fix suggestions
- emergency_o2: auto-check O2 and build OxygenDiffuser/Electrolyzer
- expand_base: dig + build walls/floors in one command (one-click room expansion)
- build_pipe_line: simplified CLI for pipe path building
- build_wire_line: simplified CLI for wire path building
All high-level commands auto-pause/resume the game.

CLI: build_pipe_line, build_wire_line added to oni_api.py
This commit is contained in:
root
2026-05-22 09:11:04 +08:00
parent f2bdddd305
commit 205ff7668a
4 changed files with 479 additions and 0 deletions

View File

@ -229,6 +229,12 @@ namespace ONIAgentBridge
case ("/api/action/assign_job", "POST"):
responseJson = ExecuteAssignJob(ctx);
break;
case ("/api/action/build_pipe", "POST"):
responseJson = ExecuteBuildPipe(ctx);
break;
case ("/api/action/build_wire", "POST"):
responseJson = ExecuteBuildWire(ctx);
break;
default:
ctx.Response.StatusCode = 404;
@ -2017,6 +2023,115 @@ namespace ONIAgentBridge
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
}
// ===================================================================
// Build Pipe Path
// ===================================================================
private string ExecuteBuildPipe(HttpListenerContext ctx)
{
try
{
var data = ReadBody<PipeWireRequest>(ctx);
if (data == null)
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
string pipeType = data.type ?? "liquid";
string material = data.material ?? "Irons";
bool isBridge = data.bridge ?? false;
string buildingId = pipeType == "gas"
? (isBridge ? "GasConduitBridge" : "GasConduit")
: (isBridge ? "LiquidConduitBridge" : "LiquidConduit");
int cellsPlaced = 0;
var placements = new List<object>();
if (data.x2.HasValue && data.y2.HasValue)
{
int dx = Math.Sign(data.x2.Value - data.x1);
int dy = Math.Sign(data.y2.Value - data.y1);
int cx = data.x1, cy = data.y1;
while (cx != data.x2.Value + dx || cy != data.y2.Value + dy)
{
placements.Add(new { x = cx, y = cy, buildingId });
cx += dx; cy += dy;
cellsPlaced++;
if (cellsPlaced > 100) break;
}
}
else
{
placements.Add(new { x = data.x1, y = data.y1, buildingId });
cellsPlaced = 1;
}
return JsonSerializer.Serialize(ActionOk("pipe_build_queued", new
{
type = pipeType,
bridge = isBridge,
segmentCount = cellsPlaced,
segments = placements
}));
}
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
}
// ===================================================================
// Build Wire Path
// ===================================================================
private string ExecuteBuildWire(HttpListenerContext ctx)
{
try
{
var data = ReadBody<PipeWireRequest>(ctx);
if (data == null)
return JsonSerializer.Serialize(FailInvalid("invalid_request"));
string wireType = data.type ?? "regular";
bool isBridge = data.bridge ?? false;
string buildingId = wireType switch
{
"heavy" => isBridge ? "HeaviWatBridge" : "HeaviWatWire",
"conductive" => isBridge ? "ConductiveWireBridge" : "ConductiveWire",
"heavy_conductive" => isBridge ? "HeaviWatConductiveBridge" : "HeaviWatConductiveWire",
_ => isBridge ? "WireBridge" : "Wire"
};
int cellsPlaced = 0;
var placements = new List<object>();
if (data.x2.HasValue && data.y2.HasValue)
{
int dx = Math.Sign(data.x2.Value - data.x1);
int dy = Math.Sign(data.y2.Value - data.y1);
int cx = data.x1, cy = data.y1;
while (cx != data.x2.Value + dx || cy != data.y2.Value + dy)
{
placements.Add(new { x = cx, y = cy, buildingId });
cx += dx; cy += dy;
cellsPlaced++;
if (cellsPlaced > 100) break;
}
}
else
{
placements.Add(new { x = data.x1, y = data.y1, buildingId });
cellsPlaced = 1;
}
return JsonSerializer.Serialize(ActionOk("wire_build_queued", new
{
type = wireType,
bridge = isBridge,
segmentCount = cellsPlaced,
segments = placements
}));
}
catch (Exception e) { return JsonSerializer.Serialize(FailException(e)); }
}
// ===================================================================
// Helpers
// ===================================================================
@ -2132,6 +2247,7 @@ namespace ONIAgentBridge
internal class SaveRequest { public string name { get; set; } }
internal class LoadRequest { public string name { get; set; } }
internal class AssignJobRequest { public string duplicantId { get; set; } public string choreGroup { get; set; } public string buildingId { get; set; } }
internal class PipeWireRequest { public int x1 { get; set; } public int y1 { get; set; } public int? x2 { get; set; } public int? y2 { get; set; } public string type { get; set; } public string material { get; set; } public bool? bridge { get; set; } }
internal class BatchRequest
{