-
Notifications
You must be signed in to change notification settings - Fork 419
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
Sync initial input state of PassThroughInputManager
from parent
#6398
base: master
Are you sure you want to change the base?
Conversation
I don't have the mental willpower to face this head on right now but this is like the fifth change touching this class in a super specific manner and when I read "double schedule" I just recoil. There has to be a better way to do this. I refuse to accept that this is the best that can be done. |
Really it's just being adjusted inline with user expectations. I'm pretty sure I said this before, but this class's first-and-foremost usage is gameplay, it's barely used anywhere else.
What do you generally expect when you use schedule basically anywhere? It schedules to next frame, right? This is not the case in
If this refers to touching the class in general, you can't really expect me to define any other place to store the content of Unless you want me to look at the entire issue from a very different perspective where I can make this somehow work without doing this "initial input state sync" logic, at which point I don't know. |
Shouldn't be in framework then should it? Why are we justifying framework changes by specific game usage scenarios? Bit backwards isn't it? I dunno. Rather than making the hyperspecific scenarios work the framework component should provide usages with the tools to implement desired behaviours themselves, if possible. |
Is there a reason we haven't just made Or expose some sort of |
Signaling a parent input manager to resync input when a key binding container is loaded feels very backwards to me. I'm personally quite anxious from attempting to Going by what @bdach stated above, I can go for exposing a general diff --git a/osu.Framework/Input/PassThroughInputManager.cs b/osu.Framework/Input/PassThroughInputManager.cs
index 3112b4045..e2cbb6f1c 100644
--- a/osu.Framework/Input/PassThroughInputManager.cs
+++ b/osu.Framework/Input/PassThroughInputManager.cs
@@ -42,10 +42,7 @@ public virtual bool UseParentInput
useParentInput = value;
if (UseParentInput)
- {
- syncReleasedInputs();
- syncJoystickAxes();
- }
+ Sync(SyncBehaviour.ReleasedInput);
}
}
@@ -56,10 +53,6 @@ protected override void LoadComplete()
base.LoadComplete();
parentInputManager = GetContainingInputManager();
-
- // allow a frame for children to be prepared before passing input from parent.
- // this is especially necessary if our child is a KeyBindingContainer since the key bindings are not prepared until LoadComplete is called on it.
- Schedule(() => Schedule(syncInitialState));
}
public override bool HandleHoverEvents => parentInputManager != null && UseParentInput ? parentInputManager.HandleHoverEvents : base.HandleHoverEvents;
@@ -184,16 +177,23 @@ protected override void Update()
// There are scenarios wherein we cannot receive the release events of pressed inputs. For simplicity, sync every frame.
if (UseParentInput)
- {
- syncReleasedInputs();
- syncJoystickAxes();
- }
+ Sync(SyncBehaviour.ReleasedInput);
}
/// <summary>
- /// Syncs initial state of this input manager to the current state of the parent input manager.
+ /// Syncs the state of this input manager to the current state of the parent input manager, according to the given <paramref name="behaviour"/>.
/// </summary>
- private void syncInitialState()
+ protected void Sync(SyncBehaviour behaviour)
+ {
+ if (behaviour == SyncBehaviour.PressedInput)
+ syncPressedInputs();
+ else
+ syncReleasedInputs();
+
+ syncJoystickAxes();
+ }
+
+ private void syncPressedInputs()
{
if (parentInputManager == null)
return;
@@ -277,5 +277,11 @@ private void syncJoystickAxes()
}
}
}
+
+ protected enum SyncBehaviour
+ {
+ PressedInput,
+ ReleasedInput,
+ }
}
} diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs
index 31c7c34572..adec23b097 100644
--- a/osu.Game/Rulesets/UI/RulesetInputManager.cs
+++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs
@@ -75,6 +75,15 @@ private void load(OsuConfigManager config)
tapsDisabled = config.GetBindable<bool>(OsuSetting.TouchDisableGameplayTaps);
}
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ // allow a frame for children to be prepared before passing input from parent.
+ // this is especially necessary if our child is a KeyBindingContainer since the key bindings are not prepared until LoadComplete is called on it.
+ Schedule(() => Schedule(() => Sync(SyncBehaviour.PressedInput)));
+ }
+
#region Action mapping (for replays)
public override void HandleInputStateChange(InputStateChangeEvent inputStateChange) Does that sound more fathomable? |
Can you explain how it's better to let user code arbitrarily handle this themselves with two schedules? This looks like a workaround - if another o!f user does the same thing what do we say "yeah just schedule your thing 2 frames into the future because reasons". |
If that question is directed at me then I agree it's not. I can't give a counterproposal at this stage because I'd basically have to go revisit every single passthrough input manager change from the past year and rethink the entire thing from scratch. The diffs keep getting more and more cursed but issues still continue to pop up. From a high level view that does not bode well for this code as far as I'm concerned. |
Was directed at frenzi's latest diff. At least the PR's code is contained within o!f, but with that diff it's slipped to being handled partially at osu!'s end. Both are cursed, I absolutely agree with @bdach . For me, the part that really sucks is that the schedules are arbitrary done because children are loaded at some later point in time, so this PR will immediately break as soon as that becomes not the case. Oh, what's that -- a That's why I suggested |
It's not really some later point in time, and this is not a 2 frame schedule. If the child is asynchronously loaded then I don't think it's the input manager's concern to try and make sure input is synced after that time, neither do we have actual use cases for that? Again, this is a single frame schedule, but because it's done in If everyone agrees to the idea of triggering a parent input manager resync from a child key binding container, then...sure, I guess. |
|
||
// allow a frame for children to be prepared before passing input from parent. | ||
// this is especially necessary if our child is a KeyBindingContainer since the key bindings are not prepared until LoadComplete is called on it. | ||
Schedule(() => Schedule(syncInitialState)); |
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 quite understand the part where you're saying the "second schedule is only required due to being called in LoadComplete
" – can you elaborate on that?
The double-schedule is ugly, but mandatory to ensure the syncing process does not apply until the entire drawable hierarchy contained by the input manager is loaded / ready to handle input via event handlers.
While it's somewhat obvious, note that scheduling twice inside a
LoadComplete
means to execute in the next update frame rather than the current one, sinceLoadComplete
comes before updating the scheduler in the current update frame (see this).