5. How relay-cache joins tables

relay-cache is a same-host process that subscribes to every regional frontend on loopback, keeps selected tables in memory, and serves enriched JSON/protobuf on https://relay.bitcraftsync.app/…. You do not need it to use the WebSocket relays — it is an optional read API that already performed the joins community tools usually want.

Ingest model

Per region, the cache opens one v2 WebSocket to ws://127.0.0.1:<port> and loads data in phases:

  1. Base query set One additive Subscribe with all primary tables (claims, buildings, inventories, players, crafts, storage logs, hexite resource filters, growth, …). Wait for SubscribeApplied.
  2. Hexite locations (additive) From the base dump, collect hexite resource_state entity ids, then subscribe SELECT * FROM location_state WHERE entity_id = … per id in a second query set. Wait for Applied again.
  3. Stream Mark the region ready and apply live TransactionUpdates into columnar stores.

Full location_state is enormous (~millions of rows per region); the cache only keeps non-overworld interiors (dimension != 1) plus the hexite PK follow-up.

Endpoint → tables

Each HTTP handler reads the in-memory stores and joins by entity id (and a few derived keys). Entity ids are JSON strings for JS safety; protobuf uses uint64.

Endpoint Primary tables Join / enrichment
GET /claim?name= claim_state, player_username_state, claim_tech_state, claim_tech_desc Name substring match; owner username; tier from learned techs.
GET /claim/<id> Above + claim_local_state, claim_tile_cost Supplies, treasury, tiles, upkeep, location, researched tech list.
…/inventory building_state, inventory_state, building_desc, building_nickname_state, location_state (interiors), dimension_network_state Shared storage only (no Town Banks). Group by dimension; attach entrance for interiors.
…/members claim_member_state, skills, hexcoins, player_state Roster + roles + skills + hexcoins + login timestamps. /citizens and /hexcoins are legacy projections.
…/citizens (alias of members) Deprecated — skills projection of /members.
…/hexcoins (alias of members) Deprecated — hexcoin projection of /members.
…/crafts progressive_action_state, passive_craft_state, crafting_recipe_desc, buildings, usernames Progress + recipe outputs; optional completed= filter.
GET /player?name= player_username_state, player_state Substring search; region; last login / last active / signed-in. Walkthrough with printable columns: Extract player data.
…/inventory Player bags via deployable_state_v2 / housing / rent links + inventory_state Pockets, toolbelt, wallet, bank, wagon, cache, boat, recovery, deployable — items aggregated per bag.
…/housing player_housing_state, housing desc, buildings, inventories, locations Resolve house entity; name from username/nickname + catalog; interior storages by dimension.
…/skills experience_state, skill_desc XP → level via vendored thresholds.
GET /deposits unowned claim_state (hexite name pattern), claim_local_state, resource_state, growth_state, hexite location_state Parse N/E from claim name; match resource at world x/z; respawn_at from growth end timestamp.
GET /storage-logs storage_log_state + building / claim / player username lookups Filter by storage, player, or item(+claim|player); enrich names.

Example: claim detail join

claim_state.entity_id = C │ ├─ claim_local_state[C] → supplies, treasury, num_tiles, x/z ├─ claim_tile_cost[num_tiles] → tile_cost, upkeep_cost, supplies_run_out ├─ claim_tech_state[C] → researching, learned[] │ └─ claim_tech_desc[id] → name, tier, requirements, … └─ player_username_state[owner_player_entity_id] → owner_player_username GET /claim/C → single enriched Claim JSON / protobuf

Example: hexite deposit join

claim_state where owner=0 and name ~= Hexite Deposit │ parse north/east from name ├─ claim_local_state[claim] → world x, z ├─ resource_state @ (x,z) with hexite resource_id │ └─ growth_state[resource_entity] → end_timestamp → respawn_at └─ location_state[resource_entity] (from 2nd subscribe) → coords check GET /deposits?region=14 → { deposits: [...], count }

HTTP API cheat sheet

Base URL: https://relay.bitcraftsync.app. Default JSON; send Accept: application/x-protobuf for protobuf (entity ids are uint64 there; JSON keeps them as strings).

MethodParamsNotes
GET /cache-health ready + per-region ready. Internals (memory pressure, row counts) on loopback-only 127.0.0.1:8089/internal/stats.
GET /proto List of .proto files; /proto/relay_cache.proto downloads one.
GET /claim?name= name (substring, case-insensitive) Array of claim summaries (tier, owner username, …).
GET /claim/<id> Full enrichment (supplies, upkeep, techs, location).
…/inventory Shared storage only; grouped by dimension.
…/members Roster + roles + skills + hexcoins + last login.
…/citizens Deprecated alias of /members (skills projection).
…/hexcoins Deprecated alias of /members (hexcoin projection).
…/crafts completed=true|false (optional) Omit filter → in-progress and completed.
GET /player?name= name (≥2 chars recommended) Cross-region search.
GET /player/<id> Plus /inventory, /housing, /skills, /crafts?completed=.
GET /deposits region=N (optional) Active omit respawn_at; depleted include it.
GET /storage-logs Exactly one mode:
storageId= or
playerId= or
itemId=+claimId= or
itemId=+playerId=
Optional: itemType=Item|Cargo, region=N, limit=N
Upstream retention ~15–16 days. Newest-first when limited.

Calling the public HTTP API

curl -s 'https://relay.bitcraftsync.app/claim?name=concordia' | jq .
curl -s 'https://relay.bitcraftsync.app/claim/1234567890/citizens' | jq .
curl -s 'https://relay.bitcraftsync.app/claim/1234567890/crafts?completed=false' | jq .
curl -s 'https://relay.bitcraftsync.app/deposits?region=14' | jq .
curl -s 'https://relay.bitcraftsync.app/storage-logs?storageId=1008806316593474517&limit=50' | jq .
curl -s https://relay.bitcraftsync.app/cache-health | jq .
curl -sH 'Accept: application/x-protobuf' \
  'https://relay.bitcraftsync.app/player/1297036692699996362/skills' \
  -o skills.pb

# Protobuf schemas:
curl -s https://relay.bitcraftsync.app/proto
curl -OJ https://relay.bitcraftsync.app/proto/relay_cache.proto