Humanoid.SeatPart sometimes set on server or client even though Humanoid is not seated anymore

Hello,

In recent months, we have received many bug reports in which users in our game Emergency Hamburg could not enter vehicles and equip tools (except the phone) after doing stuff involving vehicles.

After testing, we suspected it was due to SeatPart not being set correctly, as Humanoid.SeatPart being set while the Humanoid is not seated would exactly cause these issues.

We have now found a replication, which most often only works in Roblox Studio though, but I have some screenshots that show the issue.

In Emergency Hamburg Roblox Studio:

  1. Press play and locate your car.
  2. Enable a network delay tool like clumsy.
    Filtering: “inbound or outbound”
    Functions: Drop and Throttle Enabled (Default Settings are fine)
  3. Enter a vehicle seat repeatedly after jumping (Press Space and immediately after that press E) until it isn’t possible anymore.

If the “Seat” Prompt disappears, SeatPart is set incorrectly on the Client.
If the prompt is visible, but the interaction doesn’t work, it’s set incorrectly on the client.

In the following screenshots i was able to replicate the bug:

On this screenshot, you can see SeatPart is correctly set to nil on the Client:

On this screenshot, you can see that SeatPart is incorrectly set on the Server.:

Seat.Occupant and Seat.GetPropertyChangedSignal(“Occupant”) still works correctly even if SeatPart is incorrect on the character.

The issue with SeatPart being set incorrectly can happen both on the client and on the server; In our bug reports, it was most often set incorrectly on the server.

This issue seems to happen to players mostly with a bad internet connection, however, it leaves them in a soft-locked state and requires them to rejoin as vital game mechanics stop working, so I hope for a fast fix.

Let me know if you need any additional information.

Thanks!
~ Felix

5 Likes

Thank you for the report and for the details on how to repro. Using our own placefiles and seats we are unable to repro - would it be possible for you to DM me a minimal placefile which contains just enough to reproduce the issue? Is the vehicle seat the only part that is needed?

Thank you!

Hi,

Unfortunately, I was not able to create a working reproduction place. The issue is rare and depends on network factors that don’t really exist on empty place files.

With the two screenshots I submitted, it’s pretty obvious that the SeatPart property gets out of sync. My game code could not cause this, as SeatPart is a read-only property.

I also don’t know which factors play into the fact that the property gets out of sync. Our game systems have additional functionality regarding vehicle seats, including calling Humanoid:SetState(“GettingUp”) when jumping in a vehicle seat to stop the jump animation as well as teleporting the player out of the vehicle once they are unseated.

With clumsy or another network delay tool in studio (50% Drop, 50% Throttle Rates work best for replication) you could easily replicate the issue in 10-15 minutes in our experience, let me know if you need access via dm.

Thanks!
~ Felix

1 Like

Hello, Felix!

Try flipping this flag and let me know what happens: WaitForSeatWeld

A few of my players have been reporting this recently in my game too. Seems to be also caused by network delays/lag as the OP mentioned, and the issue is identical to the original post where the SeatPart does not get set to nil properly when a player has left a seat.

My seats don’t have any ProximityPrompts or any code associated with sitting players in them, players just sit in them by walking over the SeatParts.

The “workaround” my players report is to just sit in another different seat then jump out of it, which seems to re-sync the property and fix their issues.

How do I go about changing that flag?

Hi!

Sorry for the late response;

Can you explain how to flip a flag? The methods described in this devforum post Fast Flags ClientAppSettings.json Folder Locations for most OS, e.g. Windows, MacOS, Android and iOS do not seem to work anymore for windows, and the StudioAppSettings.json file resets everytime i open studio.

Thanks!
~ Felix

Make sure that the JSON is right. It should still work on Windows. I updated the location for iOS, because that one changed.

We’ve began experiencing this issue on Emergency Response: Liberty County. We’re able to reproduce this bug consistently in studio (and in live game) without simulating latency.

This is a critical, game-breaking bug. We have logic to prevent players from getting damaged when they’re in vehicles, so when this bug occurs, players are immune to damage. – For that reason, I’d like to keep the repro steps private, but I’m more than happy to provide details and reproduction steps in DMs.

Thanks! Hope this can get fixed expeditiously.

I’d like to clarify that we’re experiencing an issue where the SeatPart is correct on the client, but is not correct on the server. (SeatPart is not set to nil on server after exiting seat.)

That said, there are others experiencing the inverse, where after exiting, the SeatPart is not set to nil on the client, but is correctly set on the server. I’m able to reproduce this bug by putting the character into the seat via vehicleSeat:Sit(...) and immediately removing the SeatWeld.

local seatPart = [vehicleSeat]
local player = [localPlayer]

seatPart:Sit(player.Character.Humanoid)
seatPart:WaitForChild("SeatWeld"):Destroy()

I’m still looking into finding out exactly what is causing the server issue… Would love any insight.

ER:LC Repro Steps

These are the reproduction steps that work for ER:LC – these steps don’t seem to work on an empty baseplate. I’m assuming it has to do with server load OR interaction with another system.

After playing around with this for several hours, I’ve come up with minimum reproduction steps to break Humanoid.SeatPart on the server. – This bug occurs when the player is put into a seat via VehicleSeat:Sit(...) while their humanoid is in Physics state.

You can reproduce this by setting the humanoid state to Physics, putting them into the seat, setting the humanoid state to GettingUp, and then using space/jump to get out of the seat. After you do this, you will be removed from the seat, but Humanoid.SeatPart on the server will not be set to nil.


Universal Repro Steps

SeatBugRepro.rbxl (69.4 KB)

After CONTINUING to play around with this on an empty baseplate, I’ve come up with some pretty sketchy reproduction steps to break Humanoid.SeatPart on the server. – I’m able to reproduce this when doing three things simultaneously:

  1. Rapidly iterate humanoid state between GettingUp & Physics.
  2. Rapidly call :Sit() on a seat.
  3. Simultaneously touch a bunch of other seats.

I wish I had more straight-forward reproduction steps, but this was a shot in the dark and just so happened to work. It might take 1-2 extra tries to reproduce, but I’ve had pretty good luck with it on the first or second try.

2 Likes

I’m catching up on this thread, and will be taking a look at this issue. I’ll keep everyone posted when any updates.

Man, this one was a doozy. I think I’ve discovered a few things that may answer some questions, but I’m still unsure about OP’s original report.

@crywink I’ve been playing with your repro file specifically, and this is what I’ve discovered. I may be wrong, but I believe your sequence of commands to thrash the humanoid state is bound to run into broken behavior because of how it’s handling (or perhaps, not handling) the Physics state. Take a look at this, specifically the row for the Physics state.

This state has to be set and unset manually using Humanoid:ChangeState().

As it is currently, the thrashing attempts to transition the humanoid state from Physics to Seated without using Humanoid:ChangeState() to first unset the Physics state. That being said, I naively added a few lines to the script just to see what might happen, like so:

setState("Physics")    -- manually set Physics state
task.wait(.025)
setState("GettingUp")  -- manually unset Physics state
task.wait(.025)
sit()
task.wait(.025)
setState("GettingUp")

After a little bit of testing, it seems like I don’t get stuck in the desync-ed state, where client and server don’t agree on the SeatPart. Granted, because the buggy behavior is somewhat flaky and sometimes hard to reproduce, this isn’t a conclusive test. But, at least I seem to get better behavior, and haven’t hit the dsesync-ed state (so far).

Mind giving that a go on your end just to see?

1 Like