Fix errors when re-importing 3D asset files
Some 3D asset files are treated as scenes and may cause some errors when importing. When working through different scene tabs, we need to temporarily add the scene root to the SceneTree to ensure that `editor_selection->add_node()` can work smoothly. This avoids the error message: `ERROR: Condition "!p_node->is_inside_tree()" is true.` This also ensures that no other scenes are accidentally added to the SceneTree causing the wrong display. When there is an inherited scene tab open and it is not the current tab, the new root node is accidentally added as a child node of `scene_root` during replacement. Instantiate the scene early so caches in SceneState that are cleared due to loading are rebuilt early. This avoids numerous error messages: `This operation requires the node cache to have been built.`
This commit is contained in:
parent
25519867f2
commit
9fe902b296
1 changed files with 93 additions and 62 deletions
|
@ -1067,7 +1067,7 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
|
|||
reload_instances_with_path_in_edited_scenes(E);
|
||||
}
|
||||
|
||||
scene_tabs->set_current_tab(current_tab);
|
||||
_set_current_scene_nocheck(current_tab);
|
||||
}
|
||||
|
||||
void EditorNode::_sources_changed(bool p_exist) {
|
||||
|
@ -5719,8 +5719,14 @@ void EditorNode::reload_scene(const String &p_path) {
|
|||
|
||||
if (scene_idx == -1) {
|
||||
if (get_edited_scene()) {
|
||||
int current_history_id = editor_data.get_current_edited_scene_history_id();
|
||||
bool is_unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(current_history_id);
|
||||
|
||||
// Scene is not open, so at it might be instantiated. We'll refresh the whole scene later.
|
||||
EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id());
|
||||
EditorUndoRedoManager::get_singleton()->clear_history(false, current_history_id);
|
||||
if (is_unsaved) {
|
||||
EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(current_history_id);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -5770,7 +5776,6 @@ void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *
|
|||
}
|
||||
|
||||
void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_instance_path) {
|
||||
int original_edited_scene_idx = editor_data.get_edited_scene();
|
||||
HashMap<int, List<Node *>> edited_scene_map;
|
||||
Array replaced_nodes;
|
||||
|
||||
|
@ -5801,14 +5806,34 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
|
|||
HashMap<String, Ref<PackedScene>> local_scene_cache;
|
||||
local_scene_cache[p_instance_path] = instance_scene_packed_scene;
|
||||
|
||||
// Save the current scene state/selection in case of lost.
|
||||
Dictionary editor_state = _get_main_scene_state();
|
||||
editor_data.save_edited_scene_state(editor_selection, &editor_history, editor_state);
|
||||
editor_selection->clear();
|
||||
|
||||
int original_edited_scene_idx = editor_data.get_edited_scene();
|
||||
Node *original_edited_scene_root = editor_data.get_edited_scene_root();
|
||||
|
||||
// Prevent scene roots with the same name from being in the tree at the same time.
|
||||
scene_root->remove_child(original_edited_scene_root);
|
||||
|
||||
for (const KeyValue<int, List<Node *>> &edited_scene_map_elem : edited_scene_map) {
|
||||
// Set the current scene.
|
||||
int current_scene_idx = edited_scene_map_elem.key;
|
||||
editor_data.set_edited_scene(current_scene_idx);
|
||||
Node *current_edited_scene = editor_data.get_edited_scene_root(current_scene_idx);
|
||||
|
||||
// Clear the history for this tab (should we allow history to be retained?).
|
||||
EditorUndoRedoManager::get_singleton()->clear_history();
|
||||
// Make sure the node is in the tree so that editor_selection can add node smoothly.
|
||||
scene_root->add_child(current_edited_scene);
|
||||
|
||||
// Restore the state so that the selection can be updated.
|
||||
editor_state = editor_data.restore_edited_scene_state(editor_selection, &editor_history);
|
||||
|
||||
int current_history_id = editor_data.get_current_edited_scene_history_id();
|
||||
bool is_unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(current_history_id);
|
||||
|
||||
// Clear the history for this affected tab.
|
||||
EditorUndoRedoManager::get_singleton()->clear_history(false, current_history_id);
|
||||
|
||||
// Update the version
|
||||
editor_data.is_scene_changed(current_scene_idx);
|
||||
|
@ -5818,6 +5843,52 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
|
|||
update_node_reference_modification_table_for_node(current_edited_scene, current_edited_scene, edited_scene_map_elem.value, edited_scene_global_modification_table);
|
||||
|
||||
for (Node *original_node : edited_scene_map_elem.value) {
|
||||
String original_node_file_path = original_node->get_scene_file_path();
|
||||
|
||||
// Load a replacement scene for the node.
|
||||
Ref<PackedScene> current_packed_scene;
|
||||
if (original_node_file_path == p_instance_path) {
|
||||
// If the node file name directly matches the scene we're replacing,
|
||||
// just load it since we already cached it.
|
||||
current_packed_scene = instance_scene_packed_scene;
|
||||
} else {
|
||||
// Otherwise, check the inheritance chain, reloading and caching any scenes
|
||||
// we require along the way.
|
||||
List<String> required_load_paths;
|
||||
|
||||
// Do we need to check if the paths are empty?
|
||||
if (!original_node_file_path.is_empty()) {
|
||||
required_load_paths.push_front(original_node_file_path);
|
||||
}
|
||||
Ref<SceneState> inherited_state = original_node->get_scene_inherited_state();
|
||||
while (inherited_state.is_valid()) {
|
||||
String inherited_path = inherited_state->get_path();
|
||||
// Do we need to check if the paths are empty?
|
||||
if (!inherited_path.is_empty()) {
|
||||
required_load_paths.push_front(inherited_path);
|
||||
}
|
||||
inherited_state = inherited_state->get_base_scene_state();
|
||||
}
|
||||
|
||||
// Ensure the inheritance chain is loaded in the correct order so that cache can
|
||||
// be properly updated.
|
||||
for (String path : required_load_paths) {
|
||||
if (!local_scene_cache.find(path)) {
|
||||
current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP, &err);
|
||||
local_scene_cache[path] = current_packed_scene;
|
||||
} else {
|
||||
current_packed_scene = local_scene_cache[path];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(current_packed_scene.is_null());
|
||||
|
||||
// Instantiate early so that caches cleared on load in SceneState can be rebuilt early.
|
||||
Node *instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
|
||||
|
||||
ERR_FAIL_NULL(instantiated_node);
|
||||
|
||||
// Walk the tree for the current node and extract relevant diff data, storing it in the modification table.
|
||||
// For additional nodes which are part of the current scene, they get added to the addition table.
|
||||
HashMap<NodePath, ModificationNodeEntry> modification_table;
|
||||
|
@ -5875,53 +5946,6 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
|
|||
is_editable = owner->is_editable_instance(original_node);
|
||||
}
|
||||
|
||||
// Load a replacement scene for the node.
|
||||
Ref<PackedScene> current_packed_scene;
|
||||
if (original_node->get_scene_file_path() == p_instance_path) {
|
||||
// If the node file name directly matches the scene we're replacing,
|
||||
// just load it since we already cached it.
|
||||
current_packed_scene = instance_scene_packed_scene;
|
||||
} else {
|
||||
// Otherwise, check the inheritance chain, reloading and caching any scenes
|
||||
// we require along the way.
|
||||
List<String> required_load_paths;
|
||||
String scene_path = original_node->get_scene_file_path();
|
||||
// Do we need to check if the paths are empty?
|
||||
if (!scene_path.is_empty()) {
|
||||
required_load_paths.push_front(scene_path);
|
||||
}
|
||||
Ref<SceneState> inherited_state = original_node->get_scene_inherited_state();
|
||||
while (inherited_state.is_valid()) {
|
||||
String inherited_path = inherited_state->get_path();
|
||||
// Do we need to check if the paths are empty?
|
||||
if (!inherited_path.is_empty()) {
|
||||
required_load_paths.push_front(inherited_path);
|
||||
}
|
||||
inherited_state = inherited_state->get_base_scene_state();
|
||||
}
|
||||
|
||||
// Ensure the inheritance chain is loaded in the correct order so that cache can
|
||||
// be properly updated.
|
||||
for (String path : required_load_paths) {
|
||||
if (!local_scene_cache.find(path)) {
|
||||
current_packed_scene = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP, &err);
|
||||
local_scene_cache[path] = current_packed_scene;
|
||||
} else {
|
||||
current_packed_scene = local_scene_cache[path];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND(current_packed_scene.is_null());
|
||||
|
||||
// Instantiate the node.
|
||||
Node *instantiated_node = nullptr;
|
||||
if (current_packed_scene.is_valid()) {
|
||||
instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
|
||||
}
|
||||
|
||||
ERR_FAIL_NULL(instantiated_node);
|
||||
|
||||
// For clear instance state for path recaching.
|
||||
instantiated_node->set_scene_instance_state(Ref<SceneState>());
|
||||
|
||||
|
@ -5932,7 +5956,6 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
|
|||
instantiated_node->set_name(original_node->get_name());
|
||||
|
||||
// Is this replacing the edited root node?
|
||||
String original_node_file_path = original_node->get_scene_file_path();
|
||||
|
||||
if (current_edited_scene == original_node) {
|
||||
instantiated_node->set_scene_instance_state(original_node->get_scene_instance_state());
|
||||
|
@ -5943,13 +5966,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
|
|||
instantiated_node->set_scene_inherited_state(state);
|
||||
instantiated_node->set_scene_file_path(String());
|
||||
}
|
||||
editor_data.set_edited_scene_root(instantiated_node);
|
||||
current_edited_scene = instantiated_node;
|
||||
|
||||
if (original_node->is_inside_tree()) {
|
||||
SceneTreeDock::get_singleton()->set_edited_scene(current_edited_scene);
|
||||
original_node->get_tree()->set_edited_scene_root(instantiated_node);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the original node with the instantiated version.
|
||||
|
@ -6046,8 +6063,18 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
|
|||
}
|
||||
}
|
||||
|
||||
if (is_unsaved) {
|
||||
EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(current_history_id);
|
||||
}
|
||||
|
||||
// Save the current handled scene state.
|
||||
editor_data.save_edited_scene_state(editor_selection, &editor_history, editor_state);
|
||||
editor_selection->clear();
|
||||
|
||||
// Cleanup the history of the changes.
|
||||
editor_history.cleanup_history();
|
||||
|
||||
scene_root->remove_child(current_edited_scene);
|
||||
}
|
||||
|
||||
// For the whole editor, call the _notify_nodes_scene_reimported with a list of replaced nodes.
|
||||
|
@ -6055,10 +6082,14 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
|
|||
_notify_nodes_scene_reimported(this, replaced_nodes);
|
||||
|
||||
edited_scene_map.clear();
|
||||
}
|
||||
editor_data.set_edited_scene(original_edited_scene_idx);
|
||||
|
||||
_edit_current();
|
||||
editor_data.set_edited_scene(original_edited_scene_idx);
|
||||
|
||||
original_edited_scene_root = editor_data.get_edited_scene_root();
|
||||
scene_root->add_child(original_edited_scene_root);
|
||||
|
||||
editor_data.restore_edited_scene_state(editor_selection, &editor_history);
|
||||
}
|
||||
}
|
||||
|
||||
int EditorNode::plugin_init_callback_count = 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue