hex_world API

← hex_world · version 0.2.3

17 public items, in source order. Generated from the registry index, which re-derives them from the package source at publish time — so a signature here is the one that version actually ships.

pub struct Cell { c_color: u8, c_height: u8, c_age: u16 }

4-byte cell. c_color uses the u8 typedef (integer limit(0,255) size(1)); c_age uses u16 (size(2)). Storage packs to exactly 4 bytes per cell — the projector ships them through the binary surface in chunk-major order.

c_color = 0 means "empty" (no crystal, no TTT mark). Both clients treat 0 as background; non-zero as live content. It is a SENTINEL, not a colour: a colour-0 cell stores its other fields but is invisible to cell_count, neighbour_count, the decay pass and world_save. Start a palette at 1.

pub struct Chunk { ck_cx: integer, ck_cz: integer, ck_cells: vector<Cell> }

32x32 grid at chunk coords (ck_cx, ck_cz). Index into ck_cells: hx * 32 + hz where hx, hz ∈ [0, 31]. Same shape as moros_map's Chunk minus the cy layer (this world is single-layer).

pub struct World { chunks: vector<Chunk>, tick: integer }

Top-level container. Sparse: only chunks with at least one non-empty cell live in chunks; empty chunks are removed by the tick loop's GC pass — that pass is the CALLER's. Nothing in this library frees a chunk: set_cell says so, tick_and_decay empties cells without touching chunks, and the only reclaim it offers is a world_save / world_load round trip, which writes non-empty chunks only. tick is monotonic per server lifetime.

pub fn chunk_idx_32(v: integer) -> integer

floor(v / 32) — handles negative v correctly (C-style / rounds toward zero, which silently maps cell (-1, 0) to chunk 0 instead of chunk -1). Use this rather than v / 32 for any coordinate that can go west or north of the origin, which in a world that grows both ways is half of them.

pub fn hex_idx_32(v: integer) -> integer

v mod 32, always in [0, 31]. v % 32 is NOT this: it answers a negative slot for a negative v, which then indexes nothing.

pub fn cell_empty() -> Cell

Default empty cell. All fields zero; serialises to four 0x00 bytes on the wire. Also what get_cell answers for a cell that is not there at all — the two are deliberately indistinguishable.

pub fn build_chunk(cx: integer, cz: integer) -> Chunk

Build a 32x32 chunk filled with empty cells at chunk coords (cx, cz).

pub fn world_empty() -> World

New empty world, tick 0, no chunks.

pub fn has_chunk(self: World, q: integer, r: integer) -> boolean

True iff a chunk exists at the global (q, r). The only way to distinguish "no chunk here" from "chunk here, cell empty" — get_cell answers the same thing for both, on purpose.

pub fn ensure_chunk(self: &World, q: integer, r: integer)

Ensure a chunk exists at the global (q, r); creates a 32x32 of empty cells if absent — 1024 cells per first touch, and never freed again by this library.

pub fn get_cell(self: World, q: integer, r: integer) -> Cell

Read the cell at global (q, r). Returns cell_empty() when the chunk does not exist (sparse-world convention — empty chunks are implicitly all-empty). Reading never allocates, so a read sweep over any region is free however wide; ask has_chunk if you need the difference.

pub fn set_cell(self: &World, q: integer, r: integer, value: Cell)

Write a cell at global (q, r). Creates the containing chunk on demand; does NOT GC empty chunks (the tick loop's end-of-tick pass owns that — and it is the caller's loop, not this library's).

pub fn cell_count(self: World) -> integer

Total number of non-empty cells across every chunk. "Non-empty" is c_color != 0, so this can answer 0 for a world holding heights and ages.

pub fn neighbour_count(self: World, q: integer, r: integer) -> integer

Count filled axial-hex neighbours of the cell at global (q, r). Returns 0..=6. Empty centre cell is fine — neighbours are read independently of the centre's state. AXIAL: the six deltas carry no parity term, so these (q, r) are not the odd-r offset pair hex_grid uses, though both are (integer, integer) spelled q and r. "Filled" is c_color != 0.

pub fn tick_and_decay(self: &World, base_lifetime: integer, neighbour_lease: integer, decay_window: integer)

── Tick + decay ───────────────────────────────────────────────────

One world step: advances tick, ages every non-empty cell by 1, then removes any cell whose c_age has crossed effective_lifetime + decay_window where effective_lifetime = base_lifetime + neighbour_lease * filled_neighbour_count. Neighbour counts are computed against the PRE-TICK state — a single tick can remove a connected blob of cells, but the cascade (centre losing its neighbour support) only fires on the NEXT tick. This keeps the simulation deterministic per-step and prevents one-tick complete collapse of large clusters.

pub fn world_save(self: World, path: text)

Save the world to path, replacing whatever was there.

pub fn world_load(self: &World, path: text) -> integer

Load the world from path. Mutates self in place; pre-existing cells in self are left untouched unless the snapshot overwrites the same (q, r). Returns the number of cells loaded. Returns 0 if the file does not exist, has the wrong magic, or carries an unsupported version — never panics.