Looking for help with smooth multiplayer interpolated movement

idk, transpile it to javascript using the typescript compiler and replace imports with const { mod1, mod2} = BABYLON

there are several strategies i think, each with different tradeoffs, i think the term you’re looking for smoothing on the client is “client side prediction”

here is another 2d example illustrating that concept alone
.GitHub - bytezeroseven/client-side-prediction: Client side prediction and server reconciliation implementation with a little anti speed hack thingy.

one tradeoff i think is how many snapshots you take, like 1, 3, or 5 and the ms between each frame. trading smoothness for bandwidth and latency. not sure if thats completely accurate, but something along those lines. in the case of client side prediction, you first predict , but you still have to wait on the server to send the truth, then reconcile that with the prediction. if they match perfectly, there wont be any jank, but of course, there will be a little. i think that’s the little jank you’re seeing in rag’s demo. i believe widening the frame to 3 helps fix this, but requires more bandwidth and adds a frame of ms to player ping. there’s a lot of good gdc talks too

SHIT… I STILL GET JITTER

I tried the GitHub - virbela/buffered-interpolation: A class for interpolation of position, rotation, and scale for networked BabylonJS objects. library for moving the transform and its the same jitter.

What in the entire heck ???

No, it finds two states to interpolate between - some time in the past. This is done, so in case of a missed or late update, you, usually, have enough states to interpolate

There is certainly jitter present. And no, there shouldn’t be. Must be an issue somewhere in the code. We interpolate between two known states, so I don’t quite see how it can jitter in such a manner. It could potentially be the frame jitter caused by the fixed loop, but in that case, it shouldn’t exceed the jitter of the “server” mesh.

Using a timestamp is easier. Normally you would pack all your messages/states into a single serialized packet, and only send one 8 byte timestamp and use that for all entities, events etc.
In your case, you’ll need clock synchronization to get the client clock as close to the server clock as possible. If you only need to network a kinematic physics body, you don’t really need to sync, but if you want to network an actual deterministic physics simulation or events, you’ll need to sync client and server. I haven’t done clock sync before, but I am doing tick sync instead.
I have based my approach on what Overwatch does. I first synchronize the initial tick, then I speed up or slow down the client simulation based on whether I’m ahead or behind the server. This is done in order to fill or empty the input buffer on the server. You want the server to receive inputs right about when it’s needed+some jitter buffer based on client network stability.
An example is this, for three frames on the client, you apply three different inputs [left, forward, right]
Frame1, input1: body.setVelocity(-5,0,0)
simulate()
Frame2, input2: body.setVelocity(0,0,5)
simulate()
Frame3, input3: body.setVelocity(5,0,0)
simulate()
This puts you at (0,0,5)
But if the server receives and applies all three at once, it will look like the following:
Frame1, input1: body.setVelocity(-5,0,0)
Frame2, input2: body.setVelocity(0,0,5)
Frame3, input3: body.setVelocity(5,0,0)
simulate()
And puts you at (5,0,0)
Resulting in having to correct this error at the client.

Take a look at the following thread: https://www.gamedev.net/forums/topic/696756-command-frames-and-tick-synchronization/
And some code: GitHub - minism/fps-netcode: Quake-style multiplayer FPS demo that integrates a number of modern netcode techniques for quality of gameplay.

This is the “modern” approach to networking, made popular by Overwatch and Rocket League.
I have based my netcode on this, and on a stable connection I have a completely deterministic networked physics model. Even on less stable networks, within a short time span, the simulation is back at sync. Bad networks usually get a slightly(growing) bigger jitter buffer

This might not be what you’re after, at all, but it’s simple to implement, and works very well.

1 Like

I keep pitching for us to use a deterministic model but it keeps getting pushed back on by the team.

Ill hit you up today Mackey and see if there is anything obvious that might be missing or off.

1 Like

Are you kidding me, Where in the XXXX was that.

Lawl.

No matter how hard you google, there will always be a search term that you missed, at least that’s how it’s been for me.

1 Like

Okay, it wasn’t a coding error on my part(Bet there are, but this wasn’t the issue). The fixed loop adds a little bit of jitter, which can be countered with the frame interpolation from the other thread. The real issue here seemed to come down to tuning.
If the server sends out updates every 100 ms, we need to grab the two states At Least 200 ms in the past. 100 ms per state + our latency. Another issue is the circular motion of the animation. If you start plotting points around a circle, you’ll get get that round saw pattern that the jitter displays. You wont normally see a player run around in perfect circles, but the way to counter it, is finding a blend between update rate and how far back in time you go.
You often see action games run at higher Hz than 10.

Here’s a visualization of the issue, by sending states at 5Hz(200 ms) with a latency of 100 ms and interpolation delay of 400:

Compared to sending states at 20Hz(50 ms) with the same latency and interpolation delay of 100 ms

Much smoother. The more time between server authoritative updates, the farther back in time you need to go in order to get two valid states(no surprise). The more updates the server sends, the more precise of an interpolation you’ll get, which again, should come as no surprise.
20Hz seems enough for even a circular path, which linear interpolation doesn’t handle too well. And this is even low for most action games like FPS- and racing games.

2 Likes

Edit: OK… I am officially back in it.

So i am using this library GitHub - virbela/buffered-interpolation: A class for interpolation of position, rotation, and scale for networked BabylonJS objects. as the default interpolation method.

So you have three interpolation modes to choose from using my Network Entity Script Component:

  • None (Snaps to positions)
  • Default (Buffer interpolation library)
  • Custom (You can register an interpolation handler and write your own custom interpolation as well as any other client side prediction algorithms you like for your project)

I am STILL messing around with the additional client side smoothing, like maybe smooth follow ghost network target positions, or something like that… maybe a MOVE TOWARDS the new interpolated target position… Something :slight_smile:

2 Likes

to use UDP instead TCP, UDP is more faster, greetings
if you need help about it, write me, (i not use NPM to front, only to back)

Using caddy or nginx with http3 is a new easy option. Dotnet msquick and netty (jvm) and openlitespeed also have support for http3. I had issues with geckos both v1 and v2. The geckos bindings require openssl and some others to be available in your path, which is fairly difficult to set up on windows. Its not geckos problem, its the cpp lib’s node gyp setup that is the issue. Probably putting it in docker would help, but i personally find doing that slows me down so much, although thats probably more a personal workflow problem, so idk.

Yesterday, I had it in my mind to fix up support for nengi but after looking through the code i was kind of discouraged by its custom bit packing. It makes more sense to me to just use message pack or flatbuffers.

Also i saw a couple of implementations, including nengi, that use a “ghost character” that just smoothly follows the hidden networked character. I like the idea of that as an abstraction

2 Likes

I like this idea, but how would i make the real character follow around the ghost character smoothly…

Any info or sample on this approach ?

nengi.js + Babylon.js 3D First person shooter template tour - YouTube around 25 mins ish, but i’d recommend watching the whole thing.

code is here GitHub - timetocode/nengi-babylon-3d-shooter: nengi+babylon template of a 3d shooter with client-side prediction and lag compensation

there is another video on shooting rays for instant hit testing worth watching (much shorter, 3 mins)
.client side predicted shots, hitscan, nengi.js + babylon.js - YouTube

quick warning though, nengi (the library supporting the netcode) is a bit in ruins because it’s using an unmaintained fork of uws, so it’ll only work on very specific platform / node versions. you could use nvm or docker to lock it down, but it’d be better to send a pr with updates or fork if ignored - if you think it will help you compared to what you have now. i think if what you have is working, which is also in production in frame and kind of mozilla hubs, it’d be better if we could just collectively get behind something. Btw, i think what you described above with none, buffered-interpolation, custom is great.

4 Likes

I used the ghost approach outlined here a long time ago for little framework I was trying to make for cocos2d and was quite smooth. Maybe not accurate enough for you but worth a quick look. It gets into client prediction as well but I never got that far.

3 Likes

Here is the new thread, probably it may be helpful - Babylon.js + Colyseus, New Tutorial on Real-time Multiplayer

3 Likes