From 10e8f3698b8c5a8900e2ddf755fd8f503dbd9400 Mon Sep 17 00:00:00 2001
From: smix8 <52464204+smix8@users.noreply.github.com>
Date: Sun, 3 Dec 2023 18:27:17 +0100
Subject: [PATCH] Auto-bake edited NavigationPolygons in the Editor on a timer
Auto-bakes edited NavigationPolygons in the Editor on a timer.
---
doc/classes/EditorSettings.xml | 3 +
editor/editor_settings.cpp | 1 +
.../navigation_polygon_editor_plugin.cpp | 62 ++++++++++++++++++-
.../navigation_polygon_editor_plugin.h | 4 ++
4 files changed, 69 insertions(+), 1 deletion(-)
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 0e4dcacc56c..dd0522e091c 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -429,6 +429,9 @@
If [code]true[/code], warps the mouse around the 2D viewport while panning in the 2D editor. This makes it possible to pan over a large area without having to exit panning and adjust the mouse cursor.
+
+ The delay in seconds until more complex and performance costly polygon editors commit their outlines, e.g. the 2D navigation polygon editor rebakes the navigation mesh polygons. A negative value stops the auto bake.
+
The radius in which points can be selected in the [Polygon2D] and [CollisionPolygon2D] editors (in pixels). Higher values make it easier to select points quickly, but can make it more difficult to select the expected point when several points are located close to each other.
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 199fa3f6c91..d76f55564bf 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -756,6 +756,7 @@ void EditorSettings::_load_defaults(Ref p_extra_config) {
// Polygon editor
_initial_set("editors/polygon_editor/point_grab_radius", has_touchscreen_ui ? 32 : 8);
_initial_set("editors/polygon_editor/show_previous_outline", true);
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/polygon_editor/auto_bake_delay", 1.5, "-1.0,10.0,0.01");
// Animation
_initial_set("editors/animation/autorename_animation_tracks", true);
diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp
index 48335f3b948..04133072be8 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.cpp
+++ b/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "navigation_polygon_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/navigation_region_2d.h"
#include "scene/gui/dialogs.h"
@@ -50,6 +51,13 @@ Node2D *NavigationPolygonEditor::_get_node() const {
void NavigationPolygonEditor::_set_node(Node *p_polygon) {
node = Object::cast_to(p_polygon);
+ if (node) {
+ Ref navpoly = node->get_navigation_polygon();
+ if (navpoly.is_valid() && navpoly->get_outline_count() > 0 && navpoly->get_polygon_count() == 0) {
+ // We have outlines drawn / added by the user but no polygons were created for this navmesh yet so let's bake once immediately.
+ _rebake_timer_timeout();
+ }
+ }
}
int NavigationPolygonEditor::_get_polygon_count() const {
@@ -73,6 +81,10 @@ Variant NavigationPolygonEditor::_get_polygon(int p_idx) const {
void NavigationPolygonEditor::_set_polygon(int p_idx, const Variant &p_polygon) const {
Ref navpoly = _ensure_navpoly();
navpoly->set_outline(p_idx, p_polygon);
+
+ if (rebake_timer && _rebake_timer_delay >= 0.0) {
+ rebake_timer->start();
+ }
}
void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
@@ -80,6 +92,10 @@ void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "add_outline", p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "remove_outline", navpoly->get_outline_count());
+
+ if (rebake_timer && _rebake_timer_delay >= 0.0) {
+ rebake_timer->start();
+ }
}
void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
@@ -87,6 +103,10 @@ void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "remove_outline", p_idx);
undo_redo->add_undo_method(navpoly.ptr(), "add_outline_at_index", navpoly->get_outline(p_idx), p_idx);
+
+ if (rebake_timer && _rebake_timer_delay >= 0.0) {
+ rebake_timer->start();
+ }
}
void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
@@ -94,6 +114,10 @@ void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_pr
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "set_outline", p_idx, p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "set_outline", p_idx, p_previous);
+
+ if (rebake_timer && _rebake_timer_delay >= 0.0) {
+ rebake_timer->start();
+ }
}
bool NavigationPolygonEditor::_has_resource() const {
@@ -136,6 +160,15 @@ NavigationPolygonEditor::NavigationPolygonEditor() {
bake_info = memnew(Label);
bake_hbox->add_child(bake_info);
+ rebake_timer = memnew(Timer);
+ add_child(rebake_timer);
+ rebake_timer->set_one_shot(true);
+ _rebake_timer_delay = EDITOR_GET("editors/polygon_editor/auto_bake_delay");
+ if (_rebake_timer_delay >= 0.0) {
+ rebake_timer->set_wait_time(_rebake_timer_delay);
+ }
+ rebake_timer->connect("timeout", callable_mp(this, &NavigationPolygonEditor::_rebake_timer_timeout));
+
err_dialog = memnew(AcceptDialog);
add_child(err_dialog);
node = nullptr;
@@ -147,15 +180,26 @@ void NavigationPolygonEditor::_notification(int p_what) {
button_bake->set_icon(get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
button_reset->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
} break;
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ if (rebake_timer) {
+ _rebake_timer_delay = EDITOR_GET("editors/polygon_editor/auto_bake_delay");
+ if (_rebake_timer_delay >= 0.0) {
+ rebake_timer->set_wait_time(_rebake_timer_delay);
+ }
+ }
+ } break;
}
}
void NavigationPolygonEditor::_bake_pressed() {
+ if (rebake_timer) {
+ rebake_timer->stop();
+ }
button_bake->set_pressed(false);
ERR_FAIL_NULL(node);
Ref navigation_polygon = node->get_navigation_polygon();
- if (!navigation_polygon.is_valid()) {
+ if (navigation_polygon.is_null()) {
err_dialog->set_text(TTR("A NavigationPolygon resource must be set or created for this node to work."));
err_dialog->popup_centered();
return;
@@ -167,6 +211,9 @@ void NavigationPolygonEditor::_bake_pressed() {
}
void NavigationPolygonEditor::_clear_pressed() {
+ if (rebake_timer) {
+ rebake_timer->stop();
+ }
if (node) {
if (node->get_navigation_polygon().is_valid()) {
node->get_navigation_polygon()->clear();
@@ -193,6 +240,19 @@ void NavigationPolygonEditor::_update_polygon_editing_state() {
}
}
+void NavigationPolygonEditor::_rebake_timer_timeout() {
+ if (!node) {
+ return;
+ }
+ Ref navigation_polygon = node->get_navigation_polygon();
+ if (!navigation_polygon.is_valid()) {
+ return;
+ }
+
+ node->bake_navigation_polygon(true);
+ node->queue_redraw();
+}
+
NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin() :
AbstractPolygon2DEditorPlugin(memnew(NavigationPolygonEditor), "NavigationRegion2D") {
}
diff --git a/editor/plugins/navigation_polygon_editor_plugin.h b/editor/plugins/navigation_polygon_editor_plugin.h
index f1d0cd87517..bf2474bc55f 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.h
+++ b/editor/plugins/navigation_polygon_editor_plugin.h
@@ -56,6 +56,10 @@ class NavigationPolygonEditor : public AbstractPolygon2DEditor {
Button *button_reset = nullptr;
Label *bake_info = nullptr;
+ Timer *rebake_timer = nullptr;
+ float _rebake_timer_delay = 1.5;
+ void _rebake_timer_timeout();
+
void _bake_pressed();
void _clear_pressed();