diff --git a/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Prefabs/NetworkTransform Benchmark.prefab b/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Prefabs/NetworkTransform Benchmark.prefab index 27114730..6ea9f279 100644 --- a/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Prefabs/NetworkTransform Benchmark.prefab +++ b/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Prefabs/NetworkTransform Benchmark.prefab @@ -51,11 +51,13 @@ MonoBehaviour: k__BackingField: 0 k__BackingField: {fileID: 0} k__BackingField: {fileID: 0} - _networkBehaviours: - - {fileID: 0} + NetworkBehaviours: + - {fileID: 6667641716399555817} - {fileID: -5271135124957689192} - k__BackingField: {fileID: 0} - k__BackingField: [] + InitializedParentNetworkBehaviour: {fileID: 0} + InitializedNestedNetworkObjects: [] + RuntimeParentNetworkBehaviour: {fileID: 0} + RuntimeChildNetworkBehaviours: [] _isNetworked: 1 _isSpawnable: 1 _isGlobal: 0 @@ -75,7 +77,7 @@ MonoBehaviour: _spectatorInterpolation: 2 _enableTeleport: 0 _teleportThreshold: 1 - k__BackingField: 26 + k__BackingField: 33 k__BackingField: 0 k__BackingField: 14364260540862342890 k__BackingField: 0 @@ -95,13 +97,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 9880e85651efd71469092ce519317f7b, type: 3} m_Name: m_EditorClassIdentifier: - _componentIndexCache: 255 + _componentIndexCache: 0 _addedNetworkObject: {fileID: 4512293259955182956} - _networkObjectCache: {fileID: 0} - _tickCallbacks: 6 + _networkObjectCache: {fileID: 4512293259955182956} + _tickCallbacks: 14 _isActive: 1 _axes: 3 _rotationChance: 0.33 + _moveInUpdate: 0 _moveRate: 3 _rotateRate: 30 --- !u!114 &-5271135124957689192 @@ -125,7 +128,7 @@ MonoBehaviour: Position: 1 Rotation: 1 Scale: 0 - _interpolation: 2 + _interpolation: 3 _extrapolation: 2 _enableTeleport: 0 _teleportThreshold: 1 diff --git a/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Scenes/NetworkTransform Benchmark.unity b/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Scenes/NetworkTransform Benchmark.unity index 821338bc..a8a32c8d 100644 --- a/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Scenes/NetworkTransform Benchmark.unity +++ b/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Scenes/NetworkTransform Benchmark.unity @@ -38,7 +38,6 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -139,7 +138,7 @@ MonoBehaviour: _timingType: 0 _allowTickDropping: 0 _maximumFrameTicks: 2 - _tickRate: 30 + _tickRate: 60 _pingInterval: 15 _physicsMode: 1 --- !u!1 &442045874 @@ -191,10 +190,11 @@ MonoBehaviour: k__BackingField: 0 k__BackingField: {fileID: 0} k__BackingField: {fileID: 0} - _networkBehaviours: - - {fileID: 0} - k__BackingField: {fileID: 0} - k__BackingField: [] + NetworkBehaviours: [] + InitializedParentNetworkBehaviour: {fileID: 0} + InitializedNestedNetworkObjects: [] + RuntimeParentNetworkBehaviour: {fileID: 0} + RuntimeChildNetworkBehaviours: [] _isNetworked: 1 _isSpawnable: 1 _isGlobal: 0 @@ -217,7 +217,7 @@ MonoBehaviour: k__BackingField: 0 k__BackingField: 0 k__BackingField: 0 - k__BackingField: 10134845970961547977 + k__BackingField: 3684663076 SerializedTransformProperties: Position: {x: 0, y: 0, z: 0} Rotation: {x: 0, y: 0, z: 0, w: 1} @@ -582,7 +582,7 @@ MonoBehaviour: _objectPool: {fileID: 0} _persistence: 0 _logging: {fileID: 0} - _spawnablePrefabs: {fileID: 11400000, guid: 68e79e63a16f2c74e81f070bd36822b8, type: 2} + _spawnablePrefabs: {fileID: 11400000, guid: ef18464092139404db8e515b0bf59331, type: 2} --- !u!1 &7443408886575219563 GameObject: m_ObjectHideFlags: 0 @@ -596,6 +596,7 @@ GameObject: - component: {fileID: 370472796} - component: {fileID: 7443408886575219565} - component: {fileID: 7443408886575219564} + - component: {fileID: 7443408886575219566} m_Layer: 0 m_Name: NetworkManager m_TagString: Untagged @@ -635,3 +636,29 @@ MonoBehaviour: _placement: 2 _showOutgoing: 1 _showIncoming: 1 +--- !u!114 &7443408886575219566 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408886575219563} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 68828c85278210948b9d50a8db3aab74, type: 3} + m_Name: + m_EditorClassIdentifier: + _authenticator: {fileID: 0} + _remoteClientTimeout: 2 + _remoteClientTimeoutDuration: 60 + _allowPredictedSpawning: 0 + _reservedObjectIds: 15 + _syncTypeRate: 0.1 + SpawnPacking: + Position: 0 + Rotation: 2 + Scale: 2 + _changeFrameRate: 1 + _frameRate: 70 + _shareIds: 1 + _startOnHeadless: 1 diff --git a/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Scripts/MoveRandomly.cs b/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Scripts/MoveRandomly.cs index 9f069c99..ab6e9891 100644 --- a/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Scripts/MoveRandomly.cs +++ b/Assets/FishNet/Demos/Benchmarks/NetworkTransform/Scripts/MoveRandomly.cs @@ -1,5 +1,7 @@ -using FishNet.Utility.Template; +using System; +using FishNet.Utility.Template; using UnityEngine; +using Random = UnityEngine.Random; namespace FishNet.Demo.Benchmarks.NetworkTransforms { @@ -18,6 +20,8 @@ public class MoveRandomly : TickNetworkBehaviour [Header("Movement")] [SerializeField] + private bool _moveInUpdate = false; + [SerializeField] [Range(0.1f, 30f)] private float _moveRate = 3f; [Range(1f, 1000f)] @@ -31,19 +35,32 @@ public class MoveRandomly : TickNetworkBehaviour private Vector3 _goalPosition; //Rotation to move towards. private Quaternion _goalRotation; - //Position at spawn. - private Vector3 _startPosition; private Quaternion _lastRot; protected override void TimeManager_OnTick() { + if (_moveInUpdate) + return; + + float delta = (float)base.TimeManager.TickDelta; + Move(delta); + } + + private void Update() + { + if (!_moveInUpdate) + return; + + Move(Time.deltaTime); + } + + private void Move(float delta) + { if (!_isActive) return; if (!base.IsServerInitialized) return; - - float delta = (float)base.TimeManager.TickDelta; transform.position = Vector3.MoveTowards(transform.position, _goalPosition, _moveRate * delta); transform.rotation = Quaternion.RotateTowards(transform.rotation, _goalRotation, _rotateRate * delta); @@ -51,11 +68,9 @@ protected override void TimeManager_OnTick() if (transform.position == _goalPosition) RandomizeGoal(); } - + public override void OnStartServer() { - _startPosition = transform.position; - RandomizeGoal(); } diff --git a/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs b/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs index d68bb1a4..66ae9e7d 100644 --- a/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs +++ b/Assets/FishNet/Runtime/Editor/Configuring/ConfigurationEditor.cs @@ -158,7 +158,7 @@ public static void RebuildSceneIds() } checkedScenes++; - NetworkObject.CreateSceneId(s, out int changed, out int found); + NetworkObject.CreateSceneId(s, force: true, out int changed, out int found); checkedObjects += found; changedObjects += changed; } diff --git a/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs b/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs index 5eeed76a..3276b255 100644 --- a/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs +++ b/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs @@ -310,7 +310,7 @@ void IterateAssetCollection(string[] c) /// /// Generates prefabs by iterating all files within settings parameters. /// - public static void GenerateFull(PrefabGeneratorConfigurations settings = null, bool forced = false) + public static void GenerateFull(PrefabGeneratorConfigurations settings = null, bool forced = false, bool initializeAdded = true) { #if PARRELSYNC if (ParrelSync.ClonesManager.IsClone() && ParrelSync.Preferences.AssetModPref.Value) @@ -373,7 +373,7 @@ public static void GenerateFull(PrefabGeneratorConfigurations settings = null, b //Clear and add built list. prefabCollection.Clear(); - prefabCollection.AddObjects(foundNobs, false); + prefabCollection.AddObjects(foundNobs, checkForDuplicates: false, initializeAdded); bool dirtied = prefabCollection.SetAssetPathHashes(0); int newCount = prefabCollection.GetObjectCount(); diff --git a/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs b/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs index 723350b7..9c8df246 100644 --- a/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs +++ b/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs @@ -724,7 +724,7 @@ public override void OnOwnershipClient(NetworkConnection prevOwner) TryClearGoalDatas_OwnershipChange(prevOwner, false); } - + public override void OnStopNetwork() { ResetState(); @@ -946,7 +946,6 @@ private void ChangeUpdateSubscription(bool subscribe) else _timeManager.OnUpdate -= TimeManager_OnUpdate; } - /// /// Returns if controlling logic can be run. This may be the server when there is no owner, even if client authoritative, and more. @@ -2442,7 +2441,8 @@ private void ResetState() while (_goalDataQueue.Count > 0) ResettableObjectCaches.Store(_goalDataQueue.Dequeue()); - _lastSentTransformData.ResetState(); + if (_lastSentTransformData != null) + _lastSentTransformData.ResetState(); ResettableObjectCaches.StoreAndDefault(ref _currentGoalData); } diff --git a/Assets/FishNet/Runtime/Generated/Component/TakeOwnership/PredictedOwner.cs b/Assets/FishNet/Runtime/Generated/Component/TakeOwnership/PredictedOwner.cs index c3a013ec..bcd9d8a4 100644 --- a/Assets/FishNet/Runtime/Generated/Component/TakeOwnership/PredictedOwner.cs +++ b/Assets/FishNet/Runtime/Generated/Component/TakeOwnership/PredictedOwner.cs @@ -148,7 +148,7 @@ protected virtual void OnTakeOwnership(NetworkConnection caller, bool includeNes base.GiveOwnership(caller); if (includeNested) { - List allNested = base.NetworkObject.RetrieveNestedNetworkObjects(); + List allNested = base.NetworkObject.RetrieveNestedNetworkObjects(recursive: true); foreach (NetworkObject nob in allNested) { diff --git a/Assets/FishNet/Runtime/Managing/NetworkManager.cs b/Assets/FishNet/Runtime/Managing/NetworkManager.cs index 5a08c1af..c044ecb0 100644 --- a/Assets/FishNet/Runtime/Managing/NetworkManager.cs +++ b/Assets/FishNet/Runtime/Managing/NetworkManager.cs @@ -212,7 +212,7 @@ public static IReadOnlyList Instances /// /// Version of this release. /// - public const string FISHNET_VERSION = "4.5.1"; + public const string FISHNET_VERSION = "4.5.2"; /// /// Maximum framerate allowed. /// @@ -240,7 +240,7 @@ private void Awake() { Generator.IgnorePostProcess = true; Debug.Log("DefaultPrefabCollection is being refreshed."); - Generator.GenerateFull(); + Generator.GenerateFull(initializeAdded: false); Generator.IgnorePostProcess = false; } #endif @@ -250,7 +250,7 @@ private void Awake() DefaultPrefabObjects originalDpo = (DefaultPrefabObjects)SpawnablePrefabs; //If not editor then a new instance must be made and sorted. DefaultPrefabObjects instancedDpo = ScriptableObject.CreateInstance(); - instancedDpo.AddObjects(originalDpo.Prefabs.ToList(), false); + instancedDpo.AddObjects(originalDpo.Prefabs.ToList(), checkForDuplicates: false, initializeAdded: false); instancedDpo.Sort(); SpawnablePrefabs = instancedDpo; } diff --git a/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs b/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs index 1d5c6404..eddd34dd 100644 --- a/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs +++ b/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.cs @@ -182,8 +182,12 @@ internal virtual void Despawn(NetworkObject nob, DespawnType despawnType, bool a //If as server. if (asServer) { + /* If not clientHost the object can be disabled. + * + * Also, if clientHost and clientHost is not an observer, the object + * can be disabled. */ //If not clientHost then the object can be disabled. - if (!NetworkManager.IsClientStarted) + if (!NetworkManager.IsClientStarted || !nob.Observers.Contains(NetworkManager.ClientManager.Connection)) nob.gameObject.SetActive(false); } //Not as server. diff --git a/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs b/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs index 3ef0496e..a6e7858c 100644 --- a/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs +++ b/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DefaultPrefabObjects.cs @@ -96,7 +96,7 @@ internal void Sort() sortedNobs.Add(hashcodesAndNobs[hc]); base.Clear(); - base.AddObjects(sortedNobs, false); + base.AddObjects(sortedNobs, checkForDuplicates: false, initializeAdded: false); } diff --git a/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs b/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs index 1e5a39ff..75ff74d7 100644 --- a/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs +++ b/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/DualPrefabObjects.cs @@ -63,22 +63,19 @@ public override void RemoveNull() i--; } } - - if (Application.isPlaying) - InitializePrefabRange(0); } - public override void AddObject(DualPrefab dualPrefab, bool checkForDuplicates = false) + public override void AddObject(DualPrefab dualPrefab, bool checkForDuplicates = false, bool initializeAdded = true) { - AddObjects(new DualPrefab[] { dualPrefab }, checkForDuplicates); + AddObjects(new DualPrefab[] { dualPrefab }, checkForDuplicates, initializeAdded); } - public override void AddObjects(List dualPrefabs, bool checkForDuplicates = false) + public override void AddObjects(List dualPrefabs, bool checkForDuplicates = false, bool initializeAdded = true) { - AddObjects(dualPrefabs.ToArray(), checkForDuplicates); + AddObjects(dualPrefabs.ToArray(), checkForDuplicates, initializeAdded); } - public override void AddObjects(DualPrefab[] dualPrefabs, bool checkForDuplicates = false) + public override void AddObjects(DualPrefab[] dualPrefabs, bool checkForDuplicates = false, bool initializeAdded = true) { if (!checkForDuplicates) { @@ -90,7 +87,7 @@ public override void AddObjects(DualPrefab[] dualPrefabs, bool checkForDuplicate AddUniqueNetworkObjects(dp); } - if (Application.isPlaying) + if (initializeAdded && Application.isPlaying) InitializePrefabRange(0); } @@ -117,17 +114,17 @@ public override void InitializePrefabRange(int startIndex) #region Unused. - public override void AddObject(NetworkObject networkObject, bool checkForDuplicates = false) + public override void AddObject(NetworkObject networkObject, bool checkForDuplicates = false, bool initializeAdded = true) { NetworkManagerExtensions.LogError($"Single prefabs are not supported with DualPrefabObjects. Make a SinglePrefabObjects asset instead."); } - public override void AddObjects(List networkObjects, bool checkForDuplicates = false) + public override void AddObjects(List networkObjects, bool checkForDuplicates = false, bool initializeAdded = true) { NetworkManagerExtensions.LogError($"Single prefabs are not supported with DualPrefabObjects. Make a SinglePrefabObjects asset instead."); } - public override void AddObjects(NetworkObject[] networkObjects, bool checkForDuplicates = false) + public override void AddObjects(NetworkObject[] networkObjects, bool checkForDuplicates = false, bool initializeAdded = true) { NetworkManagerExtensions.LogError($"Single prefabs are not supported with DualPrefabObjects. Make a SinglePrefabObjects asset instead."); } diff --git a/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs b/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs index 5bdc84a4..b052b2e1 100644 --- a/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs +++ b/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/PrefabObjects.cs @@ -22,12 +22,12 @@ public abstract class PrefabObjects : ScriptableObject public abstract int GetObjectCount(); public abstract NetworkObject GetObject(bool asServer, int id); public abstract void RemoveNull(); - public abstract void AddObject(NetworkObject networkObject, bool checkForDuplicates = false); - public abstract void AddObjects(List networkObjects, bool checkForDuplicates = false); - public abstract void AddObjects(NetworkObject[] networkObjects, bool checkForDuplicates = false); - public abstract void AddObject(DualPrefab dualPrefab, bool checkForDuplicates = false); - public abstract void AddObjects(List dualPrefab, bool checkForDuplicates = false); - public abstract void AddObjects(DualPrefab[] dualPrefab, bool checkForDuplicates = false); + public abstract void AddObject(NetworkObject networkObject, bool checkForDuplicates = false, bool initializeAdded = true); + public abstract void AddObjects(List networkObjects, bool checkForDuplicates = false, bool initializeAdded = true); + public abstract void AddObjects(NetworkObject[] networkObjects, bool checkForDuplicates = false, bool initializeAdded = true); + public abstract void AddObject(DualPrefab dualPrefab, bool checkForDuplicates = false, bool initializeAdded = true); + public abstract void AddObjects(List dualPrefab, bool checkForDuplicates = false, bool initializeAdded = true); + public abstract void AddObjects(DualPrefab[] dualPrefab, bool checkForDuplicates = false, bool initializeAdded = true); public abstract void InitializePrefabRange(int startIndex); diff --git a/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs b/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs index 9741db34..53173375 100644 --- a/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs +++ b/Assets/FishNet/Runtime/Managing/Object/PrefabObjects/SinglePrefabObjects.cs @@ -58,23 +58,20 @@ public override void RemoveNull() i--; } } - - if (Application.isPlaying) - InitializePrefabRange(0); } - public override void AddObject(NetworkObject networkObject, bool checkForDuplicates = false) + public override void AddObject(NetworkObject networkObject, bool checkForDuplicates = false, bool initializeAdded = true) { if (!checkForDuplicates) _prefabs.Add(networkObject); else AddUniqueNetworkObject(networkObject); - if (Application.isPlaying) + if (initializeAdded && Application.isPlaying) InitializePrefabRange(0); } - public override void AddObjects(List networkObjects, bool checkForDuplicates = false) + public override void AddObjects(List networkObjects, bool checkForDuplicates = false, bool initializeAdded = true) { if (!checkForDuplicates) { @@ -86,12 +83,12 @@ public override void AddObjects(List networkObjects, bool checkFo AddUniqueNetworkObject(nob); } - if (Application.isPlaying) + if (initializeAdded && Application.isPlaying) InitializePrefabRange(0); } - public override void AddObjects(NetworkObject[] networkObjects, bool checkForDuplicates = false) + public override void AddObjects(NetworkObject[] networkObjects, bool checkForDuplicates = false, bool initializeAdded = true) { - AddObjects(networkObjects.ToList(), checkForDuplicates); + AddObjects(networkObjects.ToList(), checkForDuplicates, initializeAdded); } private void AddUniqueNetworkObject(NetworkObject nob) @@ -109,17 +106,17 @@ public override void InitializePrefabRange(int startIndex) #region Unused. - public override void AddObject(DualPrefab dualPrefab, bool checkForDuplicates = false) + public override void AddObject(DualPrefab dualPrefab, bool checkForDuplicates = false, bool initializeAdded = true) { NetworkManagerExtensions.LogError($"Dual prefabs are not supported with SinglePrefabObjects. Make a DualPrefabObjects asset instead."); } - public override void AddObjects(List dualPrefab, bool checkForDuplicates = false) + public override void AddObjects(List dualPrefab, bool checkForDuplicates = false, bool initializeAdded = true) { NetworkManagerExtensions.LogError($"Dual prefabs are not supported with SinglePrefabObjects. Make a DualPrefabObjects asset instead."); } - public override void AddObjects(DualPrefab[] dualPrefab, bool checkForDuplicates = false) + public override void AddObjects(DualPrefab[] dualPrefab, bool checkForDuplicates = false, bool initializeAdded = true) { NetworkManagerExtensions.LogError($"Dual prefabs are not supported with SinglePrefabObjects. Make a DualPrefabObjects asset instead."); } diff --git a/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs b/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs index c5c13002..5e3e5d94 100644 --- a/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs +++ b/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs @@ -203,9 +203,12 @@ internal List SortRootAndNestedByInitializeOrder(List sortedNestedCache = CollectionCaches.RetrieveList(); foreach (NetworkObject item in sortedRootCache) { - foreach (NetworkObject nestedItem in item.InitializedNestedNetworkObjects) + List nested = item.RetrieveNestedNetworkObjects(recursive: true); + foreach (NetworkObject nestedItem in nested) sortedNestedCache.AddOrdered(nestedItem); + CollectionCaches.Store(nested); + /* Once all nested are sorted then can be added to the * sorted root and nested cache. */ sortedRootAndNestedCache.Add(item); diff --git a/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs b/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs index 6128650f..c1043dae 100644 --- a/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs +++ b/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs @@ -994,6 +994,10 @@ private void FinalizeDespawn(NetworkObject nob, DespawnType despawnType) /// private void WriteDespawnAndSend(NetworkObject nob, DespawnType despawnType) { + HashSet observers = nob.Observers; + if (observers.Count == 0) + return; + PooledWriter everyoneWriter = WriterPool.Retrieve(); WriteDespawn(nob, despawnType, everyoneWriter); @@ -1001,8 +1005,12 @@ private void WriteDespawnAndSend(NetworkObject nob, DespawnType despawnType) //Add observers to a list cache. List cache = CollectionCaches.RetrieveList(); - cache.AddRange(nob.Observers); + /* Must be added into a new collection because the + * user might try and modify the observers in the despawn, which + * would cause a collection modified error. */ + cache.AddRange(observers); int cacheCount = cache.Count; + for (int i = 0; i < cacheCount; i++) { //Invoke ondespawn and send despawn. diff --git a/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs b/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs index 72de8bfc..28e0606f 100644 --- a/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs +++ b/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs @@ -542,16 +542,7 @@ protected internal void Replicate_Replay_Authoritative(uint replayTick, Repli /// protected internal void Replicate_Replay_NonAuthoritative(uint replayTick, ReplicateUserLogicDelegate del, RingBuffer replicatesHistory, Channel channel) where T : IReplicateData { - //NOTESSTART - /* When inserting states only replay the first state after the reconcile. - * This prevents an inconsistency on running created states if other created states - * were to arrive late. Essentially the first state is considered 'current' and the rest - * are acting as a buffer against unsteady networking conditions. */ - - /* When appending states all created can be run. Appended states are only inserted after they've - * run at the end of the tick, which performs of it's own queue. Because of this, it's safe to assume - * if the state has been inserted into the past it has already passed it's buffer checks. */ - //NOTESEND + T data; ReplicateState state; bool isAppendedOrder = _networkObjectCache.PredictionManager.IsAppendedStateOrder; @@ -2025,16 +2016,7 @@ protected internal void Replicate_Replay_Authoritative(uint replayTick, Repli /// protected internal void Replicate_Replay_NonAuthoritative(uint replayTick, ReplicateUserLogicDelegate del, RingBuffer replicatesHistory, Channel channel) where T : IReplicateData { - //NOTESSTART - /* When inserting states only replay the first state after the reconcile. - * This prevents an inconsistency on running created states if other created states - * were to arrive late. Essentially the first state is considered 'current' and the rest - * are acting as a buffer against unsteady networking conditions. */ - - /* When appending states all created can be run. Appended states are only inserted after they've - * run at the end of the tick, which performs of it's own queue. Because of this, it's safe to assume - * if the state has been inserted into the past it has already passed it's buffer checks. */ - //NOTESEND + T data; ReplicateState state; bool isAppendedOrder = _networkObjectCache.PredictionManager.IsAppendedStateOrder; diff --git a/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs b/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs index 11ee463a..1142f830 100644 --- a/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs +++ b/Assets/FishNet/Runtime/Object/NetworkObject.QOL.cs @@ -309,10 +309,10 @@ public void SetLocalOwnership(NetworkConnection caller, bool includeNested) if (includeNested) { - List allNested = RetrieveNestedNetworkObjects(); + List allNested = RetrieveNestedNetworkObjects(recursive: true); foreach (NetworkObject nob in allNested) - nob.SetLocalOwnership(caller, includeNested); + nob.SetLocalOwnership(caller, includeNested: true); CollectionCaches.Store(allNested); } diff --git a/Assets/FishNet/Runtime/Object/NetworkObject.Serialized.cs b/Assets/FishNet/Runtime/Object/NetworkObject.Serialized.cs index 8aa2cc22..adb8aaad 100644 --- a/Assets/FishNet/Runtime/Object/NetworkObject.Serialized.cs +++ b/Assets/FishNet/Runtime/Object/NetworkObject.Serialized.cs @@ -96,7 +96,7 @@ private void OnApplicationQuit() /// /// Tries to generate a SceneIds for NetworkObjects in a scene. /// - internal static void CreateSceneId(UnityEngine.SceneManagement.Scene scene, out int changed, out int found) + internal static void CreateSceneId(UnityEngine.SceneManagement.Scene scene, bool force, out int changed, out int found) { changed = 0; found = 0; @@ -120,10 +120,11 @@ internal static void CreateSceneId(UnityEngine.SceneManagement.Scene scene, out foreach (NetworkObject item in sceneNobs) { + bool canGenerate = (!item.IsSceneObject || !setIds.Add(item.SceneId)); /* If an Id has not been generated yet or if it * already exist then rebuild for this object. */ - if (!item.IsSceneObject || !setIds.Add(item.SceneId)) - { + if (force || canGenerate) + { item.SceneId = NetworkObject.UNSET_SCENEID_VALUE; rebuildingNobs.Add(item); } @@ -140,7 +141,7 @@ internal static void CreateSceneId(UnityEngine.SceneManagement.Scene scene, out ulong CombineHashes(uint a, uint b) { - return (b << 32 | a); + return (b | a); } setIds.Add(nextSceneId); @@ -153,7 +154,7 @@ ulong CombineHashes(uint a, uint b) /// /// Tries to generate a SceneId. /// - private void CreateSceneId() + private void CreateSceneId(bool force) { if (Application.isPlaying) return; @@ -197,7 +198,7 @@ private void CreateSceneId() _lastSceneIdAutomaticRebuildTime = realtime; - CreateSceneId(gameObject.scene, out _, out _); + CreateSceneId(gameObject.scene, force, out _, out _); } } @@ -228,12 +229,12 @@ private bool IsEditingInPrefabMode() private void ReferenceIds_OnValidate() { - CreateSceneId(); + CreateSceneId(force: false); } private void ReferenceIds_Reset() { - CreateSceneId(); + CreateSceneId(force: false); } #endif } diff --git a/Assets/FishNet/Runtime/Object/NetworkObject.cs b/Assets/FishNet/Runtime/Object/NetworkObject.cs index 39fc29ef..4f833de1 100644 --- a/Assets/FishNet/Runtime/Object/NetworkObject.cs +++ b/Assets/FishNet/Runtime/Object/NetworkObject.cs @@ -101,32 +101,43 @@ public partial class NetworkObject : MonoBehaviour, IOrderable /// [HideInInspector] public List NetworkBehaviours; - /// /// NetworkBehaviour on the root of a NetworkObject parenting this instance. Value will be null if there was no parent during serialization. /// /// This API is for internal use and may change at any time. - [field: SerializeField, HideInInspector] - public NetworkBehaviour InitializedParentNetworkBehaviour { get; private set; } + [HideInInspector] + public NetworkBehaviour InitializedParentNetworkBehaviour; /// /// Nested NetworkObjects that existed during initialization. /// /// This API is for internal use and may change at any time. - [field: SerializeField, HideInInspector] - public List InitializedNestedNetworkObjects { get; private set; } = new(); + [HideInInspector] + public List InitializedNestedNetworkObjects = new(); /// /// Returns a cached collection containing initialized and runtime nested NetworkObjects. /// - internal List RetrieveNestedNetworkObjects() + /// True to also return nested NetworkObjects beyond direct children of this object. + internal List RetrieveNestedNetworkObjects(bool recursive) { - List nobs = CollectionCaches.RetrieveList(); - nobs.AddRange(InitializedNestedNetworkObjects); + List cache = CollectionCaches.RetrieveList(); + cache.AddRange(InitializedNestedNetworkObjects); foreach (NetworkBehaviour nb in RuntimeChildNetworkBehaviours) - nobs.Add(nb.NetworkObject); + cache.Add(nb.NetworkObject); + + if (recursive) + { + int count = cache.Count; + for (int i = 0; i < count; i++) + { + List recursiveCache = cache[i].RetrieveNestedNetworkObjects(recursive: true); + cache.AddRange(recursiveCache); + CollectionCaches.Store(recursiveCache); + } + } - return nobs; + return cache; } /// @@ -134,20 +145,17 @@ internal List RetrieveNestedNetworkObjects() /// This is exposed only for low-level use and may change without notice. /// [HideInInspector] - public NetworkBehaviour RuntimeParentNetworkBehaviour { get; private set; } - + public NetworkBehaviour RuntimeParentNetworkBehaviour; /// /// NetworkObjects which are made child at runtime using NetworkObject.SetParent. /// This is exposed only for low-level use and may change without notice. /// [HideInInspector] - public List RuntimeChildNetworkBehaviours { get; private set; } - + public List RuntimeChildNetworkBehaviours; /// /// NetworkBehaviour parenting this instance. This value prioritizes the runtime value, then initialized value. /// This is exposed only for low-level use and may change without notice. /// - [HideInInspector] internal NetworkBehaviour CurrentParentNetworkBehaviour { get @@ -185,6 +193,7 @@ public bool IsNetworked /// /// public bool GetIsNetworked() => _isNetworked; + /// /// Sets IsNetworked value. This method must be called before Start. /// @@ -203,11 +212,13 @@ public void SetIsNetworked(bool value) /// [Obsolete("Use GetIsSpawnable.")] //Remove on V5. public bool IsSpawnable => _isSpawnable; + /// /// Gets the current IsSpawnable value. /// /// public bool GetIsSpawnable() => _isSpawnable; + /// /// Sets IsSpawnable value. /// @@ -299,6 +310,11 @@ public void SetDefaultDespawnType(DespawnType despawnType) /// True if disabled NetworkBehaviours have been initialized. /// private bool _disabledNetworkBehavioursInitialized; + /// + /// Becomes true once initialized values are set. + /// + [System.NonSerialized] + private bool _initializedValusSet; #endregion #region Const. @@ -334,8 +350,7 @@ public override string ToString() protected virtual void Awake() { _isStatic = gameObject.isStatic; - RuntimeChildNetworkBehaviours = CollectionCaches.RetrieveList(); - + /* If networkBehaviours are not yet initialized then do so now. * After initializing at least 1 networkBehaviour will always exist * as emptyNetworkBehaviour is added automatically when none are present. */ @@ -351,15 +366,15 @@ protected virtual void Awake() isNested = true; break; } - + parent = parent.parent; } - + //If not nested then init if (!isNested) SetInitializedValues(parentNob: null); } - + SetChildDespawnedState(); } @@ -418,6 +433,10 @@ private void OnDisable() private void OnDestroy() { + //The object never initialized for use. + if (!_initializedValusSet) + return; + /* If already deinitializing then FishNet is in the process of, * or has finished cleaning up this object. */ //callStopNetwork = (ServerManager.Objects.GetFromPending(ObjectId) == null); @@ -459,7 +478,7 @@ private void OnDestroy() { Deinitialize_Prediction(true); NetworkManager.ServerManager.Objects.NetworkObjectUnexpectedlyDestroyed(this, true); - + InvokeStopCallbacks(asServer: true, invokeSyncTypeCallbacks: true); } @@ -467,11 +486,11 @@ private void OnDestroy() { Deinitialize_Prediction(false); NetworkManager.ClientManager.Objects.NetworkObjectUnexpectedlyDestroyed(this, false); - + InvokeStopCallbacks(false, true); } } - + /* If owner exist then remove object from owner. * This has to be called here as well OnDisable because * the OnDisable will only remove the object if @@ -487,16 +506,18 @@ private void OnDestroy() if (NetworkBehaviours.Count > 0) { NetworkBehaviour thisNb = NetworkBehaviours[0]; - RuntimeParentNetworkBehaviour?.NetworkObject.RuntimeChildNetworkBehaviours.Remove(thisNb); + if (RuntimeParentNetworkBehaviour != null) + RuntimeParentNetworkBehaviour.NetworkObject.RuntimeChildNetworkBehaviours.Remove(thisNb); } - CollectionCaches.Store(RuntimeChildNetworkBehaviours); IsDeinitializing = true; SetDeinitializedStatus(); NetworkBehaviour_OnDestroy(); + StoreCollections(); + void NetworkBehaviour_OnDestroy() { foreach (NetworkBehaviour nb in NetworkBehaviours) @@ -840,6 +861,18 @@ internal void SetInitializedValues(NetworkObject parentNob, ref byte componentId return; } + /* If NetworkBehaviours is null then all collections are. + * Set values for each collection. */ + if (!_initializedValusSet) + { + /* This only runs when playing, so it's safe to return existing to the pool. */ + StoreCollections(); + + RetrieveCollections(); + + _initializedValusSet = true; + } + SerializeTransformProperties(); SetIsNestedThroughTraversal(); /* This method can be called by the developer initializing prefabs, the prefab collection doing it automatically, @@ -1023,7 +1056,7 @@ internal bool CanDeinitialize(bool asServer) return false; else if (!asServer && !IsClientInitialized) return false; - + return true; } @@ -1034,7 +1067,7 @@ internal void Deinitialize(bool asServer) { if (!CanDeinitialize(asServer)) return; - + Deinitialize_Prediction(asServer); InvokeStopCallbacks(asServer, true); @@ -1080,7 +1113,7 @@ public void ResetState(bool asServer) SetOwner(NetworkManager.EmptyConnection); if (NetworkObserver != null) NetworkObserver.Deinitialize(false); - + //QOL references. NetworkManager = null; ServerManager = null; @@ -1196,10 +1229,10 @@ internal void GiveOwnership(NetworkConnection newOwner, bool asServer, bool incl if (includeNested) { - List allNested = RetrieveNestedNetworkObjects(); + List allNested = RetrieveNestedNetworkObjects(recursive: true); foreach (NetworkObject nob in allNested) - nob.GiveOwnership(newOwner, asServer, includeNested); + nob.GiveOwnership(newOwner, asServer, includeNested: true); CollectionCaches.Store(allNested); } @@ -1315,6 +1348,23 @@ internal void SerializeTransformProperties() SerializedTransformProperties = new(transform.localPosition, transform.localRotation, transform.localScale); } + /// + /// Stores collections to caches. + /// + private void StoreCollections() + { + CollectionCaches.StoreAndDefault(ref NetworkBehaviours); + CollectionCaches.StoreAndDefault(ref InitializedNestedNetworkObjects); + CollectionCaches.StoreAndDefault(ref RuntimeChildNetworkBehaviours); + } + + private void RetrieveCollections() + { + NetworkBehaviours = CollectionCaches.RetrieveList(); + InitializedNestedNetworkObjects = CollectionCaches.RetrieveList(); + RuntimeChildNetworkBehaviours = CollectionCaches.RetrieveList(); + } + #region Editor. #if UNITY_EDITOR /// diff --git a/Assets/FishNet/Runtime/Observing/NetworkObserver.cs b/Assets/FishNet/Runtime/Observing/NetworkObserver.cs index f07de094..f86893aa 100644 --- a/Assets/FishNet/Runtime/Observing/NetworkObserver.cs +++ b/Assets/FishNet/Runtime/Observing/NetworkObserver.cs @@ -294,6 +294,7 @@ public ObserverCondition GetObserverCondition() where T : ObserverCondition internal ObserverStateChange RebuildObservers(NetworkConnection connection, bool timedOnly) { bool currentlyAdded = (_networkObject.Observers.Contains(connection)); + //True if all conditions are met. bool allConditionsMet = true; /* If cnnection is owner then they can see the object. */ @@ -313,7 +314,7 @@ internal ObserverStateChange RebuildObservers(NetworkConnection connection, bool if (parentVisible && !_lastParentVisible) timedOnly = false; _lastParentVisible = parentVisible; - + //If parent is not visible no further checks are required. if (!parentVisible) { diff --git a/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectCaching.cs b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectCaching.cs index a0f90f91..9693c129 100644 --- a/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectCaching.cs +++ b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectCaching.cs @@ -1,5 +1,4 @@ using GameKit.Dependencies.Utilities.Types; -using System; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -181,7 +180,16 @@ public static ResettableRingBuffer RetrieveRingBuffer() /// /// public static HashSet RetrieveHashSet() => CollectionCaches.RetrieveHashSet(); - + /// + /// Retrieves a collection. + /// + /// + public static Queue RetrieveQueue() => CollectionCaches.RetrieveQueue(); + /// + /// Retrieves a collection. + /// + /// + public static BasicQueue RetrieveBasicQueue() => CollectionCaches.RetrieveBasicQueue(); /// /// Stores a collection and sets the original reference to default. @@ -292,6 +300,67 @@ public static void Store(HashSet value) value.Clear(); CollectionCaches.Store(value); } + + /// + /// Stores a collection and sets the original reference to default. + /// Method will not execute if value is null. + /// + /// Value to store. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void StoreAndDefault(ref Queue value) + { + if (value == null) + return; + + Store(value); + value = default; + } + /// + /// Stores a collection. + /// + /// Value to store. + public static void Store(Queue value) + { + foreach (T item in value) + { + item.ResetState(); + ObjectCaches.Store(item); + } + value.Clear(); + CollectionCaches.Store(value); + } + + /// + /// Stores a collection and sets the original reference to default. + /// Method will not execute if value is null. + /// + /// Value to store. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void StoreAndDefault(ref BasicQueue value) + { + if (value == null) + return; + + Store(value); + value = default; + } + /// + /// Stores a collection. + /// + /// Value to store. + public static void Store(BasicQueue value) + { + while (value.TryDequeue(out T result)) + { + result.ResetState(); + ObjectCaches.Store(result); + } + + value.Clear(); + CollectionCaches.Store(value); + } + + } /// diff --git a/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/RingBuffer.cs b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/RingBuffer.cs index caf032a3..27c7d2fd 100644 --- a/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/RingBuffer.cs +++ b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/RingBuffer.cs @@ -419,7 +419,7 @@ public Enumerator GetEnumerator() return _enumerator; } - IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); // Collection.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); // Collection.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } } \ No newline at end of file diff --git a/Assets/FishNet/package.json b/Assets/FishNet/package.json index 5237bede..38dd0df5 100644 --- a/Assets/FishNet/package.json +++ b/Assets/FishNet/package.json @@ -1,6 +1,6 @@ { "name": "com.firstgeargames.fishnet", - "version": "4.5.1", + "version": "4.5.2", "displayName": "FishNet: Networking Evolved", "description": "A feature-rich Unity networking solution aimed towards reliability, ease of use, efficiency, and flexibility.", "unity": "2021.3",