ControlModule stops functioning when a script that requires it gets destroyed

If a script disables and then re-enables controls through the ControlModule and is later destroyed, the controls will no longer function for the remainder of the session or another script enables them again; the controls are essentially disabled once a script that modified them is destroyed.

Here’s a video demonstration:

Reproduction Steps (100% of the time for me on all platforms):

  1. Create a new LocalScript (any location where a LocalScript will run should work)
  2. Require the PlayerModule and call :GetControls() to access the ControlModule.
  3. Disable and re-enable the controls; :Enable(false), :Enable(true)
  4. Destroy the script.
  5. You’re no longer able to move :frowning:

In this place file, I’ve created a button which disables and enables controls as well as one to destroy the script. Follow these steps in the place to produce:

  1. Visit or Download:
    https://www.roblox.com/games/4920862742/Controls-Bug
    Player Controls Bug.rbxl (19.1 KB)
  2. Play
  3. Click the button to disable and re-enable the controls.
  4. Click the button to delete the script.
  5. The controls will no longer work for the remainder of the session, or until you reset (creates a new script so the buttons work again) and re-enable the controls from the button.

I’ve been able to reproduce this on:

  • MacOS Catalina
    Unable to control the character at all.

  • Windows 10 (Boot Camp) - Both Roblox Player & Roblox UWP App
    Unable to control the character at all.

  • iOS / Android (Bluestacks)

    • Dynamic Thumbstick
      Unable to move, can still jump.

    • Thumbstick
      Able to move & jump (unaffected)

    • Tap to Move
      Unable to move, can still jump.

    It’s possible to regain control by switching to any other movement type and back.

  • Xbox One S
    Unable to control the character at all

I first came across this bug a few days ago, but I’m assuming it’s been since the new Player Scripts were implemented due to multiple threads created with this problem (1, 2, 3, 4).

3 Likes

Has anyone been able to look into this?

I’d rather not be forced to revert to binding over the controls or forking the modules and fixing it myself; especially since these new Player Scripts were created so developers didn’t have to fork them to access basic functions like this.

I would tend to think this isn’t necessarily a bug, as when you Enable() you create fresh CAS binds
(which are ultimately put in place by your script, so if destroyed, those connections could close–
There may have been some changes at some point to reduce connection leaks.)
If you must use :Enable(false) I would suggest putting it in StarterPlayerScripts instead of
StarterCharacterScripts to prevent script destruction. If that’s not why the script is destroyed, then
I’d suggest reworking it so you can disable before destruction, and reenable in its replacement script.

1 Like

That’s fair, after some additional testing it seems that this is a thing with ModuleScripts themselves. After calling a function in a ModuleScript from LocalScript (like above) that creates a basic loop with some print statements, destroying the LocalScript stops the loop.

This is rather unfortunate as my use case was simply disabling controls during loading screen and then enabling them for the rest of session. Since I destroy the loading screen after use, the script controlling it goes as well which breaks the controls.

I think my best options would be either disabling & enabling controls from a separate script connected by BindableEvents or creating a temporary action over the control bindings with a higher priority to sink the inputs. I’ll likely do the latter since creating another script for this purpose seems pointless.

If anyone else has any input on this, I’m all ears.

Ah, what you can use to get around the ModuleScript thing, is to create a wrapper ModuleScript
for the ModuleScript that you want to make calls on–The trick is to put your needed ModuleScript
require and call(s) in the initial run part of the wrapper ModuleScript (and require the wrapper
ModuleScript in the script that gets destroyed.)
Since you are doing the controls enable thing once, I think this would be the ideal solution for your case.

1 Like