From b663acef9368651146a51fad938da39931a20fda Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Wed, 14 Jul 2021 14:34:09 +0100 Subject: [PATCH] Portals - Add configuration warnings for nodes Checks for invalid children / grandchildren etc. --- scene/3d/portal.cpp | 32 +++++++++++++++++ scene/3d/portal.h | 2 ++ scene/3d/room.cpp | 34 ++++++++++++++++++ scene/3d/room.h | 35 ++++++++++++++++++ scene/3d/room_group.cpp | 13 +++++++ scene/3d/room_group.h | 2 ++ scene/3d/room_manager.cpp | 75 +++++++++++++++++++++++++++++++++++++-- scene/3d/room_manager.h | 11 +++--- 8 files changed, 196 insertions(+), 8 deletions(-) diff --git a/scene/3d/portal.cpp b/scene/3d/portal.cpp index 06643a7a3b..2eb7c05965 100644 --- a/scene/3d/portal.cpp +++ b/scene/3d/portal.cpp @@ -33,6 +33,7 @@ #include "core/engine.h" #include "mesh_instance.h" #include "room.h" +#include "room_group.h" #include "room_manager.h" #include "scene/main/viewport.h" #include "servers/visual_server.h" @@ -69,6 +70,37 @@ Portal::~Portal() { } } +String Portal::get_configuration_warning() const { + String warning = Spatial::get_configuration_warning(); + + auto lambda = [](const Node *p_node) { + return static_cast((Object::cast_to(p_node) || Object::cast_to(p_node) || Object::cast_to(p_node))); + }; + + if (Room::detect_nodes_using_lambda(this, lambda)) { + if (Room::detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The RoomManager should not be a child or grandchild of a Portal."); + } + if (Room::detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A Room should not be a child or grandchild of a Portal."); + } + if (Room::detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A RoomGroup should not be a child or grandchild of a Portal."); + } + } + + return warning; +} + void Portal::set_points(const PoolVector &p_points) { _pts_local_raw = p_points; _sanitize_points(); diff --git a/scene/3d/portal.h b/scene/3d/portal.h index 5bc9110408..2fbddae05d 100644 --- a/scene/3d/portal.h +++ b/scene/3d/portal.h @@ -79,6 +79,8 @@ public: void set_points(const PoolVector &p_points); PoolVector get_points() const; + String get_configuration_warning() const; + Portal(); ~Portal(); diff --git a/scene/3d/room.cpp b/scene/3d/room.cpp index 815aebead3..463b1bc569 100644 --- a/scene/3d/room.cpp +++ b/scene/3d/room.cpp @@ -31,6 +31,7 @@ #include "room.h" #include "portal.h" +#include "room_group.h" #include "room_manager.h" #include "servers/visual_server.h" @@ -180,6 +181,39 @@ PoolVector Room::generate_points() { return pts_returned; } +String Room::get_configuration_warning() const { + String warning = Spatial::get_configuration_warning(); + + auto lambda = [](const Node *p_node) { + return static_cast((Object::cast_to(p_node) || Object::cast_to(p_node) || Object::cast_to(p_node))); + }; + + if (detect_nodes_using_lambda(this, lambda)) { + if (detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A Room cannot have another Room as a child or grandchild."); + } + + if (detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The RoomManager should not be placed inside a Room."); + } + + if (detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("A RoomGroup should not be placed inside a Room."); + } + } + + return warning; +} + // extra editor links to the room manager to allow unloading // on change, or re-converting void Room::_changed(bool p_regenerate_bounds) { diff --git a/scene/3d/room.h b/scene/3d/room.h index c553668bf8..e8065a6c87 100644 --- a/scene/3d/room.h +++ b/scene/3d/room.h @@ -74,9 +74,15 @@ public: // editor only PoolVector generate_points(); + String get_configuration_warning() const; + private: void clear(); void _changed(bool p_regenerate_bounds = false); + template + static bool detect_nodes_of_type(const Node *p_node, bool p_ignore_first_node = true); + template + static bool detect_nodes_using_lambda(const Node *p_node, T p_lambda, bool p_ignore_first_node = true); // planes forming convex hull of room LocalVector _planes; @@ -128,4 +134,33 @@ protected: void _notification(int p_what); }; +template +bool Room::detect_nodes_of_type(const Node *p_node, bool p_ignore_first_node) { + if (Object::cast_to(p_node) && (!p_ignore_first_node)) { + return true; + } + + for (int n = 0; n < p_node->get_child_count(); n++) { + if (detect_nodes_of_type(p_node->get_child(n), false)) { + return true; + } + } + + return false; +} + +template +bool Room::detect_nodes_using_lambda(const Node *p_node, T p_lambda, bool p_ignore_first_node) { + if (p_lambda(p_node) && !p_ignore_first_node) { + return true; + } + + for (int n = 0; n < p_node->get_child_count(); n++) { + if (detect_nodes_using_lambda(p_node->get_child(n), p_lambda, false)) { + return true; + } + } + return false; +} + #endif diff --git a/scene/3d/room_group.cpp b/scene/3d/room_group.cpp index e2b2184e1d..ec33d713a7 100644 --- a/scene/3d/room_group.cpp +++ b/scene/3d/room_group.cpp @@ -50,6 +50,19 @@ RoomGroup::~RoomGroup() { } } +String RoomGroup::get_configuration_warning() const { + String warning = Spatial::get_configuration_warning(); + + if (Room::detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The RoomManager should not be placed inside a RoomGroup."); + } + + return warning; +} + void RoomGroup::clear() { _roomgroup_ID = -1; } diff --git a/scene/3d/room_group.h b/scene/3d/room_group.h index 6bcc51a7a0..a3d398a9dc 100644 --- a/scene/3d/room_group.h +++ b/scene/3d/room_group.h @@ -55,6 +55,8 @@ public: } int get_roomgroup_priority() const { return _settings_priority; } + String get_configuration_warning() const; + private: void clear(); void _changed(); diff --git a/scene/3d/room_manager.cpp b/scene/3d/room_manager.cpp index 3f95d32c45..9742333c3b 100644 --- a/scene/3d/room_manager.cpp +++ b/scene/3d/room_manager.cpp @@ -71,6 +71,69 @@ RoomManager::~RoomManager() { active_room_manager = nullptr; #endif } + +String RoomManager::get_configuration_warning() const { + String warning = Spatial::get_configuration_warning(); + + if (_settings_path_roomlist == NodePath()) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The RoomList has not been assigned."); + } else { + Spatial *roomlist = _resolve_path(_settings_path_roomlist); + if (!roomlist || (roomlist->get_class_name() != StringName("Spatial"))) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("The RoomList should be a Spatial."); + } + } + + if (_settings_portal_depth_limit == 0) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("Portal Depth Limit is set to Zero.\nOnly the Room that the Camera is in will render."); + } + + auto lambda = [](const Node *p_node) { + return static_cast((Object::cast_to(p_node) || Object::cast_to(p_node) || Object::cast_to(p_node) || Object::cast_to(p_node))); + }; + + if (Room::detect_nodes_using_lambda(this, lambda)) { + if (Room::detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("Rooms should not be children of the RoomManager."); + } + + if (Room::detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("RoomGroups should not be children of the RoomManager."); + } + + if (Room::detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("Portals should not be children of the RoomManager."); + } + + if (Room::detect_nodes_of_type(this)) { + if (!warning.empty()) { + warning += "\n\n"; + } + warning += TTR("There should only be one RoomManager in the SceneTree."); + } + } + + return warning; +} + void RoomManager::_preview_camera_update() { Ref world = get_world(); RID scenario = world->get_scenario(); @@ -176,6 +239,9 @@ void RoomManager::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pvs_mode", "pvs_mode"), &RoomManager::set_pvs_mode); ClassDB::bind_method(D_METHOD("get_pvs_mode"), &RoomManager::get_pvs_mode); + ClassDB::bind_method(D_METHOD("set_roomlist_path", "p_path"), &RoomManager::set_roomlist_path); + ClassDB::bind_method(D_METHOD("get_roomlist_path"), &RoomManager::get_roomlist_path); + // These are commented out for now, but available in case we want to cache PVS to disk, the functionality exists // ClassDB::bind_method(D_METHOD("set_pvs_filename", "pvs_filename"), &RoomManager::set_pvs_filename); // ClassDB::bind_method(D_METHOD("get_pvs_filename"), &RoomManager::get_pvs_filename); @@ -196,7 +262,7 @@ void RoomManager::_bind_methods() { ADD_GROUP("Main", ""); LIMPL_PROPERTY(Variant::BOOL, active, rooms_set_active, rooms_get_active); - LIMPL_PROPERTY(Variant::NODE_PATH, roomlist, set_roomlist_path, get_roomlist_path); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "roomlist", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_roomlist_path", "get_roomlist_path"); ADD_GROUP("PVS", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "pvs_mode", PROPERTY_HINT_ENUM, "Disabled,Partial,Full"), "set_pvs_mode", "get_pvs_mode"); @@ -230,6 +296,11 @@ void RoomManager::_bind_methods() { #undef LPORTAL_TOSTRING } +void RoomManager::set_roomlist_path(const NodePath &p_path) { + _settings_path_roomlist = p_path; + update_configuration_warning(); +} + void RoomManager::set_preview_camera_path(const NodePath &p_path) { _settings_path_preview_camera = p_path; @@ -277,7 +348,7 @@ bool RoomManager::get_flip_portal_meshes() const { } void RoomManager::set_portal_depth_limit(int p_limit) { - _portal_depth_limit = p_limit; + _settings_portal_depth_limit = p_limit; if (is_inside_world() && get_world().is_valid()) { VisualServer::get_singleton()->rooms_set_params(get_world()->get_scenario(), p_limit); diff --git a/scene/3d/room_manager.h b/scene/3d/room_manager.h index 850d7889c5..d60cb63def 100644 --- a/scene/3d/room_manager.h +++ b/scene/3d/room_manager.h @@ -53,10 +53,7 @@ public: PVS_MODE_FULL, }; - void set_roomlist_path(const NodePath &p_path) { - _settings_path_roomlist = p_path; - } - + void set_roomlist_path(const NodePath &p_path); NodePath get_roomlist_path() const { return _settings_path_roomlist; } @@ -95,7 +92,7 @@ public: int get_overlap_warning_threshold() const { return (int)_overlap_warning_threshold; } void set_portal_depth_limit(int p_limit); - int get_portal_depth_limit() const { return _portal_depth_limit; } + int get_portal_depth_limit() const { return _settings_portal_depth_limit; } void set_flip_portal_meshes(bool p_flip); bool get_flip_portal_meshes() const; @@ -119,6 +116,8 @@ public: void rooms_clear(); void rooms_flip_portals(); + String get_configuration_warning() const; + // for internal use in the editor.. // either we can clear the rooms and unload, // or reconvert. @@ -253,7 +252,7 @@ private: real_t _default_portal_margin = 1.0; real_t _overlap_warning_threshold = 1.0; Room::SimplifyInfo _room_simplify_info; - int _portal_depth_limit = 16; + int _settings_portal_depth_limit = 16; // debug override camera ObjectID _godot_preview_camera_ID = -1;