Portals - Add configuration warnings for nodes
Checks for invalid children / grandchildren etc.
This commit is contained in:
parent
a3310c1da2
commit
b663acef93
8 changed files with 196 additions and 8 deletions
|
@ -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<bool>((Object::cast_to<RoomManager>(p_node) || Object::cast_to<Room>(p_node) || Object::cast_to<RoomGroup>(p_node)));
|
||||
};
|
||||
|
||||
if (Room::detect_nodes_using_lambda(this, lambda)) {
|
||||
if (Room::detect_nodes_of_type<RoomManager>(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<Room>(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<RoomGroup>(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<Vector2> &p_points) {
|
||||
_pts_local_raw = p_points;
|
||||
_sanitize_points();
|
||||
|
|
|
@ -79,6 +79,8 @@ public:
|
|||
void set_points(const PoolVector<Vector2> &p_points);
|
||||
PoolVector<Vector2> get_points() const;
|
||||
|
||||
String get_configuration_warning() const;
|
||||
|
||||
Portal();
|
||||
~Portal();
|
||||
|
||||
|
|
|
@ -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<Vector3> 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<bool>((Object::cast_to<Room>(p_node) || Object::cast_to<RoomManager>(p_node) || Object::cast_to<RoomGroup>(p_node)));
|
||||
};
|
||||
|
||||
if (detect_nodes_using_lambda(this, lambda)) {
|
||||
if (detect_nodes_of_type<Room>(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<RoomManager>(this)) {
|
||||
if (!warning.empty()) {
|
||||
warning += "\n\n";
|
||||
}
|
||||
warning += TTR("The RoomManager should not be placed inside a Room.");
|
||||
}
|
||||
|
||||
if (detect_nodes_of_type<RoomGroup>(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) {
|
||||
|
|
|
@ -74,9 +74,15 @@ public:
|
|||
// editor only
|
||||
PoolVector<Vector3> generate_points();
|
||||
|
||||
String get_configuration_warning() const;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
void _changed(bool p_regenerate_bounds = false);
|
||||
template <class T>
|
||||
static bool detect_nodes_of_type(const Node *p_node, bool p_ignore_first_node = true);
|
||||
template <typename T>
|
||||
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<Plane, int32_t> _planes;
|
||||
|
@ -128,4 +134,33 @@ protected:
|
|||
void _notification(int p_what);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool Room::detect_nodes_of_type(const Node *p_node, bool p_ignore_first_node) {
|
||||
if (Object::cast_to<T>(p_node) && (!p_ignore_first_node)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int n = 0; n < p_node->get_child_count(); n++) {
|
||||
if (detect_nodes_of_type<T>(p_node->get_child(n), false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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
|
||||
|
|
|
@ -50,6 +50,19 @@ RoomGroup::~RoomGroup() {
|
|||
}
|
||||
}
|
||||
|
||||
String RoomGroup::get_configuration_warning() const {
|
||||
String warning = Spatial::get_configuration_warning();
|
||||
|
||||
if (Room::detect_nodes_of_type<RoomManager>(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;
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@ public:
|
|||
}
|
||||
int get_roomgroup_priority() const { return _settings_priority; }
|
||||
|
||||
String get_configuration_warning() const;
|
||||
|
||||
private:
|
||||
void clear();
|
||||
void _changed();
|
||||
|
|
|
@ -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<Spatial>(_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<bool>((Object::cast_to<Room>(p_node) || Object::cast_to<RoomGroup>(p_node) || Object::cast_to<Portal>(p_node) || Object::cast_to<RoomManager>(p_node)));
|
||||
};
|
||||
|
||||
if (Room::detect_nodes_using_lambda(this, lambda)) {
|
||||
if (Room::detect_nodes_of_type<Room>(this)) {
|
||||
if (!warning.empty()) {
|
||||
warning += "\n\n";
|
||||
}
|
||||
warning += TTR("Rooms should not be children of the RoomManager.");
|
||||
}
|
||||
|
||||
if (Room::detect_nodes_of_type<RoomGroup>(this)) {
|
||||
if (!warning.empty()) {
|
||||
warning += "\n\n";
|
||||
}
|
||||
warning += TTR("RoomGroups should not be children of the RoomManager.");
|
||||
}
|
||||
|
||||
if (Room::detect_nodes_of_type<Portal>(this)) {
|
||||
if (!warning.empty()) {
|
||||
warning += "\n\n";
|
||||
}
|
||||
warning += TTR("Portals should not be children of the RoomManager.");
|
||||
}
|
||||
|
||||
if (Room::detect_nodes_of_type<RoomManager>(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> 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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue