From 53903bdf7673efb690dfff7456d03427bd7591d2 Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Wed, 5 Aug 2026 18:29:47 +0200 Subject: [PATCH 1/3] perf: Skip lifecycle processing work when the queue is empty --- .../components/core/component_tree_root.dart | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/flame/lib/src/components/core/component_tree_root.dart b/packages/flame/lib/src/components/core/component_tree_root.dart index b3794c42b01..959bee3bf65 100644 --- a/packages/flame/lib/src/components/core/component_tree_root.dart +++ b/packages/flame/lib/src/components/core/component_tree_root.dart @@ -143,10 +143,16 @@ class ComponentTreeRoot extends Component { } void processLifecycleEvents() { + if (!hasLifecycleEvents) { + // The completer is only ever created while events are queued, so there + // is nothing to complete here either. + assert(_lifecycleEventsCompleter == null); + return; + } // reorder events to process later grouped by parent - final reorderParents = {}; + Set? reorderParents; LifecycleEventStatus handleReorderEvent(Component parent) { - reorderParents.add(parent); + (reorderParents ??= {}).add(parent); return LifecycleEventStatus.done; } @@ -157,7 +163,8 @@ class ComponentTreeRoot extends Component { for (final event in queue) { final child = event.child!; final parent = event.parent!; - if (_blocked.contains(child) || _blocked.contains(parent)) { + if (_blocked.isNotEmpty && + (_blocked.contains(child) || _blocked.contains(parent))) { continue; } @@ -182,8 +189,10 @@ class ComponentTreeRoot extends Component { _blocked.clear(); } - for (final parent in reorderParents) { - parent.rebalanceChildren(); + if (reorderParents != null) { + for (final parent in reorderParents!) { + parent.rebalanceChildren(); + } } if (!hasLifecycleEvents && _lifecycleEventsCompleter != null) { From d9f1d7179f8e07ce36b1c9722aa4322fec0af2fe Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Wed, 5 Aug 2026 22:16:10 +0200 Subject: [PATCH 2/3] refactor: Address review feedback on the empty-queue early-out --- .../src/components/core/component_tree_root.dart | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/flame/lib/src/components/core/component_tree_root.dart b/packages/flame/lib/src/components/core/component_tree_root.dart index 959bee3bf65..ae3f62597ff 100644 --- a/packages/flame/lib/src/components/core/component_tree_root.dart +++ b/packages/flame/lib/src/components/core/component_tree_root.dart @@ -144,9 +144,11 @@ class ComponentTreeRoot extends Component { void processLifecycleEvents() { if (!hasLifecycleEvents) { - // The completer is only ever created while events are queued, so there - // is nothing to complete here either. - assert(_lifecycleEventsCompleter == null); + assert( + _lifecycleEventsCompleter == null, + 'The completer is only ever created while events are queued, so it ' + 'should never exist while the queue is empty', + ); return; } // reorder events to process later grouped by parent @@ -189,10 +191,8 @@ class ComponentTreeRoot extends Component { _blocked.clear(); } - if (reorderParents != null) { - for (final parent in reorderParents!) { - parent.rebalanceChildren(); - } + for (final parent in reorderParents ?? const {}) { + parent.rebalanceChildren(); } if (!hasLifecycleEvents && _lifecycleEventsCompleter != null) { From 29a82f1543357fd64264ca41fbdb75bd236ad081 Mon Sep 17 00:00:00 2001 From: Lukas Klingsbo Date: Sun, 16 Aug 2026 15:23:10 +0200 Subject: [PATCH 3/3] Apply suggestion from @spydon --- .../flame/lib/src/components/core/component_tree_root.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/flame/lib/src/components/core/component_tree_root.dart b/packages/flame/lib/src/components/core/component_tree_root.dart index ae3f62597ff..9627a335075 100644 --- a/packages/flame/lib/src/components/core/component_tree_root.dart +++ b/packages/flame/lib/src/components/core/component_tree_root.dart @@ -165,8 +165,7 @@ class ComponentTreeRoot extends Component { for (final event in queue) { final child = event.child!; final parent = event.parent!; - if (_blocked.isNotEmpty && - (_blocked.contains(child) || _blocked.contains(parent))) { + if (_blocked.contains(child) || _blocked.contains(parent)) { continue; }