Trying to use UDP to validate movement on server side

Post here your questions about SFS2X. Here we discuss all server-side matters. For client API questions see the dedicated forums.

Moderators: Lapo, Bax

Post Reply
SmartfoxEnjoyer
Posts: 93
Joined: 13 Dec 2023, 20:39

Trying to use UDP to validate movement on server side

Post by SmartfoxEnjoyer »

Hi,

Im working on server side validated movement in a 3d environment

But for some reason UDP is very unpredictable. My Unity Client runs at a fixed 50 FPS, so every 0.02 seconds or 20milliseconds it sends an UDP TransformUpdate request.

But on the serverside the UDP request sometimes has a deltaTime since last request of 0 milliseconds or 5 milliseconds 0_0 while the distance between the two transform updates can swing wildly from 0.1meter to 0.4m....

This doesnt make any sense, so I was thinking multiple threads are calling my UpdateTransform on serverside at the same time, resulting in a deltaTime betweenn requests of 0 milliseconds, but this is also not true as I have made all my methods synchronized and it still happens...

Can someone clarify this or provide some resources for me to learn how to validate movement correctly on a UDP connection?

Heres my debug traces:

Code: Select all

11:27:49,264 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: -----------------
11:27:49,264 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: 1. DeltaMillis since last TransformUpdate: 38
11:27:49,276 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: 2. --- TotalDistance: 4.581507205963135 --- TotalTime: 1.0880000591278076 --- ActualSpeed: 4.2109437
11:27:49,277 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: 3. --------------- Speed Evaluation: 0.8421887 ----- QueueSize: 50
11:27:49,278 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: -----------------


11:27:49,278 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: -----------------
11:27:49,278 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: 1. DeltaMillis since last TransformUpdate: 0
11:27:49,279 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: 1. newTransform.Milliseconds: 173989500 lastPos.Milliseconds: 173989500
11:27:49,280 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: 2. --- TotalDistance: 4.59747838973999 --- TotalTime: 1.0369999408721924 --- ActualSpeed: 4.433441
11:27:49,280 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: 3. --------------- Speed Evaluation: 0.88668823 ----- QueueSize: 50
11:27:49,281 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: -----------------


11:27:49,296 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: -----------------
11:27:49,296 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: 1. DeltaMillis since last TransformUpdate: 31
11:27:49,310 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: 2. --- TotalDistance: 4.542852878570557 --- TotalTime: 1.0509999990463257 --- ActualSpeed: 4.32241
11:27:49,311 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: 3. --------------- Speed Evaluation: 0.86448205 ----- QueueSize: 50
11:27:49,312 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: -----------------


11:27:52,358 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: -----------------
11:27:52,360 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: 1. DeltaMillis since last TransformUpdate: 50
11:27:52,374 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: 2. --- TotalDistance: 0.42358484864234924 --- TotalTime: 0.1379999965429306 --- ActualSpeed: 3.0694554
11:27:52,375 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: 3. --------------- Speed Evaluation: 0.61389107 ----- QueueSize: 4
11:27:52,382 INFO  [SFSWorker:Ext:1] Extensions     - {__lib__}: -----------------


11:27:52,384 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: -----------------
11:27:52,408 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: 1. DeltaMillis since last TransformUpdate: 121
11:27:52,409 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: 2. --- TotalDistance: 0.828595757484436 --- TotalTime: 0.2590000033378601 --- ActualSpeed: 3.1992114
11:27:52,416 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: 3. --------------- Speed Evaluation: 0.6398423 ----- QueueSize: 5
11:27:52,416 INFO  [SFSWorker:Ext:3] Extensions     - {__lib__}: -----------------


11:27:52,432 INFO  [SFSWorker:Ext:2] Extensions     - {__lib__}: -----------------
11:27:52,434 INFO  [SFSWorker:Ext:2] Extensions     - {__lib__}: 1. DeltaMillis since last TransformUpdate: 2
11:27:52,459 INFO  [SFSWorker:Ext:2] Extensions     - {__lib__}: 1. newTransform.Milliseconds: 173992471 lastPos.Milliseconds: 173992473
11:27:52,461 INFO  [SFSWorker:Ext:2] Extensions     - {__lib__}: 2. --- TotalDistance: 0.9114917516708374 --- TotalTime: 0.26100000739097595 --- ActualSpeed: 3.4923055
11:27:52,466 INFO  [SFSWorker:Ext:2] Extensions     - {__lib__}: 3. --------------- Speed Evaluation: 0.6984611 ----- QueueSize: 6
11:27:52,466 INFO  [SFSWorker:Ext:2] Extensions     - {__lib__}: -----------------


For example:

Code: Select all

11:27:49,278 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: -----------------
11:27:49,278 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: 1. DeltaMillis since last TransformUpdate: 0
11:27:49,279 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: 1. newTransform.Milliseconds: 173989500 lastPos.Milliseconds: 173989500
11:27:49,280 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: 2. --- TotalDistance: 4.59747838973999 --- TotalTime: 1.0369999408721924 --- ActualSpeed: 4.433441
11:27:49,280 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: 3. --------------- Speed Evaluation: 0.88668823 ----- QueueSize: 50
11:27:49,281 INFO  [SFSWorker:Ext:4] Extensions     - {__lib__}: -----------------


QueueSize = a Queue of positions, so I can keep track of distance and time for that whole queue and calculate an average speed for those positions.
SpeedEvaluation = Average Calculated Speed / Actual Allowed Speed. (ex: average speed: 10 / allowedSpeed = 5 evaluates to 2.0f) (Too High!)

Other variables should be clear by their name.

So the problem is as you can see in the logs, sometimes there is 0 milliseconds between requests, other time 2 or 3 milliseconds, othertimes 50 or 200 milliseconds, the higher values are expected as UDP is unreliable, but extremely low values are weird??

Heres how I calculate deltaMillis:
1. Server receive request, call System.nanoTime / 1_000_000 to get milliseconds.
2. I check Check that against the last timestamp, from previous request for that character ( Math.abs(lastTimestamp - thisTimestamp)
3. Store this timestamp so we can compare it with the next one.

My code:

Code: Select all

    synchronized static boolean IsValidPosition(
            Transform newTransform,
            PositionQueue positionQueue,
            float maxSpeed) {

        TimedVector3 lastPos = positionQueue.GetLastAdded();
        if (lastPos == null) {

            positionQueue.Add(new TimedVector3(newTransform.Position, newTransform.Milliseconds));

            return true;
        }
       
        // When server receives request it creates a new Transform object which stores the current nanoTime as a timestamp.
        long deltaMillis = Math.abs(newTransform.Milliseconds - lastPos.Milliseconds);
        if (deltaMillis < 6) {
            _ext.trace("-----------------");
            _ext.trace("1. DeltaMillis since last TransformUpdate: " + deltaMillis);
            _ext.trace("1. newTransform.Milliseconds: " + newTransform.Milliseconds + " lastPos.Milliseconds: "
                    + lastPos.Milliseconds);

            positionQueue.Add(new TimedVector3(newTransform.Position, newTransform.Milliseconds));

            return IsValidSpeed(positionQueue, maxSpeed);
        }

        _ext.trace("-----------------");
        _ext.trace("1. DeltaMillis since last TransformUpdate: " + deltaMillis);

        if (deltaMillis > _maxDeltaMillis) {

            positionQueue.Clear();

            positionQueue.Add(new TimedVector3(newTransform.Position, newTransform.Milliseconds));

            return true;
        }

        positionQueue.Add(new TimedVector3(newTransform.Position, newTransform.Milliseconds));

        return IsValidSpeed(positionQueue, maxSpeed);
    }

How is this possible that 2 UDP packets arrive at the same time even though they get sent in 20ms intervals?
It only happens rarely maybe once every 50 packets, so once every second, but it can also happen multiple times in a row in rare occasions.
So the behaviour fluctuates a lot, and Im sure my client is sending one UDP packet every +-20ms, ofcourse it can be 15ms or 25ms but not 0-5ms?

Heres my Unity code btw:

Code: Select all

void FixedUpdate(){
        OnMoveEvent?.Invoke(transform.position, transform.eulerAngles);
}


Thanks!
Last edited by SmartfoxEnjoyer on 20 Jan 2024, 12:53, edited 1 time in total.
SmartfoxEnjoyer
Posts: 93
Joined: 13 Dec 2023, 20:39

Re: Trying to use UDP to validate movement on server side

Post by SmartfoxEnjoyer »

A lot of times when I post a question on the forums after multiple days of trying to find the error, I find the solution on my own just an hour or so later...

I guess I just love to post tutorials veiled as questions lmao...

Anyway for anyone who has this problema...

Dont use FixedUpdate

Make your own Updater that counts 20ms inside Unity and use that, it solved all my problems, now the speed im doing in Unity Client is actually almost the same as the average im calculating server side (using the queue) and the deltaMillis doesnt read 0 or 5 ms anymore. (FixedUpdate can be called by Unity multiples times during 1 frame apparently, and I already knew that but kind of forgot I guess).

Anyway thanks for reading my blog

Cheers
Post Reply