[Add] FishNet
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31f64c354c60cc748a3c0956b14def5b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,78 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Managing.Timing.Editing
|
||||
{
|
||||
[CustomEditor(typeof(TimeManager), true)]
|
||||
[CanEditMultipleObjects]
|
||||
public class TimeManagerEditor : Editor
|
||||
{
|
||||
private SerializedProperty _updateOrder;
|
||||
private SerializedProperty _timingType;
|
||||
private SerializedProperty _tickRate;
|
||||
private SerializedProperty _allowTickDropping;
|
||||
private SerializedProperty _maximumFrameTicks;
|
||||
private SerializedProperty _pingInterval;
|
||||
// private SerializedProperty _timingInterval;
|
||||
private SerializedProperty _physicsMode;
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
_updateOrder = serializedObject.FindProperty("_updateOrder");
|
||||
_timingType = serializedObject.FindProperty("_timingType");
|
||||
_tickRate = serializedObject.FindProperty("_tickRate");
|
||||
_allowTickDropping = serializedObject.FindProperty("_allowTickDropping");
|
||||
_maximumFrameTicks = serializedObject.FindProperty("_maximumFrameTicks");
|
||||
_pingInterval = serializedObject.FindProperty("_pingInterval");
|
||||
// _timingInterval = serializedObject.FindProperty("_timingInterval");
|
||||
_physicsMode = serializedObject.FindProperty("_physicsMode");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
GUI.enabled = false;
|
||||
EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour((TimeManager)target), typeof(TimeManager), false);
|
||||
GUI.enabled = true;
|
||||
|
||||
// Timing.
|
||||
EditorGUILayout.LabelField("Timing", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_updateOrder);
|
||||
EditorGUILayout.PropertyField(_timingType);
|
||||
EditorGUILayout.PropertyField(_allowTickDropping);
|
||||
if (_allowTickDropping.boolValue == true)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(_maximumFrameTicks);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
EditorGUILayout.PropertyField(_tickRate);
|
||||
EditorGUILayout.PropertyField(_pingInterval);
|
||||
// EditorGUILayout.PropertyField(_timingInterval);
|
||||
EditorGUI.indentLevel--;
|
||||
EditorGUILayout.Space();
|
||||
|
||||
// Physics.
|
||||
EditorGUILayout.LabelField("Physics", EditorStyles.boldLabel);
|
||||
EditorGUI.indentLevel++;
|
||||
if (_physicsMode.intValue == (int)PhysicsMode.TimeManager)
|
||||
EditorGUILayout.HelpBox($"Time.fixedDeltaTime will be overridden with TimeManager.TickDelta ({(1f / (float)_tickRate.intValue).ToString("0.###")})", MessageType.Info);
|
||||
else
|
||||
EditorGUILayout.HelpBox("If you are using physics interactions be sure to change the PhysicsMode to TimeManager and implement physics within the TimeManager tick events. NetworkTransform may also jitter when not using PhysicsMode.TimeManager.", MessageType.Warning);
|
||||
EditorGUILayout.PropertyField(_physicsMode);
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
////Prediction.
|
||||
// EditorGUILayout.LabelField("Prediction", EditorStyles.boldLabel);
|
||||
// EditorGUI.indentLevel++;
|
||||
// EditorGUILayout.PropertyField(_maximumBufferedInputs);
|
||||
// EditorGUI.indentLevel--;
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12987a8c0302190489ecb55f6fbd494e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,96 @@
|
||||
using FishNet.Documenting;
|
||||
using System;
|
||||
|
||||
namespace FishNet.Managing.Timing
|
||||
{
|
||||
[APIExclude]
|
||||
public class MovingAverage : IDisposable
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// Average from samples favoring the most recent sample.
|
||||
/// </summary>
|
||||
public float Average { get; private set; }
|
||||
/// <summary>
|
||||
/// Sample size being used.
|
||||
/// </summary>
|
||||
public int SampleSize { get; private set; }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Next index to write a sample to.
|
||||
/// </summary>
|
||||
private int _writeIndex;
|
||||
/// <summary>
|
||||
/// Collected samples.
|
||||
/// </summary>
|
||||
private float[] _samples;
|
||||
/// <summary>
|
||||
/// Number of samples written. Will be at most samples size.
|
||||
/// </summary>
|
||||
private int _writtenSamples;
|
||||
/// <summary>
|
||||
/// Samples accumulated over queue.
|
||||
/// </summary>
|
||||
private float _sampleAccumulator;
|
||||
|
||||
public MovingAverage(int sampleSize)
|
||||
{
|
||||
if (sampleSize < 2)
|
||||
{
|
||||
NetworkManagerExtensions.LogWarning("Using a sampleSize of less than 2 will always return the most recent value as Average.");
|
||||
sampleSize = 1;
|
||||
}
|
||||
|
||||
SampleSize = sampleSize;
|
||||
_samples = new float[sampleSize];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a new windowed average each time a new sample arrives
|
||||
/// </summary>
|
||||
/// <param name = "newSample"></param>
|
||||
public void ComputeAverage(float newSample)
|
||||
{
|
||||
if (_samples.Length <= 1)
|
||||
{
|
||||
Average = newSample;
|
||||
return;
|
||||
}
|
||||
|
||||
_sampleAccumulator += newSample;
|
||||
_samples[_writeIndex] = newSample;
|
||||
|
||||
// Increase writeIndex.
|
||||
_writeIndex++;
|
||||
_writtenSamples = Math.Max(_writtenSamples, _writeIndex);
|
||||
if (_writeIndex >= _samples.Length)
|
||||
_writeIndex = 0;
|
||||
|
||||
Average = _sampleAccumulator / _writtenSamples;
|
||||
|
||||
/* If samples are full then drop off
|
||||
* the oldest sample. This will always be
|
||||
* the one just after written. The entry isn't
|
||||
* actually removed from the array but will
|
||||
* be overwritten next sample. */
|
||||
if (_writtenSamples >= _samples.Length)
|
||||
_sampleAccumulator -= _samples[_writeIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets values.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_sampleAccumulator = 0f;
|
||||
_writeIndex = 0;
|
||||
_writtenSamples = 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03d05f88778c5c744810e48f251f2d3b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace FishNet.Managing.Timing
|
||||
{
|
||||
/// <summary>
|
||||
/// How to simulate physics.
|
||||
/// </summary>
|
||||
public enum PhysicsMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Unity performs physics every FixedUpdate.
|
||||
/// </summary>
|
||||
Unity = 0,
|
||||
/// <summary>
|
||||
/// TimeManager performs physics each tick.
|
||||
/// </summary>
|
||||
TimeManager = 1,
|
||||
/// <summary>
|
||||
/// Physics will be disabled.
|
||||
/// </summary>
|
||||
Disabled = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 502e9f31bebd41f4f9088a19eae53735
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,195 @@
|
||||
using System;
|
||||
using FishNet.Serializing;
|
||||
using GameKit.Dependencies.Utilities;
|
||||
|
||||
namespace FishNet.Managing.Timing
|
||||
{
|
||||
public readonly struct PreciseTick : IEquatable<PreciseTick>
|
||||
{
|
||||
/// <summary>
|
||||
/// The current tick.
|
||||
/// </summary>
|
||||
public readonly uint Tick;
|
||||
/// <summary>
|
||||
/// Percentage of the tick returned between 0d and 1d.
|
||||
/// </summary>
|
||||
public readonly double PercentAsDouble;
|
||||
/// <summary>
|
||||
/// Percentage of the tick returned between 0 and 100.
|
||||
/// </summary>
|
||||
public readonly byte PercentAsByte;
|
||||
/// <summary>
|
||||
/// Maximum value a percent can be as a double.
|
||||
/// </summary>
|
||||
public const double MAXIMUM_DOUBLE_PERCENT = 1d;
|
||||
/// <summary>
|
||||
/// Maximum value a percent can be as a byte.
|
||||
/// </summary>
|
||||
public const byte MAXIMUM_BYTE_PERCENT = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Value to use when a precise tick is unset.
|
||||
/// </summary>
|
||||
public static PreciseTick GetUnsetValue() => new(TimeManager.UNSET_TICK, (byte)0);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a precise tick where the percentage is 0.
|
||||
/// </summary>
|
||||
public PreciseTick(uint tick)
|
||||
{
|
||||
Tick = tick;
|
||||
PercentAsByte = 0;
|
||||
PercentAsDouble = 0d;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a precise tick where the percentage is a byte between 0 and 100.
|
||||
/// </summary>
|
||||
public PreciseTick(uint tick, byte percentAsByte)
|
||||
{
|
||||
Tick = tick;
|
||||
|
||||
percentAsByte = Maths.ClampByte(percentAsByte, 0, MAXIMUM_BYTE_PERCENT);
|
||||
PercentAsByte = percentAsByte;
|
||||
PercentAsDouble = percentAsByte / 100d;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a precise tick where the percentage is a double between 0d and 1d.
|
||||
/// </summary>
|
||||
public PreciseTick(uint tick, double percent)
|
||||
{
|
||||
Tick = tick;
|
||||
percent = Maths.ClampDouble(percent, 0d, MAXIMUM_DOUBLE_PERCENT);
|
||||
PercentAsByte = (byte)(percent * 100d);
|
||||
PercentAsDouble = percent;
|
||||
}
|
||||
|
||||
public bool IsValid() => Tick != TimeManager.UNSET_TICK;
|
||||
|
||||
/// <summary>
|
||||
/// Prints PreciseTick information as a string.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString() => $"Tick {Tick}, Percent {PercentAsByte.ToString("000")}";
|
||||
|
||||
public static bool operator ==(PreciseTick a, PreciseTick b)
|
||||
{
|
||||
return a.Tick == b.Tick && a.PercentAsByte == b.PercentAsByte;
|
||||
}
|
||||
|
||||
public static bool operator !=(PreciseTick a, PreciseTick b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public static bool operator >=(PreciseTick a, PreciseTick b)
|
||||
{
|
||||
if (b.Tick > a.Tick)
|
||||
return false;
|
||||
if (a.Tick > b.Tick)
|
||||
return true;
|
||||
// If here ticks are the same.
|
||||
return a.PercentAsByte >= b.PercentAsByte;
|
||||
}
|
||||
|
||||
public static bool operator <=(PreciseTick a, PreciseTick b) => b >= a;
|
||||
|
||||
public static bool operator >(PreciseTick a, PreciseTick b)
|
||||
{
|
||||
if (b.Tick > a.Tick)
|
||||
return false;
|
||||
if (a.Tick > b.Tick)
|
||||
return true;
|
||||
// if here ticks are the same.
|
||||
return a.PercentAsByte > b.PercentAsByte;
|
||||
}
|
||||
|
||||
public static bool operator <(PreciseTick a, PreciseTick b) => b > a;
|
||||
public bool Equals(PreciseTick other) => Tick == other.Tick && PercentAsByte == other.PercentAsByte;
|
||||
public override bool Equals(object obj) => obj is PreciseTick other && Equals(other);
|
||||
public override int GetHashCode() => HashCode.Combine(Tick, PercentAsDouble, PercentAsByte);
|
||||
}
|
||||
|
||||
public static class PreciseTickExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds value onto a PreciseTick.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to add.</param>
|
||||
/// <param name = "delta">Tick delta.</param>
|
||||
/// <returns></returns>
|
||||
public static PreciseTick Add(this PreciseTick pt, PreciseTick value, double delta)
|
||||
{
|
||||
double ptDouble = pt.AsDouble(delta);
|
||||
double valueDouble = value.AsDouble(delta);
|
||||
|
||||
double next = ptDouble + valueDouble;
|
||||
|
||||
return next.AsPreciseTick(delta);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts value from a PreciseTick.
|
||||
/// </summary>
|
||||
/// <param name = "value">Value to subtract.</param>
|
||||
/// <param name = "delta">Tick delta.</param>
|
||||
/// <returns></returns>
|
||||
public static PreciseTick Subtract(this PreciseTick pt, PreciseTick value, double delta)
|
||||
{
|
||||
double ptDouble = pt.AsDouble(delta);
|
||||
double valueDouble = value.AsDouble(delta);
|
||||
|
||||
double remainder = ptDouble - valueDouble;
|
||||
|
||||
return remainder.AsPreciseTick(delta);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a PreciceTick to a double.
|
||||
/// </summary>
|
||||
/// <param name = "delta">Tick delta.</param>
|
||||
/// <returns></returns>
|
||||
public static double AsDouble(this PreciseTick pt, double delta)
|
||||
{
|
||||
return (double)pt.Tick * delta + pt.PercentAsDouble * delta;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a double to a PreciseTick.
|
||||
/// </summary>
|
||||
/// <param name = "delta">Tick delta.</param>
|
||||
/// <returns></returns>
|
||||
public static PreciseTick AsPreciseTick(this double ptDouble, double delta)
|
||||
{
|
||||
if (ptDouble <= 0)
|
||||
return new(0, 0);
|
||||
|
||||
ulong whole = (ulong)Math.Floor(ptDouble / delta);
|
||||
// Overflow.
|
||||
if (whole >= uint.MaxValue)
|
||||
return PreciseTick.GetUnsetValue();
|
||||
|
||||
double remainder = ptDouble % delta;
|
||||
|
||||
double percent = remainder / delta;
|
||||
return new((uint)whole, percent);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PreciseTickSerializer
|
||||
{
|
||||
public static void WritePreciseTick(this Writer writer, PreciseTick value)
|
||||
{
|
||||
writer.WriteTickUnpacked(value.Tick);
|
||||
writer.WriteUInt8Unpacked(value.PercentAsByte);
|
||||
}
|
||||
|
||||
public static PreciseTick ReadPreciseTick(this Reader reader)
|
||||
{
|
||||
uint tick = reader.ReadTickUnpacked();
|
||||
byte percentByte = reader.ReadUInt8Unpacked();
|
||||
return new(tick, percentByte);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a96dd6b21066a424199583b80746464f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,21 @@
|
||||
namespace FishNet.Managing.Timing
|
||||
{
|
||||
/// <summary>
|
||||
/// How ticks are rounded when using time.
|
||||
/// </summary>
|
||||
public enum TickRounding
|
||||
{
|
||||
/// <summary>
|
||||
/// Rounds up.
|
||||
/// </summary>
|
||||
RoundUp,
|
||||
/// <summary>
|
||||
/// Rounds down.
|
||||
/// </summary>
|
||||
RoundDown,
|
||||
/// <summary>
|
||||
/// Rounds to the nearest whole.
|
||||
/// </summary>
|
||||
RoundNearest
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d12f8894fc7343b4bbe332464dc4bce5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs
|
||||
uploadId: 866910
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace FishNet.Managing.Timing
|
||||
{
|
||||
public enum TickType : byte
|
||||
{
|
||||
Tick = 0,
|
||||
LocalTick = 1,
|
||||
LastPacketTick = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 489fba8b0da3c9b4b9ff4e7a46804473
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Managing/Timing/TickType.cs
|
||||
uploadId: 866910
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fdaae44044276a49a52229c1597e33b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: bf9191e2e07d29749bca3a1ae44e4bc8, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 207815
|
||||
packageName: 'FishNet: Networking Evolved'
|
||||
packageVersion: 4.6.22R
|
||||
assetPath: Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs
|
||||
uploadId: 866910
|
||||
Reference in New Issue
Block a user