| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 | 
							- using System;
 
- using System.Collections;
 
- using System.Collections.Generic;
 
- using UnityEngine;
 
- namespace Mirror.Examples.LagCompensationDemo
 
- {
 
-     public class ClientCube : MonoBehaviour
 
-     {
 
-         [Header("Components")]
 
-         public ServerCube server;
 
-         public Renderer render;
 
-         [Header("Toggle")]
 
-         public bool interpolate = true;
 
-         // snapshot interpolation settings
 
-         [Header("Snapshot Interpolation")]
 
-         public SnapshotInterpolationSettings snapshotSettings =
 
-             new SnapshotInterpolationSettings();
 
-         // runtime settings
 
-         public double bufferTime => server.sendInterval * snapshotSettings.bufferTimeMultiplier;
 
-         // <servertime, snaps>
 
-         public SortedList<double, Snapshot3D> snapshots = new SortedList<double, Snapshot3D>();
 
-         // for smooth interpolation, we need to interpolate along server time.
 
-         // any other time (arrival on client, client local time, etc.) is not
 
-         // going to give smooth results.
 
-         internal double localTimeline;
 
-         // catchup / slowdown adjustments are applied to timescale,
 
-         // to be adjusted in every update instead of when receiving messages.
 
-         double localTimescale = 1;
 
-         // we use EMA to average the last second worth of snapshot time diffs.
 
-         // manually averaging the last second worth of values with a for loop
 
-         // would be the same, but a moving average is faster because we only
 
-         // ever add one value.
 
-         ExponentialMovingAverage driftEma;
 
-         ExponentialMovingAverage deliveryTimeEma; // average delivery time (standard deviation gives average jitter)
 
-         // debugging ///////////////////////////////////////////////////////////
 
-         [Header("Debug")]
 
-         public Color hitColor      = Color.blue;
 
-         public Color missedColor   = Color.magenta;
 
-         public Color originalColor = Color.black;
 
-         [Header("Simulation")]
 
-         bool lowFpsMode;
 
-         double accumulatedDeltaTime;
 
-         void Awake()
 
-         {
 
-             // defaultColor = render.sharedMaterial.color;
 
-             // initialize EMA with 'emaDuration' seconds worth of history.
 
-             // 1 second holds 'sendRate' worth of values.
 
-             // multiplied by emaDuration gives n-seconds.
 
-             driftEma = new ExponentialMovingAverage(server.sendRate * snapshotSettings.driftEmaDuration);
 
-             deliveryTimeEma = new ExponentialMovingAverage(server.sendRate * snapshotSettings.deliveryTimeEmaDuration);
 
-         }
 
-         // add snapshot & initialize client interpolation time if needed
 
-         public void OnMessage(Snapshot3D snap)
 
-         {
 
-             // set local timestamp (= when it was received on our end)
 
-             // Unity 2019 doesn't have Time.timeAsDouble yet
 
-             snap.localTime = NetworkTime.localTime;
 
-             // (optional) dynamic adjustment
 
-             if (snapshotSettings.dynamicAdjustment)
 
-             {
 
-                 // set bufferTime on the fly.
 
-                 // shows in inspector for easier debugging :)
 
-                 snapshotSettings.bufferTimeMultiplier = SnapshotInterpolation.DynamicAdjustment(
 
-                     server.sendInterval,
 
-                     deliveryTimeEma.StandardDeviation,
 
-                     snapshotSettings.dynamicAdjustmentTolerance
 
-                 );
 
-             }
 
-             // insert into the buffer & initialize / adjust / catchup
 
-             SnapshotInterpolation.InsertAndAdjust(
 
-                 snapshots,
 
-                 snapshotSettings.bufferLimit,
 
-                 snap,
 
-                 ref localTimeline,
 
-                 ref localTimescale,
 
-                 server.sendInterval,
 
-                 bufferTime,
 
-                 snapshotSettings.catchupSpeed,
 
-                 snapshotSettings.slowdownSpeed,
 
-                 ref driftEma,
 
-                 snapshotSettings.catchupNegativeThreshold,
 
-                 snapshotSettings.catchupPositiveThreshold,
 
-                 ref deliveryTimeEma);
 
-         }
 
-         void Update()
 
-         {
 
-             // accumulated delta allows us to simulate correct low fps + deltaTime
 
-             // if necessary in client low fps mode.
 
-             accumulatedDeltaTime += Time.unscaledDeltaTime;
 
-             // simulate low fps mode. only update once per second.
 
-             // to simulate webgl background tabs, etc.
 
-             // after a while, disable low fps mode and see how it behaves.
 
-             if (lowFpsMode && accumulatedDeltaTime < 1) return;
 
-             // only while we have snapshots.
 
-             // timeline starts when the first snapshot arrives.
 
-             if (snapshots.Count > 0)
 
-             {
 
-                 // snapshot interpolation
 
-                 if (interpolate)
 
-                 {
 
-                     // step
 
-                     SnapshotInterpolation.Step(
 
-                         snapshots,
 
-                         // accumulate delta is Time.unscaledDeltaTime normally.
 
-                         // and sum of past 10 delta's in low fps mode.
 
-                         accumulatedDeltaTime,
 
-                         ref localTimeline,
 
-                         localTimescale,
 
-                         out Snapshot3D fromSnapshot,
 
-                         out Snapshot3D toSnapshot,
 
-                         out double t);
 
-                     // interpolate & apply
 
-                     Snapshot3D computed = Snapshot3D.Interpolate(fromSnapshot, toSnapshot, t);
 
-                     transform.position = computed.position;
 
-                 }
 
-                 // apply raw
 
-                 else
 
-                 {
 
-                     Snapshot3D snap = snapshots.Values[0];
 
-                     transform.position = snap.position;
 
-                     snapshots.RemoveAt(0);
 
-                 }
 
-             }
 
-             // reset simulation helpers
 
-             accumulatedDeltaTime = 0;
 
-         }
 
-         void OnMouseDown()
 
-         {
 
-             // send the command.
 
-             // only x coordinate matters for this simple example.
 
-             if (server.CmdClicked(transform.position))
 
-             {
 
-                 Debug.Log($"Click hit!");
 
-                 FlashColor(hitColor);
 
-             }
 
-             else
 
-             {
 
-                 Debug.Log($"Click missed!");
 
-                 FlashColor(missedColor);
 
-             }
 
-         }
 
-         // simple visual indicator for better feedback.
 
-         // changes the cube's color for a short time.
 
-         void FlashColor(Color color) =>
 
-             StartCoroutine(TemporarilyChangeColorToGreen(color));
 
-         IEnumerator TemporarilyChangeColorToGreen(Color color)
 
-         {
 
-             Renderer r = GetComponentInChildren<Renderer>();
 
-             r.material.color = color;
 
-             yield return new WaitForSeconds(0.2f);
 
-             r.material.color = originalColor;
 
-         }
 
-         void OnGUI()
 
-         {
 
-             // display buffer size as number for easier debugging.
 
-             // catchup is displayed as color state in Update() already.
 
-             const int width = 30; // fit 3 digits
 
-             const int height = 20;
 
-             Vector2 screen = Camera.main.WorldToScreenPoint(transform.position);
 
-             string str = $"{snapshots.Count}";
 
-             GUI.Label(new Rect(screen.x - width / 2, screen.y - height / 2, width, height), str);
 
-             // client simulation buttons on the bottom of the screen
 
-             float areaHeight = 150;
 
-             GUILayout.BeginArea(new Rect(0, Screen.height - areaHeight, Screen.width, areaHeight));
 
-             GUILayout.Label("Click the black cube. Lag compensation will correct the latency.");
 
-             GUILayout.BeginHorizontal();
 
-             GUILayout.Label("Client Simulation:");
 
-             if (GUILayout.Button((lowFpsMode ? "Disable" : "Enable") + " 1 FPS"))
 
-             {
 
-                 lowFpsMode = !lowFpsMode;
 
-             }
 
-             GUILayout.Label("|");
 
-             if (GUILayout.Button("Timeline 10s behind"))
 
-             {
 
-                 localTimeline -= 10.0;
 
-             }
 
-             if (GUILayout.Button("Timeline 1s behind"))
 
-             {
 
-                 localTimeline -= 1.0;
 
-             }
 
-             if (GUILayout.Button("Timeline 0.1s behind"))
 
-             {
 
-                 localTimeline -= 0.1;
 
-             }
 
-             GUILayout.Label("|");
 
-             if (GUILayout.Button("Timeline 0.1s ahead"))
 
-             {
 
-                 localTimeline += 0.1;
 
-             }
 
-             if (GUILayout.Button("Timeline 1s ahead"))
 
-             {
 
-                 localTimeline += 1.0;
 
-             }
 
-             if (GUILayout.Button("Timeline 10s ahead"))
 
-             {
 
-                 localTimeline += 10.0;
 
-             }
 
-             GUILayout.FlexibleSpace();
 
-             GUILayout.EndHorizontal();
 
-             GUILayout.EndArea();
 
-         }
 
-         void OnValidate()
 
-         {
 
-             // thresholds need to be <0 and >0
 
-             snapshotSettings.catchupNegativeThreshold = Math.Min(snapshotSettings.catchupNegativeThreshold, 0);
 
-             snapshotSettings.catchupPositiveThreshold = Math.Max(snapshotSettings.catchupPositiveThreshold, 0);
 
-         }
 
-     }
 
- }
 
 
  |