FishNet icon indicating copy to clipboard operation
FishNet copied to clipboard

Position and rotation not syncing at the same time.

Open AlphaLul opened this issue 3 years ago • 3 comments

I've noticed that the FishNet NetworkTransform has some differences from that of Mirror in terms of synchronization. While Mirror syncs everything at the same time, FishNet seems to send position and rotation at slightly separate times. I've linked a video of what I'm talking about. I'm not sure what could be causing this.

To create this issue, I created a new project and attached the player script linked below to a networked player that uses NetworkTransform. My monitor refresh rate is at 60hz and VSync is on (though I doubt that's the problem as it wouldn't affect the video).

I've also linked the whole project below so you can take a look at it from my environment and possibly find the issue easier.

Video comparison (Mirror vs FishNet): https://youtu.be/Ob8FOuEWPNE Player script: https://hastebin.com/ivulukopoh.cpp Project: https://drive.google.com/file/d/1w4wNboSANgMAQbwGYouyhnvXLW010VOt/view?usp=sharing

AlphaLul avatar Sep 22 '22 01:09 AlphaLul

Have you tried 2.5.2 to see if it's resolved?

FirstGearGames avatar Oct 03 '22 20:10 FirstGearGames

Yeah, but it still has the problem. It's also way more noticeable after I implemented client-side prediction. You can take a look at it in the project file that I linked.

AlphaLul avatar Oct 04 '22 02:10 AlphaLul

Small update, I've made a new sample project that showcases the problem with CSP. It might help find out what's wrong. I think you were right that version 2.5.2 fixed it when client-authoritative, but the problem still exists with CSP.

AlphaLul avatar Oct 09 '22 05:10 AlphaLul

With how CSP works this shouldn't be an issue with the same bug fix. There could be something else going on. We can discuss further on Discord if you want to open a DM.

FirstGearGames avatar Oct 19 '22 19:10 FirstGearGames

I've not been able to reproduce this via CSP nor client authoritative NT. If you can provide a very basic script that I can reproduce on that would be very helpful.

FirstGearGames avatar Oct 23 '22 18:10 FirstGearGames

Sure, here's the script: https://hastebin.com/uxokijugoc.csharp

I've tried keeping it as simple as possible. I'm not sure if just the script will accurately reflect my problem though, since it might be a problem with how my player is set up in the inspector. I think the updated project I sent earlier will likely better reflect the issue, since it's a near-exact recreation of my player. If you can't reproduce the problem with the script, you could check the project out?

Also, could you send me your test project so I can see what you did to have it work? That might help me figure out what the problem is and fix it on my own.

AlphaLul avatar Oct 23 '22 19:10 AlphaLul

Okay, that could be a problem with your code setup.

I assume on the NT it's client authoritative with rotation and scale synchronizing off?

You are rotating in Update, which occurs after the tick system. This is because the TransportManager has first execution order.

First replace the void Update() with the event from base.TimeManager.OnUpdate. Then go into the TimeManager and look for this line ... OnUpdate?.Invoke(); Once found, move the line just above IncreaseTick();

Let me know if that works.

FirstGearGames avatar Oct 26 '22 21:10 FirstGearGames

Unfortunately, that didn't work and also introduce a problem where the aiming is also slightly out of sync on the local client. Did that work in your testing? Have you looked at the full project I sent yet?

AlphaLul avatar Oct 27 '22 03:10 AlphaLul

I think the link to the simplified script that I sent earlier expired. Here is a link that hopefully won't expire: https://pastebin.com/urai803F

AlphaLul avatar Nov 02 '22 03:11 AlphaLul

Got your script, thank you.

FirstGearGames avatar Nov 08 '22 00:11 FirstGearGames

I assume you're using a client auth NetworkTransform for the rotation. In your example script I noticed you were applying the rotation to a different transform, but it wasn't being used anywhere.

None the less, I think your problem is that the NetworkTransform maybe had a different rotation interpolation than the predicted object. It's too hard to say without having the project.

I was going to take a look but the file size was 1GB. You can leave out the library, cache, temp, ect folders when zipping.

But before you do that, to replicate reliably I'll need the full client auth NT version, no CSP.

FirstGearGames avatar Nov 08 '22 00:11 FirstGearGames

Yeah, my bad. I left the library folder in. I uploaded a new version without the library folder that's about 28 MB. Here's the link to the new one: https://drive.google.com/file/d/1w4wNboSANgMAQbwGYouyhnvXLW010VOt/view?usp=sharing

My first thought was also a difference in interpolation, which is why I originally titled the post "not interpolating at the same time". If there is a discrepancy between client and server-authoritative network transform interpolation, I do think a client-authoritative NT that simulates the interpolation of a server-authoritative NT would be a nice feature if possible.

Examples of both fully client-authoritative and CSP are in the project I linked in this post. If you want to have another simpler script for fully client-authoritative movement, let me know and I'll make one for you.

Thanks so much for taking the time to look into this issue for me!

AlphaLul avatar Nov 08 '22 07:11 AlphaLul

Just wanted to update you that I have the files. I'm going to focus on releasing 2.6.0 in the next couple days because there is already a lot into that version, then look immediately after.

FirstGearGames avatar Nov 12 '22 00:11 FirstGearGames

Alright, thanks! I'm excited for the new release

AlphaLul avatar Nov 12 '22 07:11 AlphaLul

I looked at your example project and did some test on it. First I started with the client auth example because that would be the easiest to debug issues. I tested on version 2.6.0.

In testing I discovered that packets being received did contain both position and rotation as expected.

I also tested if each pos/rot goal was reached before moving onto the next pos/rot goal, and this also returned true. Note that the next goal is set regardless of alignment using time calculations, not when all values match goals. This means if something wasn't moving fast enough then it would not be at the goal by the time next goal was expected to be set, but findings showed everything was aligned properly.

Test passed both with the TimeManager update order set to before and after tick.

One thing I did observe is at a tick rate of 10 it appeared as if rotations were maybe moving slowly, but this went away after increasing the tick rate to 50. This would not be considered a bug because the interpolation is calculating speeds every 100ms rather than every 20ms at a 50 tick rate. In result the movement might feel a little lower with sudden changes.

I cannot recall if you tried increasing the tick rate, and after the update order feature. But if you have not that could be the problem. Mirror by default runs at an uncapped tick rate which means it's essentially hammering out data quickly as possible, while FN by default is 30.

FirstGearGames avatar Nov 15 '22 16:11 FirstGearGames

Did you try the server-auth example? The problem is fixed with the client-auth example after 2.5.2, but the server-auth example still has the problem. The problem is lessened with a higher tick rate, but it's still there even if I set the tick rate all the way up to 60, just less noticeable. If you set the tick rate to 30 and try the server-auth example, you should see what I'm talking about.

I tried both Before Tick and After Tick for Update Order and neither of them fixed the problem. Also, subscribing to OnUpdate instead of doing aiming in Unity's update causes the same rotation problem on the local client as well, likely because it has to be done every frame to be smooth and the Time Manager update isn't done every frame (but that's just aiming in general, not much I can do about that).

My guess is still a difference in interpolation. It might have to do with movement being predicted and aiming not, but I don't know why that would make a difference on observing clients. It also might have to do with rotation having to be done every frame and that's not happening on observing clients, but I'm not sure if that matters since they're just reading the most recent value from the server sent by the NT rather than calculating it themselves.

Edit: Just to clarify, there are 2 server-auth scripts and prefabs. The ones in the Assets folder titled "ServerAuthExample" are the simple version of my player script. The ones in the Server Auth CSP folder titled "ServerAuthPlayer" are slightly more complicated but are more accurate to my actual player script in my main project. Both of them should show the same problem, just wanted to let you know if you wanted to test with one or the other or wanted to look at the scripts.

AlphaLul avatar Nov 16 '22 05:11 AlphaLul

I will have to take a look at the CSP ones but given the non-csp works fine, and your CSP also uses NT, the problem almost definitely is in your approach. I'll let you know what I find out.

FirstGearGames avatar Nov 16 '22 22:11 FirstGearGames

Have you had time to look at them yet? The only problem I can think of with my implementation is that I am using 2 network transforms, 1 server-authoritative for the movement and 1 client-authoritative for the rotation, but there isn't really a way for me to make rotation server-authoritative since the rotation code needs to run every frame to look smooth.

It could be a problem with my implementation of aiming in general with rotating every frame, but that's the only way for it to look smooth and I believe that's how most top-down shooters accomplish aiming. It may just be that FishNet's architecture doesn't support that kind of aiming with running every frame and syncing to make it look the same on other clients, but if that's the case, it would be nice if support for it were added in some way since not having support limits people from making top-down shooters with FishNet. If Mirror accomplishes this via an uncapped tick rate, maybe that's something you can look into adding support for.

Thanks for spending your time helping me and looking into this.

AlphaLul avatar Nov 26 '22 21:11 AlphaLul

If you are doing Server Auth but Client Rotation, simply set the rotation in the Move Function. Make the Z Euler Angle part of the StateData. There's no need for two NetworkTransform components.

here are changes you'd need to make to these specific parts.

public struct StateData
    {
        public Vector2 velocity;
        public float zRotation;
    }

    private StateData MoveInput()
    {
        StateData stateData = default;

        Vector2 moveInput = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")).normalized;
        stateData.velocity = moveInput;

        stateData.zRotation = transform.eulerAngles.z;

        return stateData;
    }

    [Replicate]
    private void Move(StateData sd, bool asServer, bool replaying = false)
    {
        rb.velocity = sd.velocity * speed;

        if (asServer)
            transform.eulerAngles = new Vector3(transform.eulerAngles.x, transform.eulerAngles.y, sd.zRotation);
    }

Kreyg avatar Nov 26 '22 22:11 Kreyg

Like I said, the rotation has to be done in update to look smooth. The time manager tick doesn't run every frame.

Edit: Oh, I just read the code and saw what you're talking about. I have tried that before and from what I remember, there is still a desync in rotation but it snaps instead of smoothly rotating.

AlphaLul avatar Nov 27 '22 00:11 AlphaLul

Quick update, I found that subscribing the rotation method to the time manager's OnLateUpdate event keeps rotation looking smooth on the local client. However, for some reason, it is still out of sync on observing clients. I'm not sure why this would be, as it is using the time manager now. Maybe that's something you could look in to.

AlphaLul avatar Nov 27 '22 04:11 AlphaLul

Quick update, I found that subscribing the rotation method to the time manager's OnLateUpdate event keeps rotation looking smooth on the local client. However, for some reason, it is still out of sync on observing clients. I'm not sure why this would be, as it is using the time manager now. Maybe that's something you could look in to.

I don't think I'm going to be able to look at this in a timely manner. But given the client auth works fine I can only assume it's your setup causing the desync, rather than a bug. Perhaps we can voice chat today or sometime soon to discuss ideas on getting your desired behavior? That way I can help while working.

FirstGearGames avatar Nov 27 '22 15:11 FirstGearGames

That sounds good, although I'm not sure I'm going to be able to provide much more clarification than what's already in the sample project. Today I tried to make it use just 1 network transform and sync the rotation over CSP, but the issue was still there. I'm not really sure what much more could be wrong with my setup.

If you ever have the time, I think that looking at my setup directly might help find out what the issue is, but a call could help too.

AlphaLul avatar Nov 27 '22 21:11 AlphaLul

Good news! I didn't really find a fix, but I did find a workaround that produces the intended result. Instead of syncing rotation through a client-authoritative network transform, I'm now using a client-authoritative SyncVar that sends the direction that the player is aiming in every 0.02 seconds. Then, I have every observing client use the synced aim direction to do the rotation on their own, and I added some simple interpolation to smooth it out. This setup allows the rotation to be done in Update on all clients, keeping it smooth and always pointing directly at the intended point.

So, I guess the problem is solved now but I do want to ask, is this less performant than a network transform? If anything I'd imagine it would be more performant since I'm only syncing a simple Vector2, but I'm not sure if network transforms are more optimized than SyncVars. So far I haven't noticed any problems, but the game at this point is still just a few characters running around in an empty room. Will using a SyncVar instead of a network transform cause performance issues later down the line? If not, I guess our work is done here.

AlphaLul avatar Nov 30 '22 03:11 AlphaLul

Closing this out, but still up for exploring your options via voice chat some time.

FirstGearGames avatar Dec 04 '22 22:12 FirstGearGames