#landmass
1 messages Β· Page 2 of 1
@fathom jetty you're still maintaining bevy_rapier, right?
If so, this might be relevant to you as well π
I've added a tiny crate to convert avian colliders to navmeshes, and it should be easy to add another crate for rapier integration
(Also, here it's very noticeable that we don't have a serialized image type for the textures yet lol)
Fantastic! Simply fantastic. π
Thank you so much. I learned this from you!
@gentle basin how important is determinism for navmesh gen? I have no idea how navmeshes are done in multiplayer games, but I would have assumed that only the server uses them.
Though I remember you doing something recently where only inputs were sent between players, so in that case they would need a navmesh each
Usually the server owns and uses the navmesh and clients just interpolate
IME
makes sense, thanks π
I'll delegate determinism to "when I feel like it" then haha
I think we may even already be deterministic, but I haven't checked
I don't think there are any transcendental function calls
Ah @sharp oxide you asked about layers before. Here you can see that a mesh with mutiple vertical floors is nicely supported out of the box π
@wicked shard I believe you could use the crate in its current form already for baking your navmesh FYI
The things missing are mainly QOL and API, but the underlying functionality is mostly done. The only big thing missing is tiling, but since we don't have asset streaming, you probably don't need that if you don't update intend to update the navmesh at runtime IMO
Ah also @hollow quartz, you may be interested in this as well π
If client movement is predicted or if only inputs are networked, then the navmesh needs to be deterministic
Do you know examples where that would be the case?
RTS games for instance usually only replicate inputs
Something like an FPS with bots wouldn't need that, right?
Since I assume the prediction code for the bots would just use the same code as for players
@unreal rover I've never looked into how to make sure a library is deterministic. Do you have some advice here? I think you run some tests on all operating systems?
Oh oh, I know ... My game!
Probably not since they usually use server-authoritative replication. And the bots would be replicated from the server.
But something like rocket league would need it. Basically any games that predict other clients instead of just their client
Hehehe
I don't replicate only inputs, but I definitely don't plan to replicate navmeshes π€£
MOBAs/Arena games, etc.
Ha, interesting. I would have expected the navmesh stuff to be done on the server and then clients predicting stuff based on velocities etc
Ideally you'd do this where possible, but there are plenty of cases where the client might need to predict something that needs pathfinding, even if it's as simple as "You can only use a skill on a place you can walk to"
If such things end up non-deterministic, then it could start causing issues (especially if you use the path and not just a yes/no question)
Totally forgot that in some genres players also have navmeshes π
Yea and there's the plain "the player just moves using navigation too" yea
Lots of games still let you move by clicking on the groun after all
Yeah true, MOBAs again come to mind
I was thinking about first person stuff mainly since that's what I do
Or retro MMORPGs
Oh right
And in my use cases, only NPCs need navmeshes
Hopefully in many cases you can have prebuilt navmeshes however
But y'all are completely right
Alright, that bumps determinism up my priority π
Again, I think it's already deterministic
But I'd like to add tests ensuring that
Also @sharp oxide I think you said building a height field is easier for SDFs than building a trimesh?
Asking because I have builtin support for Mesh3d and Collider and API for adding support to other types to act as navmesh affectors
Currently, that API expects you to create a trimesh
which is very convenient, as it allows you to send it over the to the editor and preview it nicely
A heightfield can also be previewed, but is not visualized nearly as nicely as a trimesh
Note that this is just convenience API. You can always bypass bevy_rerecast and just do whatever you want with rerecast directly
Not necessarily easier, but it should be possible to make it cheaper
And in my game, with servers needing to compute navmeshes as player change terrain, or when a dungeon is generated whenever a player starts a mission, I sure want it to be cheap
yeah makes sense
Then I think it's best you use rerecast directly
The bevy layer is thin anyways
It's not like bevy_rerecast would know what the heck SDF colliders are anyway π€£
Well, I have API for
app.add_rasterizer(some_system_that_turns_navmesh_affectors_into_trimeshes)
Also, is there some sort of support for cheap rebuilding of modified sections of a navmesh?
So it would be elegant if that was flexible enough to support SDF colliders
yep π That's tiling
Not implemented yet, but that won't take long when I get to it
Basically, the map is split into multiple sub-navmeshes
And when you modify something, that tile is rebuilt
Neat, cause I may or may not be planning for the terrain in my game's dungeons to change constantly π
Also allows streaming of big navmeshes FYI
Gotta use that smooth min/max you get for free with SDFs
hmm? what's that?
Aaah I see π
Yeah I have this one and also a local determinism test elsewhere
It runs a 2D simulation with some jointed together objects falling on the ground and colliding for 500 steps, and then it queries for all positions and rotations, and computes a djb2 hash value based on the bytes of all the isometries. The expected hash is manually written into the file, and if it doesn't match on some platform, CI will complain and you need to update it
So the idea is:
- Do stuff with the library
- Write down the hash
- Verify that all platforms get the same hash
?
Yeah
It just creates a new App several times and tests that they all return the same result
https://github.com/Jondolf/avian/blob/c15549d6f752ca27c83ace3745e9eaa2b314d674/src/tests/mod.rs#L152-L184
Ah, fair enough π
there are better ways, they're just more complex https://www.jdxdev.com/blog/2021/07/06/rts-pathfinding-2-dynamic-navmesh-with-constrained-delaunay-triangles/
https://youtu.be/SYDxb6pVUIg?t=24 is a really good visualization
Oh hey I know that post π
I may have posted it every time navmeshes come up here lol
I think someone interested in it should be able to have a leg up compared to Unity, since a lot of these processes are implemented in rerecast. E.g., no need to write your own Delaunay triangulation.
Also, I wouldn't be opposed to adding it to rerecast as an alternative strategy
does rerecast implement its own delaunay triangulation>
Ye, it ports the one from the C++ impl
It was very important to me that the Rust port generates the exact same navmesh as the original for now
So I didn't use spade
I believe Godot uses an unmodified Recast, so we should have full parity with Godot
Unreal and Unity both use forks
Since I don't have a need for it, I won't try to implement it. But PRs are welcome in case you ever want to get nerdsniped @timid forge π
Oh wow I didn't know that video. Looks supremely cool π
@near nexus check this out
(though you probably already know it)
@light comet as you can see, Bevy cannot currently send textures over BRP because they are not serializable. I've discussed that with the rendering folks and they're fine with me adding a SerializedImage analogous to SerializedMesh.
If I manage to make a PR soon, may I place it in the 0.17 milestone? Should not be controversial.
I can live with that
thanks π
@sleek scarab looks like the triangles in the detail mesh don't have a consistent ordering... neither clockwise nor counter-clockwise?
Or I've parsed out this data incorrectly lol
It's currently complaining about the first two triangles. If I try to parse them CCW, the second triangle fails. If I try to parse them CW, the first triangle fails.
possible 
I'm not entirely sure
WAIT NO I'M BEING STUPID
Though if it was inconsistent, my mesh wouldn't show up here due to culling, right?
^
Don't tell me you also used .windows() instead of .chunks() lol
maybe this can help?
Looks fairly similar to my code...
Ok I was being stupid
I was adding the first_triangle_index to the vertex indices in a triangle π
@sleek scarab
ah, that explains it π
OOOOOOOOO π π π π π π π π π π π π π π
The blue gizmos are still the poly mesh, right?
@fast pawn ^
yes
I'm so hyped for this
@mellow mirage lemme know if there's anything I should change on the API π
There are a few things that annoy me
So far
- Use no
Vec3Ain API - Split
PolygonMesh::polygonsinto two vecs instead of one containing everything - Make sure the user doesn't need to know about
RC_MESH_NULL_IDX - Make some flags
bitflags
Yes Vec3A in the API makes it a little cumbersome to convert
I'm noticing that the detail mesh weirdly can sometimes be both above and below the regular mesh?
Green here is there detail mesh, blue is the regular mesh
Not sure if that's intentional?
detail mesh
Ahhh got it
hehe
Hmmm ok I guess it's fine then
Unfortunately I cannot display both at the same time in C++
Or at least not without looking into how ImGui works lol
Haha, yeah rendering both here makes it really messy in Rust lol
I'm currently adding checkboxes for visualizations to the Rust editor so I can debug edge cases better
In that vid it looks like the detail mesh is under the regular mesh though?
ha, you're right
Maybe we are visualizing them wrong?
There's also this
Is that closer to what you're seeing?
No mine is closer to the opposite. It's like there's an off by one error on the detail mesh
Like it looks shifted up a bit?
hrmm weird
I'll investigate later, need to be AFK for some minutes
If you want to try your hand, here's the C++ code
sec
@mellow mirage
- Poly mesh: https://github.com/recastnavigation/recastnavigation/blob/main/DebugUtils/Source/RecastDebugDraw.cpp#L855-L962
- Detail mesh: https://github.com/recastnavigation/recastnavigation/blob/main/DebugUtils/Source/RecastDebugDraw.cpp#L964-L1063 (it's the function right after)
rcPolyMesh and rcPolyMeshDetail are exactly identical to our meshes.
@mellow mirage I quickly checked the code on my phone and it looks like maybe the poly mesh is offset by 0.1 in Y direction when drawing for some reason
Does that match what you see?
In any case, I wouldnβt worry about that. Itβs just an offset in the drawing, the underlying data is correct π
I think I'm seeing the opposite? the detail mesh looks offset 0.1 in Y direction up
So it looks like the detail mesh is higher than the poly mesh when on flat ground

Maybe the cpp editor uses -Y up?
No clue
Yeah I'm not sure...
UI is not too pretty yet, but I've added different visualization options π
You can see that I also have the detail mesh above the poly mesh 
Also added the ability to toggle the visual aids off and only show affectors as wireframes. Looks pretty cool π
Is this using bevy_editor_cam as the controller?
Itβs using the flycam from the bevy examples
Not sure what its official name is haha
ahaha
Very funny to see it getting used more widely; I have so many problems with that code
Oh really? I didnβt inspect it at all and blindly copy-pasted it π
I would love to have bevy_editor_cam instead, but I donβt know how I would be able to set it into a flycam mode
#editor-dev was also in agreement that it should be configurable, but I havenβt seen anyone write code for it, and I didnβt want to spend too much time fiddling with it
Yeah, see https://github.com/bevyengine/bevy/pull/20215 for complaints
This is a good motivating use case for figuring out high-quality composable first-party camera controllers today
Rather than waiting on an Official Editor to need them
Well, maybe not today today :p
Oh wow I completely missed that
Yeah definitely, the navmesh editor should be in production use after the next few weeks
This will be great to have π
@light comet while I happen to have you on the line so to speak, does this sound like a good upstreamening plan?
I'm happy that we already got the two biggest pathfinding authors Andriy and FraΓ§ois on board for integration π
Yeah, this seems like the right shape.
Little ping @hollow quartz, do you think that rerecast is something that would be useful to integrate in your game? π
Also @fathom jetty I haven't touched Rapier in years, so do you think you could spare a little bit of time to help me out?
Here's the avian integration: https://github.com/janhohenheim/rerecast/tree/main/crates/avian_rerecast
I heavily assume that most of this is just copy-pasteable to rapier
Iβd love to, my current priority is final touches on updating bevy_rapier to latest rapier then I may be able to look into that
thanks a bunch! 
Might be related to https://github.com/rust-lang/rust/issues/144621 ?
Sounds similar from a very short skim lol
Apparently fix is merged so try again tomorrow?
I was also thinking of that
will do!
Oh hey that's the same thing Avian's CI is failing on
(or was yesterday, need to rerun to see if it's fixed now)
nightly was broken on glam #rust message
@mellow mirage I've generated a rerecast navmesh for Chainboom if you want to try it with landmass
Sure I can plug it in at least haha
Coolio, I'll check that out when I get home
let me also give you an untextured glTF so you have something to look at
@mellow mirage could you help me out? I'm trying to write an asset loader, but I always get empty bytes
When I debug print the bytes at line 42/43, I get an empty vector tho 
Context: I'm using this inside an automated test
And it's entirely possible that the issue is that I'm not adding some necessary plugin: https://github.com/janhohenheim/rerecast/pull/15/files#diff-a9973e2e055cca800e7ba2552558b9767a9241aed1af3a5c5442292ed5a34b38R109-R129
But everything looks correct to me?
If you want to check it out yourself, just run cargo test
(on that specific branch)
read is not the correct call, I think it's called read_to_end or something
It's in an ext trait
that was exactly it!
Thanks a bunch π
This is the user-facing API now btw
fn generate_navmesh(mut generator: NavmeshGenerator, mut commands: Commands) {
// configure things like the agent height
let config = NavmeshConfigBuilder::default();
// this is a `Handle<Navmesh>`. It's reserved and will get "filled" asynchroniously
let navmesh = generator.generate(config);
// This spawns a debug gizmo for visualizing the detail mesh
commands.spawn(DetailNavmeshGizmo::new(&navmesh));
// This is just here to save the handle somewhere.
// Maybe pass it to landmass? Or just save it in a resource like here.
commands.insert_resource(NavmeshHandle(navmesh));
}
Or alternatively, you use Bevy's regular RemoteHttpPlugin and generate the navmesh on the editor
You can then load the navmesh from disk with the asset loader
And if you have hot reloading, you can tweak the navmesh in the editor and save it, and Bevy should do the rest automagically π
Update: newest nightly building landmass again, if I use this patch: https://github.com/Emerentius/ord_subset/pull/9
Oh I goofed, this is fixed on landmass main, I just haven't published a new release of landmass
Sorry about that!
No problem π
@mellow mirage I believe we are now at the stage where we can publish integration plugins FYI
I recently implemented:
- Code-first navmesh generation API (see above)
- Load
Asset<Navmesh>from disk - Save a navmesh from the editor to disk
- Polished the API some more
The only things I still want for the MVP are
- configurate params in the editor
- load configurations from navmeshes on disk (so you can adjust them)
Then it should be already usable by projects that don't need dynamic rebuilds π
That also means that the non-editor workflow is pretty much done for the moment, until I go and add tiling
Absolutely brilliant!
I really love it β€οΈ
@mellow mirage how come you're doing the CW checks on the XY plane instead of XZ?
Is landmass Z up internally?
oh hey there it is
does that mean I need to do .xzy() on my data, given that it assumes Y = up? 
And flip the Z axis after
*before you mean, right?
same ;-;
Meh, I have to give up for the moment
@mellow mirage when you have time, could you take a look at what I've been tinkering with?
This is my rerecast -> landmass code: https://github.com/janhohenheim/foxtrot/pull/412/files#diff-9427b1919c7e7e7f172d76149fc0baacd522f29706e2a33b50f4d9cbabefe330R44
And this is my landmass fork: https://github.com/andriyDev/landmass/pull/130
The landmass fork is mostly just trivial renames and types, but I've commented on one line where I believe the old check was bugged
Seems like no matter what I do, I get Landmass navmesh failed validation: The triangle at index X in the height mesh is clockwise instead of counter-clockwise
That line is absolutely wrong, thanks!
Are your triangles actually both? Or is the check wrong?
Honestly, I'm not sure at this point π
I'll double check
@mellow mirage given that landmass seems to use a different coordinate system from bevy / rerecast, should I convert all verts like this?
trait LandmassVec3: Copy {
fn landmass(self) -> Vec3;
}
impl LandmassVec3 for Vec3 {
fn landmass(self) -> Vec3 {
Vec3::new(self.x, -self.z, self.y)
}
}
You shouldn't have to? CoordinateSystem::to_landmass should handle that?
Oh okay, so bevy_landmass::NavMesh gets everything in Bevy coordinates?
Yup!
Cool!
Then let me print the CCW-ness of my tris now
can confirm what Francois reported: all polygons and all tris are CW
landmass wants CCW, right?
If so, something weird is going on 
When I omit the height field, it will only accept my poly mesh indices if they're not reversed
Which imo would be CW
Oh I can't remember, there might be a weirdness - the landmass coordinates need to be CCW, but the conversion from bevy coordinates to landmass coordinates might flip the sign and make it CW?
Ooooh that would explain it!
@near nexus is oxi_nav CW?
I believe so.
As a consequence of the contour winding order, which should mean outlines = CW, holes = CCW.
And these are used for triangulation iirc
Great, then that matches what Andriy says π
Note to self: rerecast is CW and uses bevy coords, landmass expects the navmesh to be built in Bevy coords and to be CW.
That means that no conversion should be necessary
Which leads me to believe that this is broken on the landmass side π¬
@sleek scarab I think I could make the coordinate system decide CW or CCW. So even in Bevy it would be CCW. Since you're generating navmeshes CCW and need to flip them, it might be better if landmass does it automatically
Thoughts?
Navmeshes are CW
So I donβt benefit from this haha
Just needs to be documented on landmasses side, but I can PR that
I suspect the indexing into the actual vertices is bugged for landmass
That, or the coordinate conversion is applied at the wrong stage
Then why does this https://github.com/janhohenheim/foxtrot/pull/412/files#diff-9427b1919c7e7e7f172d76149fc0baacd522f29706e2a33b50f4d9cbabefe330R77 do reverse stuff?
Because I wrote that code before chatting with you π
Haha
Issue is that when removing the faulty reversing, I still get "random vertex at index 33 is CW and not CCW"
Come to think of it, thatβs a very misleading error message given that bevy_landmass expects CW
Yeah I was just thinking that haha
When does the coordinate conversion for the height mesh happen?
The top of HeightNavigationMesh::validate, I call CS::to_landmass
Aah gotcha
Something fishy is going on beyond the CW-ness. If I remove the CW check, I get this:
And commenting out the validation outright nets me
@sleek scarab Why did you change https://github.com/andriyDev/landmass/pull/130/files#diff-33bb3cc574b69a17cf73d31044e89629d4a9517e09f5f9be074686df986eb622R498 from u16 to usize? Could it be that the vertex indices aren't relative to the start of the submesh vertex range?
They are relative in rerecast, see the docs
Because youβre using usize for everything else that can be indexed, so I thought it would be more consistent π
Note that rerecast now uses u8, if you want to use the exact same API
Ah yes I think that's my preference, mainly so we limit the memory usage (I'd expect the detail mesh to be big compared to the polygon mesh)
Then I can also go ahead and change some other indices to u16 later
If there's a bug in landmass, I don't see it π This is failing when its trying to iterate through the vertices of a height polygon. So it really seems like something is wrong with the indices being passed in
https://github.com/janhohenheim/foxtrot/pull/412/files#diff-9427b1919c7e7e7f172d76149fc0baacd522f29706e2a33b50f4d9cbabefe330R103 Why are you changing the triangles here? Couldn't the triangle indices no longer match up? as in the triangle_index and the triangle_count may no longer correlate with where they end up after the collect
Alright, let me really really make sure the input is right
Thanks for checking
Updated my branches / PRs
Locally, when I create the detail navmesh debug mesh, I validate all triangles being CW and panic if not. And it indeed does not panic
I've changed the landmass types to align exactly with the rerecast height mesh types
and I've added a dedicated function called rerecast_to_landsmass
If you take a look at that, you can see that the only transform even left for me to do is convert the vertices from local coords (u16) to global coords
And I assume landmass wants the vertices to be in global coords? And not relative to some bounding box or another
yes
This makes me believe that there must be a bug in landmass, as there is no longer any place for my code to really have a bug in 
Given that the detail mesh gizmos show that the mesh is well-behaved
I'll dig a bit into the relevant landmass code
Maybe it's a simple "oops we used this index offset instead of this"
That's what I'm expecting, but I can't see it :/ I spent a while looking at the code because I figured mine was most likely to be broken lol
Wait
This line is using the polygon mesh?
AAAAAA
hahaha
hahahaha
well would you look at that, the validation passes now 
thanks!! I was a silly goose haha
Haha no worries! You caught my own silly goose moment in your PR π
Alright, my code now just inserts a NavMeshHandle into the archipelago and hopes everything connects magically
but it doesn't 
Do I need to do anything else?
oh yeah you need an island
ooooh
I assume simplest is to spawn just one?
Even technically the mesh is separated into distinct areas
Yup! The mesh does not need to be connected
But I'd have to split these out first, right?
cool!
Can the Island be the same entity as the Archipelago?
(Since I only have one)
Oh uhhhh I'm honestly not sure. I don't think that would technically be a problem??
Eh, I'll do two entities to be sure
And the navmesh handle is on the island, right?
my nightly is really not liking me constructing things from aliases haha
Yup!
oh wait no that is actually my bad
Yeah that's just normal rust I think...
yep
Yeah it's a limitation. I've had to use NavMeshHandle itself to construct it :/
AAAAAA
It works 


The dual gizmos are because I also use the rerecast gizmos on top
Can I tell the landmass debug gizmos to only display the pathfinding stuff and not the navmesh?
Anyways, treat https://github.com/andriyDev/landmass/pull/130 as done 
And for future readers, this is the entire secret sauce:
fn rerecast_to_landsmass(
rerecast_navmesh: &bevy_rerecast::Navmesh,
) -> bevy_landmass::NavigationMesh3d {
let orig = rerecast_navmesh.polygon.aabb.min;
let cs = rerecast_navmesh.polygon.cell_size;
let ch = rerecast_navmesh.polygon.cell_height;
let to_local = Vec3::new(cs, ch, cs);
let nvp = rerecast_navmesh.polygon.max_vertices_per_polygon as usize;
NavigationMesh3d {
vertices: rerecast_navmesh
.polygon
.vertices
.iter()
.map(|v| orig + v.as_vec3() * to_local)
.collect(),
polygons: (0..rerecast_navmesh.polygon.polygon_count()).fold(Vec::new(), |mut acc, i| {
let poly = &rerecast_navmesh.polygon.polygons[i * nvp..];
let verts = poly[..nvp]
.iter()
.filter(|i| **i != PolygonNavmesh::NO_INDEX)
.map(|i| *i as usize)
.collect::<Vec<_>>();
acc.push(verts);
acc
}),
polygon_type_indices: rerecast_navmesh
.polygon
.areas
.iter()
.map(|a| a.0 as usize)
.collect(),
height_mesh: HeightNavigationMesh3d {
polygons: rerecast_navmesh
.detail
.meshes
.iter()
.map(|submesh| HeightPolygon {
base_vertex_index: submesh.base_vertex_index,
vertex_count: submesh.vertex_count,
base_triangle_index: submesh.base_triangle_index,
triangle_count: submesh.triangle_count,
})
.collect(),
triangles: rerecast_navmesh.detail.triangles.clone(),
vertices: rerecast_navmesh.detail.vertices.clone(),
}
.into(),
}
}
Running when Asset<bevy_rerecast::Navmesh> was LoadedWithDependencies π
Also added comments about winding order
The default debug stuff isn't very configurable. But you can honestly just fork it and not render the gizmos
It's not very complex code iirc
Mind if I just add it to the same detail mesh PR?
(configuration, not deletion :D)
Oh, the code works perfectly when editing the mesh from the editor btw π
landmass nicely uses the new navmesh when the editor saves it to disk because the code I wrote runs when the asset is loaded 
I'd prefer that as a separate PR
Alright, I'll do that after the detail stuff is on main then π
From my humble user-perspective, I think you can merge the detail stuff onto main
Your pathfinding is working great in Foxtrot π
No more stair problems 
Thanks again for creating landmass, it's working soooo nicely together with rerecast 
I think I agree? I need to do one more pass to make sure I'm not forgetting something
Haha thank you for actually integration testing everything AND making rerecast haha, I just hope I can implement everything you need to take advantage of rerecast π
I wonder if splitting a navmesh into islands should be rerecast's or landmass' job
I'm tending towards rerecast
Assuming by "island" you mean "disconnected area" in landmass
Not quite, island is closer to "chunk" or "tile"
Oooh I see
Well then I'll need to implement tiling first π
I've been lazy with that because the tile-less approach is surprisingly fast for my use-cases
Very understandable!
Also, is there a way to easily do portals / off-mesh connections?
I think that would be the pathfinding library's job
Maybe by reading a component somewhere on the world that has a relationship with another entity?
No there isn't yet. It's this issue https://github.com/andriyDev/landmass/issues/7
Definitely pathfinding's job haha
That way I could easily add them over the level editor
got it π
I suppose I would need to wait for that for ladders too, right?
As in, a 3D ladder that goes straight up
Well, maybe a 10 degree tilt
Yeah there's no way to do that today
Hahaha you could indeed have a super steep ladder LMAO
just set the max angle to 90 degrees on that tile specifically 
Francois is planning on adding further first-party support for rerecast navmeshes to vleue_navigator
Wonder what the implication on https://github.com/andriyDev/landmass/issues/121 is
Since in principle, the two plugins could just share the same bevy_rerecast::Navmesh
I think the only reason this issue existed was because vleue_navigator was for its nav mesh generation
If vleue starts using rerecast, I don't see a reason to integrate that
Yep. It was also about 2D support, which rerecast supports, you just need to write a backend that extends the Vec2s to Vec3s.
Which takes about 50 lines of code, backends are really simple to write π
Pasted my code here so it doesn't get lost: https://github.com/andriyDev/landmass/issues/131
I'm afraid that merge did not go as planned :p
I am so sorry D:
Oh because I accidentally killed all your commits, so that auto closes the PR
phahaha
@sleek scarab here's the commit hash for your branch 6f84711753376a881f4f56cb6b53dc5b665d0e1c
You un-hohenheimed landmass 
Feels like you're handing out a receipt lol
MY DUMBASS THOUGHT git push -u jan detail WOULD PUSH MY CURRENT BRANCH TO jan/detail π
phahahaha
Do you need me to upload anything again?
I have it all local
Alright, can you send another PR?
So sorry about that
haha no worries, been there
Oh and just PR main eh?

hold up
did you commit on my fork? 
alright, let me force push
there we go hahaha
I can fix the merge conflicts, sec
Yes, I thought "oh I'll just go to your fork, remove the merge, and then I can merge it correctly". But then I replaced your detail branch with my detail branch instead of your fixed branch
I think this just needs a rebase

Oh I'll leave it to you then
phahahaha
It's still intact locally, I can always force push it again π
Or wait, I'll also push a detail-bk branch
there, now it's doubly safe π
hahahaha
wanna do a 0.4.1 release?
Oh wait your structs are probably not #[non_exhaustive], so this is breaking
Yup this is breaking
I can depend on the git repo, no problem
I'm gonna grind out some changes first, starting with making you generate CCW nav meshes π (so lock down your rev hash)
Now I can finally go back to annoying you with non-navmesh-related bugs lol
With rerecast, this is fixable on your end. Whenever a physics object gets frozen, rebake the nav mesh
I read through the hole cutting blog you sent a while ago, and it seems like their solution is mostly to let recast deal with it
oh right, I remember
I do wish I could fix this on my end, but alas
but the API is in detour, isn't it 
I think Detour orchestrates the hole cutting? My understanding is they store the heightfields or something, and then just updated the polygonization. Something like that
that's probably a good incentive to implement tiling haha
aaaah alright
Yeah I could probably port that part too
I mean if it really is fast enough, you might be able to get away with literally regenerating the whole map?
Honestly, probably
This is the speed we're talking about
Lowkey that might be fine? I think it's fine if physics objects take a while to settle
just need a good heuristic because there's always something moving and freezing on the map if we regenerate the whole thing
so I'd queue a new build every frame
which is fine, as a running navmesh regeneration will not be overwritten when kicked off again
So it will in effect just produce as many navmeshes as possible, no starvation there
But probably doing one every 200 ms is good enough
https://github.com/andriyDev/landmass/pull/134 is merged. So flip all your stuff!
on it 
Got this for you in the meantime: https://github.com/andriyDev/landmass/pull/135
I would have preferred to do it like Avian and have navmesh: Option<Color>, but the current bevy-agnostic draw stuff you do makes that hard
Sec, let me also add an agent field
Update your docs!
dunno what you mean by this
I'm fine with only changing the Bevy-facing API (since I only use Bevy), but I don't know what exactly you mean
ah wait
I think I got it
Fixed haha
Can I rename LandmassGizmoConfigGroup to LandmassGizmos while I'm on it?
Parity with how Avian styles it
Yeah sure!
nice
I'll add color configs to all current colors while I'm on it
/// A config group for landmass debug gizmos.
#[derive(Reflect, GizmoConfigGroup, Debug, Clone, Copy, PartialEq)]
pub struct LandmassGizmos {
// points
pub agent_position: Option<Color>,
pub target_position: Option<Color>,
pub waypoint: Option<Color>,
// lines
pub boundary_edge: Option<Color>,
pub connectivity_edge: Option<Color>,
pub height_edge: Option<Color>,
pub boundary_link: Option<Color>,
pub agent_corridor: Option<Color>,
pub target: Option<Color>,
pub waypoint_line: Option<Color>,
}
fine like this?
Not quite sure what to put in the docs other than repeating the name π
/// The color with which to render agent positions. If [`None`], agent positions are not drawn.
Something like that please
A little verbose, but I don't want None to seem like "default"
/// A config group for landmass debug gizmos.
#[derive(Reflect, GizmoConfigGroup, Debug, Clone, Copy, PartialEq)]
pub struct LandmassGizmos {
// points
/// The color to use when drawing an agent's current position. If [`None`], agent positions are not drawn.
pub agent_position: Option<Color>,
/// The color to use when drawing an agent's target position. If [`None`], target positions are not drawn.
pub target_position: Option<Color>,
/// The color to use when drawing waypoints along a path. If [`None`], waypoints are not drawn.
pub waypoint: Option<Color>,
// lines
pub boundary_edge: Option<Color>,
pub connectivity_edge: Option<Color>,
pub height_edge: Option<Color>,
pub boundary_link: Option<Color>,
pub agent_corridor: Option<Color>,
pub target: Option<Color>,
pub waypoint_line: Option<Color>,
}
Yup, looks good!
Uhhh
Wait can we add color suffix to each
Oh wait
Nah let's not
I was thinking if we wanted to add size or something
But if that were the case we'd house those options in a struct
LGTM
great, let me wire this up real quick
Just make sure those doc comments are <80 columns or else my format should complain lol
It's in the rustfmt.toml, so it should autoformat for me π
You need nightly though for it to work though so it might not be automatic
(I have my vscode configured to always use nightly rustfmt lol)
I'm always on nightly 
ahhh ok awesome haha
(in fact, stutterless wasm audio requires nightly, so I don't really have a choice anymore lol)
@mellow mirage check the PR again
How do you like to document breaking changes?
Currently I don't π I don't know what a good mechanism for that is.
Maybe just a changelog md is good enough...
yeah probably. Or add a PR template with a "added" and a "migration" section π
That way contributors donβt forget to list their changes
When you make a new release, you can then just go through the PRs of the release and copy-paste them into the changelog
That part I feel ok about enforcing myself
I just need a pattern to stick myself to lol
Hehe
Can confirm gizmos are working as intended 
Also, do you maybe want to disable CodeCov?
I feel like it's failing on almost every PR haha
Added a "Changelog" and "Migration" section to the PR so you can use that later
noice
No I want to keep it. Let me see if I can make it more reliable
I think I might have it configured wrong lol
Implemented add_triangle for good measure π
It's not as nice as having a filled-in triangle by creating a mesh, but eh
Not opening that can of worms haha
Is it providing good visuals? It seems like it might just be a jumbled mess without the fill?
Pretty sure I fixed codecov now, it's actually showing a redacted token now lol
looks completely fine
Whether its useful or not is imo not a question of the drawer, but of the drawn feature
It's probably good to leave it at None by default
but IMO if there are debug drawing calls for it, it feels silly not to offer the gizmo
hehehe
Ok sure, if we're gonna default it to None, I'm down
Debug now renders the paths the way they are computed - we navigate through the center of edges, not through the center of nodes
For context, here's what debug view looked like before
(that's also how it used to be computed, which gives an indication of why landmass use to give bad paths in some situations.
Yeah this is much much better π
Oh btw, you may care about this regarding polyanya-landmass parity
Polyanya currently expects all polygons to be planar, but rerecast generates aplanar polys. It should be mathematically possible to deal with this, but until that is done, polyanya just uses the detail mesh for pathfinding when available. Meaning that for rerecast purposes, polyanya just uses triangles for everything.
So I believe landmass and polyanya probably generate fairly similar results? Not sure
polyanya will generate better results overall. The way the A* in landmass works it always goes through the edge center. polyanya on the other hand keeps track of the "cone" that the edge is visible through.
Effectively they are doing the "string pulling" while doing the A*
Aah got it
So they are actually computing the straight-line path while navigating and optimizing that
Makes sense π
I'll soon remerge the planar triangles, it's fairly easy to do, just a pain to check that all the indexes are updated correctly. luckily it panics very fast if it's not right π
β€οΈ panics
I already have a function that merge polygons by checking each polygon with its neighbours if it's convex, I'll reuse something similar but driven by the already defined group of triangles from the poly mesh
@sleek scarab https://github.com/andriyDev/landmass/pull/141 wdyt
Not the standard changelog format, but I like Bevy's split of "release notes" / "migration guide". Makes it a clear separation between "using the shiny new stuff" / "bare minimum to make it work"
I like the same format as you describe π
Looks good, also add the blurb I had in the gizmo PR description π
Ah wait, you did
Just not the migration part
OHHH I'm dumb I thought it was new, but it's actually renamed haha
I will fix that and mix in more of your description
Thank you!!
@sleek scarab https://github.com/andriyDev/landmass/tree/rerecast Partially done. Still needs an asset loader, and an example to test it all out, but alas it is bed time
A navigation system for video games written in Rust. - GitHub - andriyDev/landmass at rerecast
Oh and at least some testing.
Oh wow, this is great news π
Curious what you want an asset loader for
Do you want to load .nav files directly as landmass navmeshes?
I didnβt consider that, but thatβs actually pretty smart, and super nice for the user π
Hmm looking at the code, wouldnβt it be perhaps easier to accept a user provided Handle<bevy_rerecast::Navmesh> on an island, that is then converted to a Handle<landmass::NavMesh> when the resource is (re)loaded
The current wrapping API makes it more time intensive to update landmass_rerecast, as every change in bevy_rerecast needs to be mirrored
Yup exactly. The loader will just wrap your loader and then do the conversion in the loader instead of after
Clever!
Oh interesting. That's also an option! I'll have to think about this.
I'm a little worried it's gonna be harder to juggle the handles correctly, but I'll give it a try
Oh here's a concern, there's no place to put the type index map. I guess you could register the type index map for a specific handle, but that seems a little gross... You'd need to call generate, then register the type index map, then insert the handle on the island.
If we made the type index map a component, we'd have to dedupe them when converting rerecast to landmass
Maybe the answer there is to make the type index map a component in bevy_landmass too though. It's already difficult to set that correctly from a loader anyway...
Sorry, whatβs a type index map? π
A map from area IDs to costs?
If so, I'm open adding something like that, sure!
Ehhh not quite haha, it's a map from area ID to node type. There's a separate map from node type to cost, that way agents can have different costs for the same node type
Oooh gotcha
Wonder if the user flags could serve that purpose? Probably not
Anyways, if it helps adoption, I'm happy to make it an optional field on Navmesh π
Nooooo definitely not. I'm currently wondering why I should bother with a node type and why not just use the raw type indexes. Leave it to the user to manage correctly...
Seems perfectly fine too
Though about this some more and yeah, I think just using the indexes is good enough. The user has enough data to build their own abstractions on top.
Yeah it's basically just some juggling the user has to do. The initial motivation was so that your type indices didn't have to be consistent globally when loading the nav mesh. So like, if you had a city mesh with roads, you could say 1=road, and is you have a cave mesh, you could say 1=rock. Then when you load up those meshes, you'd register those types and they will be mapped to be distinct
Makes sense
But like, this seems like way too difficult of a solution, when a user could just do that conversion themself.
And since the user has access to the rerecast mesh, they can just change the areas how they want
At load time, pick a random number to act as road, and another random number to act as rock
Anyway, this is already on main haha
I'll see how this change makes me feel about the rerecast integration
(once I rip out the node type stuff)
I think I'm most concerned about having to deal with the lifecycle of the navmesh handles
Like your island will now have two nav mesh handle components: one for the rerecast mesh and for the landmass mesh
And now I need to make sure to delete that landmass mesh handle component if you delete the rerecast mesh handle component
Maybe that's just one observer though so perhaps it's not a big issue lol
Yeah thatβs what I'd do
And then update the landmass asset when the rerecast asset is reloaded
I think thatβs enough
The navmesh is twice in memory, but these meshes are fairly small, so I think thatβs alright
If the user cares, they can just manually convert the rerecast mesh to a landmass mesh
Oh I've been removing the rerecast mesh when converting it.
I wouldnβt
If you keep it, you can have hot-reloading
I'm pretty sure even if you remove the asset, you still get hot reloading
Oh, really?
Well, you would know better than me π
I may be wrong but I don't think the assets impl cares, it just sees "this path has been changed, and there's a handle for this path"
I'll verify that before committing haha
That would be really really nice
Landmass can have a very clean API
and very easy migrations
Which is imo even more important, otherwise it will just rot
Also, I think we could sunset the oxi_nav integration @near nexus
Rerecast still has no impl for tiling until I have time to port it, but given the performance of regenerating the whole mesh, itβs not really essential imo.
The thing I like about the wrapping API was that users never saw the rerecast handle, so they never had the chance to be confused by two types of nav meshes, and if I remove their rerecast mesh, they won't miss it because all they'll see is the landmass mesh
But you're right, the cost is the ease of migrations
Seeing as how oxi nav hasn't published an 0.16 version, I think that's correct
Yeah in a perfect world I would also wrap everything. Itβs your migration pain, so your choice, but I wouldnβt recommend it.
Plus, I'd like to upstream bevy_rerecast_core eventually, which would make it alright to leak the rerecast types
I agree. It's served it's purpose and Rerecast is quickly surpassing it π
Again, fantastic work
Thanks! I cannot stress enough that I would not have been able to do this without building on your previous work 
https://github.com/andriyDev/landmass/pull/145
wink wink nudge nudge
Thanks haha, I just gotta test this every now and then
Hopefully it gets fixed soon
Hopefully we're not the only ones with issues π₯
When I ran into it the other day a quick google told me that no one reported it yet
Eh I'm not sure how valuable
I think there's zero value
It just annoyed me that the matrix was missing an entry for nightly hahaha
sec, doing a bug report
(on Bevy)
Oh awesome thank you!!! This conversation was gonna make me do it tonight haha
Alas it is time for work and I'm sooooo late
have fun π
Some notes on the branch:
- Mind switching
rerecast_to_landmassout for animpl From<RerecastNavmesh> for bevy_landmass::NavigationMesh3d? If you do, I could already depend on it in Foxtrot to help test it. - We could also have a 3D and 2D variant of the integration crate, given that there is interest in generating 2D navmeshes.
bevy_rerecastdoesn't have a 2d and 3d split because it has no reason to do so; just set one dimension to 0. But given that landmass uses a 2D / 3D split, we should imo be able to generate both from a rerecast mesh, again by just throwing away one dimension. The settings tell which axis isup, so it can be used to know which dimension to discard π
Oh
I just realized a height mesh makes no sense for 2d
But I don't have this skipped for 2d in any way...
I guess there's not much I can do there though.
BTW the new debug visualization for the purple line is looking nice!
I'm down to make the conversion function public, but I don't think I wanna make it a From impl. From is for when the conversation is lossless, but I throw out rerecast data like user flags
As for 2d, I'll keep it in mind when implementing the integration crate. I don't think we need separate crates for 2d vs 3d
That said, I really think rerecast is the wrong implementation for 2d? You can probably strip out so much from rerecast and simplify a lot of its internal DSs
Like you probably still want rasterization, but that math could be much simpler. You don't need any span business. You still could use partitioning, and turning that into polygons.
Maybe all that doesn't matter though, it's probably not a big performance concern in 2d
Just seems wasteful haha
oooh fair point, yes
Navmeshes are preauthored anyways, so it doesn't matter
I guess highly dynamic 2D games with a big map and lots of obstacles would want something custom
I am definitely more focused on dynamic games haha, you're totally right that for preauthored nav meshes, just let the computer whir
I tried your API and I think it'll work well too
Island3dBundle, NavMeshHandle3d and NavMeshHandle should all be manually imported, and then they'll effectively shadow bevy_landmass
Aaah Weak<StrongHandle>, our good friend
oh that's a really good idea π
Didn't think of that!
what is my API?
I need a boatload of tests, an example and a README, but then I'll be ready
The one about using rerecast handles on islands?
The "don't wrap rerecast"
ah gotcha
Yeah this seems way more maintainable!
that's cool π
There is a bit of sadness where we now can't load the landmass mesh directly from rerecast files - the disadvantage being that we'll be doing the conversion during a game frame
@fast pawn you may be interested in this, since you're also thinking about having more rerecast integration options
Hmm fair point
I think that should be fairly inexpensive
But I haven't benched anything
Yeah almost definitely not a big deal, but it makes me wish it could be different haha
@sleek scarab btw https://github.com/janhohenheim/rerecast/pull/25 is stuck
Looks like it's just the nightly stuff that's broken π
Ooof I also just realized the rerecast has an entirely different meaning of "area type" compared to landmass...
Areatype in rerecast is a bitmask, whereas its an index in landmass
Itβs an index in rerecast too
Did I make it a bitflag? Whoops
It's a bitflag in original recast iirc
It's really just a choice of vision, I guess recast nerds view it as a bit flag of "I can walk over this, I can swim over this, I can skateboard over this, etc", I'm viewing it more like "this is grass, this is road, this is lava, etc"
As long as your area type stuff has a "set" operation as opposed to bitwise OR / bitwise AND, I don't think it's a significant issue.
Oh lol I didnβt even realize
Yeah the thing is, no one is doing area types anyways since we have no way to paint them yet π
Oh LMAO then we're all set hahaha
I mean there is in API, but no way to artistically control that visually
I wanted to add a simple version to the editor but didnβt bother yet because it involves mesh picking through a backface culled portion of the same mesh and that sounds scary
Oh I would still consider that valid
I actually didn't have a problem with that EXCEPT for "stray geometry"
But that's a texturing problem maybe
Ha, good to know
The ultra simple API is not even texturing, itβs just you drawing a polygon where you want the region to be
Oh all I meant was it was hard to see what I was clicking on because it was all white π π
Aaaah got it haha
@sleek scarab you've heard of "which direction is forward", now get ready for "which order is clockwise" π
bevy_landmass on main currently treats a polygon as counter-clockwise if its vertex coordinates follow the right hand rule. rerecast on the other hand treats a polygon as counter-clockwise if the XZ of the coordinates follow the right hand rule. Turns out, this corresponds to clockwise oriented polygons by bevy_landmass's definition
The solution to this is reversing the coordinates during the conversion from rerecast to landmass, which I can do.
Just wanted to make you aware of this weirdness I guess
Also example has been recreated. I decided to strip out moving the camera and just keep it fixed.
https://github.com/andriyDev/landmass/pull/146 It's ready π
barring the ack of this

Why do you say that rerecast treats them as counter-clockwise? I changed the docs to say that the polygons and tris are always clockwise
Oh? Is that version released?
(totally fine if not)
Should be
0.1.1
If I didnβt accidentally write something wrong π
bevy_rerecast_core is on 0.2.0
Those docs are on rerecast
Represents a polygon mesh suitable for use in building a navigation mesh.
Maybe this doc was missed haha
Or I am misunderstanding this doc
Oh wow yes this is exactly the doc π
Whoops
My bad haha
Exactly the *wrong doc
LMAO npnp
Will fix later, thx
Oh hey I know that scene π
Make the light a liiiittle bit orange to make it look less clininal
Hahaha ok you got it
Hopefully slightly less awful
oh wait
I have night light on
Nah I think that's the right color lol
Better π
Initial review: mind replacing bevy_rerecast_core with bevy_rerecast in user-facing docs?
The split there is only so that upstreaming into bevy is easier
But users should not care about that detail
bevy_rerecast is primarily for the editor, yeah?
it just reexports core and the editor integration
If you donβt need the editor, you can just disable that feature
Oh this is awkward, the docs won't link to bevy_rerecast because it's not a dependency...
Heh
I guess I can make all my Navmesh links manually link it to core?
You can depend on bevy_rerecast with default features disabled
Fair π
I'll patch foxtrot to your branch later to see if it works
Good night π
Awesome!! And thanks haha
Curious why it should be clockwise? Afaik counterclockwise is the standard for stuff like triangle meshes for determining which side is the front face
Because thatβs what recast does 
Agreed that CCW would be better
But this is not a choice I have; rerecast (at least right now) produces exact matches of recast
Since Godot uses an unmodified Recast, I wonder if they convert it to CCW before showing it to the user
Fair, I guess it's good to match it at least for the core rerecast crate
Unity and Unreal are both using Recast forks, so I imagine they may have changed the winding order
we can make rererecast that is a modified version of rerecast
Hehehehhe
I have at least one place in the code where I am 90% certain the original has a bug
It compares a length to a squared length
(In other places, itβs always compared to lengths, not squared lengths)
Iβve just commented it for now
And added an issue to the original, but the author is not very active
Which is good, since it means we probably never need to touch rerecast to update it π
@mellow mirage I'm using your branch and everything related to it works, but...
The API seems easiest to use in my case by scoping the archipelago and island to my level, since another level would presumably want a different archipelago + island.
Trouble is that when the level is reloaded, landmass kinda doesn't use the island? This is not new to your branch, this happened before. I just ignored it because I manually updated the island as necessary instead of scoping it to the state.
As you can see, the island and archipelago are present in the world when the level is reloaded 
Here's the relevant code: https://github.com/janhohenheim/foxtrot/pull/426
If I hack the system with a Local<bool> to only spawn the archipelago / island once and don't state-scope them, it works, FYI
Is there something I have missed that is needed to "properly" despawn an archipelago / island?
Or am I supposed to never ever despawn the archipelago and just mutate when spawning a new level?
Ooof this is definitely not intentional
You should totally be free to spawn a new archipelago and island
Oh dang, maybe it's because I've consumed the navmesh to create the landmass version, but then since we drop the landmass handle but NOT the rerecast handle, it never reloads
I think this is just an issue with landmass_rerecast
Oh I bet this also breaks if you use the rerecast mesh in two islands and then drop one lol
I had something similar even when I was building the landmass navmesh manually on main, so I'm not sure
Could be unrelated though
Landmass doesn't use any resources iirc so if you're deleting the entities, all that state should go with it. The only exception are the navmesh assets
yeah I checked the source I don't know what it could be either
Whoops I take it back
This bug doesn't happen when using just bevy_landmass
I had it happen with the old oxi_nav code (according to my comments)
maybe that helps π
Huh ok. Maybe my oxi nav integration was also broken? Lol
Well most Bevy games are not on the scope of "multiple levels", so it makes sense no one noticed π
Please pull and retry! Should be fixed now π
I haven'
t gotten to your feedback on the PR yet and I need to leave for a bit but I will get that done tonight
yeeeesssss it works πππ
thanks for looking into it!
Thanks for testing it! Nice to finally have a full navigation stack haha
Greet job π π π
At the end of slope, agent not work, say AgentNotOnNavMesh. Do I need to upgrade bevy_landmass to github main branch?
Your agent should be positioned at the feet, or alternatively change the PointSampleDistance3d to change the distance above and distance below
I might have those values set too strict
Options that apply to all agents
thanks, adjust PointSampleDistance3d make it works.
And another question, has some way to block left slope navigation one side on ground to top?
Uhhh I'm sorry I am not understanding your question π
Are you asking how to prevent the navigation mesh from being created on the left slope?
Yes,
Question 1: How can I prevent the navigation mesh from being created on the left slope? Should I use an invisible mesh?
Question 2: Is it possible to create a navigation mesh that prevents an agent from going through the left slope when it is on the ground, but allows the agent to go through the same slope when it is on top of the platform?
- I think you can tinker with some of the nav mesh settings in rerecast. walkable_slope_angle and walkable_climb might help, and maybe cell_size and cell_height could be used so the voxelization can better represent your geometry (I would start with the first two though)
- Unfortunately there's no way to do this right now. This is known as off-mesh links https://github.com/andriyDev/landmass/issues/7 . It is something I want to implement eventually
I was hoping to crush this out this past weekend, but I've been working on animation links aka off mesh links.
I've got a bunch of the pieces ready (for raw landmass). I mainly just need to figure out how to assign the portal of an animation link to the nodes in the navigation mesh. The other thing I need to decide on is the API for when the user should take an animation link, when they're *taking" a link, and when they're done taking a link. But that's all stuff I can change easily later.
Exciting!!!
Ugh annoyed... I can't figure out how to assign the portal of the animation link. Projecting an edge onto a node is hard...
So I'm gonna cheat and only support animation links between points
I really wanted to have animation links for an entire edge so the agent could dynamically pick where along the edge they run the animation...
The really sad part is that means that agents could get "locked in" to using a link, resulting in a crowd fighting over taking a single animation link and not willing to repath
Maybe Detour has something you could use as inspiration?
It looks like Detour also only does point-to-point animation links https://recastnav.com/structdtOffMeshConnection.html
Ah heck
huhhh now I think I'm going crazy. Unity also only seems to have point-to-point...
I swear there was a navigation system with edge-to-edge...
I guess I'm gaslighting myself?
Welp that makes this much easier to reach parity with these engines...
The Unity Manual helps you learn and use the Unity engine. With the Unity engine you can create 2D and 3D games, apps and experiences.
Just to give an update, I've got the links all generated - both point and edge links! So the biggest question marks are handled.
Now I just need to figure out some API details with how to actually communicate that you need to take a link somewhere on a path, and we should be good to go!
The other API question I don't know how to handle is how to let users specify the allowed vertical distance between the animation link and the nav mesh, since obviously that option doesn't make sense for 2d.
I might just rename AgentOptions to ArchipelagoOptions there and then stick this in with PointSampleDistance... Kinda ugly but whatever
As an aside, in the future I want to separate all the coordinate system conversion stuff from the core landmass stuff. So there'd be a CoreArchipelago that would just be all the data in the standard landmass coordinate system, and then Archipelago<CS> would be a wrapper around the core archipelago. That would also help some weirdness happening in bevy_landmass, which could reimplement its own interface directly on top of CoreArchipelago which would store more stuff in the ECS I think.
And it would help compile times since very little would be generic!
And landmass internal tests would be easier to write lol
But that comes after animation links
Alright, I'm finally at a state where landmass is pretty much done. There are some pieces I have skipped because I'm lazy, like that ArchipelagoOptions change, configuring which link types an agent is allowed to take, and maybe also bidirectional animation links. But before all that I'm gonna update bevy_landmass to expose them, and then make a (3d) example for them so I can see it for real.
If I'm intensely lucky, all my unit testing actually results in real expected behavior haha
Oh wow that is huge π congrats!
woo congrats I've been following your project
@mellow mirage any idea why my friend here is slowing down when close to the wall?
I use the same radius for the navmesh, the collider, and the agent settings
This is using landmass main FYI
Increasing the radius of the character for the navmesh and the agent settings seems to help a bit?
Something looks kinda weird there, why do they give such a wide berth to the corners?
You mean the navmesh?
That's just an artifact of the cell resolution
this is with a higher resolution
No I'm talking about the corners of the navmesh
That's also just a setting
They're normally supposed to walk along the edges of the nav mesh
But your agent looks like it's offset from them or something
Maybe the collider is colliding with the wall?
Let me increase the agent radius by a lot for the navmesh
Could you also reduce their speed?
Just so I can see in finer detail lol
Though I guess this could be a high speed problem
how he's wiggling π
This is the setup:
commands.spawn((
Name::new("NPC Agent"),
Transform::from_translation(Vec3::new(0.0, -NPC_FLOAT_HEIGHT, 0.0)),
Agent3dBundle {
agent: default(),
settings: AgentSettings {
radius: NPC_RADIUS,
desired_speed: 5.0,
max_speed: 7.0,
},
archipelago_ref: ArchipelagoRef3d::new(*archipelago),
},
ChildOf(npc),
AgentOf(npc),
AgentTarget3d::default(),
));
it's not much code
Yeah been looking at that
Yes please, but with the nav mesh radius turned back down to the original
I am also building it locally so I have more control lol
do a git pull now
made the navmesh the correct size again
here's a slower controller
Hmmm hard to see this problem now. I guess it's only a high speed problem...
it's more visible in a maze
For some reason it's directional
Maybe that's just because of the angles though...
Definitely not a high speed problem though
aah you mean because the navmesh doesn't have 90 deg angles there?
As in the path from the bottom right to the top left has the "next edge" at a shaper angle than the path from the top left to the bottom right
let me know if there's anything I can do to help debug this
I think for foxtrot I told you to normalize the desired velocity
Which was a hacky fix to this
Oh really? I completely forgot about that
You mean here?
fn set_controller_velocity(
mut agent_query: Query<(&mut TnuaController, &Agent)>,
desired_velocity_query: Query<&AgentDesiredVelocity3d>,
) {
for (mut controller, agent) in &mut agent_query {
let Ok(desired_velocity) = desired_velocity_query.get(**agent) else {
continue;
};
let velocity = desired_velocity.velocity();
let forward = Dir3::try_from(velocity).ok();
controller.basis(TnuaBuiltinWalk {
desired_velocity: velocity,
desired_forward: forward,
float_height: NPC_FLOAT_HEIGHT,
..default()
});
}
}
that would break the speedup to evade others, right?
thanks for the tip, that hack works
Ok I think I have a solution. I think I've been overcomplicating it, and I can implement it quickly
Oh maybe not hmmm it would help, but it wouldnt' solve it I think. Let me keep thinking
here's a running dude to help thinking
look at him go
Not a single worry on his mind
I don't understand... I can't reproduce this behaviour in a test env. I've tried reproing it in dodgy, landmass, and bevy_landmass, and they all produce the expected result.
The only thing I can think of left is it has something to do with a non-constant time in Bevy, but that seems crazy...
One thing that's really strange is I need to negate the Z coordinates in thief_sense_demo but not in my bevy_landmass test...
Ah turns out that was just a change in my test. Fixed that but still can't reproduce the weird behavior in the thief demo
Hmm weird, considering itβs a pretty simple setup 
Is it maybe connected to the fact that I do the movement in fixed update?
Perhaps?
Let me see if I can extract that info
That really shouldn't matter though. I think the worst case is that a couple frames get the same velocity, which should just result in the same desired velocity
Oh hmmm I guess I don't know how to get that info...
Get which info?
Ah nvm, I changed your thief example to do movement (both avian and tnua) in PreUpdate and it's still broken
WAIT
I think I know what's happening lol
sync_agent_velocity isn't running, since no entity has LandmassVelocity and AgentDesiredVelocity
@sleek scarab Crispppp
I gaslit myself into thinking this was an issue in landmass lol
Oh hecccccc sorry for the user error
Beautiful, thank you so much
Maybe that could go into an FAQ?
Hahaha npnp
Yeah that's a good idea. Just having a bunch of debugging tips like "check the agent state" is very useful
Or maybe there could be a validation that the velocity is updated every now and then
Yeah I was just thinking about adding a debug check for when the position is moving but the velocity isn't lol. Might have too many false positives though? Unclear
We could add it and remove it again it people complain
Also should probably be a setting in a resource that defaults to true, so people can deactivate it
I'll think about it. I guess doing it for just bevy_landmass is reasonable, though a little weird
As an aside, just migrated bevy_landmass to 0.17. Took 5m lol. Not surprised!
I'll need to wait for rerecast to be migrated anyway, but the main bottleneck there is probably waiting on avian
TIL the rerecast editor doesn't use egui and actually uses bevy_ui π€―
I really need to push to finish off mesh links. I really want them in the 0.17 release, and I'd rather have one big version rather than two smaller releases.
I want beeeg release notes >:)
Not really, the avian integration is intentionally a separate crate π the only bottleneck is my time haha
I'll port it tomorrow
Yeah that can upgraded right away, and can then finally use bevy_feathers! 
Hehehe
TAKE YOUR TIME NO PRESSURE hurriedly gets back to working on off mesh links
phahahaha alright
Also need to migrate Yarn Spinner
The rest is trivial in comparison
Oooh and bevy_new_2d also wants feathers integration 
so we don't forget
I started migrating Avian yesterday, hopefully will have a PR ready later today or tomorrow
(just got sick though so I'm feeling a bit run down, but it's getting better)
Shocking nobody, I've found a panic lol
Thankfully it was a simple fix. Hopefully it fixed it permanently lol
I think I'm down to one thing left for animation links - I just need to provide a way to set the vertical distance allowed for animation links to their polygons.
And just like that, we're done
Now that's a PR
Weeeee!
Oh wow haha
Now go get your ladders π
This opens up a question: how do I specify the mesh links as a designer?
The original recast editor allows just clicking somewhere to create them
But adding that to the rerecast editor would tie it to landmass
But I like the idea of other pathfinding crates also being able to use it
Maybe I could write some metadata somewhere?
Thereβs a user-data field in the navmesh
Put IIRC itβs per polygon
So eeeh
I don't have strong opinions here. Rerecast could also write a whole new file for the off mesh links, and then define its own notion of an animation link, then parse that in landmass_rerecast
I'm open to that
how does the original recast editor saves them?
@fast pawn I was just about to ping you π
Whew no clue
well then do the same π
Yeah good idea
The original editor is tied to a pathfinding lib
Detour
But I can just treat that as "hereβs data any pathfinding lib could use if they wanted"
yup, then the parser are easy enough to write for each lib
either follow the same format as recast for something already explored, or create your own
I'll check out how they do it
Thanks π
Does vleue_navigator have off mesh links?
not yet, but mostly because I had no idea how to create them without a mess in code π
and that blocked me from writing the impl, but (I think) I have all the building blocks already
if rerecast gives me link definitions I'll add them π
A lot of my time implementing was spent trying to take the link definitions and actually find where they projected on the nav mesh lol, especially since hand placed links are more likely to be vertically offset from the nav mesh π
@mellow mirage rerecast migration is done FYI
I'm currently replacing the editor UI with upstream feathers
But the functionality is ported π
Awesome, I'll update my 0.17 branch to use updated rerecast
Upgraded landmass_rerecast to 0.17 too π
heck yeah! thanks!
I'll do an RC release once I get this editor wrangled
progress:
Oooooh nice!
Do you have a before screenshot?
Ah that's just this
Looks cleaner!
We love πͺΆπͺΆπͺΆ

done!
Alright, I'll fix some lints now and then release the RCs
I'm probably not gonna publish RC versions since I want to keep making changes until the release π
works for me π
published the RCs 
@mellow mirage mind pointing the rerecast dep to the RC instead of the git branch?
Reason: I just deleted that branch and now my build is failing because landmass is looking for it lol
Pushed
thanks!
Can confirm the landmass RC is working 
@sleek scarab you might have opinions here https://github.com/andriyDev/landmass/issues/159
https://github.com/andriyDev/landmass/blob/0e3680e29ea0020966177955ede8a5e931918367/crates/landmass_rerecast/src/lib.rs#L219C73-L220C1 for rerecast_id in changed_rerecast_ids { let Some(landmass_id...
Didnβt read it fully, but doesn't this mean that asset hot reloading doesnβt work?
Like, when I overwrite my navmesh on disk using the editor
Will landmass pick up on that?
I thought it did
I'm pretty sure it will! The asset system doesn't care whether the asset exists, it just sees "this path changed and this handle refers to this path"
Ah, neat!
This would also be broken for render assets only on the GPU if it were broken
Was really questioning my memory for a second
Like, I could have sworn it worked haha
Well that wouldnβt surprise me, GPU assets are usually broken in general
I tried making as many of my assets GPU-only as possible
Result: nothing
Not a single one is safe to be made GPU-only in practice

I think thatβs fine then?
Need to think this through
They all need to be used on the CPU? That's surprising...
But I donβt see an immediate issue
I guess my main question is how much you intend for people to use rerecast meshes directly
As opposed to other crates turning them into their own representations
(like landmass now)
Yeah. Meshes are needed to generate colliders and fixed skinned AABBs, UI images need donβt render when GPU-only, textures run into weird race conditions when combining different render features
Render folks say yeah, GPU-only is not tested that well outside of very simple scenarios
Dang that sucks
Uuuuh good question. I only assume that I can keep the handle, so that APIs like regenerate work. I believe even C++ Detour wraps the C++ recast navmesh in a custom representation, so I would say that is probably the usual path?