1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-10 13:00:37 +00:00

Fix heap-use-after-free when closing a scene with 2D particle nodes selected

This commit is contained in:
Haoyu Qiu
2025-05-23 12:15:01 +08:00
parent 7a0ab9d561
commit f16378a8de
2 changed files with 43 additions and 16 deletions

View File

@@ -293,33 +293,58 @@ Particles2DEditorPlugin::Particles2DEditorPlugin() {
emission_mask->connect(SceneStringName(confirmed), callable_mp(this, &Particles2DEditorPlugin::_generate_emission_mask)); emission_mask->connect(SceneStringName(confirmed), callable_mp(this, &Particles2DEditorPlugin::_generate_emission_mask));
} }
void Particles2DEditorPlugin::_set_show_gizmos(Node *p_node, bool p_show) {
GPUParticles2D *gpu_particles = Object::cast_to<GPUParticles2D>(p_node);
if (gpu_particles) {
gpu_particles->set_show_gizmos(p_show);
}
CPUParticles2D *cpu_particles = Object::cast_to<CPUParticles2D>(p_node);
if (cpu_particles) {
cpu_particles->set_show_gizmos(p_show);
}
// The `selection_changed` signal is deferred. A node could be deleted before the signal is emitted.
if (p_show) {
p_node->connect(SceneStringName(tree_exiting), callable_mp(this, &Particles2DEditorPlugin::_node_removed).bind(p_node));
} else {
p_node->disconnect(SceneStringName(tree_exiting), callable_mp(this, &Particles2DEditorPlugin::_node_removed));
}
}
void Particles2DEditorPlugin::_selection_changed() { void Particles2DEditorPlugin::_selection_changed() {
List<Node *> selected_nodes = EditorNode::get_singleton()->get_editor_selection()->get_top_selected_node_list(); List<Node *> current_selection = EditorNode::get_singleton()->get_editor_selection()->get_top_selected_node_list();
if (selected_particles.is_empty() && selected_nodes.is_empty()) { if (selected_particles.is_empty() && current_selection.is_empty()) {
return; return;
} }
for (Node *particles : selected_particles) { // Turn gizmos off for nodes that are no longer selected.
if (GPUParticles2D *gpu_particles = Object::cast_to<GPUParticles2D>(particles)) { for (List<Node *>::Element *E = selected_particles.front(); E;) {
gpu_particles->set_show_gizmos(false); Node *node = E->get();
} else if (CPUParticles2D *cpu_particles = Object::cast_to<CPUParticles2D>(particles)) { List<Node *>::Element *N = E->next();
cpu_particles->set_show_gizmos(false); if (current_selection.find(node) == nullptr) {
_set_show_gizmos(node, false);
selected_particles.erase(E);
} }
E = N;
} }
selected_particles.clear(); // Turn gizmos on for nodes that are newly selected.
for (Node *node : current_selection) {
for (Node *node : selected_nodes) { if (selected_particles.find(node) == nullptr) {
if (GPUParticles2D *selected_gpu_particle = Object::cast_to<GPUParticles2D>(node)) { _set_show_gizmos(node, true);
selected_gpu_particle->set_show_gizmos(true); selected_particles.push_back(node);
selected_particles.push_back(selected_gpu_particle);
} else if (CPUParticles2D *selected_cpu_particle = Object::cast_to<CPUParticles2D>(node)) {
selected_cpu_particle->set_show_gizmos(true);
selected_particles.push_back(selected_cpu_particle);
} }
} }
} }
void Particles2DEditorPlugin::_node_removed(Node *p_node) {
List<Node *>::Element *E = selected_particles.find(p_node);
if (E) {
_set_show_gizmos(E->get(), false);
selected_particles.erase(E);
}
}
void GPUParticles2DEditorPlugin::_generate_visibility_rect() { void GPUParticles2DEditorPlugin::_generate_visibility_rect() {
GPUParticles2D *particles = Object::cast_to<GPUParticles2D>(edited_node); GPUParticles2D *particles = Object::cast_to<GPUParticles2D>(edited_node);

View File

@@ -109,7 +109,9 @@ protected:
void _get_base_emission_mask(PackedVector2Array &r_valid_positions, PackedVector2Array &r_valid_normals, PackedByteArray &r_valid_colors, Vector2i &r_image_size); void _get_base_emission_mask(PackedVector2Array &r_valid_positions, PackedVector2Array &r_valid_normals, PackedByteArray &r_valid_colors, Vector2i &r_image_size);
virtual void _generate_emission_mask() = 0; virtual void _generate_emission_mask() = 0;
void _notification(int p_what); void _notification(int p_what);
void _set_show_gizmos(Node *p_node, bool p_show);
void _selection_changed(); void _selection_changed();
void _node_removed(Node *p_node);
public: public:
Particles2DEditorPlugin(); Particles2DEditorPlugin();