|
@@ -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;
|
|
|
}
|
|
|
|