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.

StatusWhenBody
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
}

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:

IncludedNotes
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

  1. Wait until GET /roads/health reports your region READY (same gate as the map snapshot).
  2. Collect the odd-r small-hex tiles on the planned path (world x, z). Chunk requests at 16 384.
  3. POST one ResourceQuery per chunk to /roads/region/<id>/resources.
  4. Resolve resource_id to names/tags via your local resource.json / resource_desc catalog, or fetch GET /bitme/region/<region>/resource-dictionary (per-resource name + harvestable flag + gamedata).
Your planner │ planned tiles (world small-hex x, z) — max 16384 per POST ▼ POST /roads/region/14/resources → ResourceQuery { tiles: [{x,z}, …] } ← ResourcesResponse { nodes: [{x, z, resource_id, direction, origin}, …] } sparse: empty hexes omitted; one node max per hex (multi-hex shapes win shared tiles)