From d4b697942627ba4076266cc4b80ca6c5e5790611 Mon Sep 17 00:00:00 2001 From: Orkuncakilkaya Date: Sun, 27 Sep 2026 21:34:23 +0300 Subject: [PATCH 1/2] feat(nav): 17.4 - a mesh has eight filters (a cost per kind of ground each) and every path, straight line and random point names the one it walks by, so a deer, a marmot and a person each take their own way over the same mesh; tested with a band of thicket walked round by the filter that dislikes it Co-Authored-By: Claude Opus 5.5 --- packages/ludic.nav/README.md | 18 ++++---- .../lib/macos-arm64/libludicnav.dylib | 2 +- packages/ludic.nav/native.ludic | 8 ++-- packages/ludic.nav/native/shim/nav_query.inl | 20 ++++----- packages/ludic.nav/native/shim/nav_shim.cpp | 11 +++-- packages/ludic.nav/query.ludic | 19 +++++---- packages/ludic.nav/state.ludic | 1 + packages/ludic.nav/tests/fakes/meadow.ludic | 6 ++- packages/ludic.nav/tests/nav_test.ludic | 42 ++++++++++++------- packages/ludic.nav/tests/tiles_test.ludic | 12 +++--- 10 files changed, 82 insertions(+), 57 deletions(-) diff --git a/packages/ludic.nav/README.md b/packages/ludic.nav/README.md index f209c10c..a889a2cf 100644 --- a/packages/ludic.nav/README.md +++ b/packages/ludic.nav/README.md @@ -29,7 +29,10 @@ import "ludic.nav" - **A wander's goal is somewhere it can go.** `nav_random_near` answers a point about r away that a walker standing at the start can reach - never across a river without a ford - from a seed the caller draws from its own `Rng`, so the same seed is the same point on every machine. -- **A kind of ground has a cost** (`nav_area_cost`): a trail cheaper than a meadow, scree dearer. +- **A kind of ground has a cost, and a walker has a taste.** A mesh carries `NAV_FILTERS` (8) sets of + costs per area (`nav_area_cost(kind, filter, area, cost)`), and every path, straight line and + random point names the filter it walks by: a deer's dislikes scree, a marmot's likes it, a + person's prefers the town. The nearest point uses filter 0. - **The same question gets the same answer.** Detour is deterministic for the same mesh and the same points, so co-op's order of dice is untouched by asking it. @@ -37,17 +40,17 @@ import "ludic.nav" | | | | --- | --- | -| `NAV_PERSON`, `NAV_LARGE`, `NAV_SMALL`, `NAV_CORNERS` | the kinds of walker, and a path's most corners (256) | +| `NAV_PERSON`, `NAV_LARGE`, `NAV_SMALL`, `NAV_FILTERS`, `NAV_CORNERS` | the kinds of walker, the filters a mesh has (8), and a path's most corners (256) | | `NavConfig { cell, cell_h, height, radius, climb, slope }` | what a mesh is built for (a person by default, 0.25 m cells) | | `NavGround { v, nv, t, nt, area, cyl, nc, foot, nf }` | what it is built from: triangles, an area byte each, cylinders (`x, y, z, r, h`) and footprints (`n`, n points `x z`, `ymin`, `ymax`) | | `nav_build(kind, ground, config) -> bool`, `nav_polygons(kind)` | one mesh over all of it | | `nav_tiled(kind, ox, oz, tile, max_tiles, max_polys) -> bool`, `nav_tile_build(kind, tx, tz, ground, config) -> int` | a map of square tiles, a tile at a time (its polygons, 0 none, -1 failed) | | `nav_save_file(kind, path)`, `nav_load_file(kind, path)`, `nav_reset()` | a baked mesh written and read; every mesh let go | | `nav_nearest(kind, x, y, z) -> bool`, `nav_near_x/y/z()` | the nearest walkable point within a couple of metres | -| `nav_path(kind, sx, sy, sz, ex, ey, ez) -> int`, `nav_corners()`, `nav_corner_x/y/z(i)`, `nav_partial(kind)` | a way as corners | -| `nav_straight(kind, sx, sy, sz, ex, ez) -> bool` | does the straight line stay walkable | -| `nav_random_near(kind, x, y, z, r, seed) -> bool`, `nav_near_x/y/z()` | a reachable point about r away, from the caller's seed | -| `nav_area_cost(kind, area, cost)` | how dear a kind of ground is to cross | +| `nav_path(kind, filter, sx, sy, sz, ex, ey, ez) -> int`, `nav_corners()`, `nav_corner_x/y/z(i)`, `nav_partial(kind)` | a way as corners | +| `nav_straight(kind, filter, sx, sy, sz, ex, ez) -> bool` | does the straight line stay walkable | +| `nav_random_near(kind, filter, x, y, z, r, seed) -> bool`, `nav_near_x/y/z()` | a reachable point about r away, from the caller's seed | +| `nav_area_cost(kind, filter, area, cost)` | how dear a kind of ground is to cross by that filter | ## Tests @@ -55,7 +58,8 @@ import "ludic.nav" ludic test packages/ludic.nav ``` -A 40 m meadow built by hand: a path round a post and a boulder's footprint, over a river's ford, +A 40 m meadow built by hand: a path round a post and a boulder's footprint, round a band of thicket +by a filter that dislikes it and straight through by the plain one, over a river's ford, stopping at the bank of a river with none, the nearest point, random points that never cross the river, and a saved mesh answering as the built one did. And a 128 m meadow as four tiles: a path across the seams, a tile under water with no polygons, and the set saved and loaded. diff --git a/packages/ludic.nav/lib/macos-arm64/libludicnav.dylib b/packages/ludic.nav/lib/macos-arm64/libludicnav.dylib index f88c1f04..4ea3bedc 100755 --- a/packages/ludic.nav/lib/macos-arm64/libludicnav.dylib +++ b/packages/ludic.nav/lib/macos-arm64/libludicnav.dylib @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:43832102310c1fa30e7efbca67b2665c018997d12efe784b71ebe98f171fde64 +oid sha256:7d2e4aa97130a76c41dfb6a6b93172e7cbab3fa6249035cc745c8eb162a8487a size 176736 diff --git a/packages/ludic.nav/native.ludic b/packages/ludic.nav/native.ludic index 61bb8f3c..0d897d54 100644 --- a/packages/ludic.nav/native.ludic +++ b/packages/ludic.nav/native.ludic @@ -8,8 +8,8 @@ extern function nvc_load(buf: pointer, size: int) -> pointer = "nav_load" extern function nvc_free(h: pointer) -> void = "nav_free" extern function nvc_polys(h: pointer) -> int = "nav_polys" extern function nvc_nearest(h: pointer, x: float, y: float, z: float, out: pointer) -> int = "nav_nearest" -extern function nvc_area_cost(h: pointer, area: int, cost: float) -> void = "nav_area_cost" -extern function nvc_path(h: pointer, sx: float, sy: float, sz: float, ex: float, ey: float, ez: float, out: pointer, max: int) -> int = "nav_path" +extern function nvc_area_cost(h: pointer, f: int, area: int, cost: float) -> void = "nav_area_cost" +extern function nvc_path(h: pointer, f: int, sx: float, sy: float, sz: float, ex: float, ey: float, ez: float, out: pointer, max: int) -> int = "nav_path" extern function nvc_partial(h: pointer) -> int = "nav_partial" -extern function nvc_raycast(h: pointer, sx: float, sy: float, sz: float, ex: float, ez: float) -> int = "nav_raycast" -extern function nvc_random_near(h: pointer, x: float, y: float, z: float, r: float, seed: int, out: pointer) -> int = "nav_random_near" +extern function nvc_raycast(h: pointer, f: int, sx: float, sy: float, sz: float, ex: float, ez: float) -> int = "nav_raycast" +extern function nvc_random_near(h: pointer, f: int, x: float, y: float, z: float, r: float, seed: int, out: pointer) -> int = "nav_random_near" diff --git a/packages/ludic.nav/native/shim/nav_query.inl b/packages/ludic.nav/native/shim/nav_query.inl index 4874d3a7..c3a8fdf3 100644 --- a/packages/ludic.nav/native/shim/nav_query.inl +++ b/packages/ludic.nav/native/shim/nav_query.inl @@ -3,7 +3,7 @@ static dtPolyRef nav_poly_at(Nav *n, const float *p, float *on) { dtPolyRef r = 0; - if (dtStatusFailed(n->query->findNearestPoly(p, n->ext, &n->filter, &r, on))) return 0; + if (dtStatusFailed(n->query->findNearestPoly(p, n->ext, nav_filter(n, 0), &r, on))) return 0; return r; } @@ -13,23 +13,23 @@ NAV_SHIM int nav_nearest(void *h, float x, float y, float z, float *out) { return nav_poly_at(static_cast