Local player's position predict error occured when spawn ghost in client

I’m working on Netcode for Entities
There is a player(me) in the scene, and I move it monontone and continuedly. In the absence of other conditions, its moving is smooth
And I create a system which update in PredictedSimulationGroup, the system’s purpose is to create projectile continuedly, it’s written like this:

public struct ProjectileState : IComponentData {
    [GhostField]
    public uint spawnId;
    public float lifeTime;
}

public struct Player : IComponentData {
    [GhostField]
    public int playerId;

    // server
    public Entity connectionEnt;
}

public struct TargetActor : IComponentData {
    // The actual player entity which has LocalTransform
    [GhostField] public Entity actorEnt;
}

[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]  // [Edit]
[UpdateInGroup(typeof(PredictedSimulationSystemGroup))]
public partial class ActorShootPredictedProcessSystem : SystemBase {
    private EntityQuery projectilePrefabQuery;
    private float timer;
    protected override void OnCreate() {
        projectilePrefabQuery = GetEntityQuery(new EntityQueryDesc() {
            All = new ComponentType[] {
                typeof(GhostInstance),
                typeof(ProjectileState),
                typeof(Prefab),
            },
            None = new ComponentType[] {
                typeof(InitializedTag)
            },
            Options = EntityQueryOptions.IncludePrefab,
        });
        RequireForUpdate<GameLoadedTag>();
    }
    protected override void OnUpdate() {
        timer -= UnityEngine.Time.fixedDeltaTime;
        bool isServer = World.IsServer();
        var networkTime = SystemAPI.GetSingleton<NetworkTime>();
        if (!networkTime.IsFirstTimeFullyPredictingTick) {
            return;
        }
        Entities
            .WithStructuralChanges()
            .WithAll<Player>()
            .ForEach((ref Entity entity, ref TargetActor targetActor) => {
                NetworkTick tick = networkTime.ServerTick;

                if (timer <= 0) {
                    if (!isServer) {
                        Entity projectileClient = SpawnProjectile(prevSampledTick.TickIndexForValidTick + 9999, false, targetActor, new float3(1, 1, 1));
                    }
                    timer = 0.05f;
                }
            }).Run();
    }
    private Entity SpawnProjectile(uint spawnId, bool isPredictedSpawn, TargetActor targetActor, float3 spawnPosOffset) {
        Entity prefab = projectilePrefabQuery.GetSingletonEntity();
        Entity projectile = EntityManager.Instantiate(prefab);
        EntityManager.AddComponent<EntityPrefabInstanceTag>(projectile);
        EntityManager.SetComponentData(projectile, new ProjectileState() {
            spawnId = spawnId,
            lifeTime = 5,
        });
        LocalTransform actorTrans = EntityManager.GetComponentData<LocalTransform>(targetActor.actorEnt);
        EntityManager.SetComponentData(projectile, new LocalTransform() {
            Position = actorTrans.Position + spawnPosOffset,
            Rotation = quaternion.identity,
            Scale = 1f
        });
        return projectile;
    }
}

After this system start working, I found prediction error in the character’s movement, The phenomenon is that the player is constantly overmove

The projectile has no collider, and there is no any collider in scene except ground, so in theory there is no object blocking the player’s movement

I try to check player’s LocalTransform data, found that its position did roll back. In the ex below, the player is moving right. But in Tick-267, its position occured a big change, but it goes back next tick


Does anyone know something about it?Thank you very much!

I tried to get the Ghost content when sending packets and receiving packets for prediction, found that when this problem occued, the amount of displacement between the receipt of the packet by the client and the completion of the first prediction by the client greatly exceeded its speed.

For example, there are 2 ticks below, the x distance is 0.458 which is exceeded its speed(5.5) can reach

I see three problem in that code:

  1. timer -= UnityEngine.Time.fixedDeltaTime; You should not use UnityEngineTime but the SystemAPI.Time for getting the delta. Otherwise client and server does not run the same code and decrement the timer differently.
[LIST=1]
[*].WithStructuralChanges()
[*]            .WithAll<Player>()
[*]            .ForEach((ref Entity entity, ref TargetActor targetActor)
[/LIST]

You also need to add the WithAll otherwise you are predicting this also when another entity rollback but the Player does not need to be resimulated.

[LIST=1]
[*]if (!isServer) {
[*]                        Entity projectileClient = SpawnProjectile(prevSampledTick.TickIndexForValidTick + 9999, false, targetActor, new float3(1, 1, 1));
[*]                    }
[/LIST]

Why this is done only on the client ? And never on the server? does the server spawn this in another place? Also, why you are passing the isPredictedSpawn to false? (because this is a predicted spawn)

[LIST=1]
[*]projectilePrefabQuery = GetEntityQuery(new EntityQueryDesc() {
[*]            All = new ComponentType[] {
[*]                typeof(GhostInstance),
[*]                typeof(ProjectileState),
[*]                typeof(Prefab),
[*]            },
[*]            None = new ComponentType[] {
[*]                typeof(InitializedTag)
[*]            },
[*]            Options = EntityQueryOptions.IncludePrefab,
[*]        });
[/LIST]

That prefab you get, are you sure that is the one with PredictedSpawnRequest (on the client is required, otherwise things will not work)

First thank you for your help!

For problem 1 and 3, I forget to mark that ActorShootPredictedProcessSystem is only run on client*([WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)])*, sorry. Because I want to simulate the failure of prediction spawning in this system, it’s also the reason I passing the isPredictedSpawn to false, the field doesn’t matter here, don’t worry about it for a moment. I will delete this part of the above. And for the same reason, the timer is only count down in client

For problem 4, yes, I got the true prefab with PredictedSpawnRequest, It’s working fine in my formal predicted spawning system

For problem 2, I try to add WithAll as you said, but it doesn’t seem to be working. I add it like this:

Entities
    .WithStructuralChanges()
    .WithAll<Player>()
    .WithAll<Simulate>()
    .ForEach((ref Entity entity, ref TargetActor targetActor) => {
...

And I notice that I didn’t give the struct of Player And TargetActor, their structure looks like this:

public struct Player : IComponentData {
   [GhostField]
   public int playerId;

   // server
   public Entity connectionEnt;
}

public struct TargetActor : IComponentData {
   // The actual player entity which has LocalTransform
   [GhostField] public Entity actorEnt;
}

Did I add the code in the wrong place or there is other problem?