Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make reimported models reimport their owner. #96144

Merged
merged 1 commit into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 72 additions & 40 deletions editor/editor_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -5962,27 +5977,42 @@ 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;

Ref<SceneState> inherited_state = current_node->get_scene_inherited_state();
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;
}

inherited_state = inherited_state->get_base_scene_state();
}
}

// 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);
}
Expand All @@ -6001,40 +6031,40 @@ 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.
get_preload_scene_modification_table(edited_scene_root, original_node, original_node, instance_modifications);

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;
}
}
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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());

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
11 changes: 9 additions & 2 deletions editor/editor_node.h
Original file line number Diff line number Diff line change
Expand Up @@ -849,12 +849,19 @@ class EditorNode : public Node {
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,
Expand All @@ -863,7 +870,7 @@ class EditorNode : public Node {
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);
Expand Down Expand Up @@ -924,7 +931,7 @@ class EditorNode : public Node {

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();

Expand Down
19 changes: 0 additions & 19 deletions scene/resources/packed_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.");

Expand Down
Loading