Assemblies with a ControllerManager get locally simulated for other clients when near other assemblies with different network owners

Currently, assemblies paired with a ControllerManager instance near other unanchored assemblies with different network owners (for example an assembly with an active ControllerManager instance assigned to Player1 as well as another similar assembly assigned to Player2) start to be simulated locally on clients who aren’t the network owners of such assemblies (for example Player2 locally gains ownership of Player1’s assembly when Player1’s assembly is idle). This issue occurs whenever the ControllerManager instance is not actively moving. It appears as if other clients (which do not have network ownership of the assembly) start to locally simulate the assembly whenever it is not moving (asleep?) which causes various issues due to differences in properties of the GroundController and ControllerPartSensor. The biggest issue with this is using custom methods of detecting the ground (ControllerPartSensor.UpdateType = “Manual”) which makes this issue especially visible since other clients don’t perform any sort of casting at all due to the "Manual" ControllerPartSensor.UpdateType and makes the ControllerManager instance completely unusable in multi-player games. Not only that, but the moment the assembly starts moving again, the assembly visually stutters for a moment (being woken up?) before no longer being locally simulated on other clients and behaving as expected, replicating the positions correctly from the true network owner.

This issue does not occur with Humanoid instances. Humanoids continue to be actively replicated despite being idle or not, which makes the experience a ton smoother and does not cause any weird physics syncing issues or visual stutters after inactivity.

The issue has been successfully reproduced both in studio and in game.
Cannot provide a timestamp of when the issue started happening, as today was the first time I’ve tested it in multi-player.

Video of the issue: https://youtu.be/3rf9MUuAHtc

System Information:
CPU: 11th Gen Intel(R) Core™ i7-11800H @ 2.30GHz
RAM: 32 GB @ 3200 MHz
GPU: NVIDIA GeForce RTX 3070 Laptop GPU
OS: Windows 11

Reproduction file: ControllerManagerReplicationPhysicsIssue.rbxl (65.6 KB)

Reproduction steps:
Open the attached file, head over to the “Test” tab, create a local server with 2 players and click start. The issue should be clearly visible. Pressing the spacebar applies an upwards force, which showcases the replication syncing up again. This issue can also be reproduced in solo play, the issue then appears in server view, however that is a little harder to reproduce as you need to position the propellers with the move tool just close enough to the player owned assembly to trigger the issue.

Expected behavior

Assemblies with a ControllerManager should continue to replicate the position from the actual network owner no matter the circumstances and not be locally simulated by clients without ownership of the assembly when near other assemblies with different network owners.

4 Likes

This is expected behavior since the ControllerManager does not force a network owner under the hood like Humanoid does. Instead, it has the same default behavior as all simulated assemblies/constraints, where ownership is set automatically, based on proximity. This is by design, to maximize flexibility and consistency.

You can force physics ownership yourself by calling SetNetworkOwner from the server. This will prevent ownership from ever being automatically assigned.
I added Character.Part:SetNetworkOwner(Player) to your script in the CharacterAdded callback and it looks like the issue was fixed.

@kleptonaut While it appeared to have solved the issue at an initial glance, it has not.
Video: https://www.youtube.com/watch?v=IIaBCo8xmK0

While the issue in the repro with the 2 players doesn’t seem to happen anymore (probably because both players are in the same CollisionGroup to prevent collision of them), it still has happened in my own personal project testing in-game with another player, as well as in the same repro file I included in my original post. The issue is not forcing ownership related. In the video I attached, it is visible that the server gains local simulation of the player’s character whenever the server-owned propeller is in really close range of the player despite explicit setting of :SetNetworkOwner(Player) to the player’s character in the server script, as you had suggested.

I might have a theory on why this is happening, however I’ll wait for a response first.

Hi, so we now have a better understanding of this bug, and have plans to address it as a part of larger physics networking changes coming in the next year - unfortunetely there is no quick fix, nor is this issue exclusive to the ControllerManager. But we do hope to get fixes here sooner than other networking changes, and we’ll be using your case to verify these.

You don’t see this happen with the Humanoid because Humanoids can never fall asleep.

The client is simulating themselves, and sending their results to the server. But when it falls asleep, it stops sending these updates, and the server will momentarily simulate the part non-authoritatively.

Since your custom sensor runs in a local script, the server doesn’t see a valid FloorPart, and therefore the GroundController is inactive and the part falls - and causing it to “wake up” on the server, and drop. This could happen with any physics simulation that depends on some script state which is only running on server or client. There should be a few workarounds, such as having a version of your sensor script run on the server as well, or using the script to ensure the player character never falls asleep.