Portals - Remove node naming restrictions
The use of special prefixes is only actually required during the import phase - the first conversion of rooms, roomgroups, and portals from Spatials and MeshInstances (based on the workflow of importing from blender). Once converted to the native Godot nodes there is no longer a need for the naming requirements. This PR removes the requirements except for the import. Manual portal linking after the initial conversion is now done exclusively using the `linked_room` nodepath property of the Portal.
This commit is contained in:
parent
4542e3382b
commit
8c4c6a93b0
|
@ -145,6 +145,7 @@ void Portal::clear() {
|
|||
_internal = false;
|
||||
_linkedroom_ID[0] = -1;
|
||||
_linkedroom_ID[1] = -1;
|
||||
_importing_portal = false;
|
||||
}
|
||||
|
||||
void Portal::_notification(int p_what) {
|
||||
|
@ -279,34 +280,14 @@ bool Portal::try_set_unique_name(const String &p_name) {
|
|||
void Portal::set_linked_room(const NodePath &link_path) {
|
||||
_settings_path_linkedroom = link_path;
|
||||
|
||||
// change the name of the portal as well, if the link looks legit
|
||||
// see if the link looks legit
|
||||
Room *linkedroom = nullptr;
|
||||
if (has_node(link_path)) {
|
||||
linkedroom = Object::cast_to<Room>(get_node(link_path));
|
||||
|
||||
if (linkedroom) {
|
||||
if (linkedroom != get_parent()) {
|
||||
_settings_path_linkedroom = link_path;
|
||||
|
||||
// change the portal name
|
||||
String string_link_room = RoomManager::_find_name_after(linkedroom, "Room");
|
||||
|
||||
// we need a unique name for the portal
|
||||
String string_name_base = "Portal" + GODOT_PORTAL_DELINEATOR + string_link_room;
|
||||
if (!try_set_unique_name(string_name_base)) {
|
||||
bool success = false;
|
||||
for (int n = 0; n < 128; n++) {
|
||||
String string_name = string_name_base + GODOT_PORTAL_WILDCARD + itos(n);
|
||||
if (try_set_unique_name(string_name)) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
WARN_PRINT("Could not set portal name, suggest setting name manually instead.");
|
||||
}
|
||||
}
|
||||
// was ok
|
||||
} else {
|
||||
WARN_PRINT("Linked room cannot be the parent room of a portal.");
|
||||
}
|
||||
|
|
|
@ -154,6 +154,13 @@ private:
|
|||
real_t _margin;
|
||||
bool _use_default_margin;
|
||||
|
||||
// during conversion, we need to know
|
||||
// whether this portal is being imported from a mesh
|
||||
// and is using an explicitly named link room with prefix.
|
||||
// If this is not the case, and it is already a Godot Portal node,
|
||||
// we will either use the assigned nodepath, or autolink.
|
||||
bool _importing_portal = false;
|
||||
|
||||
// for editing
|
||||
#ifdef TOOLS_ENABLED
|
||||
ObjectID _room_manager_godot_ID;
|
||||
|
|
|
@ -776,16 +776,34 @@ void RoomManager::_third_pass_rooms(const LocalVector<Portal *> &p_portals) {
|
|||
for (int n = 0; n < _rooms.size(); n++) {
|
||||
Room *room = _rooms[n];
|
||||
|
||||
String room_short_name = _find_name_after(room, "ROOM");
|
||||
convert_log("ROOM\t" + room_short_name);
|
||||
// no need to do all these string operations if we are not debugging and don't need logs
|
||||
if (_show_debug) {
|
||||
String room_short_name = _find_name_after(room, "Room", true);
|
||||
convert_log("ROOM\t" + room_short_name);
|
||||
|
||||
// log output the portals associated with this room
|
||||
for (int p = 0; p < room->_portals.size(); p++) {
|
||||
const Portal &portal = *p_portals[room->_portals[p]];
|
||||
// log output the portals associated with this room
|
||||
for (int p = 0; p < room->_portals.size(); p++) {
|
||||
const Portal &portal = *p_portals[room->_portals[p]];
|
||||
|
||||
String in_or_out = (portal._linkedroom_ID[0] == room->_room_ID) ? "POUT" : "PIN ";
|
||||
convert_log("\t\t" + in_or_out + "\t" + portal.get_name());
|
||||
}
|
||||
bool portal_links_out = portal._linkedroom_ID[0] == room->_room_ID;
|
||||
|
||||
int linked_room_id = (portal_links_out) ? portal._linkedroom_ID[1] : portal._linkedroom_ID[0];
|
||||
|
||||
// this shouldn't be out of range, but just in case
|
||||
if (linked_room_id < _rooms.size()) {
|
||||
Room *linked_room = _rooms[linked_room_id];
|
||||
|
||||
String portal_link_room_name = _find_name_after(linked_room, "Room", true);
|
||||
String in_or_out = (portal_links_out) ? "POUT" : "PIN ";
|
||||
|
||||
// display the name of the room linked to
|
||||
convert_log("\t\t" + in_or_out + "\t" + portal_link_room_name);
|
||||
} else {
|
||||
WARN_PRINT_ONCE("linked_room_id is out of range");
|
||||
}
|
||||
}
|
||||
|
||||
} // if _show_debug
|
||||
|
||||
// do a second pass finding the statics, where they are
|
||||
// finally added to the rooms in the portal_renderer.
|
||||
|
@ -808,21 +826,26 @@ void RoomManager::_third_pass_rooms(const LocalVector<Portal *> &p_portals) {
|
|||
}
|
||||
|
||||
void RoomManager::_second_pass_portals(Spatial *p_roomlist, LocalVector<Portal *> &r_portals) {
|
||||
convert_log("_second_pass_portals");
|
||||
|
||||
for (unsigned int n = 0; n < r_portals.size(); n++) {
|
||||
Portal *portal = r_portals[n];
|
||||
String string_link_room_shortname = _find_name_after(portal, "Portal");
|
||||
String string_link_room = "Room" + GODOT_PORTAL_DELINEATOR + string_link_room_shortname;
|
||||
|
||||
if (string_link_room_shortname != "") {
|
||||
Room *linked_room = Object::cast_to<Room>(p_roomlist->find_node(string_link_room, true, false));
|
||||
if (linked_room) {
|
||||
NodePath path = portal->get_path_to(linked_room);
|
||||
portal->set_linked_room_internal(path);
|
||||
} else {
|
||||
WARN_PRINT("Portal link room : " + string_link_room + " not found.");
|
||||
_warning_portal_link_room_not_found = true;
|
||||
// we have a choice here.
|
||||
// If we are importing, we will try linking using the naming convention method.
|
||||
// We do this by setting the assigned nodepath if we find the link room, then
|
||||
// the resolving links is done in the usual manner from the nodepath.
|
||||
if (portal->_importing_portal) {
|
||||
String string_link_room_shortname = _find_name_after(portal, "Portal");
|
||||
String string_link_room = "Room" + GODOT_PORTAL_DELINEATOR + string_link_room_shortname;
|
||||
|
||||
if (string_link_room_shortname != "") {
|
||||
Room *linked_room = Object::cast_to<Room>(p_roomlist->find_node(string_link_room, true, false));
|
||||
if (linked_room) {
|
||||
NodePath path = portal->get_path_to(linked_room);
|
||||
portal->set_linked_room_internal(path);
|
||||
} else {
|
||||
WARN_PRINT("Portal link room : " + string_link_room + " not found.");
|
||||
_warning_portal_link_room_not_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -849,8 +872,6 @@ void RoomManager::_second_pass_portals(Spatial *p_roomlist, LocalVector<Portal *
|
|||
}
|
||||
|
||||
void RoomManager::_autolink_portals(Spatial *p_roomlist, LocalVector<Portal *> &r_portals) {
|
||||
convert_log("_autolink_portals");
|
||||
|
||||
for (unsigned int n = 0; n < r_portals.size(); n++) {
|
||||
Portal *portal = r_portals[n];
|
||||
|
||||
|
@ -958,12 +979,12 @@ bool RoomManager::_check_roomlist_validity(Node *p_node) {
|
|||
|
||||
void RoomManager::_convert_rooms_recursive(Spatial *p_node, LocalVector<Portal *> &r_portals, LocalVector<RoomGroup *> &r_roomgroups, int p_roomgroup) {
|
||||
// is this a room?
|
||||
if (_name_starts_with(p_node, "Room") || _node_is_type<Room>(p_node)) {
|
||||
if (_node_is_type<Room>(p_node) || _name_starts_with(p_node, "Room")) {
|
||||
_convert_room(p_node, r_portals, r_roomgroups, p_roomgroup);
|
||||
}
|
||||
|
||||
// is this a roomgroup?
|
||||
if (_name_starts_with(p_node, "RoomGroup") || _node_is_type<RoomGroup>(p_node)) {
|
||||
if (_node_is_type<RoomGroup>(p_node) || _name_starts_with(p_node, "RoomGroup")) {
|
||||
p_roomgroup = _convert_roomgroup(p_node, r_roomgroups);
|
||||
}
|
||||
|
||||
|
@ -1570,12 +1591,16 @@ bool RoomManager::_add_plane_if_unique(const Room *p_room, LocalVector<Plane, in
|
|||
void RoomManager::_convert_portal(Room *p_room, Spatial *p_node, LocalVector<Portal *> &portals) {
|
||||
Portal *portal = Object::cast_to<Portal>(p_node);
|
||||
|
||||
bool importing = false;
|
||||
|
||||
// if not a gportal already, convert the node type
|
||||
if (!portal) {
|
||||
importing = true;
|
||||
portal = _change_node_type<Portal>(p_node, "G", false);
|
||||
portal->create_from_mesh_instance(Object::cast_to<MeshInstance>(p_node));
|
||||
|
||||
p_node->queue_delete();
|
||||
|
||||
} else {
|
||||
// only allow converting once
|
||||
if (portal->_conversion_tick == _conversion_tick) {
|
||||
|
@ -1586,6 +1611,10 @@ void RoomManager::_convert_portal(Room *p_room, Spatial *p_node, LocalVector<Por
|
|||
// make sure to start with fresh internal data each time (for linked rooms etc)
|
||||
portal->clear();
|
||||
|
||||
// mark the portal if we are importing, because we will need to use the naming
|
||||
// prefix system to look for linked rooms in that case
|
||||
portal->_importing_portal = importing;
|
||||
|
||||
// mark so as only to convert once
|
||||
portal->_conversion_tick = _conversion_tick;
|
||||
|
||||
|
@ -1976,12 +2005,29 @@ bool RoomManager::_name_starts_with(const Node *p_node, String p_search_string,
|
|||
return false;
|
||||
}
|
||||
|
||||
String RoomManager::_find_name_after(Node *p_node, String p_string_start) {
|
||||
p_string_start += GODOT_PORTAL_DELINEATOR;
|
||||
String RoomManager::_find_name_after(Node *p_node, String p_prefix, bool p_allow_no_prefix) {
|
||||
ERR_FAIL_NULL_V(p_node, String());
|
||||
|
||||
p_prefix += GODOT_PORTAL_DELINEATOR;
|
||||
p_prefix = p_prefix.to_lower();
|
||||
int prefix_length = p_prefix.length();
|
||||
|
||||
String name = p_node->get_name();
|
||||
String name_start = name.substr(0, prefix_length).to_lower();
|
||||
|
||||
String string_result;
|
||||
String name = p_node->get_name();
|
||||
string_result = name.substr(p_string_start.length());
|
||||
|
||||
// is the prefix correct?
|
||||
if (p_prefix == name_start) {
|
||||
string_result = name.substr(prefix_length);
|
||||
} else {
|
||||
if (p_allow_no_prefix) {
|
||||
// there is no prefix, or the prefix is incorrect...
|
||||
// we will pass the whole name
|
||||
string_result = name;
|
||||
}
|
||||
// else we will return a null string
|
||||
}
|
||||
|
||||
// because godot doesn't support multiple nodes with the same name, we will strip e.g. a number
|
||||
// after an @ on the end of the name...
|
||||
|
|
|
@ -215,7 +215,7 @@ private:
|
|||
void debug_print_line(String p_string, int p_priority = 0);
|
||||
|
||||
public:
|
||||
static String _find_name_after(Node *p_node, String p_string_start);
|
||||
static String _find_name_after(Node *p_node, String p_prefix, bool p_allow_no_prefix = false);
|
||||
static void show_warning(const String &p_string, const String &p_extra_string = "", bool p_alert = true);
|
||||
static real_t _get_default_portal_margin() { return _default_portal_margin; }
|
||||
|
||||
|
|
Loading…
Reference in New Issue