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
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