Character input controller tracking its activeController incorrectly

Reproduction Steps
If required too early, the default character controller has a chance to have an incorrect activeController, and inputs are broken (race condition on character?). This results in things like calls to GetMoveVector failing to return correct values, and it can break player movements.

I don’t really understand the root cause of why this happens, but I tried to diagnose it.

When testing, there were sometimes two different instances of the Keyboard module, both with enabled = true. One was bound to inputs, the other was set to the activeController and was not bound to inputs. Reading the logic, this doesn’t make sense.

Semi-related feedback: The humanoid (and character) should not be required by input modules to function imo, as far as I could tell, none of them use it and this is the real cause, only the main controller module does to call Move and such, but I am implementing my own controls on top. It means they have to wait for the character and wait for the humanoid, but, I don’t need a humanoid, so why wait for one to call Move?


(Crude) Steps to reproduce:

  1. Enter a LocalScript which outputs the activeController's table address in StarterPlayerScripts like so (for easy identification):
local PlayerModule = require(script.Parent:WaitForChild("PlayerModule"))
local controls = PlayerModule:GetControls()

while true do
	task.wait(0.1)
	print(tostring(controls.activeController))
end
  1. Play in Studio
  2. Add a logpoint in the controller in its update function(s). Example: In the Keyboard module on line 74 (Keyboard controls activated)

    image
  3. Press some keys and compare the results

Expected Behavior
The activeController should be the same as the controller that has inputs bound.

Using above repro steps this is a correct output:
image

Actual Behavior
The activeController which has its keys bound is stale.

Using above repo steps this is an incorrect output (activeController is stale along with the data from it e.g. ControlModule:GetMoveVector())

Modified version with expanded tables:

Top and bottom are from the example script modified to print the table directly with the address, the middle is from an input, coming from a breakpoint on line 74 of the Keyboard module.

The character did not exist initially when requiring the PlayerModule module

Workaround
Forcefully setting the LocalPlayer’s Character or waiting for their character to load before requiring PlayerModule appears to resolve the issue.
Does not, just makes it less frequent.

Annoying workaround for GetMoveVector:

local humanoid = character:FindFirstChildWhichIsA("Humanoid")
humanoidMoveDirection = humanoid.MoveDirection

Issue Area: Engine
Issue Type: Other
Impact: Moderate
Frequency: Sometimes
Date First Experienced: 2022-02-13 10:02:00 (-05:00)
Date Last Experienced: 2022-02-13 00:02:00 (-05:00)

4 Likes

Thanks for the report! We’ll follow up when we have an update for you.