Flame 1.21.0 removes Components from World by itself
What happened?
- Updated from Flame 1.18.0 to 1.21.0 (so issue was not present on 1.18.0)
- During game session, flame randomly can remove my components (I have no clue why that happens on 1.21 and not on 1.18)
What do you expect?
I expect to know the reason why the component is removed. Both removeFromParent or onRemove are NOT called on removed components. So they just dissapear from World children set. Maybe Flame introduced some sort of garbage collector?
How can we reproduce this?
To be honest, I have no idea, maybe you can give me a clue why that can be happening.
What steps should take to fix this?
Make World's children set immutable and all add or remove operations can be logged if debug is true?
Do have an example of where the bug occurs?
no
Relevant log output
No response
Execute in a terminal and put output into the code block below
fvm flutter doctor -v [√] Flutter (Channel stable, 3.24.3, on Microsoft Windows [Version 10.0.22631.4317], locale ru-RU) • Flutter version 3.24.3 on channel stable at C:\Users\dima\fvm\versions\3.24.3 • Upstream repository https://github.com/flutter/flutter.git • Framework revision 2663184aa7 (7 weeks ago), 2024-09-11 16:27:48 -0500 • Engine revision 36335019a8 • Dart version 3.5.3 • DevTools version 2.37.3
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 34.0.0) • Android SDK at C:\sdk\Android\android-sdk • Platform android-34, build-tools 34.0.0 • ANDROID_HOME = C:\sdk\Android\android-sdk • Java binary at: C:\sdk\AndroidStudio\jbr\bin\java • Java version OpenJDK Runtime Environment (build 17.0.7+0-b2043.56-10550314) • All Android licenses accepted.
[√] Chrome - develop for the web • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe
[√] Visual Studio - develop Windows apps (Visual Studio Community 2022 17.7.4) • Visual Studio at C:\Program Files\Microsoft Visual Studio\2022\Community • Visual Studio Community 2022 version 17.7.34031.279 • Windows 10 SDK version 10.0.19041.0
[!] Android Studio (version 2022.3) • Android Studio at D:\Programs\Android • Flutter plugin can be installed from: https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: https://plugins.jetbrains.com/plugin/6351-dart X Unable to determine bundled Java version. • Try updating or re-installing Android Studio.
[√] Android Studio (version 2023.1) • Android Studio at C:\sdk\AndroidStudio • Flutter plugin can be installed from: https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 17.0.7+0-b2043.56-10550314)
[√] VS Code, 64-bit edition (version 1.94.2) • VS Code at C:\Program Files\Microsoft VS Code • Flutter extension version 3.100.0
[√] Connected device (4 available) • 21081111RG (mobile) • 5hmjbehqvsgqvseq • android-arm64 • Android 13 (API 33) • Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.22631.4317] • Chrome (web) • chrome • web-javascript • Google Chrome 130.0.6723.92 • Edge (web) • edge • web-javascript • Microsoft Edge 127.0.2651.86
[√] Network resources • All expected network resources are available.
Affected platforms
Android, Windows
Other information
No response
Are you interested in working on a PR for this?
- [X] I want to work on this
Im ready to fix this if you can give me a clue who and why can be modifing World's children set without even calling onRemove or removeFromParent. (its definitely not my code)
Please provide a way to reproduce this, otherwise it's hard for us to investigate it.
If this is reproducible, it is most likely related to this change: https://github.com/bluefireteam/ordered_set/pull/46
@spydon thanks for the hint, I will try to test it and come back with the result
@spydon so the issue is fixed if Im using old ordered set. Steps:
- updated flame to flame: 1.21.0
- forked ordered_set 5.0.3
- Change signature to
Iterable<C> query<C extends T>()(otherwise wont compile, this methods is overridden by flame with exactly this signature) Everything works. So I guess the bug is either in ordered_set, or Im using it wrong (to be honest Im using forked bonfire package, but as Ive seen nothing wrong there and I guess the bug happens during reordering the world)
@dvmatyun try to reproduce this for just Flame, because @RafaelBarbosatec reported something similar for Bonfire, but nobody has reported anything similar for pure Flame.
@dvmatyun can you try with Flame v1.23.0?
Closing this since it is stale, and fairly sure that it has been solved.
@spydon I have reproduced a similar issue to this one.
Components are randomly removed from World.children when a component is removed (by removeFromParent) and priority settings are changed at the same time.
This issue is reproduced with ordered_set 6.1.0 and later. https://github.com/bluefireteam/ordered_set/pull/46 Is ordered_set implementation as expected? (Will ordered_set be fixed?)
I have attached a sample program that reproduces this issue and some screenshots.
In this sample program, some of the green circles will disappear when you tap Down repeatedly.
- The white circles have the remove(removeFromParent) method executed in the program, but the green circles do not.
- Priority settings of all CircleComponents will change when the screen is tapped down.
| flame 1.26.0, ordered_set 6.0.1 | flame 1.26.0, ordered_set 6.1.1 |
|---|---|
These screenshots were taken on the Android Simulator (Pixel 4a API 34)
Sample code
import 'dart:async' as async;
import 'dart:math';
import 'package:flame/camera.dart';
import 'package:flame/components.dart';
import 'package:flame/effects.dart';
import 'package:flame/events.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';
class SampleGame extends FlameGame with TapCallbacks {
SampleGame() : super(camera: CameraComponent(viewfinder: Viewfinder()..anchor = Anchor.topLeft));
static const int _rows = 16;
static const int _cols = 10;
@override
Future<void> onLoad() async {
super.onLoad();
final greenCircleSize = canvasSize.x / _cols;
for (int row = 0; row < _rows; row++) {
for (int col = 0; col < _cols; col++) {
final position = Vector2(col * greenCircleSize, row * greenCircleSize);
final greenCircle = CircleComponent(radius: greenCircleSize / 2, position: position, paint: Paint()..color = Colors.green);
world.add(greenCircle);
}
}
async.Timer.periodic(const Duration(milliseconds: 40), (timer) {
final whiteCircleSize = greenCircleSize / 4;
final whiteCircle = CircleComponent(radius: whiteCircleSize / 2, position: Vector2(canvasSize.x * 0.2, canvasSize.y - whiteCircleSize), paint: Paint()..color = Colors.white);
whiteCircle.add(MoveToEffect(
Vector2(canvasSize.x * 0.8, canvasSize.y - whiteCircleSize),
EffectController(duration: 1.0),
onComplete: () {
whiteCircle.removeFromParent();
},
));
world.add(whiteCircle);
});
}
@override
void onTapDown(TapDownEvent event) {
world.children.whereType<CircleComponent>().forEach((greenCircle) {
greenCircle.priority = Random().nextInt(1000);
});
super.onTapDown(event);
}
}
Hmm that's odd, thanks for the good MRE! I'll have a closer look in a few days. Or maybe you could have a look @luanpotter ?
This should fix it! https://github.com/flame-engine/flame/pull/3530
Fix released in v1.26.1