DOTS - Multiplayer synchronization lags

Hi there,

I testing around with the new dots multiplayer tech stack from github. So I took the Astroids sample from github and try to implement my own version with characters.

My problem now is that the movement looks realy laggy. I think it comes from the quantization. When using a higher precision the lag is not that strong… It looks like that the character will try to move on a grid. So the prediction says: Ok my position is 1.5423 and the server says no you are at 1.5. Therefore the Character moves forward and on rollback it will snap back to the quantized position.

Anyway I think I do something wrong or I miss something here. Because the Astroids sample runs without such lags… But my code does not look that different.

My basic setup is similar to the astroid sample.

So here is my setup:


The Hero shown in the scene is normaly not in the scene

5044343--494777--upload_2019-10-8_21-33-59.png

An here is my prediction movement system (client) and my movement system (server):

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

[UpdateAfter(typeof(InputSystem))]
[UpdateAfter(typeof(GhostReceiveSystemGroup))]
[UpdateBefore(typeof(AfterSimulationInterpolationSystem))]
[UpdateInGroup(typeof(ClientSimulationSystemGroup))]
public class MovementPredictionSystem : JobComponentSystem
{
    private ClientSimulationSystemGroup _ClientSimulationSystemGroup;
    private NetworkTimeSystem _NetworkTimeSystem;

    [BurstCompile]
    [RequireComponentTag(typeof(HeroTagComponentData), typeof(PredictedEntityComponent))]
    struct MovementJob : IJobForEach_BBCCC<HeroSnapshotData, HeroCommandData, Translation, Rotation, LocalToWorld> {

        public uint currentTick;
        public float deltaTime;
        public void Execute([ReadOnly] DynamicBuffer<HeroSnapshotData> snapshot, [ReadOnly] DynamicBuffer<HeroCommandData> input, ref Translation position, ref Rotation rotation, [ReadOnly] ref LocalToWorld localToWorld) {

            snapshot.GetDataAtTick(currentTick, out HeroSnapshotData snapshotData);

            // Iterate over last snapshot tick + 1 (we just applied the first one)
            // to the current tick + 1 and apply prediction
            for (uint tick = snapshotData.Tick + 1; tick != currentTick + 1; tick++) {
                input.GetDataAtTick(tick, out HeroCommandData inputData);

                rotation.Value = math.mul(rotation.Value, quaternion.RotateY(math.radians(inputData.Look.x * deltaTime * 10))) ;
                position.Value += (localToWorld.Forward * inputData.Move.y + localToWorld.Right * inputData.Move.x) * deltaTime * 5;
            }
        }
    }

    protected override void OnCreate() {
        _ClientSimulationSystemGroup = World.GetOrCreateSystem<ClientSimulationSystemGroup>();
        _NetworkTimeSystem = World.GetOrCreateSystem<NetworkTimeSystem>();
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        var topGroup = World.GetExistingSystem<ClientSimulationSystemGroup>();

        var job = new MovementJob() {
            deltaTime = topGroup.UpdateDeltaTime,
            currentTick = _NetworkTimeSystem.predictTargetTick,
        }; 

   
        // Now that the job is set up, schedule it to be run.
        return job.ScheduleSingle(this, inputDeps);
    }
}
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

[UpdateAfter(typeof(HeroCommandReceiverSystem))]
[UpdateInGroup(typeof(ServerSimulationSystemGroup))]
public class MovementSystem : JobComponentSystem
{
    private ServerSimulationSystemGroup _ServerSimulationSystemGroup;

    [BurstCompile]
    struct MovementJob : IJobForEach_BCCC<HeroCommandData, Translation, Rotation, LocalToWorld> {
        public float deltaTime;
        public uint currentTick;
        public void Execute([ReadOnly] DynamicBuffer<HeroCommandData> input, ref Translation position, ref Rotation rotation, [ReadOnly] ref LocalToWorld localToWorld) {
            input.GetDataAtTick(currentTick, out HeroCommandData inputData);

            rotation.Value = math.mul(rotation.Value, quaternion.RotateY(math.radians(inputData.Look.x * deltaTime * 10)));
            position.Value += (localToWorld.Forward * inputData.Move.y + localToWorld.Right * inputData.Move.x) * deltaTime * 5;
        }
    }

    protected override void OnCreate() {
        _ServerSimulationSystemGroup = World.GetOrCreateSystem<ServerSimulationSystemGroup>();
    }

    protected override JobHandle OnUpdate(JobHandle inputDeps) {
        var topGroup = World.GetExistingSystem<ServerSimulationSystemGroup>();
        var job = new MovementJob() {
            currentTick = _ServerSimulationSystemGroup.ServerTick,
            deltaTime = topGroup.UpdateDeltaTime,
        };

        return job.Schedule(this, inputDeps);
    }
}

I hope that someone can help me.
If you need more information feel free to ask me!

EDIT:
It looks like that the rollback and playback functionality isn’t correct

Just wonder, how do you increase precision? By changing sampling frequence?

You can adjust Quantization setting to get more precise numbers (e.g. for Translation from 10 to 1000), though more data has to be sent over network.

1 Like

Excited to try the new DOTS netcode, too!

Do you have a link to the new DOTS netcode on github?

Just Download the master
https://github.com/Unity-Technologies/multiplayer?files=1

Then go to samples and there you find the folder netcode. Inside there, you’ll find a folder documentation with quick start instructions and a brief overview of the netcode.
By the way, this is not the unite demo but it’s similar to it…
Try to start with the astroids sample. It’s not too hard to get in. I recommend to watch the unite session about the netcode on YouTube.

https://github.com/Unity-Technologies/multiplayer/blob/master/sampleproject/Assets/NetCode/Documentation~/quickstart.md

https://github.com/Unity-Technologies/multiplayer/blob/master/sampleproject/Assets/NetCode/Documentation~/netcode.md

https://www.youtube.com/watch?v=P_-FoJuaYOI

1 Like

Thank you very much for the nice explanation! Going to try it out right now :slight_smile:

1 Like

Ok, I made a video of the problem.

I also changed the send receive delay to 250ms
5048282--495281--upload_2019-10-9_19-23-26.png

Now it looks like that the problem is the Rollback funktion…

And this is how it looks like with an extreme delay of 1 second:

I start to move, then I release the button. Now it snaps back to the starting position and after a second, it moves to the destination position…

So now I would say that the tick rate isn’t calculated correctly.
Very weird

Hey!
I had the same issues.
First thing is to use a quantization of at least 1000.
Then I did a tick by tick analysis from server and client and came to the conclusion that the for loop is wrong and it has to start at the snapshot.tick and not +1

I use this loop: for (uint tick = snapshotData.Tick; tick != currentTick + 1; ++tick)
The analysis afterwards had no wrong predictions anymore. I use a hybrid model so that part could be only on my side.

Even with accurate predictions I had jittery movement. Not really visible from outside but with a 3rd person camera it got apparent that the movement is not fluid at all.

I could find the root cause of this was the interpolation system. It has a bug that I couldn’t find even with lots of debugging. I just threw it out. Sure, would be nice but it works fine without any now.

edit: The asteroid sample doesn’t run fine when you increase the velocity. For testing purposes I applied velocity instantly instead of gradually and didn’t spawn any asteroids to actually test. Movement will skip and jitter at faster speeds.

Many thanks! I’ll try it out and write my feedback to it later on :slight_smile:

This is still the 3 month old version though, right? Been holding my breath for the 2019.3 updated one.

Yep, it is.

1 Like

Yeah, sadly no word when it’ll be released. :frowning:
My version also doesn’t run in anything newer than 2019.3.0a5. Throws weird job errors I can’t figure out.
I made a thread about it some time ago: https://discussions.unity.com/t/753212

1 Like

We are planning for a new entities release next week.

13 Likes

Will the new multiplayer sample from Unite drop around the same time by any chance?

~3-4 weeks Ante said: DOTS Netcode Copenhagen updates

1 Like