Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Fast Paced Multiplayer Possible?

Discussion in 'NetCode for ECS' started by Ericky14, Apr 5, 2020.

  1. Ericky14

    Ericky14

    Joined:
    Jun 10, 2016
    Posts:
    34
    I have tried to bring back one of my old game ideas to work on so I could get familiarized with DOTS, and I still can't seem to get it to work right.

    Can anyone tell if it's possible to have a fast paced multiplayer game with DOTS? My idea is just have a small arena and two goals and some kind of puck in the middle. The players would stay on their side and just shoot/deflect the puck. But even marking all the ghosts as Predicted and having interpolation, it seems very jitter-ly even with 50ms ping.

    Here is the video of how it looks playing it with ping


    Is there anything else I can configure on the Ghost scripts to make this better? I thought since the movement is so simple and linear, with less than 100 ping it shouldn't be jittery since the prediction wouldn't be wrong.

    The movement code looks like this,
    Player:
    Code (CSharp):
    1.  
    2. public class FreezePlayerRotationSystem : JobComponentSystem {
    3.     protected override JobHandle OnUpdate(JobHandle inputDeps) {
    4.         inputDeps.Complete();
    5.  
    6.         Entities.ForEach((
    7.             ref PhysicsMass pm,
    8.             ref PhysicsVelocity pv,
    9.             ref Rotation rotation,
    10.             ref Translation translation,
    11.             in NetPlayer netPlayer
    12.         ) => {
    13.             pv.Angular = new float3();
    14.             pm.InverseInertia = new float3();
    15.  
    16.             translation.Value.y = 0.3188247f;
    17.             rotation.Value = quaternion.EulerXYZ(math.radians(-90), math.radians(netPlayer.team == 0 ? 180 : 0), 0);
    18.         }).Run();
    19.  
    20.         return inputDeps;
    21.     }
    22. }
    23.  
    24. [UpdateInGroup(typeof(GhostPredictionSystemGroup))]
    25. public class MoveMovementSystem : JobComponentSystem {
    26.     protected override JobHandle OnUpdate(JobHandle inputDeps) {
    27.         inputDeps.Complete();
    28.  
    29.         var worldForward = new float3(0, 0, 1);
    30.         var worldUp = new float3(0, 1, 0);
    31.         var group = World.GetExistingSystem<GhostPredictionSystemGroup>();
    32.         var tick = group.PredictingTick;
    33.         var deltaTime = Time.DeltaTime;
    34.  
    35.         Entities.ForEach((
    36.             ref MovementData movementData,
    37.             ref PhysicsMass pm,
    38.             ref PhysicsVelocity pv,
    39.             ref PredictedGhostComponent prediction,
    40.             ref Rotation rotation,
    41.             ref Translation translation,
    42.             in DynamicBuffer<MovementInput> inputBuffer,
    43.             in NetPlayer netPlayer
    44.         ) => {
    45.             if (!GhostPredictionSystemGroup.ShouldPredict(tick, prediction))
    46.                 return;
    47.  
    48.             MovementInput input;
    49.             inputBuffer.GetDataAtTick(tick, out input);
    50.  
    51.             float speed = movementData.speed;
    52.             float3 velocityChange = new float3(input.horizontal * speed * deltaTime, 0, input.vertical * speed * deltaTime * (netPlayer.team == 0 ? -1 : 1));
    53.  
    54.             if (velocityChange.x != 0 || velocityChange.z != 0) {
    55.                 pv.Linear += velocityChange;
    56.             }
    57.  
    58.             pv.Angular = new float3();
    59.             pm.InverseInertia = new float3();
    60.  
    61.             translation.Value.y = 0.3188247f;
    62.             rotation.Value = quaternion.EulerXYZ(math.radians(-90), math.radians(netPlayer.team == 0 ? 180 : 0), 0);
    63.         }).Run();
    64.  
    65.         return inputDeps;
    66.     }
    67. }
    68.  
    Code (CSharp):
    1. public class BallSystem : JobComponentSystem {
    2.     protected override JobHandle OnUpdate(JobHandle inputDeps) {
    3.         Entities.WithAll<BallData>().ForEach((ref Rotation rotation, ref Translation translation, ref PhysicsMass pm, ref PhysicsVelocity pv) => {
    4.             pm.InverseInertia = new float3();
    5.             pv.Angular = new float3();
    6.             rotation.Value = quaternion.EulerXYZ(math.radians(-90), 0, 0);
    7.             translation.Value.y = -0.03616257f;
    8.         }).Run();
    9.  
    10.         return inputDeps;
    11.     }
    12. }
    13.  
    14. [UpdateInGroup(typeof(GhostPredictionSystemGroup))]
    15. public class BallPredictionSystem : JobComponentSystem {
    16.     protected override JobHandle OnUpdate(JobHandle inputDeps) {
    17.         inputDeps.Complete();
    18.  
    19.         var worldForward = new float3(0, 0, 1);
    20.         var worldUp = new float3(0, 1, 0);
    21.         var group = World.GetExistingSystem<GhostPredictionSystemGroup>();
    22.         var tick = group.PredictingTick;
    23.         var deltaTime = Time.DeltaTime;
    24.  
    25.         Entities.ForEach((
    26.             ref PhysicsVelocity pv,
    27.             ref PredictedGhostComponent prediction,
    28.             in BallData ballData
    29.         ) => {
    30.             if (!GhostPredictionSystemGroup.ShouldPredict(tick, prediction))
    31.                 return;
    32.  
    33.             if (math.length(pv.Linear) > ballData.maxVelocity) {
    34.                 pv.Linear = math.normalize(pv.Linear) * ballData.maxVelocity;
    35.             }
    36.         }).Run();
    37.  
    38.         return inputDeps;
    39.     }
    40. }
    41.  
     
  2. mhernandez88

    mhernandez88

    Joined:
    Jul 20, 2016
    Posts:
    38
    I can't tell you exactly what is wrong with your code, however I can tell you that DOTS is definitely capable of what you are trying to achieve. It seems that you are relying on the physics here, you may have some sort of race condition with the interpolation and the prediction. I remember having similar issues even outside of DOTS during a gamejam a while ago, it was an issue with collision detection and the order of operations the network was dealing with the data. Sorry cannot be of more help to your specific situation, however the answer to the main question is yes, DOTS is more than capable.
     
    Ericky14 likes this.
  3. Ericky14

    Ericky14

    Joined:
    Jun 10, 2016
    Posts:
    34
    @mhernandez88 Thank you for the reply!

    I will keep trying then to figure it out since you say it is possible. I have a quick question though, in that kind of physics simulation, is it correct to have all players and the object they interact with be "predicted"? And should all of them have physicsVelocity and translation components have Linear and Value respectively be default ghost fields that are synced and interpolated?
     
    Last edited: Apr 6, 2020
  4. SebLazyWizard

    SebLazyWizard

    Joined:
    Jun 15, 2018
    Posts:
    234
    Running physics in prediction is currently not possible out of the box.
    Also keep in mind that the prediction systems run multiple times within a single frame on the client, whereas on the server they run just once per frame/tick. So your physics velocity runs out of sync anyway.

    The only thing you can do right now is to disable the physics velocity component on the client side ghost to make that system run on the server only. This way it's no longer predicted but interpolated.

    Not sure why you constantly reset the angular velocity and rotation, you can just set the Intertia Tensor in the Physics Body script to "Infinity" in order to prevent the physics system to affect the body's rotation.

    And why the heck are you fixing it's position on the y axis aswell?
    When working with physics you should move the bodies via their velocities only.
     
  5. Ericky14

    Ericky14

    Joined:
    Jun 10, 2016
    Posts:
    34
    Sorry, those were result of me testing how to do things such as disable the rotation on collision. And I fixed the y position because sometimes the ball would just fly up into infinity after some weird collisions.

    Thank you for the info. I'll try that and disable the physics velocity component!
     
  6. Ericky14

    Ericky14

    Joined:
    Jun 10, 2016
    Posts:
    34
    @SebLazyWizard One issue with that approach though now that I think of it, is that since the client doesn't know the ball's velocity, it wouldn't be able to properly collide with the predicted player
     
  7. SebLazyWizard

    SebLazyWizard

    Joined:
    Jun 15, 2018
    Posts:
    234
    The server just synces back the translation and rotation of the players and the ball and since the physics component is on the server only, the physics simulation also runs on the server only.
     
  8. Ericky14

    Ericky14

    Joined:
    Jun 10, 2016
    Posts:
    34
    I removed the physic components from the clients, and even then the ball still lags or seems to lose frames with a little ping. :/

     
  9. SebLazyWizard

    SebLazyWizard

    Joined:
    Jun 15, 2018
    Posts:
    234
    Interpolation with implied lag is still buggy, it's not related to your code as long as it works fine with zero delay.
     
  10. Ericky14

    Ericky14

    Joined:
    Jun 10, 2016
    Posts:
    34
    Ah ok, thank you!