-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Introduce common structure for key counters #22654
Conversation
To implement different different sources of input for KeyCounter, it is now possible to create a Trigger class (to inherit) instead of inheriting KeyCounter. This eases the creation of more input sources (like for tests) while allowing to implement different UI variants. That way, if another variant of the key counter needs to implemented (for whathever reason), this can be done by only inheriting KeyCounter and changing how things are arranged visually.
This allows for different layouts of display. Idk, maybe someone would want to mix both variants? (don't do this please). This commit is mostly prep for further changes.
This caused the Keyboard inputs to register twice, which is not what we want.
Makes it better to understand their purpose
I'm not too sure I understand why you've added non-action based key triggers. Before I begin to review, could you explain that? |
miss click was about to answer smh |
If you're talking about
osu/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs Lines 28 to 31 in 87901bc
osu/osu.Game.Tests/Visual/Gameplay/TestSceneKeyCounter.cs Lines 34 to 37 in 74e7cc2
Some other tests also had custom I hope I was clear enough, even though I thought this would be obvious to think about at first 74a58fb message is also relevant to look at. |
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.
First pass. Mostly examination of structure.
} | ||
|
||
protected virtual bool CheckType(KeyCounter key) => true; |
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 very weird. What is this for? As best I can tell it's to avoid mixing up key counters of different drawable implementations?
Hesitantly I'd suggest to make the class a generic (as in KeyCounterDisplay<TKeyCounter> where TKeyCounter : KeyCounter
) or something. I'm not sure it's ever going to be valid to mix these?
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 don't know what to do for this one, as I feel like there could be a lot of directions, but I don't know which one is the best.
From what I can learn from other generics in the codebase, I could separate the class into generic and non-generic base classes.
However, forcing the new implementations to inherit the generic base only is pretty impossible for this class, as making the constructor internal
on the non-generic has pretty much no effect since new implementations will essentially be created in the same assembly.
I could also just make the base class generic without splitting anything, but then it would mean that every occurrence of KeyCounterDisplay
would have to be replaced with KeyCounterDisplay<KeyCounter>
, and I don't know if it's okay to do that (especially for variable declarations).
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.
Why does the check even need to exist?
`IsCounting` is back being an auto-property. `countPresses` is now encapsulated and being exposed as an `IBindable<int>` via `CountPresses`
As for the second suggestion in ppy#22654 (comment), I went with the first one as only one Trigger actually uses this argument for rewinding.
All issues have been addressed (hopefully). |
public abstract void AddTrigger(InputTrigger trigger); | ||
|
||
public void AddTriggerRange(IEnumerable<InputTrigger> triggers) => triggers.ForEach(AddTrigger); | ||
|
||
public override void Add(KeyCounter counter) | ||
{ | ||
if (!checkType(counter)) | ||
throw new InvalidOperationException($"{counter.GetType()} is not a supported counter type. (hint: you may want to use {nameof(AddTrigger)} instead.)"); | ||
|
||
base.Add(counter); | ||
counter.IsCounting.BindTo(IsCounting); | ||
} |
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 started to apply some final cleanups to this pull but this is where I get stuck. Why is this here still? As in, why is any subclass still allowed to arbitrarily try and add any KeyCounter
if the type isn't matching?
Like this is so weird for me, because KeyCounterDisplay
is apparently a Container
, but then DefaultKeyCounterDisplay
is setting InternalChild
anyway, and thus is just nullifying the fact that its base class is a container.
I would like to see the process of creating the individual key counters and placing them in the key counter display's layout entirely encapsulated within the key counter display, because it shouldn't ever make sense to mix and match key counter implementations. It should be fundamentally impossible to misuse the component. This would be done by making KeyCounter
a plain CompositeDrawable
, with the expectation that implementors of AddTrigger()
should in response create the KeyCounter
they want and place it in the layout of the key counter display according to expectation.
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 did consider guarding against this further but wasn't sure it was worth the effort. Don't disagree with direction though.
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.
That said, I did initially try to refactor to a CompositeDrawable
but it gets messy since CompositeDrawable
doesn't support Content
overrides.
As can be seen by 44297a7.
So I'm not 100%, see what you think I guess.
/// <summary> | ||
/// The <see cref="KeyCounter"/>s contained in this <see cref="KeyCounterDisplay"/>. | ||
/// </summary> | ||
public abstract Container<KeyCounter> Counters { get; } |
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 being a Container<KeyCounter>
again means the last 3 commits actually changed nothing in the state of affairs, because if it's exposed as a container, then you can add anything you like again through it.
Can we revert 5d15426? I was honestly quite fine with the IEnumerable<KeyCounter>
. I don't find it at all messy. The only consumers of this property are: test scenes, and RulesetInputManager
. It's very contained.
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.
The purpose of that commit was to fix this
https://github.com/ppy/osu/actions/runs/4360048022
Does that mean that I need to remove the checks for the counter flows visibility in TestSceneHUDOverlay
? This is the only way I see to solve the failures (plus I think that this check will most likely be irrelevant as new variants get implemented)
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.
How does changing that from IEnumerable
to Container
fix test failures? That's an alarm bell if you ask me. Just changing the returned type fix it? Can you explain why?
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.
Because of this??
private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First(); |
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.
Actually the more I look into it, the more the failure feels weird to me [the failures]
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.
Well this is where I would just fix the test to not use .ChildrenOfType<>()
. But maybe it's just me.
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'll get into this later, I'm really not focused right now.
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've pushed a potential fix. Tbh I'm a little bit lost rn so I don't know if this fix is heading towards a right direction, sorry.
As suggested by bdach as this would make the last two commits useless Refs: 5d15426
@@ -43,7 +42,7 @@ public partial class TestSceneSkinnableHUDOverlay : SkinnableTestScene | |||
|
|||
// best way to check without exposing. | |||
private Drawable hideTarget => hudOverlay.KeyCounter; | |||
private FillFlowContainer<KeyCounter> keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType<FillFlowContainer<KeyCounter>>().First(); | |||
private Drawable keyCounterFlow => (Drawable)hudOverlay.KeyCounter.Counters; |
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 the dodgiest code I've seen in a long time. To the point my brain has trouble comprehending how it even compiles..
I've pushed remaining menial fixes. Kinda done with this PR at this point so going to go ahead with the merge. Any further changes can be applied in a new PR. |
Supersedes #22640
I decided to split the abstraction and the new design implementation as suggested in #22640 (comment)
This PR abstracts the
KeyCounter
andKeyCounterDisplay
in order to simplfy the implementation of more designs.This also simplifies the creation of more input triggers for the
KeyCounter
s to react to.Some commits have extended messages, in case the diff is too messy to understand anything.
Most of these commits were just cherry-picked from #22640