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>
81 lines
3.1 KiB
Text
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)
|
|
}
|