mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 07:53:26 +00:00
Add unique Node IDs to support base and instantiated scene refactorings
The main goal of this PR is to safeguard when a base or instantiated scene changes (nodes renamed, moved or readded), that the hierarchy is still maintained and the node and its overridden properties can be preserved. What it does: * Implements unique node IDs. * These IDs act as a fallback to names when saving. * The IDs are **USED AS A FALLBACK**, so they are just an addition. It should not break any current existing scene. * If a scene renames or moves a node, inherited or instantiated scenes will no longer lose reference to it. Unlike the previous approach, this one is intended to be a fallback, only used if the node is not found. This makes it safer to implement and ensure that, at worst case, we fail to find the node, but nothing breaks.
This commit is contained in:
parent
60b7b8b16e
commit
faddd60c40
6 changed files with 370 additions and 28 deletions
|
@ -351,6 +351,7 @@ void ResourceUID::clear() {
|
|||
unique_ids.clear();
|
||||
changed = false;
|
||||
}
|
||||
|
||||
void ResourceUID::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("id_to_text", "id"), &ResourceUID::id_to_text);
|
||||
ClassDB::bind_method(D_METHOD("text_to_id", "text_id"), &ResourceUID::text_to_id);
|
||||
|
|
|
@ -2082,6 +2082,14 @@ Node *Node::find_parent(const String &p_pattern) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void Node::set_unique_scene_id(int32_t p_unique_id) {
|
||||
data.unique_scene_id = p_unique_id;
|
||||
}
|
||||
|
||||
int32_t Node::get_unique_scene_id() const {
|
||||
return data.unique_scene_id;
|
||||
}
|
||||
|
||||
Window *Node::get_window() const {
|
||||
ERR_THREAD_GUARD_V(nullptr);
|
||||
Viewport *vp = get_viewport();
|
||||
|
|
|
@ -132,6 +132,9 @@ public:
|
|||
#ifdef DEBUG_ENABLED
|
||||
static SafeNumeric<uint64_t> total_node_count;
|
||||
#endif
|
||||
enum {
|
||||
UNIQUE_SCENE_ID_UNASSIGNED = 0
|
||||
};
|
||||
|
||||
void _update_process(bool p_enable, bool p_for_children);
|
||||
|
||||
|
@ -281,6 +284,8 @@ private:
|
|||
mutable bool is_translation_domain_inherited : 1;
|
||||
mutable bool is_translation_domain_dirty : 1;
|
||||
|
||||
int32_t unique_scene_id = UNIQUE_SCENE_ID_UNASSIGNED;
|
||||
|
||||
mutable NodePath *path_cache = nullptr;
|
||||
|
||||
} data;
|
||||
|
@ -527,6 +532,9 @@ public:
|
|||
Node *get_parent() const;
|
||||
Node *find_parent(const String &p_pattern) const;
|
||||
|
||||
void set_unique_scene_id(int32_t p_unique_id);
|
||||
int32_t get_unique_scene_id() const;
|
||||
|
||||
Window *get_window() const;
|
||||
Window *get_non_popup_window() const;
|
||||
Window *get_last_exclusive_window() const;
|
||||
|
|
|
@ -124,18 +124,38 @@ Ref<Resource> SceneState::get_remap_resource(const Ref<Resource> &p_resource, Ha
|
|||
return remap_resource;
|
||||
}
|
||||
|
||||
static Node *_find_node_by_id(Node *p_owner, Node *p_node, int32_t p_id) {
|
||||
if (p_owner == p_node || p_node->get_owner() == p_owner) {
|
||||
if (p_node->get_unique_scene_id() == p_id) {
|
||||
return p_node;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||
Node *found = _find_node_by_id(p_owner, p_node->get_child(i), p_id);
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node *SceneState::instantiate(GenEditState p_edit_state) const {
|
||||
// Nodes where instantiation failed (because something is missing.)
|
||||
List<Node *> stray_instances;
|
||||
|
||||
#define NODE_FROM_ID(p_name, p_id) \
|
||||
Node *p_name; \
|
||||
if (p_id & FLAG_ID_IS_PATH) { \
|
||||
NodePath np = node_paths[p_id & FLAG_MASK]; \
|
||||
p_name = ret_nodes[0]->get_node_or_null(np); \
|
||||
} else { \
|
||||
ERR_FAIL_INDEX_V(p_id & FLAG_MASK, nc, nullptr); \
|
||||
p_name = ret_nodes[p_id & FLAG_MASK]; \
|
||||
#define NODE_FROM_ID(p_name, p_id) \
|
||||
Node *p_name; \
|
||||
if (p_id & FLAG_ID_IS_PATH) { \
|
||||
NodePath np = node_paths[p_id & FLAG_MASK]; \
|
||||
p_name = ret_nodes[0]->get_node_or_null(np); \
|
||||
if (!p_name) { \
|
||||
p_name = _recover_node_path_index(ret_nodes[0], p_id & FLAG_MASK); \
|
||||
} \
|
||||
} else { \
|
||||
ERR_FAIL_INDEX_V(p_id & FLAG_MASK, nc, nullptr); \
|
||||
p_name = ret_nodes[p_id & FLAG_MASK]; \
|
||||
}
|
||||
|
||||
int nc = nodes.size();
|
||||
|
@ -165,6 +185,8 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
|
|||
|
||||
LocalVector<DeferredNodePathProperties> deferred_node_paths;
|
||||
|
||||
bool deep_search_warned = false;
|
||||
|
||||
for (int i = 0; i < nc; i++) {
|
||||
const NodeData &n = nd[i];
|
||||
|
||||
|
@ -249,6 +271,30 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
|
|||
// Get the node from somewhere, it likely already exists from another instance.
|
||||
if (parent) {
|
||||
node = parent->_get_child_by_name(snames[n.name]);
|
||||
if (i < ids.size()) {
|
||||
if (!node) {
|
||||
// Can't get by name, try to fetch by ID. This is slow, but should be fixed after re-save.
|
||||
int32_t id = ids[i];
|
||||
if (id != Node::UNIQUE_SCENE_ID_UNASSIGNED) {
|
||||
if (!deep_search_warned) {
|
||||
WARN_PRINT(vformat("%sA node in the scene this one inherits from has been removed or moved, so a recovery process needs to take place. Please re-save this scene to avoid the cost of this process next time.", !get_path().is_empty() ? get_path() + ": " : ""));
|
||||
deep_search_warned = true;
|
||||
}
|
||||
Node *base = parent;
|
||||
while (base != ret_nodes[0] && !base->is_instance()) {
|
||||
base = base->get_parent();
|
||||
}
|
||||
node = _find_node_by_id(base, base, id);
|
||||
}
|
||||
} else {
|
||||
if (ids[i] != node->get_unique_scene_id()) {
|
||||
// This may be a scene that did not originally have ids and
|
||||
// was saved before the parent, so force the id to match the
|
||||
// parent scene node id.
|
||||
ids.write[i] = node->get_unique_scene_id();
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (!node) {
|
||||
WARN_PRINT(String("Node '" + String(ret_nodes[0]->get_path_to(parent)) + "/" + String(snames[n.name]) + "' was modified from inside an instance, but it has vanished.").ascii().get_data());
|
||||
|
@ -297,6 +343,9 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
|
|||
}
|
||||
|
||||
if (node) {
|
||||
if (i < ids.size()) {
|
||||
node->set_unique_scene_id(ids[i]);
|
||||
}
|
||||
// may not have found the node (part of instantiated scene and removed)
|
||||
// if found all is good, otherwise ignore
|
||||
|
||||
|
@ -734,7 +783,7 @@ static int _vm_get_variant(const Variant &p_variant, HashMap<Variant, int, Varia
|
|||
return idx;
|
||||
}
|
||||
|
||||
Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map) {
|
||||
Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map, HashSet<int32_t> &ids_saved) {
|
||||
// this function handles all the work related to properly packing scenes, be it
|
||||
// instantiated or inherited.
|
||||
// given the complexity of this process, an attempt will be made to properly
|
||||
|
@ -1014,14 +1063,14 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
|
|||
// below condition is true for all nodes of the scene being saved, and ones in subscenes
|
||||
// that hold changes
|
||||
|
||||
bool save_node = nd.properties.size() || nd.groups.size(); // some local properties or groups exist
|
||||
save_node = save_node || p_node == p_owner; // owner is always saved
|
||||
bool save_node = p_node == p_owner; // owner is always saved
|
||||
save_node = save_node || (p_node->get_owner() == p_owner && instantiated_by_owner); //part of scene and not instanced
|
||||
bool save_data = nd.properties.size() || nd.groups.size(); // some local properties or groups exist
|
||||
|
||||
int idx = nodes.size();
|
||||
int parent_node = NO_PARENT_SAVED;
|
||||
|
||||
if (save_node) {
|
||||
if (save_node || save_data) {
|
||||
//don't save the node if nothing and subscene
|
||||
|
||||
node_map[p_node] = idx;
|
||||
|
@ -1041,13 +1090,39 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has
|
|||
nd.parent = p_parent_idx;
|
||||
}
|
||||
|
||||
int32_t unique_scene_id = p_node->get_unique_scene_id();
|
||||
if (save_node && (unique_scene_id == Node::UNIQUE_SCENE_ID_UNASSIGNED || ids_saved.has(unique_scene_id))) {
|
||||
// Unassigned or clash somehow.
|
||||
// Clashes will always happen with instantiated scenes, so it is normal
|
||||
// to expect them to be resolved.
|
||||
|
||||
while (true) {
|
||||
uint32_t data = ResourceUID::get_singleton()->create_id();
|
||||
unique_scene_id = data & 0x7FFFFFFF; // keep positive.
|
||||
|
||||
if (unique_scene_id == Node::UNIQUE_SCENE_ID_UNASSIGNED) {
|
||||
unique_scene_id = 1;
|
||||
}
|
||||
if (ids_saved.has(unique_scene_id)) {
|
||||
// While there is one in a four billion chance for a clash, the scenario where one scene is instantiated multiple times is common, so it must reassign the local id.
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
p_node->set_unique_scene_id(unique_scene_id);
|
||||
}
|
||||
|
||||
ids_saved.insert(unique_scene_id);
|
||||
ids.push_back(unique_scene_id);
|
||||
|
||||
parent_node = idx;
|
||||
nodes.push_back(nd);
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||
Node *c = p_node->get_child(i);
|
||||
Error err = _parse_node(p_owner, c, parent_node, name_map, variant_map, node_map, nodepath_map);
|
||||
Error err = _parse_node(p_owner, c, parent_node, name_map, variant_map, node_map, nodepath_map, ids_saved);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
@ -1273,6 +1348,7 @@ Error SceneState::pack(Node *p_scene) {
|
|||
HashMap<Variant, int, VariantHasher, VariantComparator> variant_map;
|
||||
HashMap<Node *, int> node_map;
|
||||
HashMap<Node *, int> nodepath_map;
|
||||
HashSet<int32_t> ids_saved;
|
||||
|
||||
// If using scene inheritance, pack the scene it inherits from.
|
||||
if (scene->get_scene_inherited_state().is_valid()) {
|
||||
|
@ -1284,7 +1360,7 @@ Error SceneState::pack(Node *p_scene) {
|
|||
}
|
||||
|
||||
// Instanced, only direct sub-scenes are supported of course.
|
||||
Error err = _parse_node(scene, scene, -1, name_map, variant_map, node_map, nodepath_map);
|
||||
Error err = _parse_node(scene, scene, -1, name_map, variant_map, node_map, nodepath_map, ids_saved);
|
||||
if (err) {
|
||||
clear();
|
||||
ERR_FAIL_V(err);
|
||||
|
@ -1310,8 +1386,31 @@ Error SceneState::pack(Node *p_scene) {
|
|||
}
|
||||
|
||||
node_paths.resize(nodepath_map.size());
|
||||
id_paths.resize(nodepath_map.size());
|
||||
for (const KeyValue<Node *, int> &E : nodepath_map) {
|
||||
node_paths.write[E.value] = scene->get_path_to(E.key);
|
||||
|
||||
// Build a path of IDs to reach the node.
|
||||
PackedInt32Array id_path;
|
||||
bool id_path_valid = false;
|
||||
Node *base = E.key;
|
||||
while (base && base->get_unique_scene_id() != Node::UNIQUE_SCENE_ID_UNASSIGNED) {
|
||||
id_path.push_back(base->get_unique_scene_id());
|
||||
base = base->get_owner();
|
||||
if (base == p_scene) {
|
||||
id_path_valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!id_path_valid) {
|
||||
id_path.clear();
|
||||
}
|
||||
|
||||
// Reverse it since we went from node to owner, and we seek from owner to node.
|
||||
id_path.reverse();
|
||||
|
||||
id_paths.write[E.value] = id_path;
|
||||
}
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
|
@ -1340,6 +1439,8 @@ void SceneState::clear() {
|
|||
node_path_cache.clear();
|
||||
node_paths.clear();
|
||||
editable_instances.clear();
|
||||
ids.clear();
|
||||
id_paths.clear();
|
||||
base_scene_idx = -1;
|
||||
}
|
||||
|
||||
|
@ -1366,6 +1467,9 @@ Error SceneState::copy_from(const Ref<SceneState> &p_scene_state) {
|
|||
for (const NodePath &E : p_scene_state->node_paths) {
|
||||
node_paths.append(E);
|
||||
}
|
||||
for (const PackedInt32Array &E : p_scene_state->id_paths) {
|
||||
id_paths.append(E);
|
||||
}
|
||||
for (const NodePath &E : p_scene_state->editable_instances) {
|
||||
editable_instances.append(E);
|
||||
}
|
||||
|
@ -1389,6 +1493,7 @@ int SceneState::find_node_by_path(const NodePath &p_node) const {
|
|||
ERR_FAIL_COND_V_MSG(node_path_cache.is_empty(), -1, "This operation requires the node cache to have been built.");
|
||||
|
||||
if (!node_path_cache.has(p_node)) {
|
||||
// If not in this scene state, find node path by scene inheritance.
|
||||
if (get_base_scene_state().is_valid()) {
|
||||
int idx = get_base_scene_state()->find_node_by_path(p_node);
|
||||
if (idx != -1) {
|
||||
|
@ -1610,15 +1715,30 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
|
|||
}
|
||||
}
|
||||
|
||||
if (p_dictionary.has("node_ids")) {
|
||||
ids = p_dictionary["node_ids"];
|
||||
}
|
||||
|
||||
Array np;
|
||||
if (p_dictionary.has("node_paths")) {
|
||||
np = p_dictionary["node_paths"];
|
||||
}
|
||||
|
||||
node_paths.resize(np.size());
|
||||
for (int i = 0; i < np.size(); i++) {
|
||||
node_paths.write[i] = np[i];
|
||||
}
|
||||
|
||||
Array idp;
|
||||
if (p_dictionary.has("id_paths") && ids.size()) {
|
||||
idp = p_dictionary["id_paths"];
|
||||
}
|
||||
|
||||
id_paths.resize(idp.size());
|
||||
for (int i = 0; i < idp.size(); i++) {
|
||||
id_paths.write[i] = idp[i];
|
||||
}
|
||||
|
||||
Array ei;
|
||||
if (p_dictionary.has("editable_instances")) {
|
||||
ei = p_dictionary["editable_instances"];
|
||||
|
@ -1678,6 +1798,7 @@ Dictionary SceneState::get_bundled_scene() const {
|
|||
}
|
||||
|
||||
d["nodes"] = rnodes;
|
||||
d["node_ids"] = ids;
|
||||
|
||||
Vector<int> rconns;
|
||||
d["conn_count"] = connections.size();
|
||||
|
@ -1705,6 +1826,13 @@ Dictionary SceneState::get_bundled_scene() const {
|
|||
}
|
||||
d["node_paths"] = rnode_paths;
|
||||
|
||||
Array rid_paths;
|
||||
rid_paths.resize(id_paths.size());
|
||||
for (int i = 0; i < id_paths.size(); i++) {
|
||||
rid_paths[i] = id_paths[i];
|
||||
}
|
||||
d["id_paths"] = rid_paths;
|
||||
|
||||
Array reditable_instances;
|
||||
reditable_instances.resize(editable_instances.size());
|
||||
for (int i = 0; i < editable_instances.size(); i++) {
|
||||
|
@ -1785,6 +1913,74 @@ Vector<StringName> SceneState::get_node_groups(int p_idx) const {
|
|||
return groups;
|
||||
}
|
||||
|
||||
Node *SceneState::_recover_node_path_index(Node *p_base, int p_idx) const {
|
||||
// ID paths are only used for recovery, since they are slower to traverse.
|
||||
// This function attempts to recover a node by using IDs in case the path
|
||||
// has disappeared.
|
||||
if (p_idx >= id_paths.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const PackedInt32Array &id_path = id_paths[p_idx & FLAG_MASK];
|
||||
|
||||
Vector<StringName> full_path;
|
||||
const SceneState *ss = this;
|
||||
for (int i = 0; i < id_path.size(); i++) {
|
||||
int idx = ss->ids.find(id_path[i]);
|
||||
if (idx == -1) {
|
||||
// Not found, but may belong to a base scene, so search.
|
||||
while (ss && idx == -1 && ss->base_scene_idx >= 0) {
|
||||
Ref<PackedScene> sdata = ss->variants[ss->base_scene_idx];
|
||||
if (sdata.is_null()) {
|
||||
return nullptr;
|
||||
}
|
||||
Ref<SceneState> ssd = sdata->get_state();
|
||||
if (!ssd.is_valid()) {
|
||||
return nullptr;
|
||||
}
|
||||
ss = ssd.ptr();
|
||||
idx = ss->ids.find(id_path[i]);
|
||||
if (idx != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (idx == -1) {
|
||||
//No luck.
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
ERR_FAIL_COND_V(idx >= ss->nodes.size(), nullptr); // Should be a node.
|
||||
|
||||
NodePath so_far = ss->get_node_path(idx);
|
||||
for (int j = 0; j < so_far.get_name_count(); j++) {
|
||||
full_path.push_back(so_far.get_name(j));
|
||||
}
|
||||
|
||||
if (i == id_path.size() - 1) {
|
||||
break; // Do not go further, we have the path.
|
||||
}
|
||||
|
||||
const NodeData &nd = ss->nodes[idx];
|
||||
// Get instance
|
||||
ERR_FAIL_COND_V(nd.instance < 0, nullptr); // Not an instance, middle of path should be an instance.
|
||||
ERR_FAIL_COND_V(nd.instance & FLAG_INSTANCE_IS_PLACEHOLDER, nullptr); // Instance is somehow a placeholder?!
|
||||
Ref<PackedScene> sdata = ss->variants[nd.instance & FLAG_MASK];
|
||||
ERR_FAIL_COND_V(sdata.is_null(), nullptr);
|
||||
Ref<SceneState> sstate = sdata->get_state();
|
||||
ss = sstate.ptr();
|
||||
}
|
||||
|
||||
NodePath recovered_path(full_path, false);
|
||||
return p_base->get_node_or_null(recovered_path);
|
||||
}
|
||||
|
||||
int32_t SceneState::get_node_unique_id(int p_idx) const {
|
||||
if (p_idx >= ids.size()) {
|
||||
return Node::UNIQUE_SCENE_ID_UNASSIGNED;
|
||||
}
|
||||
return ids[p_idx];
|
||||
}
|
||||
|
||||
NodePath SceneState::get_node_path(int p_idx, bool p_for_parent) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, nodes.size(), NodePath());
|
||||
|
||||
|
@ -1828,6 +2024,52 @@ NodePath SceneState::get_node_path(int p_idx, bool p_for_parent) const {
|
|||
return NodePath(sub_path, false);
|
||||
}
|
||||
|
||||
PackedInt32Array SceneState::get_node_id_path(int p_idx) const {
|
||||
PackedInt32Array pp = get_node_parent_id_path(p_idx);
|
||||
if (pp.is_empty()) {
|
||||
return pp;
|
||||
}
|
||||
|
||||
if (p_idx < ids.size()) {
|
||||
pp.push_back(ids[p_idx]);
|
||||
return pp;
|
||||
}
|
||||
|
||||
return PackedInt32Array();
|
||||
}
|
||||
|
||||
PackedInt32Array SceneState::get_node_parent_id_path(int p_idx) const {
|
||||
if (nodes[p_idx].parent < 0 || nodes[p_idx].parent == NO_PARENT_SAVED) {
|
||||
return PackedInt32Array();
|
||||
}
|
||||
|
||||
if (nodes[p_idx].parent & FLAG_ID_IS_PATH) {
|
||||
int id = nodes[p_idx].parent & FLAG_MASK;
|
||||
if (id >= id_paths.size()) {
|
||||
return PackedInt32Array();
|
||||
}
|
||||
return id_paths[id];
|
||||
}
|
||||
|
||||
return PackedInt32Array();
|
||||
}
|
||||
|
||||
PackedInt32Array SceneState::get_node_owner_id_path(int p_idx) const {
|
||||
if (nodes[p_idx].owner < 0) {
|
||||
return PackedInt32Array();
|
||||
}
|
||||
|
||||
if (nodes[p_idx].owner & FLAG_ID_IS_PATH) {
|
||||
int id = nodes[p_idx].owner & FLAG_MASK;
|
||||
if (id >= id_paths.size()) {
|
||||
return PackedInt32Array();
|
||||
}
|
||||
return id_paths[id];
|
||||
}
|
||||
|
||||
return PackedInt32Array();
|
||||
}
|
||||
|
||||
int SceneState::get_node_property_count(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, nodes.size(), -1);
|
||||
return nodes[p_idx].properties.size();
|
||||
|
@ -1909,6 +2151,24 @@ NodePath SceneState::get_connection_target(int p_idx) const {
|
|||
}
|
||||
}
|
||||
|
||||
PackedInt32Array SceneState::get_connection_target_id_path(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, connections.size(), PackedInt32Array());
|
||||
if (connections[p_idx].to & FLAG_ID_IS_PATH && connections[p_idx].to < id_paths.size()) {
|
||||
return id_paths[connections[p_idx].to];
|
||||
} else {
|
||||
return PackedInt32Array();
|
||||
}
|
||||
}
|
||||
|
||||
PackedInt32Array SceneState::get_connection_source_id_path(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, connections.size(), PackedInt32Array());
|
||||
if (connections[p_idx].from & FLAG_ID_IS_PATH && connections[p_idx].from < id_paths.size()) {
|
||||
return id_paths[connections[p_idx].from];
|
||||
} else {
|
||||
return PackedInt32Array();
|
||||
}
|
||||
}
|
||||
|
||||
StringName SceneState::get_connection_method(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx, connections.size(), StringName());
|
||||
return names[connections[p_idx].method];
|
||||
|
@ -2013,12 +2273,13 @@ int SceneState::add_value(const Variant &p_value) {
|
|||
return variants.size() - 1;
|
||||
}
|
||||
|
||||
int SceneState::add_node_path(const NodePath &p_path) {
|
||||
int SceneState::add_node_path(const NodePath &p_path, const PackedInt32Array &p_uid_path) {
|
||||
node_paths.push_back(p_path);
|
||||
id_paths.push_back(p_uid_path);
|
||||
return (node_paths.size() - 1) | FLAG_ID_IS_PATH;
|
||||
}
|
||||
|
||||
int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index) {
|
||||
int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index, int32_t p_unique_id) {
|
||||
NodeData nd;
|
||||
nd.parent = p_parent;
|
||||
nd.owner = p_owner;
|
||||
|
@ -2029,6 +2290,8 @@ int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int
|
|||
|
||||
nodes.push_back(nd);
|
||||
|
||||
ids.push_back(p_unique_id);
|
||||
|
||||
return nodes.size() - 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ class SceneState : public RefCounted {
|
|||
Vector<StringName> names;
|
||||
Vector<Variant> variants;
|
||||
Vector<NodePath> node_paths;
|
||||
Vector<PackedInt32Array> id_paths;
|
||||
mutable PackedInt32Array ids;
|
||||
Vector<NodePath> editable_instances;
|
||||
mutable HashMap<NodePath, int> node_path_cache;
|
||||
mutable HashMap<int, int> base_scene_node_remap;
|
||||
|
@ -88,7 +90,7 @@ class SceneState : public RefCounted {
|
|||
|
||||
Vector<ConnectionData> connections;
|
||||
|
||||
Error _parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map);
|
||||
Error _parse_node(Node *p_owner, Node *p_node, int p_parent_idx, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map, HashSet<int32_t> &ids_saved);
|
||||
Error _parse_connections(Node *p_owner, Node *p_node, HashMap<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, HashMap<Node *, int> &node_map, HashMap<Node *, int> &nodepath_map);
|
||||
|
||||
String path;
|
||||
|
@ -101,6 +103,8 @@ class SceneState : public RefCounted {
|
|||
|
||||
int _find_base_scene_node_remap_key(int p_idx) const;
|
||||
|
||||
Node *_recover_node_path_index(Node *p_base, int p_idx) const;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
public:
|
||||
typedef void (*InstantiationWarningNotify)(const String &p_warning);
|
||||
|
@ -171,7 +175,11 @@ public:
|
|||
StringName get_node_type(int p_idx) const;
|
||||
StringName get_node_name(int p_idx) const;
|
||||
NodePath get_node_path(int p_idx, bool p_for_parent = false) const;
|
||||
int32_t get_node_unique_id(int p_idx) const;
|
||||
PackedInt32Array get_node_id_path(int p_idx) const;
|
||||
PackedInt32Array get_node_parent_id_path(int p_idx) const;
|
||||
NodePath get_node_owner_path(int p_idx) const;
|
||||
PackedInt32Array get_node_owner_id_path(int p_idx) const;
|
||||
Ref<PackedScene> get_node_instance(int p_idx) const;
|
||||
String get_node_instance_placeholder(int p_idx) const;
|
||||
bool is_node_instance_placeholder(int p_idx) const;
|
||||
|
@ -188,6 +196,10 @@ public:
|
|||
StringName get_connection_signal(int p_idx) const;
|
||||
NodePath get_connection_target(int p_idx) const;
|
||||
StringName get_connection_method(int p_idx) const;
|
||||
|
||||
PackedInt32Array get_connection_source_id_path(int p_idx) const;
|
||||
PackedInt32Array get_connection_target_id_path(int p_idx) const;
|
||||
|
||||
int get_connection_flags(int p_idx) const;
|
||||
int get_connection_unbinds(int p_idx) const;
|
||||
Array get_connection_binds(int p_idx) const;
|
||||
|
@ -202,8 +214,8 @@ public:
|
|||
|
||||
int add_name(const StringName &p_name);
|
||||
int add_value(const Variant &p_value);
|
||||
int add_node_path(const NodePath &p_path);
|
||||
int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index);
|
||||
int add_node_path(const NodePath &p_path, const PackedInt32Array &p_uid_path);
|
||||
int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index, int32_t p_unique_id);
|
||||
void add_node_property(int p_node, int p_name, int p_value, bool p_deferred_node_path = false);
|
||||
void add_node_group(int p_node, int p_group);
|
||||
void set_base_scene(int p_idx);
|
||||
|
|
|
@ -194,6 +194,8 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
|
|||
int name = -1;
|
||||
int instance = -1;
|
||||
int index = -1;
|
||||
int unique_id = Node::UNIQUE_SCENE_ID_UNASSIGNED;
|
||||
|
||||
//int base_scene=-1;
|
||||
|
||||
if (next_tag.fields.has("name")) {
|
||||
|
@ -202,8 +204,14 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
|
|||
|
||||
if (next_tag.fields.has("parent")) {
|
||||
NodePath np = next_tag.fields["parent"];
|
||||
np.prepend_period(); //compatible to how it manages paths internally
|
||||
parent = packed_scene->get_state()->add_node_path(np);
|
||||
PackedInt32Array np_id;
|
||||
if (next_tag.fields.has("parent_id_path")) {
|
||||
np_id = next_tag.fields["parent_id_path"];
|
||||
}
|
||||
parent = packed_scene->get_state()->add_node_path(np, np_id);
|
||||
}
|
||||
if (next_tag.fields.has("unique_id")) {
|
||||
unique_id = next_tag.fields["unique_id"];
|
||||
}
|
||||
|
||||
if (next_tag.fields.has("type")) {
|
||||
|
@ -246,7 +254,11 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
|
|||
}
|
||||
|
||||
if (next_tag.fields.has("owner")) {
|
||||
owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"]);
|
||||
PackedInt32Array np_id;
|
||||
if (next_tag.fields.has("owner_uid_path")) {
|
||||
np_id = next_tag.fields["owner_uid_path"];
|
||||
}
|
||||
owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"], np_id);
|
||||
} else {
|
||||
if (parent != -1 && !(type == SceneState::TYPE_INSTANTIATED && instance == -1)) {
|
||||
owner = 0; //if no owner, owner is root
|
||||
|
@ -257,7 +269,7 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
|
|||
index = next_tag.fields["index"];
|
||||
}
|
||||
|
||||
int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance, index);
|
||||
int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance, index, unique_id);
|
||||
|
||||
if (next_tag.fields.has("groups")) {
|
||||
Array groups = next_tag.fields["groups"];
|
||||
|
@ -327,6 +339,16 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
|
|||
int unbinds = 0;
|
||||
Array binds;
|
||||
|
||||
PackedInt32Array from_id;
|
||||
if (next_tag.fields.has("from_uid_path")) {
|
||||
from_id = next_tag.fields["from_uid_path"];
|
||||
}
|
||||
|
||||
PackedInt32Array to_id;
|
||||
if (next_tag.fields.has("to_uid_path")) {
|
||||
to_id = next_tag.fields["to_uid_path"];
|
||||
}
|
||||
|
||||
if (next_tag.fields.has("flags")) {
|
||||
flags = next_tag.fields["flags"];
|
||||
}
|
||||
|
@ -345,8 +367,8 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
|
|||
}
|
||||
|
||||
packed_scene->get_state()->add_connection(
|
||||
packed_scene->get_state()->add_node_path(from.simplified()),
|
||||
packed_scene->get_state()->add_node_path(to.simplified()),
|
||||
packed_scene->get_state()->add_node_path(from.simplified(), from_id),
|
||||
packed_scene->get_state()->add_node_path(to.simplified(), to_id),
|
||||
packed_scene->get_state()->add_name(signal),
|
||||
packed_scene->get_state()->add_name(method),
|
||||
flags,
|
||||
|
@ -1963,7 +1985,10 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
|
|||
StringName type = state->get_node_type(i);
|
||||
StringName name = state->get_node_name(i);
|
||||
int index = state->get_node_index(i);
|
||||
NodePath path = state->get_node_path(i, true);
|
||||
int unique_id = state->get_node_unique_id(i);
|
||||
NodePath parent_path = state->get_node_path(i, true);
|
||||
PackedInt32Array parent_id_path = state->get_node_parent_id_path(i);
|
||||
PackedInt32Array owner_id_path = state->get_node_owner_id_path(i);
|
||||
NodePath owner = state->get_node_owner_path(i);
|
||||
Ref<PackedScene> instance = state->get_node_instance(i);
|
||||
String instance_placeholder = state->get_node_instance_placeholder(i);
|
||||
|
@ -1975,16 +2000,27 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
|
|||
if (type != StringName()) {
|
||||
header += " type=\"" + String(type) + "\"";
|
||||
}
|
||||
if (path != NodePath()) {
|
||||
header += " parent=\"" + String(path.simplified()).c_escape() + "\"";
|
||||
if (parent_path != NodePath()) {
|
||||
header += " parent=\"" + String(parent_path.simplified()).c_escape() + "\"";
|
||||
if (parent_id_path.size()) {
|
||||
header += " parent_id_path=" + Variant(parent_id_path).get_construct_string();
|
||||
}
|
||||
}
|
||||
|
||||
if (owner != NodePath() && owner != NodePath(".")) {
|
||||
header += " owner=\"" + String(owner.simplified()).c_escape() + "\"";
|
||||
if (owner_id_path.size()) {
|
||||
header += " owner_uid_path=" + Variant(owner_id_path).get_construct_string();
|
||||
}
|
||||
}
|
||||
if (index >= 0) {
|
||||
header += " index=\"" + itos(index) + "\"";
|
||||
}
|
||||
|
||||
if (unique_id != Node::UNIQUE_SCENE_ID_UNASSIGNED) {
|
||||
header += " unique_id=" + itos(unique_id) + "";
|
||||
}
|
||||
|
||||
if (deferred_node_paths.size()) {
|
||||
header += " node_paths=" + Variant(deferred_node_paths).get_construct_string();
|
||||
}
|
||||
|
@ -2050,6 +2086,20 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Reso
|
|||
connstr += " flags=" + itos(flags);
|
||||
}
|
||||
|
||||
{
|
||||
PackedInt32Array from_idp = state->get_connection_source_id_path(i);
|
||||
if (from_idp.size()) {
|
||||
connstr += " from_uid_path=" + Variant(from_idp).get_construct_string();
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
PackedInt32Array to_idp = state->get_connection_target_id_path(i);
|
||||
if (to_idp.size()) {
|
||||
connstr += " to_uid_path=" + Variant(to_idp).get_construct_string();
|
||||
}
|
||||
}
|
||||
|
||||
int unbinds = state->get_connection_unbinds(i);
|
||||
if (unbinds > 0) {
|
||||
connstr += " unbinds=" + itos(unbinds);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue