Search Unity

  1. Calling all beginners! Join the FPS Beginners Mods Challenge until December 13.
    Dismiss Notice
  2. It's Cyber Week at the Asset Store!
    Dismiss Notice

AnySync - Transform sync for any networking.

Discussion in 'Assets and Asset Store' started by forcepusher, Mar 28, 2018.

  1. MustangLM

    MustangLM

    Joined:
    Feb 6, 2015
    Posts:
    34
    @forcepusher Moving The RigiBody.MovePosition to Fixed Update, using rigibody interpolation, and increasing send rate to 15 msg/s fixed the problem, but the object seems to be correcting a lot, move back and forth while moving(not jittery) , What can I do about this ?
     
  2. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    While figuring out the source of issues I suggest to set TargetLatency to something very high like 0.3 seconds to exclude the possibility that extrapolation is creating any artifacts. I'm not sure what the issue is without a reproduction project.
     
  3. joshua-jebadurai

    joshua-jebadurai

    Joined:
    Jul 3, 2009
    Posts:
    13
    I'm working on fast paced Server based Authoritative Air Hockey game, modded to work with Forge Remastered. The puck without anything hitting it, seems to be in sync properly across all clients. The problem is obvious, when the paddle hits the puck in the client, it needs to be updated immediately on the client, but since it goes across the server and comes back, the puck goes inside the paddle then responds later on the client.

    I give a RPC call about the hit position and velocity of the puck from the client to server. And in the server, I use the teleport method to notify the sudden change in position and velocity. But the server round-about still causes the puck to go inside the paddle, is there a way the client playbacks in a delay, so if I hit the paddle on the client, the round about would match the timing of the delay?

    Code (CSharp):
    1. // Paddle code snippet
    2. private void Update() {
    3.         isOwner = networkObject.IsOwner;
    4.         networkId = networkObject.playerIndex;
    5.  
    6.         if (networkObject.IsServer) {
    7.             // Disabled on the client for now, because too many hits are getting called.
    8.             _collider2D.enabled = false;
    9.  
    10.         } else if (networkObject.IsOwner && !networkObject.IsServer) {
    11.  
    12.             if (Input.GetMouseButton(0)) {
    13.                 moveToPosition = Table.ClosestPoint(0, Camera.main.ScreenToWorldPoint(Input.mousePosition));
    14.                 _rigidbody.MovePosition(moveToPosition);
    15.             }
    16.  
    17.         } else {
    18.             // Other clients don't need collision detection.
    19.             _collider2D.enabled = false;
    20.         }
    21.     }
    22.  
    23.     private void OnCollisionExit2D(Collision2D collision) {
    24.         if (networkObject.IsOwner) {
    25.             Puck puck = collision.gameObject.GetComponent<Puck>();
    26.             if (puck != null) {
    27.                 networkObject.SendRpc(RPC_PUCK_HIT, Receivers.Server, (Vector2)puck.transform.position, puck.Velocity);
    28.              
    29.                 StopAllCoroutines();
    30.                 StartCoroutine(EnableCollider());
    31.             }
    32.         }
    33.     }
    34.  
    35.     // This happens on the server
    36.     public override void PuckHit(RpcArgs args) {
    37.         var hitPosition = args.GetNext<Vector2>();
    38.         var hitVelocity = args.GetNext<Vector2>();
    39.         Puck.TakeHit(hitPosition, hitVelocity);
    40.      
    41.     }
    Puck Code:
    Code (CSharp):
    1. private void Update() {
    2.         if (networkObject.IsServer) {
    3.            
    4.             // send sync messages
    5.             _timeSinceLastSync += Time.deltaTime;
    6.             if (_timeSinceLastSync >= MinimumSendInterval) {
    7.                 if (_lastSentPosition != transform.position)
    8.                     _idle = false;
    9.  
    10.                 if (!_idle) {
    11.                    
    12.                     syncBuffer.AddKeyframe(_timeSinceLastSync, transform.position);
    13.                     networkObject.SendRpc(RPC_SYNC, Receivers.Others, _timeSinceLastSync, transform.position, _rigidbody.velocity);
    14.                     // go idle only after sending a keyframe with the same position to prevent drifting while idle
    15.                     if (_lastSentPosition == transform.position)
    16.                         _idle = true;
    17.  
    18.                     _lastSentPosition = transform.position;
    19.                     _timeSinceLastSync = 0f;
    20.                 }
    21.             }
    22.         }
    23.         else {
    24.  
    25.             // avoid warnings if syncBuffer is empty
    26.             if (syncBuffer.HasKeyframes) {
    27.                 // update playback and apply new position
    28.                 syncBuffer.UpdatePlayback(Time.deltaTime);
    29.  
    30.                 transform.position = syncBuffer.Position;
    31.                 _rigidbody.velocity = syncBuffer.Velocity;
    32.  
    33.             }
    34.         }
    35.     }
    36.  
    37.     public override void Sync(RpcArgs args) {
    38.         syncBuffer.AddKeyframe(
    39.             interpolationTime: args.GetNext<float>(),
    40.             position: args.GetNext<Vector3>()
    41.             );
    42.     }
    43.  
    44.     // Server running a hit call from the Client
    45.     public static void TakeHit (Vector2 position, Vector2 hitVelocity) {
    46.         _instance._TakeHit(position, hitVelocity);
    47.     }
    48.  
    49.     // Server calculates the hit that happened on the client and then notifies the others the sudden change
    50.     public void _TakeHit(Vector2 position, Vector2 hitVelocity) {
    51.         syncBuffer.AddKeyframe(_timeSinceLastSync, transform.position, velocity: hitVelocity);
    52.         networkObject.SendRpc(RPC_SYNC, Receivers.Others, _timeSinceLastSync, transform.position, _rigidbody.velocity);
    53.  
    54.         transform.position = position;
    55.         _rigidbody.velocity = hitVelocity;
    56.  
    57.         _timeSinceLastSync = 0;
    58.         syncBuffer.AddKeyframe(0, transform.position, velocity: hitVelocity);
    59.         networkObject.SendRpc(RPC_SYNC, Receivers.Others, _timeSinceLastSync, transform.position, _rigidbody.velocity);
    60.  
    61.     }
     
  4. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    Hello. I don't think it's possible to properly prevent that in this setup. One solution I can suggest is to override the puck positioning locally for a moment after hitting it.
    If I was going to make a game like this myself, I would have used Physics.Simulate to predict puck position in the future. Take a look at this page http://www.codersblock.org/blog/client-side-prediction-in-unity-2018
     
  5. joshua-jebadurai

    joshua-jebadurai

    Joined:
    Jul 3, 2009
    Posts:
    13
    Thank you, I did override the position for a moment after the hit but when I enable syncbuffer back, it goes back in time. I'll try the Physics.Simulate method, I think I read that blog a time ago. Thanks for the quick response, I love AnySync by the way.
     
    forcepusher likes this.
  6. HallMaruShiranui

    HallMaruShiranui

    Joined:
    Aug 10, 2018
    Posts:
    3
    Hi, this asset is easy to integrate to a custom network serializer and sender/receiver? I'm using TcpListener and TcpClient on my game.
     
  7. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    Hello. Yeah, you can do that. AnySync is not tied to any specific network architecture.
     
  8. HallMaruShiranui

    HallMaruShiranui

    Joined:
    Aug 10, 2018
    Posts:
    3
    Cool, i'm reading your documentation, i can sync animators too using SyncBuffer? There is some example syncing animation?
     
  9. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    There's no examples for that unfortunately. It's designed to sync position and rotation values (and their velocities) only.
     
  10. HallMaruShiranui

    HallMaruShiranui

    Joined:
    Aug 10, 2018
    Posts:
    3
    Cool, i'll try to sync all animations using parameters on animators and events on custom packets, thanks for your reply i'll give a try on AnySync.
     
  11. Zincord

    Zincord

    Joined:
    Dec 21, 2013
    Posts:
    14
    Some news about the "Delayed Action Execution"?
     
  12. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    It's still there in a high priority feature list along with decoupling sync logic from MonoBehaviour, and looking into ECS compatibility.
    Currently I'm working with some company on releasing a battle royale game that uses AnySync, so I can't afford to work on new features until it's released because that stuff requires a fair bit of research. Definitely not in February or March.
     
    Last edited: May 7, 2019
  13. yuliyF

    yuliyF

    Joined:
    Nov 15, 2012
    Posts:
    144
    I get problem when my user change a move speed, as example: going - 3, get in a car - 10. In the moment when person transit on, looks some shake. Have any advice?
     
  14. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    That's not supposed to happen. If you can share a reproduction project, I can point out the issue with the netcode.
    You can email me at bananapartydev@gmail.com or start a personal conversation to share the project and get into details.
     
  15. Tony-Lovell

    Tony-Lovell

    Joined:
    Jul 14, 2014
    Posts:
    93
    Is it easily possible to swap out networking sublayers such as PUN/UNET/etc for my own? I have my own networking in place now which can write/read rotations and Vector3s which I'd like to keep. I only really need network smoothing, not network transport.

    Thanks in advance!

    tone
     
  16. yuliyF

    yuliyF

    Joined:
    Nov 15, 2012
    Posts:
    144
    forcepusher, thanks. Problem was in my part(moving twice the same object), so I'm testing demo to change speed dynamical - works fine
     
    Last edited: Mar 22, 2019
    forcepusher likes this.
  17. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    Hello. This asset is not tied to any specific network transport nor networking solution, you can swap things as you see fit.
     
  18. Velcer

    Velcer

    Joined:
    Mar 16, 2017
    Posts:
    14
    Hey, any update on getting this to not require mono behavior?
     
  19. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    I'm finally able to work on the new features full time.
    An early version of new AnySync update is ready for preview. If anyone wants to try it and maybe give me some feedback, send me a personal message with the invoice number of your purchase.

    New features:
    • No longer inherits from MonoBehaviour (it's no longer a component).
    • Invocation synchronization. Now you can execute RPCs in perfect sync with the movement ("Delayed Event Execution" feature I was talking about earlier).
    • ECS compatibility. It's not exactly designed for pure ECS since data is not separated from the behavior code, but it should work fine regardless if you put MotionGenerator into a component struct.
    • Lots of cosmetic changes that solve some naming issues and make coding less daunting.
    I'm still working on rewriting the examples, documentation and rolling a new video. I can't publish it yet on the Asset Store.
     
    Last edited: May 14, 2019
    yuliyF likes this.
  20. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    2.0 Update mentioned above is up in the Asset Store.
    Remove the old AnySync folder before importing it and please let me know if there are any issues.

    It's a major update that includes some code-breaking changes. Backup your project and prepare to change your game code in order to upgrade.
     
  21. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    2.01 Update brought significant improvement to the Photon sample code. It was unnecessarily complex and not well thought when used together with other networked components. I've decided to calculate keyframe interpolation time from PhotonMessageInfo and that allowed us to use any PhotonView observe option, not just Unreliable.
    So now we have a choice to use ReliableDeltaCompressed or UnreliableOnChange to save some bandwidth without a hassle.
    See new Photon sample code here https://pastebin.com/T57V07E9
     
    Last edited: Jul 1, 2019
  22. Ruslank100

    Ruslank100

    Joined:
    Apr 11, 2018
    Posts:
    11
    Hello! I am using this asset to smooth tanks movement(I am using Dark Rift 2), but have a small problem, that causes tanks to move a bit jittery(it looks like micro - freezes, but the game is running at 60 fps smoothly!). How do I fix this?
    The code works like this : position message received from the server. A keyframe is added using the data received, and the interpolation time is time since tank spawned. In Update() I am progressing the playback using Time.deltaTime, and then setting the position from buffer. Thanks in advance!
     
  23. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    Hello. Thanks for using AnySync.
    Interpolation time should not be calculated from spawn time. It should be transferred over the network explicitly (See lines 40-45) or calculated from timestamp sent with network message (See lines 90-99).
    In case if you can't figure it out, send me a reproduction project so I can fix it for you and point out what went wrong.
     
    Last edited: Jul 15, 2019
  24. Ruslank100

    Ruslank100

    Joined:
    Apr 11, 2018
    Posts:
    11
    Thanks for your reply, I have tried to do this, but it looks that I am doing something wrong. The code :
    This is called when a client receives a message from the server, all the simulations are happening on it(on the server)
    Code (CSharp):
    1.  if(lastReceivedKeyframeTime < 0f)
    2.                           {
    3.                              lastReceivedKeyframeTime = timeS;
    4.                           }
    5.                               var interpolationTime = (float)(timeS - lastReceivedKeyframeTime);
    6.                               lastReceivedKeyframeTime = timeS;
    7.  
    8. then...
    9. buffers[i].AddKeyframe(interpolationTime , new Vector3(pos[num * 3 + 0], pos[num * 3 + 1], pos[num * 3 + 2]),Quaternion.Euler(rots[num * 3 + 0], rots[num * 3 + 1], rots[num * 3 + 2]));
    Then in Update() I am doing this :
    Code (CSharp):
    1. buffers[i].UpdatePlayback(Time.deltaTime);
    2.                     tank.position = buffers[i].Position;
    3.                     tank.rotation = buffers[i].Rotation;
    Now jitter happens stable once in 3 - 4 seconds, for a second. Also do you have the older version of AnySync? My game breaks when .net 4.x used for some reason.
     
  25. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    197
    Sent an old version in a private conversation.
    I didn't find any issues in the code chunks you posted. If you are unable to provide a reproduction project, then I will offer you a refund. There's not much I can do without a repro, my help is limited to guessing.

    UPDATE: After providing more support we figured there was no issues since it ran fine in builds.
    Slight hitch was an editor lag caused by things unrelated to this asset.
     
    Last edited: Aug 9, 2019