ludic/packages/ludic.nav/state.ludic
Orkuncakilkaya e807fd556c ludic.nav (23.5b): a baked mesh resident by chunk
nav_load_index indexes a saved mesh's tiles (cell, offset, size, ref) from their headers and keeps the file open, with no tile in. nav_tiles_keep reads in the tiles within rin of any player and removes those past rout of all; the file is read through Ludic's pack-aware file_open. The file format is unchanged. tiles_test: tiles come and go with the point, a path works across the seams once they are in, and a reset closes all. Measured on the baked maps (the 900 / 1100 m ring round the start): Maroon 617 of 1807 tiles in, 8.9 MB instead of about 27 MB for a person and 5.4 MB of about 14 for a large walker; Lamar 391 of 1147. Both libraries are rebuilt; nav 17/17 on the Mac and the PC, DLL KERNEL32 only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 11:07:27 +03:00

82 lines
3.5 KiB
Text

# state.ludic - the kinds of walker, what a mesh is built for, and what the package holds: a mesh
# per kind, and the last path's corners and nearest point, read back through the verbs
export const NAV_PERSON: int = 0 # 0.35 m wide, steps what a hiker steps (CHAR_STEP)
export const NAV_LARGE: int = 1 # an elk, a bear, a horse
export const NAV_SMALL: int = 2 # a hare, a marmot
export const NAV_KINDS: int = 3
export const NAV_FILTERS: int = 8 # costs per kind of ground, one set per taste (nav_area_cost)
export const NAV_CORNERS: int = 256 # a path's corners at most; a longer one is cut there
# what a mesh is built for: its voxels (cell across, cell high) and its walker (height, radius,
# the step it takes whatever its gradient, the steepest ground it walks, degrees). A tile must be a
# whole number of cells across, or its seams never join: 0.25 m is 256 to a 64 m tile
export property NavConfig {
cell: float = 0.25
cell_h: float = 0.2
height: float = 1.8
radius: float = 0.35
climb: float = 0.55
slope: float = 45.0
detail: float = 1.5 # the detail mesh's samples, metres apart (at least 0.9: 0 took one small test to 3.5 GB)
}
# what a mesh is built from: v holds nv points (x, y, z) and t nt triangles (three indices each);
# area a byte per triangle, 0 not walkable and 1..62 a kind of ground; cyl nc cylinders (x, y, z,
# r, h) and foot nf floats of convex footprints (n, n points x z, ymin, ymax) nothing stands in
export property NavGround {
v: []float = null
nv: int = 0
t: []int = null
nt: int = 0
area: []byte = null
cyl: []float = null
nc: int = 0
foot: []float = null
nf: int = 0
}
export state NavState {
nv_meshes: []pointer = nv_none()
nv_out: []float = floats(NAV_CORNERS * 3)
nv_count: int = 0
nv_near: []float = floats(3)
nv_cfg: []float = floats(7) # the configuration handed to the shim, filled in place per build
nv_empty: []float = floats(1) # what the shim is handed for no cylinders or no footprints
nv_asked: int = 0 # paths asked for, found (two corners or more), and cut short
nv_found: int = 0
nv_short: int = 0
nv_crowds: []pointer = nv_none() # a crowd per kind, on that kind's mesh (crowd.ludic)
nv_agent: []float = floats(6) # the last walker read: position, velocity
nv_files: []pointer = nv_none() # a file-backed mesh's file, kept open for its tiles (resident.ludic)
nv_tile: []float = floats(4) # the last tile asked about: centre x, z, in, bytes
}
function nv_none() -> []pointer {
let m = new []pointer
for k in 0 .. NAV_KINDS { push(m, null) }
return m
}
function nv_mesh(nav_st: NavState, kind: int) -> pointer {
if kind < 0 or kind >= NAV_KINDS { return null }
return nav_st.nv_meshes[kind]
}
function nv_set(nav_st: mut NavState, kind: int, h: pointer) -> bool {
if kind < 0 or kind >= NAV_KINDS { return false }
nv_crowd_drop(nav_st, kind)
if nav_st.nv_files[kind] != null { file_close(nav_st.nv_files[kind]) }
nav_st.nv_files[kind] = null
if nav_st.nv_meshes[kind] != null { nvc_free(nav_st.nv_meshes[kind]) }
nav_st.nv_meshes[kind] = h
return h != null
}
# one kind's mesh let go (a bake writes each kind and drops it before the next)
export function nav_drop(nav_st: mut NavState, kind: int) -> void { nv_set(nav_st, kind, null) }
# every mesh let go: a new map, or the world closed
export function nav_reset(nav_st: mut NavState) -> void {
for k in 0 .. NAV_KINDS { nv_set(nav_st, k, null) }
nav_st.nv_count = 0
nav_st.nv_asked = 0
nav_st.nv_found = 0
nav_st.nv_short = 0
}