Make reimported models reimport their owner.
Changes the behaviour of the scene hot-reload system so that if the scene which needs to be reimported is owned by another instance, reload that instance instead.
This commit is contained in:
parent
61598c5c88
commit
86ce15fb7a
3 changed files with 81 additions and 61 deletions
|
@ -4391,6 +4391,21 @@ bool EditorNode::is_additional_node_in_scene(Node *p_edited_scene, Node *p_reimp
|
|||
return true;
|
||||
}
|
||||
|
||||
void EditorNode::get_scene_editor_data_for_node(Node *p_root, Node *p_node, HashMap<NodePath, SceneEditorDataEntry> &p_table) {
|
||||
SceneEditorDataEntry new_entry;
|
||||
new_entry.is_display_folded = p_node->is_displayed_folded();
|
||||
|
||||
if (p_root != p_node) {
|
||||
new_entry.is_editable = p_root->is_editable_instance(p_node);
|
||||
}
|
||||
|
||||
p_table.insert(p_root->get_path_to(p_node), new_entry);
|
||||
|
||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||
get_scene_editor_data_for_node(p_root, p_node->get_child(i), p_table);
|
||||
}
|
||||
}
|
||||
|
||||
void EditorNode::get_preload_scene_modification_table(
|
||||
Node *p_edited_scene,
|
||||
Node *p_reimported_root,
|
||||
|
@ -4497,7 +4512,7 @@ void EditorNode::get_preload_scene_modification_table(
|
|||
void EditorNode::get_preload_modifications_reference_to_nodes(
|
||||
Node *p_root,
|
||||
Node *p_node,
|
||||
List<Node *> &p_excluded_nodes,
|
||||
HashSet<Node *> &p_excluded_nodes,
|
||||
List<Node *> &p_instance_list_with_children,
|
||||
HashMap<NodePath, ModificationNodeEntry> &p_modification_table) {
|
||||
if (!p_excluded_nodes.find(p_node)) {
|
||||
|
@ -5962,12 +5977,14 @@ void EditorNode::reload_scene(const String &p_path) {
|
|||
scene_tabs->set_current_tab(current_tab);
|
||||
}
|
||||
|
||||
void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, List<Node *> &p_instance_list) {
|
||||
void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, HashSet<Node *> &p_instance_list) {
|
||||
String scene_file_path = p_node->get_scene_file_path();
|
||||
|
||||
// This is going to get messy...
|
||||
bool valid_instance_found = false;
|
||||
|
||||
// Attempt to find all the instances matching path we're going to reload.
|
||||
if (p_node->get_scene_file_path() == p_instance_path) {
|
||||
p_instance_list.push_back(p_node);
|
||||
valid_instance_found = true;
|
||||
} else {
|
||||
Node *current_node = p_node;
|
||||
|
||||
|
@ -5975,7 +5992,7 @@ void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *
|
|||
while (inherited_state.is_valid()) {
|
||||
String inherited_path = inherited_state->get_path();
|
||||
if (inherited_path == p_instance_path) {
|
||||
p_instance_list.push_back(p_node);
|
||||
valid_instance_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -5983,6 +6000,19 @@ void EditorNode::find_all_instances_inheriting_path_in_node(Node *p_root, Node *
|
|||
}
|
||||
}
|
||||
|
||||
// Instead of adding this instance directly, if its not owned by the scene, walk its ancestors
|
||||
// and find the first node still owned by the scene. This is what we will reloading instead.
|
||||
if (valid_instance_found) {
|
||||
Node *current_node = p_node;
|
||||
while (true) {
|
||||
if (current_node->get_owner() == p_root || current_node->get_owner() == nullptr) {
|
||||
p_instance_list.insert(current_node);
|
||||
break;
|
||||
}
|
||||
current_node = current_node->get_parent();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < p_node->get_child_count(); i++) {
|
||||
find_all_instances_inheriting_path_in_node(p_root, p_node->get_child(i), p_instance_path, p_instance_list);
|
||||
}
|
||||
|
@ -6001,20 +6031,20 @@ void EditorNode::preload_reimporting_with_path_in_edited_scenes(const List<Strin
|
|||
Node *edited_scene_root = editor_data.get_edited_scene_root(current_scene_idx);
|
||||
|
||||
if (edited_scene_root) {
|
||||
SceneModificationsEntry scene_motifications;
|
||||
SceneModificationsEntry scene_modifications;
|
||||
|
||||
for (const String &instance_path : p_scenes) {
|
||||
if (editor_data.get_scene_path(current_scene_idx) == instance_path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Node *> instance_list;
|
||||
find_all_instances_inheriting_path_in_node(edited_scene_root, edited_scene_root, instance_path, instance_list);
|
||||
if (instance_list.size() > 0) {
|
||||
HashSet<Node *> instances_to_reimport;
|
||||
find_all_instances_inheriting_path_in_node(edited_scene_root, edited_scene_root, instance_path, instances_to_reimport);
|
||||
if (instances_to_reimport.size() > 0) {
|
||||
editor_data.set_edited_scene(current_scene_idx);
|
||||
|
||||
List<Node *> instance_list_with_children;
|
||||
for (Node *original_node : instance_list) {
|
||||
for (Node *original_node : instances_to_reimport) {
|
||||
InstanceModificationsEntry instance_modifications;
|
||||
|
||||
// Fetching all the modified properties of the nodes reimported scene.
|
||||
|
@ -6022,19 +6052,19 @@ void EditorNode::preload_reimporting_with_path_in_edited_scenes(const List<Strin
|
|||
|
||||
instance_modifications.original_node = original_node;
|
||||
instance_modifications.instance_path = instance_path;
|
||||
scene_motifications.instance_list.push_back(instance_modifications);
|
||||
scene_modifications.instance_list.push_back(instance_modifications);
|
||||
|
||||
instance_list_with_children.push_back(original_node);
|
||||
get_children_nodes(original_node, instance_list_with_children);
|
||||
}
|
||||
|
||||
// Search the scene to find nodes that references the nodes will be recreated.
|
||||
get_preload_modifications_reference_to_nodes(edited_scene_root, edited_scene_root, instance_list, instance_list_with_children, scene_motifications.other_instances_modifications);
|
||||
get_preload_modifications_reference_to_nodes(edited_scene_root, edited_scene_root, instances_to_reimport, instance_list_with_children, scene_modifications.other_instances_modifications);
|
||||
}
|
||||
}
|
||||
|
||||
if (scene_motifications.instance_list.size() > 0) {
|
||||
scenes_modification_table[current_scene_idx] = scene_motifications;
|
||||
if (scene_modifications.instance_list.size() > 0) {
|
||||
scenes_modification_table[current_scene_idx] = scene_modifications;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6157,10 +6187,10 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
|
|||
// Instantiate early so that caches cleared on load in SceneState can be rebuilt early.
|
||||
Node *instantiated_node = nullptr;
|
||||
|
||||
// If we are in a inherit scene, it's easier to create a new base scene and
|
||||
// If we are in a inherited scene, it's easier to create a new base scene and
|
||||
// grab the node from there.
|
||||
// When scene_path_to_node is '.' and we have scene_inherited_state, it's because
|
||||
// it's a muli-level inheritance scene. We should use
|
||||
// it's a multi-level inheritance scene. We should use
|
||||
NodePath scene_path_to_node = current_edited_scene->get_path_to(original_node);
|
||||
Ref<SceneState> scene_state = current_edited_scene->get_scene_inherited_state();
|
||||
if (scene_path_to_node != "." && scene_state.is_valid() && scene_state->get_path() != instance_modifications.instance_path && scene_state->find_node_by_path(scene_path_to_node) >= 0) {
|
||||
|
@ -6184,9 +6214,9 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
|
|||
|
||||
if (!instantiated_node) {
|
||||
// If no base scene was found to create the node, we will use the reimported packed scene directly.
|
||||
// But, when the current edited scene is the reimported scene, it's because it's a inherited scene
|
||||
// of the reimported scene. In that case, we will not instantiate current_packed_scene, because
|
||||
// we would reinstanciate ourself. Using the base scene is better.
|
||||
// But, when the current edited scene is the reimported scene, it's because it's an inherited scene
|
||||
// derived from the reimported scene. In that case, we will not instantiate current_packed_scene, because
|
||||
// we would reinstantiate ourself. Using the base scene is better.
|
||||
if (current_edited_scene == original_node) {
|
||||
if (base_packed_scene.is_valid()) {
|
||||
instantiated_node = base_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
|
||||
|
@ -6242,6 +6272,17 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
|
|||
// crash when reimporting scenes with animations when "Editable children" was enabled.
|
||||
replace_history_reimported_nodes(original_node, instantiated_node, original_node);
|
||||
|
||||
// Reset the editable instance state.
|
||||
HashMap<NodePath, SceneEditorDataEntry> scene_editor_data_table;
|
||||
Node *owner = original_node->get_owner();
|
||||
if (!owner) {
|
||||
owner = original_node;
|
||||
}
|
||||
|
||||
get_scene_editor_data_for_node(owner, original_node, scene_editor_data_table);
|
||||
|
||||
bool original_node_scene_instance_load_placeholder = original_node->get_scene_instance_load_placeholder();
|
||||
|
||||
// Delete all the remaining node children.
|
||||
while (original_node->get_child_count()) {
|
||||
Node *child = original_node->get_child(0);
|
||||
|
@ -6250,16 +6291,6 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
|
|||
child->queue_free();
|
||||
}
|
||||
|
||||
// Reset the editable instance state.
|
||||
bool is_editable = true;
|
||||
Node *owner = original_node->get_owner();
|
||||
if (owner) {
|
||||
is_editable = owner->is_editable_instance(original_node);
|
||||
}
|
||||
|
||||
bool original_node_is_displayed_folded = original_node->is_displayed_folded();
|
||||
bool original_node_scene_instance_load_placeholder = original_node->get_scene_instance_load_placeholder();
|
||||
|
||||
// Update the name to match
|
||||
instantiated_node->set_name(original_node->get_name());
|
||||
|
||||
|
@ -6290,19 +6321,9 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
|
|||
// Mark the old node for deletion.
|
||||
original_node->queue_free();
|
||||
|
||||
// Restore the folded and placeholder state from the original node.
|
||||
instantiated_node->set_display_folded(original_node_is_displayed_folded);
|
||||
// Restore the placeholder state from the original node.
|
||||
instantiated_node->set_scene_instance_load_placeholder(original_node_scene_instance_load_placeholder);
|
||||
|
||||
if (owner) {
|
||||
Ref<SceneState> ss_inst = owner->get_scene_instance_state();
|
||||
if (ss_inst.is_valid()) {
|
||||
ss_inst->update_instance_resource(instance_modifications.instance_path, current_packed_scene);
|
||||
}
|
||||
|
||||
owner->set_editable_instance(instantiated_node, is_editable);
|
||||
}
|
||||
|
||||
// Attempt to re-add all the additional nodes.
|
||||
for (AdditiveNodeEntry additive_node_entry : instance_modifications.addition_list) {
|
||||
Node *parent_node = instantiated_node->get_node_or_null(additive_node_entry.parent);
|
||||
|
@ -6334,6 +6355,17 @@ void EditorNode::reload_instances_with_path_in_edited_scenes() {
|
|||
}
|
||||
}
|
||||
|
||||
// Restore the scene's editable instance and folded states.
|
||||
for (HashMap<NodePath, SceneEditorDataEntry>::Iterator I = scene_editor_data_table.begin(); I; ++I) {
|
||||
Node *node = owner->get_node_or_null(I->key);
|
||||
if (node) {
|
||||
if (owner != node) {
|
||||
owner->set_editable_instance(node, I->value.is_editable);
|
||||
}
|
||||
node->set_display_folded(I->value.is_display_folded);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore the selection.
|
||||
if (selected_node_paths.size()) {
|
||||
for (NodePath selected_node_path : selected_node_paths) {
|
||||
|
|
|
@ -849,12 +849,19 @@ public:
|
|||
HashMap<NodePath, ModificationNodeEntry> other_instances_modifications;
|
||||
};
|
||||
|
||||
struct SceneEditorDataEntry {
|
||||
bool is_editable;
|
||||
bool is_display_folded;
|
||||
};
|
||||
|
||||
HashMap<int, SceneModificationsEntry> scenes_modification_table;
|
||||
List<String> scenes_reimported;
|
||||
List<String> resources_reimported;
|
||||
|
||||
void update_node_from_node_modification_entry(Node *p_node, ModificationNodeEntry &p_node_modification);
|
||||
|
||||
void get_scene_editor_data_for_node(Node *p_root, Node *p_node, HashMap<NodePath, SceneEditorDataEntry> &p_table);
|
||||
|
||||
void get_preload_scene_modification_table(
|
||||
Node *p_edited_scene,
|
||||
Node *p_reimported_root,
|
||||
|
@ -863,7 +870,7 @@ public:
|
|||
void get_preload_modifications_reference_to_nodes(
|
||||
Node *p_root,
|
||||
Node *p_node,
|
||||
List<Node *> &p_excluded_nodes,
|
||||
HashSet<Node *> &p_excluded_nodes,
|
||||
List<Node *> &p_instance_list_with_children,
|
||||
HashMap<NodePath, ModificationNodeEntry> &p_modification_table);
|
||||
void get_children_nodes(Node *p_node, List<Node *> &p_nodes);
|
||||
|
@ -924,7 +931,7 @@ public:
|
|||
|
||||
void reload_scene(const String &p_path);
|
||||
|
||||
void find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, List<Node *> &p_instance_list);
|
||||
void find_all_instances_inheriting_path_in_node(Node *p_root, Node *p_node, const String &p_instance_path, HashSet<Node *> &p_instance_list);
|
||||
void preload_reimporting_with_path_in_edited_scenes(const List<String> &p_scenes);
|
||||
void reload_instances_with_path_in_edited_scenes();
|
||||
|
||||
|
|
|
@ -1267,25 +1267,6 @@ Ref<SceneState> SceneState::get_base_scene_state() const {
|
|||
return Ref<SceneState>();
|
||||
}
|
||||
|
||||
void SceneState::update_instance_resource(String p_path, Ref<PackedScene> p_packed_scene) {
|
||||
ERR_FAIL_COND(p_packed_scene.is_null());
|
||||
|
||||
for (const NodeData &nd : nodes) {
|
||||
if (nd.instance >= 0) {
|
||||
if (!(nd.instance & FLAG_INSTANCE_IS_PLACEHOLDER)) {
|
||||
int instance_id = nd.instance & FLAG_MASK;
|
||||
Ref<PackedScene> original_packed_scene = variants[instance_id];
|
||||
if (original_packed_scene.is_valid()) {
|
||||
if (original_packed_scene->get_path() == p_path) {
|
||||
variants.remove_at(instance_id);
|
||||
variants.insert(instance_id, p_packed_scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
|
|
Loading…
Reference in a new issue