bacommontools package¶
Tools functionality shared by all Ballistica components.
Submodules¶
bacommontools.bacloud module¶
A tool for interacting with ballistica’s cloud services. This facilitates workflows such as creating asset-packages, etc.
- class bacommontools.bacloud.StateData(login_token: str | None = None)[source]¶
Bases:
objectPersistent state data stored to disk.
bacommontools.meshcompile module¶
Compilers for Ballistica’s binary mesh formats.
Covers display meshes (.bob) and collision meshes (.cob).
This module is intentionally stdlib-only and side-effect free so it can run anywhere it gets efrosynced to (game repo asset builds now, master-server cloud-build recipes later).
- class bacommontools.meshcompile.BobCompileResult(corner_count: int, vertex_count: int, tri_count: int, index_size: int)[source]¶
Bases:
objectStats from a display-mesh compile.
- class bacommontools.meshcompile.BobData(mesh_format: int, vertices: list[tuple[float, float, float, int, int, int, int, int]], indices: list[int])[source]¶
Bases:
objectParsed contents of a
.bobfile.
- class bacommontools.meshcompile.CobCompileResult(vertex_count_in: int, vertex_count_out: int, tri_count_in: int, tri_count_out: int)[source]¶
Bases:
objectStats from a collision-mesh compile.
- class bacommontools.meshcompile.CobData(file_id: int, positions: list[float], indices: list[int], normals: list[float] | None)[source]¶
Bases:
objectParsed contents of a
.cobfile.
- bacommontools.meshcompile.compile_collision_mesh(src: str | Path, dst: str | Path) CobCompileResult[source]¶
Compile a wavefront
.objfile to a binary.cobfile.Reads a constrained subset of the obj format:
vrecords andfrecords (v,v/t,v//n, andv/t/ncorner forms are all accepted; texture-coordinate and normal references are ignored). Faces with more than 3 corners are fan-triangulated.Output is deterministic for a given input, which matters for content-addressed asset storage.
Beyond straight conversion this applies a few optimizations:
Exact-duplicate vertex positions are welded (compared at float32 precision, matching what gets written).
Degenerate triangles (two or more corners sharing a vertex) are dropped.
Triangles are sorted along a Morton curve of their centroids and vertices are then ordered by first use, so triangles that are near each other in space are also near each other in memory. ODE/OPCODE reads these arrays in place during collision queries; spatially-local queries thus touch fewer cache lines. (Tree shape is unaffected; OPCODE splits on geometry, not input order.)
Unreferenced vertices are pruned (they would otherwise inflate both memory use and ODE’s model-space AABB).
- bacommontools.meshcompile.compile_mesh(src: str | Path, dst: str | Path) BobCompileResult[source]¶
Compile a wavefront
.objfile to a binary.bobfile.Reads the obj subset our exporters produce:
v/vt/vnrecords plusfrecords with fullv/t/ncorners. Faces with more than 3 corners are fan-triangulated. The obj V texture coordinate is flipped (1 - v) per GL convention. UVs and normal components meaningfully outside their encodable ranges ([0, 1] / [-1, 1]) are errors; values within a 0.05 tolerance are treated as authoring noise and clamped silently by the quantization.Output is deterministic for a given input, which matters for content-addressed asset storage.
Optimizations applied:
Corners are quantized to the final vertex encoding and welded (exact-match on all attributes), so identical corners share one vertex.
Degenerate triangles (two or more corners welding to the same vertex) are dropped.
Triangle order is optimized for the GPU post-transform vertex cache (Forsyth’s linear-speed algorithm), then vertices are renumbered by first use for fetch locality. This also prunes unreferenced vertices.
Index width is chosen per mesh: u16 when vertices fit, u32 otherwise (the engine supports both; this removes the old make_bob 21845-face limit).
bacommontools.pcommands module¶
Pcommands for bacommontools.
- bacommontools.pcommands.bacurl() None[source]¶
Run curl with the Ballistica API key injected.
Usage: bacurl [curl-args…] <url>
Reads
ballistica_api_keyfrompconfig/localconfig.jsonand passes it as a Bearer token in the Authorization header. All arguments are forwarded to curl. The-s(silent) flag is added automatically.Examples:
bacurl https://dev.ballistica.net/api/v1/admin/stats/catalog bacurl -X POST -H 'Content-Type: application/json' \ -d '{"dry_run":true}' \ https://dev.ballistica.net/api/v1/admin/stats/flush
- bacommontools.pcommands.compile_collision_mesh() None[source]¶
Compile a collision mesh from .obj to our binary .cob format.
Usage: compile_collision_mesh <src.obj> <dst.cob>
bacommontools.streamws module¶
WebSocket-based stream consumer for bacloud (Phase 2).
A stream-mode bacloud kickoff lands at a basn node, which injects a
StreamWS into the response pointing at its own
/streamcall/<call_id> WebSocket endpoint. We open that WS, print
StreamOutput frames live as they arrive, and return the terminal
StreamFinal so the caller can splice it back into bacloud’s
existing response-handling flow.
On a non-terminal close (network blip, abnormal close, expired
token) we reconnect — refreshing the token via POST
/streamcall/<call_id>/refresh-token first if the close code says
the token is expired (4001). Reconnects use exponential backoff up
to a configurable wall-clock budget (default 60s, override via
BACLOUD_RECONNECT_BUDGET_SECONDS); past the budget we surface
CleanError. Token-bad / call-id-mismatch / no-token closes
(4002/4003/4004) are fatal — no retry.
v0 reconnect doesn’t ask basn to replay the cursor: a reconnecting
client may miss frames that landed during the disconnect window. In
practice the stream still completes (the basn-side subscription
keeps polling regardless of WS attachments), and bacloud renders the
terminal StreamFinal correctly. Cursor-aware resume is
Phase 3 territory.
Test-only env vars:
BACLOUD_TEST_FORCE_DROP_AFTER_SECONDS=N— force the WS closed N seconds after open; the reconnect path then runs as it would on a real drop.BACLOUD_TEST_BREAK_RECONNECT=1— point the reconnect URL at a guaranteed-unreachable host (127.0.0.1:1); reconnects fail until the budget expires.
- bacommontools.streamws.consume_via_ws(response: ResponseData, *, bearer: str | None, host: str) ResponseData[source]¶
Drain a stream over WebSocket and return a terminal-only response.
The returned
ResponseDatacarries the terminalStreamFinalinstream_framesso bacloud’s existingstream_framesloop falls through to the usual terminal handling (message/error/end_command).hostis the bacloud client’s resolved kickoff hostname (the basn the kickoff went to); used to construct the WS URL when the producer didn’t pin one.Caller must check
response.stream_ws is not Nonefirst. RaisesCleanErroron unrecoverable WS failure (token-bad, reconnect-budget exhausted, etc.).