-
-
Notifications
You must be signed in to change notification settings - Fork 899
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
feat: Components are now always added in the correct order #1337
Conversation
Since we are already having an ordering function in the So the comparator would be something like this: Comparing.join<Component>([
Comparing.on<Component>((c) => c.priority),
Comparing.on<Component>((c) => c.addIndex),
]); ( This could also be made a non-breaking change in terms of API. Another small thing is that we probably want to keep the |
Can you please elaborate what benefit do you see for this approach? What it does is that it adds component unordered, but keeps an extra variable The approach that you suggest also leads to a significant increase in memory size of the component tree. This is due to the fact of how I'm not even sure how solid the statement "we are already having an ordering function in the OrderedSet" is. I mean, surely, we do, but eventually we want to support different implementations for Another advantage this PR brings is that it reduces the size of the
Sure, we can. After all, it's already there: So, having a future there that sometimes works and sometimes doesn't, just doesn't sound like a solid API to me. Though I do agree with you that scenarios where that future is meaningful are quite common. Still, they aren't overwhelmingly common. On the other hand, what if we removed the restriction that the parent needs to be mounted before we can proceed with loading? That would remove the "add" queue altogether and make the future far better defined. |
It makes the code here a lot simpler, there is no extra cost to add them in their correct place in the OrderedSet even if they aren't added in the add-order.
That's true, that's a good argument.
It does remove
Many games depend on the game
How could it remove the queue though, since there would still be different loading times between components? |
What if we handle this at Game's lifecycle? That is, first
I agree that it does look somewhat more complex, but I wonder if maybe that's just a matter of perception? Because what I did is I gathered code that was spread over As for the queue, it replaces the So, what I am saying is that the overall complexity remains approximately the same, only now it is concentrated in a single place, which makes it appear like it got more complex.
We could remove the "add" queue only, the "children" queue will remain. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some final small comments, other than those I think this is ready to get merged!
); | ||
assert( | ||
_state == LifecycleState.uninitialized || | ||
_state == LifecycleState.removed, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pretty message for this assert? or this one that "should never happen AFAWK"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a sanity check on the internal state: I do not think it is possible to violate this assert in the current code. But, if in the future we need to refactor this again (say, adding more states), this assert may trigger.
mixin SingleGameInstance on Game { | ||
@override | ||
void onMount() { | ||
Component.staticGameInstance = this; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could add some checks like: if staticGameInstance != null && != this
then throw pretty error message saying you cannot use SingleGameInstance like that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is an assert like that in FlameGame
class:
assert(
Component.staticGameInstance == null,
'$this instantiated, while another game ${Component.staticGameInstance} '
'declares itself to be a singleton',
);
I think it's better to have it in FlameGame because then not only we protect against two SingleGameInstance
objects, but we also prevent a SingleGameInstance
to coexist with a regular FlameGame
.
@@ -1,9 +1,10 @@ | |||
import 'dart:developer'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow what class requires this? never seem it before
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is for logging the stack-trace in line 337. It won't be needed after we upgrade to Dart 2.16 (which is in Flutter 2.10.0, released on 2022-02-03).
return FutureBuilder( | ||
future: loaderFuture, | ||
builder: (_, snapshot) { | ||
if (snapshot.hasError) { | ||
final errorBuilder = widget.errorBuilder; | ||
if (errorBuilder == null) { | ||
// @Since('2.16') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we just add dart>=2.16 to the pubspecs? otherwise I would just put out an issue with this code to tackle later, rather than commented code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd love to! We have issue #1346 so that we won't forget to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One small additional nit, but LGTM!
Co-authored-by: Erick <erickzanardoo@gmail.com>
Description
Components may be added into game tree out of order #1222: Main change is that the system now ensures that when components are added into the game tree, they will be always added in the order that the user requested. For example, if the user says
game..add(c1)..add(c2)
, then componentsc1
andc2
will appear in that order in game's children list, regardless of how long it took for them to load.New mixin
SingleGameInstance
allowsonLoad()
to be always called when the component is added to a parent, even if the parent is not mounted yet.Improving Flame testing by allowing users to wait for game to load #1335: Added
game.ready()
function, which can be awaited if you need to resolve all pending changes to the game tree (mostly useful for testing).Remove prepareComponent #1342: Lifecycle methods
prepare
andprepareComponent
were removed. Existing logic inprepare
can be merged withonMount
, and functionality ofprepareComponent
can always be replicated within theComponent
itself.Some of the functionality from
ComponentSet
was moved out into the_LifecycleManager
class. This has several advantages: first, theComponent
is no longer forced to carry temporary lifecycle queues forever, which reduces overall memory consumption; second, implementing alternativeComponentSet
s now becomes easier, as it is no longer required to cater to theComponent
s lifecycle peculiarities.From testing standpoint, the main difference is that now at least some game instance is required in each test which involves more than one component. The idiom
await game.ready()
can now be used to ensure that all components were fully mounted. In most cases it could replace thegame.update(0)
call, which is less reliable.Checklist
fix:
,feat:
,docs:
etc).docs
and added dartdoc comments with///
.examples
.Breaking Change
prepare()
/prepareComponent()
, which we believe to be extremely rare. But if you did, then the recommendation is to merge that functionality into theonMount
callback.Related Issues
Closes #1222
Closes #1293
Closes #1305
Closes #1335
Closes #1338
Closes #1342