chore: tony starkified clod
This commit is contained in:
Binary file not shown.
@@ -24,6 +24,9 @@ _last_build_time: float = 0.0
|
||||
_BUILD_SESSION_TIMEOUT = 3.0 # seconds of inactivity before session ends
|
||||
_build_session_origin: tuple[float, float, float] | None = None
|
||||
_watcher_task: asyncio.Task | None = None
|
||||
_build_bounds: dict | None = None # {"min_x", "max_x", "min_y", "max_y", "min_z", "max_z"}
|
||||
_build_flying: bool = False # whether current session uses flying mode
|
||||
_build_fly_xz: tuple[float, float] | None = None # fixed XZ while flying
|
||||
|
||||
|
||||
async def _request(method: str, path: str, **kwargs) -> Any:
|
||||
@@ -67,6 +70,10 @@ async def _look_at_pos(x: float, y: float, z: float) -> None:
|
||||
await _request("POST", "/look_at", json={"x": x, "y": y, "z": z})
|
||||
|
||||
|
||||
async def _set_bot_flying(flying: bool) -> None:
|
||||
await _request("POST", "/set_flying", json={"flying": flying})
|
||||
|
||||
|
||||
async def _get_bot_position() -> tuple[float, float, float] | None:
|
||||
data = await _request("GET", "/status")
|
||||
if isinstance(data, dict) and "position" in data:
|
||||
@@ -78,8 +85,42 @@ async def _get_bot_position() -> tuple[float, float, float] | None:
|
||||
def _compute_viewing_position(
|
||||
build_x: float, build_y: float, build_z: float,
|
||||
bot_x: float, bot_y: float, bot_z: float,
|
||||
bounds: dict | None = None,
|
||||
) -> tuple[float, float, float]:
|
||||
"""Compute a spot 5 blocks from the build, on the side the bot is on."""
|
||||
"""Compute a viewing spot outside the build volume.
|
||||
|
||||
When *bounds* is provided, position 3 blocks outside the nearest edge
|
||||
of the build footprint (on the side the bot is already on).
|
||||
Otherwise fall back to 5 blocks from the center point.
|
||||
"""
|
||||
if bounds is not None:
|
||||
min_x = bounds["min_x"]
|
||||
max_x = bounds["max_x"]
|
||||
min_z = bounds["min_z"]
|
||||
max_z = bounds["max_z"]
|
||||
center_x = (min_x + max_x) / 2.0
|
||||
center_z = (min_z + max_z) / 2.0
|
||||
dx = bot_x - center_x
|
||||
dz = bot_z - center_z
|
||||
if abs(dx) < 0.01 and abs(dz) < 0.01:
|
||||
dx = 1.0
|
||||
# Pick the axis the bot is farthest on
|
||||
if abs(dx) >= abs(dz):
|
||||
# Position outside X edge
|
||||
if dx >= 0:
|
||||
vx = max_x + 3.5
|
||||
else:
|
||||
vx = min_x - 3.5
|
||||
vz = center_z
|
||||
else:
|
||||
# Position outside Z edge
|
||||
vx = center_x
|
||||
if dz >= 0:
|
||||
vz = max_z + 3.5
|
||||
else:
|
||||
vz = min_z - 3.5
|
||||
return (vx, build_y, vz)
|
||||
|
||||
dx = bot_x - build_x
|
||||
dz = bot_z - build_z
|
||||
dist = math.hypot(dx, dz)
|
||||
@@ -90,35 +131,67 @@ def _compute_viewing_position(
|
||||
return (build_x + dx * scale, build_y, build_z + dz * scale)
|
||||
|
||||
|
||||
async def _ensure_build_session(x: float, y: float, z: float) -> None:
|
||||
async def _ensure_build_session(
|
||||
x: float, y: float, z: float,
|
||||
bounds: dict | None = None,
|
||||
flying: bool = False,
|
||||
) -> None:
|
||||
"""Start or continue a build session, managing state/teleport/look."""
|
||||
global _build_session_active, _last_build_time, _build_session_origin
|
||||
global _watcher_task
|
||||
global _watcher_task, _build_bounds, _build_flying, _build_fly_xz
|
||||
|
||||
async with _build_session_lock:
|
||||
_last_build_time = time.monotonic()
|
||||
|
||||
if _build_session_active:
|
||||
# Session already running — just look at the new target
|
||||
# Session already running
|
||||
_build_session_origin = (x, y, z)
|
||||
await _look_at_pos(x, y, z)
|
||||
if _build_flying and _build_fly_xz is not None:
|
||||
# Flying mode: keep XZ fixed, only update Y to rise with layers
|
||||
fx, fz = _build_fly_xz
|
||||
await _teleport_bot(fx, y, fz)
|
||||
# Look at the center of the build at the current layer height
|
||||
if _build_bounds:
|
||||
cx = (_build_bounds["min_x"] + _build_bounds["max_x"]) / 2.0
|
||||
cz = (_build_bounds["min_z"] + _build_bounds["max_z"]) / 2.0
|
||||
await _look_at_pos(cx, y, cz)
|
||||
else:
|
||||
await _look_at_pos(x, y, z)
|
||||
else:
|
||||
await _look_at_pos(x, y, z)
|
||||
return
|
||||
|
||||
# --- Start a new session ---
|
||||
_build_session_active = True
|
||||
_build_session_origin = (x, y, z)
|
||||
_build_bounds = bounds
|
||||
_build_flying = flying
|
||||
|
||||
await _set_bot_state("building")
|
||||
|
||||
pos = await _get_bot_position()
|
||||
if pos is not None:
|
||||
bx, by, bz = pos
|
||||
dist = math.sqrt((bx - x) ** 2 + (by - y) ** 2 + (bz - z) ** 2)
|
||||
if dist > 16:
|
||||
vx, vy, vz = _compute_viewing_position(x, y, z, bx, by, bz)
|
||||
await _teleport_bot(vx, vy, vz)
|
||||
|
||||
await _look_at_pos(x, y, z)
|
||||
if bounds is not None and flying:
|
||||
# Compute safe position outside build volume
|
||||
vx, vy, vz = _compute_viewing_position(x, y, z, bx, by, bz, bounds=bounds)
|
||||
_build_fly_xz = (vx, vz)
|
||||
await _set_bot_flying(True)
|
||||
await _teleport_bot(vx, y, vz)
|
||||
else:
|
||||
_build_fly_xz = None
|
||||
dist = math.sqrt((bx - x) ** 2 + (by - y) ** 2 + (bz - z) ** 2)
|
||||
if dist > 16:
|
||||
vx, vy, vz = _compute_viewing_position(x, y, z, bx, by, bz)
|
||||
await _teleport_bot(vx, vy, vz)
|
||||
|
||||
if bounds is not None:
|
||||
cx = (bounds["min_x"] + bounds["max_x"]) / 2.0
|
||||
cz = (bounds["min_z"] + bounds["max_z"]) / 2.0
|
||||
await _look_at_pos(cx, y, cz)
|
||||
else:
|
||||
await _look_at_pos(x, y, z)
|
||||
|
||||
# Start the watcher if not already running
|
||||
if _watcher_task is None or _watcher_task.done():
|
||||
@@ -128,6 +201,7 @@ async def _ensure_build_session(x: float, y: float, z: float) -> None:
|
||||
async def _build_session_watcher() -> None:
|
||||
"""Background task that ends the build session after inactivity."""
|
||||
global _build_session_active, _build_session_origin
|
||||
global _build_bounds, _build_flying, _build_fly_xz
|
||||
|
||||
while True:
|
||||
await asyncio.sleep(1.0)
|
||||
@@ -136,9 +210,14 @@ async def _build_session_watcher() -> None:
|
||||
return
|
||||
elapsed = time.monotonic() - _last_build_time
|
||||
if elapsed >= _BUILD_SESSION_TIMEOUT:
|
||||
if _build_flying:
|
||||
await _set_bot_flying(False)
|
||||
await _set_bot_state("idle")
|
||||
_build_session_active = False
|
||||
_build_session_origin = None
|
||||
_build_bounds = None
|
||||
_build_flying = False
|
||||
_build_fly_xz = None
|
||||
return
|
||||
|
||||
|
||||
@@ -366,12 +445,13 @@ async def build_schematic(name: str, x: int, y: int, z: int) -> str:
|
||||
layers = info.get("layers", [])
|
||||
fmt = info.get("format", "unknown")
|
||||
num_layers = len(layers)
|
||||
bounds = info.get("bounds") # may be None for empty schematics
|
||||
|
||||
if num_layers == 0:
|
||||
return _fmt({"ok": True, "message": "Schematic is empty, nothing to build.", "placed": 0})
|
||||
|
||||
# 2. Start build session and announce
|
||||
await _ensure_build_session(x, y, z)
|
||||
# 2. Start build session with flying + bounds and announce
|
||||
await _ensure_build_session(x, y, z, bounds=bounds, flying=True)
|
||||
await _request("POST", "/chat", json={
|
||||
"message": f"Starting build of {name}! {total_blocks} blocks, {num_layers} layers."
|
||||
})
|
||||
@@ -384,8 +464,8 @@ async def build_schematic(name: str, x: int, y: int, z: int) -> str:
|
||||
layer_y = layer["y"]
|
||||
block_count = layer["block_count"]
|
||||
|
||||
# Keep build session alive and look at current layer
|
||||
await _ensure_build_session(x, layer_y, z)
|
||||
# Keep build session alive; flying mode rises with each layer
|
||||
await _ensure_build_session(x, layer_y, z, bounds=bounds, flying=True)
|
||||
|
||||
# Check if this layer crosses a milestone threshold
|
||||
progress = (i + 1) / num_layers
|
||||
@@ -408,6 +488,7 @@ async def build_schematic(name: str, x: int, y: int, z: int) -> str:
|
||||
}, timeout=15.0)
|
||||
|
||||
if isinstance(result, dict) and "error" in result:
|
||||
await _set_bot_flying(False)
|
||||
await _request("POST", "/chat", json={
|
||||
"message": f"Build failed at layer {i + 1}/{num_layers}! Error: {result['error']}"
|
||||
})
|
||||
@@ -426,7 +507,8 @@ async def build_schematic(name: str, x: int, y: int, z: int) -> str:
|
||||
if i < num_layers - 1:
|
||||
await asyncio.sleep(0.4)
|
||||
|
||||
# 4. Announce completion
|
||||
# 4. Land and announce completion
|
||||
await _set_bot_flying(False)
|
||||
await _request("POST", "/chat", json={
|
||||
"message": f"Build complete! Placed {total_placed} blocks in {num_layers} layers."
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user