Skip to content

Commit d020ccc

Browse files
committed
Add local schematic build_file API and docs coverage
1 parent 417c538 commit d020ccc

File tree

13 files changed

+514
-18
lines changed

13 files changed

+514
-18
lines changed

python/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ from pyritone import PyritoneClient
1515

1616
with PyritoneClient() as client:
1717
print(client.ping())
18-
dispatch = client.goto(100, 70, 100)
18+
dispatch = client.build_file("schematics/base.schem", 100, 70, 100)
1919
print(dispatch)
2020
```
2121

@@ -31,7 +31,7 @@ async def main() -> None:
3131
await client.connect()
3232
try:
3333
print(await client.ping())
34-
dispatch = await client.goto(100, 70, 100)
34+
dispatch = await client.build_file("schematics/base.schem", 100, 70, 100)
3535
print(dispatch)
3636
finally:
3737
await client.close()
@@ -69,6 +69,9 @@ asyncio.run(main())
6969
- `ping`, `status_get`, `execute`, `cancel`, `next_event`, `wait_for_task`
7070
- Command wrappers:
7171
- All top-level Baritone commands exposed as methods.
72+
- Local schematic helpers:
73+
- `build_file(path, *coords, base_dir=None)`
74+
- `build_file_wait(path, *coords, base_dir=None)`
7275
- Settings namespace:
7376
- Sync: `client.settings.allowPlace = True`
7477
- Async: `await client.settings.allowPlace.set(True)`
@@ -84,4 +87,3 @@ Override precedence:
8487
1. Explicit constructor args
8588
2. Environment variables: `PYRITONE_BRIDGE_INFO`, `PYRITONE_TOKEN`, `PYRITONE_HOST`, `PYRITONE_PORT`
8689
3. Auto-discovered bridge info file
87-

python/docs/async-client.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@ async def main() -> None:
2727
print(await client.ping())
2828
print(await client.status_get())
2929

30-
dispatch = await client.goto(100, 70, 100)
30+
dispatch = await client.build_file("schematics/base.schem", 100, 70, 100)
3131
print(dispatch)
3232

3333
task_id = dispatch.get("task_id")
3434
if task_id:
3535
terminal = await client.wait_for_task(task_id)
3636
print(terminal)
37+
38+
# Convenience helper that dispatches + waits in one call
39+
print(await client.build_file_wait("schematics/base.schem", 100, 70, 100))
3740
finally:
3841
await client.close()
3942

@@ -47,17 +50,22 @@ asyncio.run(main())
4750
Async low-level methods return awaitable dict[str, Any] payloads.
4851
Command wrappers return awaitable CommandDispatchResult.
4952
events()/next_event() return event envelope dictionaries.
53+
54+
Build helpers:
55+
- await build_file(...) -> CommandDispatchResult
56+
- await build_file_wait(...) -> terminal event envelope dict[str, Any]
5057
```
5158

5259
### Common mistakes
5360

5461
- Calling command methods before `await client.connect()`.
5562
- Not closing the client in `finally`.
63+
- Passing 1 or 2 coordinates to `build_file` (must be 0 or 3).
64+
- Assuming relative paths are from cwd; default is caller file directory.
5665
- Blocking event-loop threads with sync operations while waiting for events.
5766

5867
### Related methods
5968

6069
- `sync-client.md`
6170
- `tasks-events-and-waiting.md`
6271
- `settings-api.md`
63-

python/docs/commands/build.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,46 @@ CommandDispatchResult
2929
- [Errors and troubleshooting](../errors-and-troubleshooting.md)
3030
- [Alias methods](aliases.md)
3131

32+
## Pyritone Build Helpers
33+
34+
Extra helpers for local schematic files relative to your Python script.
35+
36+
### Sync example
37+
```python
38+
from pyritone import PyritoneClient
39+
40+
with PyritoneClient() as client:
41+
dispatch = client.build_file("schematics/base", 100, 70, 100)
42+
print(dispatch)
43+
terminal = client.build_file_wait("schematics/base", 100, 70, 100)
44+
print(terminal)
45+
```
46+
47+
### Async example
48+
```python
49+
import asyncio
50+
from pyritone import AsyncPyritoneClient
51+
52+
async def main() -> None:
53+
client = AsyncPyritoneClient()
54+
await client.connect()
55+
try:
56+
dispatch = await client.build_file("schematics/base", 100, 70, 100)
57+
print(dispatch)
58+
terminal = await client.build_file_wait("schematics/base", 100, 70, 100)
59+
print(terminal)
60+
finally:
61+
await client.close()
62+
63+
asyncio.run(main())
64+
```
65+
66+
### Notes
67+
- Relative paths are resolved from the calling Python file directory by default.
68+
- Pass `base_dir` to override path base.
69+
- No extension uses probing order: `.schem`, `.schematic`, `.litematic`.
70+
- If no file matches, extension-less path is sent so Baritone fallback extension still applies.
71+
3272
## `build`
3373

3474
Build a schematic
@@ -92,6 +132,8 @@ If `task_id` exists, wait for a terminal event:
92132
### Common mistakes
93133
- Passing separate string tokens when one argument contains spaces. Use one Python string.
94134
- Treating dispatch as completion. Dispatch is immediate; wait on `task_id` when needed.
135+
- For local Python-file-relative schematic paths, use `build_file(...)`.
136+
- Use `build_file_wait(...)` when you want dispatch + wait in one call.
95137

96138
### Source provenance
97139
- Baritone version: `v1.15.0`

python/docs/quickstart.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ from pyritone import PyritoneClient
1515
with PyritoneClient() as client:
1616
print(client.ping())
1717
print(client.status_get())
18-
dispatch = client.goto(100, 70, 100)
18+
dispatch = client.build_file("schematics/base.schem", 100, 70, 100)
1919
print(dispatch)
20+
21+
task_id = dispatch.get("task_id")
22+
if task_id:
23+
print(client.wait_for_task(task_id))
2024
```
2125

2226
### Async example
@@ -32,8 +36,12 @@ async def main() -> None:
3236
try:
3337
print(await client.ping())
3438
print(await client.status_get())
35-
dispatch = await client.goto(100, 70, 100)
39+
dispatch = await client.build_file("schematics/base.schem", 100, 70, 100)
3640
print(dispatch)
41+
42+
task_id = dispatch.get("task_id")
43+
if task_id:
44+
print(await client.wait_for_task(task_id))
3745
finally:
3846
await client.close()
3947

@@ -45,7 +53,7 @@ asyncio.run(main())
4553

4654
```text
4755
ping/status_get return dict[str, Any] payloads.
48-
goto and other command wrappers return CommandDispatchResult:
56+
build_file and other command wrappers return CommandDispatchResult:
4957
- command_text
5058
- raw
5159
- task_id (optional)
@@ -55,12 +63,12 @@ goto and other command wrappers return CommandDispatchResult:
5563
### Common mistakes
5664

5765
- Running Python before Minecraft has started with `pyritone_bridge`.
58-
- Calling command wrappers before joining a world (may return `NOT_IN_WORLD`).
66+
- Calling build commands before joining a world (may return `NOT_IN_WORLD`).
67+
- Using relative paths that are not relative to your script file (set `base_dir` to override).
5968
- Treating dispatch as completion; use `wait_for_task` when `task_id` exists.
6069

6170
### Related methods
6271

6372
- `connection-and-discovery.md`
6473
- `tasks-events-and-waiting.md`
6574
- `commands/navigation.md`
66-

python/docs/sync-client.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@ with PyritoneClient() as client:
1616
print(client.ping())
1717
print(client.status_get())
1818

19-
dispatch = client.goto(100, 70, 100)
19+
dispatch = client.build_file("schematics/base.schem", 100, 70, 100)
2020
print(dispatch)
2121

2222
task_id = dispatch.get("task_id")
2323
if task_id:
2424
terminal = client.wait_for_task(task_id)
2525
print(terminal)
26+
27+
# Convenience helper that dispatches + waits in one call
28+
print(client.build_file_wait("schematics/base.schem", 100, 70, 100))
2629
```
2730

2831
### Async example
@@ -40,17 +43,22 @@ Low-level methods:
4043
4144
Command methods:
4245
- CommandDispatchResult
46+
47+
build helpers:
48+
- build_file(...) -> CommandDispatchResult
49+
- build_file_wait(...) -> terminal event envelope dict[str, Any]
4350
```
4451

4552
### Common mistakes
4653

4754
- Creating a sync client and forgetting to close it outside a `with` block.
4855
- Assuming command wrappers block until completion by default.
56+
- Passing 1 or 2 coordinates to `build_file` (must be 0 or 3).
57+
- Assuming relative paths are from cwd; default is caller file directory.
4958
- Passing invalid argument shapes to command wrappers.
5059

5160
### Related methods
5261

5362
- `async-client.md`
5463
- `tasks-events-and-waiting.md`
5564
- `settings-api.md`
56-

python/src/pyritone/client_async.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import asyncio
44
import contextlib
5+
from pathlib import Path
56
from typing import Any
67

78
from .commands.async_build import AsyncBuildCommands
@@ -10,9 +11,11 @@
1011
from .commands.async_navigation import AsyncNavigationCommands
1112
from .commands.async_waypoints import AsyncWaypointsCommands
1213
from .commands.async_world import AsyncWorldCommands
14+
from .commands._types import CommandDispatchResult
1315
from .discovery import resolve_bridge_info
1416
from .models import BridgeError, BridgeInfo
1517
from .protocol import decode_line, encode_line, new_request
18+
from .schematic_paths import normalize_build_coords, normalize_schematic_path
1619
from .settings import AsyncSettingsNamespace
1720

1821

@@ -139,6 +142,42 @@ async def wait_for_task(self, task_id: str) -> dict[str, Any]:
139142
if isinstance(event_name, str) and event_name in self.TERMINAL_TASK_EVENTS:
140143
return event
141144

145+
async def build_file(
146+
self,
147+
path: str | Path,
148+
*coords: int,
149+
base_dir: str | Path | None = None,
150+
) -> CommandDispatchResult:
151+
"""Dispatch Baritone `build` using a local schematic path.
152+
153+
Relative paths resolve from the calling Python file directory by default.
154+
Use `base_dir` to override that base path.
155+
156+
Coordinate args must be either:
157+
- none (build at player position), or
158+
- exactly three ints `(x, y, z)`.
159+
"""
160+
normalized_path = normalize_schematic_path(path, base_dir=base_dir)
161+
normalized_coords = normalize_build_coords(coords)
162+
return await self.build(normalized_path, *normalized_coords)
163+
164+
async def build_file_wait(
165+
self,
166+
path: str | Path,
167+
*coords: int,
168+
base_dir: str | Path | None = None,
169+
) -> dict[str, Any]:
170+
"""Dispatch `build_file` and wait for terminal task event.
171+
172+
Raises `BridgeError(code=\"BAD_RESPONSE\", ...)` when dispatch response
173+
does not include a `task_id`.
174+
"""
175+
dispatch = await self.build_file(path, *coords, base_dir=base_dir)
176+
task_id = dispatch.get("task_id")
177+
if not task_id:
178+
raise BridgeError("BAD_RESPONSE", "No task_id returned for command: build", dispatch["raw"])
179+
return await self.wait_for_task(task_id)
180+
142181
async def _request(self, method: str, params: dict[str, Any]) -> dict[str, Any]:
143182
self._ensure_connected()
144183
assert self._writer is not None

python/src/pyritone/client_sync.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import asyncio
44
import threading
5+
from pathlib import Path
56
from typing import Any
67

78
from .client_async import AsyncPyritoneClient
@@ -11,6 +12,9 @@
1112
from .commands.sync_navigation import SyncNavigationCommands
1213
from .commands.sync_waypoints import SyncWaypointsCommands
1314
from .commands.sync_world import SyncWorldCommands
15+
from .commands._types import CommandDispatchResult
16+
from .models import BridgeError
17+
from .schematic_paths import normalize_build_coords, normalize_schematic_path
1418
from .settings import SyncSettingsNamespace
1519

1620

@@ -108,3 +112,39 @@ def next_event(self, timeout: float | None = None) -> dict[str, Any]:
108112

109113
def wait_for_task(self, task_id: str) -> dict[str, Any]:
110114
return self._runner.run(self._client.wait_for_task(task_id))
115+
116+
def build_file(
117+
self,
118+
path: str | Path,
119+
*coords: int,
120+
base_dir: str | Path | None = None,
121+
) -> CommandDispatchResult:
122+
"""Dispatch Baritone `build` using a local schematic path.
123+
124+
Relative paths resolve from the calling Python file directory by default.
125+
Use `base_dir` to override that base path.
126+
127+
Coordinate args must be either:
128+
- none (build at player position), or
129+
- exactly three ints `(x, y, z)`.
130+
"""
131+
normalized_path = normalize_schematic_path(path, base_dir=base_dir)
132+
normalized_coords = normalize_build_coords(coords)
133+
return self.build(normalized_path, *normalized_coords)
134+
135+
def build_file_wait(
136+
self,
137+
path: str | Path,
138+
*coords: int,
139+
base_dir: str | Path | None = None,
140+
) -> dict[str, Any]:
141+
"""Dispatch `build_file` and wait for terminal task event.
142+
143+
Raises `BridgeError(code=\"BAD_RESPONSE\", ...)` when dispatch response
144+
does not include a `task_id`.
145+
"""
146+
dispatch = self.build_file(path, *coords, base_dir=base_dir)
147+
task_id = dispatch.get("task_id")
148+
if not task_id:
149+
raise BridgeError("BAD_RESPONSE", "No task_id returned for command: build", dispatch["raw"])
150+
return self.wait_for_task(task_id)

0 commit comments

Comments
 (0)