Hex resource lookup
POST /roads/region/<id>/resources returns resource
nodes on a list of small-hex tiles in one region — every
resource type (trees, ore, clay, sand, mushrooms, berry bushes,
fiber plants, flowers, event resources, hexite nodes, …), served
from the region's dense resource tile map. It is a
point lookup, not a region dump: send the hexes
your planner already has (typically 1–16 384), get back
sparse ResourceNodes. Schema:
roads_cache.proto.
HTTP semantics
Protobuf on both sides. Send
Content-Type: application/x-protobuf and
Accept: application/x-protobuf. There is no JSON variant.
| Status | When | Body |
|---|---|---|
200 OK |
Region ready; query accepted | ResourcesResponse protobuf. Empty tiles simply
contribute no nodes. |
202 Accepted |
Region exists but roads grid still seeding | Empty. Poll /roads/health until
state=READY (3), then retry. |
400 Bad Request |
Body is not a ResourceQuery, or
tiles.length > 16384 |
Plain text
(invalid ResourceQuery protobuf or
too many tiles (N > 16384)).
The cap is on the request list before de-duplication. |
404 Not Found |
Unknown region id | Plain text: unknown region N |
503 Service Unavailable |
Roads cache disabled on host | Plain text: roads cache not enabled |
Protobuf messages
From roads_cache.proto (package roads_cache):
message Hex {
int32 x = 1;
int32 z = 2;
}
message ResourceQuery {
repeated Hex tiles = 1; // max 16384
}
message ResourceNode {
int32 x = 1;
int32 z = 2;
int32 resource_id = 3; // resource_desc.id
// resource_state.direction_index of the owning resource (0..=5).
uint32 direction = 4;
// True when this tile is the resource's anchor (origin) tile.
bool origin = 5;
}
message ResourcesResponse {
repeated ResourceNode nodes = 1; // sparse; omitted hexes had no match
}
-
x/zare world small-hex coordinates — the same space aslocation_state.x/zand the overlay grid in Region map format (not region-locallx/lz). -
Duplicate hexes in
tilesare ignored after the length check (first occurrence wins). -
direction(0–5) andoriginlet clients reconstruct whole resource instances from per-tile rows: origin tiles anchor an instance of the direction-rotatedresource_desc.footprint. - At most one node per hex: the tile map keeps a single resource per tile. Multi-hex shapes win shared tiles; a single-hex newcomer (e.g. a forageable spawned under a tree) is not stamped on an already-occupied tile.
- Hexes outside this region, or with no resource, produce no row — not a sentinel.
What is indexed
The response comes from a dense per-region resource tile map (one u16
word per odd-r tile across the whole 7680×7680 grid), stamped
server-side from resource_desc.footprint ×
direction for every
resource_state row joined to an overworld
(dimension = 1) location. There is no allowlist anymore:
| Included | Notes |
|---|---|
| All resource types — trees, saplings, stumps, ore veins, rocks, clay, sand, plus mushrooms, berry bushes, fiber plants, flowers, event resources, and hexite nodes |
The old forestry/mining/clay/sand 215-id harvestable allowlist is
gone. Filtering by tag is now the client's job: fetch
GET /bitme/region/<region>/resource-dictionary
for per-resource harvestable flags + names, or join
resource_id against your own
resource.json / resource_desc catalog.
|
| Every occupied tile of a multi-hex footprint |
Large trees, clay/sand patches, giant bushes, … are
returned on all their tiles (rotated by direction),
not just the anchor.
|
resource_id matches resource_desc.id (and
resource.json id). This API does not return
names. Hexite claims with parsed coordinates remain available in the
friendlier GET /deposits view.
Example (Python)
Generate stubs from
/proto/roads_cache.proto
(protoc --python_out=.), then:
import requests
from roads_cache_pb2 import ResourceQuery, ResourcesResponse
REGION = 14
# World small-hex, same space as location_state / overlay.
# Region 14 origin is (23040, 15360); these two tiles sit on that origin.
query = ResourceQuery()
query.tiles.add(x=23040, z=15360)
query.tiles.add(x=23041, z=15360)
r = requests.post(
f"https://relay.bitcraftsync.app/roads/region/{REGION}/resources",
data=query.SerializeToString(),
headers={
"Content-Type": "application/x-protobuf",
"Accept": "application/x-protobuf",
},
timeout=30,
)
r.raise_for_status()
if r.status_code == 202:
raise RuntimeError("region still seeding; retry after /roads/health READY")
resp = ResourcesResponse()
resp.ParseFromString(r.content)
for n in resp.nodes:
print(n.x, n.z, n.resource_id, n.direction, n.origin)
With a pre-encoded body file:
# query.pb is a serialized roads_cache.ResourceQuery
curl -sS -H 'Content-Type: application/x-protobuf' \
-H 'Accept: application/x-protobuf' \
--data-binary @query.pb \
https://relay.bitcraftsync.app/roads/region/14/resources \
-o resources.pb -w '%{http_code}\n'
# 200 → decode resources.pb as ResourcesResponse
# 202 → empty body, region not ready
# 400 → too many tiles or invalid protobuf
Client workflow
-
Wait until
GET /roads/healthreports your regionREADY(same gate as the map snapshot). -
Collect the odd-r small-hex tiles on the planned path
(world
x,z). Chunk requests at 16 384. -
POSToneResourceQueryper chunk to/roads/region/<id>/resources. -
Resolve
resource_idto names/tags via your localresource.json/resource_desccatalog, or fetchGET /bitme/region/<region>/resource-dictionary(per-resource name +harvestableflag + gamedata).