SFS Islands demo - is there a bug?

Post here your questions about the Unity / .Net / Mono / Windows 8 / Windows Phone 8 API for SFS2X

Moderators: Lapo, Bax

COB
Posts: 68
Joined: 28 Dec 2010, 08:54

SFS Islands demo - is there a bug?

Postby COB » 10 May 2011, 14:59

I use SFS Islands scripts as a base for the network communication in my project. Some time ago I have migrated to SFS2X. Now my NetworkTransformReceiver looks like this:

Code: Select all

using UnityEngine;
using System.Collections;
using System;

using Sfs2X;
using Sfs2X.Core;
using Sfs2X.Entities;
using Sfs2X.Entities.Data;
using Sfs2X.Requests;
using Sfs2X.Logging;

public class NetworkTransformReceiver : MonoBehaviour {
   
   public float yAdjust = 0.0f; // Ajust y position when synchronizing the local and remote models.
   public float interpolationPeriod = 0.1f;  // This value should be equal to the sendingPerion value of the Sender script
   
   private bool receiveMode = false;
   private NetworkTransform lastState; // Last received transform state
   private NetworkTransform interpolateTo = null;  // Last state we interpolate to in receiving mode.
   private NetworkTransform interpolateFrom;  // Point from which to start interpolation
   
   private int interpolationPoint = 0; // Current interpolation point
   private int maxInterpolationPoints = 0; // Maximum number of interpolation points;
   private float interpolationDelta = 0; // Delta value by which interpolate
   
   private FPSStorage fpsStorage;
   private Queue queue = new Queue();  // Queue to store transform states for interpolations
         
   // We call it on remote player to start receiving his transform
   void StartReceiving() {
      lastState = new NetworkTransform(this.gameObject);   
      fpsStorage = GameObject.Find("FPS").GetComponent(typeof(FPSStorage)) as FPSStorage;
      receiveMode = true;
   }
   
   void Update() {
      if (receiveMode) {
         InterpolateTransform();
      }
   }
      
   //This method is called when receiving remote transform
   // We update lastState here to know last received transform state
   void ReceiveTransform(SFSObject data) {
      if (receiveMode) {
         Vector3 pos = new Vector3(Convert.ToSingle(data.GetDouble("x")),
                              Convert.ToSingle(data.GetDouble("y"))+yAdjust,
                              Convert.ToSingle(data.GetDouble("z"))
                              );
                              
         Quaternion rot = new Quaternion(Convert.ToSingle(data.GetDouble("rx")),
                              Convert.ToSingle(data.GetDouble("ry")),
                              Convert.ToSingle(data.GetDouble("rz")),
                              Convert.ToSingle(data.GetDouble("w"))
      
         );
         
         lastState.InitFromValues(pos, rot);
      
         // Adding next received state to the queue   
         NetworkTransform nextState = new NetworkTransform(this.gameObject);
         nextState.InitFromValues(pos, rot);
         queue.Enqueue(nextState);
      }
   }
      
   // This method is called in every Fixed Update in receiving mode. And it does transform interpolation to the latest state.
   void InterpolateTransform() {
         // If interpolationg
         if (interpolationPoint < maxInterpolationPoints) {
            interpolationPoint++;
            float t = interpolationPoint*interpolationDelta;
            if (t>1) t=1;
            transform.position = Vector3.Lerp(interpolateFrom.position, interpolateTo.position, t);
            transform.rotation = Quaternion.Slerp(interpolateFrom.rotation, interpolateTo.rotation, t);
         }
         else {
            // Finished interpolating to the next point
            if (interpolateTo!=null) {
               // Fixing interpolation result to set transform right to the next point
               transform.position = interpolateTo.position;
               transform.rotation = interpolateTo.rotation;
            }
                  
            // Take new value from queue
            if (queue.Count!=0) {
                  NetworkTransform nextTransform = queue.Dequeue() as NetworkTransform;
                  //Start interpolation to the next transform
                  // Set new final interpolation state and reset interpolationPoint
                  interpolateTo = nextTransform;
                  // Set new point from which to start interpolation as current transform
                  interpolateFrom = new NetworkTransform(this.gameObject);
                     
                  interpolationPoint = 0;
                  float frameRate = fpsStorage.GetCurrentFPS();
                                          
                  // Calculate the total number of interpolation points as number of frames during interpolationPriod
                  maxInterpolationPoints = Convert.ToInt32(Math.Round(frameRate * interpolationPeriod));
                                 
                  // Reset interpolation deltaTime
                  interpolationDelta = 1.0f / Convert.ToSingle(maxInterpolationPoints);
            }
            else {
               // If queue is empty just setting the transform to the last received state
               transform.position = lastState.position;
               transform.rotation = lastState.rotation;
            }
         }   
   }
   
}


I don't think that there are major changes. First thing is that comment says that InterpolateTransform is called in every FixedUpdate, but in fact it is called in every Update. However, this is not so important.
I noticed that big "lags" can be observed in my application. What is strange, I checked network communication and there are no real lags. After some analysis of the above script I noticed that when other player is moving all the time my queue is growing almost constantly and this produces huge lag. This is strange because during normal usage queue should be almost empty all the time. When player is moving all the time, the new coordinates are sent after each 0,1s (interpolationPeriod set to 0.1f on sender and receiver), but this should not ba a problem. Scripts contains an interpolation which is using fpsStorage.GetCurrentFPS() and a minute ago I noticed that fpsStorage calculates FPS in a strange way. Here is an Update in which this is done:

Code: Select all

function Update()
{
    ++frames;
    var newSample = Time.realtimeSinceStartup;
    var deltaTime = newSample - lastSample;
    lastSample = newSample;

    timeleft -= deltaTime;
    accum += 1.0 / deltaTime;
   
    // Interval ended - update GUI text and start new interval
    if( timeleft <= 0.0 )
    {
        // display two fractional digits (f2 format)
        fps = accum/frames;
        if (fps!=oldFps) {
           oldFps = fps;
           SendMessage("FPSChanged", fps);
        }
       
        guiText.text = fps.ToString("f2");
      SendMessage("DisplayFPS", fps.ToString("f2"));
      
        timeleft = updateInterval;
        accum = 0.0;
        frames = 0;
        ++gotIntervals;
    }

As you can see fps is calculated not as a number of frames per second, but rather as an average value of the momentary FPS values and this in my opinion is wrong, because interpolation mechanism is not working well in specific conditions. For example if we take 2 frames one is displayed for 0.25s and the second one for 0.75s, for me it's obvious that FPS is 2 (2/(0.25 + 0.75)). However, above script will give different result: (1/0.25 + 1/0.75)/2=~2.67. Both methods will give similar values when frame rate is quite constant, but as you can see it can be very different when it's not. Value is higher and iterpolation between each stateis taking more time that it should. This causes queue to grow...
Can somebody please check my theory? Why FPS are calculated in such strange way in this script?

Return to “SFS2X C# API”

Who is online

Users browsing this forum: No registered users and 75 guests