Summary
I think this issue only affects inputs of the “Standard Action” Category and their Creative Input Action equivalents.
The issue occurs when you register a player to an input_trigger_device “A” (does not matter if "Consume Input” is enabled or which input it uses) and afterwards(while still being registered device A) register the player to another input_trigger_device “B” which has “Consume Input” activated and an Input Action of the “Standard Action” Category(or a Creative Input Action equivalent) configured.
If you now unregister the player from device “B” (the one with the Standard Acton Input), the input will stay blocked, as if it would still be consumed by the device. Though no input events are triggered anymore by the device, which indicates that the player is indeed unregistered from it.
The only thing that fixes the issue is (as odd as it sounds) unregistering the player from device “A”. After unregistering from device “A” the broken input will work again.
Now it gets even more odd:
When registering to device “A” again, the input that is configured in device “B” will again be unusable. And that occurs even without registering the player to device “B” now.
In fact, registering to any other input_trigger_device will from now on render the input that is configured in device “B” unusable.
Please select what you are reporting on:
Unreal Editor for Fortnite
What Type of Bug are you experiencing?
Devices
Steps to Reproduce
- Add two input_trigger_devices and name them “Input_A” and “Input_B”
- Set the “Registered Player Behaviour” in both devices to “Require Registered”
- Set Input Type of Input_A to “Creative Input Action” and the “Creative Input” to “SwapQuickbar”(can be any, just not the same as the input of Input_B)
- Set Input Type of Input_B to “Standard Action” and the “Standard Input” to “Crouch”
- Activate “Consume Input” in Input_B
- Create a new verse class and paste into it the content found in “Additional Notes” below
- Compile Verse and add the new device to your Level
- Click on the Device in the Level and set Input_A to your “Input A” device and “Input_B “to your Input_B device
- Launch the Session
- Observe the Output Log and wait until it says, “Binding Players to Input B!”
- Now press the Crouch button (or the one you configured) and observe, that the Input Events will be correctly printed to the screen.
- Now wait until it says, “Unbinding Players from Input B!” and “INPUT OF INPUT B IS NOW UNUSABLE!”
- Observe that pressing the crouch button does nothing now
- Wait until it says, “Unbinding Players from Input A!” and “INPUT OF INPUT B IS NOW USABLE AGAIN!”
- Observe that you can now use the crouch button again to crouch
- Wait again until it says, “Binding Players to Input A!” and “INPUT OF INPUT B IS NOW UNUSABLE!”
- Observe that the Crouch button is now again unusable, although you are only bound to the Input A device
Expected Result
Unregistering from a input_trigger_device should always make the button usable again
Observed Result
Unregistering from an input_trigger_device renders a button useless in the described scenario
Platform(s)
Tested on PC and Playstation 5
Additional Notes
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Simulation/Tags }
input_debugger_device := class(creative_device):
@editable
Input_A:?input_trigger_device = false
@editable
Input_B:?input_trigger_device = false
OnBegin<override>()<suspends>:void={
if(TriggerA:=Input_A?){
Print("Subscribed Events of Input A!")
TriggerA.PressedEvent.Subscribe(OnFirstInputPressed)
TriggerA.ReleasedEvent.Subscribe(OnFirstInputReleased)
}
if(TriggerB:=Input_B?){
Print("Subscribed Events of Input B!")
TriggerB.PressedEvent.Subscribe(OnSecondInputPressed)
TriggerB.ReleasedEvent.Subscribe(OnSecondInputReleased)
}
if(Input_A? or Input_B?){
Print("Starting Debug Routine!")
spawn{DebugRoutine()}
}
}
DebugRoutine()<suspends>:void={
Sleep(5.0)
var FirstLoop:logic = true
loop:
if(TriggerA:=Input_A?){
Print("Binding Players to Input A!")
for(Player:GetPlayspace().GetPlayers()){
TriggerA.Register(Player)
}
if(not FirstLoop?){
Print("INPUT OF INPUT B IS NOW UNUSABLE!")
}
Sleep(5.0)
}
if(TriggerB:=Input_B?){
Print("Binding Players to Input B!")
for(Player:GetPlayspace().GetPlayers()){
TriggerB.Register(Player)
}
Sleep(5.0)
Print("Unbinding Players from Input B!")
for(Player:GetPlayspace().GetPlayers()){
TriggerB.Unregister(Player)
}
if(FirstLoop?){
Print("INPUT OF INPUT B IS NOW UNUSABLE!")
}
Sleep(5.0)
}
if(TriggerA:=Input_A?){
Print("Unbinding Players from Input A!")
for(Player:GetPlayspace().GetPlayers()){
TriggerA.Unregister(Player)
}
Print("INPUT OF INPUT B IS NOW USABLE AGAIN!")
Sleep(5.0)
}
set FirstLoop = false
}
OnFirstInputPressed(Player:agent):void={
Print("Input A pressed!")
}
OnFirstInputReleased(Player:agent,Duration:float):void={
Print("Input A released after {Duration} seconds!")
}
OnSecondInputPressed(Player:agent):void={
Print("Input B pressed!")
}
OnSecondInputReleased(Player:agent,Duration:float):void={
Print("Input B released after {Duration} seconds!")
}