ludic/packages/ludic.nav/resident.ludic
Orkuncakilkaya 93e5cb391e nav: nav_tiles_keep_near - a file-backed mesh's tiles kept by a distance the game answers (its players' zones, ludic.zones' zones_nearest): in within pad of it, out only past pad + hyst; the tile counters in resident_count.ludic
For loading the world by each player's fog rather than a fixed 900 m. keep_near_test: a zone round
one corner brings in its tile, a bigger one its neighbours, an edge nudged back and forth twenty times
changes nothing, and a zone moved 2 km away lets them all go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 15:43:22 +03:00

81 lines
3.1 KiB
Text

# resident.ludic - a baked mesh whose tiles are resident by chunk (phase 23.5b): its file is indexed
# once and kept open, and a tile is read in when a player comes within `rin` of it and let go when
# every player is past `rout`. Only the index and the tiles near someone are in memory.
# kind's mesh as an index of the file at `path`, with no tile in yet; false when it is not a mesh
export function nav_load_index(nav_st: mut NavState, kind: int, path: string) -> bool {
let f = file_open(path, "rb")
if f == null { return false }
let rec = nvc_stage(40)
var ok = file_read(f, rec, 40) == 40
var h: pointer = null
if ok { h = nvc_index_open(rec) }
if h != null {
let count = nvc_index_count_in(rec)
var at = 40
for i in 0 .. count {
file_seek(f, at, 0)
if file_read(f, rec, 28) != 28 { break }
let n = nvc_index_put(h, rec, long(at))
if n < 0 { break }
at = at + 12 + n
}
}
nvc_unstage(rec)
if not nv_set(nav_st, kind, h) {
file_close(f)
return false
}
nav_st.nv_files[kind] = f
return true
}
# tiles within rin of any of the n points (xs, zs) read in, those past rout of all of them let go;
# how many changed. Asked now and then (a second), not every frame
export function nav_tiles_keep(nav_st: NavState, kind: int, xs: []float, zs: []float, n: int, rin: float, rout: float) -> int {
let h = nv_mesh(nav_st, kind)
let f = nav_st.nv_files[kind]
if h == null or f == null { return 0 }
var changed = 0
for i in 0 .. nvc_index_count(h) {
nvc_index_tile(h, i, nav_st.nv_tile)
var best = 1000000000000.0
for p in 0 .. n {
let dx = xs[p] - nav_st.nv_tile[0]
let dz = zs[p] - nav_st.nv_tile[1]
best = Math.min(best, dx * dx + dz * dz)
}
let is_in = nav_st.nv_tile[2] > 0.5
if is_in and best > rout * rout { changed += nvc_index_out(h, i) }
if not is_in and best < rin * rin { changed += nv_tile_read(h, f, i) }
}
return changed
}
# the same ring by a distance the game answers: near(x, z) is how far (x, z) is from what must be
# loaded (0 inside it). A tile comes in when its centre is within pad of that, and goes only past
# pad + hyst, so a player at an edge does not read one in and out; how many changed
export function nav_tiles_keep_near(nav_st: NavState, kind: int, near: fn(float, float) -> float, pad: float, hyst: float) -> int {
let h = nv_mesh(nav_st, kind)
let f = nav_st.nv_files[kind]
if h == null or f == null { return 0 }
var changed = 0
for i in 0 .. nvc_index_count(h) {
nvc_index_tile(h, i, nav_st.nv_tile)
let m = near(nav_st.nv_tile[0], nav_st.nv_tile[1]) - pad
let is_in = nav_st.nv_tile[2] > 0.5
if is_in and m > hyst { changed += nvc_index_out(h, i) }
if not is_in and m < 0.0 { changed += nv_tile_read(h, f, i) }
}
return changed
}
function nv_tile_read(h: pointer, f: pointer, i: int) -> int {
let size = nvc_index_size(h, i)
let buf = nvc_stage(size)
if buf == null { return 0 }
file_seek(f, int(nvc_index_offset(h, i)), 0)
if file_read(f, buf, size) != size {
nvc_unstage(buf)
return 0
}
return nvc_index_in(h, i, buf, size)
}