Looking for help with smooth multiplayer interpolated movement

I am looking for someone to help implement smooth multiplayer movement for my Babylon Toolkit: Pro Tools Networking.

I already have in place a networking system using Colyseus. I am already buffer up to 20 network position update (Buffering and running behind the network server time is supposed to be the way to go). I just CANT get the Proper T-Value calculated for smoothing the movement in between buffered server updates.

I am willing to pay for a good interpolation/extrapolation solutions.
Anyone interested in helping me with Pro Networking Features please contact me ANYTIME

Mackey Kinard
MackeyK24@gmail.com

I’m using Colyseus as well for my own project. And I’ve been making mediocre attempts at solving similar problems, but probably not quite the same. For me its rendering the positions of each players humanoid character, and showing a smooth running/walking/flying animation from point A to point B between server update ticks. I haven’t even started to use a delta T approach to make everything in sync based on server time, and instead just rely on the server as the source of truth for all mesh positions.

In practice, that amounts to something like this:

function onServerUpdate(...) {
  player.mesh.position =    update.position // Vector3
  player.isMoving =         update.isMoving // boolean
  player.forward =          update.forward  // Vector3
}

and then just putting the mesh into a walking animation throughout the duration that the mesh is “moving”.

I track keyboard events so that I know when a given player has any of the moving keys pressed (wasd) and animate each players mesh model walking in their current forward facing direction (updated by mouse movements). This animation stops once the key is released and this corresponds to the server no longer updating the position of the mesh since the player is no longer moving.

Not sure I can contribute in any meaningful way since I’m short on time between my day-job obligations, social life and my own project. But maybe there’s some common goals we share that we could both work on. Where your projects github link?

1 Like

You still gotta update the transforms position. You only get server updates at (for example) 50 ms. If you simply set the transforms position every time you get an update. You get get choppy movement. Independent of any animations that you may or may not be playing.

You must interpolate the time in between server updates for the position. That is what i am having the problem with… Smoothing out that movement using any of the various techniques out there for doing such. Both with and without using the actual server time.

Got a notification for this thread and couldn’t help but pop in with some been there done that code.

A good entry point for my solution touhou-online/useSolveWorldState.ts at main · ChisatoSozo/touhou-online · GitHub

It’s in react-babylonjs but it should be pretty comprehensible

Fairly simple interpolation strategy

You may check https://www.vrspace.org/
We had no problems running more than 50 users with this solution.

1 Like

What is vrspace … I am looking for development help in creating smooth interpolated movement for networked entities. I dont get what is vrspace… Some kind of API they use or something ???

This is Java client-server professional grade solution for Babylon.js worlds, open source.

Im sorry i dont understand how that would help me with my multiplayer interpolation issues. I still need a developer to help me implement this in my toolkit.

I do server updates every 20ms, but only at changes in my viewport and this is custom-made server logic.

I have an client grid map for the positions available, and as the player moves around I validates this against the server, if movement is invalid I move it back to last server-valid position.

Then you don’t have to interpolate positions and take player ping time into consideration.

I am making a online game and after choosing this method no players have complained about slow movement.

edit: typo

2 Likes

Taking a look at that code -

            const curDelta = performance.now() - target.timestamp;
            const timestep = target.timestamp - last.timestamp;
            const alpha = curDelta / timestep;

            for (const poseString in PLAYER_POSE_STORE[curUsername]) {
                const poseProp = poseString as keyof InternalRig;
                const lastPosition = last[poseProp]?.position;
                const lastRotation = last[poseProp]?.rotation;
                const targetPosition = target[poseProp]?.position;
                const targetRotation = target[poseProp]?.rotation;
                if (!lastPosition || !lastRotation || !targetPosition || !targetRotation) return;

                const position = Vector3.Lerp(lastPosition, targetPosition, alpha);
                const rotation = Quaternion.Slerp(lastRotation, targetRotation, alpha).normalize();

Am I mistaken in thinking your players position is always chasing the most current position provided by the server?

Other than that, I think this would look smooth. Using that lerp function for the position and rotation will definitely give everything a smoother feel.

2 Likes

Yep yep, and it gives the possibility to overshoot the current position if the server is late with its updates.

I find this works as a general solution if you don’t need super advanced heuristics for competitive play.

1 Like

@MackeyK24 @Chisato_Sozo do either of you see any issues with using an approach like this?

The correction vector shouldn’t be too large if you’re receiving regular updates at 50ms, but obviously becomes much worse with lag spikes just like any other game. These calculations become much more stable if you include momentum as well, since a player can no longer instantly change their velocity by 180 degrees. Including player momentum would constrain just how large the correction vector can be.

3 Likes

That’s good if you really care about positional accuracy, generally though for most applications, it’s kinda fine to not bother correcting the position, and just move towards the new position a bit quicker or slower.

One benefit of this solution however is that you aren’t “behind” by a network frame

1 Like

I created a little “fake” server for the simple purpose of trying out different things.
It allows for setting your latency, interpolation delay and whether you want to interpolate or simply apply the latest state received. It’s pretty bad code, but it’s enough to test other implementations

Without interpolation: https://playground.babylonjs.com/#ZDJ98Z#5
With interpolation: https://playground.babylonjs.com/#ZDJ98Z#6

EDIT: Accidentally left the fake latency hardcoded

4 Likes

@Raggar this is really useful! Thank you!! Is this interpolation method chasing the actual current position?

@MackeyK24 I think that’s a good step towards getting the functionality you’re after. It looks really smooth in the interpolated example. If that is good enough, then you can just generalize that code for your toolkit.

Yo @Chisato_Sozo i got a couple questions about this implementation.

First of all how are you using performance.now at the time here

const curDelta = performance.now() - target.timestamp;

I mean what value is being stored on the entity as timestamp. In my solution the server is being tick at 60fps accumulating delta time and STAMPING the entity updates as they go out.

How can a clients local performance.now time ever work with entity.timestamp. I gues i need to see how you are creating the entity timestamp.

I dont know react so i can tell alot of what is going on in the code snippet. So i cant tell what is going on with the buffering… so i dont know how or what is LAST and TARGET snapshot you are using for the position and rotation lerping

Yo @Raggar … thanks bro… i going to study that code and see if i can tell what is going on with my shit. I still dont see how local time can be used to check against the entity.timestamp…

For me… the entity.timestamp is set at the server using the serverTime… Which starts a ZERO when the server room instance is created in match making… then ticked with the the server delta time in the server game loop running at 60 fps. How the heck is the local time used for that in a real server situation.

I gotta take time to study what is going on in your code example. THANKS FOR THE EXAMPLE :slight_smile:

P.S. I dont know if its just me but i still see a bit of jitter in the example with interpolation. Just a little… It is not as smooth as the green cube. I dont know if that is just as good as it gets for networking or what… Should i NOT expect the movement of the network entity to EVER be as smooth as local movement, even with interpolation ???

1 Like

if the client sends updates at a specific interval, i dont think you have to trust the actual time, instead, i think you can use the delta from the previous time to basically reconcile ping variance from frame to frame.

2 Likes

btw this might help GitHub - virbela/buffered-interpolation: A class for interpolation of position, rotation, and scale for networked BabylonJS objects.

4 Likes

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

Its usage looks simple, is there some kind of timestamp from the server it is expecting or what ?

1 Like