RobustToolbox icon indicating copy to clipboard operation
RobustToolbox copied to clipboard

Clientside physics fix

Open MLGTASTICa opened this issue 3 months ago • 4 comments

Client-side physics would become wildly inconsistent with server-side physics due to the following reasons

  1. Prediction runs them without properly resetting positions (they are client-side so they don't even need prediction, and trying to run them without Predict set to true wouldn't work)
  2. Lerp interjects in the client-side physics sub-ticks by modifying the xform's local position , causing the position-delta to be erronous when applied(thus reducing how far the object actually travels by up to a third)

This PR patches the engine side of the issue , content-wise on the standard wizard's federation codebase , the only system that interferes with proper client-side prediction is the TileFrictionController. Once disabled or overhauled , the states match almost identically (barring high client CPU usage that might cause the client-side sim to fall behind)

MLGTASTICa avatar Sep 17 '25 20:09 MLGTASTICa

I have to think about it a bit, but I'm pretty sure lerping client-side physics entities should be fine, and is something we want, because physics updates can still happen a lot slower than frame updates and you don't want to visually see the entities moving around at 30/60tps when rendering at 120fps. If its currently broken for whatever reason, it should be fixed and not just disabled.

I'm also not sure whats happening with the other change. Entities shouldn't be getting predicted unless something sets PhysicsComponent.Predict to true. So your change should only be doing something if something else is actively trying to make client side entities predicted, so wouldn't it make more sense to turn that off instead?

As to how client-side physics entities should behave (though they currently don't), I'd expect that they would need to have prediction enabled and should reset & get re-predicted alongside any other networked & predicted physics entities. But resetting them just isn't supported yet, but it probably wouldn't be too much work.

ElectroJr avatar Sep 19 '25 02:09 ElectroJr

I have to think about it a bit, but I'm pretty sure lerping client-side physics entities should be fine, and is something we want, because physics updates can still happen a lot slower than frame updates and you don't want to visually see the entities moving around at 30/60tps when rendering at 120fps. If its currently broken for whatever reason, it should be fixed and not just disabled.

I don't know how to fix LERP(as of now). Its implementation seems to be reliant on server-states, because locally it sets the positions of entities , so it couldn't be correct for any physics solving unless it is all ran on the server where the physics position is not shifted. Every tick that runs LERP , runs off the wrong positions.

I've looked deeper into this and tried to force the TransformSystem client-side to set all positions to the next-position with no lerp when the physics BeforeSolveEvent is called, this mostly fixes the issue with client-side zooming way past but the states are still not consistent overall.

I'm also not sure whats happening with the other change. Entities shouldn't be getting predicted unless something sets PhysicsComponent.Predict to true. So your change should only be doing something if something else is actively trying to make client side entities predicted, so wouldn't it make more sense to turn that off instead?

Client-side physics are always assumed to be predicted, I initially tried to make it so the first prediction tick is not considered so , but such results in wonky differences between server & client. Client-side entities don't need prediction, there is no server to predict against, physics run the same in prediction & non prediction. The only difference is how body Sleeping is handled (which can't run in prediction)

As to how client-side physics entities should behave (though they currently don't), I'd expect that they would need to have prediction enabled and should reset & get re-predicted alongside any other networked & predicted physics entities. But resetting them just isn't supported yet, but it probably wouldn't be too much work.

I've looked a lot at how physics handles, i haven't found anything that actually resets physics positions. My current belief is that the "reset" is actually server-side transform states.

MLGTASTICa avatar Sep 19 '25 07:09 MLGTASTICa

I don't know how to fix LERP(as of now). Its implementation seems to be reliant on server-states, because locally it sets the positions of entities

Lerping shouldn't change the final positions of entities. All it should do is record the position of an entity at the start & end of a tick via PrevPosition and NextPosition in TransformComponent. Then while rendering frames, TransformSystem.FrameUpdate should interpolate between those values. The local position at the end should match NextPosition, which should've been the position at the end of the game tick.

But it seems like maybe that doesn't actually work like that, and that just hasn't been a problem for networked entities as their positions get reset anyways. So that should be fixed instead of disabling client side lerping. I.e., something probably needs to run after the last frame has been rendered to make sure all client side entities are actually at their final positions, and not at some interpolated value somewhere in between.

Client-side physics are always assumed to be predicted

I initially misread the change you were making to Solve() as trying to conditionally disable prediction for client side ents, not the other way around, sorry about that confusion. Though the point still stands that this should be done by setting PhysicsComponent.Predict instead of adding that check. So either in engine in UpdateIsPredicted() or in content somewhere by subscribing to the UpdateIsPredicted event. And if its in engine, it should probably be a cvar so that content can disable it.

Client-side entities don't need prediction, there is no server to predict against, physics run the same in prediction & non prediction.

The issue is that these client side entities are interacting with entities that are predicted. I guess it depends on what you're actually trying to do, but if you want to handle mispredicts properly you need to be able to reset the entity and re-predict it alongside the other predicted entities. But maybe its not required for whatever it is you want the client side entity to do? I guess supporting that is probably quite hard and not worth the effort unless its needed.

I've looked a lot at how physics handles, i haven't found anything that actually resets physics positions. My current belief is that the "reset" is actually server-side transform states.

Yes, prediction resetting is all done via networked component states. Resetting client side entities isn't currently supported and I don't know how to go about adding it. So if its not needed it'd be better to just deal with mispredicts

ElectroJr avatar Sep 28 '25 08:09 ElectroJr

Bump. Has this been thought about more ?

MLGTASTICa avatar Dec 08 '25 14:12 MLGTASTICa