godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.12k stars 69 forks source link

Make NavigationServer handle all navigation debug visuals #7208

Open smix8 opened 1 year ago

smix8 commented 1 year ago

Describe the project you are working on

Godot Navigation

Describe the problem or limitation you are having in your project

Historically Godot has (with the exception of rendering) placed most debug visuals as a task handled directly by the related nodes.

The proposal is about moving the entire navigation debug visuals from nodes to the servers as having the debug on nodes has multiple drawbacks.

While this proposal focuses on navigation a lot applies to physics as well so examples from physics are also included to make the problems more obvious.

Node debug requires the SceneTree

A major one is that most nodes need to be in the SceneTree to do anything useful or render their debug visuals. Server RIDs not attached to a node are simply ignored in debug.

This means every object a user creates with the server API does not show up in any debug but may still be active, just invisible. There is an endless amount of bug reports related to this where users are not aware that a server object exists that causes a "bug" because it is invisible in the debug.

An additional problem is that any change user do with the server API does not reflect in the node debug. The node is not aware of any server internal changes to the RID that it is using.

E.g. if you create a navigation mesh or collision object on the server, what do you see in debug? Nothing. What do you see when you change a RID from a node object with the server API? The wrong, old thing.

Node debug reality and server reality do often not match

Another problem is data clarity or that you see in debug what you get on the server.

Devs historically created debug visuals that "looked nice" instead of providing information that is in sync with the data reality on the server.

E.g. not too long ago the navigation mesh debug did not show the polygons, just a plain surface with outline. One of the most important informations to debug navigation issues was just missing from the debug.

E.g. TileMap shows collision debug as a perfectly crafted solid polygon ... while it is in fact the opposite when you look what ends up in the server, a splintered and inefficient, small polygons mess that cause endless collision seam problems.

Issues that could be easily identified with "real" debug take users a lot of research to even learn about what is going on and connect it to performance problems or bugs that they have in their projects.

Node debug is oblivious to the surroundings

The server has the complete picture, nodes do not.

E.g. the server knows what navigation meshes are connected with what and can visualize that. The server knows what parts had errors and can visualize that. The server knows what parts from the user input it had to modify and can visualize that.

A node is for the most part oblivious to all this information. It would require a lot of boilerplate API to provide a way to get this information back to the node debug.

In general nodes require more boilerplate for debug visuals because all the node specifics and SceneTree shenanigans need to be accounted for.

Nodes are not performant at scale

There is also the problem of performance on larger scenes. Updating so many single nodes individually is simply not efficient.

E.g. TileMaps already suffer a lot of performance issues on larger scenes when zoomed out just from the debug visuals because each single quadrant renders its own debug canvas item where each single debug element has its own visual polygon and polyline mix.

The server could make use of far more efficient ways to display debug e.g. use a MultiMesh to render all the objects that use the same data.

A node does not know necessarily its neighbor node, or that both use the same navigation mesh, so that the two could share the same debug mesh just with a different transform.

Editor gizmo debug is node focused and does not work at runtime

The 3D nodes have most debug visuals as part of their Editor only gizmos but those gizmos only exist in the Editor.

Navigation debug is very runtime centric so a lot of the visual debug requires code duplication on the nodes just for the runtime debug.

It is an unnecessary amount of code duplication that requires devs to keep both versions in sync when doing debug related changes.

A gizmo could just tell the node/server to display the debug visuals instead of doing its own, redundant thing.

Longterm ..

There are plans to keep only a single set of data inside the NavigationServer at runtime instead of keeping multiple copies of the same data on node / resource / server like it is now. This would mean that at this point the node debug would need to query large sets of data back from the server all the time to render debug which is not very efficient.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

See problem description.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

This is the general draft currently tested in a dev branch and subject to change:

In a first step the current debug visual code will migrate from the node types to the corresponding server objects.

E.g. the NavigationRegion node debug will move to the NavRegion server object. E.g. the NavigationAgent node debug will move to the NavAgent server object.

The only thing that stays on the node are the debug properties and functions so users can set them with the inspector / gizmo. Internally those property setters and functions will tell the server to update the debug visuals.

In the next step all the duplicated code parts of 3D gizmos will be removed. Instead, the gizmos will tell the server to show the corresponding debug visuals, e.g. when selected in the Editor.

In order to render debug visuals the NavigationServer needs access to the RenderingServer and visual scenarios.

Each navigation map will get the visual scenario RID injected to render its debug visuals. For the default navigation maps this will be the visual scenario RID from the World2D/3D. For custom navigation maps created by users the default could be used or unique visual scenarios created for each map.

It would be beneficial if the Editor debug menu receives options to select the debug to be displayed only for certain navigation map so the Viewport does not become too convoluted with debug visuals when multiple navigation maps are involved. This would require the NavigationServer to process to make this map information available for the Editor. This is not a problem for navigation because the NavigationServer already runs inside the Editor to display edge connections.

This change will create a new dependency that the NavigationServer has on the RenderingServer in debug builds because it is using rendering RIDs. Primarly this means that the NavigationServer needs to finalize before the RenderingServer does its last queue flush to free the debug RIDs. This requires that in the main.cpp the finalize_navigation_server() gets moved up in the cleanup() function before the last RenderingServer::get_singleton()->sync() call. This should not impose any problems as the NavigationServer is rather isolated from anything else in the engine and was already moved "up" in the chain. This was done before for the PhysicsServer for similar reasons e.g. because users had physics RIDs binded in the old agent callbacks.

If this enhancement will not be used often, can it be worked around with a few lines of script?

navigation debug is core

Is there a reason why this should be core and not an add-on in the asset library?

navigation debug is core

smix8 commented 10 months ago

Doing this for Godot 4.3 because I am going crazy with all the bugs caused by the node-based debug.