Update FishNet

This commit is contained in:
2026-04-07 03:11:52 +07:00
parent 9675b7b31d
commit ba7513d478
869 changed files with 3675 additions and 2764 deletions
@@ -112,7 +112,7 @@ namespace FishNet.Managing.Client
}
PooledWriter writer = WriterPool.Retrieve();
BroadcastsSerializers.WriteBroadcast(NetworkManager, writer, message, ref channel);
BroadcastsSerializers.WriteBroadcast(writer, message);
ArraySegment<byte> segment = writer.GetArraySegment();
#if DEVELOPMENT && !UNITY_SERVER
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Client/ClientManager.Broadcast.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Client/ClientManager.QOL.cs
uploadId: 866910
uploadId: 892096
@@ -141,7 +141,32 @@ namespace FishNet.Managing.Client
/// <summary>
/// Used to read splits.
/// </summary>
private SplitReader _splitReader = new();
private SplitReader _splitReader;
/// <summary>
/// Gets the current SplitReader.
/// </summary>
/// <returns></returns>
private bool TryGetSplitReader(int expectedMessages, out SplitReader splitReader)
{
if (_splitReader == null)
{
if (NetworkManager is null)
{
NetworkManagerExtensions.LogError($"SplitReader cannot be returned because the NetworkManager reference is null.");
splitReader = null;
return false;
}
_splitReader = ResettableObjectCaches<SplitReader>.Retrieve();
_splitReader.Initialize(NetworkManager, NetworkManager.TransportManager.MaximumClientPacketSize, isSenderClient: false, expectedMessages);
}
splitReader = _splitReader;
return true;
}
/// <summary>
/// </summary>
[NonSerialized]
@@ -447,18 +472,32 @@ namespace FishNet.Managing.Client
#endif
// Skip packetId.
reader.ReadPacketId();
int expectedMessages;
_splitReader.GetHeader(reader, out expectedMessages);
_splitReader.Write(NetworkManager.TimeManager.LastPacketTick.LastRemoteTick, reader, expectedMessages);
int expectedMessages = reader.ReadInt32();
if (!TryGetSplitReader(expectedMessages, out SplitReader splitReader))
{
NetworkManager.LogError($"Something went wrong when trying to get the [{nameof(splitReader)}] for a server message.");
return;
}
if (!splitReader.Write(reader))
{
NetworkManager.LogError($"Something went wrong when writing a split message from the server.");
return;
}
/* If fullMessage returns 0 count then the split
* has not written fully yet. Otherwise, if there is
* data within then reinitialize reader with the
* full message. */
ArraySegment<byte> fullMessage = _splitReader.GetFullMessage();
if (fullMessage.Count == 0)
if (!splitReader.TryGetFullMessage(out ArraySegment<byte> fullMessage))
return;
reader.Initialize(fullMessage, NetworkManager, dataSource);
//Once here the split reader can be stored.
ResettableObjectCaches<SplitReader>.StoreAndDefault(ref _splitReader);
}
while (reader.Remaining > 0)
@@ -468,16 +507,6 @@ namespace FishNet.Managing.Client
packetId = reader.ReadPacketId();
#if DEVELOPMENT
NetworkManager.PacketIdHistory.ReceivedPacket(packetId, packetFromServer: true);
// if (!NetworkManager.IsServerStarted)
// print = true;
// if (print)
// {
// if (packetId == PacketId.ObserversRpc)
// Debug.Log($"PacketId {packetId} - Remaining {reader.Remaining}.");
// else
// Debug.LogWarning($"PacketId {packetId} - Remaining {reader.Remaining}.");
// }
// print = false;
#endif
}
bool spawnOrDespawn = packetId == PacketId.ObjectSpawn || packetId == PacketId.ObjectDespawn;
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Client/ClientManager.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Client/Editor/ClientManagerEditor.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.RpcLinks.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Debugging/DebugManager.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Debugging/Editor/DebugManagerEditor.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Debugging/PacketIdHistory.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Editor/NetworkManagerEditor.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Logging/Editor/LevelLoggingConfigurationEditor.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Logging/LevelLoggingConfiguration.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Logging/LoggingConfiguration.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Logging/LoggingType.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/NetworkManager.Logging.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/NetworkManager.ObjectPooling.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/NetworkManager.Pro.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/NetworkManager.QOL.cs
uploadId: 866910
uploadId: 892096
@@ -239,7 +239,7 @@ namespace FishNet.Managing
/// <summary>
/// Version of this release.
/// </summary>
public const string FISHNET_VERSION = "4.6.22";
public const string FISHNET_VERSION = "4.7.1";
/// <summary>
/// Maximum framerate allowed.
/// </summary>
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/NetworkManager.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Object/DualPrefab.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Object/ManagedObjects.Spawning.cs
uploadId: 866910
uploadId: 892096
@@ -14,6 +14,7 @@ using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using FishNet.Managing.Server;
using FishNet.Managing.Statistic;
using UnityEngine;
using UnityEngine.SceneManagement;
@@ -41,6 +42,7 @@ namespace FishNet.Managing.Object
/// Invoked when Spawned is cleared.
/// </summary>
public event Action OnSpawnedClear;
/// <summary>
/// Delegate for when there is change to Spawned.
/// </summary>
@@ -48,11 +50,10 @@ namespace FishNet.Managing.Object
#endregion
#region Private Profiler Markers
private static readonly ProfilerMarker _pm_ParseReplicateRpc =
new("ManagedObjects.ParseReplicateRpc(PooledReader, NetworkConnection, Channel)");
private static readonly ProfilerMarker _pm_ParseReplicateRpc = new("ManagedObjects.ParseReplicateRpc(PooledReader, NetworkConnection, Channel)");
#endregion
#region Protected.
#region Protected.
/// <summary>
/// Returns the next ObjectId to use.
/// </summary>
@@ -78,8 +79,8 @@ namespace FishNet.Managing.Object
public IReadOnlyDictionary<ulong, NetworkObject> SceneObjects => SceneObjects_Internal;
/// <summary>
/// </summary>
[NonSerialized] protected NetworkTrafficStatistics NetworkTrafficStatistics;
[NonSerialized]
protected NetworkTrafficStatistics NetworkTrafficStatistics;
/// <summary>
/// Called to add an object to Spawned.
@@ -107,7 +108,6 @@ namespace FishNet.Managing.Object
_spawned.Clear();
OnSpawnedClear?.Invoke();
}
#endregion
#region Private.
@@ -156,13 +156,37 @@ namespace FishNet.Managing.Object
RemoveFromSpawned(nob, fromOnDestroy: true, asServer);
}
/// <summary>
/// Attempts to remove an old ObjectId when an object had called Initialize without deinitializing first.
/// </summary>
/// <returns>True if clean-up was successful.</returns>
internal void ObjectInitializedWithoutDeinitializing(int oldId, NetworkObject callingNetworkObject)
{
// Check for the oldId in spawned.
if (_spawned.TryGetValueIL2CPP(oldId, out NetworkObject oldNetworkObject))
{
/* If the old networkObject is the same as new then remove
* the old entry from spawned and return the Id. */
if (callingNetworkObject == oldNetworkObject || oldNetworkObject == null)
{
_spawned.Remove(oldId);
if (this is ServerObjects serverObjects)
serverObjects.CacheObjectId(oldId);
return;
}
NetworkManager.LogError($"Initialization occurred twice on object {this.ToString()} and recovery not clean up as expected. The prior Id of [{oldId}] belonged to a different object {oldNetworkObject} when it was expected to belong to the first.");
}
}
/// <summary>
/// Removes a NetworkedObject from spawned.
/// </summary>
protected virtual void RemoveFromSpawned(NetworkObject nob, bool fromOnDestroy, bool asServer)
{
RemoveFromSpawnedCollectionAndInvoke(nob);
// Do the same with SceneObjects.
if (fromOnDestroy && nob.IsSceneObject)
RemoveFromSceneObjects(nob);
@@ -378,9 +402,9 @@ namespace FishNet.Managing.Object
/// <param name = "nob"></param>
protected virtual void DespawnWithoutSynchronization(NetworkObject nob, bool recursive, bool asServer, DespawnType despawnType, bool removeFromSpawned)
{
#if FISHNET_STABLE_RECURSIVE_DESPAWNS
#if FISHNET_STABLE_RECURSIVE_DESPAWNS
recursive = false;
#endif
#endif
GetNetworkObjectOption getOption = recursive ? GetNetworkObjectOption.All : GetNetworkObjectOption.Self;
List<NetworkObject> allNobs = nob.GetNetworkObjects(getOption);
@@ -493,11 +517,11 @@ namespace FishNet.Managing.Object
/* Default logging for server is errors only. Use error on client and warning
* on servers to reduce chances of allocation attacks. */
#if DEVELOPMENT_BUILD || UNITY_EDITOR || !UNITY_SERVER
#if DEVELOPMENT_BUILD || UNITY_EDITOR || !UNITY_SERVER
NetworkManager.LogError(msg);
#else
#else
NetworkManager.LogWarning(msg);
#endif
#endif
reader.Clear();
}
/* If length is known then is unreliable packet. It's possible
@@ -524,8 +548,7 @@ namespace FishNet.Managing.Object
using (_pm_ParseReplicateRpc.Auto())
{
#if DEVELOPMENT
NetworkBehaviour.ReadDebugForValidatedRpc(NetworkManager, reader, out int startReaderRemaining,
out string rpcInformation, out uint expectedReadAmount);
NetworkBehaviour.ReadDebugForValidatedRpc(NetworkManager, reader, out int startReaderRemaining, out string rpcInformation, out uint expectedReadAmount);
#endif
int readerStartAfterDebug = reader.Position;
@@ -537,13 +560,12 @@ namespace FishNet.Managing.Object
SkipDataLength((ushort)PacketId.ServerRpc, reader, dataLength);
#if DEVELOPMENT
NetworkBehaviour.TryPrintDebugForValidatedRpc(fromRpcLink: false, NetworkManager, reader,
startReaderRemaining, rpcInformation, expectedReadAmount, channel);
NetworkBehaviour.TryPrintDebugForValidatedRpc(fromRpcLink: false, NetworkManager, reader, startReaderRemaining, rpcInformation, expectedReadAmount, channel);
#endif
}
}
#if DEVELOPMENT
#if DEVELOPMENT
/// <summary>
/// Checks to write a scene object's details into a writer.
/// </summary>
@@ -568,6 +590,6 @@ namespace FishNet.Managing.Object
objectName = r.ReadStringAllocated();
}
}
#endif
#endif
}
}
}
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Object/ObjectSpawnType.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Object/SpawnParentType.cs
uploadId: 866910
uploadId: 892096
@@ -10,13 +10,24 @@ namespace FishNet.Managing.Observing.Editing
{
private SerializedProperty _updateHostVisibility;
private SerializedProperty _maximumTimedObserversDuration;
private SerializedProperty _defaultConditions;
private SerializedProperty _defaultConditions
;
private SerializedProperty _useLevelOfDetail;
private SerializedProperty _maximumLevelOfDetailInterval;
private SerializedProperty _levelOfDetailUpdateDuration;
private SerializedProperty _levelOfDetailDistances;
protected virtual void OnEnable()
{
_updateHostVisibility = serializedObject.FindProperty(nameof(_updateHostVisibility));
_maximumTimedObserversDuration = serializedObject.FindProperty(nameof(_maximumTimedObserversDuration));
_defaultConditions = serializedObject.FindProperty(nameof(_defaultConditions));
_useLevelOfDetail = serializedObject.FindProperty(nameof(_useLevelOfDetail));
_maximumLevelOfDetailInterval = serializedObject.FindProperty(nameof(_maximumLevelOfDetailInterval));
_levelOfDetailUpdateDuration = serializedObject.FindProperty(nameof(_levelOfDetailUpdateDuration));
_levelOfDetailDistances = serializedObject.FindProperty(nameof(_levelOfDetailDistances));
}
public override void OnInspectorGUI()
@@ -27,7 +38,7 @@ namespace FishNet.Managing.Observing.Editing
EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour((ObserverManager)target), typeof(ObserverManager), false);
GUI.enabled = true;
EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel);
EditorGUILayout.LabelField("Observers", EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(_updateHostVisibility);
@@ -38,8 +49,29 @@ namespace FishNet.Managing.Observing.Editing
EditorGUI.indentLevel--;
EditorGUILayout.LabelField("Level of Detail *", EditorStyles.boldLabel);
EditorGUI.indentLevel++;
if (Application.isPlaying)
GUI.enabled = false;
EditorGUILayout.PropertyField(_useLevelOfDetail);
if (_useLevelOfDetail.boolValue)
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(_maximumLevelOfDetailInterval, new GUIContent("Maximum Send Interval"));
EditorGUILayout.PropertyField(_levelOfDetailUpdateDuration, new GUIContent("Recalculation Duration"));
EditorGUILayout.PropertyField(_levelOfDetailDistances);
EditorGUI.indentLevel--;
}
GUI.enabled = true;
EditorGUI.indentLevel--;
serializedObject.ApplyModifiedProperties();
}
}
}
}
#endif
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Observing/Editor/ObserverManagerEditor.cs
uploadId: 866910
uploadId: 892096
@@ -0,0 +1,19 @@
namespace FishNet.Managing.Observing
{
/// <summary>
/// A configuration which affects the level of detail for a connection.
/// </summary>
public struct LevelOfDetail
{
/// <summary>
/// How often data will send when on this level of detail.
/// </summary>
public ushort SendInterval;
/// <summary>
/// Distance a connection's objects must be within to use this LevelOfDetail.
/// </summary>
public ushort Distance;
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 573375ac2883b974c9201b040a432f76
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Observing/LevelOfDetail.cs
uploadId: 892096
@@ -0,0 +1,78 @@
using System;
using System.Collections.Generic;
using FishNet.Connection;
using FishNet.Managing.Timing;
using FishNet.Object;
using FishNet.Utility;
using GameKit.Dependencies.Utilities;
using UnityEngine;
namespace FishNet.Managing.Observing
{
/// <summary>
/// Handles level of detail actions.
/// </summary>
public sealed partial class ObserverManager : MonoBehaviour
{
/// <summary>
/// Most recent LocalTick value on the TimeManager.
/// </summary>
internal uint LocalTick;
[Tooltip("True to enable level of detail.")]
[SerializeField]
private bool _useLevelOfDetail;
/// <summary>
/// The maximum delay between updates when an object is using the highest level of detail.
/// </summary>
[Tooltip("The maximum delay between updates when an object is using the highest level of detail.")]
[Range(MINIMUM_LEVEL_OF_DETAIL_SEND_INTERVAL, MAXIMUM_LEVEL_OF_DETAIL_SEND_INTERVAL)]
[SerializeField]
private float _maximumLevelOfDetailInterval = 2f;
/// <summary>
/// The time it will take to calculate new level of detail values.
/// </summary>
[Tooltip("The time it will take to calculate new level of detail values.")]
[Range(MINIMUM_LEVEL_OF_DETAIL_UPDATE_DURATION, MAXIMUM_LEVEL_OF_DETAIL_UPDATE_DURATION)]
[SerializeField]
private float _levelOfDetailUpdateDuration = 1f;
/// <summary>
/// Distances for each level of detail change. Each distance is an exponential increase. When the largest distance is surpassed the maximum delay is used; while within the first distance standard delays are used.
/// </summary>
[Tooltip("Distances for each level of detail change. Each distance is an exponential increase. When the largest distance is surpassed the maximum delay is used; while within the first distance standard delays are used.")]
[SerializeField]
private List<float> _levelOfDetailDistances = new();
#region Consts.
/// <summary>
/// Minimum time allowed for the maximum level of detail send interval.
/// </summary>
private const float MINIMUM_LEVEL_OF_DETAIL_SEND_INTERVAL = 0.1f;
/// <summary>
/// Maximum time allowed for the maximum level of detail send interval.
/// </summary>
private const float MAXIMUM_LEVEL_OF_DETAIL_SEND_INTERVAL = 15f;
/// <summary>
/// Minimum time which can be used for the level of detail update duration.
/// </summary>
private const float MINIMUM_LEVEL_OF_DETAIL_UPDATE_DURATION = 0.5f;
/// <summary>
/// Maximum time which can be used for the level of detail update duration.
/// </summary>
private const float MAXIMUM_LEVEL_OF_DETAIL_UPDATE_DURATION = 10f;
#endregion
/// <summary>
/// Initializes for level of detail use.
/// </summary>
/// <returns>New UseLevelOfDetail value.</returns>
private bool InitializeLevelOfDetailValues()
{
return false;
}
/// <summary>
/// Updates the duration of how long level of update values should be recalculated.
/// </summary>
public void SetLevelOfDetailRecalculationDuration(float duration) => _levelOfDetailUpdateDuration = Mathf.Clamp(duration, MINIMUM_LEVEL_OF_DETAIL_UPDATE_DURATION, MAXIMUM_LEVEL_OF_DETAIL_UPDATE_DURATION);
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 72fa5d7278196bd4f82ad85cd7d20038
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.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Observing/ObserverManager.LevelOfDetail.cs
uploadId: 892096
@@ -1,12 +1,11 @@
using FishNet.Component.Observing;
using FishNet.Connection;
using FishNet.Connection;
using FishNet.Object;
using FishNet.Observing;
using FishNet.Utility;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using FishNet.Managing.Timing;
using UnityEngine;
using UnityEngine.Serialization;
[assembly: InternalsVisibleTo(UtilityConstants.DEMOS_ASSEMBLY_NAME)]
[assembly: InternalsVisibleTo(UtilityConstants.TEST_ASSEMBLY_NAME)]
@@ -18,7 +17,7 @@ namespace FishNet.Managing.Observing
/// </summary>
[DisallowMultipleComponent]
[AddComponentMenu("FishNet/Manager/ObserverManager")]
public sealed class ObserverManager : MonoBehaviour
public sealed partial class ObserverManager : MonoBehaviour
{
#region Serialized.
/// <summary>
@@ -71,7 +70,7 @@ namespace FishNet.Managing.Observing
/// </summary>
private const float MINIMUM_TIMED_OBSERVERS_DURATION = 0.1f;
/// <summary>
/// Maxmimum time allowed for timed observers to rebuild.
/// Maximum time allowed for timed observers to rebuild.
/// </summary>
private const float MAXIMUM_TIMED_OBSERVERS_DURATION = 20f;
#endregion
@@ -85,6 +84,8 @@ namespace FishNet.Managing.Observing
_networkManager = manager;
// Update the current value to itself so it becomes clamped. This is just to protect against the user manually setting it outside clamp somehow.
SetMaximumTimedObserversDuration(MaximumTimedObserversDuration);
_useLevelOfDetail = InitializeLevelOfDetailValues();
}
/// <summary>
@@ -213,5 +214,6 @@ namespace FishNet.Managing.Observing
return result;
}
}
}
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Observing/ObserverManager.cs
uploadId: 866910
uploadId: 892096
@@ -18,7 +18,7 @@ namespace FishNet.Managing.Predicting.Editing
//Server.
private SerializedProperty _dropExcessiveReplicates;
private SerializedProperty _maximumServerReplicates;
//private SerializedProperty _maximumConsumeCount;
protected virtual void OnEnable()
{
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Prediction/Editor/PredictionManagerEditor.cs
uploadId: 866910
uploadId: 892096
@@ -199,8 +199,7 @@ namespace FishNet.Managing.Predicting
public event PostPhysicsSyncTransformDel OnPostPhysicsTransformSync;
public delegate void PostPhysicsSyncTransformDel(uint clientTick, uint serverTick);
public event PostPhysicsSyncTransformDel OnPostReconcileSyncTransforms;
/// <summary>
/// Called before physics is simulated when replaying a replicate method.
/// </summary>
@@ -682,12 +681,6 @@ namespace FishNet.Managing.Predicting
OnPostPhysicsTransformSync?.Invoke(ClientStateTick, ServerStateTick);
}
using (_pm_OnPostReconcileSyncTransforms.Auto())
OnPostReconcileSyncTransforms?.Invoke(ClientStateTick, ServerStateTick);
Physics.SyncTransforms();
Physics2D.SyncTransforms();
/* Set first replicate to be the 1 tick
* after reconcile. This is because reconcile calcs
* should be performed after replicate has run.
@@ -729,7 +722,7 @@ namespace FishNet.Managing.Predicting
using (_pm_OnPostReconcile.Auto())
OnPostReconcile?.Invoke(ClientStateTick, ServerStateTick);
ClientStateTick = TimeManager.UNSET_TICK;
ServerStateTick = TimeManager.UNSET_TICK;
ClientReplayTick = TimeManager.UNSET_TICK;
@@ -772,7 +765,7 @@ namespace FishNet.Managing.Predicting
lastReplicateTick = ncLocalTick;
}
foreach (PooledWriter writer in nc.PredictionStateWriters)
{
#if DEVELOPMENT && !UNITY_SERVER
@@ -798,9 +791,8 @@ namespace FishNet.Managing.Predicting
writer.WriteInt32Unpacked(dataLength);
// Channel is defaulted to unreliable.
Channel channel = Channel.Unreliable;
// If a single state exceeds MTU it must be sent on reliable. This is extremely unlikely.
_networkManager.TransportManager.CheckSetReliableChannel(segment.Count, ref channel);
tm.SendToClient((byte)channel, segment, nc, splitLargeMessages: true);
tm.SendToClient((byte)channel, segment, nc);
}
nc.StorePredictionStateWriters();
@@ -831,9 +823,6 @@ namespace FishNet.Managing.Predicting
reader.ReadTickUnpacked();
int payloadLength = reader.ReadInt32Unpacked();
reader.Skip(payloadLength);
// if (!_networkManager.IsServerStarted)
// Debug.Log($"Discarding state " + lastRemoteTick);
}
else
{
@@ -855,12 +844,10 @@ namespace FishNet.Managing.Predicting
* add onto the data. Otherwise, add a new state packet. */
if (_stateLookups.TryGetValue(clientTick, out StatePacket sp1))
{
//Debug.Log($"Updating state " + clientTick);
sp1.AddData(segment, channel);
}
else
{
//Debug.Log($"Adding state " + clientTick);
StatePacket sp2 = ResettableObjectCaches<StatePacket>.Retrieve();
sp2.Update(segment, clientTick, lastRemoteTick, channel);
_stateLookups[clientTick] = sp2;
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Prediction/PredictionManager.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Prediction/StateOrder.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/RemoteTimeoutType.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/Broadcast/SceneBroadcasts.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/DefaultSceneProcessor.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/Events/ClientPresenceChangeEventArgs.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/Events/LoadSceneEventArgs.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/Events/UnloadSceneEventArgs.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadOptions.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadParams.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/LoadQueueData.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/PreferredActiveScenes.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/ReplaceOption.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneLoadData.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneScopeTypes.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/SceneUnloadData.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadOptions.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadParams.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/LoadUnloadDatas/UnloadQueueData.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/SceneProcessorBase.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/SceneSpawner.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Scened/UnloadedScene.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/KickReasons.cs
uploadId: 866910
uploadId: 892096
@@ -93,7 +93,7 @@ namespace FishNet.Managing.Server
CollectionCaches<NetworkConnection>.Store(connCache);
CollectionCaches<NetworkObject>.Store(nobCache);
}
/// <summary>
/// Indicates that a networkObserver component should be updated regularly. This is done automatically.
/// </summary>
@@ -105,7 +105,7 @@ namespace FishNet.Managing.Server
else
_timedNetworkObservers.Add(networkObject);
}
/// <summary>
/// Indicates that a networkObserver component no longer needs to be updated regularly. This is done automatically.
/// </summary>
@@ -375,10 +375,10 @@ namespace FishNet.Managing.Server
NetworkManager.TransportManager.SendToClient((byte)Channel.Reliable, _writer.GetArraySegment(), nc);
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
if (NetworkTrafficStatistics != null)
NetworkTrafficStatistics.AddOutboundPacketIdData(PacketId.BulkSpawnOrDespawn, string.Empty, _writer.Length, gameObject: null, asServer: true);
#endif
#endif
_writer.Clear();
@@ -399,36 +399,36 @@ namespace FishNet.Managing.Server
return;
_writer.Clear();
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
PacketId trafficPacketId;
#endif
#endif
conn.UpdateHashGridPositions(!timedOnly);
// If observer state changed then write changes.
ObserverStateChange osc = nob.RebuildObservers(conn, timedOnly);
if (osc == ObserverStateChange.Added)
{
WriteSpawn(nob, _writer, conn);
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
trafficPacketId = PacketId.ObjectSpawn;
#endif
#endif
}
else if (osc == ObserverStateChange.Removed)
{
nob.InvokeOnServerDespawn(conn);
WriteDespawn(nob, nob.GetDefaultDespawnType(), _writer);
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
trafficPacketId = PacketId.ObjectDespawn;
#endif
#endif
}
else
{
return;
}
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
if (NetworkTrafficStatistics != null)
NetworkTrafficStatistics.AddOutboundPacketIdData(trafficPacketId, string.Empty, _writer.Length, gameObject: null, asServer: true);
#endif
#endif
NetworkManager.TransportManager.SendToClient((byte)Channel.Reliable, _writer.GetArraySegment(), conn);
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs
uploadId: 866910
uploadId: 892096
@@ -129,7 +129,7 @@ namespace FishNet.Managing.Server
}
PooledWriter writer = WriterPool.Retrieve();
BroadcastsSerializers.WriteBroadcast(NetworkManager, writer, message, ref channel);
BroadcastsSerializers.WriteBroadcast(writer, message);
ArraySegment<byte> segment = writer.GetArraySegment();
AddOutboundNetworkTraffic<T>(segment.Count);
@@ -156,7 +156,7 @@ namespace FishNet.Managing.Server
bool failedAuthentication = false;
PooledWriter writer = WriterPool.Retrieve();
BroadcastsSerializers.WriteBroadcast(NetworkManager, writer, message, ref channel);
BroadcastsSerializers.WriteBroadcast(writer, message);
ArraySegment<byte> segment = writer.GetArraySegment();
int sentBytes = 0;
@@ -349,7 +349,7 @@ namespace FishNet.Managing.Server
bool failedAuthentication = false;
PooledWriter writer = WriterPool.Retrieve();
BroadcastsSerializers.WriteBroadcast(NetworkManager, writer, message, ref channel);
BroadcastsSerializers.WriteBroadcast(writer, message);
ArraySegment<byte> segment = writer.GetArraySegment();
int sentBytes = 0;
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs
uploadId: 866910
uploadId: 892096
@@ -218,10 +218,6 @@ namespace FishNet.Managing.Server
/// </summary>
private float _nextTimeoutCheckTime;
/// <summary>
/// Used to read splits.
/// </summary>
private SplitReader _splitReader = new();
/// <summary>
/// </summary>
private NetworkTrafficStatistics _networkTrafficStatistics;
#if DEVELOPMENT
@@ -611,46 +607,44 @@ namespace FishNet.Managing.Server
{
//Sanity check to make sure transports are following proper types/ranges.
int id = args.ConnectionId;
if (id < 0 || id > NetworkConnection.MAXIMUM_CLIENTID_VALUE)
if (id < 0)
{
Kick(args.ConnectionId, KickReason.UnexpectedProblem, LoggingType.Error, $"The transport you are using supplied an invalid connection Id of {id}. Connection Id values must range between 0 and {NetworkConnection.MAXIMUM_CLIENTID_VALUE}. The client has been disconnected.");
return;
}
//Valid Id.
else
//If started then add to authenticated clients.
if (args.ConnectionState == RemoteConnectionState.Started)
{
//If started then add to authenticated clients.
if (args.ConnectionState == RemoteConnectionState.Started)
NetworkManager.Log($"Remote connection started for Id {id}.");
NetworkConnection conn = new(NetworkManager, id, args.TransportIndex, true);
Clients.Add(args.ConnectionId, conn);
_clientsList.Add(conn);
OnRemoteConnectionState?.Invoke(conn, args);
//Do nothing else until the client sends it's version.
}
//If stopping.
else if (args.ConnectionState == RemoteConnectionState.Stopped)
{
/* If client's connection is found then clean
* them up from server. */
if (Clients.TryGetValueIL2CPP(id, out NetworkConnection conn))
{
NetworkManager.Log($"Remote connection started for Id {id}.");
NetworkConnection conn = new(NetworkManager, id, args.TransportIndex, true);
Clients.Add(args.ConnectionId, conn);
_clientsList.Add(conn);
conn.SetDisconnecting(true);
OnRemoteConnectionState?.Invoke(conn, args);
Clients.Remove(id);
_clientsList.Remove(conn);
Objects.ClientDisconnected(conn);
BroadcastClientConnectionChange(false, conn);
//Return predictedObjectIds.
Queue<int> pqId = conn.PredictedObjectIds;
while (pqId.Count > 0)
Objects.CacheObjectId(pqId.Dequeue());
//Do nothing else until the client sends it's version.
}
//If stopping.
else if (args.ConnectionState == RemoteConnectionState.Stopped)
{
/* If client's connection is found then clean
* them up from server. */
if (Clients.TryGetValueIL2CPP(id, out NetworkConnection conn))
{
conn.SetDisconnecting(true);
OnRemoteConnectionState?.Invoke(conn, args);
Clients.Remove(id);
_clientsList.Remove(conn);
Objects.ClientDisconnected(conn);
BroadcastClientConnectionChange(false, conn);
//Return predictedObjectIds.
Queue<int> pqId = conn.PredictedObjectIds;
while (pqId.Count > 0)
Objects.CacheObjectId(pqId.Dequeue());
conn.ResetState();
NetworkManager.Log($"Remote connection stopped for Id {id}.");
}
conn.ResetState();
NetworkManager.Log($"Remote connection stopped for Id {id}.");
}
}
}
@@ -717,6 +711,14 @@ namespace FishNet.Managing.Server
//Not from a valid connection. Should not be possible.
if (args.ConnectionId < 0)
return;
/* Connection isn't available. This should never happen.
* Force an immediate disconnect. */
if (!Clients.TryGetValueIL2CPP(args.ConnectionId, out NetworkConnection connection))
{
Kick(args.ConnectionId, KickReason.UnexpectedProblem, LoggingType.Error, $"ConnectionId {args.ConnectionId} not found within Clients. Connection will be kicked immediately.");
return;
}
ArraySegment<byte> segment;
if (NetworkManager.TransportManager.HasIntermediateLayer)
@@ -735,7 +737,7 @@ namespace FishNet.Managing.Server
//If over MTU kick client immediately.
if (segment.Count > channelMtu)
{
ExceededMTUKick();
ExceededMTUKick(segment.Count, channelMtu);
return;
}
@@ -761,30 +763,35 @@ namespace FishNet.Managing.Server
#endif
//Skip packetId.
reader.ReadPacketId();
int expectedMessages;
_splitReader.GetHeader(reader, out expectedMessages);
//If here split message is to be read into splitReader.
_splitReader.Write(tick, reader, expectedMessages);
/* If fullMessage returns 0 count then the split
* has not written fully yet. Otherwise, if there is
* data within then reinitialize reader with the
* full message. */
ArraySegment<byte> fullMessage = _splitReader.GetFullMessage();
if (fullMessage.Count == 0)
int expectedMessages = reader.ReadInt32();
if (!connection.TryGetSplitReader(expectedMessages, out SplitReader splitReader))
{
//Intentionally a normal log rather than error to prevent spam from client attacks.
NetworkManager.Log($"Something went wrong when trying to get the [{nameof(splitReader)}] for connection [{connection.ToString()}].");
connection.Kick(KickReason.UnusualActivity);
return;
/* If here then all data has been received.
* It's possible the client could have exceeded
* maximum MTU but not the maximum number of splits.
* This is because the length of each split
* is not written, so we don't know how much data of the
* final message actually belonged to the split vs
* unrelated data added afterwards. We're going to cut
* the client some slack in this situation for the sake
* of keeping things simple. */
}
if (!splitReader.Write(reader))
{
//Intentionally a normal log rather than error to prevent spam from client attacks.
NetworkManager.Log($"Something went wrong when trying to write a split message for connection [{connection.ToString()}].");
connection.Kick(KickReason.UnusualActivity);
return;
}
//This will return true if the full message has been written.
if (!splitReader.TryGetFullMessage(out ArraySegment<byte> fullMessage))
return;
reader.Initialize(fullMessage, NetworkManager, dataSource);
//Once here the split reader can be returned.
connection.StoreSplitReader();
}
//Parse reader.
@@ -794,64 +801,55 @@ namespace FishNet.Managing.Server
#if DEVELOPMENT
NetworkManager.PacketIdHistory.ReceivedPacket(packetId, packetFromServer: false);
#endif
NetworkConnection conn;
/* Connection isn't available. This should never happen.
* Force an immediate disconnect. */
if (!Clients.TryGetValueIL2CPP(args.ConnectionId, out conn))
{
Kick(args.ConnectionId, KickReason.UnexpectedProblem, LoggingType.Error, $"ConnectionId {args.ConnectionId} not found within Clients. Connection will be kicked immediately.");
return;
}
conn.LocalTick.Update(timeManager, tick, EstimatedTick.OldTickOption.Discard);
conn.PacketTick.Update(timeManager, tick, EstimatedTick.OldTickOption.SetLastRemoteTick);
connection.LocalTick.Update(timeManager, tick, EstimatedTick.OldTickOption.Discard);
connection.PacketTick.Update(timeManager, tick, EstimatedTick.OldTickOption.SetLastRemoteTick);
/* If connection isn't authenticated and isn't a broadcast
* then disconnect client. If a broadcast then process
* normally; client may still become disconnected if the broadcast
* does not allow to be called while not authenticated. */
if (!conn.IsAuthenticated && packetId != PacketId.Version && packetId != PacketId.Broadcast)
if (!connection.IsAuthenticated && packetId != PacketId.Version && packetId != PacketId.Broadcast)
{
conn.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {conn.ClientId} sent packetId {packetId} without being authenticated. Connection will be kicked immediately.");
connection.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {connection.ClientId} sent packetId {packetId} without being authenticated. Connection will be kicked immediately.");
return;
}
if (packetId == PacketId.Replicate)
{
Objects.ParseReplicateRpc(reader, conn, args.Channel);
Objects.ParseReplicateRpc(reader, connection, args.Channel);
}
else if (packetId == PacketId.ServerRpc)
{
Objects.ParseServerRpc(reader, conn, args.Channel);
Objects.ParseServerRpc(reader, connection, args.Channel);
}
else if (packetId == PacketId.ObjectSpawn)
{
if (!GetAllowPredictedSpawning())
{
conn.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {conn.ClientId} sent a predicted spawn while predicted spawning is not enabled. Connection will be kicked immediately.");
connection.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {connection.ClientId} sent a predicted spawn while predicted spawning is not enabled. Connection will be kicked immediately.");
return;
}
Objects.ReadSpawn(reader, conn);
Objects.ReadSpawn(reader, connection);
}
else if (packetId == PacketId.ObjectDespawn)
{
if (!GetAllowPredictedSpawning())
{
conn.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {conn.ClientId} sent a predicted spawn while predicted spawning is not enabled. Connection will be kicked immediately.");
connection.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {connection.ClientId} sent a predicted spawn while predicted spawning is not enabled. Connection will be kicked immediately.");
return;
}
Objects.ReadDespawn(reader, conn);
Objects.ReadDespawn(reader, connection);
}
else if (packetId == PacketId.Broadcast)
{
ParseBroadcast(reader, conn, args.Channel);
ParseBroadcast(reader, connection, args.Channel);
}
else if (packetId == PacketId.PingPong)
{
ParsePingPong(reader, conn);
ParsePingPong(reader, connection);
}
else if (packetId == PacketId.Version)
{
ParseVersion(reader, conn, args.TransportIndex);
ParseVersion(reader, connection, args.TransportIndex);
}
else
{
@@ -880,9 +878,9 @@ namespace FishNet.Managing.Server
#endif
//Kicks connection for exceeding MTU.
void ExceededMTUKick()
void ExceededMTUKick(int sentCount, int maximumCount)
{
Kick(args.ConnectionId, KickReason.ExploitExcessiveData, LoggingType.Common, $"ConnectionId {args.ConnectionId} sent a message larger than allowed amount. Connection will be kicked immediately.");
Kick(args.ConnectionId, KickReason.ExploitExcessiveData, LoggingType.Common, $"ConnectionId {args.ConnectionId} sent a message of {sentCount} bytes while the maximum allowed amount is {maximumCount}. Connection will be kicked immediately.");
}
}
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ServerManager.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficArgs.cs
uploadId: 866910
uploadId: 892096
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using FishNet.Editing;
using FishNet.Editing.NetworkProfiler;
using FishNet.Transporting;
using GameKit.Dependencies.Utilities;
using Unity.Profiling;
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Statistic/NetworkTrafficStatistics.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Statistic/StatisticsManager.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Statistic/Types.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Timing/MovingAverage.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Timing/PhysicsMode.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Timing/PreciseTick.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Timing/TickRounding.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Timing/TickType.cs
uploadId: 866910
uploadId: 892096
@@ -8,6 +8,7 @@ using GameKit.Dependencies.Utilities;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using FishNet.Managing.Observing;
using FishNet.Managing.Predicting;
using FishNet.Managing.Statistic;
using FishNet.Object;
@@ -770,6 +771,9 @@ namespace FishNet.Managing.Timing
_elapsedTickTime -= timePerSimulation;
Tick++;
LocalTick++;
//Cache localTick to ObserverManager for performance.
NetworkManager.ObserverManager.LocalTick = LocalTick;
}
} while (_elapsedTickTime >= timePerSimulation);
}
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Transporting/IntermediateLayer.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Transporting/LatencySimulator.cs
uploadId: 866910
uploadId: 892096
@@ -1,17 +1,18 @@
using FishNet.Serializing;
using System;
using GameKit.Dependencies.Utilities;
using UnityEngine;
namespace FishNet.Managing.Transporting
{
internal class SplitReader
internal class SplitReader : IResettable
{
#region Private.
/// <summary>
/// Tick split is for.
/// Tick must be a negative value so that it's impossible for the first tick to align.
/// Writer containing the combined split packet.
/// </summary>
private long _tick = -1;
private readonly PooledWriter _writer = new();
/// <summary>
/// Expected number of splits.
/// </summary>
@@ -21,40 +22,52 @@ namespace FishNet.Managing.Transporting
/// </summary>
private ushort _receivedMessages;
/// <summary>
/// Writer containing split packet combined.
/// The maximum allowed bytes which can be read. This acts as a guard against overflow.
/// </summary>
private PooledWriter _writer = WriterPool.Retrieve();
private uint _maximumClientBytes;
/// <summary>
/// NetworkManager for this.
/// </summary>
private NetworkManager _networkManager;
/// <summary>
/// True if the sender of the split packet is a client.
/// </summary>
/// <returns></returns>
private bool _isSenderClient;
#endregion
internal SplitReader()
public void Initialize(NetworkManager networkManager, uint maximumClientBytes, bool isSenderClient, int expectedMessages)
{
// Increase capacity to reduce the chance of resizing.
_writer.EnsureBufferCapacity(20000);
}
/// <summary>
/// Gets split header values.
/// </summary>
internal void GetHeader(PooledReader reader, out int expectedMessages)
{
expectedMessages = reader.ReadInt32();
}
/// <summary>
/// Combines split data.
/// </summary>
internal void Write(uint tick, PooledReader reader, int expectedMessages)
{
// New tick which means new split.
if (tick != _tick)
Reset(tick, expectedMessages);
_networkManager = networkManager;
_maximumClientBytes = maximumClientBytes;
_isSenderClient = isSenderClient;
_expectedMessages = expectedMessages;
/* This is just a guess as to how large the end
* message could be. If the writer is not the minimum
* of this length then resize it. */
int estimatedBufferSize = expectedMessages * 1500;
if (_writer.Capacity < estimatedBufferSize)
_writer.EnsureBufferCapacity(estimatedBufferSize);
}
/// <summary>
/// Combines split data.
/// </summary>
internal bool Write(PooledReader reader)
{
if (_isSenderClient)
{
long totalBytes = _writer.Length + reader.Remaining;
if (totalBytes > _maximumClientBytes)
{
_networkManager.LogError($"A split packet of [{totalBytes}] exceeds the maximum allowed bytes of [{_maximumClientBytes}].");
return false;
}
}
/* Empty remainder of reader into the writer.
* It does not matter if parts of the reader
* contain data added after the split because
@@ -63,33 +76,40 @@ namespace FishNet.Managing.Transporting
* which is how data is normally read. */
ArraySegment<byte> data = reader.ReadArraySegment(reader.Remaining);
_writer.WriteArraySegment(data);
_receivedMessages++;
return true;
}
/// <summary>
/// Returns if all split messages have been received.
/// </summary>
/// <returns></returns>
internal ArraySegment<byte> GetFullMessage()
internal bool TryGetFullMessage(out ArraySegment<byte> segment)
{
if (_receivedMessages < _expectedMessages)
{
return default;
}
else
{
ArraySegment<byte> segment = _writer.GetArraySegment();
Reset();
return segment;
segment = ArraySegment<byte>.Empty;
return false;
}
segment = _writer.GetArraySegment();
return true;
}
private void Reset(uint tick = 0, int expectedMessages = 0)
public void ResetState()
{
_tick = tick;
_receivedMessages = 0;
_expectedMessages = expectedMessages;
_writer.Clear();
_expectedMessages = 0;
_receivedMessages = 0;
_maximumClientBytes = 0;
_networkManager = null;
}
public void InitializeState() { }
}
}
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Transporting/SplitReader.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Transporting/TransportManager.QOL.cs
uploadId: 866910
uploadId: 892096
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using FishNet.Managing.Statistic;
using GameKit.Dependencies.Utilities;
using UnityEngine;
using UnityEngine.Serialization;
namespace FishNet.Managing.Transporting
{
@@ -66,6 +67,13 @@ namespace FishNet.Managing.Transporting
#region Serialized.
/// <summary>
/// The maximum amount of bytes of any combined packet that a client may send.
/// </summary>
public uint MaximumClientPacketSize => _maximumClientPacketSize;
[Tooltip("The maximum amount of bytes of any combined packet that a client may send.")]
[SerializeField]
private uint _maximumClientPacketSize = 20480;
/// <summary>
/// Layer used to modify data before it is sent or received.
/// </summary>
[Tooltip("Layer used to modify data before it is sent or received.")]
@@ -123,6 +131,10 @@ namespace FishNet.Managing.Transporting
/// <summary>
/// </summary>
private NetworkTrafficStatistics _networkTrafficStatistics;
/// <summary>
/// Maximum size which each segment of a split message can be.
/// </summary>
private int _maximumSplitPacketSegmentLength => GetLowestMTU(SPLIT_PACKET_CHANNELID) - SPLIT_PACKET_HEADER_LENGTH - UNPACKED_TICK_LENGTH;
#endregion
#region Consts.
@@ -153,8 +165,7 @@ namespace FishNet.Managing.Transporting
/// <summary>
/// Number of bytes required for split data.
/// </summary>
/// // todo: This shouldn't have to include TickBytes but there is a parse error if it's not included. Figure out why.
public const byte SPLIT_INDICATOR_LENGTH = UNPACKED_TICK_LENGTH + PACKETID_LENGTH + SPLIT_COUNT_LENGTH;
public const byte SPLIT_PACKET_HEADER_LENGTH = PACKETID_LENGTH + SPLIT_COUNT_LENGTH;
/// <summary>
/// Number of channels supported.
/// </summary>
@@ -168,6 +179,22 @@ namespace FishNet.Managing.Transporting
/// Value to use when a MTU could not be found.
/// </summary>
public const int INVALID_MTU = -1;
/// <summary>
/// A split message was not required, the value can be sent normally.
/// </summary>
private const int SPLIT_NOT_REQUIRED_VALUE = 0;
/// <summary>
/// A message was sent split.
/// </summary>
private const int SPLIT_SENT_VALUE = 1;
/// <summary>
/// An error occurred while trying to split a message.
/// </summary>
private const int SPLIT_ERROR_VALUE = 2;
/// <summary>
/// ChannelId to use for split packets.
/// </summary>
private const byte SPLIT_PACKET_CHANNELID = (byte)Channel.Reliable;
#endregion
/// <summary>
@@ -188,9 +215,9 @@ namespace FishNet.Managing.Transporting
if (_intermediateLayer != null)
_intermediateLayer.InitializeOnce(this);
#if DEVELOPMENT
#if DEVELOPMENT
_latencySimulator.Initialize(manager, Transport);
#endif
#endif
}
/// <summary>
@@ -287,75 +314,6 @@ namespace FishNet.Managing.Transporting
CollectionCaches<NetworkConnection>.Store(clientsForIndex);
}
///// <summary>
///// Gets port for the first transport, or client transport if using Multipass.
///// </summary>
// private ushort GetPort(bool asServer)
// {
// if (Transport is Multipass mp)
// {
// if (asServer)
// return mp.Transports[0].GetPort();
// else
// return mp.ClientTransport.GetPort();
// }
// else
// {
// return Transport.GetPort();
// }
// }
///// <summary>
///// Stops the local server or client connection.
///// </summary>
// internal bool StopConnection(bool asServer)
// {
// return Transport.StopConnection(asServer);
// }
///// <summary>
///// Starts the local server or client connection.
///// </summary>
// internal bool StartConnection(bool asServer)
// {
// return Transport.StartConnection(asServer);
// }
///// <summary>
///// Starts the local server or client connection.
///// </summary>
// internal bool StartConnection(string address, bool asServer)
// {
// return StartConnection(address, GetPort(asServer), asServer);
// }
///// <summary>
///// Starts the local server or client connection on the first transport or ClientTransport if using Multipass and as client.
///// </summary>
// internal bool StartConnection(string address, ushort port, bool asServer)
// {
// Transport t;
// if (Transport is Multipass mp)
// {
// if (asServer)
// t = mp.Transports[0];
// else
// t = mp.ClientTransport;
// }
// else
// {
// t = Transport;
// }
// /* SetServerBindAddress must be called explictly. Only
// * set address if for client. */
// if (!asServer)
// t.SetClientAddress(address);
// t.SetPort(port);
// return t.StartConnection(asServer);
// }
/// <summary>
/// Sets a connection from server to client dirty.
/// </summary>
@@ -449,6 +407,7 @@ namespace FishNet.Managing.Transporting
public int GetLowestMTU(byte channel)
{
SetLowestMTUs();
return GetMTUWithReserve(_lowestMtus[channel]);
}
@@ -460,6 +419,7 @@ namespace FishNet.Managing.Transporting
public int GetMTU(byte channel)
{
SetLowestMTUs();
int mtu = Transport.GetMTU(channel);
if (mtu == INVALID_MTU)
return mtu;
@@ -484,18 +444,19 @@ namespace FishNet.Managing.Transporting
return GetMTUWithReserve(mtu);
}
// Using first/only transport.
else if (transportIndex == 0)
{
if (transportIndex == 0)
return GetMTU(channel);
}
// Unhandled.
else
{
_networkManager.LogWarning($"MTU cannot be returned with transportIndex because {typeof(Multipass).Name} is not in use.");
return -1;
}
_networkManager.LogWarning($"MTU cannot be returned with transportIndex because {typeof(Multipass).Name} is not in use.");
return -1;
}
/// <summary>
/// Returns Channel.Reliable if data length is over MTU for the provided channel.
/// </summary>
public Channel GetReliableChannelIfOverMTU(int dataLength, Channel currentChannel) => dataLength > GetMTU((byte)currentChannel) ? Channel.Reliable : currentChannel;
/// <summary>
/// Gets MTU on the transport type for channel. This requires use of Multipass.
/// </summary>
@@ -542,38 +503,23 @@ namespace FishNet.Managing.Transporting
/// <param name = "segment">Data to send.</param>
/// <param name = "connection">Connection to send to. Use null for all clients.</param>
/// <param name = "splitLargeMessages">True to split large packets which exceed MTU and send them in order on the reliable channel.</param>
internal void SendToClient(byte channelId, ArraySegment<byte> segment, NetworkConnection connection, bool splitLargeMessages = true, DataOrderType orderType = DataOrderType.Default)
internal void SendToClient(byte channelId, ArraySegment<byte> segment, NetworkConnection connection, DataOrderType orderType = DataOrderType.Default)
{
SetSplitValues(channelId, segment, splitLargeMessages, out int requiredMessages, out int maxSplitMessageSize);
SendToClient(channelId, segment, connection, requiredMessages, maxSplitMessageSize, orderType);
}
channelId = GetFallbackChannelIdAsNeeded(channelId);
private void SendToClient(byte channelId, ArraySegment<byte> segment, NetworkConnection connection, int requiredSplitMessages, int maxSplitMessageSize, DataOrderType orderType = DataOrderType.Default)
{
if (connection == null)
return;
if (requiredSplitMessages > 1)
SendSplitData(connection, ref segment, requiredSplitMessages, maxSplitMessageSize, orderType);
else
connection.SendToClient(channelId, segment, false, orderType);
if (SendSplitMessage(connection, channelId, segment, orderType) == SPLIT_NOT_REQUIRED_VALUE)
connection.SendToClient(channelId, segment, forceNewBuffer: false, orderType);
}
/// <summary>
/// Sends data to observers.
/// </summary>
internal void SendToClients(byte channelId, ArraySegment<byte> segment, HashSet<NetworkConnection> observers, HashSet<NetworkConnection> excludedConnections = null, bool splitLargeMessages = true, DataOrderType orderType = DataOrderType.Default)
{
SetSplitValues(channelId, segment, splitLargeMessages, out int requiredMessages, out int maxSplitMessageSize);
SendToClients(channelId, segment, observers, excludedConnections, requiredMessages, maxSplitMessageSize, orderType);
}
private void SendToClients(byte channelId, ArraySegment<byte> segment, HashSet<NetworkConnection> observers, HashSet<NetworkConnection> excludedConnections, int requiredSplitMessages, int maxSplitMessageSize, DataOrderType orderType = DataOrderType.Default)
internal void SendToClients(byte channelId, ArraySegment<byte> segment, HashSet<NetworkConnection> observers, HashSet<NetworkConnection> excludedConnections = null, DataOrderType orderType = DataOrderType.Default)
{
if (excludedConnections == null || excludedConnections.Count == 0)
{
foreach (NetworkConnection conn in observers)
SendToClient(channelId, segment, conn, requiredSplitMessages, maxSplitMessageSize, orderType);
SendToClient(channelId, segment, conn, orderType);
}
else
{
@@ -581,7 +527,8 @@ namespace FishNet.Managing.Transporting
{
if (excludedConnections.Contains(conn))
continue;
SendToClient(channelId, segment, conn, requiredSplitMessages, maxSplitMessageSize, orderType);
SendToClient(channelId, segment, conn, orderType);
}
}
}
@@ -592,20 +539,14 @@ namespace FishNet.Managing.Transporting
/// <param name = "channelId">Channel to send on.</param>
/// <param name = "segment">Data to send.</param>
/// <param name = "splitLargeMessages">True to split large packets which exceed MTU and send them in order on the reliable channel.</param>
internal void SendToClients(byte channelId, ArraySegment<byte> segment, bool splitLargeMessages = true)
{
SetSplitValues(channelId, segment, splitLargeMessages, out int requiredMessages, out int maxSplitMessageSize);
SendToClients_Internal(channelId, segment, requiredMessages, maxSplitMessageSize);
}
private void SendToClients_Internal(byte channelId, ArraySegment<byte> segment, int requiredSplitMessages, int maxSplitMessageSize)
internal void SendToClients(byte channelId, ArraySegment<byte> segment)
{
/* Rather than buffer the message once and send to every client
* it must be queued into every client. This ensures clients
* receive the message in order of other packets being
* delivered to them. */
foreach (NetworkConnection conn in _networkManager.ServerManager.Clients.Values)
SendToClient(channelId, segment, conn, requiredSplitMessages, maxSplitMessageSize);
SendToClient(channelId, segment, conn);
}
/// <summary>
@@ -614,131 +555,76 @@ namespace FishNet.Managing.Transporting
/// <param name = "channelId">Channel to send on.</param>
/// <param name = "segment">Data to send.</param>
/// <param name = "splitLargeMessages">True to split large packets which exceed MTU and send them in order on the reliable channel.</param>
internal void SendToServer(byte channelId, ArraySegment<byte> segment, bool splitLargeMessages = true, DataOrderType orderType = DataOrderType.Default)
internal void SendToServer(byte channelId, ArraySegment<byte> segment, DataOrderType orderType = DataOrderType.Default)
{
SetSplitValues(channelId, segment, splitLargeMessages, out int requiredMessages, out int maxSplitMessageSize);
SendToServer(channelId, segment, requiredMessages, maxSplitMessageSize, orderType);
}
channelId = GetFallbackChannelIdAsNeeded(channelId);
private void SendToServer(byte channelId, ArraySegment<byte> segment, int requiredMessages, int maxSplitMessageSize, DataOrderType orderType)
{
if (channelId >= _toServerBundles.Count)
channelId = (byte)Channel.Reliable;
if (requiredMessages > 1)
SendSplitData(null, ref segment, requiredMessages, maxSplitMessageSize, orderType);
else
_toServerBundles[channelId].Write(segment, false, orderType);
}
#region Splitting.
/// <summary>
/// Checks if a message can be split and outputs split information if so.
/// </summary>
private void SetSplitValues(byte channelId, ArraySegment<byte> segment, bool split, out int requiredMessages, out int maxSplitMessageSize)
{
if (!split)
{
requiredMessages = 0;
maxSplitMessageSize = 0;
}
else
{
SplitRequired(channelId, segment.Count, out requiredMessages, out maxSplitMessageSize);
}
if (SendSplitMessage(conn: null, channelId, segment, orderType) == SPLIT_NOT_REQUIRED_VALUE)
_toServerBundles[channelId].Write(segment, forceNewBuffer: false, orderType);
}
/// <summary>
/// Checks to set channel to reliable if dataLength is too long.
/// Gets the channelId to use, returning a fallback Id if the provided channelId is not supported.
/// </summary>
internal void CheckSetReliableChannel(int dataLength, ref Channel channel)
{
if (channel == Channel.Reliable)
return;
bool requiresMultipleMessages = GetRequiredMessageCount((byte)channel, dataLength, out _) > 1;
if (requiresMultipleMessages)
channel = Channel.Reliable;
}
/// <summary>
/// Gets the required number of messages needed for segmentSize and channel.
/// </summary>
private int GetRequiredMessageCount(byte channelId, int segmentSize, out int maxMessageSize)
{
maxMessageSize = GetLowestMTU(channelId) - SPLIT_INDICATOR_LENGTH;
return Mathf.CeilToInt((float)segmentSize / maxMessageSize);
}
/// <summary>
/// True if data must be split.
/// </summary>
/// <param name = "channelId"></param>
/// <param name = "segmentSize"></param>
private bool SplitRequired(byte channelId, int segmentSize, out int requiredMessages, out int maxMessageSize)
{
requiredMessages = GetRequiredMessageCount(channelId, segmentSize, out maxMessageSize);
bool splitRequired = requiredMessages > 1;
if (splitRequired && channelId != (byte)Channel.Reliable)
_networkManager.LogError($"A message of length {segmentSize} requires the reliable channel but was sent on channel {(Channel)channelId}. Please file this stack trace as a bug report.");
return splitRequired;
}
private byte GetFallbackChannelIdAsNeeded(byte channelId) => channelId > _toServerBundles.Count ? (byte)Channel.Reliable : channelId;
/// <summary>
/// Splits data going to which is too large to fit within the transport MTU.
/// </summary>
/// <param name = "conn">Connection to send to. If null data will be sent to the server.</param>
/// <returns>True if data was sent split.</returns>
private void SendSplitData(NetworkConnection conn, ref ArraySegment<byte> segment, int requiredMessages, int maxMessageSize, DataOrderType orderType)
private int SendSplitMessage(NetworkConnection conn, byte channelId, ArraySegment<byte> segment, DataOrderType orderType)
{
if (requiredMessages <= 1)
int lowestMTU = GetLowestMTU(channelId);
int segmentCount = segment.Count;
//Splitting is not required.
if (segmentCount <= lowestMTU)
//0 indicates no split required.
return SPLIT_NOT_REQUIRED_VALUE;
int maximumSegmentLength = _maximumSplitPacketSegmentLength;
int messageCount = (int)Math.Ceiling((double)segmentCount / maximumSegmentLength);
/* If going to the server and value exceeds the
* maximum segment size then the data cannot be sent. */
if (conn == null && messageCount * maximumSegmentLength > _maximumClientPacketSize)
{
_networkManager.LogError($"SendSplitData was called with {requiredMessages} required messages. This method should only be called if messages must be split into 2 pieces or more.");
return;
_networkManager.LogError($"A packet of length {segmentCount} cannot be sent because it exceeds the maximum packet size allowed by a client of {_maximumClientPacketSize}.");
return SPLIT_ERROR_VALUE;
}
byte channelId = (byte)Channel.Reliable;
PooledWriter headerWriter = WriterPool.Retrieve();
headerWriter.WritePacketIdUnpacked(PacketId.Split);
headerWriter.WriteInt32(requiredMessages);
ArraySegment<byte> headerSegment = headerWriter.GetArraySegment();
//Writer used to write the header and segment of each split message.
PooledWriter splitWriter = WriterPool.Retrieve();
int writeIndex = 0;
bool firstWrite = true;
// Send to connection until everything is written.
while (writeIndex < segment.Count)
//Channel is forced to reliable for split messages.
channelId = SPLIT_PACKET_CHANNELID;
for (int i = 0; i < messageCount; i++)
{
int headerReduction = 0;
if (firstWrite)
{
headerReduction = headerSegment.Count;
firstWrite = false;
}
int chunkSize = Mathf.Min(segment.Count - writeIndex - headerReduction, maxMessageSize);
// Make a new array segment for the chunk that is getting split.
ArraySegment<byte> splitSegment = new(segment.Array, segment.Offset + writeIndex, chunkSize);
splitWriter.WritePacketIdUnpacked(PacketId.Split);
splitWriter.WriteInt32(messageCount);
int startPosition = i * maximumSegmentLength;
int chunkSize = Mathf.Min(segment.Count - startPosition, maximumSegmentLength);
ArraySegment<byte> splitSegment = new(segment.Array, segment.Offset + startPosition, chunkSize);
splitWriter.WriteArraySegment(splitSegment);
// If connection is specified then it's going to a client.
if (conn != null)
{
conn.SendToClient(channelId, headerSegment, true);
conn.SendToClient(channelId, splitSegment);
}
conn.SendToClient(channelId, splitWriter.GetArraySegment());
// Otherwise it's going to the server.
else
{
_toServerBundles[channelId].Write(headerSegment, true, orderType);
_toServerBundles[channelId].Write(splitSegment, false, orderType);
}
_toServerBundles[channelId].Write(splitWriter.GetArraySegment(), forceNewBuffer: false, orderType);
writeIndex += chunkSize;
splitWriter.Clear();
}
headerWriter.Store();
WriterPool.Store(splitWriter);
return SPLIT_SENT_VALUE;
}
#endregion
/// <summary>
/// Processes data received by the socket.
@@ -763,9 +649,9 @@ namespace FishNet.Managing.Transporting
OnIterateOutgoingStart?.Invoke();
int channelCount = CHANNEL_COUNT;
ulong sentBytes = 0;
#if DEVELOPMENT
#if DEVELOPMENT
bool latencySimulatorEnabled = LatencySimulator.CanSimulate;
#endif
#endif
if (asServer)
SendAsServer();
else
@@ -806,11 +692,11 @@ namespace FishNet.Managing.Transporting
ArraySegment<byte> segment = new(bb.Data, 0, bb.Length);
if (HasIntermediateLayer)
segment = ProcessIntermediateOutgoing(segment, false);
#if DEVELOPMENT
#if DEVELOPMENT
if (latencySimulatorEnabled)
_latencySimulator.AddOutgoing(channel, segment, false, conn.ClientId);
else
#endif
#endif
Transport.SendToClient(channel, segment, conn.ClientId);
sentBytes += (ulong)segment.Count;
}
@@ -881,11 +767,11 @@ namespace FishNet.Managing.Transporting
ArraySegment<byte> segment = new(bb.Data, 0, bb.Length);
if (HasIntermediateLayer)
segment = ProcessIntermediateOutgoing(segment, true);
#if DEVELOPMENT
#if DEVELOPMENT
if (latencySimulatorEnabled)
_latencySimulator.AddOutgoing(channel, segment);
else
#endif
#endif
Transport.SendToServer(channel, segment);
sentBytes += (ulong)segment.Count;
}
@@ -900,17 +786,17 @@ namespace FishNet.Managing.Transporting
_networkTrafficStatistics.AddOutboundSocketData(sentBytes, asServer: false);
}
#if DEVELOPMENT
#if DEVELOPMENT
if (latencySimulatorEnabled)
_latencySimulator.IterateOutgoing(asServer);
#endif
#endif
Transport.IterateOutgoing(asServer);
OnIterateOutgoingEnd?.Invoke();
}
#region Editor.
#if UNITY_EDITOR
#if UNITY_EDITOR
private void OnValidate()
{
if (Transport == null)
@@ -923,7 +809,7 @@ namespace FishNet.Managing.Transporting
* will happen. */
_latencySimulator.SetEnabled(_latencySimulator.GetEnabled());
}
#endif
#endif
#endregion
}
}

Some files were not shown because too many files have changed in this diff Show More