From b69f2aff4769f385fcbc5f35ffde8ee25963fafe Mon Sep 17 00:00:00 2001 From: Jakob Feldmann Date: Tue, 14 May 2024 14:29:29 +0200 Subject: [PATCH] chore: updated FishNet --- Assets/FishNet.meta | 2 +- .../CodeGenerating/Helpers/GeneralHelper.cs | 25 +- .../CodeGenerating/ILCore/FishNetILPP.cs | 38 + .../Prediction/PredictionProcessor.cs | 4 +- .../Processing/ReaderProcessor.cs | 19 +- .../Processing/Rpc/RpcProcessor.cs | 3 - .../Processing/WriterProcessor.cs | 3 +- .../Prefabs/_Authenticator_Prefabs.asset | 15 - .../Prefabs/_Authenticator_Prefabs.asset.meta | 8 - .../Authenticator/Scenes/Authenticator.unity | 2 +- .../Prefabs/_ColliderRollback_Prefabs.asset | 16 - .../_ColliderRollback_Prefabs.asset.meta | 8 - .../Scenes/ColliderRollbackDemo.unity | 11 +- .../HashGrid/Prefabs/_HashGrid_Prefabs.asset | 17 - .../Prefabs/_HashGrid_Prefabs.asset.meta | 8 - .../Demos/HashGrid/Scenes/HashGrid_Demo.unity | 16 +- .../Demos/IntermediateLayer/Prefabs.meta | 8 - .../Prefabs/_IntermediateLayer_Prefabs.asset | 15 - .../_IntermediateLayer_Prefabs.asset.meta | 8 - .../Prefabs/_Network LOD_Prefabs.asset | 17 - .../Prefabs/_Network LOD_Prefabs.asset.meta | 8 - Assets/FishNet/Demos/Prediction 2.meta | 8 - .../Prediction 2/CharacterController.meta | 8 - .../CharacterController/Materials.meta | 8 - .../CharacterController/Materials/BlueMat.mat | 77 - .../Materials/BlueMat.mat.meta | 8 - .../CharacterController/PredictionV2_CC.unity | 2001 ---------------- .../CharacterController/Prefabs.meta | 8 - .../CharacterControllerPrediction.prefab | 202 -- .../CharacterController/Scripts.meta | 8 - .../CharacterControllerPredictionV2.cs | 152 -- .../README Prediction V Examples.txt | 5 - .../README Prediction V Examples.txt.meta | 7 - .../FishNet/Demos/Prediction 2/Rigidbody.meta | 8 - .../Rigidbody/PredictionV2_RB.unity | 2063 ----------------- .../Rigidbody/PredictionV2_RB.unity.meta | 7 - .../Demos/Prediction 2/Rigidbody/Prefabs.meta | 8 - .../Prefabs/RigidbodyPrediction.prefab | 451 ---- .../Prefabs/RigidbodyPrediction.prefab.meta | 7 - .../Demos/Prediction 2/Rigidbody/Scripts.meta | 8 - .../Scripts/RigidbodyPredictionV2.cs | 211 -- .../Demos/Prefabs/NetworkHudCanvas.prefab | 23 +- .../Demos/Prefabs/NetworkManager.prefab | 208 ++ .../NetworkManager.prefab.meta} | 2 +- .../Prefabs/_SceneManager_Old_Prefabs.asset | 16 - .../_SceneManager_Old_Prefabs.asset.meta | 8 - ...SceneManager_Additive Scenes_Prefabs.asset | 16 - ...Manager_Additive Scenes_Prefabs.asset.meta | 8 - .../Bayou/Core/BidirectionalDictionary.cs | 186 +- .../Plugins/Bayou/Core/ServerSocket.cs | 2 +- .../SimpleWebTransport/Common/BufferPool.cs | 6 +- .../SimpleWebTransport/Common/ReceiveLoop.cs | 4 +- .../SimpleWebTransport/Common/SendLoop.cs | 26 +- .../Server/ServerHandshake.cs | 2 +- .../Server/SimpleWebServer.cs | 20 +- .../Server/WebSocketServer.cs | 23 +- .../SimpleWebTransport.asmdef | 10 +- .../Edgegap/Editor/EdgegapBuildUtils.cs | 8 +- .../Plugins/Edgegap/Editor/EdgegapWindowV2.cs | 10 - .../Plugins/Edgegap/Enums/ApiEnvironment.cs | 4 +- .../Edgegap/Newtonsoft_Package_Patch.cs | 5 +- .../Runtime/CodeGenerating/Attributes.cs | 13 +- Assets/FishNet/Runtime/Connection/Buffer.cs | 2 +- .../NetworkConnection.Prediction.cs | 26 +- .../Runtime/Connection/NetworkConnection.cs | 152 +- .../PrefabCollectionGenerator/Generator.cs | 39 +- .../Runtime/Editor/ScriptingDefines.cs | 2 + Assets/FishNet/Runtime/FishNet.Runtime.asmdef | 18 +- .../Editor/NetworkAnimatorEditor.cs | 16 +- .../NetworkAnimator/NetworkAnimator.cs | 72 +- .../NetworkTransform/NetworkTransform.cs | 32 +- .../Component/Prediction/NetworkCollider.cs | 30 +- .../Component/Prediction/NetworkCollider2D.cs | 37 +- .../Component/Prediction/NetworkCollision.cs | 10 - .../Prediction/NetworkCollision2D.cs | 11 - .../Component/Prediction/PredictedObject.cs | 2 +- .../Component/Prediction/RigidbodyPauser.cs | 4 +- .../Runtime/Managing/Client/ClientManager.cs | 55 +- .../Managing/Client/Object/ClientObjects.cs | 7 +- .../Managing/Client/Object/ObjectCaching.cs | 4 +- .../Runtime/Managing/Debugging/ParseLogger.cs | 3 + .../Logging/LevelLoggingConfiguration.cs | 15 +- .../Runtime/Managing/NetworkManager.cs | 23 +- .../Object/ManagedObjects.Spawning.cs | 24 +- .../Editor/PredictionManagerEditor.cs | 101 +- .../Managing/Prediction/PredictionManager.cs | 415 ++-- .../Runtime/Managing/Scened/SceneManager.cs | 2 +- .../Server/Editor/ServerManagerEditor.cs | 43 +- .../Managing/Server/Object/ServerObjects.cs | 6 +- .../Runtime/Managing/Server/ServerManager.cs | 141 +- .../Timing/Editor/TimeManagerEditor.cs | 6 +- .../Runtime/Managing/Timing/TimeManager.cs | 168 +- .../Managing/Transporting/TransportManager.cs | 33 +- .../Object/ChangedTransformProperties.cs | 36 +- .../Object/Editor/NetworkObjectEditor.cs | 67 +- .../Object/NetworkBehaviour.Prediction.cs | 192 +- .../Runtime/Object/NetworkBehaviour.RPCs.cs | 9 +- .../Runtime/Object/NetworkObject.Callbacks.cs | 60 +- .../Object/NetworkObject.Prediction.cs | 173 +- .../FishNet/Runtime/Object/NetworkObject.cs | 60 +- .../Runtime/Object/Prediction/MoveRates.cs | 159 +- .../Object/Prediction/PredictionRigidbody.cs | 199 +- .../Prediction/PredictionRigidbody2D.cs | 98 +- .../Object/Synchronizing/SyncDictionary.cs | 3 - .../Runtime/Object/Synchronizing/SyncList.cs | 2 +- .../Runtime/Object/Synchronizing/SyncVar.cs | 17 +- .../Runtime/Object/TransformProperties.cs | 22 + .../Runtime/Object/TransformPropertiesFlag.cs | 24 + .../Object/TransformPropertiesFlag.cs.meta} | 2 +- .../Scripts/ColliderRollback.cs | 2 + .../Scripts/RollbackManager.cs | 83 +- .../Dependencies/Utilities/ObjectCaching.cs | 37 + .../Utilities/Types/BasicQueue.cs | 231 ++ .../Utilities/Types/BasicQueue.cs.meta} | 2 +- .../GameKit/Dependencies/Utilities/Vectors.cs | 6 +- .../FishNet/Runtime/Plugins/Yak/CHANGELOG.txt | 2 - .../Runtime/Plugins/Yak/Core/ClientSocket.cs | 57 + .../Runtime/Plugins/Yak/Core/CommonSocket.cs | 50 + .../Runtime/Plugins/Yak/Core/LocalPacket.cs | 12 +- .../Runtime/Plugins/Yak/Core/ServerSocket.cs | 83 + .../FishNet/Runtime/Plugins/Yak/VERSION.txt | 1 - .../Runtime/Plugins/Yak/VERSION.txt.meta | 7 - Assets/FishNet/Runtime/Plugins/Yak/Yak.cs | 322 +++ .../Runtime/Serializing/GenericReader.cs | 43 + .../Runtime/Serializing/GenericReader.cs.meta | 11 + .../Runtime/Serializing/GenericWriter.cs | 42 + .../Runtime/Serializing/GenericWriter.cs.meta | 11 + .../Serializing/Helping/ValueConversions.cs | 3 - .../Runtime/Serializing/Reader.Delta.cs | 96 + .../Runtime/Serializing/Reader.Delta.cs.meta | 11 + Assets/FishNet/Runtime/Serializing/Reader.cs | 68 +- .../Serializing/UnityMathmatics.meta} | 2 +- .../Serializers.UnityMathmaticsBoolean.cs | 470 ++++ ...Serializers.UnityMathmaticsBoolean.cs.meta | 11 + .../Serializers.UnityMathmaticsDouble.cs | 194 ++ .../Serializers.UnityMathmaticsDouble.cs.meta | 11 + .../Serializers.UnityMathmaticsFloat.cs | 192 ++ .../Serializers.UnityMathmaticsFloat.cs.meta | 11 + .../Serializers.UnityMathmaticsHalf.cs | 84 + .../Serializers.UnityMathmaticsHalf.cs.meta | 11 + .../Serializers.UnityMathmaticsInt.cs | 190 ++ .../Serializers.UnityMathmaticsInt.cs.meta | 11 + .../Serializers.UnityMathmaticsMisc.cs | 86 + .../Serializers.UnityMathmaticsMisc.cs.meta | 11 + .../Serializers.UnityMathmaticsUInt.cs | 190 ++ .../Serializers.UnityMathmaticsUInt.cs.meta | 11 + .../Runtime/Serializing/Writer.Delta.cs | 218 ++ .../Runtime/Serializing/Writer.Delta.cs.meta | 11 + Assets/FishNet/Runtime/Serializing/Writer.cs | 94 +- .../Runtime/Serializing/WriterExtensions.cs | 2 + .../FishNet/Runtime/Transporting/PacketId.cs | 1 + .../Runtime/Transporting/TransportConsts.cs | 16 + .../Transporting/TransportConsts.cs.meta | 11 + .../Transports/Multipass/Multipass.cs | 1153 ++++++++- .../Transports/Tugboat/Core/ClientSocket.cs | 2 +- .../Transports/Tugboat/Core/ServerSocket.cs | 11 +- .../Tugboat/LiteNetLib/BaseChannel.cs | 10 +- .../Tugboat/LiteNetLib/Layers/Crc32cLayer.cs | 4 +- .../LiteNetLib/Layers/PacketLayerBase.cs | 2 +- .../LiteNetLib/Layers/XorEncryptLayer.cs | 11 +- .../LiteNetLib/LiteNetLib.csproj.meta} | 2 +- .../Tugboat/LiteNetLib/NatPunchModule.cs | 31 +- .../Tugboat/LiteNetLib/NativeSocket.cs | 128 +- .../Transports/Tugboat/LiteNetLib/NetDebug.cs | 20 +- .../Tugboat/LiteNetLib/NetManager.HashSet.cs | 310 +++ .../LiteNetLib/NetManager.HashSet.cs.meta | 11 + .../LiteNetLib/NetManager.PacketPool.cs | 4 +- .../Tugboat/LiteNetLib/NetManager.Socket.cs | 513 ++-- .../Tugboat/LiteNetLib/NetManager.cs | 564 ++--- .../Tugboat/LiteNetLib/NetPacket.cs | 5 +- .../Transports/Tugboat/LiteNetLib/NetPeer.cs | 157 +- .../Transports/Tugboat/LiteNetLib/NetUtils.cs | 62 +- .../Tugboat/LiteNetLib/PausedSocketFix.cs | 57 + .../LiteNetLib/PausedSocketFix.cs.meta | 11 + .../Tugboat/LiteNetLib/ReliableChannel.cs | 31 +- .../Tugboat/LiteNetLib/SequencedChannel.cs | 32 +- .../Transports/Tugboat/LiteNetLib/Trimming.cs | 12 + .../Tugboat/LiteNetLib/Trimming.cs.meta | 11 + .../LiteNetLib/Utils/FastBitConverter.cs | 4 +- .../Tugboat/LiteNetLib/Utils/NetDataReader.cs | 339 ++- .../Tugboat/LiteNetLib/Utils/NetDataWriter.cs | 70 +- .../LiteNetLib/Utils/NetPacketProcessor.cs | 60 +- .../Tugboat/LiteNetLib/Utils/NetSerializer.cs | 40 +- .../Tugboat/LiteNetLib/Utils/Preserve.cs | 12 + .../Tugboat/LiteNetLib/Utils/Preserve.cs.meta | 11 + .../Tugboat/LiteNetLib/package.json | 11 + .../Tugboat/LiteNetLib/package.json.meta} | 2 +- .../Utility/AdaptiveInterpolationType.cs | 36 + .../Utility/AdaptiveInterpolationType.cs.meta | 11 + .../Utility/AdaptiveLocalTransformSmoother.cs | 612 +++++ .../AdaptiveLocalTransformSmoother.cs.meta | 11 + .../Runtime/Utility/Extension/Transforms.cs | 18 +- .../Runtime/Utility/Performance/BasicQueue.cs | 402 ++-- .../Utility/Performance/DefaultObjectPool.cs | 11 +- Assets/FishNet/VERSION.txt | 1 - Assets/FishNet/VERSION.txt.meta | 7 - Assets/FishNet/package.json | 2 +- 197 files changed, 8429 insertions(+), 8131 deletions(-) delete mode 100644 Assets/FishNet/Demos/Authenticator/Prefabs/_Authenticator_Prefabs.asset delete mode 100644 Assets/FishNet/Demos/Authenticator/Prefabs/_Authenticator_Prefabs.asset.meta delete mode 100644 Assets/FishNet/Demos/ColliderRollback/Prefabs/_ColliderRollback_Prefabs.asset delete mode 100644 Assets/FishNet/Demos/ColliderRollback/Prefabs/_ColliderRollback_Prefabs.asset.meta delete mode 100644 Assets/FishNet/Demos/HashGrid/Prefabs/_HashGrid_Prefabs.asset delete mode 100644 Assets/FishNet/Demos/HashGrid/Prefabs/_HashGrid_Prefabs.asset.meta delete mode 100644 Assets/FishNet/Demos/IntermediateLayer/Prefabs.meta delete mode 100644 Assets/FishNet/Demos/IntermediateLayer/Prefabs/_IntermediateLayer_Prefabs.asset delete mode 100644 Assets/FishNet/Demos/IntermediateLayer/Prefabs/_IntermediateLayer_Prefabs.asset.meta delete mode 100644 Assets/FishNet/Demos/Network LOD/Prefabs/_Network LOD_Prefabs.asset delete mode 100644 Assets/FishNet/Demos/Network LOD/Prefabs/_Network LOD_Prefabs.asset.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/CharacterController.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/CharacterController/Materials.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/CharacterController/Materials/BlueMat.mat delete mode 100644 Assets/FishNet/Demos/Prediction 2/CharacterController/Materials/BlueMat.mat.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/CharacterController/PredictionV2_CC.unity delete mode 100644 Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs/CharacterControllerPrediction.prefab delete mode 100644 Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts/CharacterControllerPredictionV2.cs delete mode 100644 Assets/FishNet/Demos/Prediction 2/README Prediction V Examples.txt delete mode 100644 Assets/FishNet/Demos/Prediction 2/README Prediction V Examples.txt.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/Rigidbody.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/Rigidbody/PredictionV2_RB.unity delete mode 100644 Assets/FishNet/Demos/Prediction 2/Rigidbody/PredictionV2_RB.unity.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs/RigidbodyPrediction.prefab delete mode 100644 Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs/RigidbodyPrediction.prefab.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts.meta delete mode 100644 Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts/RigidbodyPredictionV2.cs create mode 100644 Assets/FishNet/Demos/Prefabs/NetworkManager.prefab rename Assets/FishNet/Demos/{Prediction 2/CharacterController/Prefabs/CharacterControllerPrediction.prefab.meta => Prefabs/NetworkManager.prefab.meta} (74%) delete mode 100644 Assets/FishNet/Demos/SceneManager (Old Examples)/Prefabs/_SceneManager_Old_Prefabs.asset delete mode 100644 Assets/FishNet/Demos/SceneManager (Old Examples)/Prefabs/_SceneManager_Old_Prefabs.asset.meta delete mode 100644 Assets/FishNet/Demos/SceneManager/Additive Scenes/Prefabs/_SceneManager_Additive Scenes_Prefabs.asset delete mode 100644 Assets/FishNet/Demos/SceneManager/Additive Scenes/Prefabs/_SceneManager_Additive Scenes_Prefabs.asset.meta create mode 100644 Assets/FishNet/Runtime/Object/TransformPropertiesFlag.cs rename Assets/FishNet/{Demos/Prediction 2/CharacterController/Scripts/CharacterControllerPredictionV2.cs.meta => Runtime/Object/TransformPropertiesFlag.cs.meta} (83%) create mode 100644 Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/BasicQueue.cs rename Assets/FishNet/{Demos/Prediction 2/Rigidbody/Scripts/RigidbodyPredictionV2.cs.meta => Runtime/Plugins/GameKit/Dependencies/Utilities/Types/BasicQueue.cs.meta} (83%) delete mode 100644 Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt delete mode 100644 Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt delete mode 100644 Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt.meta create mode 100644 Assets/FishNet/Runtime/Serializing/GenericReader.cs create mode 100644 Assets/FishNet/Runtime/Serializing/GenericReader.cs.meta create mode 100644 Assets/FishNet/Runtime/Serializing/GenericWriter.cs create mode 100644 Assets/FishNet/Runtime/Serializing/GenericWriter.cs.meta create mode 100644 Assets/FishNet/Runtime/Serializing/Reader.Delta.cs create mode 100644 Assets/FishNet/Runtime/Serializing/Reader.Delta.cs.meta rename Assets/FishNet/{Demos/Authenticator/Prefabs.meta => Runtime/Serializing/UnityMathmatics.meta} (77%) create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsBoolean.cs create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsBoolean.cs.meta create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsDouble.cs create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsDouble.cs.meta create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsFloat.cs create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsFloat.cs.meta create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsHalf.cs create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsHalf.cs.meta create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsInt.cs create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsInt.cs.meta create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsMisc.cs create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsMisc.cs.meta create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsUInt.cs create mode 100644 Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsUInt.cs.meta create mode 100644 Assets/FishNet/Runtime/Serializing/Writer.Delta.cs create mode 100644 Assets/FishNet/Runtime/Serializing/Writer.Delta.cs.meta create mode 100644 Assets/FishNet/Runtime/Transporting/TransportConsts.cs create mode 100644 Assets/FishNet/Runtime/Transporting/TransportConsts.cs.meta rename Assets/FishNet/{Demos/Prediction 2/CharacterController/PredictionV2_CC.unity.meta => Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta} (74%) create mode 100644 Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.HashSet.cs create mode 100644 Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.HashSet.cs.meta create mode 100644 Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PausedSocketFix.cs create mode 100644 Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PausedSocketFix.cs.meta create mode 100644 Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Trimming.cs create mode 100644 Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Trimming.cs.meta create mode 100644 Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/Preserve.cs create mode 100644 Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/Preserve.cs.meta create mode 100644 Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/package.json rename Assets/FishNet/Runtime/{Plugins/Yak/CHANGELOG.txt.meta => Transporting/Transports/Tugboat/LiteNetLib/package.json.meta} (75%) create mode 100644 Assets/FishNet/Runtime/Utility/AdaptiveInterpolationType.cs create mode 100644 Assets/FishNet/Runtime/Utility/AdaptiveInterpolationType.cs.meta create mode 100644 Assets/FishNet/Runtime/Utility/AdaptiveLocalTransformSmoother.cs create mode 100644 Assets/FishNet/Runtime/Utility/AdaptiveLocalTransformSmoother.cs.meta delete mode 100644 Assets/FishNet/VERSION.txt delete mode 100644 Assets/FishNet/VERSION.txt.meta diff --git a/Assets/FishNet.meta b/Assets/FishNet.meta index 5e5a228..e0a3c57 100644 --- a/Assets/FishNet.meta +++ b/Assets/FishNet.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f1525dbf8ebd59e438b504fa19c4fd6c +guid: baec5a367bebced4da1b56dbcedde312 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs b/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs index bb308fc..7d1f26d 100644 --- a/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs +++ b/Assets/FishNet/CodeGenerating/Helpers/GeneralHelper.cs @@ -8,11 +8,13 @@ using FishNet.Object.Helping; using FishNet.Serializing; using FishNet.Serializing.Helping; using FishNet.Utility.Performance; +using GameKit.Dependencies.Utilities; using MonoFN.Cecil; using MonoFN.Cecil.Cil; using MonoFN.Cecil.Rocks; using System; using System.Collections.Generic; +using System.Runtime.InteropServices.ComTypes; using UnityEngine; using SR = System.Reflection; @@ -63,6 +65,7 @@ namespace FishNet.CodeGenerating.Helping public TypeReference ActionT3_TypeRef; public MethodReference ActionT2Constructor_MethodRef; public MethodReference ActionT3Constructor_MethodRef; + public TypeReference ObjectCaches_TypeRef; private Dictionary _importedTypeReferences = new Dictionary(); private Dictionary _importedFieldReferences = new Dictionary(); @@ -70,6 +73,7 @@ namespace FishNet.CodeGenerating.Helping private Dictionary _typeReferenceResolves = new Dictionary(); private Dictionary _fieldReferenceResolves = new Dictionary(); private Dictionary _comparerDelegates = new Dictionary(); + private MethodReference _objectCaches_Retrieve_MethodRef; #endregion #region Const. @@ -93,6 +97,9 @@ namespace FishNet.CodeGenerating.Helping ExcludeSerializationAttribute_FullName = typeof(ExcludeSerializationAttribute).FullName; NotSerializerAttribute_FullName = typeof(NotSerializerAttribute).FullName; + TypeReference _objectCaches_TypeRef = base.ImportReference(typeof(ObjectCaches<>)); + _objectCaches_Retrieve_MethodRef = _objectCaches_TypeRef.CachedResolve(base.Session).GetMethodReference(base.Session, nameof(ObjectCaches.Retrieve)); + tmpType = typeof(BasicQueue<>); base.ImportReference(tmpType); foreach (SR.MethodInfo mi in tmpType.GetMethods()) @@ -904,7 +911,23 @@ namespace FishNet.CodeGenerating.Helping #region SetVariableDef. /// - /// Initializes variableDef as a new object or collection of typeDef. + /// Initializes variableDef as an object or collection of typeDef using cachces. + /// + /// + /// + /// + public void SetVariableDefinitionFromCaches(ILProcessor processor, VariableDefinition variableDef, TypeDefinition typeDef) + { + TypeReference dataTr = variableDef.VariableType; + GenericInstanceType git = ObjectCaches_TypeRef.MakeGenericInstanceType(new TypeReference[] { dataTr }); + + MethodReference genericInstanceMethod = _objectCaches_Retrieve_MethodRef.MakeHostInstanceGeneric(base.Session, git); + processor.Emit(OpCodes.Call, genericInstanceMethod); + processor.Emit(OpCodes.Stloc, variableDef); + } + + /// + /// Initializes variableDef as a new object or collection of typeDef using instantiation. /// /// /// diff --git a/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs b/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs index 7fcbe3b..013bdc4 100644 --- a/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs +++ b/Assets/FishNet/CodeGenerating/ILCore/FishNetILPP.cs @@ -78,6 +78,7 @@ namespace FishNet.CodeGenerating.ILCore modified |= CreateDeclaredSerializerDelegates(session); modified |= CreateDeclaredSerializers(session); modified |= CreateDeclaredComparerDelegates(session); + modified |= CreateIncludeSerializationSerializers(session); modified |= CreateIBroadcast(session); #if !DISABLE_QOL_ATTRIBUTES modified |= CreateQOLAttributes(session); @@ -233,6 +234,43 @@ namespace FishNet.CodeGenerating.ILCore return modified; } + + /// + /// Creates serializers for types that use IncludeSerialization attribute. + /// + private bool CreateIncludeSerializationSerializers(CodegenSession session) + { + string attributeName = typeof(IncludeSerializationAttribute).FullName; + WriterProcessor wp = session.GetClass(); + ReaderProcessor rp = session.GetClass(); + + bool modified = false; + List allTypeDefs = session.Module.Types.ToList(); + foreach (TypeDefinition td in allTypeDefs) + { + if (!CanSerialize()) + continue; + + TypeReference tr = session.ImportReference(td); + if (wp.CreateWriter(tr) != null && rp.CreateReader(tr) != null) + modified = true; + else + session.LogError($"Failed to create serializers for {td.FullName}."); + + bool CanSerialize() + { + foreach (CustomAttribute item in td.CustomAttributes) + { + if (item.AttributeType.FullName == attributeName) + return true; + } + + return false; + } + } + + return modified; + } /// diff --git a/Assets/FishNet/CodeGenerating/Processing/Prediction/PredictionProcessor.cs b/Assets/FishNet/CodeGenerating/Processing/Prediction/PredictionProcessor.cs index 8350f28..22d1008 100644 --- a/Assets/FishNet/CodeGenerating/Processing/Prediction/PredictionProcessor.cs +++ b/Assets/FishNet/CodeGenerating/Processing/Prediction/PredictionProcessor.cs @@ -302,7 +302,7 @@ namespace FishNet.CodeGenerating.Processing { if (inst.Operand is MethodReference mr) { - if (mr.FullName == reconcileMd.FullName) + if (mr.Name == reconcileMd.Name) return true; } } @@ -372,6 +372,8 @@ namespace FishNet.CodeGenerating.Processing { if (!MethodIsPrivate(methodDef) || AlreadyFound(reconcileMd)) error = true; + else + reconcileMd = methodDef; } if (error) break; diff --git a/Assets/FishNet/CodeGenerating/Processing/ReaderProcessor.cs b/Assets/FishNet/CodeGenerating/Processing/ReaderProcessor.cs index f00a35b..75b1779 100644 --- a/Assets/FishNet/CodeGenerating/Processing/ReaderProcessor.cs +++ b/Assets/FishNet/CodeGenerating/Processing/ReaderProcessor.cs @@ -11,6 +11,7 @@ using FishNet.CodeGenerating.Extension; using FishNet.Utility.Performance; using FishNet.Object; using FishNet.Utility; +using GameKit.Dependencies.Utilities; namespace FishNet.CodeGenerating.Helping { @@ -220,7 +221,7 @@ namespace FishNet.CodeGenerating.Helping return; GeneratedReader_OnLoad_MethodDef.RemoveEndRet(base.Session); - + //Check if already exist. ILProcessor processor = GeneratedReader_OnLoad_MethodDef.Body.GetILProcessor(); TypeReference dataTypeRef = readMr.ReturnType; @@ -365,7 +366,7 @@ namespace FishNet.CodeGenerating.Helping TypeReference genericTr = base.ImportReference(readTypeRef); readMr = _readUnpackedMethodRef.GetMethodReference(base.Session, genericTr); } - + insts.Add(processor.Create(OpCodes.Call, readMr)); //Store into local variable. insts.Add(processor.Create(OpCodes.Stloc, createdVariableDef)); @@ -1045,8 +1046,18 @@ namespace FishNet.CodeGenerating.Helping } /* If here then not null. */ - //Make a new instance of object type and set to objectVariableDef. - base.GetClass().SetVariableDefinitionFromObject(processor, objectVariableDef, objectTypeDef); + //See if to use non-alloc reads. + if (objectTr.CachedResolve(base.Session).HasCustomAttribute()) + { + //Make a new instance of object type and set to objectVariableDef. + base.GetClass().SetVariableDefinitionFromCaches(processor, objectVariableDef, objectTypeDef); + } + else + { + //Make a new instance of object type and set to objectVariableDef. + base.GetClass().SetVariableDefinitionFromObject(processor, objectVariableDef, objectTypeDef); + } + if (!ReadFieldsAndProperties(createdReaderMd, readerParameterDef, objectVariableDef, objectTr)) return null; /* //codegen scriptableobjects seem to climb too high up to UnityEngine.Object when diff --git a/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs b/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs index 179b804..54127ad 100644 --- a/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs +++ b/Assets/FishNet/CodeGenerating/Processing/Rpc/RpcProcessor.cs @@ -218,10 +218,7 @@ namespace FishNet.CodeGenerating.Processing.Rpc { RpcType rpcType = base.GetClass().GetRpcAttributeType(customAttribute); if (rpcType != RpcType.None) - { count++; - break; - } } } diff --git a/Assets/FishNet/CodeGenerating/Processing/WriterProcessor.cs b/Assets/FishNet/CodeGenerating/Processing/WriterProcessor.cs index 8c11590..8e044cb 100644 --- a/Assets/FishNet/CodeGenerating/Processing/WriterProcessor.cs +++ b/Assets/FishNet/CodeGenerating/Processing/WriterProcessor.cs @@ -80,7 +80,8 @@ namespace FishNet.CodeGenerating.Helping /// public static readonly string[] EXCLUDED_ASSEMBLY_PREFIXES = new string[] { - "UnityEngine." + "UnityEngine.", + "Unity.Mathmatics", }; #endregion diff --git a/Assets/FishNet/Demos/Authenticator/Prefabs/_Authenticator_Prefabs.asset b/Assets/FishNet/Demos/Authenticator/Prefabs/_Authenticator_Prefabs.asset deleted file mode 100644 index 3dc3623..0000000 --- a/Assets/FishNet/Demos/Authenticator/Prefabs/_Authenticator_Prefabs.asset +++ /dev/null @@ -1,15 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4489d77032a81ef42b0067acf2737d4d, type: 3} - m_Name: _Authenticator_Prefabs - m_EditorClassIdentifier: - _prefabs: [] diff --git a/Assets/FishNet/Demos/Authenticator/Prefabs/_Authenticator_Prefabs.asset.meta b/Assets/FishNet/Demos/Authenticator/Prefabs/_Authenticator_Prefabs.asset.meta deleted file mode 100644 index f9f89f3..0000000 --- a/Assets/FishNet/Demos/Authenticator/Prefabs/_Authenticator_Prefabs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ab6a9000f5ff83f45b6761c2a3be018d -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Authenticator/Scenes/Authenticator.unity b/Assets/FishNet/Demos/Authenticator/Scenes/Authenticator.unity index bbf17a2..5528bea 100644 --- a/Assets/FishNet/Demos/Authenticator/Scenes/Authenticator.unity +++ b/Assets/FishNet/Demos/Authenticator/Scenes/Authenticator.unity @@ -362,7 +362,7 @@ MonoBehaviour: _objectPool: {fileID: 0} _persistence: 0 _logging: {fileID: 0} - _spawnablePrefabs: {fileID: 11400000, guid: ab6a9000f5ff83f45b6761c2a3be018d, type: 2} + _spawnablePrefabs: {fileID: 11400000, guid: 68e79e63a16f2c74e81f070bd36822b8, type: 2} --- !u!1 &7443408886491481971 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/FishNet/Demos/ColliderRollback/Prefabs/_ColliderRollback_Prefabs.asset b/Assets/FishNet/Demos/ColliderRollback/Prefabs/_ColliderRollback_Prefabs.asset deleted file mode 100644 index d2dffc6..0000000 --- a/Assets/FishNet/Demos/ColliderRollback/Prefabs/_ColliderRollback_Prefabs.asset +++ /dev/null @@ -1,16 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4489d77032a81ef42b0067acf2737d4d, type: 3} - m_Name: _ColliderRollback_Prefabs - m_EditorClassIdentifier: - _prefabs: - - {fileID: 8475222101369129519, guid: 8cf33e8e99a9b0c4c8f29ff725650de6, type: 3} diff --git a/Assets/FishNet/Demos/ColliderRollback/Prefabs/_ColliderRollback_Prefabs.asset.meta b/Assets/FishNet/Demos/ColliderRollback/Prefabs/_ColliderRollback_Prefabs.asset.meta deleted file mode 100644 index 538d408..0000000 --- a/Assets/FishNet/Demos/ColliderRollback/Prefabs/_ColliderRollback_Prefabs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: d9693011b7416444aa06cafe900e23c0 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/ColliderRollback/Scenes/ColliderRollbackDemo.unity b/Assets/FishNet/Demos/ColliderRollback/Scenes/ColliderRollbackDemo.unity index 5db26c4..4ef26be 100644 --- a/Assets/FishNet/Demos/ColliderRollback/Scenes/ColliderRollbackDemo.unity +++ b/Assets/FishNet/Demos/ColliderRollback/Scenes/ColliderRollbackDemo.unity @@ -309,6 +309,7 @@ MonoBehaviour: _predictionType: 0 _graphicalObject: {fileID: 0} _enableStateForwarding: 1 + _networkTransform: {fileID: 0} _ownerInterpolation: 1 _enableTeleport: 0 _teleportThreshold: 1 @@ -833,6 +834,7 @@ MonoBehaviour: _predictionType: 0 _graphicalObject: {fileID: 0} _enableStateForwarding: 1 + _networkTransform: {fileID: 0} _ownerInterpolation: 1 _enableTeleport: 0 _teleportThreshold: 1 @@ -1817,6 +1819,7 @@ Canvas: m_OverrideSorting: 0 m_OverridePixelPerfect: 0 m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 m_AdditionalShaderChannelsFlag: 0 m_SortingLayerID: 0 m_SortingOrder: 0 @@ -2099,13 +2102,14 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 6f48f002b825cbd45a19bd96d90f9edb, type: 3} m_Name: m_EditorClassIdentifier: - _unreliableMTU: 1023 + _dontRoute: 0 + _unreliableMtu: 1023 _ipv4BindAddress: + _enableIpv6: 1 _ipv6BindAddress: _port: 7770 _maximumClients: 4095 _clientAddress: localhost - _timeout: 15 --- !u!114 &1016939666208092867 MonoBehaviour: m_ObjectHideFlags: 0 @@ -2699,6 +2703,7 @@ Canvas: m_OverrideSorting: 0 m_OverridePixelPerfect: 0 m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 m_AdditionalShaderChannelsFlag: 0 m_SortingLayerID: 0 m_SortingOrder: 0 @@ -2797,7 +2802,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} m_Name: m_EditorClassIdentifier: - _autoStartType: 0 + _autoStartType: 2 _stoppedColor: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} _changingColor: {r: 0.78431374, g: 0.6862745, b: 0, a: 1} _startedColor: {r: 0, g: 0.5882353, b: 0.64705884, a: 1} diff --git a/Assets/FishNet/Demos/HashGrid/Prefabs/_HashGrid_Prefabs.asset b/Assets/FishNet/Demos/HashGrid/Prefabs/_HashGrid_Prefabs.asset deleted file mode 100644 index fe4ef1d..0000000 --- a/Assets/FishNet/Demos/HashGrid/Prefabs/_HashGrid_Prefabs.asset +++ /dev/null @@ -1,17 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4489d77032a81ef42b0067acf2737d4d, type: 3} - m_Name: _HashGrid_Prefabs - m_EditorClassIdentifier: - _prefabs: - - {fileID: 4512293259955182956, guid: 44611030e61220d42ab7c37ba3c0ea92, type: 3} - - {fileID: 4512293259955182956, guid: 0d6d0f48b03b17f49a6340103cd9b9d0, type: 3} diff --git a/Assets/FishNet/Demos/HashGrid/Prefabs/_HashGrid_Prefabs.asset.meta b/Assets/FishNet/Demos/HashGrid/Prefabs/_HashGrid_Prefabs.asset.meta deleted file mode 100644 index 8531564..0000000 --- a/Assets/FishNet/Demos/HashGrid/Prefabs/_HashGrid_Prefabs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 2863463f6933f3f439a639f883f642f6 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/HashGrid/Scenes/HashGrid_Demo.unity b/Assets/FishNet/Demos/HashGrid/Scenes/HashGrid_Demo.unity index 4077e5b..f90af50 100644 --- a/Assets/FishNet/Demos/HashGrid/Scenes/HashGrid_Demo.unity +++ b/Assets/FishNet/Demos/HashGrid/Scenes/HashGrid_Demo.unity @@ -290,6 +290,14 @@ MonoBehaviour: _initializeOrder: 0 _defaultDespawnType: 0 NetworkObserver: {fileID: 0} + _enablePrediction: 0 + _predictionType: 0 + _graphicalObject: {fileID: 0} + _enableStateForwarding: 1 + _networkTransform: {fileID: 0} + _ownerInterpolation: 1 + _enableTeleport: 0 + _teleportThreshold: 1 k__BackingField: 0 k__BackingField: 0 _scenePathHash: 1046374546 @@ -429,6 +437,7 @@ MonoBehaviour: - 90 - 100 _updateHostVisibility: 1 + _maximumTimedObserversDuration: 10 _defaultConditions: - {fileID: 11400000, guid: cc503f7541ebd424c94541e6a767efee, type: 2} --- !u!114 &1424052073952814568 @@ -854,6 +863,7 @@ Canvas: m_OverrideSorting: 0 m_OverridePixelPerfect: 0 m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 m_AdditionalShaderChannelsFlag: 0 m_SortingLayerID: 0 m_SortingOrder: 0 @@ -1002,7 +1012,7 @@ MonoBehaviour: _objectPool: {fileID: 0} _persistence: 0 _logging: {fileID: 0} - _spawnablePrefabs: {fileID: 11400000, guid: 2863463f6933f3f439a639f883f642f6, type: 2} + _spawnablePrefabs: {fileID: 11400000, guid: 68e79e63a16f2c74e81f070bd36822b8, type: 2} --- !u!1 &7443408886575219563 GameObject: m_ObjectHideFlags: 0 @@ -1090,9 +1100,9 @@ MonoBehaviour: _ipv4BindAddress: _enableIpv6: 1 _ipv6BindAddress: - _port: 30681 + _port: 7112 _maximumClients: 4095 - _clientAddress: 4d3a4e3f1ace.pr.edgegap.net + _clientAddress: localhost --- !u!224 &9139860295505404435 RectTransform: m_ObjectHideFlags: 0 diff --git a/Assets/FishNet/Demos/IntermediateLayer/Prefabs.meta b/Assets/FishNet/Demos/IntermediateLayer/Prefabs.meta deleted file mode 100644 index b2a92e2..0000000 --- a/Assets/FishNet/Demos/IntermediateLayer/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 90949fa81eb0c194080a75b84fa699d9 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/IntermediateLayer/Prefabs/_IntermediateLayer_Prefabs.asset b/Assets/FishNet/Demos/IntermediateLayer/Prefabs/_IntermediateLayer_Prefabs.asset deleted file mode 100644 index 9d00963..0000000 --- a/Assets/FishNet/Demos/IntermediateLayer/Prefabs/_IntermediateLayer_Prefabs.asset +++ /dev/null @@ -1,15 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4489d77032a81ef42b0067acf2737d4d, type: 3} - m_Name: _IntermediateLayer_Prefabs - m_EditorClassIdentifier: - _prefabs: [] diff --git a/Assets/FishNet/Demos/IntermediateLayer/Prefabs/_IntermediateLayer_Prefabs.asset.meta b/Assets/FishNet/Demos/IntermediateLayer/Prefabs/_IntermediateLayer_Prefabs.asset.meta deleted file mode 100644 index 5529107..0000000 --- a/Assets/FishNet/Demos/IntermediateLayer/Prefabs/_IntermediateLayer_Prefabs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: dcdf15fc89edd2546baf8ff544470626 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Network LOD/Prefabs/_Network LOD_Prefabs.asset b/Assets/FishNet/Demos/Network LOD/Prefabs/_Network LOD_Prefabs.asset deleted file mode 100644 index cacc73d..0000000 --- a/Assets/FishNet/Demos/Network LOD/Prefabs/_Network LOD_Prefabs.asset +++ /dev/null @@ -1,17 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4489d77032a81ef42b0067acf2737d4d, type: 3} - m_Name: _Network LOD_Prefabs - m_EditorClassIdentifier: - _prefabs: - - {fileID: 4512293259955182956, guid: 300370bdf7819da41937e0beac65b32c, type: 3} - - {fileID: 4512293259955182956, guid: f32d4c19de900e64cb73cedcb8ba6f70, type: 3} diff --git a/Assets/FishNet/Demos/Network LOD/Prefabs/_Network LOD_Prefabs.asset.meta b/Assets/FishNet/Demos/Network LOD/Prefabs/_Network LOD_Prefabs.asset.meta deleted file mode 100644 index a559414..0000000 --- a/Assets/FishNet/Demos/Network LOD/Prefabs/_Network LOD_Prefabs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 0078a285cda09f349b2668a721a53212 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2.meta b/Assets/FishNet/Demos/Prediction 2.meta deleted file mode 100644 index 93248ba..0000000 --- a/Assets/FishNet/Demos/Prediction 2.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7e04426ec3811c4439a20fc6f21abb62 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController.meta b/Assets/FishNet/Demos/Prediction 2/CharacterController.meta deleted file mode 100644 index efba932..0000000 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: accc5b93ebf3b0040baaec2298c7d394 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/Materials.meta b/Assets/FishNet/Demos/Prediction 2/CharacterController/Materials.meta deleted file mode 100644 index 945b291..0000000 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/Materials.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bdae6fa333d2d94449c27856e21d936a -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/Materials/BlueMat.mat b/Assets/FishNet/Demos/Prediction 2/CharacterController/Materials/BlueMat.mat deleted file mode 100644 index f0d6684..0000000 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/Materials/BlueMat.mat +++ /dev/null @@ -1,77 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!21 &2100000 -Material: - serializedVersion: 6 - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_Name: BlueMat - m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} - m_ShaderKeywords: - m_LightmapFlags: 4 - m_EnableInstancingVariants: 0 - m_DoubleSidedGI: 0 - m_CustomRenderQueue: -1 - stringTagMap: {} - disabledShaderPasses: [] - m_SavedProperties: - serializedVersion: 3 - m_TexEnvs: - - _BumpMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _DetailAlbedoMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _DetailMask: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _DetailNormalMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _EmissionMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _MainTex: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _MetallicGlossMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _OcclusionMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - - _ParallaxMap: - m_Texture: {fileID: 0} - m_Scale: {x: 1, y: 1} - m_Offset: {x: 0, y: 0} - m_Floats: - - _BumpScale: 1 - - _Cutoff: 0.5 - - _DetailNormalMapScale: 1 - - _DstBlend: 0 - - _GlossMapScale: 1 - - _Glossiness: 0.5 - - _GlossyReflections: 1 - - _Metallic: 0 - - _Mode: 0 - - _OcclusionStrength: 1 - - _Parallax: 0.02 - - _SmoothnessTextureChannel: 0 - - _SpecularHighlights: 1 - - _SrcBlend: 1 - - _UVSec: 0 - - _ZWrite: 1 - m_Colors: - - _Color: {r: 0, g: 0.363446, b: 0.5471698, a: 1} - - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/Materials/BlueMat.mat.meta b/Assets/FishNet/Demos/Prediction 2/CharacterController/Materials/BlueMat.mat.meta deleted file mode 100644 index 39a6c0a..0000000 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/Materials/BlueMat.mat.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: a2ca0973c8f8a4846bb7f3894c3bc5cf -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 2100000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/PredictionV2_CC.unity b/Assets/FishNet/Demos/Prediction 2/CharacterController/PredictionV2_CC.unity deleted file mode 100644 index ba2ebbe..0000000 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/PredictionV2_CC.unity +++ /dev/null @@ -1,2001 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!29 &1 -OcclusionCullingSettings: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_OcclusionBakeSettings: - smallestOccluder: 5 - smallestHole: 0.25 - backfaceThreshold: 100 - m_SceneGUID: 00000000000000000000000000000000 - m_OcclusionCullingData: {fileID: 0} ---- !u!104 &2 -RenderSettings: - m_ObjectHideFlags: 0 - serializedVersion: 9 - m_Fog: 0 - m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} - m_FogMode: 3 - m_FogDensity: 0.01 - m_LinearFogStart: 0 - m_LinearFogEnd: 300 - m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} - m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} - m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} - m_AmbientIntensity: 1 - m_AmbientMode: 0 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} - m_HaloStrength: 0.5 - m_FlareStrength: 1 - m_FlareFadeSpeed: 3 - m_HaloTexture: {fileID: 0} - m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} - m_DefaultReflectionMode: 0 - m_DefaultReflectionResolution: 128 - m_ReflectionBounces: 1 - 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: - m_ObjectHideFlags: 0 - serializedVersion: 12 - m_GIWorkflowMode: 1 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - m_EnableRealtimeLightmaps: 0 - m_LightmapEditorSettings: - serializedVersion: 12 - m_Resolution: 2 - m_BakeResolution: 40 - m_AtlasSize: 1024 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAmbientOcclusion: 0 - m_Padding: 2 - m_LightmapParameters: {fileID: 0} - m_LightmapsBakeMode: 1 - m_TextureCompression: 1 - m_FinalGather: 0 - m_FinalGatherFiltering: 1 - m_FinalGatherRayCount: 256 - m_ReflectionCompression: 2 - m_MixedBakeMode: 2 - m_BakeBackend: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 512 - m_PVRBounces: 2 - m_PVREnvironmentSampleCount: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVREnvironmentMIS: 1 - m_PVRCulling: 1 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_LightProbeSampleCountMultiplier: 4 - m_LightingDataAsset: {fileID: 0} - m_LightingSettings: {fileID: 0} ---- !u!196 &4 -NavMeshSettings: - serializedVersion: 2 - m_ObjectHideFlags: 0 - m_BuildSettings: - serializedVersion: 2 - agentTypeID: 0 - agentRadius: 0.5 - agentHeight: 2 - agentSlope: 45 - agentClimb: 0.4 - ledgeDropHeight: 0 - maxJumpAcrossDistance: 0 - minRegionArea: 2 - manualCellSize: 0 - cellSize: 0.16666667 - manualTileSize: 0 - tileSize: 256 - accuratePlacement: 0 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!114 &192429404 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3fdaae44044276a49a52229c1597e33b, type: 3} - m_Name: - m_EditorClassIdentifier: - _updateOrder: 0 - _timingType: 0 - _allowTickDropping: 0 - _maximumFrameTicks: 2 - _tickRate: 20 - _pingInterval: 1 - _physicsMode: 1 ---- !u!114 &192429405 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6f48f002b825cbd45a19bd96d90f9edb, type: 3} - m_Name: - m_EditorClassIdentifier: - _unreliableMTU: 1023 - _ipv4BindAddress: - _ipv6BindAddress: - _port: 7770 - _maximumClients: 5000 - _clientAddress: localhost - _timeout: 15 ---- !u!114 &192429406 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f9b6b565cd9533c4ebc18003f0fc18a2, type: 3} - m_Name: - m_EditorClassIdentifier: - _color: {r: 1, g: 1, b: 1, a: 1} - _placement: 1 - _hideTickRate: 1 ---- !u!114 &192429407 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 34e4a322dca349547989b14021da4e23, type: 3} - m_Name: - m_EditorClassIdentifier: - Transport: {fileID: 192429405} - _intermediateLayer: {fileID: 0} - _latencySimulator: - _enabled: 0 - _simulateHost: 1 - _latency: 70 - _outOfOrder: 0 - _packetLoss: 0 ---- !u!114 &192429408 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 68828c85278210948b9d50a8db3aab74, type: 3} - m_Name: - m_EditorClassIdentifier: - _authenticator: {fileID: 0} - _remoteClientTimeout: 0 - _remoteClientTimeoutDuration: 60 - _syncTypeRate: 0.1 - SpawnPacking: - Position: 0 - Rotation: 2 - Scale: 2 - _changeFrameRate: 1 - _frameRate: 100 - _shareIds: 1 - _startOnHeadless: 1 - _limitClientMTU: 1 ---- !u!114 &192429409 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e08bb003fce297d4086cf8cba5aa459a, type: 3} - m_Name: - m_EditorClassIdentifier: - _queuedInputs: 1 - _dropExcessiveReplicates: 1 - _maximumServerReplicates: 15 - _maximumConsumeCount: 4 - _redundancyCount: 2 - _allowPredictedSpawning: 0 - _reservedObjectIds: 15 ---- !u!114 &192429410 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: aca43cf6f20e77c4f8fcc078fd85081f, type: 3} - m_Name: - m_EditorClassIdentifier: - _remoteServerTimeout: 2 - _remoteServerTimeoutDuration: 60 - _changeFrameRate: 1 - _frameRate: 100 ---- !u!1 &212039606 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 212039607} - - component: {fileID: 212039608} - m_Layer: 0 - m_Name: View - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &212039607 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 212039606} - m_LocalRotation: {x: 0.37959778, y: -0.5981522, z: 0.3830318, w: 0.5927952} - m_LocalPosition: {x: 10.585218, y: 24.346329, z: 20.032343} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 40, y: -90, z: 0} ---- !u!114 &212039608 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 212039606} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} - m_Name: - m_EditorClassIdentifier: - k__BackingField: 0 - _enablePrediction: 0 - _predictionType: 0 - _graphicalObject: {fileID: 0} - _enableStateForwarding: 1 - _ownerInterpolation: 1 - _enableTeleport: 0 - _ownerTeleportThreshold: 1 - _spectatorAdaptiveInterpolation: 1 - _spectatorInterpolation: 1 - k__BackingField: 0 - k__BackingField: {fileID: 0} - _networkBehaviours: [] - k__BackingField: {fileID: 0} - k__BackingField: [] - SerializedTransformProperties: - Position: {x: 10.585218, y: 24.346329, z: 20.032343} - Rotation: {x: 0.37959778, y: -0.5981522, z: 0.3830318, w: 0.5927952} - LocalScale: {x: 1, y: 1, z: 1} - _isNetworked: 1 - _isSpawnable: 1 - _isGlobal: 0 - _initializeOrder: 0 - _defaultDespawnType: 0 - NetworkObserver: {fileID: 0} - k__BackingField: 0 - k__BackingField: 0 - _scenePathHash: 2478811136 - k__BackingField: 10646412763218034985 - k__BackingField: 0 ---- !u!1 &555580081 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 555580085} - - component: {fileID: 555580084} - - component: {fileID: 555580083} - - component: {fileID: 555580082} - m_Layer: 0 - m_Name: Sphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!135 &555580082 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 555580081} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &555580083 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 555580081} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: a2ca0973c8f8a4846bb7f3894c3bc5cf, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &555580084 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 555580081} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &555580085 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 555580081} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -9.16, y: -3.4, z: 13.1} - m_LocalScale: {x: 15, y: 15, z: 15} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &587483120 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 587483126} - - component: {fileID: 587483125} - - component: {fileID: 587483124} - - component: {fileID: 587483123} - - component: {fileID: 587483122} - - component: {fileID: 587483121} - m_Layer: 0 - m_Name: OfflineCapsule - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 ---- !u!54 &587483121 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 1 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 ---- !u!114 &587483122 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b749f90d4c9961c4991179db1130fa4d, type: 3} - m_Name: - m_EditorClassIdentifier: ---- !u!136 &587483123 -CapsuleCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - m_Radius: 0.5 - m_Height: 2 - m_Direction: 1 - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &587483124 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &587483125 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &587483126 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 6.0329375, y: 0.01036527, z: 8.858636} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &872683029 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 872683031} - - component: {fileID: 872683030} - m_Layer: 0 - m_Name: Directional Light - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &872683030 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 872683029} - m_Enabled: 1 - serializedVersion: 10 - m_Type: 1 - m_Shape: 0 - m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} - m_Intensity: 1 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 2 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 1 - m_Bias: 0.05 - m_NormalBias: 0.4 - m_NearPlane: 0.2 - m_CullingMatrixOverride: - e00: 1 - e01: 0 - e02: 0 - e03: 0 - e10: 0 - e11: 1 - e12: 0 - e13: 0 - e20: 0 - e21: 0 - e22: 1 - e23: 0 - e30: 0 - e31: 0 - e32: 0 - e33: 1 - m_UseCullingMatrixOverride: 0 - m_Cookie: {fileID: 0} - m_DrawHalo: 0 - m_Flare: {fileID: 0} - m_RenderMode: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingLayerMask: 1 - m_Lightmapping: 4 - m_LightShadowCasterMode: 0 - m_AreaSize: {x: 1, y: 1} - m_BounceIntensity: 1 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ShadowRadius: 0 - m_ShadowAngle: 0 ---- !u!4 &872683031 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 872683029} - m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} - m_LocalPosition: {x: 0, y: 3, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!1 &967467089 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 967467090} - - component: {fileID: 967467093} - - component: {fileID: 967467092} - - component: {fileID: 967467091} - m_Layer: 0 - m_Name: Wall - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &967467090 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 967467089} - m_LocalRotation: {x: 0, y: 0.82565534, z: 0, w: 0.56417483} - m_LocalPosition: {x: 8.24, y: -0.08, z: 15.86} - m_LocalScale: {x: 1, y: 5, z: 5} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 5 - m_LocalEulerAnglesHint: {x: 0, y: 111.31, z: 0} ---- !u!65 &967467091 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 967467089} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &967467092 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 967467089} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: a2ca0973c8f8a4846bb7f3894c3bc5cf, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &967467093 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 967467089} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &1112005912 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1112005916} - - component: {fileID: 1112005915} - - component: {fileID: 1112005914} - - component: {fileID: 1112005913} - m_Layer: 0 - m_Name: Cube - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!65 &1112005913 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1112005912} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1112005914 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1112005912} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 0bb31cf72dfcef449a1a4a5aab857f63, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1112005915 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1112005912} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &1112005916 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1112005912} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: -2, z: 0} - m_LocalScale: {x: 100, y: 1, z: 100} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1256183191 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1256183192} - - component: {fileID: 1256183195} - - component: {fileID: 1256183194} - m_Layer: 0 - m_Name: Sphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1256183192 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1256183191} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1560902884} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!23 &1256183194 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1256183191} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1256183195 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1256183191} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &1470934487 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1470934491} - - component: {fileID: 1470934490} - - component: {fileID: 1470934489} - - component: {fileID: 1470934488} - m_Layer: 0 - m_Name: Wall - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!65 &1470934488 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1470934487} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1470934489 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1470934487} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: a2ca0973c8f8a4846bb7f3894c3bc5cf, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1470934490 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1470934487} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &1470934491 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1470934487} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 12.11, y: -0.08, z: 0} - m_LocalScale: {x: 1, y: 5, z: 20} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1560902877 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1560902884} - - component: {fileID: 1560902881} - - component: {fileID: 1560902878} - - component: {fileID: 1560902880} - - component: {fileID: 1560902879} - m_Layer: 0 - m_Name: OnlineSphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 ---- !u!54 &1560902878 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 1 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 1 ---- !u!114 &1560902879 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 402926ef33e0a894d9fec352693988ac, type: 3} - m_Name: - m_EditorClassIdentifier: - _componentIndexCache: 0 - _addedNetworkObject: {fileID: 1560902880} - _networkObjectCache: {fileID: 1560902880} ---- !u!114 &1560902880 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} - m_Name: - m_EditorClassIdentifier: - k__BackingField: 0 - _enablePrediction: 0 - _predictionType: 0 - _graphicalObject: {fileID: 0} - _enableStateForwarding: 1 - _ownerInterpolation: 1 - _enableTeleport: 0 - _ownerTeleportThreshold: 1 - _spectatorAdaptiveInterpolation: 1 - _spectatorInterpolation: 1 - k__BackingField: 0 - k__BackingField: {fileID: 0} - _networkBehaviours: - - {fileID: 1560902879} - k__BackingField: {fileID: 0} - k__BackingField: [] - SerializedTransformProperties: - Position: {x: 0, y: 0, z: 0} - Rotation: {x: 0, y: 0, z: 0, w: 0} - LocalScale: {x: 0, y: 0, z: 0} - _isNetworked: 1 - _isSpawnable: 1 - _isGlobal: 0 - _initializeOrder: 0 - _defaultDespawnType: 0 - NetworkObserver: {fileID: 0} - k__BackingField: 65535 - k__BackingField: 0 - _scenePathHash: 2478811136 - k__BackingField: 10646412763343888858 - k__BackingField: 0 ---- !u!135 &1560902881 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - m_Material: {fileID: 13400000, guid: 2315b89c915a21c40982b5867ff7d343, type: 2} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!4 &1560902884 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 1.1, y: 0, z: 5.430528} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1256183192} - m_Father: {fileID: 0} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1726381377 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7d331f979d46e8e4a9fc90070c596d44, type: 3} - m_Name: - m_EditorClassIdentifier: - _enableNetworkLod: 0 - _levelOfDetailDistances: [] - _updateHostVisibility: 1 - _defaultConditions: - - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} ---- !u!1 &1784594014 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1784594015} - m_Layer: 0 - m_Name: Level - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1784594015 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1784594014} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1112005916} - - {fileID: 1470934491} - - {fileID: 555580085} - - {fileID: 1852016427} - - {fileID: 872683031} - - {fileID: 967467090} - - {fileID: 1883869627} - m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1852016424 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1852016427} - - component: {fileID: 1852016426} - - component: {fileID: 1852016425} - m_Layer: 0 - m_Name: Main Camera - m_TagString: MainCamera - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!81 &1852016425 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1852016424} - m_Enabled: 1 ---- !u!20 &1852016426 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1852016424} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 1 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} - m_projectionMatrixMode: 1 - m_GateFitMode: 2 - m_FOVAxisMode: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - m_FocalLength: 50 - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 0.3 - far clip plane: 1000 - field of view: 60 - orthographic: 0 - orthographic size: 5 - m_Depth: -1 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 0} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 1 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!4 &1852016427 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1852016424} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1883869626 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1883869627} - - component: {fileID: 1883869630} - - component: {fileID: 1883869629} - - component: {fileID: 1883869628} - m_Layer: 0 - m_Name: Cube (3) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1883869627 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1883869626} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -48.62, y: -0.08, z: 0} - m_LocalScale: {x: 1, y: 5, z: 20} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 6 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!65 &1883869628 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1883869626} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 1, y: 1, z: 1} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1883869629 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1883869626} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 6273444b68d517449aadb36abebaf561, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1883869630 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1883869626} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!114 &1424052073902602981 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2480283714093027852} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 2b3dca501a9d8c8479dc71dd068aa8b8, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!1 &2480283714093027852 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 9139860295689780510} - - component: {fileID: 6745855428745291286} - - component: {fileID: 1424052073902602981} - m_Layer: 5 - m_Name: Indicator - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &3965864432699664111 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4808982256744730386} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 2b3dca501a9d8c8479dc71dd068aa8b8, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!114 &4393252310837120370 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252310837120383} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 2d50394614f8feb4eb0567fb7618d84d, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &4393252310837120371 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252310837120383} - m_CullTransparentMesh: 0 ---- !u!224 &4393252310837120380 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252310837120383} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 9139860295689780510} - m_Father: {fileID: 4393252311378272345} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 16, y: -96} - m_SizeDelta: {x: 256, y: 64} - m_Pivot: {x: 0, y: 1} ---- !u!114 &4393252310837120381 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252310837120383} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 4393252310837120370} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 4393252311378272325} - m_TargetAssemblyTypeName: - m_MethodName: OnClick_Client - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 ---- !u!1 &4393252310837120383 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4393252310837120380} - - component: {fileID: 4393252310837120371} - - component: {fileID: 4393252310837120370} - - component: {fileID: 4393252310837120381} - m_Layer: 5 - m_Name: Client - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &4393252311222810866 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311222810879} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 1b187e63031bf7849b249c8212440c3b, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &4393252311222810867 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311222810879} - m_CullTransparentMesh: 0 ---- !u!224 &4393252311222810876 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311222810879} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 7233259200132978428} - m_Father: {fileID: 4393252311378272345} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 16, y: -16} - m_SizeDelta: {x: 256, y: 64} - m_Pivot: {x: 0, y: 1} ---- !u!114 &4393252311222810877 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311222810879} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 4393252311222810866} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 4393252311378272325} - m_TargetAssemblyTypeName: - m_MethodName: OnClick_Server - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 ---- !u!1 &4393252311222810879 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4393252311222810876} - - component: {fileID: 4393252311222810867} - - component: {fileID: 4393252311222810866} - - component: {fileID: 4393252311222810877} - m_Layer: 5 - m_Name: Server - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!1 &4393252311378272324 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4393252311378272345} - - component: {fileID: 4393252311378272325} - - component: {fileID: 4393252311378272344} - - component: {fileID: 4393252311378272347} - - component: {fileID: 4393252311378272346} - m_Layer: 5 - m_Name: NetworkHudCanvas - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &4393252311378272325 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} - m_Name: - m_EditorClassIdentifier: - _autoStartType: 2 - _stoppedColor: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} - _changingColor: {r: 0.78431374, g: 0.6862745, b: 0, a: 1} - _startedColor: {r: 0, g: 0.5882353, b: 0.64705884, a: 1} - _serverIndicator: {fileID: 3965864432699664111} - _clientIndicator: {fileID: 1424052073902602981} ---- !u!223 &4393252311378272344 -Canvas: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_Enabled: 1 - serializedVersion: 3 - m_RenderMode: 0 - m_Camera: {fileID: 0} - m_PlaneDistance: 100 - m_PixelPerfect: 0 - m_ReceivesEvents: 1 - m_OverrideSorting: 0 - m_OverridePixelPerfect: 0 - m_SortingBucketNormalizedSize: 0 - m_AdditionalShaderChannelsFlag: 0 - m_SortingLayerID: 0 - m_SortingOrder: 0 - m_TargetDisplay: 0 ---- !u!224 &4393252311378272345 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0, y: 0, z: 0} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 4393252311222810876} - - {fileID: 4393252310837120380} - m_Father: {fileID: 7443408886491487332} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0, y: 0} ---- !u!114 &4393252311378272346 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} - m_Name: - m_EditorClassIdentifier: - m_IgnoreReversedGraphics: 1 - m_BlockingObjects: 0 - m_BlockingMask: - serializedVersion: 2 - m_Bits: 4294967295 ---- !u!114 &4393252311378272347 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UiScaleMode: 1 - m_ReferencePixelsPerUnit: 100 - m_ScaleFactor: 1 - m_ReferenceResolution: {x: 1920, y: 1080} - m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 - m_PhysicalUnit: 3 - m_FallbackScreenDPI: 96 - m_DefaultSpriteDPI: 96 - m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 0 ---- !u!1 &4808982256744730386 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 7233259200132978428} - - component: {fileID: 5104387649508117141} - - component: {fileID: 3965864432699664111} - m_Layer: 5 - m_Name: Indicator - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!222 &5104387649508117141 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4808982256744730386} - m_CullTransparentMesh: 0 ---- !u!222 &6745855428745291286 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2480283714093027852} - m_CullTransparentMesh: 0 ---- !u!224 &7233259200132978428 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4808982256744730386} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -1} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 4393252311222810876} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!4 &7443408886491487332 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 4393252311378272345} - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &7443408886491487334 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 7443408886491487332} - - component: {fileID: 7443408886491487335} - - component: {fileID: 1726381377} - - component: {fileID: 7443408886491487337} - - component: {fileID: 192429409} - - component: {fileID: 192429404} - - component: {fileID: 192429405} - - component: {fileID: 192429406} - - component: {fileID: 192429407} - - component: {fileID: 192429408} - - component: {fileID: 192429410} - m_Layer: 0 - m_Name: NetworkManager - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &7443408886491487335 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d2c95dfde7d73b54dbbdc23155d35d36, type: 3} - m_Name: - m_EditorClassIdentifier: - _refreshDefaultPrefabs: 1 - _runInBackground: 1 - _dontDestroyOnLoad: 1 - _objectPool: {fileID: 0} - _persistence: 0 - _logging: {fileID: 0} - _spawnablePrefabs: {fileID: 11400000, guid: 3a54436bdb916194f99da0d17231e617, type: 2} ---- !u!114 &7443408886491487337 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 211a9f6ec51ddc14f908f5acc0cd0423, type: 3} - m_Name: - m_EditorClassIdentifier: - _playerPrefab: {fileID: 201277550, guid: 5b712878ecece354ba4ffb026c0a221c, type: 3} - _addToDefaultScene: 1 - Spawns: [] ---- !u!224 &9139860295689780510 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2480283714093027852} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -1} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 4393252310837120380} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs.meta b/Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs.meta deleted file mode 100644 index e0abc32..0000000 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 50d54accc2af0c746b0729b097981b93 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs/CharacterControllerPrediction.prefab b/Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs/CharacterControllerPrediction.prefab deleted file mode 100644 index 6a5bb9b..0000000 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs/CharacterControllerPrediction.prefab +++ /dev/null @@ -1,202 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &303449598114786579 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 303449598114786577} - - component: {fileID: -2060332294883903109} - - component: {fileID: 201277550} - - component: {fileID: 4148834954576211901} - m_Layer: 0 - m_Name: CharacterControllerPrediction - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &303449598114786577 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598114786579} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -4.80351, y: 0.18147132, z: 5.430528} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 6952090537135875148} - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &-2060332294883903109 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598114786579} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 53a6d84aa5d214e48a7308646e5d20da, type: 3} - m_Name: - m_EditorClassIdentifier: - _componentIndexCache: 0 - _addedNetworkObject: {fileID: 201277550} - _networkObjectCache: {fileID: 201277550} ---- !u!114 &201277550 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598114786579} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} - m_Name: - m_EditorClassIdentifier: - k__BackingField: 0 - k__BackingField: 0 - k__BackingField: {fileID: 0} - _networkBehaviours: - - {fileID: -2060332294883903109} - k__BackingField: {fileID: 0} - k__BackingField: [] - SerializedTransformProperties: - Position: {x: -4.80351, y: 0.18147132, z: 5.430528} - Rotation: {x: 0, y: 0, z: 0, w: 1} - LocalScale: {x: 1, y: 1, z: 1} - _isNetworked: 1 - _isSpawnable: 1 - _isGlobal: 0 - _initializeOrder: 0 - _defaultDespawnType: 0 - NetworkObserver: {fileID: 0} - k__BackingField: 3 - k__BackingField: 0 - _scenePathHash: 0 - k__BackingField: 0 - k__BackingField: 15176741689908595000 ---- !u!143 &4148834954576211901 -CharacterController: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598114786579} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Height: 2 - m_Radius: 0.5 - m_SlopeLimit: 45 - m_StepOffset: 0.3 - m_SkinWidth: 0.08 - m_MinMoveDistance: 0.001 - m_Center: {x: 0, y: 0, z: 0} ---- !u!1 &5873068582516782542 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 6952090537135875148} - - component: {fileID: 6605329024375725182} - - component: {fileID: 9006911641345807741} - - component: {fileID: 4946798872430241371} - m_Layer: 0 - m_Name: Capsule - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &6952090537135875148 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5873068582516782542} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0.01, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 303449598114786577} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &6605329024375725182 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5873068582516782542} - m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &9006911641345807741 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5873068582516782542} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!136 &4946798872430241371 -CapsuleCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5873068582516782542} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - m_Radius: 0.5 - m_Height: 2 - m_Direction: 1 - m_Center: {x: 0, y: 0, z: 0} diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts.meta b/Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts.meta deleted file mode 100644 index 6ddee3b..0000000 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: eaf414b899169f04bb4b0d65424a40bf -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts/CharacterControllerPredictionV2.cs b/Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts/CharacterControllerPredictionV2.cs deleted file mode 100644 index 5677cc0..0000000 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts/CharacterControllerPredictionV2.cs +++ /dev/null @@ -1,152 +0,0 @@ -using FishNet; -using FishNet.Object; -using FishNet.Object.Prediction; -using FishNet.Transporting; -using System.Collections.Generic; -using UnityEngine; -using static FishNet.PredictionV2.CharacterControllerPredictionV2; - -namespace FishNet.PredictionV2 -{ - - public class CharacterControllerPredictionV2 : NetworkBehaviour - { -#if !PREDICTION_1 - - - public struct MoveData : IReplicateData - { - public uint SentTick; - public bool Jump; - public float Horizontal; - public float Vertical; - public MoveData(bool jump, float horizontal, float vertical, uint sentTick) - { - Jump = jump; - Horizontal = horizontal; - Vertical = vertical; - SentTick = sentTick; - _tick = 0; - } - - private uint _tick; - public void Dispose() { } - public uint GetTick() => _tick; - public void SetTick(uint value) => _tick = value; - } - - public struct ReconcileData : IReconcileData - { - public Vector3 Position; - public float VerticalVelocity; - public ReconcileData(Vector3 position, float verticalVelocity) - { - Position = position; - VerticalVelocity = verticalVelocity; - _tick = 0; - } - - private uint _tick; - public void Dispose() { } - public uint GetTick() => _tick; - public void SetTick(uint value) => _tick = value; - } - - [SerializeField] - private float _jumpForce = 15f; - [SerializeField] - private float _moveRate = 4f; - - private CharacterController _characterController; - private bool _jump; - private float _verticalVelocity; - - private void Update() - { - if (base.IsOwner) - { - if (Input.GetKeyDown(KeyCode.Space)) - _jump = true; - } - } - - public override void OnStartNetwork() - { - _characterController = GetComponent(); - base.TimeManager.OnTick += TimeManager_OnTick; - } - - public override void OnStopNetwork() - { - base.TimeManager.OnTick -= TimeManager_OnTick; - } - - - private void TimeManager_OnTick() - { - Move(BuildMoveData()); - /* The base.IsServer check is not required but does save a little - * performance by not building the reconcileData if not server. */ - CreateReconcile(); - } - - public override void CreateReconcile() - { - if (base.IsServerStarted) - { - ReconcileData rd = new ReconcileData(transform.position, _verticalVelocity); - Reconciliation(rd); - } - } - private MoveData BuildMoveData() - { - if (!base.IsOwner) - return default; - - float horizontal = Input.GetAxisRaw("Horizontal"); - float vertical = Input.GetAxisRaw("Vertical"); - - MoveData md; - if (horizontal != 0 || vertical != 0) - md = new MoveData(_jump, horizontal, vertical, base.TimeManager.LocalTick); - else - md = new MoveData(_jump, horizontal, vertical, 0); - _jump = false; - - return md; - } - - - [Replicate] - private void Move(MoveData md, ReplicateState state = ReplicateState.Invalid, Channel channel = Channel.Unreliable) - { - if (state == ReplicateState.CurrentFuture) - return; - - if (md.Jump) - _verticalVelocity = _jumpForce; - - float delta = (float)base.TimeManager.TickDelta; - _verticalVelocity += (Physics.gravity.y * delta); - if (_verticalVelocity < -20f) - _verticalVelocity = -20f; - - - Vector3 forces = new Vector3(md.Horizontal, _verticalVelocity, md.Vertical) * _moveRate; - _characterController.Move(forces * delta); - - - } - - [Reconcile] - private void Reconciliation(ReconcileData rd, Channel channel = Channel.Unreliable) - { - transform.position = rd.Position; - _verticalVelocity = rd.VerticalVelocity; - - } - -#endif - } - -} \ No newline at end of file diff --git a/Assets/FishNet/Demos/Prediction 2/README Prediction V Examples.txt b/Assets/FishNet/Demos/Prediction 2/README Prediction V Examples.txt deleted file mode 100644 index a2dbccd..0000000 --- a/Assets/FishNet/Demos/Prediction 2/README Prediction V Examples.txt +++ /dev/null @@ -1,5 +0,0 @@ -Prediction V2 is a work in progress and so are the examples. - -The Rigidbody example may not smooth properly. - -The CharacterController example is expected to work. \ No newline at end of file diff --git a/Assets/FishNet/Demos/Prediction 2/README Prediction V Examples.txt.meta b/Assets/FishNet/Demos/Prediction 2/README Prediction V Examples.txt.meta deleted file mode 100644 index 6fdc8cc..0000000 --- a/Assets/FishNet/Demos/Prediction 2/README Prediction V Examples.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 43f99d5241a617843a16537c3229c093 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/Rigidbody.meta b/Assets/FishNet/Demos/Prediction 2/Rigidbody.meta deleted file mode 100644 index 9a1671a..0000000 --- a/Assets/FishNet/Demos/Prediction 2/Rigidbody.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1603123a7ba837c4892564f087decd80 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/Rigidbody/PredictionV2_RB.unity b/Assets/FishNet/Demos/Prediction 2/Rigidbody/PredictionV2_RB.unity deleted file mode 100644 index 9500251..0000000 --- a/Assets/FishNet/Demos/Prediction 2/Rigidbody/PredictionV2_RB.unity +++ /dev/null @@ -1,2063 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!29 &1 -OcclusionCullingSettings: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_OcclusionBakeSettings: - smallestOccluder: 5 - smallestHole: 0.25 - backfaceThreshold: 100 - m_SceneGUID: 00000000000000000000000000000000 - m_OcclusionCullingData: {fileID: 0} ---- !u!104 &2 -RenderSettings: - m_ObjectHideFlags: 0 - serializedVersion: 9 - m_Fog: 0 - m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} - m_FogMode: 3 - m_FogDensity: 0.01 - m_LinearFogStart: 0 - m_LinearFogEnd: 300 - m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} - m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} - m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} - m_AmbientIntensity: 1 - m_AmbientMode: 0 - m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} - m_HaloStrength: 0.5 - m_FlareStrength: 1 - m_FlareFadeSpeed: 3 - m_HaloTexture: {fileID: 0} - m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} - m_DefaultReflectionMode: 0 - m_DefaultReflectionResolution: 128 - m_ReflectionBounces: 1 - 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: - m_ObjectHideFlags: 0 - serializedVersion: 12 - m_GIWorkflowMode: 1 - m_GISettings: - serializedVersion: 2 - m_BounceScale: 1 - m_IndirectOutputScale: 1 - m_AlbedoBoost: 1 - m_EnvironmentLightingMode: 0 - m_EnableBakedLightmaps: 1 - m_EnableRealtimeLightmaps: 0 - m_LightmapEditorSettings: - serializedVersion: 12 - m_Resolution: 2 - m_BakeResolution: 40 - m_AtlasSize: 1024 - m_AO: 0 - m_AOMaxDistance: 1 - m_CompAOExponent: 1 - m_CompAOExponentDirect: 0 - m_ExtractAmbientOcclusion: 0 - m_Padding: 2 - m_LightmapParameters: {fileID: 0} - m_LightmapsBakeMode: 1 - m_TextureCompression: 1 - m_FinalGather: 0 - m_FinalGatherFiltering: 1 - m_FinalGatherRayCount: 256 - m_ReflectionCompression: 2 - m_MixedBakeMode: 2 - m_BakeBackend: 1 - m_PVRSampling: 1 - m_PVRDirectSampleCount: 32 - m_PVRSampleCount: 512 - m_PVRBounces: 2 - m_PVREnvironmentSampleCount: 256 - m_PVREnvironmentReferencePointCount: 2048 - m_PVRFilteringMode: 1 - m_PVRDenoiserTypeDirect: 1 - m_PVRDenoiserTypeIndirect: 1 - m_PVRDenoiserTypeAO: 1 - m_PVRFilterTypeDirect: 0 - m_PVRFilterTypeIndirect: 0 - m_PVRFilterTypeAO: 0 - m_PVREnvironmentMIS: 1 - m_PVRCulling: 1 - m_PVRFilteringGaussRadiusDirect: 1 - m_PVRFilteringGaussRadiusIndirect: 5 - m_PVRFilteringGaussRadiusAO: 2 - m_PVRFilteringAtrousPositionSigmaDirect: 0.5 - m_PVRFilteringAtrousPositionSigmaIndirect: 2 - m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ExportTrainingData: 0 - m_TrainingDataDestination: TrainingData - m_LightProbeSampleCountMultiplier: 4 - m_LightingDataAsset: {fileID: 0} - m_LightingSettings: {fileID: 0} ---- !u!196 &4 -NavMeshSettings: - serializedVersion: 2 - m_ObjectHideFlags: 0 - m_BuildSettings: - serializedVersion: 2 - agentTypeID: 0 - agentRadius: 0.5 - agentHeight: 2 - agentSlope: 45 - agentClimb: 0.4 - ledgeDropHeight: 0 - maxJumpAcrossDistance: 0 - minRegionArea: 2 - manualCellSize: 0 - cellSize: 0.16666667 - manualTileSize: 0 - tileSize: 256 - accuratePlacement: 0 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 - debug: - m_Flags: 0 - m_NavMeshData: {fileID: 0} ---- !u!114 &192429404 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 3fdaae44044276a49a52229c1597e33b, type: 3} - m_Name: - m_EditorClassIdentifier: - _updateOrder: 0 - _timingType: 0 - _allowTickDropping: 0 - _maximumFrameTicks: 2 - _tickRate: 10 - _pingInterval: 1 - _physicsMode: 1 ---- !u!114 &192429405 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6f48f002b825cbd45a19bd96d90f9edb, type: 3} - m_Name: - m_EditorClassIdentifier: - _dontRoute: 0 - _unreliableMtu: 1023 - _ipv4BindAddress: - _enableIpv6: 1 - _ipv6BindAddress: - _port: 7770 - _maximumClients: 5000 - _clientAddress: localhost ---- !u!114 &192429406 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f9b6b565cd9533c4ebc18003f0fc18a2, type: 3} - m_Name: - m_EditorClassIdentifier: - _color: {r: 1, g: 1, b: 1, a: 1} - _placement: 1 - _hideTickRate: 1 ---- !u!114 &192429407 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 34e4a322dca349547989b14021da4e23, type: 3} - m_Name: - m_EditorClassIdentifier: - Transport: {fileID: 192429405} - _intermediateLayer: {fileID: 0} - _latencySimulator: - _enabled: 0 - _simulateHost: 1 - _latency: 5 - _outOfOrder: 0 - _packetLoss: 0 ---- !u!114 &192429408 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - 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 - _syncTypeRate: 0.1 - SpawnPacking: - Position: 0 - Rotation: 2 - Scale: 2 - _changeFrameRate: 1 - _frameRate: 100 - _shareIds: 1 - _startOnHeadless: 1 ---- !u!114 &192429409 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: e08bb003fce297d4086cf8cba5aa459a, type: 3} - m_Name: - m_EditorClassIdentifier: - _queuedInputs: 0 - _dropExcessiveReplicates: 1 - _maximumServerReplicates: 15 - _redundancyCount: 2 - _allowPredictedSpawning: 0 - _reservedObjectIds: 15 ---- !u!114 &192429410 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: aca43cf6f20e77c4f8fcc078fd85081f, type: 3} - m_Name: - m_EditorClassIdentifier: - _remoteServerTimeout: 2 - _remoteServerTimeoutDuration: 60 - _changeFrameRate: 1 - _frameRate: 100 ---- !u!1 &212039606 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 212039607} - - component: {fileID: 212039608} - m_Layer: 0 - m_Name: View - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &212039607 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 212039606} - m_LocalRotation: {x: 0.37959778, y: -0.5981522, z: 0.3830318, w: 0.5927952} - m_LocalPosition: {x: 10.585218, y: 24.346329, z: 20.032343} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 40, y: -90, z: 0} ---- !u!114 &212039608 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 212039606} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} - m_Name: - m_EditorClassIdentifier: - k__BackingField: 0 - k__BackingField: 0 - k__BackingField: {fileID: 0} - _networkBehaviours: [] - k__BackingField: {fileID: 0} - k__BackingField: [] - SerializedTransformProperties: - Position: {x: 10.585218, y: 24.346329, z: 20.032343} - Rotation: {x: 0.37959778, y: -0.5981522, z: 0.3830318, w: 0.5927952} - LocalScale: {x: 1, y: 1, z: 1} - _isNetworked: 1 - _isSpawnable: 0 - _isGlobal: 0 - _initializeOrder: 0 - _defaultDespawnType: 0 - NetworkObserver: {fileID: 0} - _enablePrediction: 0 - _predictionType: 0 - _graphicalObject: {fileID: 0} - _enableStateForwarding: 1 - _ownerInterpolation: 1 - _enableTeleport: 0 - _teleportThreshold: 1 - k__BackingField: 0 - k__BackingField: 0 - _scenePathHash: 1828152806 - k__BackingField: 7851856517478923898 - k__BackingField: 0 ---- !u!1 &555580081 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 555580085} - - component: {fileID: 555580084} - - component: {fileID: 555580083} - - component: {fileID: 555580082} - m_Layer: 0 - m_Name: Sphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!135 &555580082 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 555580081} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &555580083 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 555580081} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 6273444b68d517449aadb36abebaf561, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &555580084 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 555580081} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &555580085 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 555580081} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -9.16, y: -3.4, z: 26.49} - m_LocalScale: {x: 15, y: 15, z: 15} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &587483120 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 587483126} - - component: {fileID: 587483125} - - component: {fileID: 587483124} - - component: {fileID: 587483123} - - component: {fileID: 587483122} - - component: {fileID: 587483121} - m_Layer: 0 - m_Name: OfflineCapsule - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 ---- !u!54 &587483121 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 1 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 ---- !u!114 &587483122 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: b749f90d4c9961c4991179db1130fa4d, type: 3} - m_Name: - m_EditorClassIdentifier: - _rigidbodyType: 0 - _getInChildren: 0 ---- !u!136 &587483123 -CapsuleCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - m_Radius: 0.5 - m_Height: 2 - m_Direction: 1 - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &587483124 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &587483125 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &587483126 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 587483120} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 6.0329375, y: 0.01036527, z: 8.858636} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &872683029 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 872683031} - - component: {fileID: 872683030} - m_Layer: 0 - m_Name: Directional Light - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!108 &872683030 -Light: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 872683029} - m_Enabled: 1 - serializedVersion: 10 - m_Type: 1 - m_Shape: 0 - m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} - m_Intensity: 1 - m_Range: 10 - m_SpotAngle: 30 - m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 - m_Shadows: - m_Type: 2 - m_Resolution: -1 - m_CustomResolution: -1 - m_Strength: 1 - m_Bias: 0.05 - m_NormalBias: 0.4 - m_NearPlane: 0.2 - m_CullingMatrixOverride: - e00: 1 - e01: 0 - e02: 0 - e03: 0 - e10: 0 - e11: 1 - e12: 0 - e13: 0 - e20: 0 - e21: 0 - e22: 1 - e23: 0 - e30: 0 - e31: 0 - e32: 0 - e33: 1 - m_UseCullingMatrixOverride: 0 - m_Cookie: {fileID: 0} - m_DrawHalo: 0 - m_Flare: {fileID: 0} - m_RenderMode: 0 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingLayerMask: 1 - m_Lightmapping: 4 - m_LightShadowCasterMode: 0 - m_AreaSize: {x: 1, y: 1} - m_BounceIntensity: 1 - m_ColorTemperature: 6570 - m_UseColorTemperature: 0 - m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} - m_UseBoundingSphereOverride: 0 - m_UseViewFrustumForShadowCasterCull: 1 - m_ShadowRadius: 0 - m_ShadowAngle: 0 ---- !u!4 &872683031 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 872683029} - m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} - m_LocalPosition: {x: 0, y: 3, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 4 - m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} ---- !u!1 &967467089 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 967467090} - - component: {fileID: 967467093} - - component: {fileID: 967467092} - - component: {fileID: 967467091} - m_Layer: 0 - m_Name: Wall - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &967467090 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 967467089} - m_LocalRotation: {x: 0, y: 0.82565534, z: 0, w: 0.56417483} - m_LocalPosition: {x: 8.24, y: -0.08, z: 15.86} - m_LocalScale: {x: 1, y: 5, z: 5} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 5 - m_LocalEulerAnglesHint: {x: 0, y: 111.31, z: 0} ---- !u!65 &967467091 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 967467089} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 2, y: 2, z: 2} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &967467092 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 967467089} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 6273444b68d517449aadb36abebaf561, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &967467093 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 967467089} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &1112005912 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1112005916} - - component: {fileID: 1112005915} - - component: {fileID: 1112005914} - - component: {fileID: 1112005913} - m_Layer: 0 - m_Name: Cube - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!65 &1112005913 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1112005912} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 2, y: 1, z: 2} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1112005914 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1112005912} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 0bb31cf72dfcef449a1a4a5aab857f63, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1112005915 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1112005912} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &1112005916 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1112005912} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: -2, z: 0} - m_LocalScale: {x: 100, y: 1, z: 100} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1256183191 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1256183192} - - component: {fileID: 1256183195} - - component: {fileID: 1256183194} - m_Layer: 0 - m_Name: Sphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1256183192 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1256183191} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1560902884} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!23 &1256183194 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1256183191} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1256183195 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1256183191} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!1 &1470934487 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1470934491} - - component: {fileID: 1470934490} - - component: {fileID: 1470934489} - - component: {fileID: 1470934488} - m_Layer: 0 - m_Name: Wall - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!65 &1470934488 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1470934487} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 2, y: 2, z: 2} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1470934489 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1470934487} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 6273444b68d517449aadb36abebaf561, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1470934490 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1470934487} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &1470934491 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1470934487} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 12.11, y: -0.08, z: 0} - m_LocalScale: {x: 1, y: 5, z: 20} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1560902877 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1560902884} - - component: {fileID: 1560902881} - - component: {fileID: 1560902878} - - component: {fileID: 1560902880} - - component: {fileID: 1560902879} - m_Layer: 0 - m_Name: OnlineSphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 0 ---- !u!54 &1560902878 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 1 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 1 ---- !u!114 &1560902879 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 402926ef33e0a894d9fec352693988ac, type: 3} - m_Name: - m_EditorClassIdentifier: - _componentIndexCache: 0 - _addedNetworkObject: {fileID: 1560902880} - _networkObjectCache: {fileID: 1560902880} ---- !u!114 &1560902880 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} - m_Name: - m_EditorClassIdentifier: - k__BackingField: 0 - k__BackingField: 0 - k__BackingField: {fileID: 0} - _networkBehaviours: - - {fileID: 1560902879} - k__BackingField: {fileID: 0} - k__BackingField: [] - SerializedTransformProperties: - Position: {x: 0, y: 0, z: 0} - Rotation: {x: 0, y: 0, z: 0, w: 0} - LocalScale: {x: 0, y: 0, z: 0} - _isNetworked: 1 - _isSpawnable: 0 - _isGlobal: 0 - _initializeOrder: 0 - _defaultDespawnType: 0 - NetworkObserver: {fileID: 0} - _enablePrediction: 0 - _predictionType: 0 - _graphicalObject: {fileID: 0} - _enableStateForwarding: 1 - _ownerInterpolation: 1 - _enableTeleport: 0 - _teleportThreshold: 1 - k__BackingField: 65535 - k__BackingField: 0 - _scenePathHash: 1828152806 - k__BackingField: 7851856515000995197 - k__BackingField: 0 ---- !u!135 &1560902881 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - m_Material: {fileID: 13400000, guid: 2315b89c915a21c40982b5867ff7d343, type: 2} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!4 &1560902884 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1560902877} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 1.1, y: 0, z: 5.430528} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1256183192} - m_Father: {fileID: 0} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1726381377 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 7d331f979d46e8e4a9fc90070c596d44, type: 3} - m_Name: - m_EditorClassIdentifier: - _enableNetworkLod: 0 - _levelOfDetailDistances: [] - _updateHostVisibility: 1 - _defaultConditions: - - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} ---- !u!1 &1784594014 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1784594015} - m_Layer: 0 - m_Name: Level - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1784594015 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1784594014} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 1112005916} - - {fileID: 1470934491} - - {fileID: 555580085} - - {fileID: 1852016427} - - {fileID: 872683031} - - {fileID: 967467090} - - {fileID: 1883869627} - m_Father: {fileID: 0} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1852016424 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1852016427} - - component: {fileID: 1852016426} - - component: {fileID: 1852016425} - m_Layer: 0 - m_Name: Main Camera - m_TagString: MainCamera - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!81 &1852016425 -AudioListener: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1852016424} - m_Enabled: 1 ---- !u!20 &1852016426 -Camera: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1852016424} - m_Enabled: 1 - serializedVersion: 2 - m_ClearFlags: 1 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} - m_projectionMatrixMode: 1 - m_GateFitMode: 2 - m_FOVAxisMode: 0 - m_SensorSize: {x: 36, y: 24} - m_LensShift: {x: 0, y: 0} - m_FocalLength: 50 - m_NormalizedViewPortRect: - serializedVersion: 2 - x: 0 - y: 0 - width: 1 - height: 1 - near clip plane: 0.3 - far clip plane: 1000 - field of view: 60 - orthographic: 0 - orthographic size: 5 - m_Depth: -1 - m_CullingMask: - serializedVersion: 2 - m_Bits: 4294967295 - m_RenderingPath: -1 - m_TargetTexture: {fileID: 0} - m_TargetDisplay: 0 - m_TargetEye: 3 - m_HDR: 1 - m_AllowMSAA: 1 - m_AllowDynamicResolution: 0 - m_ForceIntoRT: 0 - m_OcclusionCulling: 1 - m_StereoConvergence: 10 - m_StereoSeparation: 0.022 ---- !u!4 &1852016427 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1852016424} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &1883869626 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1883869627} - - component: {fileID: 1883869630} - - component: {fileID: 1883869629} - - component: {fileID: 1883869628} - m_Layer: 0 - m_Name: Cube (3) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &1883869627 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1883869626} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: -48.62, y: -0.08, z: 0} - m_LocalScale: {x: 1, y: 5, z: 20} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 1784594015} - m_RootOrder: 6 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!65 &1883869628 -BoxCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1883869626} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Size: {x: 2, y: 2, z: 2} - m_Center: {x: 0, y: 0, z: 0} ---- !u!23 &1883869629 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1883869626} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: 6273444b68d517449aadb36abebaf561, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!33 &1883869630 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1883869626} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!114 &1424052073902602981 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2480283714093027852} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 2b3dca501a9d8c8479dc71dd068aa8b8, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!1001 &1712874950459209376 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 0} - m_Modifications: - - target: {fileID: 1712874951232431508, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_Name - value: Sphere_A - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_RootOrder - value: 5 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalPosition.x - value: 10.983304 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalPosition.y - value: -0.99999994 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalPosition.z - value: 11.61 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalRotation.w - value: -0.40963268 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalRotation.z - value: 0.9122505 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 1712874951232431512, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9108174227488385262, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: _scenePathHash - value: 1828152806 - objectReference: {fileID: 0} - - target: {fileID: 9108174227488385262, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} - propertyPath: k__BackingField - value: 7851856514066328649 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: bcf416aedafd2ea4d9ed2cd8469dbf56, type: 3} ---- !u!1 &2480283714093027852 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 9139860295689780510} - - component: {fileID: 6745855428745291286} - - component: {fileID: 1424052073902602981} - m_Layer: 5 - m_Name: Indicator - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &3965864432699664111 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4808982256744730386} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 2b3dca501a9d8c8479dc71dd068aa8b8, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!114 &4393252310837120370 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252310837120383} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 2d50394614f8feb4eb0567fb7618d84d, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &4393252310837120371 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252310837120383} - m_CullTransparentMesh: 0 ---- !u!224 &4393252310837120380 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252310837120383} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 9139860295689780510} - m_Father: {fileID: 4393252311378272345} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 16, y: -96} - m_SizeDelta: {x: 256, y: 64} - m_Pivot: {x: 0, y: 1} ---- !u!114 &4393252310837120381 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252310837120383} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 4393252310837120370} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 4393252311378272325} - m_TargetAssemblyTypeName: - m_MethodName: OnClick_Client - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 ---- !u!1 &4393252310837120383 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4393252310837120380} - - component: {fileID: 4393252310837120371} - - component: {fileID: 4393252310837120370} - - component: {fileID: 4393252310837120381} - m_Layer: 5 - m_Name: Client - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &4393252311222810866 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311222810879} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 21300000, guid: 1b187e63031bf7849b249c8212440c3b, type: 3} - m_Type: 0 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!222 &4393252311222810867 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311222810879} - m_CullTransparentMesh: 0 ---- !u!224 &4393252311222810876 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311222810879} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 7233259200132978428} - m_Father: {fileID: 4393252311378272345} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 1} - m_AnchorMax: {x: 0, y: 1} - m_AnchoredPosition: {x: 16, y: -16} - m_SizeDelta: {x: 256, y: 64} - m_Pivot: {x: 0, y: 1} ---- !u!114 &4393252311222810877 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311222810879} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 4393252311222810866} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 4393252311378272325} - m_TargetAssemblyTypeName: - m_MethodName: OnClick_Server - m_Mode: 1 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: - m_BoolArgument: 0 - m_CallState: 2 ---- !u!1 &4393252311222810879 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4393252311222810876} - - component: {fileID: 4393252311222810867} - - component: {fileID: 4393252311222810866} - - component: {fileID: 4393252311222810877} - m_Layer: 5 - m_Name: Server - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!1 &4393252311378272324 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4393252311378272345} - - component: {fileID: 4393252311378272325} - - component: {fileID: 4393252311378272344} - - component: {fileID: 4393252311378272347} - - component: {fileID: 4393252311378272346} - m_Layer: 5 - m_Name: NetworkHudCanvas - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &4393252311378272325 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} - m_Name: - m_EditorClassIdentifier: - _autoStartType: 1 - _stoppedColor: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} - _changingColor: {r: 0.78431374, g: 0.6862745, b: 0, a: 1} - _startedColor: {r: 0, g: 0.5882353, b: 0.64705884, a: 1} - _serverIndicator: {fileID: 3965864432699664111} - _clientIndicator: {fileID: 1424052073902602981} ---- !u!223 &4393252311378272344 -Canvas: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_Enabled: 1 - serializedVersion: 3 - m_RenderMode: 0 - m_Camera: {fileID: 0} - m_PlaneDistance: 100 - m_PixelPerfect: 0 - m_ReceivesEvents: 1 - m_OverrideSorting: 0 - m_OverridePixelPerfect: 0 - m_SortingBucketNormalizedSize: 0 - m_AdditionalShaderChannelsFlag: 0 - m_SortingLayerID: 0 - m_SortingOrder: 0 - m_TargetDisplay: 0 ---- !u!224 &4393252311378272345 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0, y: 0, z: 0} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 4393252311222810876} - - {fileID: 4393252310837120380} - m_Father: {fileID: 7443408886491487332} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0, y: 0} ---- !u!114 &4393252311378272346 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} - m_Name: - m_EditorClassIdentifier: - m_IgnoreReversedGraphics: 1 - m_BlockingObjects: 0 - m_BlockingMask: - serializedVersion: 2 - m_Bits: 4294967295 ---- !u!114 &4393252311378272347 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4393252311378272324} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} - m_Name: - m_EditorClassIdentifier: - m_UiScaleMode: 1 - m_ReferencePixelsPerUnit: 100 - m_ScaleFactor: 1 - m_ReferenceResolution: {x: 1920, y: 1080} - m_ScreenMatchMode: 0 - m_MatchWidthOrHeight: 0.5 - m_PhysicalUnit: 3 - m_FallbackScreenDPI: 96 - m_DefaultSpriteDPI: 96 - m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 0 ---- !u!1 &4808982256744730386 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 7233259200132978428} - - component: {fileID: 5104387649508117141} - - component: {fileID: 3965864432699664111} - m_Layer: 5 - m_Name: Indicator - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!222 &5104387649508117141 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4808982256744730386} - m_CullTransparentMesh: 0 ---- !u!222 &6745855428745291286 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2480283714093027852} - m_CullTransparentMesh: 0 ---- !u!224 &7233259200132978428 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 4808982256744730386} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -1} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 4393252311222810876} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!4 &7443408886491487332 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 4393252311378272345} - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!1 &7443408886491487334 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 7443408886491487332} - - component: {fileID: 7443408886491487335} - - component: {fileID: 1726381377} - - component: {fileID: 7443408886491487337} - - component: {fileID: 192429404} - - component: {fileID: 192429405} - - component: {fileID: 192429406} - - component: {fileID: 192429407} - - component: {fileID: 192429408} - - component: {fileID: 192429409} - - component: {fileID: 192429410} - m_Layer: 0 - m_Name: NetworkManager - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &7443408886491487335 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: d2c95dfde7d73b54dbbdc23155d35d36, type: 3} - m_Name: - m_EditorClassIdentifier: - _refreshDefaultPrefabs: 1 - _runInBackground: 1 - _dontDestroyOnLoad: 1 - _objectPool: {fileID: 0} - _persistence: 0 - _logging: {fileID: 0} - _spawnablePrefabs: {fileID: 11400000, guid: 68e79e63a16f2c74e81f070bd36822b8, type: 2} ---- !u!114 &7443408886491487337 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7443408886491487334} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 211a9f6ec51ddc14f908f5acc0cd0423, type: 3} - m_Name: - m_EditorClassIdentifier: - _playerPrefab: {fileID: 201277550, guid: 8ef354bfc16ca8a459074c3fa9b6727e, type: 3} - _addToDefaultScene: 1 - Spawns: [] ---- !u!224 &9139860295689780510 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2480283714093027852} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -1} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 4393252310837120380} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} diff --git a/Assets/FishNet/Demos/Prediction 2/Rigidbody/PredictionV2_RB.unity.meta b/Assets/FishNet/Demos/Prediction 2/Rigidbody/PredictionV2_RB.unity.meta deleted file mode 100644 index c11f8c5..0000000 --- a/Assets/FishNet/Demos/Prediction 2/Rigidbody/PredictionV2_RB.unity.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 7f31e665d963214449f27dc0ad466dfb -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs.meta b/Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs.meta deleted file mode 100644 index d875209..0000000 --- a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: c147d08de81079a4c8f17246c4e49dc5 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs/RigidbodyPrediction.prefab b/Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs/RigidbodyPrediction.prefab deleted file mode 100644 index 9724be0..0000000 --- a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs/RigidbodyPrediction.prefab +++ /dev/null @@ -1,451 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &303449597948771942 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 303449597948771941} - - component: {fileID: 303449597948771939} - - component: {fileID: 303449597948771940} - m_Layer: 0 - m_Name: Cube (1) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &303449597948771941 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449597948771942} - m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1.5, y: 0.25, z: 0.25} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 303449599178274091} - m_RootOrder: 1 - m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} ---- !u!33 &303449597948771939 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449597948771942} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &303449597948771940 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449597948771942} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!1 &303449598114786579 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 303449598114786577} - - component: {fileID: 4875864441162262683} - - component: {fileID: 303449598114786578} - - component: {fileID: 201277550} - - component: {fileID: 201277549} - m_Layer: 0 - m_Name: RigidbodyPrediction - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &303449598114786577 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598114786579} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: -4.80351, y: 0.18147132, z: 5.430528} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 303449599178274091} - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &4875864441162262683 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598114786579} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1e66bfd8c92aad24e8526e7d3aae8b34, type: 3} - m_Name: - m_EditorClassIdentifier: - _componentIndexCache: 0 - _addedNetworkObject: {fileID: 201277550} - _networkObjectCache: {fileID: 201277550} ---- !u!135 &303449598114786578 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598114786579} - m_Material: {fileID: 13400000, guid: b31539408c1f95d4281bb4484bb6b78e, type: 2} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} ---- !u!114 &201277550 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598114786579} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 26b716c41e9b56b4baafaf13a523ba2e, type: 3} - m_Name: - m_EditorClassIdentifier: - k__BackingField: 0 - k__BackingField: 0 - k__BackingField: {fileID: 0} - _networkBehaviours: - - {fileID: 4875864441162262683} - k__BackingField: {fileID: 0} - k__BackingField: [] - SerializedTransformProperties: - Position: {x: -4.80351, y: 0.18147132, z: 5.430528} - Rotation: {x: 0, y: 0, z: 0, w: 1} - LocalScale: {x: 1, y: 1, z: 1} - _isNetworked: 1 - _isSpawnable: 1 - _isGlobal: 0 - _initializeOrder: 0 - _defaultDespawnType: 0 - NetworkObserver: {fileID: 0} - k__BackingField: 21 - k__BackingField: 0 - _scenePathHash: 0 - k__BackingField: 0 - k__BackingField: 12616697518120799840 ---- !u!54 &201277549 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598114786579} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 1 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 112 - m_CollisionDetection: 1 ---- !u!1 &303449598207636365 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 303449598207636364} - - component: {fileID: 303449598207636362} - - component: {fileID: 303449598207636363} - m_Layer: 0 - m_Name: Cube (2) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &303449598207636364 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598207636365} - m_LocalRotation: {x: 0.5, y: 0.5, z: 0.5, w: 0.5} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1.5, y: 0.25, z: 0.25} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 303449599178274091} - m_RootOrder: 2 - m_LocalEulerAnglesHint: {x: 0, y: 90, z: 90} ---- !u!33 &303449598207636362 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598207636365} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &303449598207636363 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598207636365} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!1 &303449598691742042 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 303449598691742041} - - component: {fileID: 303449598691742039} - - component: {fileID: 303449598691742040} - m_Layer: 0 - m_Name: Cube - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &303449598691742041 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598691742042} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1.5, y: 0.25, z: 0.25} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 303449599178274091} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &303449598691742039 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598691742042} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &303449598691742040 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449598691742042} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!1 &303449599178274092 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 303449599178274091} - - component: {fileID: 303449599178274088} - - component: {fileID: 303449599178274089} - m_Layer: 0 - m_Name: Sphere (1) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &303449599178274091 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449599178274092} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 303449598691742041} - - {fileID: 303449597948771941} - - {fileID: 303449598207636364} - m_Father: {fileID: 303449598114786577} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &303449599178274088 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449599178274092} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &303449599178274089 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 303449599178274092} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_StaticShadowCaster: 0 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} diff --git a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs/RigidbodyPrediction.prefab.meta b/Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs/RigidbodyPrediction.prefab.meta deleted file mode 100644 index 9e75a80..0000000 --- a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Prefabs/RigidbodyPrediction.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 8ef354bfc16ca8a459074c3fa9b6727e -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts.meta b/Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts.meta deleted file mode 100644 index 3207c14..0000000 --- a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: bf02fdf4a8ce43c489e5b5d8e65cb87d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts/RigidbodyPredictionV2.cs b/Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts/RigidbodyPredictionV2.cs deleted file mode 100644 index 9e7442d..0000000 --- a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts/RigidbodyPredictionV2.cs +++ /dev/null @@ -1,211 +0,0 @@ -using FishNet.Object; -using FishNet.Object.Prediction; -using FishNet.Transporting; -using UnityEngine; - -/* -* -* See TransformPrediction.cs for more detailed notes. -* -*/ - -namespace FishNet.PredictionV2 -{ - /* THIS CLASS IS CURRENTLY USED FOR TESTING AND IS NOT CONSIDERED - * AN EXAMPLE TO FOLLOW. */ - /* THIS CLASS IS CURRENTLY USED FOR TESTING AND IS NOT CONSIDERED - * AN EXAMPLE TO FOLLOW. */ - /* THIS CLASS IS CURRENTLY USED FOR TESTING AND IS NOT CONSIDERED - * AN EXAMPLE TO FOLLOW. */ - /* THIS CLASS IS CURRENTLY USED FOR TESTING AND IS NOT CONSIDERED - * AN EXAMPLE TO FOLLOW. */ - - public class RigidbodyPredictionV2 : NetworkBehaviour - { -#if !PREDICTION_1 - - public struct MoveData : IReplicateData - { - public bool Jump; - public float Horizontal; - public float Vertical; - public Vector3 OtherImpulseForces; - public MoveData(bool jump, float horizontal, float vertical, Vector3 otherImpulseForces) - { - Jump = jump; - Horizontal = horizontal; - Vertical = vertical; - OtherImpulseForces = otherImpulseForces; - _tick = 0; - } - - private uint _tick; - public void Dispose() { } - public uint GetTick() => _tick; - public void SetTick(uint value) => _tick = value; - } - - public struct ReconcileData : IReconcileData - { - public Vector3 Position; - public Quaternion Rotation; - public Vector3 Velocity; - public Vector3 AngularVelocity; - public ReconcileData(Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity) - { - Position = position; - Rotation = rotation; - Velocity = velocity; - AngularVelocity = angularVelocity; - _tick = 0; - } - - private uint _tick; - public void Dispose() { } - public uint GetTick() => _tick; - public void SetTick(uint value) => _tick = value; - } - - //[SerializeField] - //private float _jumpForce = 15f; - [SerializeField] - private float _moveRate = 15f; - - public Rigidbody Rigidbody { get; private set; } - private bool _jump; - - private void Update() - { - if (base.IsOwner) - { - if (Input.GetKeyDown(KeyCode.Space)) - _jump = true; - } - } - - public override void OnStartNetwork() - { - Rigidbody = GetComponent(); - base.TimeManager.OnTick += TimeManager_OnTick; - base.TimeManager.OnPostTick += TimeManager_OnPostTick; - } - - public override void OnStopNetwork() - { - - base.TimeManager.OnTick -= TimeManager_OnTick; - base.TimeManager.OnPostTick -= TimeManager_OnPostTick; - } - - - private void TimeManager_OnTick() - { - Move(BuildMoveData()); - } - - private void TimeManager_OnPostTick() - { - CreateReconcile(); - } - - private MoveData BuildMoveData() - { - if (!IsOwner && Owner.IsValid) - return default; - - float horizontal = Input.GetAxisRaw("Horizontal"); - float vertical = Input.GetAxisRaw("Vertical"); - //MoveData md = new MoveData(_jump, horizontal, vertical, (SpringForces + RocketForces)); - MoveData md = new MoveData(_jump, horizontal, vertical, Vector3.zero); - - //SpringForces = Vector3.zero; - //RocketForces = Vector3.zero; - - _jump = false; - - return md; - } - - public uint LastMdTick; - - [Replicate] - private void Move(MoveData md, ReplicateState state = ReplicateState.Invalid, Channel channel = Channel.Unreliable) - { - LastMdTick = md.GetTick(); - //if (base.IsOwner) - // Debug.Log(PredictionManager.ClientReplayTick + " > " + md.GetTick()); - //if (state == ReplicateState.Future) - //{ - // /* Reduce velocity slightly. This will be slightly less accurate if - // * the object continues to move in the same direction but can drastically - // * reduce jarring visuals if the object changes path rather than predicted(future) - // * forward. */ - // _rigidbody.velocity *= 0.65f; - // _rigidbody.angularVelocity *= 0.65f; - // return; - //} - - //Vector3 forces = new Vector3(md.Horizontal, 0f, md.Vertical) * _moveRate; - //Rigidbody.AddForce(forces); - - //if (md.Jump) - // Rigidbody.AddForce(new Vector3(0f, _jumpForce, 0f), ForceMode.Impulse); - ////Add gravity to make the object fall faster. - //Rigidbody.AddForce(Physics.gravity * 3f); - - Vector3 forces = new Vector3(md.Horizontal, 0f, md.Vertical) * _moveRate; - //PRB.AddForce(forces); - forces += Physics.gravity * 3f; - //if (md.Jump) - // PRB.AddForce(new Vector3(0f, _jumpForce, 0f), ForceMode.Impulse); - ////Add gravity to make the object fall faster. - //PRB.AddForce(forces); - - - //if (IsOwner) - //{ - // if (state.IsReplayed()) - // Debug.Log($"{md.GetTick()} -> {transform.position.x} -> {Rigidbody.velocity.x}"); - // else - // Debug.LogWarning($"{md.GetTick()} -> {transform.position.x} -> {Rigidbody.velocity.x}"); - //} - - //if ((!base.IsServerStarted && base.IsOwner) || (base.IsServerStarted && !base.IsOwner)) - // Debug.LogWarning($"Frame {Time.frameCount}. State {state}, Horizontal {md.Horizontal}. MdTick {md.GetTick()}, PosX {transform.position.x.ToString("0.##")}. VelX {Rigidbody.velocity.x.ToString("0.###")}."); - } - - public override void CreateReconcile() - { - /* The base.IsServer check is not required but does save a little - * performance by not building the reconcileData if not server. */ - if (IsServerStarted) - { - ReconcileData rd = new ReconcileData(transform.position, transform.rotation, Rigidbody.velocity, Rigidbody.angularVelocity); - //if (!base.IsOwner) - // Debug.LogError($"Frame {Time.frameCount}. Reconcile, MdTick {LastMdTick}, PosX {transform.position.x.ToString("0.##")}. VelX {Rigidbody.velocity.x.ToString("0.###")}."); - Reconciliation(rd); - } - } - - [Reconcile] - private void Reconciliation(ReconcileData rd, Channel channel = Channel.Unreliable) - { - transform.position = rd.Position; - transform.rotation = rd.Rotation; - Rigidbody.velocity = rd.Velocity; - Rigidbody.angularVelocity = rd.AngularVelocity; - - //if (PrintForClient()) - //{ - // Debug.LogError($"Frame {Time.frameCount}. Reconcile, MdTick {rd.GetTick()}, PosX {transform.position.x.ToString("0.##")}. VelX {Rigidbody.velocity.x.ToString("0.###")}. RdPosX " + - // $"{rd.Position.x.ToString("0.##")}. RdVelX {Rigidbody.velocity.x.ToString("0.###")}"); - //} - - } - - private bool PrintForClient() => ((!base.IsServerStarted && base.IsOwner) || (base.IsServerStarted && !base.IsOwner)); - -#endif - } - -} \ No newline at end of file diff --git a/Assets/FishNet/Demos/Prefabs/NetworkHudCanvas.prefab b/Assets/FishNet/Demos/Prefabs/NetworkHudCanvas.prefab index 8eee31a..a0288e4 100644 --- a/Assets/FishNet/Demos/Prefabs/NetworkHudCanvas.prefab +++ b/Assets/FishNet/Demos/Prefabs/NetworkHudCanvas.prefab @@ -28,9 +28,9 @@ RectTransform: m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: -1} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 4393252311501663115} + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -60,7 +60,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -105,11 +104,11 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 0, y: 0, z: 0} - m_ConstrainProportionsScale: 0 m_Children: - {fileID: 4393252311652982283} - {fileID: 4393252311501663115} m_Father: {fileID: 0} + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -128,7 +127,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 6d3606bfdac5a4743890fc1a5ecd8f24, type: 3} m_Name: m_EditorClassIdentifier: - _autoStartType: 0 + AutoStart: 0 _stoppedColor: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} _changingColor: {r: 0.78431374, g: 0.6862745, b: 0, a: 1} _startedColor: {r: 0, g: 0.5882353, b: 0.64705884, a: 1} @@ -151,9 +150,7 @@ Canvas: m_OverrideSorting: 0 m_OverridePixelPerfect: 0 m_SortingBucketNormalizedSize: 0 - m_VertexColorAlwaysGammaSpace: 0 m_AdditionalShaderChannelsFlag: 0 - m_UpdateRectTransformForStandalone: 0 m_SortingLayerID: 0 m_SortingOrder: 0 m_TargetDisplay: 0 @@ -179,7 +176,6 @@ MonoBehaviour: m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 0 --- !u!114 &4393252310969058989 MonoBehaviour: m_ObjectHideFlags: 0 @@ -226,10 +222,10 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: - {fileID: 9139860296052841449} m_Father: {fileID: 4393252310969058990} + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} @@ -259,7 +255,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -288,7 +283,6 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 - m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -319,7 +313,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 4393252310969058994} - m_TargetAssemblyTypeName: m_MethodName: OnClick_Client m_Mode: 1 m_Arguments: @@ -359,10 +352,10 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: - {fileID: 7233259200663826443} m_Father: {fileID: 4393252310969058990} + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} @@ -392,7 +385,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -421,7 +413,6 @@ MonoBehaviour: m_EditorClassIdentifier: m_Navigation: m_Mode: 3 - m_WrapAround: 0 m_SelectOnUp: {fileID: 0} m_SelectOnDown: {fileID: 0} m_SelectOnLeft: {fileID: 0} @@ -452,7 +443,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 4393252310969058994} - m_TargetAssemblyTypeName: m_MethodName: OnClick_Server m_Mode: 1 m_Arguments: @@ -491,9 +481,9 @@ RectTransform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: -1} m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 4393252311652982283} + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -523,7 +513,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.25490198, g: 0.25490198, b: 0.25490198, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: diff --git a/Assets/FishNet/Demos/Prefabs/NetworkManager.prefab b/Assets/FishNet/Demos/Prefabs/NetworkManager.prefab new file mode 100644 index 0000000..fce3e55 --- /dev/null +++ b/Assets/FishNet/Demos/Prefabs/NetworkManager.prefab @@ -0,0 +1,208 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &7443408887813606051 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7443408887813606049} + - component: {fileID: 7443408887813606050} + - component: {fileID: 934570884} + - component: {fileID: 7443408887813606060} + m_Layer: 0 + m_Name: NetworkManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7443408887813606049 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887813606051} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 4393252310584637084} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &7443408887813606050 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887813606051} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d2c95dfde7d73b54dbbdc23155d35d36, type: 3} + m_Name: + m_EditorClassIdentifier: + _logging: {fileID: 0} + _spawnablePrefabs: {fileID: 11400000, guid: ec64eb18c93ab344892891f33edbf82a, type: 2} + _refreshDefaultPrefabs: 0 + _runInBackground: 1 + _dontDestroyOnLoad: 1 + _persistence: 0 +--- !u!114 &934570884 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887813606051} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7d331f979d46e8e4a9fc90070c596d44, type: 3} + m_Name: + m_EditorClassIdentifier: + _defaultConditions: + - {fileID: 11400000, guid: 2033f54fd2794464bae08fa5a55c8996, type: 2} +--- !u!114 &7443408887813606060 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7443408887813606051} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 211a9f6ec51ddc14f908f5acc0cd0423, type: 3} + m_Name: + m_EditorClassIdentifier: + _playerPrefab: {fileID: 0} + _addToDefaultScene: 1 + Spawns: [] +--- !u!1001 &2130063410 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 7443408887813606049} + m_Modifications: + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_Pivot.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_Pivot.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_RootOrder + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_AnchorMax.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 4393252310969058995, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + propertyPath: m_Name + value: NetworkHudCanvas + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 0570b6f7f713dc44a90463654bbcd8d0, type: 3} +--- !u!224 &4393252310584637084 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 4393252310969058990, guid: 0570b6f7f713dc44a90463654bbcd8d0, + type: 3} + m_PrefabInstance: {fileID: 2130063410} + m_PrefabAsset: {fileID: 0} diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs/CharacterControllerPrediction.prefab.meta b/Assets/FishNet/Demos/Prefabs/NetworkManager.prefab.meta similarity index 74% rename from Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs/CharacterControllerPrediction.prefab.meta rename to Assets/FishNet/Demos/Prefabs/NetworkManager.prefab.meta index 3ae3ba7..ae648e6 100644 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/Prefabs/CharacterControllerPrediction.prefab.meta +++ b/Assets/FishNet/Demos/Prefabs/NetworkManager.prefab.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 5b712878ecece354ba4ffb026c0a221c +guid: 0b650fca685f2eb41a86538aa883e4c1 PrefabImporter: externalObjects: {} userData: diff --git a/Assets/FishNet/Demos/SceneManager (Old Examples)/Prefabs/_SceneManager_Old_Prefabs.asset b/Assets/FishNet/Demos/SceneManager (Old Examples)/Prefabs/_SceneManager_Old_Prefabs.asset deleted file mode 100644 index 98b2c12..0000000 --- a/Assets/FishNet/Demos/SceneManager (Old Examples)/Prefabs/_SceneManager_Old_Prefabs.asset +++ /dev/null @@ -1,16 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4489d77032a81ef42b0067acf2737d4d, type: 3} - m_Name: _SceneManager_Old_Prefabs - m_EditorClassIdentifier: - _prefabs: - - {fileID: 611616139817875448, guid: bf5f023b4017a5e41a9815ec5745df3d, type: 3} diff --git a/Assets/FishNet/Demos/SceneManager (Old Examples)/Prefabs/_SceneManager_Old_Prefabs.asset.meta b/Assets/FishNet/Demos/SceneManager (Old Examples)/Prefabs/_SceneManager_Old_Prefabs.asset.meta deleted file mode 100644 index cbcaf6c..0000000 --- a/Assets/FishNet/Demos/SceneManager (Old Examples)/Prefabs/_SceneManager_Old_Prefabs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b1b4d193fc9b1bb41a92600a22b3d34e -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Demos/SceneManager/Additive Scenes/Prefabs/_SceneManager_Additive Scenes_Prefabs.asset b/Assets/FishNet/Demos/SceneManager/Additive Scenes/Prefabs/_SceneManager_Additive Scenes_Prefabs.asset deleted file mode 100644 index cb251a0..0000000 --- a/Assets/FishNet/Demos/SceneManager/Additive Scenes/Prefabs/_SceneManager_Additive Scenes_Prefabs.asset +++ /dev/null @@ -1,16 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4489d77032a81ef42b0067acf2737d4d, type: 3} - m_Name: _SceneManager_Additive Scenes_Prefabs - m_EditorClassIdentifier: - _prefabs: - - {fileID: 8192566354860284824, guid: 6331b3542e64a564c81bc39cedf70c8d, type: 3} diff --git a/Assets/FishNet/Demos/SceneManager/Additive Scenes/Prefabs/_SceneManager_Additive Scenes_Prefabs.asset.meta b/Assets/FishNet/Demos/SceneManager/Additive Scenes/Prefabs/_SceneManager_Additive Scenes_Prefabs.asset.meta deleted file mode 100644 index c8e83b3..0000000 --- a/Assets/FishNet/Demos/SceneManager/Additive Scenes/Prefabs/_SceneManager_Additive Scenes_Prefabs.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 223fa01133c52c7469e6520b901bcebd -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Plugins/Bayou/Core/BidirectionalDictionary.cs b/Assets/FishNet/Plugins/Bayou/Core/BidirectionalDictionary.cs index f8d85cc..b10d8a7 100644 --- a/Assets/FishNet/Plugins/Bayou/Core/BidirectionalDictionary.cs +++ b/Assets/FishNet/Plugins/Bayou/Core/BidirectionalDictionary.cs @@ -1,115 +1,115 @@ -//using System.Collections; -//using System.Collections.Generic; +using System.Collections; +using System.Collections.Generic; -//namespace FishNet.Transporting.Bayou -//{ -// internal class BidirectionalDictionary : IEnumerable -// { -// private Dictionary t1ToT2Dict = new Dictionary(); -// private Dictionary t2ToT1Dict = new Dictionary(); +namespace FishNet.Transporting.Bayou +{ + internal class BidirectionalDictionary : IEnumerable + { + private Dictionary t1ToT2Dict = new Dictionary(); + private Dictionary t2ToT1Dict = new Dictionary(); -// public IEnumerable FirstTypes => t1ToT2Dict.Keys; -// public IEnumerable SecondTypes => t2ToT1Dict.Keys; + public IEnumerable FirstTypes => t1ToT2Dict.Keys; + public IEnumerable SecondTypes => t2ToT1Dict.Keys; -// public IEnumerator GetEnumerator() => t1ToT2Dict.GetEnumerator(); + public IEnumerator GetEnumerator() => t1ToT2Dict.GetEnumerator(); -// public int Count => t1ToT2Dict.Count; + public int Count => t1ToT2Dict.Count; -// public Dictionary First => t1ToT2Dict; -// public Dictionary Second => t2ToT1Dict; + public Dictionary First => t1ToT2Dict; + public Dictionary Second => t2ToT1Dict; -// public void Add(T1 key, T2 value) -// { -// if (t1ToT2Dict.ContainsKey(key)) -// { -// Remove(key); -// } + public void Add(T1 key, T2 value) + { + if (t1ToT2Dict.ContainsKey(key)) + { + Remove(key); + } -// t1ToT2Dict[key] = value; -// t2ToT1Dict[value] = key; -// } + t1ToT2Dict[key] = value; + t2ToT1Dict[value] = key; + } -// public void Add(T2 key, T1 value) -// { -// if (t2ToT1Dict.ContainsKey(key)) -// { -// Remove(key); -// } + public void Add(T2 key, T1 value) + { + if (t2ToT1Dict.ContainsKey(key)) + { + Remove(key); + } -// t2ToT1Dict[key] = value; -// t1ToT2Dict[value] = key; -// } + t2ToT1Dict[key] = value; + t1ToT2Dict[value] = key; + } -// public T2 Get(T1 key) => t1ToT2Dict[key]; + public T2 Get(T1 key) => t1ToT2Dict[key]; -// public T1 Get(T2 key) => t2ToT1Dict[key]; + public T1 Get(T2 key) => t2ToT1Dict[key]; -// public bool TryGetValue(T1 key, out T2 value) => t1ToT2Dict.TryGetValue(key, out value); + public bool TryGetValue(T1 key, out T2 value) => t1ToT2Dict.TryGetValue(key, out value); -// public bool TryGetValue(T2 key, out T1 value) => t2ToT1Dict.TryGetValue(key, out value); + public bool TryGetValue(T2 key, out T1 value) => t2ToT1Dict.TryGetValue(key, out value); -// public bool Contains(T1 key) => t1ToT2Dict.ContainsKey(key); + public bool Contains(T1 key) => t1ToT2Dict.ContainsKey(key); -// public bool Contains(T2 key) => t2ToT1Dict.ContainsKey(key); + public bool Contains(T2 key) => t2ToT1Dict.ContainsKey(key); -// public void Remove(T1 key) -// { -// if (First.TryGetValue(key, out T2 value)) -// { -// t1ToT2Dict.Remove(key); -// t2ToT1Dict.Remove(value); -// } -// } + public void Remove(T1 key) + { + if (First.TryGetValue(key, out T2 value)) + { + t1ToT2Dict.Remove(key); + t2ToT1Dict.Remove(value); + } + } -// public void Clear() -// { -// First.Clear(); -// Second.Clear(); -// } + public void Clear() + { + First.Clear(); + Second.Clear(); + } -// public void Remove(T2 key) -// { -// if (Second.TryGetValue(key, out T1 value)) -// { -// t1ToT2Dict.Remove(value); -// t2ToT1Dict.Remove(key); -// } -// } + public void Remove(T2 key) + { + if (Second.TryGetValue(key, out T1 value)) + { + t1ToT2Dict.Remove(value); + t2ToT1Dict.Remove(key); + } + } -// public void RemoveFirst(T1 key) -// { -// if (First.TryGetValue(key, out T2 value)) -// { -// Second.Remove(value); -// First.Remove(key); -// } -// } + public void RemoveFirst(T1 key) + { + if (First.TryGetValue(key, out T2 value)) + { + Second.Remove(value); + First.Remove(key); + } + } -// public void RemoveSecond(T2 key) -// { -// if (Second.TryGetValue(key, out T1 value)) -// { -// First.Remove(value); -// Second.Remove(key); -// } -// } + public void RemoveSecond(T2 key) + { + if (Second.TryGetValue(key, out T1 value)) + { + First.Remove(value); + Second.Remove(key); + } + } -// public T1 this[T2 key] -// { -// get => t2ToT1Dict[key]; -// set -// { -// Add(key, value); -// } -// } + public T1 this[T2 key] + { + get => t2ToT1Dict[key]; + set + { + Add(key, value); + } + } -// public T2 this[T1 key] -// { -// get => t1ToT2Dict[key]; -// set -// { -// Add(key, value); -// } -// } -// } -//} \ No newline at end of file + public T2 this[T1 key] + { + get => t1ToT2Dict[key]; + set + { + Add(key, value); + } + } + } +} \ No newline at end of file diff --git a/Assets/FishNet/Plugins/Bayou/Core/ServerSocket.cs b/Assets/FishNet/Plugins/Bayou/Core/ServerSocket.cs index 3b327f0..71d1d71 100644 --- a/Assets/FishNet/Plugins/Bayou/Core/ServerSocket.cs +++ b/Assets/FishNet/Plugins/Bayou/Core/ServerSocket.cs @@ -56,7 +56,7 @@ namespace FishNet.Transporting.Bayou.Server /// /// Currently connected clients. /// - private HashSet _clients = new HashSet(); + private List _clients = new List(); /// /// Server socket manager. /// diff --git a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/BufferPool.cs b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/BufferPool.cs index 6ee08a3..7ab1711 100644 --- a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/BufferPool.cs +++ b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/BufferPool.cs @@ -129,7 +129,7 @@ namespace JamesFrowen.SimpleWeb } else { - //Log.Verbose($"BufferBucket({arraySize}) create new"); + Log.Verbose($"BufferBucket({arraySize}) create new"); return new ArrayBuffer(this, arraySize); } } @@ -145,13 +145,13 @@ namespace JamesFrowen.SimpleWeb void IncrementCreated() { int next = Interlocked.Increment(ref _current); - //Log.Verbose($"BufferBucket({arraySize}) count:{next}"); + Log.Verbose($"BufferBucket({arraySize}) count:{next}"); } [Conditional("DEBUG")] void DecrementCreated() { int next = Interlocked.Decrement(ref _current); - //Log.Verbose($"BufferBucket({arraySize}) count:{next}"); + Log.Verbose($"BufferBucket({arraySize}) count:{next}"); } } diff --git a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/ReceiveLoop.cs b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/ReceiveLoop.cs index e14bb31..a0ebf6d 100644 --- a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/ReceiveLoop.cs +++ b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/ReceiveLoop.cs @@ -41,7 +41,7 @@ namespace JamesFrowen.SimpleWeb { (Connection conn, int maxMessageSize, bool expectMask, ConcurrentQueue queue, BufferPool _) = config; - //Profiler.BeginThreadProfiling("SimpleWeb", $"ReceiveLoop {conn.connId}"); + Profiler.BeginThreadProfiling("SimpleWeb", $"ReceiveLoop {conn.connId}"); byte[] readBuffer = new byte[Constants.HeaderSize + (expectMask ? Constants.MaskSize : 0) + maxMessageSize]; try @@ -95,7 +95,7 @@ namespace JamesFrowen.SimpleWeb } finally { - //Profiler.EndThreadProfiling(); + Profiler.EndThreadProfiling(); conn.Dispose(); } diff --git a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/SendLoop.cs b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/SendLoop.cs index db9d770..92d2728 100644 --- a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/SendLoop.cs +++ b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Common/SendLoop.cs @@ -39,7 +39,7 @@ namespace JamesFrowen.SimpleWeb { (Connection conn, int bufferSize, bool setMask) = config; - //Profiler.BeginThreadProfiling("SimpleWeb", $"SendLoop {conn.connId}"); + Profiler.BeginThreadProfiling("SimpleWeb", $"SendLoop {conn.connId}"); // create write buffer for this thread byte[] writeBuffer = new byte[bufferSize]; @@ -70,11 +70,7 @@ namespace JamesFrowen.SimpleWeb while (conn.sendQueue.TryDequeue(out ArrayBuffer msg)) { // check if connected before sending message - if (!client.Connected) - { - //Log.Info($"SendLoop {conn} not connected"); - return; - } + if (!client.Connected) { Log.Info($"SendLoop {conn} not connected"); return; } int maxLength = msg.count + Constants.HeaderSize + Constants.MaskSize; @@ -99,11 +95,7 @@ namespace JamesFrowen.SimpleWeb while (conn.sendQueue.TryDequeue(out ArrayBuffer msg)) { // check if connected before sending message - if (!client.Connected) - { - //Log.Info($"SendLoop {conn} not connected"); - return; - } + if (!client.Connected) { Log.Info($"SendLoop {conn} not connected"); return; } int length = SendMessage(writeBuffer, 0, msg, setMask, maskHelper); stream.Write(writeBuffer, 0, length); @@ -114,14 +106,8 @@ namespace JamesFrowen.SimpleWeb Log.Info($"{conn} Not Connected"); } - catch (ThreadInterruptedException e) - { - Log.InfoException(e); - } - catch (ThreadAbortException e) - { - Log.InfoException(e); - } + catch (ThreadInterruptedException e) { Log.InfoException(e); } + catch (ThreadAbortException e) { Log.InfoException(e); } catch (Exception e) { Log.Exception(e); @@ -149,7 +135,7 @@ namespace JamesFrowen.SimpleWeb offset += msgLength; // dump before mask on - //Log.DumpBuffer("Send", buffer, startOffset, offset); + Log.DumpBuffer("Send", buffer, startOffset, offset); if (setMask) { diff --git a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/ServerHandshake.cs b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/ServerHandshake.cs index 8419f31..b883029 100644 --- a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/ServerHandshake.cs +++ b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/ServerHandshake.cs @@ -46,7 +46,7 @@ namespace JamesFrowen.SimpleWeb if (!IsGet(getHeader.array)) { - //Log.Warn($"First bytes from client was not 'GET' for handshake, instead was {Log.BufferToString(getHeader.array, 0, GetSize)}"); + Log.Warn($"First bytes from client was not 'GET' for handshake, instead was {Log.BufferToString(getHeader.array, 0, GetSize)}"); return false; } } diff --git a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/SimpleWebServer.cs b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/SimpleWebServer.cs index 592d0dc..ff55c20 100644 --- a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/SimpleWebServer.cs +++ b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/SimpleWebServer.cs @@ -52,7 +52,7 @@ namespace JamesFrowen.SimpleWeb } } - public void SendAll(HashSet connectionIds, ArraySegment source) + public void SendAll(List connectionIds, ArraySegment source) { ArrayBuffer buffer = bufferPool.Take(source.Count); buffer.CopyFrom(source); @@ -60,7 +60,9 @@ namespace JamesFrowen.SimpleWeb // make copy of array before for each, data sent to each client is the same foreach (int id in connectionIds) + { server.Send(id, buffer); + } } public void SendOne(int connectionId, ArraySegment source) { @@ -80,15 +82,25 @@ namespace JamesFrowen.SimpleWeb return server.GetClientAddress(connectionId); } - /// - /// Processes all messages. + /// Processes all new messages /// public void ProcessMessageQueue() + { + ProcessMessageQueue(null); + } + + /// + /// Processes all messages while is enabled + /// + /// + public void ProcessMessageQueue(MonoBehaviour behaviour) { int processedCount = 0; + bool skipEnabled = behaviour == null; // check enabled every time incase behaviour was disabled after data - while ( + while ( + (skipEnabled || behaviour.enabled) && processedCount < maxMessagesPerTick && // Dequeue last server.receiveQueue.TryDequeue(out Message next) diff --git a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/WebSocketServer.cs b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/WebSocketServer.cs index 620d11e..a42773e 100644 --- a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/WebSocketServer.cs +++ b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/Server/WebSocketServer.cs @@ -1,5 +1,3 @@ -using FishNet.Connection; -using FishNet.Managing; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -33,7 +31,7 @@ namespace JamesFrowen.SimpleWeb if (_idCache.Count == 0) GrowIdCache(1000); - int result = NetworkConnection.UNSET_CLIENTID_VALUE; + int result; _idCache.TryDequeue(out result); return result; } @@ -43,11 +41,11 @@ namespace JamesFrowen.SimpleWeb /// private void GrowIdCache(int value) { - int over = (_nextId + value) - NetworkConnection.MAXIMUM_CLIENTID_VALUE; + int over = (_nextId + value) - int.MaxValue; //Prevent overflow. if (over > 0) value -= over; - + for (int i = _nextId; i < value; i++) _idCache.Enqueue(i); } @@ -112,7 +110,7 @@ namespace JamesFrowen.SimpleWeb // this might not be a problem as HandshakeAndReceiveLoop checks for stop // and returns/disposes before sending message to queue Connection conn = new Connection(client, AfterConnectionDisposed); - //Log.Info($"A client connected {conn}"); + Log.Info($"A client connected {conn}"); // handshake needs its own thread as it needs to wait for message from client Thread receiveThread = new Thread(() => HandshakeAndReceiveLoop(conn)); @@ -142,7 +140,7 @@ namespace JamesFrowen.SimpleWeb bool success = sslHelper.TryCreateStream(conn); if (!success) { - //Log.Error($"Failed to create SSL Stream {conn}"); + Log.Error($"Failed to create SSL Stream {conn}"); conn.Dispose(); return; } @@ -151,11 +149,11 @@ namespace JamesFrowen.SimpleWeb if (success) { - //Log.Info($"Sent Handshake {conn}"); + Log.Info($"Sent Handshake {conn}"); } else { - //Log.Error($"Handshake Failed {conn}"); + Log.Error($"Handshake Failed {conn}"); conn.Dispose(); return; } @@ -168,13 +166,6 @@ namespace JamesFrowen.SimpleWeb } conn.connId = GetNextId(); - if (conn.connId == NetworkConnection.UNSET_CLIENTID_VALUE) - { - NetworkManagerExtensions.LogWarning($"At maximum connections. A client attempting to connect to be rejected."); - conn.Dispose(); - return; - } - connections.TryAdd(conn.connId, conn); receiveQueue.Enqueue(new Message(conn.connId, EventType.Connected)); diff --git a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/SimpleWebTransport.asmdef b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/SimpleWebTransport.asmdef index d35bb06..73f18a0 100644 --- a/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/SimpleWebTransport.asmdef +++ b/Assets/FishNet/Plugins/Bayou/SimpleWebTransport/SimpleWebTransport.asmdef @@ -1,16 +1,12 @@ { "name": "SimpleWebTransport", - "rootNamespace": "", - "references": [ - "GUID:7c88a4a7926ee5145ad2dfa06f454c67" - ], + "references": [], + "optionalUnityReferences": [], "includePlatforms": [], "excludePlatforms": [], "allowUnsafeCode": false, "overrideReferences": false, "precompiledReferences": [], "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false + "defineConstraints": [] } \ No newline at end of file diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs index cbae559..d7ed357 100644 --- a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapBuildUtils.cs @@ -23,7 +23,9 @@ namespace Edgegap public static BuildReport BuildServer() { - IEnumerable scenes = EditorBuildSettings.scenes.Select(s=>s.path); + IEnumerable scenes = EditorBuildSettings.scenes + .Where(s => s.enabled) + .Select(s => s.path); BuildPlayerOptions options = new BuildPlayerOptions { scenes = scenes.ToArray(), @@ -102,7 +104,7 @@ namespace Edgegap onStatusUpdate(msg); }); - if (realErrorMessage != null) + if(realErrorMessage != null) { throw new Exception(realErrorMessage); } @@ -297,4 +299,4 @@ ENTRYPOINT [ ""/root/build/ServerBuild"", ""-batchmode"", ""-nographics""] } } -#endif \ No newline at end of file +#endif diff --git a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindowV2.cs b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindowV2.cs index dd42f1f..7544351 100644 --- a/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindowV2.cs +++ b/Assets/FishNet/Plugins/Edgegap/Editor/EdgegapWindowV2.cs @@ -44,7 +44,6 @@ namespace Edgegap.Editor private string _deploymentRequestId; private string _userExternalIp; private bool _isAwaitingDeploymentReadyStatus; - private bool _registered; #endregion // Vars @@ -151,7 +150,6 @@ namespace Edgegap.Editor unregisterClickEvents(); unregisterFieldCallbacks(); SyncObjectWithForm(); - _registered = false; } #endregion // Unity Funcs @@ -163,7 +161,6 @@ namespace Edgegap.Editor /// private void InitUIElements() { - _registered = true; setVisualElementsToFields(); assertVisualElementKeys(); closeDisableGroups(); @@ -380,9 +377,6 @@ namespace Edgegap.Editor /// private void unregisterFieldCallbacks() { - if (!_registered) - return; - _apiTokenInput.UnregisterValueChangedCallback(onApiTokenInputChanged); _apiTokenInput.UnregisterCallback(onApiTokenInputFocusOut); @@ -419,8 +413,6 @@ namespace Edgegap.Editor /// private void unregisterClickEvents() { - if (!_registered) - return; _debugBtn.clickable.clicked -= onDebugBtnClick; _apiTokenVerifyBtn.clickable.clicked -= onApiTokenVerifyBtnClick; @@ -612,8 +604,6 @@ namespace Edgegap.Editor /// private void SyncObjectWithForm() { - if (_appIconSpriteObjInput == null) - return; _appIconSpriteObj = _appIconSpriteObjInput.value as Sprite; } diff --git a/Assets/FishNet/Plugins/Edgegap/Enums/ApiEnvironment.cs b/Assets/FishNet/Plugins/Edgegap/Enums/ApiEnvironment.cs index 8533a9b..dc854b5 100644 --- a/Assets/FishNet/Plugins/Edgegap/Enums/ApiEnvironment.cs +++ b/Assets/FishNet/Plugins/Edgegap/Enums/ApiEnvironment.cs @@ -55,10 +55,10 @@ namespace Edgegap switch (apiEnvironment) { case ApiEnvironment.Staging: - apiUrl = "https://staging-docs.edgegap.com/docs"; + apiUrl = "https://staging-docs.edgegap.com/docs/category/unity"; break; case ApiEnvironment.Console: - apiUrl = "https://docs.edgegap.com/docs"; + apiUrl = "https://docs.edgegap.com/docs/category/unity"; break; default: apiUrl = null; diff --git a/Assets/FishNet/Plugins/Edgegap/Newtonsoft_Package_Patch.cs b/Assets/FishNet/Plugins/Edgegap/Newtonsoft_Package_Patch.cs index 5ad72dc..c9197e6 100644 --- a/Assets/FishNet/Plugins/Edgegap/Newtonsoft_Package_Patch.cs +++ b/Assets/FishNet/Plugins/Edgegap/Newtonsoft_Package_Patch.cs @@ -18,7 +18,7 @@ namespace Newtonsoft.Json [InitializeOnLoadMethod] private static void Initialize() - { + { string dtStr = EditorPrefs.GetString(WARN_TIME_NAME, string.Empty); //Somehow got cleared. Reset. if (string.IsNullOrWhiteSpace(dtStr)) @@ -43,12 +43,13 @@ namespace Newtonsoft.Json } + ResetWarnTime(); UnityEngine.Debug.LogWarning($"Edgegap requires Json.NET to be imported to function. To import Json.NET navigate to Window -> Package Manager -> Click the + symbol and choose 'Add package by name' -> com.unity.nuget.newtonsoft-json -> Leave version blank and click Add. If you are not currently using Edgegap you may ignore this message."); } } } #endif - + namespace Newtonsoft.Json { diff --git a/Assets/FishNet/Runtime/CodeGenerating/Attributes.cs b/Assets/FishNet/Runtime/CodeGenerating/Attributes.cs index 6f3e9a0..fa3226f 100644 --- a/Assets/FishNet/Runtime/CodeGenerating/Attributes.cs +++ b/Assets/FishNet/Runtime/CodeGenerating/Attributes.cs @@ -10,7 +10,12 @@ namespace FishNet.CodeGenerating /// public class AllowMutableSyncTypeAttribute : Attribute { } /// - /// Type will be excluded from creating auto serializer creation. + /// Type will be included in auto serializer creation. + /// + [AttributeUsage((AttributeTargets.Class | AttributeTargets.Struct), Inherited = true, AllowMultiple = false)] + public class IncludeSerializationAttribute : Attribute { } + /// + /// Type will be excluded from auto serializer creation. /// public class ExcludeSerializationAttribute : Attribute { } /// @@ -30,4 +35,10 @@ namespace FishNet.CodeGenerating /// [AttributeUsage((AttributeTargets.Class | AttributeTargets.Struct), Inherited = true, AllowMultiple = false)] public class UseGlobalCustomSerializerAttribute : Attribute { } + /// + /// Uses built-in caches to retrieve read classes rather than initializing a new instance. + /// This attribute is primarily for internal use and may change at anytime without notice. + /// + [AttributeUsage((AttributeTargets.Class), Inherited = true, AllowMultiple = false)] + public class ReadUnallocated : Attribute { } } \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Connection/Buffer.cs b/Assets/FishNet/Runtime/Connection/Buffer.cs index 0c3b563..61d0892 100644 --- a/Assets/FishNet/Runtime/Connection/Buffer.cs +++ b/Assets/FishNet/Runtime/Connection/Buffer.cs @@ -147,7 +147,7 @@ namespace FishNet.Connection * Modify reserve after making sendLast bundle * so that the wrong reserve is not passed into * the sendLast bundle. */ - reserve += TransportManager.TICK_BYTES; + reserve += TransportManager.UNPACKED_TICK_LENGTH; _reserve = reserve; //Add buffer requires the right reserve so call after setting. AddBuffer(); diff --git a/Assets/FishNet/Runtime/Connection/NetworkConnection.Prediction.cs b/Assets/FishNet/Runtime/Connection/NetworkConnection.Prediction.cs index 0a5afe1..324e5db 100644 --- a/Assets/FishNet/Runtime/Connection/NetworkConnection.Prediction.cs +++ b/Assets/FishNet/Runtime/Connection/NetworkConnection.Prediction.cs @@ -1,6 +1,10 @@ -using FishNet.Managing; +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +using FishNet.Managing; using FishNet.Managing.Predicting; using FishNet.Managing.Timing; +using FishNet.Managing.Transporting; using FishNet.Serializing; using FishNet.Transporting; using System.Collections.Generic; @@ -45,20 +49,21 @@ namespace FishNet.Connection /// internal void WriteState(PooledWriter data) { -#if !DEVELOPMENT_BUILD && !UNITY_EDITOR +#if !DEVELOPMENT //Do not send states to clientHost. if (IsLocalClient) return; #endif - TimeManager tm = NetworkManager.TimeManager; - uint ticksBehind = (IsLocalClient) ? 0 : PacketTick.LocalTickDifference(tm); + TimeManager timeManager = NetworkManager.TimeManager; + TransportManager transportManager = NetworkManager.TransportManager; + uint ticksBehind = (IsLocalClient) ? 0 : PacketTick.LocalTickDifference(timeManager); /* If it's been a really long while the client could just be setting up * or dropping. Only send if they've communicated within 5 seconds. */ - if (ticksBehind > (tm.TickRate * 5)) + if (ticksBehind > (timeManager.TickRate * 5)) return; - int mtu = NetworkManager.TransportManager.GetLowestMTU((byte)Channel.Unreliable); + int mtu = transportManager.GetLowestMTU((byte)Channel.Unreliable); PooledWriter stateWriter; int writerCount = PredictionStateWriters.Count; /* Conditions to create a new writer are: @@ -66,7 +71,7 @@ namespace FishNet.Connection * - data length + currentWriter length > mtu */ Channel channel = Channel.Unreliable; if (writerCount > 0) - NetworkManager.TransportManager.CheckSetReliableChannel((data.Length + PredictionStateWriters[writerCount - 1].Length), ref channel); + transportManager.CheckSetReliableChannel((data.Length + PredictionStateWriters[writerCount - 1].Length), ref channel); /* If no writers or if channel would be forced reliable. * * By checking if channel would be reliable this is @@ -78,8 +83,11 @@ namespace FishNet.Connection if (writerCount == 0 || channel == Channel.Reliable) { stateWriter = WriterPool.Retrieve(mtu); - PredictionStateWriters.Add(stateWriter); - stateWriter.Reserve(PredictionManager.STATE_HEADER_RESERVE_COUNT); + PredictionStateWriters.Add(stateWriter); + stateWriter.Reserve(PredictionManager.STATE_HEADER_RESERVE_LENGTH); + /// 2 PacketId. + /// 4 Last replicate tick run for connection. + /// 4 Length unpacked. } else { diff --git a/Assets/FishNet/Runtime/Connection/NetworkConnection.cs b/Assets/FishNet/Runtime/Connection/NetworkConnection.cs index 112dccd..2739811 100644 --- a/Assets/FishNet/Runtime/Connection/NetworkConnection.cs +++ b/Assets/FishNet/Runtime/Connection/NetworkConnection.cs @@ -1,8 +1,10 @@ -using FishNet.Component.Observing; +using FishNet.CodeGenerating; +using FishNet.Component.Observing; using FishNet.Documenting; using FishNet.Managing; using FishNet.Managing.Timing; using FishNet.Object; +using GameKit.Dependencies.Utilities; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -31,9 +33,28 @@ namespace FishNet.Connection /// /// A container for a connected client used to perform actions on and gather information for the declared client. /// - public partial class NetworkConnection : IEquatable + public partial class NetworkConnection : IResettable, IEquatable { + #region Internal. + /// + /// Tick when Disconnecting was set. + /// + internal uint DisconnectingTick { get; private set; } + /// + /// ObjectIds to use for predicted spawning. + /// + internal Queue PredictedObjectIds = new Queue(); + /// + /// True if the client has sent the same version that the server is on. + /// + internal bool HasSentVersion; + /// + /// LocalTick of the server when this connection was established. This value is not set for clients. + /// + internal uint ServerConnectionTick; + #endregion + #region Public. /// /// Called after this connection has loaded start scenes. Boolean will be true if asServer. Available to this connection and server. @@ -66,18 +87,6 @@ namespace FishNet.Connection return _loadedStartScenesAsClient; } /// - /// True if loaded start scenes as server. - /// - private bool _loadedStartScenesAsServer; - /// - /// True if loaded start scenes as client. - /// - private bool _loadedStartScenesAsClient; - /// - /// ObjectIds to use for predicted spawning. - /// - internal Queue PredictedObjectIds = new Queue(); - /// /// TransportIndex this connection is on. /// For security reasons this value will be unset on clients if this is not their connection. /// @@ -137,19 +146,11 @@ namespace FishNet.Connection /// public bool Disconnecting { get; private set; } /// - /// Tick when Disconnecting was set. - /// - internal uint DisconnectingTick { get; private set; } - /// /// Custom data associated with this connection which may be modified by the user. /// The value of this field are not synchronized over the network. /// public object CustomData = null; /// - /// LocalTick of the server when this connection was established. This value is not set for clients. - /// - internal uint ServerConnectionTick; - /// /// Tick of the last packet received from this connection which was not out of order. /// This value is only available on the server. /// @@ -161,6 +162,17 @@ namespace FishNet.Connection public EstimatedTick LocalTick { get; private set; } = new EstimatedTick(); #endregion + #region Private. + /// + /// True if loaded start scenes as server. + /// + private bool _loadedStartScenesAsServer; + /// + /// True if loaded start scenes as client. + /// + private bool _loadedStartScenesAsClient; + #endregion + #region Const. /// /// Value used when ClientId has not been set. @@ -169,7 +181,11 @@ namespace FishNet.Connection /// /// Maximum value a ClientId can be. /// - public const int MAXIMUM_CLIENTID_VALUE = (int.MaxValue - 1); + public const int MAXIMUM_CLIENTID_VALUE = int.MaxValue; + /// + /// Maximum value a ClientId can be excluding simulated value. + /// + public const int MAXIMUM_CLIENTID_WITHOUT_SIMULATED_VALUE = (int.MaxValue - 1); /// /// Value to use as a ClientId when simulating a local client without actually using a socket. /// @@ -177,7 +193,7 @@ namespace FishNet.Connection /// /// Number of bytes to reserve for a connectionId if writing the value uncompressed. /// - public const int CLIENTID_UNCOMPRESSED_RESERVE_BYTES = 4; + public const int CLIENTID_UNCOMPRESSED_RESERVE_LENGTH = 4; #endregion #region Comparers. @@ -228,11 +244,6 @@ namespace FishNet.Connection Initialize(manager, clientId, transportIndex, asServer); } - internal void Dispose() - { - Deinitialize(); - } - /// /// Outputs data about this connection as a string. /// @@ -271,40 +282,6 @@ namespace FishNet.Connection } } - /// - /// Deinitializes this NetworkConnection. This is called prior to resetting. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Deinitialize() - { - MatchCondition.RemoveFromMatchesWithoutRebuild(this, NetworkManager); - - foreach (PacketBundle p in _toClientBundles) - p.Dispose(); - _toClientBundles.Clear(); - - ServerConnectionTick = 0; - PacketTick.Reset(); - LocalTick.Reset(); - TransportIndex = -1; - ClientId = -1; - ClearObjects(); - IsAuthenticated = false; - NetworkManager = null; - _loadedStartScenesAsClient = false; - _loadedStartScenesAsServer = false; - SetDisconnecting(false); - Scenes.Clear(); - PredictedObjectIds.Clear(); - ResetPingPong(); - ResetStates_Lod(); - AllowedForcedLodUpdates = 0; - LastLevelOfDetailUpdate = 0; - LevelOfDetailInfractions = 0; - Observers_Reset(); - Prediction_Reset(); - } - /// /// Sets Disconnecting boolean for this connection. /// @@ -341,18 +318,6 @@ namespace FishNet.Connection ServerDirty(); } - private float _localTickUpdateTime = float.NegativeInfinity; - /// - /// Tries to update the LocalTick for this connection after a number of conditions are checked. - /// - internal void TryUpdateLocalTick(uint tick) - { - bool resetValue = (Time.time - _localTickUpdateTime) > 1f; - LocalTick.Update(tick, OldTickOption.Discard, resetValue); - if (resetValue) - _localTickUpdateTime = Time.time; - } - /// /// Returns if just loaded start scenes and sets them as loaded if not. /// @@ -468,6 +433,43 @@ namespace FishNet.Connection return Scenes.Remove(scene); } + /// + /// Resets all states for re-use. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ResetState() + { + MatchCondition.RemoveFromMatchesWithoutRebuild(this, NetworkManager); + + foreach (PacketBundle p in _toClientBundles) + p.Dispose(); + _toClientBundles.Clear(); + + ServerConnectionTick = 0; + PacketTick.Reset(); + LocalTick.Reset(); + TransportIndex = -1; + ClientId = -1; + ClearObjects(); + IsAuthenticated = false; + HasSentVersion = false; + NetworkManager = null; + _loadedStartScenesAsClient = false; + _loadedStartScenesAsServer = false; + SetDisconnecting(false); + Scenes.Clear(); + PredictedObjectIds.Clear(); + ResetPingPong(); + ResetStates_Lod(); + AllowedForcedLodUpdates = 0; + LastLevelOfDetailUpdate = 0; + LevelOfDetailInfractions = 0; + Observers_Reset(); + Prediction_Reset(); + } + + public void InitializeState() { } + } diff --git a/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs b/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs index bda157c..00440c9 100644 --- a/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs +++ b/Assets/FishNet/Runtime/Editor/PrefabCollectionGenerator/Generator.cs @@ -1,5 +1,6 @@ #if UNITY_EDITOR using FishNet.Configuring; +using FishNet.Managing; using FishNet.Managing.Object; using FishNet.Object; using System.Collections.Generic; @@ -437,7 +438,7 @@ namespace FishNet.Editing.PrefabCollectionGenerator /// /// Returns the DefaultPrefabObjects file. /// - private static DefaultPrefabObjects GetDefaultPrefabObjects(PrefabGeneratorConfigurations settings = null) + internal static DefaultPrefabObjects GetDefaultPrefabObjects(PrefabGeneratorConfigurations settings = null) { if (settings == null) settings = Configuration.Configurations.PrefabGenerator; @@ -605,37 +606,15 @@ namespace FishNet.Editing.PrefabCollectionGenerator _ranOnce = true; fullRebuild = true; } - else + //Other conditions which a full rebuild may be required. + else if (!fullRebuild) { - CheckForVersionFile(importedAssets); - CheckForVersionFile(deletedAssets); - CheckForVersionFile(movedAssets); - CheckForVersionFile(movedFromAssetPaths); - } - - /* See if any of the changed files are the version file. - * A new version file suggests an update. Granted, this could occur if - * other assets imported a new version file as well but better - * safe than sorry. */ - void CheckForVersionFile(string[] arr) - { - string targetText = "VERSION.txt".ToLower(); - int targetLength = targetText.Length; - - for (int i = 0; i < arr.Length; i++) + const string fishnetVersionSave = "fishnet_version"; + string savedVersion = EditorPrefs.GetString(fishnetVersionSave, string.Empty); + if (savedVersion != NetworkManager.FISHNET_VERSION) { - string item = arr[i]; - int itemLength = item.Length; - if (itemLength < targetLength) - continue; - - item = item.ToLower(); - int startIndex = (itemLength - targetLength); - if (item.Substring(startIndex, targetLength) == targetText) - { - fullRebuild = true; - return; - } + fullRebuild = true; + EditorPrefs.SetString(fishnetVersionSave, NetworkManager.FISHNET_VERSION); } } diff --git a/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs b/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs index f2d7cc8..108ee69 100644 --- a/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs +++ b/Assets/FishNet/Runtime/Editor/ScriptingDefines.cs @@ -53,6 +53,8 @@ namespace FishNet foreach (string item in fishNetDefines) modified |= definesHs.Add(item); + //Remove old prediction defines. + modified |= definesHs.Remove("PREDICTION_V2"); /* Remove pro define if not on pro. This might look a little * funny because the code below varies depending on if pro or not. */ diff --git a/Assets/FishNet/Runtime/FishNet.Runtime.asmdef b/Assets/FishNet/Runtime/FishNet.Runtime.asmdef index f5dbdb9..dc41020 100644 --- a/Assets/FishNet/Runtime/FishNet.Runtime.asmdef +++ b/Assets/FishNet/Runtime/FishNet.Runtime.asmdef @@ -3,7 +3,8 @@ "rootNamespace": "", "references": [ "GUID:894a6cc6ed5cd2645bb542978cbed6a9", - "GUID:1d82bdf40e2465b44b34adf79595e74c" + "GUID:1d82bdf40e2465b44b34adf79595e74c", + "GUID:d8b63aba1907145bea998dd612889d6b" ], "includePlatforms": [], "excludePlatforms": [], @@ -17,6 +18,21 @@ "name": "com.veriorpies.parrelsync", "expression": "1.2", "define": "PARRELSYNC" + }, + { + "name": "com.unity.mathematics", + "expression": "1.2.6", + "define": "UNITYMATHEMATICS" + }, + { + "name": "com.unity.mathematics", + "expression": "1.3.1", + "define": "UNITYMATHEMATICS_131" + }, + { + "name": "com.unity.mathematics", + "expression": "1.3.2", + "define": "UNITYMATHEMATICS_132" } ], "noEngineReferences": false diff --git a/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs b/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs index f171a2b..e3f0035 100644 --- a/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs +++ b/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/Editor/NetworkAnimatorEditor.cs @@ -14,7 +14,7 @@ namespace FishNet.Component.Animating.Editing { private SerializedProperty _animator; private SerializedProperty _interpolation; - //private SerializedProperty _synchronizeInterval; + private SerializedProperty _synchronizeWhenDisabled; private SerializedProperty _smoothFloats; private SerializedProperty _clientAuthoritative; private SerializedProperty _sendToOwner; @@ -23,13 +23,13 @@ namespace FishNet.Component.Animating.Editing protected virtual void OnEnable() { - _animator = serializedObject.FindProperty("_animator"); - _interpolation = serializedObject.FindProperty("_interpolation"); - //_synchronizeInterval = serializedObject.FindProperty("_synchronizeInterval"); - _smoothFloats = serializedObject.FindProperty("_smoothFloats"); + _animator = serializedObject.FindProperty(nameof(_animator)); + _interpolation = serializedObject.FindProperty(nameof(_interpolation)); + _synchronizeWhenDisabled = serializedObject.FindProperty(nameof(_synchronizeWhenDisabled)); + _smoothFloats = serializedObject.FindProperty(nameof(_smoothFloats)); - _clientAuthoritative = serializedObject.FindProperty("_clientAuthoritative"); - _sendToOwner = serializedObject.FindProperty("_sendToOwner"); + _clientAuthoritative = serializedObject.FindProperty(nameof(_clientAuthoritative)); + _sendToOwner = serializedObject.FindProperty(nameof(_sendToOwner)); } public override void OnInspectorGUI() @@ -50,6 +50,7 @@ namespace FishNet.Component.Animating.Editing EditorGUILayout.LabelField("Animator", EditorStyles.boldLabel); EditorGUI.indentLevel++; EditorGUILayout.PropertyField(_animator); + EditorGUILayout.PropertyField(_synchronizeWhenDisabled); EditorGUI.indentLevel--; EditorGUILayout.Space(); @@ -57,7 +58,6 @@ namespace FishNet.Component.Animating.Editing EditorGUILayout.LabelField("Synchronization Processing", EditorStyles.boldLabel); EditorGUI.indentLevel++; EditorGUILayout.PropertyField(_interpolation); - //EditorGUILayout.PropertyField(_synchronizeInterval, new GUIContent("Synchronize Interval", "How often to synchronize this animator.")); EditorGUILayout.PropertyField(_smoothFloats); EditorGUI.indentLevel--; EditorGUILayout.Space(); diff --git a/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs b/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs index 3648a18..b1db921 100644 --- a/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs +++ b/Assets/FishNet/Runtime/Generated/Component/NetworkAnimator/NetworkAnimator.cs @@ -1,3 +1,6 @@ +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif using FishNet.Component.Transforming; using FishNet.Connection; using FishNet.Documenting; @@ -285,6 +288,12 @@ namespace FishNet.Component.Animating /// public Animator Animator { get { return _animator; } } /// + /// True to synchronize changes even when the animator component is disabled. + /// + [Tooltip("True to synchronize changes even when the animator component is disabled.")] + [SerializeField] + private bool _synchronizeWhenDisabled; + /// /// True to smooth float value changes for spectators. /// [Tooltip("True to smooth float value changes for spectators.")] @@ -297,13 +306,6 @@ namespace FishNet.Component.Animating [Range(1, NetworkTransform.MAX_INTERPOLATION)] [SerializeField] private ushort _interpolation = 2; - ///// - ///// How often to synchronize this animator. - ///// - //[Tooltip("How often to synchronize this animator.")] - //[Range(0.01f, 0.5f)] - //[SerializeField] - //private float _synchronizeInterval = 0.1f; /// /// /// @@ -356,13 +358,25 @@ namespace FishNet.Component.Animating /// private List _toClientsBuffer = new List(); /// - /// Returns if the animator is exist and is active. + /// Returns if the animator is exist and can be synchronized. /// - private bool _isAnimatorEnabled + private bool _canSynchronizeAnimator { get { - bool failedChecks = (_animator == null || !_animator.enabled || _animator.runtimeAnimatorController == null); + bool enabled = (_animator.enabled || _synchronizeWhenDisabled); + bool failedChecks = (!_isAnimatorSet || !enabled); + return !failedChecks; + } + } + /// + /// True if the animator is valid but not enabled. + /// + private bool _isAnimatorSet + { + get + { + bool failedChecks = (_animator == null || _animator.runtimeAnimatorController == null); return !failedChecks; } } @@ -396,10 +410,6 @@ namespace FishNet.Component.Animating /// private Dictionary _unsynchronizedLayerStates = new Dictionary(); /// - /// Layers which need to have their state blend synchronized. Key is ParameterIndex, Value is next state hash. - /// - //private Dictionary _unsynchronizedLayerStates = new HashSet(); - /// /// Last animator set. /// private Animator _lastAnimator; @@ -469,7 +479,7 @@ namespace FishNet.Component.Animating [APIExclude] public override void OnSpawnServer(NetworkConnection connection) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; if (AnimatorUpdated(out ArraySegment updatedBytes, true)) TargetAnimatorUpdated(connection, updatedBytes); @@ -531,7 +541,7 @@ namespace FishNet.Component.Animating /// private void TimeManager_OnPreTick() { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) { _fromServerBuffer.Clear(); return; @@ -565,7 +575,7 @@ namespace FishNet.Component.Animating private void TimeManager_OnPostTick() { //One check rather than per each method. - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; CheckSendToServer(); @@ -574,7 +584,7 @@ namespace FishNet.Component.Animating private void Update() { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; if (base.IsClientStarted) @@ -593,7 +603,7 @@ namespace FishNet.Component.Animating if (!ApplicationState.IsPlaying()) return; - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) { //Debug.LogWarning("Animator is null or not enabled; unable to initialize for animator. Use SetAnimator if animator was changed or enable the animator."); return; @@ -1025,7 +1035,7 @@ namespace FishNet.Component.Animating /// private void ApplyParametersUpdated(ref ArraySegment updatedParameters) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; if (_layerWeights == null) return; @@ -1153,7 +1163,7 @@ namespace FishNet.Component.Animating stateHash = 0; normalizedTime = 0f; - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return false; AnimatorStateInfo st = _animator.GetCurrentAnimatorStateInfo(layerIndex); @@ -1214,7 +1224,7 @@ namespace FishNet.Component.Animating /// public void Play(int hash, int layer, float normalizedTime) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; if (_animator.HasState(layer, hash) || hash == 0) { @@ -1249,7 +1259,7 @@ namespace FishNet.Component.Animating /// public void PlayInFixedTime(int hash, int layer, float fixedTime) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; if (_animator.HasState(layer, hash) || hash == 0) { @@ -1282,7 +1292,7 @@ namespace FishNet.Component.Animating /// public void CrossFade(int hash, float normalizedTransitionDuration, int layer, float normalizedTimeOffset = 0.0f, float normalizedTransitionTime = 0.0f) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; if (_animator.HasState(layer, hash) || hash == 0) { @@ -1312,7 +1322,7 @@ namespace FishNet.Component.Animating /// public void CrossFadeInFixedTime(int hash, float fixedTransitionDuration, int layer, float fixedTimeOffset = 0.0f, float normalizedTransitionTime = 0.0f) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; if (_animator.HasState(layer, hash) || hash == 0) { @@ -1329,7 +1339,7 @@ namespace FishNet.Component.Animating /// public void SetTrigger(int hash) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; UpdateTrigger(hash, true); } @@ -1365,7 +1375,7 @@ namespace FishNet.Component.Animating /// private void UpdateTrigger(int hash, bool set) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; bool clientAuth = ClientAuthoritative; @@ -1422,12 +1432,12 @@ namespace FishNet.Component.Animating [TargetRpc(ValidateTarget = false)] private void TargetAnimatorUpdated(NetworkConnection connection, ArraySegment data) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; -#if DEVELOPMENT +#if !DEVELOPMENT //If receiver is client host then do nothing, clientHost need not process. - if (base.IsServer && conn.IsLocalClient) + if (base.IsServerInitialized && connection.IsLocalClient) return; #endif bool clientAuth = ClientAuthoritative; @@ -1457,7 +1467,7 @@ namespace FishNet.Component.Animating [ServerRpc] private void ServerAnimatorUpdated(ArraySegment data) { - if (!_isAnimatorEnabled) + if (!_canSynchronizeAnimator) return; if (!ClientAuthoritative) { diff --git a/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs b/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs index aaeb7ca..5183efb 100644 --- a/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs +++ b/Assets/FishNet/Runtime/Generated/Component/NetworkTransform/NetworkTransform.cs @@ -336,6 +336,10 @@ namespace FishNet.Component.Transforming /// True if the local client used TakeOwnership and is awaiting an ownership change. /// public bool TakenOwnership { get; private set; } + /// + /// NetworkBehaviour this transform is a child of. + /// + public NetworkBehaviour ParentBehaviour { get; private set; } #endregion #region Serialized. @@ -519,10 +523,6 @@ namespace FishNet.Component.Transforming /// private bool _lastReceiveReliable = true; /// - /// NetworkBehaviour this transform is a child of. - /// - private NetworkBehaviour _parentBehaviour; - /// /// Last transform which this object was a child of. /// private Transform _parentTransform; @@ -1098,7 +1098,7 @@ namespace FishNet.Component.Transforming else { _parentTransform = transform.parent; - _parentBehaviour = parentBehaviour; + ParentBehaviour = parentBehaviour; } } } @@ -1297,10 +1297,10 @@ namespace FishNet.Component.Transforming } //Childed. - if (ChangedContains(changed, ChangedDelta.Childed) && _parentBehaviour != null) + if (ChangedContains(changed, ChangedDelta.Childed) && ParentBehaviour != null) { flagsB |= UpdateFlagB.Child; - writer.WriteNetworkBehaviour(_parentBehaviour); + writer.WriteNetworkBehaviour(ParentBehaviour); } writer.FastInsertByte((byte)flagsB, startIndexB); @@ -1459,7 +1459,7 @@ namespace FishNet.Component.Transforming if (base.NetworkObject.RuntimeParentNetworkBehaviour != null) Debug.LogWarning($"{gameObject.name} parent object was removed without calling UnsetParent. Use networkObject.UnsetParent() to remove a NetworkObject from it's parent. This is being made a requirement in Fish-Networking v4."); - _parentBehaviour = null; + ParentBehaviour = null; _parentTransform = null; } //Has a parent, see if eligible. @@ -1470,15 +1470,18 @@ namespace FishNet.Component.Transforming return; _parentTransform = parent; - parent.TryGetComponent(out _parentBehaviour); - if (_parentBehaviour == null) + NetworkBehaviour outParentBehaviour; + + if (!parent.TryGetComponent(out outParentBehaviour)) { + ParentBehaviour = null; LogInvalidParent(); } else { + ParentBehaviour = outParentBehaviour; //Check for being set without using nob.SetParent. - if (base.NetworkObject.CurrentParentNetworkBehaviour != _parentBehaviour) + if (base.NetworkObject.CurrentParentNetworkBehaviour != ParentBehaviour) Debug.LogWarning($"{gameObject.name} parent was set without calling SetParent. Use networkObject.SetParent(obj) to assign a NetworkObject a new parent. This is being made a requirement in Fish-Networking v4."); } } @@ -1689,7 +1692,7 @@ namespace FishNet.Component.Transforming Transform t = transform; /* If here a send for transform values will occur. Update last values. * Tick doesn't need to be set for whoever controls transform. */ - lastSentData.Update(0, t.localPosition, t.localRotation, t.localScale, t.localPosition, _parentBehaviour); + lastSentData.Update(0, t.localPosition, t.localRotation, t.localScale, t.localPosition, ParentBehaviour); SerializeChanged(changed, writer, lodIndex); } @@ -1764,7 +1767,7 @@ namespace FishNet.Component.Transforming /* If here a send for transform values will occur. Update last values. * Tick doesn't need to be set for whoever controls transform. */ Transform t = transform; - lastSentTransformData.Update(0, t.localPosition, t.localRotation, t.localScale, t.localPosition, _parentBehaviour); + lastSentTransformData.Update(0, t.localPosition, t.localRotation, t.localScale, t.localPosition, ParentBehaviour); //Send latest. PooledWriter writer = WriterPool.Retrieve(); @@ -1876,7 +1879,7 @@ namespace FishNet.Component.Transforming changed |= ChangedDelta.ScaleZ; //if (lastParentBehaviour != _parentBehaviour) - if (_parentBehaviour != null) + if (ParentBehaviour != null) changed |= ChangedDelta.Childed; //If added scale or childed then also add extended. @@ -2271,7 +2274,6 @@ namespace FishNet.Component.Transforming { SetCalculatedRates(lodIndex, prevTd, prevRd, nextGd, changedFull, hasChanged, channel, asServer); } - prevTd.Update(nextTd); _lastReceiveReliable = (channel == Channel.Reliable); /* If channel is reliable then this is a settled packet. diff --git a/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollider.cs b/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollider.cs index e107ae8..e4aaa5f 100644 --- a/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollider.cs +++ b/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollider.cs @@ -59,16 +59,25 @@ namespace FishNet.Component.Prediction [HideInInspector] protected bool IsTrigger; /// - /// The maximum number of simultaneous hits to check for. + /// Maximum number of simultaneous hits to check for. Larger values decrease performance but allow detection to work for more overlapping colliders. Typically the default value of 16 is more than sufficient. /// + [Tooltip("Maximum number of simultaneous hits to check for. Larger values decrease performance but allow detection to work for more overlapping colliders. Typically the default value of 16 is more than sufficient.")] [SerializeField] private ushort _maximumSimultaneousHits = 16; - /// - /// The duration of the history. + /// How long of collision history to keep. Lower values will result in marginally better memory usage at the cost of collision histories desynchronizing on clients with excessive latency. /// + [Tooltip("How long of collision history to keep. Lower values will result in marginally better memory usage at the cost of collision histories desynchronizing on clients with excessive latency.")] + [Range(0.1f, 2f)] [SerializeField] private float _historyDuration = 0.5f; + /// + /// Units to extend collision traces by. This is used to prevent missed overlaps when colliders do not intersect enough. + /// + [Tooltip("Units to extend collision traces by. This is used to prevent missed overlaps when colliders do not intersect enough.")] + [Range(0f, 100f)] + [SerializeField] + private float _additionalSize = 0.1f; /// /// The colliders on this object. @@ -102,7 +111,8 @@ namespace FishNet.Component.Prediction protected virtual void Awake() { - _colliderDataHistory = ResettableCollectionCaches.RetrieveRingBuffer(); + //_colliderDataHistory = ResettableCollectionCaches.RetrieveRingBuffer(); + _colliderDataHistory = new(); _hits = CollectionCaches.RetrieveArray(); if (_hits.Length < _maximumSimultaneousHits) _hits = new Collider[_maximumSimultaneousHits]; @@ -110,8 +120,8 @@ namespace FishNet.Component.Prediction private void OnDestroy() { - ResettableCollectionCaches.StoreAndDefault(ref _colliderDataHistory); - CollectionCaches.StoreAndDefault(ref _hits, -_hits.Length); + //ResettableCollectionCaches.StoreAndDefault(ref _colliderDataHistory); + CollectionCaches.StoreAndDefault(ref _hits, _hits.Length); } public override void OnStartNetwork() @@ -193,7 +203,7 @@ namespace FishNet.Component.Prediction /// /// Units to extend collision traces by. This is used to prevent missed overlaps when colliders do not intersect enough. /// - public virtual float GetAdditionalSize() => 0f; + public virtual float GetAdditionalSize() => _additionalSize; /// /// Checks for any trigger changes; @@ -416,7 +426,7 @@ namespace FishNet.Component.Prediction { sphereCollider.GetSphereOverlapParams(out Vector3 center, out float radius); radius += GetAdditionalSize(); - return Physics.OverlapSphereNonAlloc(center, radius, _hits, layerMask); + return gameObject.scene.GetPhysicsScene().OverlapSphere(center, radius, _hits, layerMask, QueryTriggerInteraction.UseGlobal); } /// @@ -427,7 +437,7 @@ namespace FishNet.Component.Prediction { capsuleCollider.GetCapsuleCastParams(out Vector3 start, out Vector3 end, out float radius); radius += GetAdditionalSize(); - return Physics.OverlapCapsuleNonAlloc(start, end, radius, _hits, layerMask); + return gameObject.scene.GetPhysicsScene().OverlapCapsule(start, end, radius, _hits, layerMask, QueryTriggerInteraction.UseGlobal); } /// @@ -440,7 +450,7 @@ namespace FishNet.Component.Prediction boxCollider.GetBoxOverlapParams(out Vector3 center, out Vector3 halfExtents); Vector3 additional = (Vector3.one * GetAdditionalSize()); halfExtents += additional; - return Physics.OverlapBoxNonAlloc(center, halfExtents, _hits, rotation, layerMask); + return gameObject.scene.GetPhysicsScene().OverlapBox(center, halfExtents, _hits, rotation, layerMask, QueryTriggerInteraction.UseGlobal); } /// diff --git a/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollider2D.cs b/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollider2D.cs index a4aa95d..3f82896 100644 --- a/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollider2D.cs +++ b/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollider2D.cs @@ -59,16 +59,25 @@ namespace FishNet.Component.Prediction [HideInInspector] protected bool IsTrigger; /// - /// The maximum number of simultaneous hits to check for. + /// Maximum number of simultaneous hits to check for. Larger values decrease performance but allow detection to work for more overlapping colliders. Typically the default value of 16 is more than sufficient. /// + [Tooltip("Maximum number of simultaneous hits to check for. Larger values decrease performance but allow detection to work for more overlapping colliders. Typically the default value of 16 is more than sufficient.")] [SerializeField] private ushort _maximumSimultaneousHits = 16; - /// - /// The duration of the history. + /// How long of collision history to keep. Lower values will result in marginally better memory usage at the cost of collision histories desynchronizing on clients with excessive latency. /// + [Tooltip("How long of collision history to keep. Lower values will result in marginally better memory usage at the cost of collision histories desynchronizing on clients with excessive latency.")] + [Range(0.1f, 2f)] [SerializeField] private float _historyDuration = 0.5f; + /// + /// Units to extend collision traces by. This is used to prevent missed overlaps when colliders do not intersect enough. + /// + [Tooltip("Units to extend collision traces by. This is used to prevent missed overlaps when colliders do not intersect enough.")] + [Range(0f, 100f)] + [SerializeField] + private float _additionalSize = 0.1f; /// /// The colliders on this object. @@ -102,7 +111,8 @@ namespace FishNet.Component.Prediction protected virtual void Awake() { - _colliderDataHistory = ResettableCollectionCaches.RetrieveRingBuffer(); + _colliderDataHistory = new(); + //_colliderDataHistory = ResettableCollectionCaches.RetrieveRingBuffer(); _hits = CollectionCaches.RetrieveArray(); if (_hits.Length < _maximumSimultaneousHits) _hits = new Collider2D[_maximumSimultaneousHits]; @@ -110,8 +120,8 @@ namespace FishNet.Component.Prediction private void OnDestroy() { - ResettableCollectionCaches.StoreAndDefault(ref _colliderDataHistory); - CollectionCaches.StoreAndDefault(ref _hits, -_hits.Length); + //ResettableCollectionCaches.StoreAndDefault(ref _colliderDataHistory); + CollectionCaches.StoreAndDefault(ref _hits, _hits.Length); } public override void OnStartNetwork() @@ -205,11 +215,11 @@ namespace FishNet.Component.Prediction } } + /// - /// Returns the size multiplier. + /// Units to extend collision traces by. This is used to prevent missed overlaps when colliders do not intersect enough. /// - /// - protected virtual float GetSizeMultiplier() => 1f; + protected virtual float GetAdditionalSize() => _additionalSize; /// /// Checks for any trigger changes; @@ -429,8 +439,8 @@ namespace FishNet.Component.Prediction private int GetCircleCollider2DHits(CircleCollider2D circleCollider, int layerMask) { circleCollider.GetCircleOverlapParams(out Vector3 center, out float radius); - radius *= GetSizeMultiplier(); - return Physics2D.OverlapCircleNonAlloc(center, radius, _hits, layerMask); + radius += GetAdditionalSize(); + return gameObject.scene.GetPhysicsScene2D().OverlapCircle(center, radius, _hits, layerMask); } /// @@ -440,8 +450,9 @@ namespace FishNet.Component.Prediction private int GetBoxCollider2DHits(BoxCollider2D boxCollider, Quaternion rotation, int layerMask) { boxCollider.GetBox2DOverlapParams(out Vector3 center, out Vector3 halfExtents); - halfExtents *= GetSizeMultiplier(); - return Physics2D.OverlapBoxNonAlloc(center, halfExtents, rotation.z, _hits, layerMask); + Vector3 additional = (Vector3.one * GetAdditionalSize()); + halfExtents += additional; + return gameObject.scene.GetPhysicsScene2D().OverlapBox(center, halfExtents, rotation.z, _hits, layerMask); } /// diff --git a/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollision.cs b/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollision.cs index 2b10512..be50af9 100644 --- a/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollision.cs +++ b/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollision.cs @@ -5,21 +5,11 @@ namespace FishNet.Component.Prediction public sealed class NetworkCollision : NetworkCollider { #if !PREDICTION_1 - [Tooltip("Units to extend collision traces by. This is used to prevent missed overlaps when colliders do not intersect enough.")] - [Range(0f, 100f)] - [SerializeField] - private float _additionalSize = 0.1f; - protected override void Awake() { base.IsTrigger = false; base.Awake(); } - - /// - /// Units to extend collision traces by. This is used to prevent missed overlaps when colliders do not intersect enough. - /// - public override float GetAdditionalSize() => _additionalSize; #endif } diff --git a/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollision2D.cs b/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollision2D.cs index 765910c..c690895 100644 --- a/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollision2D.cs +++ b/Assets/FishNet/Runtime/Generated/Component/Prediction/NetworkCollision2D.cs @@ -5,22 +5,11 @@ namespace FishNet.Component.Prediction public sealed class NetworkCollision2D : NetworkCollider2D { #if !PREDICTION_1 - - /// - /// Percentage larger than each collider for each overlap test. This is used to prevent missed overlaps when colliders do not intersect enough. - /// - [Tooltip("Percentage larger than each collider for each overlap test. This is used to prevent missed overlaps when colliders do not intersect enough.")] - [Range(0f, 0.2f)] - [SerializeField] - private float _sizeMultiplier = 0.05f; - protected override void Awake() { base.IsTrigger = false; base.Awake(); } - - protected override float GetSizeMultiplier() => (1f + _sizeMultiplier); #endif } diff --git a/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs b/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs index 070e3e6..c940aa9 100644 --- a/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs +++ b/Assets/FishNet/Runtime/Generated/Component/Prediction/PredictedObject.cs @@ -280,7 +280,7 @@ namespace FishNet.Component.Prediction /* If host then initialize owner smoother. * Host will use owner smoothing settings for more * accurate results. */ - if (base.IsHostInitialized) + if (base.IsHostStarted) InitializeSmoother(true); UpdateRigidbodiesCount(true); diff --git a/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyPauser.cs b/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyPauser.cs index 6ae28b3..f8bfdd3 100644 --- a/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyPauser.cs +++ b/Assets/FishNet/Runtime/Generated/Component/Prediction/RigidbodyPauser.cs @@ -245,7 +245,7 @@ namespace FishNet.Component.Prediction _rigidbodyDatas[index] = rbData; rb.collisionDetectionMode = CollisionDetectionMode.Discrete; rb.isKinematic = true; - rb.detectCollisions = false; + //rb.detectCollisions = false; return true; } @@ -313,7 +313,7 @@ namespace FishNet.Component.Prediction return false; rb.isKinematic = rbData.IsKinematic; - rb.detectCollisions = rbData.DetectCollisions; + //rb.detectCollisions = rbData.DetectCollisions; rb.collisionDetectionMode = rbData.CollisionDetectionMode; if (!rb.isKinematic) { diff --git a/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs b/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs index 8afc489..a54d0cc 100644 --- a/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs +++ b/Assets/FishNet/Runtime/Managing/Client/ClientManager.cs @@ -1,4 +1,7 @@ -using FishNet.Connection; +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +using FishNet.Connection; using FishNet.Managing.Debugging; using FishNet.Managing.Logging; using FishNet.Managing.Server; @@ -23,6 +26,11 @@ namespace FishNet.Managing.Client { #region Public. /// + /// This is set true if the server has notified the client it is using a development build. + /// Value is set before authentication. + /// + public bool IsServerDevelopment { get; private set; } + /// /// Called after local client has authenticated. /// public event Action OnAuthenticated; @@ -127,7 +135,7 @@ namespace FishNet.Managing.Client /// Used to read splits. /// private SplitReader _splitReader = new SplitReader(); -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT /// /// Logs data about parser to help debug. /// @@ -179,7 +187,7 @@ namespace FishNet.Managing.Client OnRemoteConnectionState?.Invoke(rcs); if (Clients.TryGetValue(args.Id, out NetworkConnection c)) { - c.Dispose(); + c.ResetState(); Clients.Remove(args.Id); } } @@ -304,6 +312,12 @@ namespace FishNet.Managing.Client else { _lastPacketTime = Time.unscaledTime; + //Send version. + PooledWriter writer = WriterPool.Retrieve(); + writer.WritePacketId(PacketId.Version); + writer.WriteString(NetworkManager.FISHNET_VERSION); + NetworkManager.TransportManager.SendToServer((byte)Channel.Reliable, writer.GetArraySegment()); + WriterPool.Store(writer); } if (NetworkManager.CanLog(LoggingType.Common)) @@ -349,7 +363,7 @@ namespace FishNet.Managing.Client /// private void ParseReceived(ClientReceivedDataArgs args) { -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT _parseLogger.Reset(); #endif _lastPacketTime = Time.unscaledTime; @@ -361,7 +375,7 @@ namespace FishNet.Managing.Client segment = args.Data; NetworkManager.StatisticsManager.NetworkTraffic.LocalClientReceivedData((ulong)segment.Count); - if (segment.Count <= TransportManager.TICK_BYTES) + if (segment.Count <= TransportManager.UNPACKED_TICK_LENGTH) return; PooledReader reader = ReaderPool.Retrieve(segment, NetworkManager, Reader.DataSource.Server); @@ -375,7 +389,7 @@ namespace FishNet.Managing.Client internal void ParseReader(PooledReader reader, Channel channel, bool print = false) { PacketId packetId = PacketId.Unset; -#if !UNITY_EDITOR && !DEVELOPMENT_BUILD +#if !DEVELOPMENT try { #endif @@ -404,7 +418,7 @@ namespace FishNet.Managing.Client while (reader.Remaining > 0) { packetId = reader.ReadPacketId(); -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (print) Debug.Log($"PacketId {packetId} - Remaining {reader.Remaining}."); _parseLogger.AddPacket(packetId); @@ -480,7 +494,7 @@ namespace FishNet.Managing.Client } else if (packetId == PacketId.TimingUpdate) { - NetworkManager.TimeManager.ParseTimingUpdate(); + NetworkManager.TimeManager.ParseTimingUpdate(reader); } else if (packetId == PacketId.OwnershipChange) { @@ -495,18 +509,22 @@ namespace FishNet.Managing.Client reader.Clear(); StopConnection(); } + else if (packetId == PacketId.Version) + { + ParseVersion(reader); + } else { NetworkManager.LogError($"Client received an unhandled PacketId of {(ushort)packetId} on channel {channel}. Remaining data has been purged."); -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT _parseLogger.Print(NetworkManager); #endif return; } } -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (print) Debug.Log($"Reader remaining {reader.Remaining}"); #endif @@ -519,7 +537,7 @@ namespace FishNet.Managing.Client * in doing this check multiple times as there's * an exit early check. */ Objects.IterateObjectCache(); -#if !UNITY_EDITOR && !DEVELOPMENT_BUILD +#if !DEVELOPMENT } catch (Exception e) { @@ -539,6 +557,17 @@ namespace FishNet.Managing.Client NetworkManager.TimeManager.ModifyPing(clientTick); } + + /// + /// Parses a Version packet. + /// + /// + private void ParseVersion(PooledReader reader) + { + IsServerDevelopment = reader.ReadBoolean(); + } + + /// /// Parses a received connectionId. This is received before client receives connection state change. /// @@ -578,7 +607,7 @@ namespace FishNet.Managing.Client } //If predicted spawning is enabled also get reserved Ids. - if (NetworkManager.PredictionManager.GetAllowPredictedSpawning()) + if (NetworkManager.ServerManager.GetAllowPredictedSpawning()) { byte count = reader.ReadByte(); Queue q = Connection.PredictedObjectIds; @@ -629,7 +658,7 @@ namespace FishNet.Managing.Client return; if (_remoteServerTimeout == RemoteTimeoutType.Disabled) return; -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT //If development but not set to development return. else if (_remoteServerTimeout != RemoteTimeoutType.Development) return; diff --git a/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs b/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs index 4a4f37c..c2fa7ed 100644 --- a/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs +++ b/Assets/FishNet/Runtime/Managing/Client/Object/ClientObjects.cs @@ -94,7 +94,7 @@ namespace FishNet.Managing.Client { foreach (NetworkObject n in Spawned.Values) { - n.InvokeStopCallbacks(false); + n.InvokeStopCallbacks(false, true); n.SetInitializedStatus(false, false); } } @@ -434,8 +434,9 @@ namespace FishNet.Managing.Client if (sceneObject) { ReadSceneObject(reader, out sceneId); -#if UNITY_EDITOR || DEVELOPMENT_BUILD - base.CheckReadSceneObjectDetails(reader, ref sceneName, ref objectName); +#if DEVELOPMENT + if (NetworkManager.ClientManager.IsServerDevelopment) + base.CheckReadSceneObjectDetails(reader, ref sceneName, ref objectName); #endif } else diff --git a/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs b/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs index 6f8e6cf..8a082d9 100644 --- a/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs +++ b/Assets/FishNet/Runtime/Managing/Client/Object/ObjectCaching.cs @@ -578,7 +578,7 @@ namespace FishNet.Managing.Client public Quaternion? LocalRotation; public Vector3? LocalScale; public ulong SceneId; -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT public string SceneName = string.Empty; public string ObjectName = string.Empty; #endif @@ -626,7 +626,7 @@ namespace FishNet.Managing.Client LocalRotation = localRotation; LocalScale = localScale; SceneId = sceneId; -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT SceneName = sceneName; ObjectName = objectName; #endif diff --git a/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs b/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs index 558cfdb..519922e 100644 --- a/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs +++ b/Assets/FishNet/Runtime/Managing/Debugging/ParseLogger.cs @@ -1,4 +1,7 @@ #if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +#if DEVELOPMENT using FishNet.Managing.Logging; using FishNet.Object; using FishNet.Serializing; diff --git a/Assets/FishNet/Runtime/Managing/Logging/LevelLoggingConfiguration.cs b/Assets/FishNet/Runtime/Managing/Logging/LevelLoggingConfiguration.cs index dc83b59..27ccc45 100644 --- a/Assets/FishNet/Runtime/Managing/Logging/LevelLoggingConfiguration.cs +++ b/Assets/FishNet/Runtime/Managing/Logging/LevelLoggingConfiguration.cs @@ -1,4 +1,7 @@ -using FishNet.Documenting; +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +using FishNet.Documenting; using System; using System.Runtime.CompilerServices; using UnityEngine; @@ -61,13 +64,11 @@ namespace FishNet.Managing.Logging public override void InitializeOnce() { byte currentHighest = (byte)LoggingType.Off; -#if UNITY_SERVER //if headless. +#if UNITY_SERVER currentHighest = Math.Max(currentHighest, (byte)_headlessLogging); -#endif -#if UNITY_EDITOR || DEVELOPMENT_BUILD //if editor or development. +#elif DEVELOPMENT currentHighest = Math.Max(currentHighest, (byte)_developmentLogging); -#endif -#if !UNITY_EDITOR && !UNITY_SERVER //if a build. +#else currentHighest = Math.Max(currentHighest, (byte)_guiLogging); #endif _highestLoggingType = (LoggingType)currentHighest; @@ -86,7 +87,7 @@ namespace FishNet.Managing.Logging if (!_initialized) { -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (Application.isPlaying) Debug.LogError("CanLog called before being initialized."); else diff --git a/Assets/FishNet/Runtime/Managing/NetworkManager.cs b/Assets/FishNet/Runtime/Managing/NetworkManager.cs index 0d6706c..d0b9775 100644 --- a/Assets/FishNet/Runtime/Managing/NetworkManager.cs +++ b/Assets/FishNet/Runtime/Managing/NetworkManager.cs @@ -23,8 +23,10 @@ using FishNet.Component.ColliderRollback; using FishNet.Managing.Predicting; using System.Runtime.CompilerServices; using GameKit.Dependencies.Utilities; + #if UNITY_EDITOR using FishNet.Editing.PrefabCollectionGenerator; +using UnityEditor; #endif namespace FishNet.Managing @@ -191,6 +193,10 @@ namespace FishNet.Managing #region Const. /// + /// Version of this release. + /// + public const string FISHNET_VERSION = "4.3.1"; + /// /// Maximum framerate allowed. /// internal const ushort MAXIMUM_FRAMERATE = 500; @@ -393,6 +399,19 @@ namespace FishNet.Managing //If null and object is in a scene. if (SpawnablePrefabs == null && !string.IsNullOrEmpty(gameObject.scene.name)) { + //First try to fetch the file, only if editor and not in play mode. +#if UNITY_EDITOR + if (!ApplicationState.IsPlaying()) + { + SpawnablePrefabs = Generator.GetDefaultPrefabObjects(); + if (SpawnablePrefabs != null) + { + Debug.Log($"SpawnablePrefabs was set to DefaultPrefabObjects automatically on object {gameObject.name} in scene {gameObject.scene.name}."); + EditorUtility.SetDirty(this); + return true; + } + } +#endif //Always throw an error as this would cause failure. if (print) Debug.LogError($"SpawnablePrefabs is null on {gameObject.name}. Select the NetworkManager in scene {gameObject.scene.name} and choose a prefabs file. Choosing DefaultPrefabObjects will automatically populate prefabs for you."); @@ -455,13 +474,13 @@ namespace FishNet.Managing if (value.TransportIndex == transportIndex) { cache.Add(kvp.Key); - value.Dispose(); + value.ResetState(); } } //Not using transport index, no check required. else { - value.Dispose(); + value.ResetState(); } } diff --git a/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.Spawning.cs b/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.Spawning.cs index 757d48c..f9ad227 100644 --- a/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.Spawning.cs +++ b/Assets/FishNet/Runtime/Managing/Object/ManagedObjects.Spawning.cs @@ -24,19 +24,19 @@ namespace FishNet.Managing.Object protected void ReadTransformProperties(Reader reader, out Vector3? localPosition, out Quaternion? localRotation, out Vector3? localScale) { //Read changed. - ChangedTransformProperties ctp = (ChangedTransformProperties)reader.ReadByte(); + TransformPropertiesFlag tpf = (TransformPropertiesFlag)reader.ReadByte(); //Position. - if (ChangedTransformPropertiesEnum.Contains(ctp, ChangedTransformProperties.LocalPosition)) + if (tpf.FastContains(TransformPropertiesFlag.Position)) localPosition = reader.ReadVector3(); else localPosition = null; //Rotation. - if (ChangedTransformPropertiesEnum.Contains(ctp, ChangedTransformProperties.LocalRotation)) + if (tpf.FastContains(TransformPropertiesFlag.Rotation)) localRotation = reader.ReadQuaternion(NetworkManager.ServerManager.SpawnPacking.Rotation); else localRotation = null; //Scale. - if (ChangedTransformPropertiesEnum.Contains(ctp, ChangedTransformProperties.LocalScale)) + if (tpf.FastContains(TransformPropertiesFlag.LocalScale)) localScale = reader.ReadVector3(); else localScale = null; @@ -213,28 +213,28 @@ namespace FishNet.Managing.Object protected void WriteChangedTransformProperties(NetworkObject nob, bool sceneObject, bool nested, Writer headerWriter) { /* Write changed transform properties. */ - ChangedTransformProperties ctp; + TransformPropertiesFlag tpf; //If a scene object then get it from scene properties. if (sceneObject || nested) { - ctp = nob.GetTransformChanges(nob.SerializedTransformProperties); + tpf = nob.GetTransformChanges(nob.SerializedTransformProperties); } else { PrefabObjects po = NetworkManager.GetPrefabObjects(nob.SpawnableCollectionId, false); - ctp = nob.GetTransformChanges(po.GetObject(true, nob.PrefabId).gameObject); + tpf = nob.GetTransformChanges(po.GetObject(true, nob.PrefabId).gameObject); } - headerWriter.WriteByte((byte)ctp); + headerWriter.WriteByte((byte)tpf); //If properties have changed. - if (ctp != ChangedTransformProperties.Unset) + if (tpf != TransformPropertiesFlag.Unset) { //Write any changed properties. - if (ChangedTransformPropertiesEnum.Contains(ctp, ChangedTransformProperties.LocalPosition)) + if (tpf.FastContains(TransformPropertiesFlag.Position)) headerWriter.WriteVector3(nob.transform.localPosition); - if (ChangedTransformPropertiesEnum.Contains(ctp, ChangedTransformProperties.LocalRotation)) + if (tpf.FastContains(TransformPropertiesFlag.Rotation)) headerWriter.WriteQuaternion(nob.transform.localRotation, NetworkManager.ServerManager.SpawnPacking.Rotation); - if (ChangedTransformPropertiesEnum.Contains(ctp, ChangedTransformProperties.LocalScale)) + if (tpf.FastContains(TransformPropertiesFlag.LocalScale)) headerWriter.WriteVector3(nob.transform.localScale); } diff --git a/Assets/FishNet/Runtime/Managing/Prediction/Editor/PredictionManagerEditor.cs b/Assets/FishNet/Runtime/Managing/Prediction/Editor/PredictionManagerEditor.cs index f92eda2..13b163c 100644 --- a/Assets/FishNet/Runtime/Managing/Prediction/Editor/PredictionManagerEditor.cs +++ b/Assets/FishNet/Runtime/Managing/Prediction/Editor/PredictionManagerEditor.cs @@ -1,4 +1,74 @@ -#if UNITY_EDITOR +#if !PREDICTION_1 +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; + +namespace FishNet.Managing.Predicting.Editing +{ + + + [CustomEditor(typeof(PredictionManager), true)] + [CanEditMultipleObjects] + public class PredictionManagerEditor : Editor + { + // private SerializedProperty _queuedInputs; + private SerializedProperty _dropExcessiveReplicates; + private SerializedProperty _maximumServerReplicates; + private SerializedProperty _maximumConsumeCount; + private SerializedProperty _stateInterpolation; + // private SerializedProperty _serverInterpolation; + + protected virtual void OnEnable() + { + _dropExcessiveReplicates = serializedObject.FindProperty(nameof(_dropExcessiveReplicates)); + _maximumServerReplicates = serializedObject.FindProperty(nameof(_maximumServerReplicates)); + _maximumConsumeCount = serializedObject.FindProperty(nameof(_maximumConsumeCount)); + _stateInterpolation = serializedObject.FindProperty(nameof(_stateInterpolation)); + // _serverInterpolation = serializedObject.FindProperty(nameof(_serverInterpolation)); + } + + public override void OnInspectorGUI() + { + serializedObject.Update(); + + GUI.enabled = false; + EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour((PredictionManager)target), typeof(PredictionManager), false); + GUI.enabled = true; + + + EditorGUILayout.LabelField("Client", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_stateInterpolation); + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Server", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + // EditorGUILayout.PropertyField(_serverInterpolation); + EditorGUILayout.PropertyField(_dropExcessiveReplicates); + EditorGUI.indentLevel++; + if (_dropExcessiveReplicates.boolValue == true) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_maximumServerReplicates); + EditorGUI.indentLevel--; + } + EditorGUI.indentLevel--; + + + serializedObject.ApplyModifiedProperties(); + } + + } +} +#endif + + +#else + + + +#if UNITY_EDITOR using UnityEditor; using UnityEngine; @@ -13,21 +83,14 @@ namespace FishNet.Managing.Predicting.Editing private SerializedProperty _queuedInputs; private SerializedProperty _dropExcessiveReplicates; private SerializedProperty _maximumServerReplicates; - private SerializedProperty _maximumConsumeCount; private SerializedProperty _redundancyCount; - private SerializedProperty _allowPredictedSpawning; - private SerializedProperty _reservedObjectIds; - protected virtual void OnEnable() { _queuedInputs = serializedObject.FindProperty(nameof(_queuedInputs)); _dropExcessiveReplicates = serializedObject.FindProperty(nameof(_dropExcessiveReplicates)); _maximumServerReplicates = serializedObject.FindProperty(nameof(_maximumServerReplicates)); - _maximumConsumeCount = serializedObject.FindProperty(nameof(_maximumConsumeCount)); _redundancyCount = serializedObject.FindProperty(nameof(_redundancyCount)); - _allowPredictedSpawning = serializedObject.FindProperty(nameof(_allowPredictedSpawning)); - _reservedObjectIds = serializedObject.FindProperty(nameof(_reservedObjectIds)); } public override void OnInspectorGUI() @@ -41,16 +104,8 @@ namespace FishNet.Managing.Predicting.Editing EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel); EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(_queuedInputs); EditorGUILayout.PropertyField(_redundancyCount); - - EditorGUILayout.PropertyField(_allowPredictedSpawning); - if (_allowPredictedSpawning.boolValue == true) - { - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(_reservedObjectIds); - EditorGUI.indentLevel--; - } + EditorGUILayout.PropertyField(_queuedInputs); EditorGUI.indentLevel--; EditorGUILayout.Space(); @@ -59,16 +114,7 @@ namespace FishNet.Managing.Predicting.Editing EditorGUILayout.PropertyField(_dropExcessiveReplicates); EditorGUI.indentLevel++; if (_dropExcessiveReplicates.boolValue == true) - { EditorGUILayout.PropertyField(_maximumServerReplicates); - } - else - { -#if PREDICTION_1 - EditorGUILayout.PropertyField(_maximumConsumeCount); -#endif - } - EditorGUI.indentLevel--; EditorGUI.indentLevel--; @@ -77,4 +123,7 @@ namespace FishNet.Managing.Predicting.Editing } } +#endif + + #endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Managing/Prediction/PredictionManager.cs b/Assets/FishNet/Runtime/Managing/Prediction/PredictionManager.cs index f3e3e89..32a25da 100644 --- a/Assets/FishNet/Runtime/Managing/Prediction/PredictionManager.cs +++ b/Assets/FishNet/Runtime/Managing/Prediction/PredictionManager.cs @@ -9,7 +9,7 @@ using GameKit.Dependencies.Utilities; using System; using System.Collections.Generic; using UnityEngine; - +using UnityEngine.Serialization; namespace FishNet.Managing.Predicting { @@ -96,24 +96,24 @@ namespace FishNet.Managing.Predicting #endregion #region Serialized. - /// - /// - /// - [Tooltip("Number of inputs to keep in queue for server and clients. " + - "Higher values will increase the likeliness of continous user created data to arrive successfully. " + - "Lower values will increase processing rate of received replicates. +" + - "This value cannot be higher than MaximumServerReplicates.")] - [Range(0, 15)] - [SerializeField] - private byte _queuedInputs = 1; - /// - /// Number of inputs to keep in queue for server and clients. - /// Higher values will increase the likeliness of continous user created data to arrive successfully. - /// Lower values will increase processing rate of received replicates. - /// This value cannot be higher than MaximumServerReplicates. - /// - //TODO: this is 0 until the rework on it is completed. - public byte QueuedInputs => 0;// _queuedInputs; + ///// + ///// + ///// + //[Tooltip("Number of inputs to keep in queue for server and clients. " + + // "Higher values will increase the likeliness of continous user created data to arrive successfully. " + + // "Lower values will increase processing rate of received replicates. +" + + // "This value cannot be higher than MaximumServerReplicates.")] + //[Range(0, 15)] + //[SerializeField] + //private byte _queuedInputs = 1; + ///// + ///// Number of inputs to keep in queue for server and clients. + ///// Higher values will increase the likeliness of continous user created data to arrive successfully. + ///// Lower values will increase processing rate of received replicates. + ///// This value cannot be higher than MaximumServerReplicates. + ///// + ////TODO: this is 0 until the rework on it is completed. + //public byte QueuedInputs => 0;// _queuedInputs; /// /// /// @@ -144,39 +144,37 @@ namespace FishNet.Managing.Predicting _maximumServerReplicates = (byte)Mathf.Clamp(value, MINIMUM_REPLICATE_QUEUE_SIZE, MAXIMUM_REPLICATE_QUEUE_SIZE); } /// - /// Clients should store no more than 2 seconds worth of replicates. + /// No more than this value of replicates should be stored as a buffer. /// - internal ushort MaximumClientReplicates => (ushort)(_networkManager.TimeManager.TickRate * 5); + internal ushort MaximumPastReplicates => (ushort)(_networkManager.TimeManager.TickRate * 5); /// /// /// - [Tooltip("Maximum number of past inputs which may send.")] - [Range(MINIMUM_PAST_INPUTS, MAXIMUM_PAST_INPUTS)] + [Tooltip("How many states to try and hold in a buffer before running them on clients. Larger values add resilience against network issues at the cost of running states later.")] + [Range(0, MAXIMUM_PAST_INPUTS)] + [FormerlySerializedAs("_redundancyCount")] //Remove on V5. + [FormerlySerializedAs("_interpolation")] //Remove on V5. [SerializeField] - private byte _redundancyCount = 2; + private byte _stateInterpolation = 1; /// - /// Maximum number of past inputs which may send and resend redundancy. - /// - internal byte RedundancyCount => _redundancyCount; + /// How many states to try and hold in a buffer before running them. Larger values add resilience against network issues at the cost of running states later. + /// + internal byte StateInterpolation => _stateInterpolation; /// - /// True to allow clients to use predicted spawning. While true, each NetworkObject prefab you wish to predicted spawn must be marked as to allow this feature. + /// Number of past inputs to send, which is also the number of times to resend final datas. /// - internal bool GetAllowPredictedSpawning() => _allowPredictedSpawning; - [Tooltip("True to allow clients to use predicted spawning and despawning. While true, each NetworkObject prefab you wish to predicted spawn must be marked as to allow this feature.")] - [SerializeField] - private bool _allowPredictedSpawning = false; - /// - /// - /// - [Tooltip("Maximum number of Ids to reserve on clients for predicted spawning. Higher values will allow clients to send more predicted spawns per second but may reduce availability of ObjectIds with high player counts.")] - [Range(1, 100)] - [SerializeField] - private byte _reservedObjectIds = 15; - /// - /// Maximum number of Ids to reserve on clients for predicted spawning. Higher values will allow clients to send more predicted spawns per second but may reduce availability of ObjectIds with high player counts. - /// - /// - internal byte GetReservedObjectIds() => _reservedObjectIds; + internal byte RedundancyCount => (byte)(_stateInterpolation + 1); + ///// + ///// + ///// + //[Tooltip("How many states to try and hold in a buffer before running them on server. Larger values add resilience against network issues at the cost of running states later.")] + //[Range(0, MAXIMUM_PAST_INPUTS + 30)] + //[SerializeField] + //private byte _serverInterpolation = 1; + ///// + ///// How many states to try and hold in a buffer before running them on server. Larger values add resilience against network issues at the cost of running states later. + ///// + //internal byte ServerInterpolation => _serverInterpolation; #endregion #region Private. @@ -228,7 +226,7 @@ namespace FishNet.Managing.Predicting internal void InitializeOnce(NetworkManager manager) { _networkManager = manager; - ClampQueuedInputs(); + ClampInterpolation(); _networkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState; } @@ -238,30 +236,27 @@ namespace FishNet.Managing.Predicting private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs obj) { _droppedReconcilesCount = 0; - + _lastOrderedReadReconcileTick = 0; } /// /// Amount to reserve for the header of a state update. - /// 2 PacketId. - /// 4 Last replicate tick run for connection. - /// 4 Length unpacked. /// - internal const int STATE_HEADER_RESERVE_COUNT = 10; + internal const int STATE_HEADER_RESERVE_LENGTH = (TransportManager.PACKETID_LENGTH + TransportManager.UNPACKED_TICK_LENGTH + TransportManager.UNPACKED_SIZE_LENGTH); /// /// Clamps queued inputs to a valid value. /// - private void ClampQueuedInputs() + private void ClampInterpolation() { - ushort startingValue = _queuedInputs; + ushort startingValue = _stateInterpolation; //Check for setting if dropping. - if (_dropExcessiveReplicates && _queuedInputs > _maximumServerReplicates) - _queuedInputs = (byte)(_maximumServerReplicates - 1); + if (_dropExcessiveReplicates && _stateInterpolation > _maximumServerReplicates) + _stateInterpolation = (byte)(_maximumServerReplicates - 1); //If changed. - if (_queuedInputs != startingValue) - _networkManager.Log($"QueuedInputs has been set to {_queuedInputs}."); + if (_stateInterpolation != startingValue) + _networkManager.Log($"Interpolation has been set to {_stateInterpolation}."); } internal class StatePacket : IResettable @@ -321,205 +316,174 @@ namespace FishNet.Managing.Predicting TimeManager tm = _networkManager.TimeManager; uint localTick = tm.LocalTick; uint estimatedLastRemoteTick = tm.LastPacketTick.Value(); - //NOTESSTART - /* Don't run a reconcile unless it's possible for ticks queued - * that tick to be run already. Otherwise you are not replaying inputs - * at all, just snapping to corrections. This means states which arrive late or out of order - * will be ignored since they're before the reconcile, which means important actions - * could have gone missed. - * - * A system which synchronized all current states rather than what's only needed to correct - * the inputs would likely solve this. */ - //NOTESEND - /* Only use the latest reconcile which passes the conditions to run. - * This will drop any excessive reconciles which built up from latency. */ - StatePacket sp = null; - /* If here then 'peeked' has met conditions. - * Check if the next state also meets, if so then - * skip ahead to the next state. */ + /* When there is an excessive amount of states try to consume + * some.This only happens when the client gets really far behind + * and has to catch up, such as a latency increase then drop. + * Limit the number of states consumed per tick so the clients + * computer doesn't catch fire. */ + int iterations = 0; + while (_reconcileStates.Count > 0) { - //If next matches then set peeked to new. - if (ConditionsMet(_reconcileStates.Peek())) - { - //Since this is being replaced, reset state first. - if (sp != null) - DisposeOfStatePacket(sp); - sp = _reconcileStates.Dequeue(); - break; - } - /* Conditions are not met on the next one, exit loop. - * This will use the latest peeked. */ + iterations++; + /* Typically there should only be 'interpolation' amount in queue but + * there can be more if the clients network is unstable and they are + * arriving in burst. + * If there's more than interpolation (+1 for as a leniency buffer) then begin to + * consume multiple. */ + byte stateInterpolation = StateInterpolation; + int maxIterations = (_reconcileStates.Count > (stateInterpolation + 1)) ? 2 : 1; + //At most 2 iterations. + if (iterations > maxIterations) + return; + + StatePacket sp; + if (!ConditionsMet(_reconcileStates.Peek())) + return; else - { - break; - } + sp = _reconcileStates.Dequeue(); //Condition met. See if the next one matches condition, if so drop current. //Returns if a state has it's conditions met. bool ConditionsMet(StatePacket spChecked) { - return ((spChecked != null) && (spChecked.ServerTick <= (estimatedLastRemoteTick - QueuedInputs - RedundancyCount - 1)) && spChecked.ClientTick < (localTick - QueuedInputs)); + if (spChecked == null) + return false; + bool serverPass = (spChecked.ServerTick <= (estimatedLastRemoteTick - stateInterpolation)); + bool clientPass = spChecked.ClientTick < (localTick - stateInterpolation); + return (serverPass && clientPass); } - } - //If state is not valid then it was never set, thus condition is not met. - if (sp == null) - return; - //StatePacket sp = _reconcileStates.Dequeue(); - bool dropReconcile = false; + bool dropReconcile = false; + uint clientTick = sp.ClientTick; + uint serverTick = sp.ServerTick; - uint clientTick = sp.ClientTick; - uint serverTick = sp.ServerTick; - //uint ticksDifference = (localTick - clientTick); - ////Target ticks are based on QueuedInputs, redundancy count, and latency. An extra bit is added as a buffer for variance. - //uint varianceAllowance = tm.TimeToTicks(0.2f, TickRounding.RoundUp); - //uint targetTicks = (varianceAllowance + (uint)QueuedInputs + (uint)RedundancyCount + tm.TimeToTicks((double)((double)tm.RoundTripTime / 1000d), TickRounding.RoundDown)); - //long ticksOverTarget = (long)ticksDifference - (long)targetTicks; - ////ReduceClientTiming = (ticksOverTarget > 0); - ///* If the reconcile is behind more ticks than hoped then slow - // * down the client simulation so it ticks very slightly - // * slower allowing fewer replays. This typically is only required after - // * the player encounters a sudden ping drop, such as a spike in latency, - // * then ping returns to norrmal. */ - //if (ticksOverTarget > 0) - //{ - - /* If client has a low frame rate - * then limit the number of reconciles to prevent further performance loss. */ - if (_networkManager.TimeManager.LowFrameRate) - { - /* Limit 3 drops a second. DropValue will be roughly the same - * as every 330ms. */ - int reconcileValue = Mathf.Max(1, (_networkManager.TimeManager.TickRate / 3)); - //If cannot drop then reset dropcount. - if (_droppedReconcilesCount >= reconcileValue) + /* If client has a low frame rate + * then limit the number of reconciles to prevent further performance loss. */ + if (_networkManager.TimeManager.LowFrameRate) + { + /* Limit 3 drops a second. DropValue will be roughly the same + * as every 330ms. */ + int reconcileValue = Mathf.Max(1, (_networkManager.TimeManager.TickRate / 3)); + //If cannot drop then reset dropcount. + if (_droppedReconcilesCount >= reconcileValue) + { + _droppedReconcilesCount = 0; + } + //If can drop... + else + { + dropReconcile = true; + _droppedReconcilesCount++; + } + } + //} + //No reason to believe client is struggling, allow reconcile. + else { _droppedReconcilesCount = 0; } - //If can drop... - else + + if (!dropReconcile) { - dropReconcile = true; - _droppedReconcilesCount++; - } - } - //} - //No reason to believe client is struggling, allow reconcile. - else - { - _droppedReconcilesCount = 0; - } + IsReconciling = true; - if (!dropReconcile) - { - IsReconciling = true; + ClientStateTick = clientTick; + /* This is the tick which the reconcile is for. + * Since reconciles are performed after replicate, if + * the replicate was on tick 100 then this reconcile is the state + * on tick 100, after the replicate is performed. */ + ServerStateTick = serverTick; - ClientStateTick = clientTick; - /* This is the tick which the reconcile is for. - * Since reconciles are performed after replicate, if - * the replicate was on tick 100 then this reconcile is the state - * on tick 100, after the replicate is performed. */ - ServerStateTick = serverTick; + //Have the reader get processed. + foreach (StatePacket.IncomingData item in sp.Datas) + { + PooledReader reader = ReaderPool.Retrieve(item.Data, _networkManager, Reader.DataSource.Server); + _networkManager.ClientManager.ParseReader(reader, item.Channel); + ReaderPool.Store(reader); + } - //Have the reader get processed. - foreach (StatePacket.IncomingData item in sp.Datas) - { - PooledReader reader = ReaderPool.Retrieve(item.Data, _networkManager, Reader.DataSource.Server); - _networkManager.ClientManager.ParseReader(reader, item.Channel); - ReaderPool.Store(reader); - } + bool timeManagerPhysics = (tm.PhysicsMode == PhysicsMode.TimeManager); + float tickDelta = ((float)tm.TickDelta * _networkManager.TimeManager.GetPhysicsTimeScale()); - bool timeManagerPhysics = (tm.PhysicsMode == PhysicsMode.TimeManager); - float tickDelta = (float)tm.TickDelta; + OnPreReconcile?.Invoke(ClientStateTick, ServerStateTick); + OnReconcile?.Invoke(ClientStateTick, ServerStateTick); - OnPreReconcile?.Invoke(ClientStateTick, ServerStateTick); - OnReconcile?.Invoke(ClientStateTick, ServerStateTick); - - if (timeManagerPhysics) - { - OnPrePhysicsTransformSync?.Invoke(ClientStateTick, ServerStateTick); - Physics.SyncTransforms(); - Physics2D.SyncTransforms(); - OnPostPhysicsTransformSync?.Invoke(ClientStateTick, ServerStateTick); - } - /* Set first replicate to be the 1 tick - * after reconcile. This is because reconcile calcs - * should be performed after replicate has run. - * In result object will reconcile to data AFTER - * the replicate tick, and then run remaining replicates as replay. - * - * Replay up to localtick, excluding localtick. There will - * be no input for localtick since reconcile runs before - * OnTick. */ - ClientReplayTick = ClientStateTick; - ServerReplayTick = ServerStateTick; - - int replays = 0; - /* Only replay up to this tick excluding queuedInputs. - * This will prevent the client from replaying into - * it's authorative/owned inputs which have not run - * yet. - * - * An additional value is subtracted to prevent - * client from running 1 local tick into the future - * since the OnTick has not run yet. */ - while (ClientReplayTick < localTick - 1) - { - replays++; - OnPreReplicateReplay?.Invoke(ClientReplayTick, ServerReplayTick); - OnReplicateReplay?.Invoke(ClientReplayTick, ServerReplayTick); if (timeManagerPhysics) { - Physics.Simulate(tickDelta); - Physics2D.Simulate(tickDelta); + OnPrePhysicsTransformSync?.Invoke(ClientStateTick, ServerStateTick); + Physics.SyncTransforms(); + Physics2D.SyncTransforms(); + OnPostPhysicsTransformSync?.Invoke(ClientStateTick, ServerStateTick); } - OnPostReplicateReplay?.Invoke(ClientReplayTick, ServerReplayTick); - ClientReplayTick++; - ServerReplayTick++; + /* Set first replicate to be the 1 tick + * after reconcile. This is because reconcile calcs + * should be performed after replicate has run. + * In result object will reconcile to data AFTER + * the replicate tick, and then run remaining replicates as replay. + * + * Replay up to localtick, excluding localtick. There will + * be no input for localtick since reconcile runs before + * OnTick. */ + ClientReplayTick = ClientStateTick; + ServerReplayTick = ServerStateTick; + + /* Only replay up to this tick excluding queuedInputs. + * This will prevent the client from replaying into + * it's authorative/owned inputs which have not run + * yet. + * + * An additional value is subtracted to prevent + * client from running 1 local tick into the future + * since the OnTick has not run yet. */ + while (ClientReplayTick < localTick - 1) + { + OnPreReplicateReplay?.Invoke(ClientReplayTick, ServerReplayTick); + OnReplicateReplay?.Invoke(ClientReplayTick, ServerReplayTick); + if (timeManagerPhysics) + { + Physics.Simulate(tickDelta); + Physics2D.Simulate(tickDelta); + } + OnPostReplicateReplay?.Invoke(ClientReplayTick, ServerReplayTick); + ClientReplayTick++; + ServerReplayTick++; + } + + OnPostReconcile?.Invoke(ClientStateTick, ServerStateTick); + + ClientStateTick = TimeManager.UNSET_TICK; + ServerStateTick = TimeManager.UNSET_TICK; + ClientReplayTick = TimeManager.UNSET_TICK; + ServerReplayTick = TimeManager.UNSET_TICK; + IsReconciling = false; } - OnPostReconcile?.Invoke(ClientStateTick, ServerStateTick); - - ClientStateTick = TimeManager.UNSET_TICK; - ServerStateTick = TimeManager.UNSET_TICK; - ClientReplayTick = TimeManager.UNSET_TICK; - ServerReplayTick = TimeManager.UNSET_TICK; - IsReconciling = false; + DisposeOfStatePacket(sp); } - - DisposeOfStatePacket(sp); } /// /// Sends written states for clients. /// internal void SendStateUpdate() { + byte stateInterpolation = StateInterpolation; + uint recentReplicateToTicks = _networkManager.TimeManager.TimeToTicks(0.25f, TickRounding.RoundUp); TransportManager tm = _networkManager.TransportManager; foreach (NetworkConnection nc in _networkManager.ServerManager.Clients.Values) { uint lastReplicateTick; - //If client has performed a replicate. - if (!nc.ReplicateTick.IsUnset) - { - /* If it's been longer than queued inputs since - * server has received a replicate then - * use estimated value. Otherwise use LastRemoteTick. */ - if (nc.ReplicateTick.LocalTickDifference(_networkManager.TimeManager) > QueuedInputs) - lastReplicateTick = nc.ReplicateTick.Value(); - else - lastReplicateTick = nc.ReplicateTick.LastRemoteTick; - } + //If client has performed a replicate recently. + if (!nc.ReplicateTick.IsUnset && nc.ReplicateTick.LocalTickDifference(_networkManager.TimeManager) < recentReplicateToTicks) + lastReplicateTick = nc.ReplicateTick.Value(); /* If not then use what is estimated to be the clients * current tick along with desired prediction queue count. * This should be just about the same as if the client used replicate, * but even if it's not it doesn't matter because the client * isn't replicating himself, just reconciling and replaying other objects. */ else - { - lastReplicateTick = (nc.PacketTick.Value() + QueuedInputs); - } + lastReplicateTick = nc.LocalTick.Value() - stateInterpolation; foreach (PooledWriter writer in nc.PredictionStateWriters) { @@ -536,7 +500,7 @@ namespace FishNet.Managing.Predicting * the reserve count of the header. The header reserve * count will always be the same so that can be parsed * off immediately upon receiving. */ - int dataLength = (segment.Count - STATE_HEADER_RESERVE_COUNT); + int dataLength = (segment.Count - STATE_HEADER_RESERVE_LENGTH); //Write length. writer.WriteInt32(dataLength, AutoPackType.Unpacked); //Channel is defaulted to unreliable. @@ -576,7 +540,7 @@ namespace FishNet.Managing.Predicting * a limit a little beyond to prevent reconciles from building up. * This is more of a last result if something went terribly * wrong with the network. */ - int maxAllowedStates = Mathf.Max(QueuedInputs * 4, 4); + int maxAllowedStates = Mathf.Max(StateInterpolation * 4, 4); while (_reconcileStates.Count > maxAllowedStates) { StatePacket oldSp = _reconcileStates.Dequeue(); @@ -622,7 +586,7 @@ namespace FishNet.Managing.Predicting #if UNITY_EDITOR private void OnValidate() { - ClampQueuedInputs(); + ClampInterpolation(); } #endif @@ -772,28 +736,9 @@ namespace FishNet.Managing.Predicting [SerializeField] private byte _redundancyCount = 2; /// - /// Maximum number of past inputs which may send and resend redundancy. + /// Maximum number of past inputs which may send. /// internal byte RedundancyCount => _redundancyCount; - /// - /// True to allow clients to use predicted spawning. While true, each NetworkObject prefab you wish to predicted spawn must be marked as to allow this feature. - /// - internal bool GetAllowPredictedSpawning() => _allowPredictedSpawning; - [Tooltip("True to allow clients to use predicted spawning and despawning. While true, each NetworkObject prefab you wish to predicted spawn must be marked as to allow this feature.")] - [SerializeField] - private bool _allowPredictedSpawning = false; - /// - /// - /// - [Tooltip("Maximum number of Ids to reserve on clients for predicted spawning. Higher values will allow clients to send more predicted spawns per second but may reduce availability of ObjectIds with high player counts.")] - [Range(1, 100)] - [SerializeField] - private byte _reservedObjectIds = 15; - /// - /// Maximum number of Ids to reserve on clients for predicted spawning. Higher values will allow clients to send more predicted spawns per second but may reduce availability of ObjectIds with high player counts. - /// - /// - internal byte GetReservedObjectIds() => _reservedObjectIds; #endregion #region Private. diff --git a/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs b/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs index 222d0ef..a77d5ff 100644 --- a/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs +++ b/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs @@ -782,7 +782,7 @@ namespace FishNet.Managing.Scened return WarnAndReturnFalse($"NetworkObject {nob.name} cannot be moved because it is not the root object. Unity can only move root objects between scenes."); //In DDOL and IsGlobal. if (nob.IsGlobal && (nob.gameObject.scene.name == DDOL.GetDDOL().gameObject.scene.name)) - return WarnAndReturnFalse("NetworkObject {nob.name} cannot be moved because it is global. Global objects must remain in the DontDestroyOnLoad scene."); + return WarnAndReturnFalse($"NetworkObject {nob.name} cannot be moved because it is global. Global objects must remain in the DontDestroyOnLoad scene."); //Fall through success. return true; diff --git a/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs b/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs index 839480d..5d93e03 100644 --- a/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs +++ b/Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs @@ -19,6 +19,8 @@ namespace FishNet.Managing.Server.Editing private SerializedProperty _frameRate; private SerializedProperty _shareIds; private SerializedProperty _startOnHeadless; + private SerializedProperty _allowPredictedSpawning; + private SerializedProperty _reservedObjectIds; protected virtual void OnEnable() { @@ -31,6 +33,9 @@ namespace FishNet.Managing.Server.Editing _frameRate = serializedObject.FindProperty(nameof(_frameRate)); _shareIds = serializedObject.FindProperty(nameof(_shareIds)); _startOnHeadless = serializedObject.FindProperty(nameof(_startOnHeadless)); + _allowPredictedSpawning = serializedObject.FindProperty(nameof(_allowPredictedSpawning)); + _reservedObjectIds = serializedObject.FindProperty(nameof(_reservedObjectIds)); + } public override void OnInspectorGUI() @@ -43,15 +48,6 @@ namespace FishNet.Managing.Server.Editing EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel); EditorGUI.indentLevel++; - - EditorGUILayout.PropertyField(_authenticator); - EditorGUILayout.PropertyField(_remoteClientTimeout); - if ((RemoteTimeoutType)_remoteClientTimeout.intValue != RemoteTimeoutType.Disabled) - { - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(_remoteClientTimeoutDuration,new GUIContent("Timeout")); - EditorGUI.indentLevel--; - } EditorGUILayout.PropertyField(_syncTypeRate); EditorGUILayout.PropertyField(SpawnPacking); EditorGUILayout.PropertyField(_changeFrameRate); @@ -61,11 +57,36 @@ namespace FishNet.Managing.Server.Editing EditorGUILayout.PropertyField(_frameRate); EditorGUI.indentLevel--; } - EditorGUILayout.PropertyField(_shareIds); EditorGUILayout.PropertyField(_startOnHeadless); - EditorGUI.indentLevel--; + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Connections", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_remoteClientTimeout); + if ((RemoteTimeoutType)_remoteClientTimeout.intValue != RemoteTimeoutType.Disabled) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_remoteClientTimeoutDuration,new GUIContent("Timeout")); + EditorGUI.indentLevel--; + } + EditorGUILayout.PropertyField(_shareIds); + EditorGUI.indentLevel--; + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Security", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_authenticator); + + EditorGUILayout.PropertyField(_allowPredictedSpawning); + if (_allowPredictedSpawning.boolValue == true) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_reservedObjectIds); + EditorGUI.indentLevel--; + } + EditorGUI.indentLevel--; + EditorGUILayout.Space(); serializedObject.ApplyModifiedProperties(); } diff --git a/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs b/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs index 1818aac..af339d2 100644 --- a/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs +++ b/Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs @@ -251,7 +251,7 @@ namespace FishNet.Managing.Server /* Only shuffle when NOT in editor and not * development build. * Debugging could be easier when Ids are ordered. */ -#if !UNITY_EDITOR && !DEVELOPMENT_BUILD +#if !DEVELOPMENT shuffledCache.Shuffle(); #endif //Add shuffled to objectIdCache. @@ -458,7 +458,7 @@ namespace FishNet.Managing.Server return; } //Server has predicted spawning disabled. - if (!NetworkManager.PredictionManager.GetAllowPredictedSpawning()) + if (!NetworkManager.ServerManager.GetAllowPredictedSpawning()) { base.NetworkManager.LogWarning("Cannot spawn object because server is not active and predicted spawning is not enabled."); return; @@ -809,7 +809,7 @@ namespace FishNet.Managing.Server return; } //Server has predicted spawning disabled. - if (!NetworkManager.PredictionManager.GetAllowPredictedSpawning()) + if (!NetworkManager.ServerManager.GetAllowPredictedSpawning()) { base.NetworkManager.LogWarning("Cannot despawn object because server is not active and predicted spawning is not enabled."); return; diff --git a/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs b/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs index 1fa6b10..6b44a98 100644 --- a/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs +++ b/Assets/FishNet/Runtime/Managing/Server/ServerManager.cs @@ -1,4 +1,7 @@ -using FishNet.Authenticating; +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +using FishNet.Authenticating; using FishNet.Component.Observing; using FishNet.Connection; using FishNet.Managing.Debugging; @@ -102,6 +105,26 @@ namespace FishNet.Managing.Server _remoteClientTimeoutDuration = duration; } /// + /// True to allow clients to use predicted spawning. While true, each NetworkObject you wish this feature to apply towards must have a PredictedSpawn component. + /// Predicted spawns can have custom validation on the server. + /// + internal bool GetAllowPredictedSpawning() => _allowPredictedSpawning; + [Tooltip("True to allow clients to use predicted spawning. While true, each NetworkObject you wish this feature to apply towards must have a PredictedSpawn component. Predicted spawns can have custom validation on the server.")] + [SerializeField] + private bool _allowPredictedSpawning = false; + /// + /// + /// + [Tooltip("Maximum number of Ids to reserve on clients for predicted spawning. Higher values will allow clients to send more predicted spawns per second but may reduce availability of ObjectIds with high player counts.")] + [Range(1, 100)] + [SerializeField] + private byte _reservedObjectIds = 15; + /// + /// Maximum number of Ids to reserve on clients for predicted spawning. Higher values will allow clients to send more predicted spawns per second but may reduce availability of ObjectIds with high player counts. + /// + /// + internal byte GetReservedObjectIds() => _reservedObjectIds; + /// /// Default send rate for SyncTypes. A value of 0f will send changed values every tick. /// SyncTypeRate cannot yet be changed at runtime because this would require recalculating rates on SyncBase, which is not yet implemented. /// @@ -180,7 +203,7 @@ namespace FishNet.Managing.Server /// Used to read splits. /// private SplitReader _splitReader = new SplitReader(); -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT /// /// Logs data about parser to help debug. /// @@ -329,7 +352,7 @@ namespace FishNet.Managing.Server { if (_remoteClientTimeout == RemoteTimeoutType.Disabled) return; -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT //If development but not set to development return. else if (_remoteClientTimeout != RemoteTimeoutType.Development) return; @@ -505,6 +528,54 @@ namespace FishNet.Managing.Server OnServerConnectionState?.Invoke(args); } + + /// + /// Checks to make sure the client is on the same version. + /// This is to help developers make sure their builds are on the same FishNet version. + /// + private void ParseVersion(PooledReader reader, NetworkConnection conn, int transportId) + { + //Cannot be authenticated if havent sent version yet. This is a duplicate version send, likely exploit attempt. + if (conn.HasSentVersion) + { + conn.Kick(reader, KickReason.ExploitAttempt, LoggingType.Common, $"Connection {conn.ToString()} has sent their FishNet version after being authenticated; this is not possible under normal conditions."); + return; + } + + conn.HasSentVersion = true; + string version = reader.ReadString(); + //Version match. + if (version == NetworkManager.FISHNET_VERSION) + { + /* Send to client if server is in development build or not. + * This is to allow the client to utilize some features/information + * received from the server only when it's in dev mode. */ + bool isDevelopmentBuild; +#if DEVELOPMENT + isDevelopmentBuild = true; +#else + isDevelopmentBuild = false; +#endif + PooledWriter writer = WriterPool.Retrieve(); + writer.WritePacketId(PacketId.Version); + writer.WriteBoolean(isDevelopmentBuild); + conn.SendToClient((byte)Channel.Reliable, writer.GetArraySegment()); + WriterPool.Store(writer); + + /* If there is an authenticator + * and the transport is not a local transport. */ + Authenticator auth = GetAuthenticator(); + if (auth != null && !NetworkManager.TransportManager.IsLocalTransport(transportId)) + auth.OnRemoteConnection(conn); + else + ClientAuthenticated(conn); + } + else + { + conn.Kick(reader, KickReason.UnexpectedProblem, LoggingType.Warning, $"Connection {conn.ToString()} has been kicked for being on FishNet version {version}. Server version is {NetworkManager.FISHNET_VERSION}."); + } + } + /// /// Called when a connection state changes for a remote client. /// @@ -512,10 +583,9 @@ namespace FishNet.Managing.Server { //Sanity check to make sure transports are following proper types/ranges. int id = args.ConnectionId; - int maxIdValue = short.MaxValue; - if (id < 0 || id > maxIdValue) + if (id < 0 || id > NetworkConnection.MAXIMUM_CLIENTID_VALUE) { - 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 {maxIdValue}. The client has been disconnected."); + 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. @@ -528,16 +598,8 @@ namespace FishNet.Managing.Server NetworkConnection conn = new NetworkConnection(NetworkManager, id, args.TransportIndex, true); Clients.Add(args.ConnectionId, conn); OnRemoteConnectionState?.Invoke(conn, args); - //Connection is no longer valid. This can occur if the user changes the state using the OnRemoteConnectionState event. - if (!conn.IsValid) - return; - /* If there is an authenticator - * and the transport is not a local transport. */ - Authenticator auth = GetAuthenticator(); - if (auth != null && !NetworkManager.TransportManager.IsLocalTransport(id)) - auth.OnRemoteConnection(conn); - else - ClientAuthenticated(conn); + + //Do nothing else until the client sends it's version. } //If stopping. else if (args.ConnectionState == RemoteConnectionState.Stopped) @@ -556,7 +618,7 @@ namespace FishNet.Managing.Server while (pqId.Count > 0) Objects.CacheObjectId(pqId.Dequeue()); - conn.Dispose(); + conn.ResetState(); NetworkManager.Log($"Remote connection stopped for Id {id}."); } } @@ -576,9 +638,9 @@ namespace FishNet.Managing.Server * reserved objectIds. */ ; PredictionManager pm = NetworkManager.PredictionManager; - if (pm.GetAllowPredictedSpawning()) + if (GetAllowPredictedSpawning()) { - int count = Mathf.Min(Objects.GetObjectIdCache().Count, pm.GetReservedObjectIds()); + int count = Mathf.Min(Objects.GetObjectIdCache().Count, GetReservedObjectIds()); writer.WriteByte((byte)count); for (int i = 0; i < count; i++) @@ -606,7 +668,7 @@ namespace FishNet.Managing.Server /// private void ParseReceived(ServerReceivedDataArgs args) { -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT _parseLogger.Reset(); #endif @@ -621,7 +683,7 @@ namespace FishNet.Managing.Server segment = args.Data; NetworkManager.StatisticsManager.NetworkTraffic.LocalServerReceivedData((ulong)segment.Count); - if (segment.Count <= TransportManager.TICK_BYTES) + if (segment.Count <= TransportManager.UNPACKED_TICK_LENGTH) return; //FishNet internally splits packets so nothing should ever arrive over MTU. @@ -633,17 +695,19 @@ namespace FishNet.Managing.Server return; } + TimeManager timeManager = NetworkManager.TimeManager; + bool hasIntermediateLayer = NetworkManager.TransportManager.HasIntermediateLayer; PacketId packetId = PacketId.Unset; PooledReader reader = null; -#if !UNITY_EDITOR && !DEVELOPMENT_BUILD +#if !DEVELOPMENT try { #endif Reader.DataSource dataSource = Reader.DataSource.Client; reader = ReaderPool.Retrieve(segment, NetworkManager, dataSource); uint tick = reader.ReadTickUnpacked(); - NetworkManager.TimeManager.LastPacketTick.Update(tick); + timeManager.LastPacketTick.Update(tick); /* This is a special condition where a message may arrive split. * When this occurs buffer each packet until all packets are * received. */ @@ -654,8 +718,8 @@ namespace FishNet.Managing.Server int expectedMessages; _splitReader.GetHeader(reader, out expectedMessages); - //If here split message can be written. - _splitReader.Write(NetworkManager.TimeManager.LastPacketTick.LastRemoteTick, reader, 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 @@ -681,7 +745,7 @@ namespace FishNet.Managing.Server while (reader.Remaining > 0) { packetId = reader.ReadPacketId(); -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT _parseLogger.AddPacket(packetId); #endif NetworkConnection conn; @@ -693,20 +757,20 @@ namespace FishNet.Managing.Server Kick(args.ConnectionId, KickReason.UnexpectedProblem, LoggingType.Error, $"ConnectionId {args.ConnectionId} not found within Clients. Connection will be kicked immediately."); return; } - conn.TryUpdateLocalTick(tick); - conn.PacketTick.Update(NetworkManager.TimeManager, tick, Timing.EstimatedTick.OldTickOption.SetLastRemoteTick); + conn.LocalTick.Update(timeManager, tick, EstimatedTick.OldTickOption.Discard); + conn.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.Broadcast) + if (!conn.IsAuthenticated && packetId != PacketId.Version && packetId != PacketId.Broadcast) { - conn.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {conn.ClientId} sent a Broadcast without being authenticated. Connection will be kicked immediately."); + conn.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {conn.ClientId} sent packetId {packetId} without being authenticated. Connection will be kicked immediately."); return; } //Only check if not developer build because users pay pause editor. -#if !DEVELOPMENT_BUILD && !UNITY_EDITOR +#if !DEVELOPMENT /* If hasn't sent LOD recently enough. LODs are sent every half a second, so * by multiplaying interval by 60 this gives the client a 30 second window. */ if (_cachedUseLod && conn.IsLateForLevelOfDetail(_cachedLevelOfDetailInterval * 60)) @@ -725,7 +789,7 @@ namespace FishNet.Managing.Server } else if (packetId == PacketId.ObjectSpawn) { - if (!NetworkManager.PredictionManager.GetAllowPredictedSpawning()) + 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."); return; @@ -734,7 +798,7 @@ namespace FishNet.Managing.Server } else if (packetId == PacketId.ObjectDespawn) { - if (!NetworkManager.PredictionManager.GetAllowPredictedSpawning()) + 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."); return; @@ -753,9 +817,13 @@ namespace FishNet.Managing.Server { ParsePingPong(reader, conn); } + else if (packetId == PacketId.Version) + { + ParseVersion(reader, conn, args.TransportIndex); + } else { -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT NetworkManager.LogError($"Server received an unhandled PacketId of {(ushort)packetId} on channel {args.Channel} from connectionId {args.ConnectionId}. Remaining data has been purged."); _parseLogger.Print(NetworkManager); #else @@ -765,7 +833,7 @@ namespace FishNet.Managing.Server return; } } -#if !UNITY_EDITOR && !DEVELOPMENT_BUILD +#if !DEVELOPMENT } catch (Exception e) { @@ -831,6 +899,9 @@ namespace FishNet.Managing.Server /// private void BroadcastClientConnectionChange(bool connected, NetworkConnection conn) { + //Only send if the connection was authenticated. + if (!conn.IsAuthenticated) + return; //If sharing Ids then send all connected client Ids first if is a connected state. if (ShareIds) { diff --git a/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs b/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs index a23e7ef..28e3263 100644 --- a/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs +++ b/Assets/FishNet/Runtime/Managing/Timing/Editor/TimeManagerEditor.cs @@ -60,9 +60,11 @@ namespace FishNet.Managing.Timing.Editing //Physics. EditorGUILayout.LabelField("Physics", EditorStyles.boldLabel); EditorGUI.indentLevel++; + if (_physicsMode.intValue == (int)FishNet.Managing.Timing.PhysicsMode.TimeManager) + EditorGUILayout.HelpBox($"Time.fixedDeltaTime will be overriden with TimeManager.TickDelta ({(1f / (float)_tickRate.intValue).ToString("0.###")})", MessageType.Info); + else + EditorGUILayout.HelpBox("If you are using physics interactions be sure to change the PhysicsMode to TimeManager and implement physics within the TimeManager tick events. NetworkTransform may also jitter when not using PhysicsMode.TimeManager.", MessageType.Warning); EditorGUILayout.PropertyField(_physicsMode); - if (_physicsMode.intValue != (int)FishNet.Managing.Timing.PhysicsMode.TimeManager) - EditorGUILayout.HelpBox("If you are using physics interactions be sure to change the PhysicsMode to TimeManager and implement physics within the TimeManager tick events.", MessageType.None); EditorGUI.indentLevel--; ////Prediction. diff --git a/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs b/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs index 5cfe17f..4121e03 100644 --- a/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs +++ b/Assets/FishNet/Runtime/Managing/Timing/TimeManager.cs @@ -1,12 +1,6 @@ using FishNet.Connection; -using FishNet.Documenting; -using FishNet.Managing.Transporting; -using FishNet.Object; using FishNet.Serializing; -using FishNet.Serializing.Helping; using FishNet.Transporting; -using FishNet.Utility; -using FishNet.Utility.Extension; using GameKit.Dependencies.Utilities; using System; using System.Runtime.CompilerServices; @@ -47,63 +41,6 @@ namespace FishNet.Managing.Timing BeforeTick = 0, AfterTick = 1, } - /// - /// Synchronizes tick timing between server and client. - /// - private class TimingSync - { - /// - /// Last server tick passed in. - /// - private uint _lastServerTick; - /// - /// Last local tick passed in. - /// - private uint _lastLocalTick; - /// - /// Last difference between server and client. - /// - private long? _lastServerClientDifference; - - /// - /// Sets differences between last server and local tick. - /// - /// True if values exist, false if unable to process. - public bool GetTickDifference(uint currentServerTick, uint currentLocalTick, out long tickDifference) - { - if (currentServerTick < _lastServerTick) - { - tickDifference = 0; - return false; - } - else - { - uint serverDifference = (currentServerTick - _lastServerTick); - uint localDifference = (currentLocalTick - _lastLocalTick); - - long td = ((long)serverDifference - (long)localDifference); - //Average tick differences over 2 updates to help with unstable connections. - if (_lastServerClientDifference.HasValue) - { - long totalTd = (td + _lastServerClientDifference.Value); - tickDifference = (totalTd / (long)2); - } - //Last tick difference not set yet, use current values only. - else - { - tickDifference = td; - } - - //Also update last values. - _lastServerTick = currentServerTick; - _lastLocalTick = currentLocalTick; - _lastServerClientDifference = td; - - return true; - } - } - - } #endregion #region Public. @@ -210,14 +147,14 @@ namespace FishNet.Managing.Timing /// [Tooltip("While true clients may drop local ticks if their devices are unable to maintain the tick rate. This could result in a temporary desynchronization but will prevent the client falling further behind on ticks by repeatedly running the logic cycle multiple times per frame.")] [SerializeField] - private bool _allowTickDropping; + private bool _allowTickDropping = true; /// /// Maximum number of ticks which may occur in a single frame before remainder are dropped for the frame. /// [Tooltip("Maximum number of ticks which may occur in a single frame before remainder are dropped for the frame.")] [Range(1, 25)] [SerializeField] - private byte _maximumFrameTicks = 2; + private byte _maximumFrameTicks = 3; /// /// /// @@ -308,9 +245,24 @@ namespace FishNet.Managing.Timing /// private bool _fixedUpdateTimeStep; /// - /// Synchronizes tick deltas between server and client. + /// /// - private TimingSync _timing = new TimingSync(); + private float _physicsTimeScale = 1f; + /// + /// Gets the current physics time scale. + /// + /// + public float GetPhysicsTimeScale() => _physicsTimeScale; + /// + /// Sets the physics time scale. + /// This is not automatically synchronized. + /// + /// New value. + public void SetPhysicsTimeScale(float value) + { + value = Mathf.Clamp(value, 0f, float.PositiveInfinity); + _physicsTimeScale = value; + } #endregion #region Const. @@ -538,8 +490,8 @@ namespace FishNet.Managing.Timing //Preserve user tick rate. PlayerPrefs.SetFloat(SAVED_FIXED_TIME_TEXT, Time.fixedDeltaTime); //Let the player know. - if (Time.fixedDeltaTime != (float)TickDelta) - Debug.LogWarning("Time.fixedDeltaTime is being overriden with TimeManager.TickDelta"); + //if (Time.fixedDeltaTime != (float)TickDelta) + // Debug.LogWarning("Time.fixedDeltaTime is being overriden with TimeManager.TickDelta"); #endif Time.fixedDeltaTime = (float)TickDelta; /* Only check this if network manager @@ -668,8 +620,7 @@ namespace FishNet.Managing.Timing bool isClient = NetworkManager.IsClientStarted; bool isServer = NetworkManager.IsServerStarted; - double tickDelta = TickDelta; - double timePerSimulation = (isServer) ? tickDelta : _adjustedTickDelta; + double timePerSimulation = (isServer) ? TickDelta : _adjustedTickDelta; if (timePerSimulation == 0d) { Debug.LogWarning($"Simulation delta cannot be 0. Network timing will not continue."); @@ -692,7 +643,7 @@ namespace FishNet.Managing.Timing if (ticksCount > 1) _lastMultipleTicksTime = Time.unscaledDeltaTime; - if (_allowTickDropping && !NetworkManager.IsServerStarted) + if (_allowTickDropping) { //If ticks require dropping. Set exactly to maximum ticks. if (ticksCount > _maximumFrameTicks) @@ -701,6 +652,7 @@ namespace FishNet.Managing.Timing bool variableTiming = (_timingType == TimingType.Variable); bool frameTicked = FrameTicked; + float tickDelta = ((float)TickDelta * GetPhysicsTimeScale()); do { @@ -727,11 +679,10 @@ namespace FishNet.Managing.Timing if (PhysicsMode == PhysicsMode.TimeManager) { - float tick = (float)TickDelta; - OnPrePhysicsSimulation?.Invoke(tick); - Physics.Simulate(tick); - Physics2D.Simulate(tick); - OnPostPhysicsSimulation?.Invoke(tick); + OnPrePhysicsSimulation?.Invoke(tickDelta); + Physics.Simulate(tickDelta); + Physics2D.Simulate(tickDelta); + OnPostPhysicsSimulation?.Invoke(tickDelta); } OnPostTick?.Invoke(); @@ -1097,12 +1048,16 @@ namespace FishNet.Managing.Timing { //Now send using a packetId. PooledWriter writer = WriterPool.Retrieve(); - writer.WritePacketId(PacketId.TimingUpdate); foreach (NetworkConnection item in NetworkManager.ServerManager.Clients.Values) { if (!item.IsAuthenticated) continue; + + writer.WritePacketId(PacketId.TimingUpdate); + writer.WriteTickUnpacked(item.PacketTick.Value()); item.SendToClient((byte)Channel.Unreliable, writer.GetArraySegment()); + writer.Reset(); + } writer.Store(); @@ -1113,12 +1068,17 @@ namespace FishNet.Managing.Timing /// Called on client when server sends a timing update. /// /// - internal void ParseTimingUpdate() + internal void ParseTimingUpdate(Reader reader) { + uint clientTick = reader.ReadTickUnpacked(); //Don't adjust timing on server. if (NetworkManager.IsServerStarted) return; - + /* This should never be possible since the server is sending a tick back + * that the client previously sent. In other words, the value returned should + * always be in the past. */ + if (LocalTick < clientTick) + return; /* Use the last ordered remote tick rather than * lastPacketTick. This will help with out of order * packets where the timing update sent before @@ -1127,42 +1087,26 @@ namespace FishNet.Managing.Timing * ticks really passed rather than the difference * between the out of order/late packet. */ uint lastPacketTick = LastPacketTick.RemoteTick; - //If difference could not be updated then something went wrong. Most likely an old timing update. - if (!_timing.GetTickDifference(lastPacketTick, LocalTick, out long tickDifference)) - return; + //Set Tick based on difference between localTick and clientTick, added onto lastPacketTick. + uint prevTick = Tick; + uint nextTick = (LocalTick - clientTick) + lastPacketTick; + long difference = ((long)nextTick - (long)prevTick); + Tick = nextTick; //Maximum difference allowed before resetting values. const int maximumDifference = 4; - - TryRecalculateTick(); - - ////Do not change timing if client is slowing down due to latency issues. - //if (Time.unscaledTime - NetworkManager.PredictionManager.SlowDownTime > 3f) - //{ - //Pefect! - if (tickDifference == 0) { } - //Difference is extreme, reset to default timings. Client probably had an issue. - else if (Mathf.Abs(tickDifference) > maximumDifference) - { - _adjustedTickDelta = TickDelta; - } - //Otherwise adjust the delta marginally. - else - { - /* A negative tickDifference indicates the client is - * moving too fast, while positive indicates too slow. */ - bool speedUp = (tickDifference > 0); - ChangeAdjustedTickDelta(speedUp); - } - // } - //Recalculates Tick value if it exceeds maximum difference. - void TryRecalculateTick() + //Difference is extreme, reset to default timings. Client probably had an issue. + if (Mathf.Abs(difference) > maximumDifference) { - uint rttTicks = TimeToTicks((RoundTripTime / 2) / 1000f); - uint newValue = lastPacketTick + rttTicks; - long difference = (long)Mathf.Abs((long)Tick - (long)newValue); - if (difference > maximumDifference) - Tick = newValue; + _adjustedTickDelta = TickDelta; + } + //Otherwise adjust the delta marginally. + else if (difference != 0) + { + /* A negative tickDifference indicates the client is + * moving too fast, while positive indicates too slow. */ + bool speedUp = (difference > 0); + ChangeAdjustedTickDelta(speedUp); } } #endregion diff --git a/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs b/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs index a4adf4d..c57687c 100644 --- a/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs +++ b/Assets/FishNet/Runtime/Managing/Transporting/TransportManager.cs @@ -1,4 +1,7 @@ -using FishNet.Connection; +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +using FishNet.Connection; using FishNet.Managing.Timing; using FishNet.Object; using FishNet.Serializing; @@ -128,27 +131,31 @@ namespace FishNet.Managing.Transporting /// /// Number of bytes sent for PacketId. /// - public const byte PACKET_ID_BYTES = 2; + public const byte PACKETID_LENGTH = 2; /// /// Number of bytes sent for ObjectId. /// - public const byte OBJECT_ID_BYTES = 2; + public const byte OBJECT_ID_LENGTH = 2; /// /// Number of bytes sent for ComponentIndex. /// - public const byte COMPONENT_INDEX_BYTES = 1; + public const byte COMPONENT_INDEX_LENGTH = 1; /// /// Number of bytes sent for Tick. /// - public const byte TICK_BYTES = 4; + public const byte UNPACKED_TICK_LENGTH = 4; + /// + /// Number of bytes sent for an unpacked size, such as a collection or array size. + /// + public const byte UNPACKED_SIZE_LENGTH = 4; /// /// Number of bytes sent to indicate split count. /// - private const byte SPLIT_COUNT_BYTES = 4; + private const byte SPLIT_COUNT_LENGTH = 4; /// /// Number of bytes required for split data. /// //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_SIZE = (TICK_BYTES + PACKET_ID_BYTES + SPLIT_COUNT_BYTES); + public const byte SPLIT_INDICATOR_LENGTH = (UNPACKED_TICK_LENGTH + PACKETID_LENGTH + SPLIT_COUNT_LENGTH); /// /// Number of channels supported. /// @@ -176,7 +183,7 @@ namespace FishNet.Managing.Transporting InitializeToServerBundles(); if (_intermediateLayer != null) _intermediateLayer.InitializeOnce(this); -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT _latencySimulator.Initialize(manager, Transport); #endif } @@ -621,7 +628,7 @@ namespace FishNet.Managing.Transporting /// private int GetRequiredMessageCount(byte channelId, int segmentSize, out int maxMessageSize) { - maxMessageSize = GetLowestMTU(channelId) - SPLIT_INDICATOR_SIZE; + maxMessageSize = GetLowestMTU(channelId) - SPLIT_INDICATOR_LENGTH; return Mathf.CeilToInt((float)segmentSize / maxMessageSize); } @@ -718,7 +725,7 @@ namespace FishNet.Managing.Transporting OnIterateOutgoingStart?.Invoke(); int channelCount = CHANNEL_COUNT; ulong sentBytes = 0; -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT bool latencySimulatorEnabled = LatencySimulator.CanSimulate; #endif /* If sending to the client. */ @@ -756,7 +763,7 @@ namespace FishNet.Managing.Transporting ArraySegment segment = new ArraySegment(bb.Data, 0, bb.Length); if (HasIntermediateLayer) segment = ProcessIntermediateOutgoing(segment, false); -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (latencySimulatorEnabled) _latencySimulator.AddOutgoing(channel, segment, false, conn.ClientId); else @@ -829,7 +836,7 @@ namespace FishNet.Managing.Transporting ArraySegment segment = new ArraySegment(bb.Data, 0, bb.Length); if (HasIntermediateLayer) segment = ProcessIntermediateOutgoing(segment, true); -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (latencySimulatorEnabled) _latencySimulator.AddOutgoing(channel, segment); else @@ -847,7 +854,7 @@ namespace FishNet.Managing.Transporting _networkManager.StatisticsManager.NetworkTraffic.LocalClientSentData(sentBytes); } -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (latencySimulatorEnabled) _latencySimulator.IterateOutgoing(toServer); #endif diff --git a/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs b/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs index 400c957..d54114b 100644 --- a/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs +++ b/Assets/FishNet/Runtime/Object/ChangedTransformProperties.cs @@ -1,35 +1 @@ -using FishNet.Documenting; - -namespace FishNet.Object -{ - /// - /// Properties which have changed on a transform. - /// - [System.Flags] - [APIExclude] - internal enum ChangedTransformProperties : byte - { - Unset = 0, - LocalPosition = 1, - LocalRotation = 2, - LocalScale = 4, - } - - [APIExclude] - internal static partial class ChangedTransformPropertiesEnum - { - /// - /// Returns if whole contains part. - /// - /// - /// - /// - public static bool Contains(ChangedTransformProperties whole, ChangedTransformProperties part) - { - return (whole & part) == part; - } - } - - -} - +//Remove on V5 \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Object/Editor/NetworkObjectEditor.cs b/Assets/FishNet/Runtime/Object/Editor/NetworkObjectEditor.cs index 98d763f..a21d0ee 100644 --- a/Assets/FishNet/Runtime/Object/Editor/NetworkObjectEditor.cs +++ b/Assets/FishNet/Runtime/Object/Editor/NetworkObjectEditor.cs @@ -1,5 +1,6 @@ #if UNITY_EDITOR #if !PREDICTION_1 +using FishNet.Object.Prediction; using UnityEditor; using UnityEngine; @@ -21,11 +22,17 @@ namespace FishNet.Object.Editing private SerializedProperty _networkTransform; private SerializedProperty _predictionType; private SerializedProperty _graphicalObject; + private SerializedProperty _detachGraphicalObject; + + private SerializedProperty _ownerSmoothedProperties; + private SerializedProperty _spectatorSmoothedProperties; private SerializedProperty _ownerInterpolation; + private SerializedProperty _adaptiveInterpolation; + private SerializedProperty _spectatorInterpolation; private SerializedProperty _enableTeleport; private SerializedProperty _teleportThreshold; - - + + protected virtual void OnEnable() { @@ -40,11 +47,15 @@ namespace FishNet.Object.Editing _networkTransform = serializedObject.FindProperty(nameof(_networkTransform)); _predictionType = serializedObject.FindProperty(nameof(_predictionType)); _graphicalObject = serializedObject.FindProperty(nameof(_graphicalObject)); + _detachGraphicalObject = serializedObject.FindProperty(nameof(_detachGraphicalObject)); + + _ownerSmoothedProperties = serializedObject.FindProperty(nameof(_ownerSmoothedProperties)); + _ownerInterpolation = serializedObject.FindProperty(nameof(_ownerInterpolation)); + _adaptiveInterpolation = serializedObject.FindProperty(nameof(_adaptiveInterpolation)); + _spectatorSmoothedProperties = serializedObject.FindProperty(nameof(_spectatorSmoothedProperties)); + _spectatorInterpolation = serializedObject.FindProperty(nameof(_spectatorInterpolation)); _enableTeleport = serializedObject.FindProperty(nameof(_enableTeleport)); _teleportThreshold = serializedObject.FindProperty(nameof(_teleportThreshold)); - - - _ownerInterpolation = serializedObject.FindProperty(nameof(_ownerInterpolation)); } public override void OnInspectorGUI() @@ -80,19 +91,51 @@ namespace FishNet.Object.Editing EditorGUILayout.PropertyField(_networkTransform); EditorGUI.indentLevel--; } - EditorGUILayout.PropertyField(_graphicalObject); - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(_ownerInterpolation, new GUIContent("Interpolation")); - EditorGUILayout.PropertyField(_enableTeleport); - if (_enableTeleport.boolValue == true) + + bool graphicalSet = (_graphicalObject.objectReferenceValue != null); + EditorGUILayout.PropertyField(_graphicalObject); + if (graphicalSet) { EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(_teleportThreshold, new GUIContent("Teleport Threshold")); + EditorGUILayout.PropertyField(_detachGraphicalObject); + EditorGUI.indentLevel--; + } + EditorGUILayout.LabelField("Smoothing", EditorStyles.boldLabel); + if (!graphicalSet) + { + EditorGUILayout.HelpBox($"More smoothing settings will be displayed when a graphicalObject is set.", MessageType.Info); + } + else + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_enableTeleport); + if (_enableTeleport.boolValue == true) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_teleportThreshold, new GUIContent("Teleport Threshold")); + EditorGUI.indentLevel--; + } + + EditorGUILayout.LabelField("Owner", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_ownerInterpolation, new GUIContent("Interpolation")); + EditorGUILayout.PropertyField(_ownerSmoothedProperties, new GUIContent("Smoothed Properties")); + EditorGUI.indentLevel--; + + EditorGUILayout.LabelField("Spectator", EditorStyles.boldLabel); + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_adaptiveInterpolation); + if (_adaptiveInterpolation.intValue == (int)AdaptiveInterpolationType.Off) + { + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(_spectatorInterpolation, new GUIContent("Interpolation")); + EditorGUI.indentLevel--; + } + EditorGUILayout.PropertyField(_spectatorSmoothedProperties, new GUIContent("Smoothed Properties")); EditorGUI.indentLevel--; } EditorGUI.indentLevel--; - EditorGUI.indentLevel--; } EditorGUI.indentLevel--; diff --git a/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs b/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs index c9d1ae1..affeed0 100644 --- a/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs +++ b/Assets/FishNet/Runtime/Object/NetworkBehaviour.Prediction.cs @@ -1,4 +1,7 @@ -#if !PREDICTION_1 +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +#if !PREDICTION_1 using FishNet.CodeGenerating; using FishNet.Connection; using FishNet.Documenting; @@ -324,7 +327,7 @@ namespace FishNet.Object methodWriter.Write(reconcileData); PooledWriter writer; -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (NetworkManager.DebugManager.ReconcileRpcLinks && _rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) #else if (_rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) @@ -348,49 +351,49 @@ namespace FishNet.Object writer.Store(); } - // /// - // /// Returns if there is a chance the transform may change after the tick. - // /// - // /// - // protected internal bool PredictedTransformMayChange() - // { - // if (TimeManager.PhysicsMode == PhysicsMode.Disabled) - // return false; + // /// + // /// Returns if there is a chance the transform may change after the tick. + // /// + // /// + // protected internal bool PredictedTransformMayChange() + // { + // if (TimeManager.PhysicsMode == PhysicsMode.Disabled) + // return false; - // if (!_predictionInitialized) - // { - // _predictionInitialized = true; - // _predictionRigidbody = GetComponentInParent(); - // _predictionRigidbody2d = GetComponentInParent(); - // } + // if (!_predictionInitialized) + // { + // _predictionInitialized = true; + // _predictionRigidbody = GetComponentInParent(); + // _predictionRigidbody2d = GetComponentInParent(); + // } - // /* Use distance when checking if changed because rigidbodies can twitch - //* or move an extremely small amount. These small moves are not worth - //* resending over because they often fix themselves each frame. */ - // float changeDistance = 0.000004f; + // /* Use distance when checking if changed because rigidbodies can twitch + //* or move an extremely small amount. These small moves are not worth + //* resending over because they often fix themselves each frame. */ + // float changeDistance = 0.000004f; - // bool positionChanged = (transform.position - _lastMayChangePosition).sqrMagnitude > changeDistance; - // bool rotationChanged = (transform.rotation.eulerAngles - _lastMayChangeRotation.eulerAngles).sqrMagnitude > changeDistance; - // bool scaleChanged = (transform.localScale - _lastMayChangeScale).sqrMagnitude > changeDistance; - // bool transformChanged = (positionChanged || rotationChanged || scaleChanged); - // /* Returns true if transform.hasChanged, or if either - //* of the rigidbodies have velocity. */ - // bool changed = ( - // transformChanged || - // (_predictionRigidbody != null && (_predictionRigidbody.velocity != Vector3.zero || _predictionRigidbody.angularVelocity != Vector3.zero)) || - // (_predictionRigidbody2d != null && (_predictionRigidbody2d.velocity != Vector2.zero || _predictionRigidbody2d.angularVelocity != 0f)) - // ); + // bool positionChanged = (transform.position - _lastMayChangePosition).sqrMagnitude > changeDistance; + // bool rotationChanged = (transform.rotation.eulerAngles - _lastMayChangeRotation.eulerAngles).sqrMagnitude > changeDistance; + // bool scaleChanged = (transform.localScale - _lastMayChangeScale).sqrMagnitude > changeDistance; + // bool transformChanged = (positionChanged || rotationChanged || scaleChanged); + // /* Returns true if transform.hasChanged, or if either + //* of the rigidbodies have velocity. */ + // bool changed = ( + // transformChanged || + // (_predictionRigidbody != null && (_predictionRigidbody.velocity != Vector3.zero || _predictionRigidbody.angularVelocity != Vector3.zero)) || + // (_predictionRigidbody2d != null && (_predictionRigidbody2d.velocity != Vector2.zero || _predictionRigidbody2d.angularVelocity != 0f)) + // ); - // //If transform changed update last values. - // if (transformChanged) - // { - // _lastMayChangePosition = transform.position; - // _lastMayChangeRotation = transform.rotation; - // _lastMayChangeScale = transform.localScale; - // } + // //If transform changed update last values. + // if (transformChanged) + // { + // _lastMayChangePosition = transform.position; + // _lastMayChangeRotation = transform.rotation; + // _lastMayChangeScale = transform.localScale; + // } - // return changed; - // } + // return changed; + // } /// @@ -438,26 +441,37 @@ namespace FishNet.Object /// protected internal void Replicate_Replay_NonAuthoritative(uint replayTick, ReplicateUserLogicDelegate del, List replicatesHistory, Channel channel) where T : IReplicateData { - ReplicateTickFinder.DataPlacementResult findResult; - int replicateIndex = ReplicateTickFinder.GetReplicateHistoryIndex(replayTick, replicatesHistory, out findResult); - + T data; ReplicateState state; - //If found then the replicate has been received by the server. - if (findResult == ReplicateTickFinder.DataPlacementResult.Exact) + //If the first replay. + if (replayTick == (_networkObjectCache.PredictionManager.ServerStateTick + 1)) { - data = replicatesHistory[replicateIndex]; - state = ReplicateState.ReplayedCreated; + ReplicateTickFinder.DataPlacementResult findResult; + int replicateIndex = ReplicateTickFinder.GetReplicateHistoryIndex(replayTick, replicatesHistory, out findResult); + //If not found then something went wrong. + if (findResult == ReplicateTickFinder.DataPlacementResult.Exact) + { + data = replicatesHistory[replicateIndex]; + state = ReplicateState.ReplayedCreated; + } + else + { + SetDataToDefault(); + } } - //If not not found then it's being run as predicted. + //Not the first replay tick. else + { + SetDataToDefault(); + } + + + void SetDataToDefault() { data = default; data.SetTick(replayTick); - if (replicatesHistory.Count == 0 || replicatesHistory[^1].GetTick() < replayTick) - state = ReplicateState.ReplayedFuture; - else - state = ReplicateState.ReplayedCreated; + state = ReplicateState.ReplayedFuture; } del.Invoke(data, state, channel); @@ -581,36 +595,19 @@ namespace FishNet.Object PredictionManager pm = NetworkManager.PredictionManager; uint localTick = TimeManager.LocalTick; - data.SetTick(localTick); - replicatesHistory.Add(data); - //Check to reset resends. - bool isDefault = isDefaultDel.Invoke(data); - bool mayChange = false;// PredictedTransformMayChange(); - bool resetResends = (mayChange || !isDefault); - /* If remaining resends is more than 0 then that means - * redundancy is still in effect. When redundancy is not - * in effect then histories to send can be 1 for this iteration. */ - int pastInputs = (_remainingResends > 0) ? PredictionManager.RedundancyCount : 1; - //pastInputs = PredictionManager.RedundancyCount; - if (resetResends) - _remainingResends = pm.RedundancyCount; - - bool sendData = (_remainingResends > 0); - if (sendData) + /* The following code is to remove replicates from replicatesHistory + * which exceed the buffer allowance. Replicates are kept for up to + * x seconds to clients can re-run them during a reconcile. The reconcile + * method removes old histories but given the server does not reconcile, + * it will never perform that operation. + * The server would not actually need to keep replicates history except + * when it is also client(clientHost). This is because the clientHost must + * send redundancies to other clients still, therefor that redundancyCount + * must be the allowance when clientHost. */ + if (IsHostStarted) { int replicatesHistoryCount = replicatesHistory.Count; - /* Remove the number of replicates which are over maximum. - * - * The clientHost object must keep redundancy count - * to send past inputs to others. - * - * Otherwise use maximum client replicates which will be a variable - * rate depending on tick rate. The value returned is several seconds - * worth of owner inputs to be able to replay during a reconcile. - * - * Server does not reconcile os it only needs enough for redundancy. - */ - int maxCount = (IsServerStarted) ? pm.RedundancyCount : pm.MaximumClientReplicates; + int maxCount = pm.RedundancyCount; //Number to remove which is over max count. int removeCount = (replicatesHistoryCount - maxCount); //If there are any to remove. @@ -623,11 +620,26 @@ namespace FishNet.Object //Then remove range. replicatesHistory.RemoveRange(0, removeCount); } + } + data.SetTick(localTick); + replicatesHistory.Add(data); + //Check to reset resends. + bool isDefault = isDefaultDel.Invoke(data); + bool mayChange = false;// PredictedTransformMayChange(); + bool resetResends = (mayChange || !isDefault); + + byte redundancyCount = PredictionManager.RedundancyCount; + if (resetResends) + _remainingResends = redundancyCount; + + bool sendData = (_remainingResends > 0); + if (sendData) + { /* If not server then send to server. * If server then send to clients. */ bool toServer = !IsServerStarted; - Replicate_SendAuthoritative(toServer, methodHash, pastInputs, replicatesHistory, localTick, channel); + Replicate_SendAuthoritative(toServer, methodHash, redundancyCount, replicatesHistory, localTick, channel); _remainingResends--; } @@ -635,7 +647,6 @@ namespace FishNet.Object _networkObjectCache.SetReplicateTick(data.GetTick(), true); //Owner always replicates with new data. del.Invoke(data, ReplicateState.CurrentCreated, channel); - //TODO: dispose replicate datas from history on replays. } /// @@ -771,7 +782,6 @@ namespace FishNet.Object /// /// Sends data from a reader which only contains the replicate packet. /// - /// Tick of the last replicate entry. [MakePublic] internal void Replicate_SendNonAuthoritative(uint hash, BasicQueue replicatesQueue, Channel channel) where T : IReplicateData { @@ -781,12 +791,11 @@ namespace FishNet.Object return; int queueCount = replicatesQueue.Count; - //Limit history count to max of queued amount, or queued inputs, whichever is lesser. - int historyCount = (int)Mathf.Min(_networkObjectCache.PredictionManager.RedundancyCount, queueCount); //None to send. - if (historyCount == 0) + if (queueCount == 0) return; + int redundancyCount = (int)Mathf.Min(_networkObjectCache.PredictionManager.RedundancyCount, queueCount); //If the only observer is the owner then there is no need to write. int observersCount = Observers.Count; //Quick exit for no observers other than owner. @@ -810,7 +819,7 @@ namespace FishNet.Object //Write the run tick now. methodWriter.WriteTickUnpacked(runTickOflastEntry); //Write the replicates. - methodWriter.WriteReplicate(replicatesQueue, historyCount, runTickOflastEntry); + methodWriter.WriteReplicate(replicatesQueue, redundancyCount, runTickOflastEntry); PooledWriter writer = CreateRpc(hash, methodWriter, PacketId.Replicate, channel); @@ -830,14 +839,14 @@ namespace FishNet.Object /// Handles a received replicate packet. /// private void Replicate_EnqueueReceivedReplicate(int receivedReplicatesCount, T[] arrBuffer, BasicQueue replicatesQueue, List replicatesHistory, Channel channel) where T : IReplicateData - { + { int startQueueCount = replicatesQueue.Count; /* Owner never gets this for their own object so * this can be processed under the assumption data is only * handled on unowned objects. */ PredictionManager pm = PredictionManager; //Maximum number of replicates allowed to be queued at once. - int maximmumReplicates = (IsServerStarted) ? pm.GetMaximumServerReplicates() : pm.MaximumClientReplicates; + int maximmumReplicates = (IsServerStarted) ? pm.GetMaximumServerReplicates() : pm.MaximumPastReplicates; for (int i = 0; i < receivedReplicatesCount; i++) { T entry = arrBuffer[i]; @@ -917,7 +926,8 @@ namespace FishNet.Object * by holding reconcile x ticks rather than not running received * x ticks. */ if (_networkObjectCache.IsServerInitialized && startQueueCount == 0 && replicatesQueue.Count > 0) - _replicateStartTick = (_networkObjectCache.TimeManager.LocalTick + pm.QueuedInputs); + //_replicateStartTick = (_networkObjectCache.TimeManager.LocalTick); + _replicateStartTick = (_networkObjectCache.TimeManager.LocalTick + pm.StateInterpolation); } @@ -1336,7 +1346,7 @@ namespace FishNet.Object methodWriter.Write(reconcileData); PooledWriter writer; -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (NetworkManager.DebugManager.ReconcileRpcLinks && _rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) #else if (_rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) diff --git a/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs b/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs index 1b36c8b..4389c07 100644 --- a/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs +++ b/Assets/FishNet/Runtime/Object/NetworkBehaviour.RPCs.cs @@ -1,4 +1,7 @@ -using FishNet.CodeGenerating; +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +using FishNet.CodeGenerating; using FishNet.Connection; using FishNet.Documenting; using FishNet.Managing; @@ -249,7 +252,7 @@ namespace FishNet.Object _transportManagerCache.CheckSetReliableChannel(methodWriter.Length + MAXIMUM_RPC_HEADER_SIZE, ref channel); PooledWriter writer; -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (NetworkManager.DebugManager.ObserverRpcLinks && _rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) #else if (_rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) @@ -314,7 +317,7 @@ namespace FishNet.Object PooledWriter writer; -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT if (NetworkManager.DebugManager.TargetRpcLinks && _rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) #else if (_rpcLinks.TryGetValueIL2CPP(hash, out RpcLinkType link)) diff --git a/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs b/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs index a036b43..a3fb7b1 100644 --- a/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs +++ b/Assets/FishNet/Runtime/Object/NetworkObject.Callbacks.cs @@ -6,11 +6,22 @@ namespace FishNet.Object { public partial class NetworkObject : MonoBehaviour { + #region Private. + /// + /// True if OnStartServer was called. + /// + private bool _onStartServerCalled; + /// + /// True if OnStartClient was called. + /// + private bool _onStartClientCalled; + #endregion + /// /// Called after all data is synchronized with this NetworkObject. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void InitializeCallbacks(bool asServer, bool invokeSyncTypeCallbacks) + private void InvokeStartCallbacks(bool asServer, bool invokeSyncTypeCallbacks) { /* Note: When invoking OnOwnership here previous owner will * always be an empty connection, since the object is just @@ -25,6 +36,7 @@ namespace FishNet.Object { for (int i = 0; i < NetworkBehaviours.Length; i++) NetworkBehaviours[i].OnStartServer_Internal(); + _onStartServerCalled = true; for (int i = 0; i < NetworkBehaviours.Length; i++) NetworkBehaviours[i].OnOwnershipServer_Internal(FishNet.Managing.NetworkManager.EmptyConnection); } @@ -33,12 +45,17 @@ namespace FishNet.Object { for (int i = 0; i < NetworkBehaviours.Length; i++) NetworkBehaviours[i].OnStartClient_Internal(); + _onStartClientCalled = true; for (int i = 0; i < NetworkBehaviours.Length; i++) NetworkBehaviours[i].OnOwnershipClient_Internal(FishNet.Managing.NetworkManager.EmptyConnection); } if (invokeSyncTypeCallbacks) InvokeOnStartSyncTypeCallbacks(true); + +#if !PREDICTION_1 + InvokeStartCallbacks_Prediction(asServer); +#endif } @@ -88,48 +105,35 @@ namespace FishNet.Object /// Invokes OnStop callbacks. /// /// - internal void InvokeStopCallbacks(bool asServer) + internal void InvokeStopCallbacks(bool asServer, bool invokeSyncTypeCallbacks) { - for (int i = 0; i < NetworkBehaviours.Length; i++) - NetworkBehaviours[i].InvokeSyncTypeOnStopCallbacks(asServer); +#if !PREDICTION_1 + InvokeStopCallbacks_Prediction(asServer); +#endif + if (invokeSyncTypeCallbacks) + InvokeOnStopSyncTypeCallbacks(asServer); - if (asServer) + bool invokeOnNetwork = (!asServer || (asServer && !_onStartClientCalled)); + if (asServer && _onStartServerCalled) { for (int i = 0; i < NetworkBehaviours.Length; i++) NetworkBehaviours[i].OnStopServer_Internal(); + _onStartServerCalled = false; } - else + else if (!asServer && _onStartClientCalled) { for (int i = 0; i < NetworkBehaviours.Length; i++) NetworkBehaviours[i].OnStopClient_Internal(); + _onStartClientCalled = false; } - /* Several conditions determine if OnStopNetwork can - * be called. - * - * - If asServer and pending destroy from clientHost. - * - If !asServer and not ServerInitialized. */ - bool callStopNetwork; - if (asServer) - { - if (!IsClientStarted) - callStopNetwork = true; - else - callStopNetwork = (ServerManager.Objects.GetFromPending(ObjectId) == null); - } - else - { - /* When not as server only perform OnStopNetwork if - * not initialized for the server. The object could be - * server initialized if it were spawned, despawned, then spawned again - * before client ran this method. */ - callStopNetwork = !IsServerInitialized; - } - if (callStopNetwork) + if (invokeOnNetwork) { for (int i = 0; i < NetworkBehaviours.Length; i++) NetworkBehaviours[i].InvokeOnNetwork(false); } + + } /// diff --git a/Assets/FishNet/Runtime/Object/NetworkObject.Prediction.cs b/Assets/FishNet/Runtime/Object/NetworkObject.Prediction.cs index 0f5b4fe..e3173ab 100644 --- a/Assets/FishNet/Runtime/Object/NetworkObject.Prediction.cs +++ b/Assets/FishNet/Runtime/Object/NetworkObject.Prediction.cs @@ -33,6 +33,10 @@ namespace FishNet.Object /// True if a reconcile is occuring on any NetworkBehaviour that is on or nested of this NetworkObject. Runtime NetworkBehaviours are not included, such as if you child a NetworkObject to another at runtime. /// public bool IsObjectReconciling { get; internal set; } + /// + /// Graphical smoother to use when using set for owner. + /// + public ChildTransformTickSmoother PredictionSmoother { get; private set; } #endif /// /// Last tick this object replicated. @@ -74,6 +78,28 @@ namespace FishNet.Object [SerializeField] private Transform _graphicalObject; /// + /// Gets the current graphical object for prediction. + /// + /// + public Transform GetGraphicalObject() => _graphicalObject; + /// + /// Sets a new graphical object for prediction. + /// + /// + public void SetGraphicalObject(Transform t) + { + _graphicalObject = t; + InitializeTickSmoother(); + } + /// + /// True to detach and re-attach the graphical object at runtime when the client initializes/deinitializes the item. + /// This can resolve camera jitter or be helpful objects child of the graphical which do not handle reconiliation well, such as certain animation rigs. + /// Transform is detached after OnStartClient, and reattached before OnStopClient. + /// + [Tooltip("True to detach and re-attach the graphical object at runtime when the client initializes/deinitializes the item. This can resolve camera jitter or be helpful objects child of the graphical which do not handle reconiliation well, such as certain animation rigs. Transform is detached after OnStartClient, and reattached before OnStopClient.")] + [SerializeField] + private bool _detachGraphicalObject; + /// /// True to forward replicate and reconcile states to all clients. This is ideal with games where you want all clients and server to run the same inputs. False to only use prediction on the owner, and synchronize to spectators using other means such as a NetworkTransform. /// public bool EnableStateForwarding => (_enablePrediction && _enableStateForwarding); @@ -94,6 +120,29 @@ namespace FishNet.Object [SerializeField] private byte _ownerInterpolation = 1; /// + /// Properties of the graphicalObject to smooth when owned. + /// + [SerializeField] + private TransformPropertiesFlag _ownerSmoothedProperties = (TransformPropertiesFlag)~(-1 << 8); + /// + /// Interpolation amount of adaptive interpolation to use on non-owned objects. Higher levels result in more interpolation. When off spectatorInterpolation is used; when on interpolation based on strength and local client latency is used. + /// + [Tooltip("Interpolation amount of adaptive interpolation to use on non-owned objects. Higher levels result in more interpolation. When off spectatorInterpolation is used; when on interpolation based on strength and local client latency is used.")] + [SerializeField] + private AdaptiveInterpolationType _adaptiveInterpolation = AdaptiveInterpolationType.Medium; + /// + /// Properties of the graphicalObject to smooth when the object is spectated. + /// + [SerializeField] + private TransformPropertiesFlag _spectatorSmoothedProperties = (TransformPropertiesFlag)~(-1 << 8); + /// + /// How many ticks to interpolate graphics on objects when not owned by the client. + /// + [Tooltip("How many ticks to interpolate graphics on objects when not owned by the client.")] + [Range(1, byte.MaxValue)] + [SerializeField] + private byte _spectatorInterpolation = 2; + /// /// True to enable teleport threshhold. /// [Tooltip("True to enable teleport threshhold.")] @@ -111,10 +160,6 @@ namespace FishNet.Object #region Private. /// - /// Graphical smoother to use when using set for owner. - /// - private LocalTransformTickSmoother _tickSmoother; - /// /// NetworkBehaviours which use prediction. /// private List _predictionBehaviours = new List(); @@ -125,16 +170,7 @@ namespace FishNet.Object if (!_enablePrediction) return; - _tickSmoother?.Update(); - } - - private void TimeManager_OnPreTick() - { - _tickSmoother?.OnPreTick(); - } - private void TimeManager_OnPostTick() - { - _tickSmoother?.OnPostTick(); + PredictionSmoother?.Update(); } private void Prediction_Preinitialize(NetworkManager manager, bool asServer) @@ -146,19 +182,14 @@ namespace FishNet.Object _networkTransform.ConfigureForPrediction(_predictionType); ReplicateTick.Initialize(manager.TimeManager); - InitializeSmoothers(); + if (!asServer) + InitializeSmoothers(); if (asServer) return; if (_predictionBehaviours.Count > 0) - { - manager.PredictionManager.OnReconcile += PredictionManager_OnReconcile; - manager.PredictionManager.OnReplicateReplay += PredictionManager_OnReplicateReplay; - manager.PredictionManager.OnPostReconcile += PredictionManager_OnPostReconcile; - manager.TimeManager.OnPreTick += TimeManager_OnPreTick; - manager.TimeManager.OnPostTick += TimeManager_OnPostTick; - } + ChangePredictionSubscriptions(true, manager); } private void Prediction_Deinitialize(bool asServer) @@ -170,13 +201,37 @@ namespace FishNet.Object /* Only the client needs to unsubscribe from these but * asServer may not invoke as false if the client is suddenly * dropping their connection. */ - if (_predictionBehaviours.Count > 0 && NetworkManager != null) + if (_predictionBehaviours.Count > 0) + ChangePredictionSubscriptions(false, NetworkManager); + } + + /// + /// Changes subscriptions to use callbacks for prediction. + /// + private void ChangePredictionSubscriptions(bool subscribe, NetworkManager manager) + { + if (manager == null) + return; + + if (subscribe) { - NetworkManager.PredictionManager.OnReconcile -= PredictionManager_OnReconcile; - NetworkManager.PredictionManager.OnReplicateReplay -= PredictionManager_OnReplicateReplay; - NetworkManager.PredictionManager.OnPostReconcile -= PredictionManager_OnPostReconcile; - NetworkManager.TimeManager.OnPreTick -= TimeManager_OnPreTick; - NetworkManager.TimeManager.OnPostTick -= TimeManager_OnPostTick; + manager.PredictionManager.OnPreReconcile += PredictionManager_OnPreReconcile; + manager.PredictionManager.OnReconcile += PredictionManager_OnReconcile; + manager.PredictionManager.OnReplicateReplay += PredictionManager_OnReplicateReplay; + manager.PredictionManager.OnPostReplicateReplay += PredictionManager_OnPostReplicateReplay; + manager.PredictionManager.OnPostReconcile += PredictionManager_OnPostReconcile; + manager.TimeManager.OnPreTick += TimeManager_OnPreTick; + manager.TimeManager.OnPostTick += TimeManager_OnPostTick; + } + else + { + manager.PredictionManager.OnPreReconcile -= PredictionManager_OnPreReconcile; + manager.PredictionManager.OnReconcile -= PredictionManager_OnReconcile; + manager.PredictionManager.OnReplicateReplay -= PredictionManager_OnReplicateReplay; + manager.PredictionManager.OnPostReplicateReplay -= PredictionManager_OnPostReplicateReplay; + manager.PredictionManager.OnPostReconcile -= PredictionManager_OnPostReconcile; + manager.TimeManager.OnPreTick -= TimeManager_OnPreTick; + manager.TimeManager.OnPostTick -= TimeManager_OnPostTick; } } @@ -201,25 +256,75 @@ namespace FishNet.Object } else { - if (_tickSmoother == null) - _tickSmoother = ResettableObjectCaches.Retrieve(); - float teleportT = (_enableTeleport) ? _teleportThreshold : MoveRatesCls.UNSET_VALUE; - _tickSmoother.InitializeOnce(_graphicalObject, teleportT, (float)TimeManager.TickDelta, _ownerInterpolation); + if (PredictionSmoother == null) + PredictionSmoother = ResettableObjectCaches.Retrieve(); + InitializeTickSmoother(); } } + /// + /// Initializes the tick smoother. + /// + private void InitializeTickSmoother() + { + if (PredictionSmoother == null) + return; + float teleportT = (_enableTeleport) ? _teleportThreshold : MoveRatesCls.UNSET_VALUE; + PredictionSmoother.Initialize(this, _graphicalObject, _detachGraphicalObject, teleportT, (float)TimeManager.TickDelta, _ownerInterpolation, _ownerSmoothedProperties, _spectatorInterpolation, _spectatorSmoothedProperties, _adaptiveInterpolation); + } /// /// Initializes tick smoothing. /// private void DeinitializeSmoothers() { - if (_tickSmoother != null) + if (PredictionSmoother != null) { - ResettableObjectCaches.StoreAndDefault(ref _tickSmoother); + PredictionSmoother.Deinitialize(); + ResettableObjectCaches.Store(PredictionSmoother); + PredictionSmoother = null; ResettableObjectCaches.StoreAndDefault(ref _rigidbodyPauser); } } + + private void InvokeStartCallbacks_Prediction(bool asServer) + { + if (_predictionBehaviours.Count == 0) + return; + + if (!asServer) + PredictionSmoother?.OnStartClient(); + } + private void InvokeStopCallbacks_Prediction(bool asServer) + { + if (_predictionBehaviours.Count == 0) + return; + + if (!asServer) + PredictionSmoother?.OnStopClient(); + } + + private void TimeManager_OnPreTick() + { + PredictionSmoother?.OnPreTick(); + } + + private void PredictionManager_OnPostReplicateReplay(uint clientTick, uint serverTick) + { + PredictionSmoother?.OnPostReplay(clientTick); + } + + private void TimeManager_OnPostTick() + { + PredictionSmoother?.OnPostTick(NetworkManager.TimeManager.LocalTick); + } + + private void PredictionManager_OnPreReconcile(uint clientTick, uint serverTick) + { + PredictionSmoother?.OnPreReconcile(); + } + + private void PredictionManager_OnReconcile(uint clientReconcileTick, uint serverReconcileTick) { if (!IsObjectReconciling) diff --git a/Assets/FishNet/Runtime/Object/NetworkObject.cs b/Assets/FishNet/Runtime/Object/NetworkObject.cs index b57ec35..fc70a60 100644 --- a/Assets/FishNet/Runtime/Object/NetworkObject.cs +++ b/Assets/FishNet/Runtime/Object/NetworkObject.cs @@ -337,9 +337,25 @@ namespace FishNet.Object private void OnDestroy() { - //Already being deinitialized by FishNet. + /* If already deinitializing then FishNet is in the process of, + * or has finished cleaning up this object. */ + //callStopNetwork = (ServerManager.Objects.GetFromPending(ObjectId) == null); if (IsDeinitializing) - return; + { + /* There is however chance the object can get destroyed before deinitializing + * as clientHost. If not clientHost its safe to skip deinitializing again. + * But if clientHost, check if the client has deinitialized. If not then do + * so now for the client side. */ + if (IsHostStarted) + { + if (!_onStartClientCalled) + return; + } + else + { + return; + } + } Owner?.RemoveObject(this); NetworkObserver?.Deinitialize(true); @@ -349,12 +365,12 @@ namespace FishNet.Object //Was destroyed without going through the proper methods. if (NetworkManager.IsServerStarted) { - DeinitializePrediction_V2(true); + Deinitialize_Prediction(true); NetworkManager.ServerManager.Objects.NetworkObjectUnexpectedlyDestroyed(this, true); } if (NetworkManager.IsClientStarted) { - DeinitializePrediction_V2(false); + Deinitialize_Prediction(false); NetworkManager.ClientManager.Objects.NetworkObjectUnexpectedlyDestroyed(this, false); } } @@ -364,9 +380,9 @@ namespace FishNet.Object * the server or client side, so send callbacks * for both. */ if (IsServerStarted) - InvokeStopCallbacks(true); + InvokeStopCallbacks(true, true); if (IsClientStarted) - InvokeStopCallbacks(false); + InvokeStopCallbacks(false, true); /* If owner exist then remove object from owner. * This has to be called here as well OnDisable because @@ -392,7 +408,7 @@ namespace FishNet.Object //Do not need to set state if being destroyed. //Don't need to reset sync types if object is being destroyed. - void DeinitializePrediction_V2(bool asServer) + void Deinitialize_Prediction(bool asServer) { #if !PREDICTION_1 Prediction_Deinitialize(asServer); @@ -817,7 +833,7 @@ namespace FishNet.Object internal void Initialize(bool asServer, bool invokeSyncTypeCallbacks) { SetInitializedStatus(true, asServer); - InitializeCallbacks(asServer, invokeSyncTypeCallbacks); + InvokeStartCallbacks(asServer, invokeSyncTypeCallbacks); } /// @@ -828,7 +844,7 @@ namespace FishNet.Object #if !PREDICTION_1 Prediction_Deinitialize(asServer); #endif - InvokeStopCallbacks(asServer); + InvokeStopCallbacks(asServer, true); for (int i = 0; i < NetworkBehaviours.Length; i++) NetworkBehaviours[i].Deinitialize(asServer); @@ -946,7 +962,7 @@ namespace FishNet.Object //After changing owners invoke callbacks. InvokeOwnershipChange(prevOwner, asServer); - + //If asServer send updates to clients as needed. if (asServer) { @@ -1025,35 +1041,35 @@ namespace FishNet.Object /// Returns if this NetworkObject is a scene object, and has changed. /// /// - internal ChangedTransformProperties GetTransformChanges(TransformProperties stp) + internal TransformPropertiesFlag GetTransformChanges(TransformProperties stp) { - ChangedTransformProperties ctp = ChangedTransformProperties.Unset; + TransformPropertiesFlag tpf = TransformPropertiesFlag.Unset; if (transform.localPosition != stp.Position) - ctp |= ChangedTransformProperties.LocalPosition; + tpf |= TransformPropertiesFlag.Position; if (transform.localRotation != stp.Rotation) - ctp |= ChangedTransformProperties.LocalRotation; + tpf |= TransformPropertiesFlag.Rotation; if (transform.localScale != stp.LocalScale) - ctp |= ChangedTransformProperties.LocalScale; + tpf |= TransformPropertiesFlag.LocalScale; - return ctp; + return tpf; } /// /// Returns if this NetworkObject is a scene object, and has changed. /// /// - internal ChangedTransformProperties GetTransformChanges(GameObject prefab) + internal TransformPropertiesFlag GetTransformChanges(GameObject prefab) { Transform t = prefab.transform; - ChangedTransformProperties ctp = ChangedTransformProperties.Unset; + TransformPropertiesFlag tpf = TransformPropertiesFlag.Unset; if (transform.position != t.position) - ctp |= ChangedTransformProperties.LocalPosition; + tpf |= TransformPropertiesFlag.Position; if (transform.rotation != t.rotation) - ctp |= ChangedTransformProperties.LocalRotation; + tpf |= TransformPropertiesFlag.Rotation; if (transform.localScale != t.localScale) - ctp |= ChangedTransformProperties.LocalScale; + tpf |= TransformPropertiesFlag.LocalScale; - return ctp; + return tpf; } #region Editor. diff --git a/Assets/FishNet/Runtime/Object/Prediction/MoveRates.cs b/Assets/FishNet/Runtime/Object/Prediction/MoveRates.cs index 3d5f508..04a7b20 100644 --- a/Assets/FishNet/Runtime/Object/Prediction/MoveRates.cs +++ b/Assets/FishNet/Runtime/Object/Prediction/MoveRates.cs @@ -13,25 +13,33 @@ namespace FishNet.Object.Prediction public float Position; public float Rotation; public float Scale; + public float TimeRemaining; - public MoveRates(float value) + public MoveRates(float value) : this() { Position = value; Rotation = value; Scale = value; } - public MoveRates(float position, float rotation) + public MoveRates(float position, float rotation) : this() { Position = position; Rotation = rotation; Scale = MoveRatesCls.INSTANT_VALUE; } - public MoveRates(float position, float rotation, float scale) + public MoveRates(float position, float rotation, float scale) : this() { Position = position; Rotation = rotation; Scale = scale; } + public MoveRates(float position, float rotation, float scale, float timeRemaining) + { + Position = position; + Rotation = rotation; + Scale = scale; + TimeRemaining = timeRemaining; + } /// /// True if a positional move rate is set. @@ -125,6 +133,15 @@ namespace FishNet.Object.Prediction return GetMoveRates(prevValues.Position, t.localPosition, prevValues.Rotation, t.localRotation, prevValues.LocalScale, t.localScale, duration, teleportThreshold); } + /// + /// Returns a new MoveRates based on previous values, and a transforms current position. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static MoveRates GetMoveRates(TransformProperties prevValues, TransformProperties nextValues, float duration, float teleportThreshold) + { + return GetMoveRates(prevValues.Position, nextValues.Position, prevValues.Rotation, nextValues.Rotation, prevValues.LocalScale, nextValues.LocalScale, duration, teleportThreshold); + } + /// /// Returns a new MoveRates based on previous values, and a transforms current position. /// @@ -190,8 +207,6 @@ namespace FishNet.Object.Prediction return rotationRate; } - - /// /// Moves transform to target values. /// @@ -203,9 +218,9 @@ namespace FishNet.Object.Prediction return; MoveRatesCls.MoveLocalToTarget(movingTransform, goalProperties.Position, Position, goalProperties.Rotation, Rotation, goalProperties.LocalScale, Scale, delta); + TimeRemaining -= delta; } - /// /// Moves transform to target values. /// @@ -217,6 +232,20 @@ namespace FishNet.Object.Prediction return; MoveRatesCls.MoveWorldToTarget(movingTransform, goalProperties.Position, Position, goalProperties.Rotation, Rotation, goalProperties.LocalScale, Scale, delta); + TimeRemaining -= delta; + } + /// + /// Moves transform to target values. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void MoveWorldToTarget(Transform movingTransform, TransformProperties goalProperties, TransformPropertiesFlag movedProperties, float delta) + { + //No rates are set. + if (!AnySet) + return; + + MoveRatesCls.MoveWorldToTarget(movingTransform, movedProperties, goalProperties.Position, Position, goalProperties.Rotation, Rotation, goalProperties.LocalScale, Scale, delta); + TimeRemaining -= delta; } } @@ -229,6 +258,7 @@ namespace FishNet.Object.Prediction public float Position; public float Rotation; public float Scale; + public float TimeRemaining; public MoveRatesCls(float value) { @@ -249,6 +279,14 @@ namespace FishNet.Object.Prediction Scale = scale; } + public MoveRatesCls(float position, float rotation, float scale, float timeRemaining) + { + Position = position; + Rotation = rotation; + Scale = scale; + TimeRemaining = timeRemaining; + } + /// /// True if a positional move rate is set. /// @@ -323,6 +361,7 @@ namespace FishNet.Object.Prediction Position = UNSET_VALUE; Rotation = UNSET_VALUE; Scale = UNSET_VALUE; + TimeRemaining = UNSET_VALUE; } public void InitializeState() { } @@ -336,6 +375,7 @@ namespace FishNet.Object.Prediction /// public const float INSTANT_VALUE = float.PositiveInfinity; + /// /// Moves transform to target values. /// @@ -347,6 +387,7 @@ namespace FishNet.Object.Prediction return; MoveRatesCls.MoveLocalToTarget(movingTransform, goalProperties.Position, Position, goalProperties.Rotation, Rotation, goalProperties.LocalScale, Scale, delta); + TimeRemaining -= delta; } /// @@ -354,58 +395,96 @@ namespace FishNet.Object.Prediction /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MoveLocalToTarget(Transform movingTransform, Vector3 posGoal, float posRate, Quaternion rotGoal, float rotRate, Vector3 scaleGoal, float scaleRate, float delta) + { + MoveLocalToTarget(movingTransform, TransformPropertiesFlag.Everything, posGoal, posRate, rotGoal, rotRate, scaleGoal, scaleRate, delta); + } + + /// + /// Moves transform to target values. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void MoveLocalToTarget(Transform movingTransform, TransformPropertiesFlag movedProperties, Vector3 posGoal, float posRate, Quaternion rotGoal, float rotRate, Vector3 scaleGoal, float scaleRate, float delta) { Transform t = movingTransform; float rate; - rate = posRate; - if (rate == MoveRatesCls.INSTANT_VALUE) - t.localPosition = posGoal; - else - t.localPosition = Vector3.MoveTowards(t.localPosition, posGoal, rate * delta); + if (movedProperties.FastContains(TransformPropertiesFlag.Position)) + { + rate = posRate; + if (rate == MoveRatesCls.INSTANT_VALUE) + t.localPosition = posGoal; + else + t.localPosition = Vector3.MoveTowards(t.localPosition, posGoal, rate * delta); + } - rate = rotRate; - if (rate == MoveRatesCls.INSTANT_VALUE) - t.localRotation = rotGoal; - else - t.localRotation = Quaternion.RotateTowards(t.localRotation, rotGoal, rate * delta); + if (movedProperties.FastContains(TransformPropertiesFlag.Rotation)) + { + rate = rotRate; + if (rate == MoveRatesCls.INSTANT_VALUE) + t.localRotation = rotGoal; + else + t.localRotation = Quaternion.RotateTowards(t.localRotation, rotGoal, rate * delta); + } - rate = scaleRate; - if (rate == MoveRatesCls.INSTANT_VALUE) - t.localScale = scaleGoal; - else - t.localScale = Vector3.MoveTowards(t.localScale, scaleGoal, rate * delta); + if (movedProperties.FastContains(TransformPropertiesFlag.LocalScale)) + { + rate = scaleRate; + if (rate == MoveRatesCls.INSTANT_VALUE) + t.localScale = scaleGoal; + else + t.localScale = Vector3.MoveTowards(t.localScale, scaleGoal, rate * delta); + } } - /// + /// /// Moves transform to target values. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void MoveWorldToTarget(Transform movingTransform, Vector3 posGoal, float posRate, Quaternion rotGoal, float rotRate, Vector3 scaleGoal, float scaleRate, float delta) + { + MoveWorldToTarget(movingTransform, TransformPropertiesFlag.Everything, posGoal, posRate, rotGoal, rotRate, scaleGoal, scaleRate, delta); + } + + /// + /// Moves transform to target values. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void MoveWorldToTarget(Transform movingTransform, TransformPropertiesFlag movedProperties, Vector3 posGoal, float posRate, Quaternion rotGoal, float rotRate, Vector3 scaleGoal, float scaleRate, float delta) { Transform t = movingTransform; float rate; - rate = posRate; - if (rate == MoveRatesCls.INSTANT_VALUE) - t.position = posGoal; - else if (rate == MoveRatesCls.UNSET_VALUE) { } - else - t.position = Vector3.MoveTowards(t.position, posGoal, rate * delta); + if (movedProperties.FastContains(TransformPropertiesFlag.Position)) + { + rate = posRate; + if (rate == MoveRatesCls.INSTANT_VALUE) + t.position = posGoal; + else if (rate == MoveRatesCls.UNSET_VALUE) { } + else + t.position = Vector3.MoveTowards(t.position, posGoal, rate * delta); + } - rate = rotRate; - if (rate == MoveRatesCls.INSTANT_VALUE) - t.rotation = rotGoal; - else if (rate == MoveRatesCls.UNSET_VALUE) { } - else - t.rotation = Quaternion.RotateTowards(t.rotation, rotGoal, rate * delta); + //Debug.Log($"StartX {start.x.ToString("0.00")}. End {t.position.x.ToString("0.00")}. Rate {posRate}. Delta {delta}"); - rate = scaleRate; - if (rate == MoveRatesCls.INSTANT_VALUE) - t.localScale = scaleGoal; - else if (rate == MoveRatesCls.UNSET_VALUE) { } - else - t.localScale = Vector3.MoveTowards(t.localScale, scaleGoal, rate * delta); + if (movedProperties.FastContains(TransformPropertiesFlag.Rotation)) + { + rate = rotRate; + if (rate == MoveRatesCls.INSTANT_VALUE) + t.rotation = rotGoal; + else if (rate == MoveRatesCls.UNSET_VALUE) { } + else + t.rotation = Quaternion.RotateTowards(t.rotation, rotGoal, rate * delta); + } + + if (movedProperties.FastContains(TransformPropertiesFlag.LocalScale)) + { + rate = scaleRate; + if (rate == MoveRatesCls.INSTANT_VALUE) + t.localScale = scaleGoal; + else if (rate == MoveRatesCls.UNSET_VALUE) { } + else + t.localScale = Vector3.MoveTowards(t.localScale, scaleGoal, rate * delta); + } } } diff --git a/Assets/FishNet/Runtime/Object/Prediction/PredictionRigidbody.cs b/Assets/FishNet/Runtime/Object/Prediction/PredictionRigidbody.cs index 62749df..adc96d4 100644 --- a/Assets/FishNet/Runtime/Object/Prediction/PredictionRigidbody.cs +++ b/Assets/FishNet/Runtime/Object/Prediction/PredictionRigidbody.cs @@ -1,4 +1,5 @@ using FishNet.CodeGenerating; +using FishNet.Component.Prediction; using FishNet.Managing; using FishNet.Serializing; using GameKit.Dependencies.Utilities; @@ -11,23 +12,32 @@ namespace FishNet.Object.Prediction public static class PredictionRigidbodySerializers { - public static void WriteForceData(this Writer w, PredictionRigidbody.EntryData value) + public static void WriteEntryData(this Writer w, PredictionRigidbody.EntryData value) { PredictionRigidbody.ForceApplicationType appType = value.Type; w.WriteByte((byte)appType); + PredictionRigidbody.AllForceData data = value.Data; + switch (appType) { case PredictionRigidbody.ForceApplicationType.AddTorque: case PredictionRigidbody.ForceApplicationType.AddForce: case PredictionRigidbody.ForceApplicationType.AddRelativeTorque: case PredictionRigidbody.ForceApplicationType.AddRelativeForce: - w.Write((PredictionRigidbody.ForceAndTorqueData)value.Data); + w.WriteVector3(data.Vector3Force); + w.WriteInt32((byte)data.Mode); break; case PredictionRigidbody.ForceApplicationType.AddExplosiveForce: - w.Write((PredictionRigidbody.ExplosiveForceData)value.Data); + w.WriteSingle(data.FloatForce); + w.WriteVector3(data.Position); + w.WriteSingle(data.Radius); + w.WriteSingle(data.UpwardsModifier); + w.WriteInt32((byte)data.Mode); break; case PredictionRigidbody.ForceApplicationType.AddForceAtPosition: - w.Write((PredictionRigidbody.PositionForceData)value.Data); + w.WriteVector3(data.Vector3Force); + w.WriteVector3(data.Position); + w.WriteInt32((byte)data.Mode); break; default: NetworkManagerExtensions.LogError($"ForceApplicationType of {appType} is not supported."); @@ -35,48 +45,61 @@ namespace FishNet.Object.Prediction } } - public static PredictionRigidbody.EntryData ReadForceData(this Reader r) + public static PredictionRigidbody.EntryData ReadEntryData(this Reader r) { PredictionRigidbody.EntryData fd = new PredictionRigidbody.EntryData(); PredictionRigidbody.ForceApplicationType appType = (PredictionRigidbody.ForceApplicationType)r.ReadByte(); fd.Type = appType; + PredictionRigidbody.AllForceData data = new(); + switch (appType) { case PredictionRigidbody.ForceApplicationType.AddTorque: case PredictionRigidbody.ForceApplicationType.AddForce: case PredictionRigidbody.ForceApplicationType.AddRelativeTorque: case PredictionRigidbody.ForceApplicationType.AddRelativeForce: - fd.Data = r.Read(); - return fd; + data.Vector3Force = r.ReadVector3(); + data.Mode = (ForceMode)r.ReadInt32(); + break; case PredictionRigidbody.ForceApplicationType.AddExplosiveForce: - fd.Data = r.Read(); - return fd; + data.FloatForce = r.ReadSingle(); + data.Position = r.ReadVector3(); + data.Radius = r.ReadSingle(); + data.UpwardsModifier = r.ReadSingle(); + data.Mode = (ForceMode)r.ReadInt32(); + break; case PredictionRigidbody.ForceApplicationType.AddForceAtPosition: - fd.Data = r.Read(); - return fd; + data.Vector3Force = r.ReadVector3(); + data.Position = r.ReadVector3(); + data.Mode = (ForceMode)r.ReadInt32(); + break; default: NetworkManagerExtensions.LogError($"ForceApplicationType of {appType} is not supported."); - return fd; + break; } - - + fd.Data = data; + return fd; } public static void WritePredictionRigidbody(this Writer w, PredictionRigidbody pr) { - w.WriteList(pr.GetPendingForces()); + w.Write(pr.Rigidbody.GetState()); + w.WriteList(pr.GetPendingForces()); } public static PredictionRigidbody ReadPredictionRigidbody(this Reader r) { + List lst = CollectionCaches.RetrieveList(); - r.ReadList(ref lst); + + RigidbodyState rs = r.Read(); + r.ReadList(ref lst); PredictionRigidbody pr = ResettableObjectCaches.Retrieve(); - pr.SetPendingForces(lst); + pr.SetReconcileData(rs, lst); return pr; } @@ -86,6 +109,51 @@ namespace FishNet.Object.Prediction public class PredictionRigidbody : IResettable { #region Types. + public struct AllForceData + { + public ForceMode Mode; + public Vector3 Vector3Force; + public Vector3 Position; + public float FloatForce; + public float Radius; + public float UpwardsModifier; + + /// + /// Used for Force and Torque. + /// + public AllForceData(Vector3 force, ForceMode mode) : this() + { + Vector3Force = force; + Mode = mode; + } + + /// + /// Used for Position. + /// + public AllForceData(Vector3 force, Vector3 position, ForceMode mode) : this() + { + Vector3Force = force; + Position = position; + Mode = mode; + } + + /// + /// Used for Explosive. + /// + /// + /// + /// + /// + /// + public AllForceData(float force, Vector3 position, float radius, float upwardsModifier, ForceMode mode) : this() + { + FloatForce = force; + Position = position; + Radius = radius; + UpwardsModifier = upwardsModifier; + Mode = mode; + } + } public interface IForceData { } //How the force was applied. [System.Flags] @@ -98,55 +166,14 @@ namespace FishNet.Object.Prediction AddTorque = 16, AddRelativeTorque = 32, } - public struct ForceAndTorqueData : IForceData - { - public Vector3 Force; - public ForceMode Mode; - - public ForceAndTorqueData(Vector3 force, ForceMode mode) - { - Force = force; - Mode = mode; - } - } - public struct PositionForceData : IForceData - { - public Vector3 Force; - public Vector3 Position; - public ForceMode Mode; - - public PositionForceData(Vector3 force, Vector3 position, ForceMode mode) - { - Force = force; - Position = position; - Mode = mode; - } - } - public struct ExplosiveForceData : IForceData - { - public float Force; - public Vector3 Position; - public float Radius; - public float UpwardsModifier; - public ForceMode Mode; - - public ExplosiveForceData(float force, Vector3 position, float radius, float upwardsModifier, ForceMode mode) - { - Force = force; - Position = position; - Radius = radius; - UpwardsModifier = upwardsModifier; - Mode = mode; - } - } [UseGlobalCustomSerializer] public struct EntryData { public ForceApplicationType Type; - public IForceData Data; + public AllForceData Data; - public EntryData(ForceApplicationType type, IForceData data) + public EntryData(ForceApplicationType type, AllForceData data) { Type = type; Data = data; @@ -166,6 +193,14 @@ namespace FishNet.Object.Prediction public Rigidbody Rigidbody { get; private set; } #endregion + #region Internal. + /// + /// RigidbodyState set only as reconcile data. + /// + [System.NonSerialized] + internal RigidbodyState RigidbodyState; + #endregion + #region Private /// /// Forces waiting to be applied. @@ -200,38 +235,38 @@ namespace FishNet.Object.Prediction public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force) { EntryData fd = new EntryData(ForceApplicationType.AddForce, - new ForceAndTorqueData(force, mode)); + new AllForceData(force, mode)); _pendingForces.Add(fd); } public void AddRelativeForce(Vector3 force, ForceMode mode = ForceMode.Force) { EntryData fd = new EntryData(ForceApplicationType.AddRelativeForce, - new ForceAndTorqueData(force, mode)); + new AllForceData(force, mode)); _pendingForces.Add(fd); } public void AddTorque(Vector3 force, ForceMode mode = ForceMode.Force) { EntryData fd = new EntryData(ForceApplicationType.AddTorque, - new ForceAndTorqueData(force, mode)); + new AllForceData(force, mode)); _pendingForces.Add(fd); } public void AddRelativeTorque(Vector3 force, ForceMode mode = ForceMode.Force) { EntryData fd = new EntryData(ForceApplicationType.AddRelativeTorque, - new ForceAndTorqueData(force, mode)); + new AllForceData(force, mode)); _pendingForces.Add(fd); } - public void AddExplosiveForce(float force, Vector3 position, float radius, float upwardsModifier = 0f, ForceMode mode = ForceMode.Force) + public void AddExplosiveForce(float force, Vector3 position, float radius, float upwardsModifier = 0f, ForceMode mode = ForceMode.Force) { EntryData fd = new EntryData(ForceApplicationType.AddExplosiveForce, - new ExplosiveForceData(force, position, radius, upwardsModifier, mode)); + new AllForceData(force, position, radius, upwardsModifier, mode)); _pendingForces.Add(fd); } public void AddForceAtPosition(Vector3 force, Vector3 position, ForceMode mode = ForceMode.Force) { EntryData fd = new EntryData(ForceApplicationType.AddForceAtPosition, - new PositionForceData(force, position, mode)); + new AllForceData(force, position, mode)); _pendingForces.Add(fd); } @@ -262,31 +297,26 @@ namespace FishNet.Object.Prediction { foreach (EntryData item in _pendingForces) { + AllForceData data = item.Data; switch (item.Type) { case ForceApplicationType.AddTorque: - ForceAndTorqueData e0 = (ForceAndTorqueData)item.Data; - Rigidbody.AddTorque(e0.Force, e0.Mode); + Rigidbody.AddTorque(data.Vector3Force, data.Mode); break; case ForceApplicationType.AddForce: - ForceAndTorqueData e1 = (ForceAndTorqueData)item.Data; - Rigidbody.AddForce(e1.Force, e1.Mode); + Rigidbody.AddForce(data.Vector3Force, data.Mode); break; - case ForceApplicationType.AddRelativeTorque: - ForceAndTorqueData e2 = (ForceAndTorqueData)item.Data; - Rigidbody.AddRelativeTorque(e2.Force, e2.Mode); + case ForceApplicationType.AddRelativeTorque: + Rigidbody.AddRelativeTorque(data.Vector3Force, data.Mode); break; case ForceApplicationType.AddRelativeForce: - ForceAndTorqueData e3 = (ForceAndTorqueData)item.Data; - Rigidbody.AddRelativeForce(e3.Force, e3.Mode); + Rigidbody.AddRelativeForce(data.Vector3Force, data.Mode); break; case ForceApplicationType.AddExplosiveForce: - ExplosiveForceData e4 = (ExplosiveForceData)item.Data; - Rigidbody.AddExplosionForce(e4.Force, e4.Position, e4.Radius, e4.UpwardsModifier, e4.Mode); + Rigidbody.AddExplosionForce(data.FloatForce, data.Position, data.Radius, data.UpwardsModifier, data.Mode); break; case ForceApplicationType.AddForceAtPosition: - PositionForceData e5 = (PositionForceData)item.Data; - Rigidbody.AddForceAtPosition(e5.Force, e5.Position, e5.Mode); + Rigidbody.AddForceAtPosition(data.Vector3Force, data.Position, data.Mode); break; } } @@ -320,6 +350,8 @@ namespace FishNet.Object.Prediction foreach (EntryData item in pr._pendingForces) _pendingForces.Add(new EntryData(item)); } + //Set state. + Rigidbody.SetState(pr.RigidbodyState); ResettableObjectCaches.Store(pr); } @@ -332,7 +364,6 @@ namespace FishNet.Object.Prediction { if (_pendingForces.Count > 0) { - bool shouldExist = velocity; ForceApplicationType velocityApplicationTypes = (ForceApplicationType.AddRelativeForce | ForceApplicationType.AddForce | ForceApplicationType.AddExplosiveForce); List newDatas = CollectionCaches.RetrieveList(); @@ -360,7 +391,11 @@ namespace FishNet.Object.Prediction } internal List GetPendingForces() => _pendingForces; - internal void SetPendingForces(List lst) => _pendingForces = lst; + internal void SetReconcileData(RigidbodyState rs, List lst) + { + RigidbodyState = rs; + _pendingForces = lst; + } public void ResetState() { diff --git a/Assets/FishNet/Runtime/Object/Prediction/PredictionRigidbody2D.cs b/Assets/FishNet/Runtime/Object/Prediction/PredictionRigidbody2D.cs index b2bf8a6..7891424 100644 --- a/Assets/FishNet/Runtime/Object/Prediction/PredictionRigidbody2D.cs +++ b/Assets/FishNet/Runtime/Object/Prediction/PredictionRigidbody2D.cs @@ -15,17 +15,23 @@ namespace FishNet.Object.Prediction { PredictionRigidbody2D.ForceApplicationType appType = value.Type; w.WriteByte((byte)appType); + PredictionRigidbody2D.AllForceData data = value.Data; + switch (appType) { case PredictionRigidbody2D.ForceApplicationType.AddForce: case PredictionRigidbody2D.ForceApplicationType.AddRelativeForce: - w.Write((PredictionRigidbody2D.ForceData)value.Data); + w.WriteVector3(data.Vector3Force); + w.WriteInt32((byte)data.Mode); break; case PredictionRigidbody2D.ForceApplicationType.AddTorque: - w.Write((PredictionRigidbody2D.TorqueData)value.Data); + w.WriteSingle(data.FloatForce); + w.WriteInt32((byte)data.Mode); break; case PredictionRigidbody2D.ForceApplicationType.AddForceAtPosition: - w.Write((PredictionRigidbody2D.PositionForceData)value.Data); + w.WriteVector3(data.Vector3Force); + w.WriteVector3(data.Position); + w.WriteInt32((byte)data.Mode); break; default: NetworkManagerExtensions.LogError($"ForceApplicationType of {appType} is not supported."); @@ -40,25 +46,28 @@ namespace FishNet.Object.Prediction PredictionRigidbody2D.ForceApplicationType appType = (PredictionRigidbody2D.ForceApplicationType)r.ReadByte(); fd.Type = appType; + PredictionRigidbody2D.AllForceData data = new(); + switch (appType) { case PredictionRigidbody2D.ForceApplicationType.AddForce: case PredictionRigidbody2D.ForceApplicationType.AddRelativeForce: - fd.Data = r.Read(); + data.Vector3Force = r.ReadVector3(); + data.Mode = (ForceMode2D)r.ReadByte(); return fd; case PredictionRigidbody2D.ForceApplicationType.AddTorque: - fd.Data = r.Read(); + data.FloatForce = r.ReadSingle(); + data.Mode = (ForceMode2D)r.ReadByte(); return fd; case PredictionRigidbody2D.ForceApplicationType.AddForceAtPosition: - fd.Data = r.Read(); + data.Vector3Force = r.ReadVector3(); + data.Position = r.ReadVector3(); + data.Mode = (ForceMode2D)r.ReadByte(); return fd; default: NetworkManagerExtensions.LogError($"ForceApplicationType of {appType} is not supported."); return fd; } - - - } public static void WritePredictionRigidbody2D(this Writer w, PredictionRigidbody2D pr) @@ -82,7 +91,6 @@ namespace FishNet.Object.Prediction public class PredictionRigidbody2D : IResettable { #region Types. - public interface IForceData { } //How the force was applied. [System.Flags] public enum ForceApplicationType : byte @@ -92,49 +100,42 @@ namespace FishNet.Object.Prediction AddRelativeForce = 8, AddTorque = 16, } - public struct ForceData : IForceData + public struct AllForceData { - public Vector3 Force; - public ForceMode2D Mode; - - public ForceData(Vector3 force, ForceMode2D mode) - { - Force = force; - Mode = mode; - } - } - public struct TorqueData : IForceData - { - public float Force; - public ForceMode2D Mode; - - public TorqueData(float force, ForceMode2D mode) - { - Force = force; - Mode = mode; - } - } - public struct PositionForceData : IForceData - { - public Vector3 Force; + public Vector3 Vector3Force; + public float FloatForce; public Vector3 Position; public ForceMode2D Mode; - public PositionForceData(Vector3 force, Vector3 position, ForceMode2D mode) + public AllForceData(Vector3 force, ForceMode2D mode) : this() { - Force = force; + Vector3Force = force; + Mode = mode; + } + + + public AllForceData(float force, ForceMode2D mode) : this() + { + FloatForce = force; + Mode = mode; + } + + public AllForceData(Vector3 force, Vector3 position, ForceMode2D mode) : this() + { + Vector3Force = force; Position = position; Mode = mode; } } + [UseGlobalCustomSerializer] public struct EntryData { public ForceApplicationType Type; - public IForceData Data; + public AllForceData Data; - public EntryData(ForceApplicationType type, IForceData data) + public EntryData(ForceApplicationType type, AllForceData data) { Type = type; Data = data; @@ -188,26 +189,26 @@ namespace FishNet.Object.Prediction public void AddForce(Vector3 force, ForceMode2D mode = ForceMode2D.Force) { EntryData fd = new EntryData(ForceApplicationType.AddForce, - new ForceData(force, mode)); + new AllForceData(force, mode)); _pendingForces.Add(fd); } public void AddRelativeForce(Vector3 force, ForceMode2D mode = ForceMode2D.Force) { EntryData fd = new EntryData(ForceApplicationType.AddRelativeForce, - new ForceData(force, mode)); + new AllForceData(force, mode)); _pendingForces.Add(fd); } public void AddTorque(float force, ForceMode2D mode = ForceMode2D.Force) { EntryData fd = new EntryData(ForceApplicationType.AddTorque, - new TorqueData(force, mode)); + new AllForceData(force, mode)); _pendingForces.Add(fd); } public void AddForceAtPosition(Vector3 force, Vector3 position, ForceMode2D mode = ForceMode2D.Force) { EntryData fd = new EntryData(ForceApplicationType.AddForceAtPosition, - new PositionForceData(force, position, mode)); + new AllForceData(force, position, mode)); _pendingForces.Add(fd); } @@ -238,23 +239,20 @@ namespace FishNet.Object.Prediction { foreach (EntryData item in _pendingForces) { + AllForceData data = item.Data; switch (item.Type) { case ForceApplicationType.AddTorque: - TorqueData e0 = (TorqueData)item.Data; - Rigidbody2D.AddTorque(e0.Force, e0.Mode); + Rigidbody2D.AddTorque(data.FloatForce, data.Mode); break; case ForceApplicationType.AddForce: - ForceData e1 = (ForceData)item.Data; - Rigidbody2D.AddForce(e1.Force, e1.Mode); + Rigidbody2D.AddForce(data.Vector3Force, data.Mode); break; case ForceApplicationType.AddRelativeForce: - ForceData e3 = (ForceData)item.Data; - Rigidbody2D.AddRelativeForce(e3.Force, e3.Mode); + Rigidbody2D.AddRelativeForce(data.Vector3Force, data.Mode); break; case ForceApplicationType.AddForceAtPosition: - PositionForceData e5 = (PositionForceData)item.Data; - Rigidbody2D.AddForceAtPosition(e5.Force, e5.Position, e5.Mode); + Rigidbody2D.AddForceAtPosition(data.Vector3Force, data.Position, data.Mode); break; } } diff --git a/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs b/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs index 708f45b..6531646 100644 --- a/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs +++ b/Assets/FishNet/Runtime/Object/Synchronizing/SyncDictionary.cs @@ -289,10 +289,7 @@ namespace FishNet.Object.Synchronizing internal protected override void WriteFull(PooledWriter writer) { if (!_valuesChanged) - { - UnityEngine.Debug.Log($"Values did not change."); return; - } base.WriteHeader(writer, false); //True for full write. diff --git a/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs b/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs index b059824..2fa5c5b 100644 --- a/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs +++ b/Assets/FishNet/Runtime/Object/Synchronizing/SyncList.cs @@ -13,7 +13,7 @@ namespace FishNet.Object.Synchronizing { [System.Serializable] public class SyncList : SyncBase, IList, IReadOnlyList - { + { #region Types. /// /// Information needed to invoke a callback. diff --git a/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs b/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs index bd32632..7f31c77 100644 --- a/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs +++ b/Assets/FishNet/Runtime/Object/Synchronizing/SyncVar.cs @@ -146,18 +146,15 @@ namespace FishNet.Object.Synchronizing [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void SetValue(T nextValue, bool calledByUser, bool sendRpc = false) { - /* If not registered then that means Awake - * has not completed on the owning class. This would be true - * when setting values within awake on the owning class. Registered - * is called at the end of awake, so it would be unset until awake completed. - * - * Registered however will be true when setting from another script, - * even if the owning class of this was just spawned. This is because - * the unity cycle will fire awake on the object soon as it's spawned, - * completing awake, and the user would set the value after. */ + /* IsInitialized is only set after the script containing this SyncVar + * has executed our codegen in the beginning of awake, and after awake + * user logic. When not set update the initial values */ if (!base.IsInitialized) + { + SetInitialValues(nextValue); return; - + } + /* If not client or server then set skipChecks * as true. When neither is true it's likely user is changing * value before object is initialized. This is allowed diff --git a/Assets/FishNet/Runtime/Object/TransformProperties.cs b/Assets/FishNet/Runtime/Object/TransformProperties.cs index 22c6bb5..ca03c3b 100644 --- a/Assets/FishNet/Runtime/Object/TransformProperties.cs +++ b/Assets/FishNet/Runtime/Object/TransformProperties.cs @@ -123,6 +123,28 @@ namespace FishNet.Object LocalScale = localScale; } + /// + /// Adds another transformProperties onto this. + /// + /// + public void Add(TransformProperties tp) + { + Position += tp.Position; + Rotation *= tp.Rotation; + LocalScale += tp.LocalScale; + } + + /// + /// Subtracts another transformProperties from this. + /// + /// + public void Subtract(TransformProperties tp) + { + Position -= tp.Position; + Rotation *= Quaternion.Inverse(tp.Rotation); + LocalScale -= tp.LocalScale; + } + /// /// Returns if this TransformProperties equals anothers values. /// diff --git a/Assets/FishNet/Runtime/Object/TransformPropertiesFlag.cs b/Assets/FishNet/Runtime/Object/TransformPropertiesFlag.cs new file mode 100644 index 0000000..ae7f1db --- /dev/null +++ b/Assets/FishNet/Runtime/Object/TransformPropertiesFlag.cs @@ -0,0 +1,24 @@ +namespace FishNet.Object +{ + [System.Flags] + public enum TransformPropertiesFlag : byte + { + Unset = 0, + Position = 1, + Rotation = 2, + LocalScale = 4, + Everything = ~(-1 << 8), + } + + public static class TransformPropertiesOptionExtensions + { + /// + /// Returns if enum contains a value. + /// + /// Value checked against. + /// Value checked if whole contains. + /// + public static bool FastContains(this TransformPropertiesFlag whole, TransformPropertiesFlag part) => (whole & part) == part; + } +} + diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts/CharacterControllerPredictionV2.cs.meta b/Assets/FishNet/Runtime/Object/TransformPropertiesFlag.cs.meta similarity index 83% rename from Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts/CharacterControllerPredictionV2.cs.meta rename to Assets/FishNet/Runtime/Object/TransformPropertiesFlag.cs.meta index 347ec1f..9e272f9 100644 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/Scripts/CharacterControllerPredictionV2.cs.meta +++ b/Assets/FishNet/Runtime/Object/TransformPropertiesFlag.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 53a6d84aa5d214e48a7308646e5d20da +guid: 67f9d37271d2b6747a71993367895814 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs b/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs index e4a0cd8..e1904b5 100644 --- a/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs +++ b/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/ColliderRollback.cs @@ -23,6 +23,7 @@ namespace FishNet.Component.ColliderRollback #endregion #region Serialized. +#pragma warning disable CS0414 /// /// How to configure the bounding box check. /// @@ -47,6 +48,7 @@ namespace FishNet.Component.ColliderRollback [Tooltip("Objects holding colliders which can rollback.")] [SerializeField] private GameObject[] _colliderParents = new GameObject[0]; +#pragma warning restore CS0414 #endregion diff --git a/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs b/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs index 05e9425..5ed7e3e 100644 --- a/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs +++ b/Assets/FishNet/Runtime/Plugins/ColliderRollback/Scripts/RollbackManager.cs @@ -88,6 +88,42 @@ namespace FishNet.Component.ColliderRollback + [Obsolete("Use Rollback(Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics, bool) instead.")] //Remove on V5 + public void Rollback(Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false) + { + + } + + [Obsolete("Use Rollback(Scene, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics, bool) instead.")] //Remove on V5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Rollback(Scene scene, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false) + { + + } + + [Obsolete("Use Rollback(int, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics, bool) instead.")] //Remove on V5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Rollback(int sceneHandle, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false) + { + + } + + + [Obsolete("Use Rollback(Scene, Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics2D, bool) instead.")] //Remove on V5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Rollback(Scene scene, Vector2 origin, Vector2 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false) + { + + } + + [Obsolete("Use Rollback(Vector3, Vector3, float, PreciseTick, RollbackPhysicsType.Physics2D, bool) instead.")] //Remove on V5 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Rollback(Vector2 origin, Vector2 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false) + { + + } + + /// /// Rolls back all colliders. /// @@ -99,10 +135,10 @@ namespace FishNet.Component.ColliderRollback } - /// - /// Rolls back all colliders. + /// Rolls back all colliders in a scene. /// + /// Scene containing colliders. /// Precise tick received from the client. /// Type of physics to rollback; this is often what your casts will use. /// True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost. @@ -112,8 +148,9 @@ namespace FishNet.Component.ColliderRollback } /// - /// Rolls back all colliders. + /// Rolls back all colliders in a scene. /// + /// Scene handle containing colliders. /// Precise tick received from the client. /// Type of physics to rollback; this is often what your casts will use. /// True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost. @@ -122,59 +159,35 @@ namespace FishNet.Component.ColliderRollback } - /// - /// Rolls back all 3d colliders hit by a test cast against bounding boxes. + /// Rolls back colliders hit by a test cast against bounding boxes, in a specific scene. /// + /// Scene containing colliders. /// Ray origin. /// Direction to cast. /// Distance of cast. /// Precise tick received from the client. + /// Type of physics to rollback; this is often what your casts will use. /// True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost. - public void Rollback(Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false) + public void Rollback(Scene scene, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false) { } /// - /// Rolls back all 3d colliders hit by a test cast against bounding boxes. + /// Rolls back colliders hit by a test cast against bounding boxes, in a specific scene. /// + /// Scene handle containing colliders. /// Ray origin. /// Direction to cast. /// Distance of cast. /// Precise tick received from the client. + /// Type of physics to rollback; this is often what your casts will use. /// True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Rollback(Scene scene, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false) + public void Rollback(int sceneHandle, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, RollbackPhysicsType physicsType, bool asOwnerAndClientHost = false) { } - /// - /// Rolls back all 3d colliders hit by a test cast against bounding boxes. - /// - /// Ray origin. - /// Direction to cast. - /// Distance of cast. - /// Precise tick received from the client. - /// True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost. - public void Rollback(int sceneHandle, Vector3 origin, Vector3 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false) - { - - } - - /// - /// Rolls back all 3d colliders hit by a test cast against bounding boxes. - /// - /// Ray origin. - /// Direction to cast. - /// Distance of cast. - /// Precise tick received from the client. - /// True if IsOwner of the object the raycast is for. This can be ignored and only provides more accurate results for clientHost. - public void Rollback(Vector2 origin, Vector2 normalizedDirection, float distance, PreciseTick pt, bool asOwnerAndClientHost = false) - { - - } - diff --git a/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectCaching.cs b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectCaching.cs index 604b2ed..0779709 100644 --- a/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectCaching.cs +++ b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/ObjectCaching.cs @@ -399,6 +399,10 @@ namespace GameKit.Dependencies.Utilities /// private readonly static Stack> _queueCache = new Stack>(); /// + /// Cache for queues. + /// + private readonly static Stack> _basicQueueCache = new Stack>(); + /// /// Cache for hashset. /// private readonly static Stack> _hashsetCache = new Stack>(); @@ -437,6 +441,17 @@ namespace GameKit.Dependencies.Utilities return _queueCache.Pop(); } /// + /// Retrieves a collection. + /// + /// + public static BasicQueue RetrieveBasicQueue() + { + if (_basicQueueCache.Count == 0) + return new BasicQueue(); + else + return _basicQueueCache.Pop(); + } + /// /// Retrieves a collection adding one entry. /// /// @@ -567,6 +582,28 @@ namespace GameKit.Dependencies.Utilities _queueCache.Push(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) + { + value.Clear(); + _basicQueueCache.Push(value); + } /// /// Stores a collection and sets the original reference to default. /// Method will not execute if value is null. diff --git a/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/BasicQueue.cs b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/BasicQueue.cs new file mode 100644 index 0000000..e17bfb0 --- /dev/null +++ b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/BasicQueue.cs @@ -0,0 +1,231 @@ +using System; + +namespace GameKit.Dependencies.Utilities +{ + + /// + /// Unity 2022 has a bug where codegen will not compile when referencing a Queue type, + /// while also targeting .Net as the framework API. + /// As a work around this class is used for queues instead. + /// + public class BasicQueue + { + /// + /// Maximum size of the collection. + /// + public int Capacity => Collection.Length; + /// + /// Number of elements in the queue. + /// + public int Count => _written; + /// + /// Collection containing data. + /// + private T[] Collection = new T[4]; + /// + /// Current write index of the collection. + /// + public int WriteIndex { get; private set; } + /// + /// Buffer for resizing. + /// + private T[] _resizeBuffer = new T[0]; + /// + /// Read position of the next Dequeue. + /// + private int _read; + + /// + /// Length of the queue. + /// + private int _written; + + /// + /// Enqueues an entry. + /// + /// + public void Enqueue(T data) + { + if (_written == Collection.Length) + Resize(); + + if (WriteIndex >= Collection.Length) + WriteIndex = 0; + Collection[WriteIndex] = data; + + WriteIndex++; + _written++; + } + + /// + /// Tries to dequeue the next entry. + /// + /// Dequeued entry. + /// True if an entry existed to dequeue. + public bool TryDequeue(out T result) + { + if (_written == 0) + { + result = default; + return false; + } + + result = Dequeue(); + return true; + } + + /// + /// Dequeues the next entry. + /// + /// + public T Dequeue() + { + if (_written == 0) + throw new Exception($"Queue of type {typeof(T).Name} is empty."); + + T result = Collection[_read]; + + _written--; + _read++; + if (_read >= Collection.Length) + _read = 0; + + return result; + } + + /// + /// Tries to peek the next entry. + /// + /// Peeked entry. + /// True if an entry existed to peek. + public bool TryPeek(out T result) + { + if (_written == 0) + { + result = default; + return false; + } + + result = Peek(); + return true; + } + + /// + /// Peeks the next queue entry. + /// + /// + public T Peek() + { + if (_written == 0) + throw new Exception($"Queue of type {typeof(T).Name} is empty."); + + return Collection[_read]; + } + + /// + /// Clears the queue. + /// + public void Clear() + { + _read = 0; + WriteIndex = 0; + _written = 0; + + DefaultCollection(Collection); + DefaultCollection(_resizeBuffer); + + void DefaultCollection(T[] array) + { + int count = array.Length; + for (int i = 0; i < count; i++) + array[i] = default; + } + } + + /// + /// Doubles the queue size. + /// + private void Resize() + { + int length = _written; + int doubleLength = (length * 2); + int read = _read; + + /* Make sure copy array is the same size as current + * and copy contents into it. */ + //Ensure large enough to fit contents. + T[] resizeBuffer = _resizeBuffer; + if (resizeBuffer.Length < doubleLength) + Array.Resize(ref resizeBuffer, doubleLength); + //Copy from the read of queue first. + int copyLength = (length - read); + Array.Copy(Collection, read, resizeBuffer, 0, copyLength); + /* If read index was higher than 0 + * then copy remaining data as well from 0. */ + if (read > 0) + Array.Copy(Collection, 0, resizeBuffer, copyLength, read); + + //Set _array to resize. + Collection = resizeBuffer; + //Reset positions. + _read = 0; + WriteIndex = length; + } + + /// + /// Returns value in actual index as it relates to simulated index. + /// + /// Simulated index to return. A value of 0 would return the first simulated index in the collection. + /// + public T this[int simulatedIndex] + { + get + { + int offset = GetRealIndex(simulatedIndex); + return Collection[offset]; + } + set + { + int offset = GetRealIndex(simulatedIndex); + Collection[offset] = value; + } + } + + + + /// + /// Returns the real index of the collection using a simulated index. + /// + /// True to allow an index be returned from an unused portion of the buffer so long as it is within bounds. + private int GetRealIndex(int simulatedIndex, bool allowUnusedBuffer = false) + { + if (simulatedIndex >= Capacity) + { + return ReturnError(); + } + else + { + int written = _written; + //May be out of bounds if allowUnusedBuffer is false. + if (simulatedIndex >= written) + { + if (!allowUnusedBuffer) + return ReturnError(); + } + int offset = (Capacity - written) + simulatedIndex + WriteIndex; + if (offset >= Capacity) + offset -= Capacity; + + return offset; + } + + int ReturnError() + { + UnityEngine.Debug.LogError($"Index {simulatedIndex} is out of range. Collection count is {_written}, Capacity is {Capacity}"); + return -1; + } + } + + } + +} \ No newline at end of file diff --git a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts/RigidbodyPredictionV2.cs.meta b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/BasicQueue.cs.meta similarity index 83% rename from Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts/RigidbodyPredictionV2.cs.meta rename to Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/BasicQueue.cs.meta index f0b87be..19188c9 100644 --- a/Assets/FishNet/Demos/Prediction 2/Rigidbody/Scripts/RigidbodyPredictionV2.cs.meta +++ b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Types/BasicQueue.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1e66bfd8c92aad24e8526e7d3aae8b34 +guid: f966ec63b499e77438c185b2870595cd MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Vectors.cs b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Vectors.cs index a45bc6c..7db156d 100644 --- a/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Vectors.cs +++ b/Assets/FishNet/Runtime/Plugins/GameKit/Dependencies/Utilities/Vectors.cs @@ -20,13 +20,13 @@ namespace GameKit.Dependencies.Utilities /// /// Returns how fast an object must move over duration to reach goal. /// - /// Vector3 to measure distance against. + /// Vector3 to measure distance against. /// How long it should take to move to goal. /// A multiplier applied towards interval. Typically this is used for ticks passed. /// - public static float GetRate(this Vector3 a, Vector3 goal, float duration, out float distance, uint interval = 1) + public static float GetRate(this Vector3 a, Vector3 b, float duration, out float distance, uint interval = 1) { - distance = Vector3.Distance(a, goal); + distance = Vector3.Distance(a, b); return distance / (duration * interval); } /// diff --git a/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt b/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt deleted file mode 100644 index 4f3eea1..0000000 --- a/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt +++ /dev/null @@ -1,2 +0,0 @@ -1.0.0 - - Initial release. \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs b/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs index e69de29..defe925 100644 --- a/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs +++ b/Assets/FishNet/Runtime/Plugins/Yak/Core/ClientSocket.cs @@ -0,0 +1,57 @@ +using FishNet.Transporting.Yak.Server; +using System; +using System.Collections.Generic; + +namespace FishNet.Transporting.Yak.Client +{ + /// + /// Creates a fake client connection to interact with the ServerSocket. + /// + public class ClientSocket : CommonSocket + { + #region Private. + /// + /// Socket for the server. + /// + private ServerSocket _server; + /// + /// Incomimg data. + /// + private Queue _incoming = new Queue(); + #endregion + + + + /// + /// Starts the client connection. + /// + internal bool StartConnection() + { + + return true; + } + + + + /// + /// Stops the local socket. + /// + internal bool StopConnection() + { + + return true; + } + + + + + + + + #region Local server. + + #endregion + + + } +} \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs b/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs index e69de29..0cb5e5a 100644 --- a/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs +++ b/Assets/FishNet/Runtime/Plugins/Yak/Core/CommonSocket.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; + +namespace FishNet.Transporting.Yak +{ + + public abstract class CommonSocket + { + + #region Public. + /// + /// Current ConnectionState. + /// + private LocalConnectionState _connectionState = LocalConnectionState.Stopped; + /// + /// Returns the current ConnectionState. + /// + /// + internal LocalConnectionState GetLocalConnectionState() + { + return _connectionState; + } + + + #endregion + + #region Protected. + /// + /// Transport controlling this socket. + /// + protected Transport Transport = null; + #endregion + + /// + /// Initializes this for use. + /// + internal virtual void Initialize(Transport t, CommonSocket socket) + { + Transport = t; + } + + /// + /// Clears a queue. + /// + internal void ClearQueue(ref Queue queue) + { + + } + } + +} diff --git a/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs b/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs index 5f28270..9059f08 100644 --- a/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs +++ b/Assets/FishNet/Runtime/Plugins/Yak/Core/LocalPacket.cs @@ -1 +1,11 @@ - \ No newline at end of file +using FishNet.Utility.Performance; +using System; + +namespace FishNet.Transporting.Yak +{ + internal struct LocalPacket + { + + } + +} diff --git a/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs b/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs index e69de29..8eec06e 100644 --- a/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs +++ b/Assets/FishNet/Runtime/Plugins/Yak/Core/ServerSocket.cs @@ -0,0 +1,83 @@ +using FishNet.Connection; +using FishNet.Transporting.Yak.Client; +using System; +using System.Collections.Generic; + +namespace FishNet.Transporting.Yak.Server +{ + /// + /// Creates a fake socket acting as server. + /// + public class ServerSocket : CommonSocket + { + #region Public. + /// + /// Gets the current ConnectionState of a remote client on the server. + /// + /// ConnectionId to get ConnectionState for. + internal RemoteConnectionState GetConnectionState(int connectionId) + { + if (connectionId != NetworkConnection.SIMULATED_CLIENTID_VALUE) + return RemoteConnectionState.Stopped; + + LocalConnectionState state = _client.GetLocalConnectionState(); + return (state == LocalConnectionState.Started) ? RemoteConnectionState.Started : + RemoteConnectionState.Stopped; + } + #endregion + + #region Private. + /// + /// Packets received from local client. + /// + private Queue _incoming = new Queue(); + /// + /// Socket for client. + /// + private ClientSocket _client; + #endregion + + + + /// + /// Starts the server. + /// + internal bool StartConnection() + { + + return true; + } + + + + + /// + /// Stops the local socket. + /// + internal bool StopConnection() + { + + return true; + } + + /// + /// Stops a remote client from the server, disconnecting the client. + /// + /// ConnectionId of the client to disconnect. + internal bool StopConnection(int connectionId) + { + + return true; + } + + + + + + #region Local client. + + + + #endregion + } +} \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt b/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt deleted file mode 100644 index afaf360..0000000 --- a/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt +++ /dev/null @@ -1 +0,0 @@ -1.0.0 \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt.meta b/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt.meta deleted file mode 100644 index afecaf0..0000000 --- a/Assets/FishNet/Runtime/Plugins/Yak/VERSION.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 3f0e4449aaa7cf0499df1847fdbd5377 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs b/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs index e69de29..f40561d 100644 --- a/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs +++ b/Assets/FishNet/Runtime/Plugins/Yak/Yak.cs @@ -0,0 +1,322 @@ +using FishNet.Connection; +using FishNet.Managing; +using System; +using UnityEngine; + +namespace FishNet.Transporting.Yak +{ + [AddComponentMenu("FishNet/Transport/Yak")] + public class Yak : Transport + { + #region Private. + /// + /// Client when acting as host. + /// + private Client.ClientSocket _client; + /// + /// Server for the transport. + /// + private Server.ServerSocket _server; + #endregion + + #region Const. + /// + /// Maximum packet size for this transport. + /// + private const int MTU = 5000; + #endregion + + public override void Initialize(NetworkManager networkManager, int transportIndex) + { + + } + + private void OnDestroy() + { + + } + + #region ConnectionStates. + /// + /// Gets the IP address of a remote connection Id. + /// + /// + /// + public override string GetConnectionAddress(int connectionId) + { + return String.Empty; + } +#pragma warning disable CS0067 + /// + /// Called when a connection state changes for the local client. + /// + public override event Action OnClientConnectionState; + /// + /// Called when a connection state changes for the local server. + /// + public override event Action OnServerConnectionState; + /// + /// Called when a connection state changes for a remote client. + /// + public override event Action OnRemoteConnectionState; +#pragma warning restore CS0067 + /// + /// Gets the current local ConnectionState. + /// + /// True if getting ConnectionState for the server. + public override LocalConnectionState GetConnectionState(bool server) + { + if (server) + return _server.GetLocalConnectionState(); + else + return _client.GetLocalConnectionState(); + } + /// + /// Gets the current ConnectionState of a remote client on the server. + /// + /// ConnectionId to get ConnectionState for. + public override RemoteConnectionState GetConnectionState(int connectionId) + { + return _server.GetConnectionState(connectionId); + } + /// + /// Handles a ConnectionStateArgs for the local client. + /// + /// + public override void HandleClientConnectionState(ClientConnectionStateArgs connectionStateArgs) + { + + } + /// + /// Handles a ConnectionStateArgs for the local server. + /// + /// + public override void HandleServerConnectionState(ServerConnectionStateArgs connectionStateArgs) + { + + } + /// + /// Handles a ConnectionStateArgs for a remote client. + /// + /// + public override void HandleRemoteConnectionState(RemoteConnectionStateArgs connectionStateArgs) + { + + } + #endregion + + #region Iterating. + /// + /// Processes data received by the socket. + /// + /// True to process data received on the server. + public override void IterateIncoming(bool server) + { + + } + + /// + /// Processes data to be sent by the socket. + /// + /// True to process data received on the server. + public override void IterateOutgoing(bool server) { } + #endregion + + #region ReceivedData. + /// + /// Called when client receives data. + /// + public override event Action OnClientReceivedData; + /// + /// Handles a ClientReceivedDataArgs. + /// + /// + public override void HandleClientReceivedDataArgs(ClientReceivedDataArgs receivedDataArgs) + { + OnClientReceivedData?.Invoke(receivedDataArgs); + } + /// + /// Called when server receives data. + /// + public override event Action OnServerReceivedData; + /// + /// Handles a ClientReceivedDataArgs. + /// + /// + public override void HandleServerReceivedDataArgs(ServerReceivedDataArgs receivedDataArgs) + { + OnServerReceivedData?.Invoke(receivedDataArgs); + } + #endregion + + #region Sending. + /// + /// Sends to the server or all clients. + /// + /// Channel to use. + /// /// Data to send. + public override void SendToServer(byte channelId, ArraySegment segment) + { + + } + /// + /// Sends data to a client. + /// + /// + /// + /// + public override void SendToClient(byte channelId, ArraySegment segment, int connectionId) + { + + } + #endregion + + #region Configuration. + /// + /// Returns if the transport is a local transport. + /// While true several security checks are disabled. + /// + public override bool IsLocalTransport(int connectionId) => true; + /// + /// Returns the maximum number of clients allowed to connect to the server. If the transport does not support this method the value -1 is returned. + /// + /// + public override int GetMaximumClients() + { + return NetworkConnection.MAXIMUM_CLIENTID_WITHOUT_SIMULATED_VALUE; + } + /// + /// Sets maximum number of clients allowed to connect to the server. If applied at runtime and clients exceed this value existing clients will stay connected but new clients may not connect. + /// + /// + public override void SetMaximumClients(int value) { } + /// + /// Sets which address the client will connect to. + /// + /// + public override void SetClientAddress(string address) { } + /// + /// Sets which address the server will bind to. + /// + /// + public override void SetServerBindAddress(string address, IPAddressType addressType) { } + /// + /// Sets which port to use. + /// + /// + public override void SetPort(ushort port) { } + #endregion + + #region Start and stop. + /// + /// Starts the local server or client using configured settings. + /// + /// True to start server. + public override bool StartConnection(bool server) + { + if (server) + return StartServer(); + else + return StartClient(); + } + + /// + /// Stops the local server or client. + /// + /// True to stop server. + public override bool StopConnection(bool server) + { + if (server) + return StopServer(); + else + return StopClient(); + } + + /// + /// Stops a remote client from the server, disconnecting the client. + /// + /// ConnectionId of the client to disconnect. + /// True to abrutly stp the client socket without waiting socket thread. + public override bool StopConnection(int connectionId, bool immediately) + { + return StopClient(connectionId, immediately); + } + + /// + /// Stops both client and server. + /// + public override void Shutdown() + { + + } + + #region Privates. + /// + /// Starts server. + /// + /// True if there were no blocks. A true response does not promise a socket will or has connected. + private bool StartServer() + { + + + bool result = _server.StartConnection(); + + return result; + } + + /// + /// Stops server. + /// + private bool StopServer() + { + + return false; + } + + /// + /// Starts the client. + /// + /// + /// True if there were no blocks. A true response does not promise a socket will or has connected. + private bool StartClient() + { + + return true; + } + + /// + /// Stops the client. + /// + private bool StopClient() + { + + return false; + } + + /// + /// Stops a remote client on the server. + /// + /// + /// True to abrutly stp the client socket without waiting socket thread. + private bool StopClient(int connectionId, bool immediately) + { + return _server.StopConnection(connectionId); + } + #endregion + #endregion + + #region Channels. + /// + /// Gets the MTU for a channel. This should take header size into consideration. + /// For example, if MTU is 1200 and a packet header for this channel is 10 in size, this method should return 1190. + /// + /// + /// + public override int GetMTU(byte channel) + { + return MTU; + } + #endregion + } + +} \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Serializing/GenericReader.cs b/Assets/FishNet/Runtime/Serializing/GenericReader.cs new file mode 100644 index 0000000..1325c95 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/GenericReader.cs @@ -0,0 +1,43 @@ +using FishNet.Documenting; +using FishNet.Utility; +using System; +using System.Runtime.CompilerServices; + + +[assembly: InternalsVisibleTo(UtilityConstants.GENERATED_ASSEMBLY_NAME)] +//Required for internal tests. +[assembly: InternalsVisibleTo(UtilityConstants.TEST_ASSEMBLY_NAME)] +namespace FishNet.Serializing +{ + /// + /// Used for read references to generic types. + /// + /// + [APIExclude] + public static class GenericReader + { + public static Func Read { get; set; } + public static Func ReadAutoPack { get; set; } + /// + /// True if this type has a custom writer. + /// + private static bool _hasCustomSerializer; + + public static void SetReadUnpacked(Func value) + { + /* If a custom serializer has already been set then exit method + * to not overwrite serializer. */ + if (_hasCustomSerializer) + return; + + //Set has custom serializer if value being used is not a generated method. + _hasCustomSerializer = !(value.Method.Name.StartsWith(UtilityConstants.GENERATED_READER_PREFIX)); + Read = value; + } + + public static void SetReadAutoPacked(Func value) + { + ReadAutoPack = value; + } + } +} diff --git a/Assets/FishNet/Runtime/Serializing/GenericReader.cs.meta b/Assets/FishNet/Runtime/Serializing/GenericReader.cs.meta new file mode 100644 index 0000000..8d2b667 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/GenericReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a02167b94bcdd84da90bbcf5d6ad649 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/GenericWriter.cs b/Assets/FishNet/Runtime/Serializing/GenericWriter.cs new file mode 100644 index 0000000..dc56385 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/GenericWriter.cs @@ -0,0 +1,42 @@ +using FishNet.Documenting; +using FishNet.Utility; +using System; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo(UtilityConstants.GENERATED_ASSEMBLY_NAME)] +namespace FishNet.Serializing +{ + + /// + /// Used for write references to generic types. + /// + /// + [APIExclude] + public static class GenericWriter + { + public static Action Write { get; private set; } + public static Action WriteAutoPack { get; private set; } + /// + /// True if this type has a custom writer. + /// + private static bool _hasCustomSerializer; + + public static void SetWriteUnpacked(Action value) + { + /* If a custom serializer has already been set then exit method + * to not overwrite serializer. */ + if (_hasCustomSerializer) + return; + + //Set has custom serializer if value being used is not a generated method. + _hasCustomSerializer = !(value.Method.Name.StartsWith(UtilityConstants.GENERATED_WRITER_PREFIX)); + Write = value; + } + + public static void SetWriteAutoPacked(Action value) + { + WriteAutoPack = value; + } + } + +} diff --git a/Assets/FishNet/Runtime/Serializing/GenericWriter.cs.meta b/Assets/FishNet/Runtime/Serializing/GenericWriter.cs.meta new file mode 100644 index 0000000..ca1a59b --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/GenericWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c79ac203808e16489cbc2072fad75db +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs b/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs index 48153c7..5736854 100644 --- a/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs +++ b/Assets/FishNet/Runtime/Serializing/Helping/ValueConversions.cs @@ -2,9 +2,6 @@ namespace FishNet.Serializing.Helping { - - - // -- helpers for float conversion without allocations -- [StructLayout(LayoutKind.Explicit)] internal struct UIntFloat { diff --git a/Assets/FishNet/Runtime/Serializing/Reader.Delta.cs b/Assets/FishNet/Runtime/Serializing/Reader.Delta.cs new file mode 100644 index 0000000..6341cd3 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/Reader.Delta.cs @@ -0,0 +1,96 @@ +using FishNet.CodeGenerating; +using FishNet.Managing; +using FishNet.Utility; +using System.Runtime.CompilerServices; +using UnityEngine; +using static FishNet.Serializing.Writer; + +/* THIS IS IN DRAFTING / WIP. Do not attempt to use or modify this file. */ +/* THIS IS IN DRAFTING / WIP. Do not attempt to use or modify this file. */ +/* THIS IS IN DRAFTING / WIP. Do not attempt to use or modify this file. */ + +[assembly: InternalsVisibleTo(UtilityConstants.GENERATED_ASSEMBLY_NAME)] +//Required for internal tests. +[assembly: InternalsVisibleTo(UtilityConstants.TEST_ASSEMBLY_NAME)] +namespace FishNet.Serializing +{ + + /// + /// Reads data from a buffer. + /// + public partial class Reader + { + //[NotSerializer] + //internal ushort ReadUInt16Delta(ushort prev) + //{ + // int next = ReadInt32(); + // return (ushort)(prev + next); + //} + //[NotSerializer] + //internal short ReadInt16Delta(short prev) => (short)ReadUInt16Delta((ushort)prev); + + //[NotSerializer] + //internal uint ReadUInt32Delta(uint prev) + //{ + // long next = ReadInt64(); + // return (prev + (uint)next); + //} + + //[NotSerializer] + //internal int ReadInt32Delta(int prev) => (int)ReadUInt32Delta((uint)prev); + + + //[NotSerializer] + //internal ulong ReadUInt64Delta(ulong prev) + //{ + // bool newLarger = ReadBoolean(); + // ulong difference = ReadPackedWhole(); + + // return (newLarger) ? + // (prev + difference) : (prev - difference); + //} + //[NotSerializer] + //internal long ReadInt64Delta(long prev) => (long)ReadUInt64Delta((ulong)prev); + + //[NotSerializer] + //internal LayerMask ReadLayerMaskDelta(LayerMask prev) + //{ + // int layerValue = ReadInt32Delta(prev); + // return (LayerMask)layerValue; + //} + + [NotSerializer] + internal float ReadSingleDelta(float prev) + { + AutoPackTypeSigned apts = (AutoPackTypeSigned)ReadByte(); + /* If numeric value is equal to PackedPositive or higher than + * the pack type will be positive, as all positive types + * are larger than negative in the enum. */ + float multiplier = ((byte)apts >= (byte)AutoPackTypeSigned.PackedPositive) ? + 1f : -1f; + + switch (apts) + { + case AutoPackTypeSigned.Unpacked: + return ReadSingle(AutoPackType.Unpacked); + case AutoPackTypeSigned.PackedPositive: + case AutoPackTypeSigned.PackedNegative: + return (prev + GetUnpackedValue(ReadByte())); + case AutoPackTypeSigned.PackedLessPositive: + case AutoPackTypeSigned.PackedLessNegative: + return (prev + GetUnpackedValue(ReadUInt16())); + } + + //Fallthrough. + NetworkManager.LogError("Unhandled ReadSingleDelta packType of {apts}."); + return default; + + float GetUnpackedValue(ushort readValue) + { + return (readValue / Writer.ACCURACY) * multiplier; + } + } + + + } +} diff --git a/Assets/FishNet/Runtime/Serializing/Reader.Delta.cs.meta b/Assets/FishNet/Runtime/Serializing/Reader.Delta.cs.meta new file mode 100644 index 0000000..be09796 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/Reader.Delta.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 90549173680239a48a3b0b61ecd47a77 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/Reader.cs b/Assets/FishNet/Runtime/Serializing/Reader.cs index e381822..e311351 100644 --- a/Assets/FishNet/Runtime/Serializing/Reader.cs +++ b/Assets/FishNet/Runtime/Serializing/Reader.cs @@ -1,3 +1,6 @@ +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif using FishNet.CodeGenerating; using FishNet.Connection; using FishNet.Documenting; @@ -21,42 +24,11 @@ using UnityEngine; [assembly: InternalsVisibleTo(UtilityConstants.TEST_ASSEMBLY_NAME)] namespace FishNet.Serializing { - /// - /// Used for read references to generic types. - /// - /// - [APIExclude] - public static class GenericReader - { - public static Func Read { get; set; } - public static Func ReadAutoPack { get; set; } - /// - /// True if this type has a custom writer. - /// - private static bool _hasCustomSerializer; - - public static void SetReadUnpacked(Func value) - { - /* If a custom serializer has already been set then exit method - * to not overwrite serializer. */ - if (_hasCustomSerializer) - return; - - //Set has custom serializer if value being used is not a generated method. - _hasCustomSerializer = !(value.Method.Name.StartsWith(UtilityConstants.GENERATED_READER_PREFIX)); - Read = value; - } - - public static void SetReadAutoPacked(Func value) - { - ReadAutoPack = value; - } - } - + /// /// Reads data from a buffer. /// - public class Reader + public partial class Reader { #region Types. public enum DataSource @@ -104,7 +76,7 @@ namespace FishNet.Serializing /// Value may not always be set. /// public NetworkConnection NetworkConnection { get; private set; } -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT /// /// Last NetworkObject parsed. /// @@ -252,7 +224,7 @@ namespace FishNet.Serializing [MethodImpl(MethodImplOptions.AggressiveInlining)] internal PacketId ReadPacketId() { - return (PacketId)ReadUInt16(); + return (PacketId)ReadUInt16(AutoPackType.Unpacked); } /// @@ -416,11 +388,21 @@ namespace FishNet.Serializing /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ushort ReadUInt16() + public ushort ReadUInt16(AutoPackType packType = AutoPackType.Unpacked) { + //todo Packing for this type appears to be broken. Fix then remove this line. + packType = AutoPackType.Unpacked; + ushort result = 0; - result |= _buffer[Position++]; - result |= (ushort)(_buffer[Position++] << 8); + if (packType == AutoPackType.Unpacked) + { + result |= _buffer[Position++]; + result |= (ushort)(_buffer[Position++] << 8); + } + else + { + result = (ushort)ReadPackedWhole(); + } return result; } @@ -430,7 +412,7 @@ namespace FishNet.Serializing /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public short ReadInt16() => (short)ReadUInt16(); + public short ReadInt16(AutoPackType packType = AutoPackType.Packed) => (short)ReadUInt16(packType); /// /// Reads an int32. @@ -900,7 +882,7 @@ namespace FishNet.Serializing [MethodImpl(MethodImplOptions.AggressiveInlining)] public NetworkObject ReadNetworkObject(out int objectOrPrefabId, HashSet readSpawningObjects = null) { -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT LastNetworkBehaviour = null; #endif objectOrPrefabId = ReadNetworkObjectId(); @@ -953,7 +935,7 @@ namespace FishNet.Serializing result = NetworkManager.GetPrefab(objectOrPrefabId, asServer); } -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT LastNetworkObject = result; #endif return result; @@ -1056,7 +1038,7 @@ namespace FishNet.Serializing } } -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT LastNetworkBehaviour = result; #endif return result; @@ -1302,7 +1284,7 @@ namespace FishNet.Serializing * newest as 98, 99, 100. Which is the correct result. In order for this to * work properly past replicates cannot skip ticks. This will be ensured * in another part of the code. */ - tick -= (uint)(count);// - 1); + tick -= (uint)(count) - 1); int fullPackType = ReadByte(); //Read once and apply to all entries. diff --git a/Assets/FishNet/Demos/Authenticator/Prefabs.meta b/Assets/FishNet/Runtime/Serializing/UnityMathmatics.meta similarity index 77% rename from Assets/FishNet/Demos/Authenticator/Prefabs.meta rename to Assets/FishNet/Runtime/Serializing/UnityMathmatics.meta index e5950b0..7d2409e 100644 --- a/Assets/FishNet/Demos/Authenticator/Prefabs.meta +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 29d7fd53a109938428ece2660c6bbf25 +guid: 4aaaca3090257be40b80f33b9e955446 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsBoolean.cs b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsBoolean.cs new file mode 100644 index 0000000..e059906 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsBoolean.cs @@ -0,0 +1,470 @@ +#if UNITYMATHEMATICS + +using Unity.Mathematics; + +namespace FishNet.Serializing { + + public partial class Writer { + + public void Writebool2(bool2 value) { + + byte b = 0; + + if (value.x) + b |= 1; + if (value.y) + b |= 2; + + WriteByte(b); + } + + public void Writebool3(bool3 value) { + + byte b = 0; + + if (value.x) + b |= 1; + if (value.y) + b |= 2; + if (value.z) + b |= 4; + + WriteByte(b); + } + + public void Writebool4(bool4 value) { + byte b = 0; + + if (value.x) + b |= 1; + if (value.y) + b |= 2; + if (value.z) + b |= 4; + if (value.w) + b |= 8; + + WriteByte(b); + } + + public void Writebool2x2(bool2x2 value) { + + byte b = 0; + + if (value.c0.x) + b |= 1; + if (value.c0.y) + b |= 2; + if (value.c1.x) + b |= 4; + if (value.c1.y) + b |= 8; + + WriteByte(b); + } + + public void Writebool2x3(bool2x3 value) { + byte b = 0; + + if (value.c0.x) + b |= 1; + if (value.c0.y) + b |= 2; + if (value.c1.x) + b |= 4; + if (value.c1.y) + b |= 8; + if (value.c2.x) + b |= 16; + if (value.c2.y) + b |= 32; + + WriteByte(b); + } + + public void Writebool2x4(bool2x4 value) { + byte b = 0; + + if (value.c0.x) + b |= 1; + if (value.c0.y) + b |= 2; + if (value.c1.x) + b |= 4; + if (value.c1.y) + b |= 8; + if (value.c2.x) + b |= 16; + if (value.c2.y) + b |= 32; + if (value.c3.x) + b |= 64; + if (value.c3.y) + b |= 128; + + WriteByte(b); + } + + public void Writebool3x2(bool3x2 value) { + byte b = 0; + + if (value.c0.x) + b |= 1; + if (value.c0.y) + b |= 2; + if (value.c0.z) + b |= 4; + if (value.c1.x) + b |= 8; + if (value.c1.y) + b |= 16; + if (value.c1.z) + b |= 32; + + WriteByte(b); + } + + public void Writebool3x3(bool3x3 value) { + ushort s = 0; + + if (value.c0.x) + s |= 1; + if (value.c0.y) + s |= 2; + if (value.c0.z) + s |= 4; + if (value.c1.x) + s |= 8; + if (value.c1.y) + s |= 16; + if (value.c1.z) + s |= 32; + if (value.c2.x) + s |= 64; + if (value.c2.y) + s |= 128; + if (value.c2.z) + s |= 256; + + WriteUInt16(s); + } + + public void Writebool3x4(bool3x4 value) { + ushort s = 0; + + if (value.c0.x) + s |= 1; + if (value.c0.y) + s |= 2; + if (value.c0.z) + s |= 4; + if (value.c1.x) + s |= 8; + if (value.c1.y) + s |= 16; + if (value.c1.z) + s |= 32; + if (value.c2.x) + s |= 64; + if (value.c2.y) + s |= 128; + if (value.c2.z) + s |= 256; + if (value.c3.x) + s |= 512; + if (value.c3.y) + s |= 1024; + if (value.c3.z) + s |= 2048; + + WriteUInt16(s); + } + + public void Writebool4x2(bool4x2 value) { + byte b = 0; + + if (value.c0.x) + b |= 1; + if (value.c0.y) + b |= 2; + if (value.c0.z) + b |= 4; + if (value.c0.w) + b |= 8; + if (value.c1.x) + b |= 16; + if (value.c1.y) + b |= 32; + if (value.c1.z) + b |= 64; + if (value.c1.w) + b |= 128; + + WriteByte(b); + } + + public void Writebool4x3(bool4x3 value) { + ushort s = 0; + + if (value.c0.x) + s |= 1; + if (value.c0.y) + s |= 2; + if (value.c0.z) + s |= 4; + if (value.c0.w) + s |= 8; + if (value.c1.x) + s |= 16; + if (value.c1.y) + s |= 32; + if (value.c1.z) + s |= 64; + if (value.c1.w) + s |= 128; + if (value.c2.x) + s |= 256; + if (value.c2.y) + s |= 512; + if (value.c2.z) + s |= 1024; + if (value.c2.w) + s |= 2048; + + WriteUInt16(s); + } + + public void Writebool4x4(bool4x4 value) { + ushort s = 0; + + if (value.c0.x) + s |= 1; + if (value.c0.y) + s |= 2; + if (value.c0.z) + s |= 4; + if (value.c0.w) + s |= 8; + if (value.c1.x) + s |= 16; + if (value.c1.y) + s |= 32; + if (value.c1.z) + s |= 64; + if (value.c1.w) + s |= 128; + if (value.c2.x) + s |= 256; + if (value.c2.y) + s |= 512; + if (value.c2.z) + s |= 1024; + if (value.c2.w) + s |= 2048; + if (value.c3.x) + s |= 4096; + if (value.c3.y) + s |= 8192; + if (value.c3.z) + s |= 16384; + if (value.c3.w) + s |= 32768; + + WriteUInt16(s); + } + } + + public partial class Reader { + public bool2 Readbool2() { + + byte b = ReadByte(); + + return new bool2() { x = (b & 1) != 0, y = (b & 2) != 0 }; + } + + public bool3 Readbool3() { + + byte b = ReadByte(); + + return new bool3() { + x = (b & 1) != 0, + y = (b & 2) != 0, + z = (b & 4) != 0 + }; + } + + public bool4 Readbool4() { + byte b = ReadByte(); + + return new bool4 { + x = (b & 1) != 0, + y = (b & 2) != 0, + z = (b & 4) != 0, + w = (b & 8) != 0 + }; + } + + public bool2x2 Readbool2x2() { + byte b = ReadByte(); + + bool2x2 value = default; + + value.c0.x = (b & 1) != 0; + value.c0.y = (b & 2) != 0; + value.c1.x = (b & 4) != 0; + value.c1.y = (b & 8) != 0; + + return value; + } + + public bool2x3 Readbool2x3() { + byte b = ReadByte(); + + bool2x3 value = default; + + value.c0.x = (b & 1) != 0; + value.c0.y = (b & 2) != 0; + value.c1.x = (b & 4) != 0; + value.c1.y = (b & 8) != 0; + value.c2.x = (b & 16) != 0; + value.c2.y = (b & 32) != 0; + + return value; + } + + public bool2x4 Readbool2x4() { + byte b = ReadByte(); + + bool2x4 value = default; + + value.c0.x = (b & 1) != 0; + value.c0.y = (b & 2) != 0; + value.c1.x = (b & 4) != 0; + value.c1.y = (b & 8) != 0; + value.c2.x = (b & 16) != 0; + value.c2.y = (b & 32) != 0; + value.c3.x = (b & 64) != 0; + value.c3.y = (b & 128) != 0; + + return value; + } + + public bool3x2 Readbool3x2() { + byte b = ReadByte(); + + bool3x2 value = default; + + value.c0.x = (b & 1) != 0; + value.c0.y = (b & 2) != 0; + value.c0.z = (b & 4) != 0; + value.c1.x = (b & 8) != 0; + value.c1.y = (b & 16) != 0; + value.c1.z = (b & 32) != 0; + + return value; + } + + public bool3x3 Readbool3x3() { + ushort s = ReadUInt16(); + + bool3x3 value = default; + value.c0.x = (s & 1) != 0; + value.c0.y = (s & 2) != 0; + value.c0.z = (s & 4) != 0; + value.c1.x = (s & 8) != 0; + value.c1.y = (s & 16) != 0; + value.c1.z = (s & 32) != 0; + value.c2.x = (s & 64) != 0; + value.c2.y = (s & 128) != 0; + value.c2.z = (s & 256) != 0; + + return value; + } + + public bool3x4 Readbool3x4() { + ushort s = ReadUInt16(); + + bool3x4 value = default; + + value.c0.x = (s & 1) != 0; + value.c0.y = (s & 2) != 0; + value.c0.z = (s & 4) != 0; + value.c1.x = (s & 8) != 0; + value.c1.y = (s & 16) != 0; + value.c1.z = (s & 32) != 0; + value.c2.x = (s & 64) != 0; + value.c2.y = (s & 128) != 0; + value.c2.z = (s & 256) != 0; + value.c3.x = (s & 512) != 0; + value.c3.y = (s & 1024) != 0; + value.c3.z = (s & 2048) != 0; + + return value; + } + + public bool4x2 Readbool4x2() { + byte b = ReadByte(); + + bool4x2 value = default; + + value.c0.x = (b & 1) != 0; + value.c0.y = (b & 2) != 0; + value.c0.z = (b & 4) != 0; + value.c0.w = (b & 8) != 0; + value.c1.x = (b & 16) != 0; + value.c1.y = (b & 32) != 0; + value.c1.z = (b & 64) != 0; + value.c1.w = (b & 128) != 0; + + return value; + } + + public bool4x3 Readbool4x3() { + ushort s = ReadUInt16(); + + bool4x3 value = default; + + value.c0.x = (s & 1) != 0; + value.c0.y = (s & 2) != 0; + value.c0.z = (s & 4) != 0; + value.c0.w = (s & 8) != 0; + value.c1.x = (s & 16) != 0; + value.c1.y = (s & 32) != 0; + value.c1.z = (s & 64) != 0; + value.c1.w = (s & 128) != 0; + value.c2.x = (s & 256) != 0; + value.c2.y = (s & 512) != 0; + value.c2.z = (s & 1024) != 0; + value.c2.w = (s & 2048) != 0; + + return value; + } + + public bool4x4 Readbool4x4() { + ushort s = ReadUInt16(); + + bool4x4 value = default; + + value.c0.x = (s & 1) != 0; + value.c0.y = (s & 2) != 0; + value.c0.z = (s & 4) != 0; + value.c0.w = (s & 8) != 0; + value.c1.x = (s & 16) != 0; + value.c1.y = (s & 32) != 0; + value.c1.z = (s & 64) != 0; + value.c1.w = (s & 128) != 0; + value.c2.x = (s & 256) != 0; + value.c2.y = (s & 512) != 0; + value.c2.z = (s & 1024) != 0; + value.c2.w = (s & 2048) != 0; + value.c3.x = (s & 4096) != 0; + value.c3.y = (s & 8192) != 0; + value.c3.z = (s & 16384) != 0; + value.c3.w = (s & 32768) != 0; + + return value; + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsBoolean.cs.meta b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsBoolean.cs.meta new file mode 100644 index 0000000..53a70e9 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsBoolean.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 254b9133ed0260b4685ea1d28bd15df1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsDouble.cs b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsDouble.cs new file mode 100644 index 0000000..879e480 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsDouble.cs @@ -0,0 +1,194 @@ +#if UNITYMATHEMATICS + +using System.Runtime.CompilerServices; + +using Unity.Mathematics; + +namespace FishNet.Serializing { + + public partial class Writer { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writedouble2(double2 value) { + WriteDouble(value.x); + WriteDouble(value.y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writedouble3(double3 value) { + WriteDouble(value.x); + WriteDouble(value.y); + WriteDouble(value.z); + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writedouble4(double4 value) { + WriteDouble(value.x); + WriteDouble(value.y); + WriteDouble(value.z); + WriteDouble(value.w); + } + + public void Writedouble2x2(double2x2 value) { + Writedouble2(value.c0); + Writedouble2(value.c1); + } + + public void Writedouble2x3(double2x3 value) { + Writedouble2(value.c0); + Writedouble2(value.c1); + Writedouble2(value.c2); + } + + public void Writedouble2x4(double2x4 value) { + Writedouble2(value.c0); + Writedouble2(value.c1); + Writedouble2(value.c2); + Writedouble2(value.c3); + } + + public void Writedouble3x2(double3x2 value) { + Writedouble3(value.c0); + Writedouble3(value.c1); + } + + public void Writedouble4x2(double4x2 value) { + Writedouble4(value.c0); + Writedouble4(value.c1); + } + + public void Writedouble3x4(double3x4 value) { + Writedouble3(value.c0); + Writedouble3(value.c1); + Writedouble3(value.c2); + Writedouble3(value.c3); + } + + public void Writedouble4x3(double4x3 value) { + Writedouble4(value.c0); + Writedouble4(value.c1); + Writedouble4(value.c2); + } + + public void Writedouble3x3(double3x3 value) { + Writedouble3(value.c0); + Writedouble3(value.c1); + Writedouble3(value.c2); + } + public void Writedouble4x4(double4x4 value) { + Writedouble4(value.c0); + Writedouble4(value.c1); + Writedouble4(value.c2); + Writedouble4(value.c3); + } + + } + + public partial class Reader { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double2 Readdouble2() { + return new double2 { + x = ReadDouble(), + y = ReadDouble() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double3 Readdouble3() { + return new double3() { + x = ReadDouble(), + y = ReadDouble(), + z = ReadDouble() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public double4 Readdouble4() { + return new double4() { + x = ReadDouble(), + y = ReadDouble(), + z = ReadDouble(), + w = ReadDouble() + }; + } + + public double2x2 Readdouble2x2() { + return new double2x2() { + c0 = Readdouble2(), + c1 = Readdouble2() + }; + } + + + public double2x3 Readdouble2x3() { + return new double2x3() { + c0 = Readdouble2(), + c1 = Readdouble2(), + c2 = Readdouble2() + }; + } + + public double2x4 Readdouble2x4() { + return new double2x4() { + c0 = Readdouble2(), + c1 = Readdouble2(), + c2 = Readdouble2(), + c3 = Readdouble2() + }; + } + + public double3x2 Readdouble3x2() { + return new double3x2() { + c0 = Readdouble3(), + c1 = Readdouble3() + }; + } + + public double4x2 Readdouble4x2() { + return new double4x2() { + c0 = Readdouble4(), + c1 = Readdouble4() + }; + } + + public double3x4 Readdouble3x4() { + return new double3x4() { + c0 = Readdouble3(), + c1 = Readdouble3(), + c2 = Readdouble3(), + c3 = Readdouble3() + }; + } + + + public double4x3 Readdouble4x3() { + return new double4x3() { + c0 = Readdouble4(), + c1 = Readdouble4(), + c2 = Readdouble4() + }; + } + public double3x3 Readdouble3x3() { + return new double3x3() { + c0 = Readdouble3(), + c1 = Readdouble3(), + c2 = Readdouble3() + }; + } + + + public double4x4 Readdouble4x4() { + return new double4x4() { + c0 = Readdouble4(), + c1 = Readdouble4(), + c2 = Readdouble4(), + c3 = Readdouble4() + }; + } + + } +} + +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsDouble.cs.meta b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsDouble.cs.meta new file mode 100644 index 0000000..e35789f --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsDouble.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b02bb31d2808f94695dfa971bbe624b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsFloat.cs b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsFloat.cs new file mode 100644 index 0000000..37fa1e9 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsFloat.cs @@ -0,0 +1,192 @@ +#if UNITYMATHEMATICS + +using System.Runtime.CompilerServices; + +using Unity.Mathematics; + +namespace FishNet.Serializing { + + public partial class Writer { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writefloat2(float2 value) { + WriteSingle(value.x); + WriteSingle(value.y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writefloat3(float3 value) { + WriteSingle(value.x); + WriteSingle(value.y); + WriteSingle(value.z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writefloat4(float4 value) { + WriteSingle(value.x); + WriteSingle(value.y); + WriteSingle(value.z); + WriteSingle(value.w); + } + + public void Writefloat2x2(float2x2 value) { + Writefloat2(value.c0); + Writefloat2(value.c1); + } + + public void Writefloat2x3(float2x3 value) { + Writefloat2(value.c0); + Writefloat2(value.c1); + Writefloat2(value.c2); + } + + public void Writefloat2x4(float2x4 value) { + Writefloat2(value.c0); + Writefloat2(value.c1); + Writefloat2(value.c2); + Writefloat2(value.c3); + } + + public void Writefloat3x2(float3x2 value) { + Writefloat3(value.c0); + Writefloat3(value.c1); + } + + public void Writefloat3x3(float3x3 value) { + Writefloat3(value.c0); + Writefloat3(value.c1); + Writefloat3(value.c2); + } + + public void Writefloat3x4(float3x4 value) { + Writefloat3(value.c0); + Writefloat3(value.c1); + Writefloat3(value.c2); + Writefloat3(value.c3); + } + + public void Writefloat4x2(float4x2 value) { + Writefloat4(value.c0); + Writefloat4(value.c1); + } + + public void Writefloat4x3(float4x3 value) { + Writefloat4(value.c0); + Writefloat4(value.c1); + Writefloat4(value.c2); + } + + public void Writefloat4x4(float4x4 value) { + Writefloat4(value.c0); + Writefloat4(value.c1); + Writefloat4(value.c2); + Writefloat4(value.c3); + } + + } + + public partial class Reader { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float2 Readfloat2() { + return new float2 { + x = ReadSingle(), + y = ReadSingle() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float3 Readfloat3() { + return new float3() { + x = ReadSingle(), + y = ReadSingle(), + z = ReadSingle() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public float4 Readfloat4() { + return new float4() { + x = ReadSingle(), + y = ReadSingle(), + z = ReadSingle(), + w = ReadSingle() + }; + } + + public float2x2 Readfloat2x2() { + return new float2x2() { + c0 = Readfloat2(), + c1 = Readfloat2() }; + } + + public float2x3 Readfloat2x3() { + return new float2x3() { + c0 = Readfloat2(), + c1 = Readfloat2(), + c2 = Readfloat2() + }; + } + + public float2x4 Readfloat2x4() { + return new float2x4() { + c0 = Readfloat2(), + c1 = Readfloat2(), + c2 = Readfloat2(), + c3 = Readfloat2() + }; + } + + public float3x2 Readfloat3x2() { + return new float3x2() { + c0 = Readfloat3(), + c1 = Readfloat3() + }; + } + + public float3x3 Readfloat3x3() { + return new float3x3() { + c0 = Readfloat3(), + c1 = Readfloat3(), + c2 = Readfloat3() + }; + } + + public float3x4 Readfloat3x4() { + return new float3x4() { + c0 = Readfloat3(), + c1 = Readfloat3(), + c2 = Readfloat3(), + c3 = Readfloat3() + }; + } + + public float4x2 Readfloat4x2() { + return new float4x2() { + c0 = Readfloat4(), + c1 = Readfloat4() + }; + } + + public float4x3 Readfloat4x3() { + return new float4x3() { + c0 = Readfloat4(), + c1 = Readfloat4(), + c2 = Readfloat4() + }; + } + + public float4x4 Readfloat4x4() { + return new float4x4() { + c0 = Readfloat4(), + c1 = Readfloat4(), + c2 = Readfloat4(), + c3 = Readfloat4() + }; + } + + } +} + + +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsFloat.cs.meta b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsFloat.cs.meta new file mode 100644 index 0000000..d79f436 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsFloat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 501c2baf76f23f64fadc0fd46e2d95fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsHalf.cs b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsHalf.cs new file mode 100644 index 0000000..61af9a8 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsHalf.cs @@ -0,0 +1,84 @@ +#if UNITYMATHEMATICS + +using System.Runtime.CompilerServices; + +using Unity.Mathematics; + +namespace FishNet.Serializing { + + public partial class Writer { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writehalf(half value) { + WriteUInt16(value.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writehalf2(half2 value) { + WriteUInt16(value.x.value); + WriteUInt16(value.y.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writehalf3(half3 value) { + WriteUInt16(value.x.value); + WriteUInt16(value.y.value); + WriteUInt16(value.z.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writehalf4(half4 value) { + + WriteUInt16(value.x.value); + WriteUInt16(value.y.value); + WriteUInt16(value.z.value); + WriteUInt16(value.w.value); + } + } + + public partial class Reader { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public half Readhalf() { + return new half { value = ReadUInt16() }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public half2 Readhalf2() { + + half2 h = default; + + h.x.value = ReadUInt16(); + h.y.value = ReadUInt16(); + + return h; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public half3 Readhalf3() { + + half3 h = default; + + h.x.value = ReadUInt16(); + h.y.value = ReadUInt16(); + h.z.value = ReadUInt16(); + + return h; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public half4 Readhalf4() { + + half4 h = default; + + h.x.value = ReadUInt16(); + h.y.value = ReadUInt16(); + h.z.value = ReadUInt16(); + h.w.value = ReadUInt16(); + + return h; + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsHalf.cs.meta b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsHalf.cs.meta new file mode 100644 index 0000000..f8332e6 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsHalf.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eeb83ce2d1531bc4ea314600a3978c79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsInt.cs b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsInt.cs new file mode 100644 index 0000000..fea7a63 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsInt.cs @@ -0,0 +1,190 @@ +#if UNITYMATHEMATICS + +using System.Runtime.CompilerServices; +using Unity.Mathematics; + +namespace FishNet.Serializing { + + public partial class Writer { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writeint2(int2 value) { + WriteInt32(value.x); + WriteInt32(value.y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writeint3(int3 value) { + WriteInt32(value.x); + WriteInt32(value.y); + WriteInt32(value.z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writeint4(int4 value) { + WriteInt32(value.x); + WriteInt32(value.y); + WriteInt32(value.z); + WriteInt32(value.w); + } + + public void Writeint2x2(int2x2 value) { + Writeint2(value.c0); + Writeint2(value.c1); + } + + public void Writeint2x3(int2x3 value) { + Writeint2(value.c0); + Writeint2(value.c1); + Writeint2(value.c2); + } + + public void Writeint2x4(int2x4 value) { + Writeint2(value.c0); + Writeint2(value.c1); + Writeint2(value.c2); + Writeint2(value.c3); + } + + public void Writeint3x2(int3x2 value) { + Writeint3(value.c0); + Writeint3(value.c1); + } + + public void Writeint3x3(int3x3 value) { + Writeint3(value.c0); + Writeint3(value.c1); + Writeint3(value.c2); + } + + public void Writeint3x4(int3x4 value) { + Writeint3(value.c0); + Writeint3(value.c1); + Writeint3(value.c2); + Writeint3(value.c3); + } + + public void Writeint4x2(int4x2 value) { + Writeint4(value.c0); + Writeint4(value.c1); + } + + public void Writeint4x3(int4x3 value) { + Writeint4(value.c0); + Writeint4(value.c1); + Writeint4(value.c2); + } + + public void Writeint4x4(int4x4 value) { + Writeint4(value.c0); + Writeint4(value.c1); + Writeint4(value.c2); + Writeint4(value.c3); + } + + } + + public partial class Reader { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int2 Readint2() { + return new int2 { + x = ReadInt32(), + y = ReadInt32() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int3 Readint3() { + return new int3() { + x = ReadInt32(), + y = ReadInt32(), + z = ReadInt32() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int4 Readint4() { + return new int4() { + x = ReadInt32(), + y = ReadInt32(), + z = ReadInt32(), + w = ReadInt32() + }; + } + + public int2x2 Readint2x2() { + return new int2x2() { + c0 = Readint2(), + c1 = Readint2() }; + } + + public int2x3 Readint2x3() { + return new int2x3() { + c0 = Readint2(), + c1 = Readint2(), + c2 = Readint2() + }; + } + + public int2x4 Readint2x4() { + return new int2x4() { + c0 = Readint2(), + c1 = Readint2(), + c2 = Readint2(), + c3 = Readint2() + }; + } + + public int3x2 Readint3x2() { + return new int3x2() { + c0 = Readint3(), + c1 = Readint3() + }; + } + + public int3x3 Readint3x3() { + return new int3x3() { + c0 = Readint3(), + c1 = Readint3(), + c2 = Readint3() + }; + } + + public int3x4 Readint3x4() { + return new int3x4() { + c0 = Readint3(), + c1 = Readint3(), + c2 = Readint3(), + c3 = Readint3() + }; + } + + public int4x2 Readint4x2() { + return new int4x2() { + c0 = Readint4(), + c1 = Readint4() + }; + } + + public int4x3 Readint4x3() { + return new int4x3() { + c0 = Readint4(), + c1 = Readint4(), + c2 = Readint4() + }; + } + + public int4x4 Readint4x4() { + return new int4x4() { + c0 = Readint4(), + c1 = Readint4(), + c2 = Readint4(), + c3 = Readint4() + }; + } + + } +} + +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsInt.cs.meta b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsInt.cs.meta new file mode 100644 index 0000000..5fe6cd8 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsInt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 74baebf467113dd4ca83dd656a4abb67 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsMisc.cs b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsMisc.cs new file mode 100644 index 0000000..fbd0694 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsMisc.cs @@ -0,0 +1,86 @@ +#if UNITYMATHEMATICS + +using System.Runtime.CompilerServices; +using Unity.Mathematics; +using Unity.Mathematics.Geometry; + +namespace FishNet.Serializing { + + public partial class Writer { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writequaternion(quaternion value) { + Writefloat4(value.value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writerandom(Unity.Mathematics.Random random) { + WriteUInt32(random.state); + } + + public void WriteRigidTransform(RigidTransform value) { + + Writequaternion(value.rot); + Writefloat3(value.pos); + } +#if UNITYMATHEMATICS_131 + public void WriteAffineTransform(AffineTransform value) { + + Writefloat3x3(value.rs); + Writefloat3(value.t); + } +#endif + +#if UNITYMATHEMATICS_132 + + public void ReadMinMaxAABB(MinMaxAABB minMaxAABB) { + Writefloat3(minMaxAABB.Min); + Writefloat3(minMaxAABB.Max); + } + +#endif + } + + public partial class Reader { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public quaternion Readquaternion() { + return new quaternion(Readfloat4()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Random Readrandom() { + return new Random() { state = ReadUInt32() }; + } + + public RigidTransform ReadRigidTransform() { + return new RigidTransform() { + rot = Readquaternion(), + pos = Readfloat3(), + }; + } + +#if UNITYMATHEMATICS_131 + public AffineTransform ReadAffineTransform() { + + return new AffineTransform() { + rs = Readfloat3x3(), + t = Readfloat3(), + }; + } +#endif + +#if UNITYMATHEMATICS_132 + + public MinMaxAABB ReadMinMaxAABB() { + return new MinMaxAABB() { + + Min = Readfloat3(), + Max = Readfloat3() + }; + } +#endif + } +} + +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsMisc.cs.meta b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsMisc.cs.meta new file mode 100644 index 0000000..1bdd8f8 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsMisc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34d28436e6d87044fa5dcd3b0b7fd097 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsUInt.cs b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsUInt.cs new file mode 100644 index 0000000..c1057ed --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsUInt.cs @@ -0,0 +1,190 @@ +#if UNITYMATHEMATICS + +using System.Runtime.CompilerServices; +using Unity.Mathematics; + +namespace FishNet.Serializing { + + public partial class Writer { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writeuint2(uint2 value) { + WriteUInt32(value.x); + WriteUInt32(value.y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writeuint3(uint3 value) { + WriteUInt32(value.x); + WriteUInt32(value.y); + WriteUInt32(value.z); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Writeuint4(uint4 value) { + WriteUInt32(value.x); + WriteUInt32(value.y); + WriteUInt32(value.z); + WriteUInt32(value.w); + } + + public void Writeuint2x2(uint2x2 value) { + Writeuint2(value.c0); + Writeuint2(value.c1); + } + + public void Writeuint2x3(uint2x3 value) { + Writeuint2(value.c0); + Writeuint2(value.c1); + Writeuint2(value.c2); + } + + public void Writeuint2x4(uint2x4 value) { + Writeuint2(value.c0); + Writeuint2(value.c1); + Writeuint2(value.c2); + Writeuint2(value.c3); + } + + public void Writeuint3x2(uint3x2 value) { + Writeuint3(value.c0); + Writeuint3(value.c1); + } + + public void Writeuint3x3(uint3x3 value) { + Writeuint3(value.c0); + Writeuint3(value.c1); + Writeuint3(value.c2); + } + + public void Writeuint3x4(uint3x4 value) { + Writeuint3(value.c0); + Writeuint3(value.c1); + Writeuint3(value.c2); + Writeuint3(value.c3); + } + + public void Writeuint4x2(uint4x2 value) { + Writeuint4(value.c0); + Writeuint4(value.c1); + } + + public void Writeuint4x3(uint4x3 value) { + Writeuint4(value.c0); + Writeuint4(value.c1); + Writeuint4(value.c2); + } + + public void Writeuint4x4(uint4x4 value) { + Writeuint4(value.c0); + Writeuint4(value.c1); + Writeuint4(value.c2); + Writeuint4(value.c3); + } + + } + + public partial class Reader { + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint2 Readuint2() { + return new uint2 { + x = ReadUInt32(), + y = ReadUInt32() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint3 Readuint3() { + return new uint3() { + x = ReadUInt32(), + y = ReadUInt32(), + z = ReadUInt32() + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint4 Readuint4() { + return new uint4() { + x = ReadUInt32(), + y = ReadUInt32(), + z = ReadUInt32(), + w = ReadUInt32() + }; + } + + public uint2x2 Readuint2x2() { + return new uint2x2() { + c0 = Readuint2(), + c1 = Readuint2() }; + } + + public uint2x3 Readuint2x3() { + return new uint2x3() { + c0 = Readuint2(), + c1 = Readuint2(), + c2 = Readuint2() + }; + } + + public uint2x4 Readuint2x4() { + return new uint2x4() { + c0 = Readuint2(), + c1 = Readuint2(), + c2 = Readuint2(), + c3 = Readuint2() + }; + } + + public uint3x2 Readuint3x2() { + return new uint3x2() { + c0 = Readuint3(), + c1 = Readuint3() + }; + } + + public uint3x3 Readuint3x3() { + return new uint3x3() { + c0 = Readuint3(), + c1 = Readuint3(), + c2 = Readuint3() + }; + } + + public uint3x4 Readuint3x4() { + return new uint3x4() { + c0 = Readuint3(), + c1 = Readuint3(), + c2 = Readuint3(), + c3 = Readuint3() + }; + } + + public uint4x2 Readuint4x2() { + return new uint4x2() { + c0 = Readuint4(), + c1 = Readuint4() + }; + } + + public uint4x3 Readuint4x3() { + return new uint4x3() { + c0 = Readuint4(), + c1 = Readuint4(), + c2 = Readuint4() + }; + } + + public uint4x4 Readuint4x4() { + return new uint4x4() { + c0 = Readuint4(), + c1 = Readuint4(), + c2 = Readuint4(), + c3 = Readuint4() + }; + } + + } +} + +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsUInt.cs.meta b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsUInt.cs.meta new file mode 100644 index 0000000..e9f085c --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/UnityMathmatics/Serializers.UnityMathmaticsUInt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5640c6f5fc37ed3419f18024866c816c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/Writer.Delta.cs b/Assets/FishNet/Runtime/Serializing/Writer.Delta.cs new file mode 100644 index 0000000..f30019f --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/Writer.Delta.cs @@ -0,0 +1,218 @@ +using FishNet.CodeGenerating; +using FishNet.Connection; +using FishNet.Documenting; +using FishNet.Managing; +using FishNet.Object; +using FishNet.Object.Prediction; +using FishNet.Serializing.Helping; +using FishNet.Utility; +using System; +using System.Runtime.CompilerServices; +using UnityEngine; + +[assembly: InternalsVisibleTo(UtilityConstants.GENERATED_ASSEMBLY_NAME)] +namespace FishNet.Serializing +{ + + /* THIS IS IN DRAFTING / WIP. Do not attempt to use or modify this file. */ + /* THIS IS IN DRAFTING / WIP. Do not attempt to use or modify this file. */ + /* THIS IS IN DRAFTING / WIP. Do not attempt to use or modify this file. */ + + /// + /// Writes data to a buffer. + /// + public partial class Writer + { + [System.Flags] + internal enum AutoPackTypeSigned : byte + { + Unpacked = 0, + PackedNegative = 1, + PackedLessNegative = 2, + PackedPositive = 4, + PackedLessPositive = 8, + } + + + internal const float LARGEST_PACKED_UNSIGNED_FLOAT = ((float)byte.MaxValue / ACCURACY); + internal const float LARGEST_PACKEDLESS_UNSIGNED_FLOAT = ((float)ushort.MaxValue / ACCURACY); + internal const float LARGEST_PACKED_SIGNED_FLOAT = ((float)sbyte.MaxValue / ACCURACY); + internal const float LARGEST_PACKEDLESS_SIGNED_FLOAT = ((float)short.MaxValue / ACCURACY); + internal const float ACCURACY = 1000f; + internal const float ACCURACY_DECIMAL = 0.001f; + + + //[NotSerializer] + //internal void WriteUInt16Delta(ushort a, ushort b) + //{ + // int difference = (int)(b - a); + // WritePackedWhole((ulong)difference); + //} + //[NotSerializer] + //internal void WriteInt16Delta(short a, short b) => WriteUInt16Delta((ushort)a, (ushort)b); + + + //[NotSerializer] + //internal void WriteUInt32Delta(uint a, uint b) + //{ + // long difference = (long)(b - a); + // WritePackedWhole((ulong)difference); + //} + //[NotSerializer] + //internal void WriteInt32Delta(int a, int b) => WriteUInt32Delta((uint)a, (uint)b); + + + //[NotSerializer] + //internal void WriteUInt64Delta(ulong a, ulong b) + //{ + // ulong difference; + // bool bLarger; + // if (b > a) + // { + // bLarger = true; + // difference = (b - a); + // } + // else + // { + // bLarger = false; + // difference = (a - b); + // } + + // WriteBoolean(bLarger); + // WritePackedWhole(difference); + //} + //[NotSerializer] + //internal void WriteInt64Delta(long a, long b) => WriteUInt64Delta((ulong)a, (ulong)b); + + //[NotSerializer] + //internal void WriteLayerMaskDelta(LayerMask a, LayerMask b) + //{ + // WriteInt32Delta(b.value, a.value); + //} + + [NotSerializer] + internal void WriteSingleDelta(float a, float b) + { + double difference = (b - a); + AutoPackTypeSigned apts = GetAutoPackTypeSigned(difference); + WriteByte((byte)apts); + + switch (apts) + { + case AutoPackTypeSigned.PackedNegative: + case AutoPackTypeSigned.PackedPositive: + WriteByte((byte)(difference * ACCURACY)); + return; + case AutoPackTypeSigned.PackedLessNegative: + case AutoPackTypeSigned.PackedLessPositive: + WriteUInt16((ushort)(difference * ACCURACY)); + return; + case AutoPackTypeSigned.Unpacked: + WriteSingle(b, AutoPackType.Unpacked); + return; + } + } + + private AutoPackTypeSigned GetAutoPackTypeSigned(double value) + { + double absValue = (value >= 0d) ? value : (value * -1d); + + if (absValue <= LARGEST_PACKED_UNSIGNED_FLOAT) + return (value >= 0d) ? AutoPackTypeSigned.PackedPositive : AutoPackTypeSigned.PackedNegative; + else if (absValue <= LARGEST_PACKEDLESS_UNSIGNED_FLOAT) + return (value >= 0d) ? AutoPackTypeSigned.PackedLessPositive : AutoPackTypeSigned.PackedLessNegative; + else + return AutoPackTypeSigned.Unpacked; + } + + //Draft / WIP below. May become discarded. + + //internal enum DeltaPackType + //{ + // Packed = 1, + // PackedLess = 2, + //} + //internal enum Vector3DeltaA : byte + //{ + // Unset = 0, + // XPacked = 1, + // XPackedLess = 2, + // XUnpacked = 4, + // YPacked = 8, + // YPackedLess = 16, + // YUnpacked = 32, + // ZPacked = 64, + // ZPackedLess = 128, + // ZUnpacked = 4, + //} + + //internal const float LARGEST_PACKED_DIFFERENCE = ((float)sbyte.MaxValue / ACCURACY); + //internal const float LARGEST_PACKEDLESS_DIFFERENCE = ((float)short.MaxValue / ACCURACY); + //internal const float ACCURACY = 1000f; + //internal const float ACCURACY_DECIMAL = 0.001f; + + + //[NotSerializer] + //public void WriteVector3Delta(Vector3 a, Vector3 b) + //{ + // //Start as the highest. + + // float xDiff = (b.x - a.x); + // float yDiff = (b.x - a.x); + // float zDiff = (b.x - a.x); + + // float absXDiff = Mathf.Abs(xDiff); + // float absYDiff = Mathf.Abs(yDiff); + // float absZDiff = Mathf.Abs(zDiff); + + // float largestDiff = 0f; + // Vector3Delta delta = Vector3Delta.Unset; + // if (absXDiff >= ACCURACY_DECIMAL) + // { + // delta |= Vector3Delta.HasX; + // largestDiff = absXDiff; + // } + // if (absYDiff >= ACCURACY_DECIMAL) + // { + // delta |= Vector3Delta.HasY; + // largestDiff = Mathf.Max(largestDiff, absYDiff); + // } + // if (absZDiff >= ACCURACY_DECIMAL) + // { + // delta |= Vector3Delta.HasZ; + // largestDiff = Mathf.Max(largestDiff, absZDiff); + // } + + // /* If packed is not specified then unpacked + // * is assumed. */ + // if (largestDiff <= LARGEST_PACKED_DIFFERENCE) + // delta |= Vector3Delta.Packed; + // else if (largestDiff <= LARGEST_PACKEDLESS_DIFFERENCE) + // delta |= Vector3Delta.PackedLess; + + + + // xDiff = Mathf.CeilToInt(xDiff * ACCURACY); + // yDiff = Mathf.CeilToInt(yDiff * ACCURACY); + // zDiff = Mathf.CeilToInt(zDiff * ACCURACY); + + // Reserve(1); + + + // UIntFloat valA; + // UIntFloat valB; + + // valA = new UIntFloat(a.x); + // valB = new UIntFloat(b.x); + // WriteUInt32(valB.UIntValue - valA.UIntValue, packType); + // Debug.Log("Diff " + (valB.UIntValue - valA.UIntValue) + ", " + (valA.UIntValue - valB.UIntValue)); + // valA = new UIntFloat(a.y); + // valB = new UIntFloat(b.y); + // WriteUInt32(valB.UIntValue - valA.UIntValue, packType); + // valA = new UIntFloat(a.z); + // valB = new UIntFloat(b.z); + // WriteUInt32(valB.UIntValue - valA.UIntValue, packType); + //} + + } +} diff --git a/Assets/FishNet/Runtime/Serializing/Writer.Delta.cs.meta b/Assets/FishNet/Runtime/Serializing/Writer.Delta.cs.meta new file mode 100644 index 0000000..599e314 --- /dev/null +++ b/Assets/FishNet/Runtime/Serializing/Writer.Delta.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 03955a9bd0c9a6f44886554887435672 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Serializing/Writer.cs b/Assets/FishNet/Runtime/Serializing/Writer.cs index 51fa92c..9f21ca4 100644 --- a/Assets/FishNet/Runtime/Serializing/Writer.cs +++ b/Assets/FishNet/Runtime/Serializing/Writer.cs @@ -19,42 +19,10 @@ using System.Reflection; namespace FishNet.Serializing { - /// - /// Used for write references to generic types. - /// - /// - [APIExclude] - public static class GenericWriter - { - public static Action Write { get; private set; } - public static Action WriteAutoPack { get; private set; } - /// - /// True if this type has a custom writer. - /// - private static bool _hasCustomSerializer; - - public static void SetWriteUnpacked(Action value) - { - /* If a custom serializer has already been set then exit method - * to not overwrite serializer. */ - if (_hasCustomSerializer) - return; - - //Set has custom serializer if value being used is not a generated method. - _hasCustomSerializer = !(value.Method.Name.StartsWith(UtilityConstants.GENERATED_WRITER_PREFIX)); - Write = value; - } - - public static void SetWriteAutoPacked(Action value) - { - WriteAutoPack = value; - } - } - /// /// Writes data to a buffer. /// - public class Writer + public partial class Writer { #region Public. /// @@ -226,7 +194,7 @@ namespace FishNet.Serializing [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void WritePacketId(PacketId pid) { - WriteUInt16((ushort)pid); + WriteUInt16((ushort)pid, AutoPackType.Unpacked); } /// @@ -346,12 +314,22 @@ namespace FishNet.Serializing /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteUInt16(ushort value) + public void WriteUInt16(ushort value, AutoPackType packType = AutoPackType.Packed) { - EnsureBufferLength(2); - _buffer[Position++] = (byte)value; - _buffer[Position++] = (byte)(value >> 8); - Length = Math.Max(Length, Position); + //todo Packing for this type appears to be broken. Fix then remove this line. + packType = AutoPackType.Unpacked; + + if (packType == AutoPackType.Unpacked) + { + EnsureBufferLength(2); + _buffer[Position++] = (byte)value; + _buffer[Position++] = (byte)(value >> 8); + Length = Math.Max(Length, Position); + } + else + { + WritePackedWhole(value); + } } /// @@ -359,13 +337,7 @@ namespace FishNet.Serializing /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void WriteInt16(short value) - { - EnsureBufferLength(2); - _buffer[Position++] = (byte)value; - _buffer[Position++] = (byte)(value >> 8); - Length = Math.Max(Length, Position); - } + public void WriteInt16(short value, AutoPackType packType = AutoPackType.Packed) => WriteUInt16((ushort)value, packType); /// /// Writes a int32. @@ -536,11 +508,8 @@ namespace FishNet.Serializing [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteVector2(Vector2 value) { - UIntFloat converter; - converter = new UIntFloat { FloatValue = value.x }; - WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); - converter = new UIntFloat { FloatValue = value.y }; - WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); + WriteSingle(value.x, AutoPackType.Unpacked); + WriteSingle(value.y, AutoPackType.Unpacked); } /// @@ -550,13 +519,9 @@ namespace FishNet.Serializing [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteVector3(Vector3 value) { - UIntFloat converter; - converter = new UIntFloat { FloatValue = value.x }; - WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); - converter = new UIntFloat { FloatValue = value.y }; - WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); - converter = new UIntFloat { FloatValue = value.z }; - WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); + WriteSingle(value.x, AutoPackType.Unpacked); + WriteSingle(value.y, AutoPackType.Unpacked); + WriteSingle(value.z, AutoPackType.Unpacked); } /// @@ -566,15 +531,10 @@ namespace FishNet.Serializing [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteVector4(Vector4 value) { - UIntFloat converter; - converter = new UIntFloat { FloatValue = value.x }; - WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); - converter = new UIntFloat { FloatValue = value.y }; - WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); - converter = new UIntFloat { FloatValue = value.z }; - WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); - converter = new UIntFloat { FloatValue = value.w }; - WriteUInt32(converter.UIntValue, AutoPackType.Unpacked); + WriteSingle(value.x, AutoPackType.Unpacked); + WriteSingle(value.y, AutoPackType.Unpacked); + WriteSingle(value.z, AutoPackType.Unpacked); + WriteSingle(value.w, AutoPackType.Unpacked); } /// diff --git a/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs b/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs index bf75044..5b5b0e7 100644 --- a/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs +++ b/Assets/FishNet/Runtime/Serializing/WriterExtensions.cs @@ -25,6 +25,8 @@ namespace FishNet.Serializing static WriterExtensions() { + DefaultPackedTypes.Add(typeof(short)); + DefaultPackedTypes.Add(typeof(ushort)); DefaultPackedTypes.Add(typeof(int)); DefaultPackedTypes.Add(typeof(uint)); DefaultPackedTypes.Add(typeof(long)); diff --git a/Assets/FishNet/Runtime/Transporting/PacketId.cs b/Assets/FishNet/Runtime/Transporting/PacketId.cs index 6dfcfa2..c74bbed 100644 --- a/Assets/FishNet/Runtime/Transporting/PacketId.cs +++ b/Assets/FishNet/Runtime/Transporting/PacketId.cs @@ -29,6 +29,7 @@ namespace FishNet.Transporting TimingUpdate = 18, NetworkLODUpdate = 19, StateUpdate = 20, + Version = 21, } } \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Transporting/TransportConsts.cs b/Assets/FishNet/Runtime/Transporting/TransportConsts.cs new file mode 100644 index 0000000..ebb009e --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/TransportConsts.cs @@ -0,0 +1,16 @@ +using FishNet.Managing; +using System; +using UnityEngine; + +namespace FishNet.Transporting +{ + + public static class TransportConsts + { + /// + /// Value used when a transport index is not known or set for a connection. + /// + public const int UNSET_TRANSPORT_INDEX = -1; + + } +} diff --git a/Assets/FishNet/Runtime/Transporting/TransportConsts.cs.meta b/Assets/FishNet/Runtime/Transporting/TransportConsts.cs.meta new file mode 100644 index 0000000..18a0f91 --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/TransportConsts.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 490a5b566793e5a4e8a97a583eab55e8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs b/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs index b806e9a..582b144 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Multipass/Multipass.cs @@ -1,3 +1,8 @@ +#if FISHNET_STABLE_MODE +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +using FishNet.Connection; using FishNet.Managing; using GameKit.Dependencies.Utilities; using System; @@ -118,13 +123,10 @@ namespace FishNet.Transporting.Multipass /// Ids available to new connections. /// private Queue _availableMultipassIds = new Queue(); - #endregion - - #region Const. /// - /// Id to use for client when acting as host. + /// Last Id added to availableMultipassIds. /// - internal const int CLIENT_HOST_ID = short.MaxValue; + private int _lastAvailableMultipassId = 0; #endregion public override void Initialize(NetworkManager networkManager, int transportIndex) @@ -173,7 +175,6 @@ namespace FishNet.Transporting.Multipass ResetLookupCollections(); } - #region ClientIds. /// /// Resets lookup collections and caches potential garbage. @@ -203,7 +204,7 @@ namespace FishNet.Transporting.Multipass } ResetLookupCollections(); - CreateAvailableIds(); + CreateAvailableIds(true); } /// @@ -357,7 +358,7 @@ namespace FishNet.Transporting.Multipass * transportConnectionId. */ int transportIndex = connectionStateArgs.TransportIndex; - int transportId = connectionStateArgs.ConnectionId; + int transportConnectionId = connectionStateArgs.ConnectionId; /* MultipassId is set to a new value when connecting * or discovered value when disconnecting. */ int multipassId; @@ -366,12 +367,22 @@ namespace FishNet.Transporting.Multipass //Started. if (connectionStateArgs.ConnectionState == RemoteConnectionState.Started) { + if (_availableMultipassIds.Count == 0) + { + bool addedIds = CreateAvailableIds(false); + if (!addedIds) + { + base.NetworkManager.Log($"There are no more available connectionIds to use. Connection {transportConnectionId} has been kicked."); + _transports[transportIndex].StopConnection(transportConnectionId, true); + return; + } + } //Get a multipassId for new connections. multipassId = _availableMultipassIds.Dequeue(); //Get and update a clienttransportdata. - ClientTransportData ctd = new ClientTransportData(transportIndex, transportId, multipassId); + ClientTransportData ctd = new ClientTransportData(transportIndex, transportConnectionId, multipassId); //Assign the lookup for transportId/index. - transportToMultipass[transportId] = ctd; + transportToMultipass[transportConnectionId] = ctd; //Assign the lookup for multipassId. _multpassIdLookup[multipassId] = ctd; @@ -383,7 +394,7 @@ namespace FishNet.Transporting.Multipass //Stopped. else { - ClientTransportData ctd = GetDataFromTransportId(transportIndex, transportId); + ClientTransportData ctd = GetDataFromTransportId(transportIndex, transportConnectionId); /* If CTD could not be found then the connection * is not stored/known. Nothing further can be done; the event cannot * invoke either since Id is unknown. */ @@ -392,9 +403,9 @@ namespace FishNet.Transporting.Multipass //Add the multipassId back to the queue. _availableMultipassIds.Enqueue(ctd.MultipassId); - transportToMultipass.Remove(transportId); + transportToMultipass.Remove(transportConnectionId); _multpassIdLookup.Remove(ctd.MultipassId); -#if UNITY_EDITOR || DEVELOPMENT_BUILD +#if DEVELOPMENT //Remove packets held for connection from latency simulator. base.NetworkManager.TransportManager.LatencySimulator.RemovePendingForConnection(ctd.MultipassId); #endif @@ -475,9 +486,6 @@ namespace FishNet.Transporting.Multipass /// /// Sends data to a client. /// - /// - /// - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override void SendToClient(byte channelId, ArraySegment segment, int multipassId) { @@ -527,12 +535,25 @@ namespace FishNet.Transporting.Multipass /// /// Populates the availableIds collection. /// - private void CreateAvailableIds() + /// True if at least 1 Id was added. + private bool CreateAvailableIds(bool reset) { - _availableMultipassIds.Clear(); - //Reserve maxValue - 1 since some local transports use that. - for (int i = 0; i < (short.MaxValue - 1); i++) - _availableMultipassIds.Enqueue(i); + if (reset) + { + _lastAvailableMultipassId = 0; + _availableMultipassIds.Clear(); + } + //Add in blocks of 1000. + int added = 0; + while ((_lastAvailableMultipassId <= NetworkConnection.MAXIMUM_CLIENTID_WITHOUT_SIMULATED_VALUE) + && (added < 1000)) + { + added++; + _availableMultipassIds.Enqueue(_lastAvailableMultipassId); + _lastAvailableMultipassId++; + } + + return (added > 0); } /// @@ -643,14 +664,13 @@ namespace FishNet.Transporting.Multipass /// /// Returns the maximum number of clients allowed to connect to the server. If the transport does not support this method the value -1 is returned. - /// The first transport is used. + /// This method is not supported. Use GetMaximumClients(transportIndex) instead. /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetMaximumClients() { base.NetworkManager.LogError($"This method is not supported. Use GetMaximumClients(transportIndex) instead."); - return -1; } /// @@ -668,12 +688,13 @@ namespace FishNet.Transporting.Multipass } /// /// Sets maximum number of clients allowed to connect to the server. If applied at runtime and clients exceed this value existing clients will stay connected but new clients may not connect. - /// This sets the value to the transport on the first index. + /// This sets the value for every transport. /// /// public override void SetMaximumClients(int value) { - base.NetworkManager.LogError($"This method is not supported. Use SetMaximumClients(value, transportIndex) instead."); + foreach (Transport t in _transports) + t.SetMaximumClients(value); } /// /// Sets maximum number of clients allowed to connect to the server. If applied at runtime and clients exceed this value existing clients will stay connected but new clients may not connect. @@ -697,10 +718,29 @@ namespace FishNet.Transporting.Multipass foreach (Transport t in _transports) t.SetClientAddress(address); } + /// + /// Sets which address the client will connect to. + /// + /// + /// Transport index to set for. + public void SetClientAddress(string address, int index) + { + if (!IndexInRange(index, true)) + return; + + _transports[index].SetClientAddress(address); + } + + /// + /// Sets which address the server will bind to. + /// This will set the address for every transport. + /// public override void SetServerBindAddress(string address, IPAddressType addressType) { - base.NetworkManager.LogError($"This method is not supported. Use SetServerBindAddress(address, transportIndex) instead."); + foreach (Transport t in _transports) + t.SetServerBindAddress(address, addressType); } + /// Sets which address the server will bind to. /// This is called on the transport of index. /// @@ -713,11 +753,13 @@ namespace FishNet.Transporting.Multipass _transports[index].SetServerBindAddress(address, addressType); } /// - /// Sets which port to use on the first transport. + /// Sets which port to use. + /// This will set the port for every transport. /// public override void SetPort(ushort port) { - base.NetworkManager.LogError($"This method is not supported. Use SetPort(port, transportIndex) instead."); + foreach (Transport t in _transports) + t.SetPort(port); } /// /// Sets which port to use on transport of index. @@ -993,3 +1035,1058 @@ namespace FishNet.Transporting.Multipass } } + + +#else + + + +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define DEVELOPMENT +#endif +using FishNet.Connection; +using FishNet.Managing; +using GameKit.Dependencies.Utilities; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Transporting.Multipass +{ + [AddComponentMenu("FishNet/Transport/Multipass")] + public class Multipass : Transport + { + #region Types. + public struct ClientTransportData : IEquatable + { + /// + /// Transport index this connection is on. + /// + public int TransportIndex; + /// + /// ConnectionId assigned by the transport. + /// + public int TransportId; + /// + /// Connection Id assigned by multipass. This Id is the one communicated to the NetworkManager. + /// + public int MultipassId; + /// + /// Cached hashcode for values. + /// + private int _hashCode; + + public ClientTransportData(int transportIndex, int transportId, int multipassId) + { + TransportIndex = transportIndex; + TransportId = transportId; + MultipassId = multipassId; + _hashCode = (transportIndex, transportId, multipassId).GetHashCode(); + } + + public bool Equals(ClientTransportData other) + { + return (_hashCode == other._hashCode); + } + } + #endregion + + #region Public. + /// + /// While true server actions such as starting or stopping the server will run on all transport. + /// + [Tooltip("While true server actions such as starting or stopping the server will run on all transport.")] + public bool GlobalServerActions = true; + /// + /// + /// + private Transport _clientTransport; + /// + /// Transport the client is using. + /// Use SetClientTransport to assign this value. + /// + [HideInInspector] + public Transport ClientTransport + { + get + { + //If not yet set. + if (_clientTransport == null) + { + //If there are transports to set from. + if (_transports.Count != 0) + _clientTransport = _transports[0]; + + /* Give feedback to developer that transport was not set + * before accessing this. Transport should always be set + * manually rather than assuming the default client + * transport. */ + if (_clientTransport == null) + base.NetworkManager.LogError($"ClientTransport in Multipass could not be set to the first transport. This can occur if no trnasports are specified or if the first entry is null."); + else + base.NetworkManager.LogError($"ClientTransport in Multipass is being automatically set to {_clientTransport.GetType()}. For production use SetClientTransport before attempting to access the ClientTransport."); + } + + return _clientTransport; + } + + private set => _clientTransport = value; + } + #endregion + + #region Serialized. + /// + /// + /// + [Tooltip("Transports to use.")] + [SerializeField] + private List _transports = new List(); + /// + /// Transports to use. + /// + public IList Transports => _transports; + #endregion + + #region Private. + /// + /// An unset/invalid ClientTransportData. + /// + private readonly ClientTransportData INVALID_CLIENTTRANSPORTDATA = new ClientTransportData(int.MinValue, int.MinValue, int.MinValue); + /// + /// MultipassId lookup. + /// + private Dictionary _multpassIdLookup = new Dictionary(); + /// + /// TransportId lookup. Each index within the list is the same as the transport index. + /// + private List> _transportIdLookup = new List>(); + /// + /// Ids available to new connections. + /// + private Queue _availableMultipassIds = new Queue(); + /// + /// Last Id added to availableMultipassIds. + /// + private int _lastAvailableMultipassId = 0; + #endregion + + public override void Initialize(NetworkManager networkManager, int transportIndex) + { + base.Initialize(networkManager, transportIndex); + + //Remove any null transports and warn. + for (int i = 0; i < _transports.Count; i++) + { + if (_transports[i] == null) + { + base.NetworkManager.LogWarning($"Transports contains a null entry on index {i}."); + _transports.RemoveAt(i); + i--; + } + } + + //No transports to use. + if (_transports.Count == 0) + { + base.NetworkManager.LogError($"No transports are set within Multipass."); + return; + } + + //Create transportsToMultipass. + for (int i = 0; i < _transports.Count; i++) + { + Dictionary dict = new Dictionary(); + _transportIdLookup.Add(dict); + //Initialize transports and callbacks. + _transports[i].Initialize(networkManager, i); + _transports[i].OnClientConnectionState += Multipass_OnClientConnectionState; + _transports[i].OnServerConnectionState += Multipass_OnServerConnectionState; + _transports[i].OnRemoteConnectionState += Multipass_OnRemoteConnectionState; + _transports[i].OnClientReceivedData += Multipass_OnClientReceivedData; + _transports[i].OnServerReceivedData += Multipass_OnServerReceivedData; + } + } + + private void OnDestroy() + { + //Initialize each transport. + foreach (Transport t in _transports) + t.Shutdown(); + + ResetLookupCollections(); + } + + #region ClientIds. + /// + /// Resets lookup collections and caches potential garbage. + /// + private void ResetLookupCollections() + { + _multpassIdLookup.Clear(); + + for (int i = 0; i < _transportIdLookup.Count; i++) + _transportIdLookup[i].Clear(); + } + + /// + /// Clears ClientIds when appropriate. + /// + private void TryResetClientIds(bool force) + { + //Can only clear when every transport server isnt connected. + if (!force) + { + foreach (Transport t in _transports) + { + //Cannot clear if a server is running still. + if (t.GetConnectionState(true) == LocalConnectionState.Started) + return; + } + } + + ResetLookupCollections(); + CreateAvailableIds(true); + } + + /// + /// Gets the Multipass connectionId using a transport connectionid. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ClientTransportData GetDataFromTransportId(int transportIndex, int transportId) + { + Dictionary dict = _transportIdLookup[transportIndex]; + if (dict.TryGetValueIL2CPP(transportId, out ClientTransportData ctd)) + return ctd; + + //Fall through/fail. + base.NetworkManager.LogError($"Multipass connectionId could not be found for transportIndex {transportIndex}, transportId of {transportId}."); + return INVALID_CLIENTTRANSPORTDATA; + } + + /// + /// Gets the TransportIdData using a Multipass connectionId. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ClientTransportData GetDataFromMultipassId(int multipassId) + { + if (_multpassIdLookup.TryGetValueIL2CPP(multipassId, out ClientTransportData ctd)) + return ctd; + + //Fall through/fail. + base.NetworkManager.LogError($"TransportIdData could not be found for Multipass connectionId of {multipassId}."); + return INVALID_CLIENTTRANSPORTDATA; + } + #endregion + + #region ConnectionStates. + /// + /// Gets the IP address of a remote connectionId. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override string GetConnectionAddress(int multipassId) + { + ClientTransportData ctd = GetDataFromMultipassId(multipassId); + if (ctd.Equals(INVALID_CLIENTTRANSPORTDATA)) + return string.Empty; + + return _transports[ctd.TransportIndex].GetConnectionAddress(ctd.TransportId); + } + /// + /// Called when a connection state changes for the local client. + /// + public override event Action OnClientConnectionState; + /// + /// Called when a connection state changes for the local server. + /// + public override event Action OnServerConnectionState; + /// + /// Called when a connection state changes for a remote client. + /// + public override event Action OnRemoteConnectionState; + /// + /// Gets the current local ConnectionState of the first transport. + /// + /// True if getting ConnectionState for the server. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override LocalConnectionState GetConnectionState(bool server) + { + if (server) + { + base.NetworkManager.LogError($"This method is not supported for server. Use GetConnectionState(server, transportIndex) instead."); + return LocalConnectionState.Stopped; + } + + if (IsClientTransportSetWithError("GetConnectionState")) + return GetConnectionState(server, ClientTransport.Index); + else + return LocalConnectionState.Stopped; + } + /// + /// Gets the current local ConnectionState of the transport on index. + /// + /// True if getting ConnectionState for the server. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public LocalConnectionState GetConnectionState(bool server, int transportIndex) + { + if (!IndexInRange(transportIndex, true)) + return LocalConnectionState.Stopped; + + return _transports[transportIndex].GetConnectionState(server); + } + /// + /// Gets the current ConnectionState of a remote client on the server. + /// + /// ConnectionId to get ConnectionState for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override RemoteConnectionState GetConnectionState(int multipassId) + { + ClientTransportData ctd = GetDataFromMultipassId(multipassId); + if (ctd.Equals(INVALID_CLIENTTRANSPORTDATA)) + return RemoteConnectionState.Stopped; + + return _transports[ctd.TransportIndex].GetConnectionState(ctd.TransportId); + } + /// + /// Gets the current ConnectionState of a remote client on the server of the transport on index. + /// + /// ConnectionId to get ConnectionState for. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public RemoteConnectionState GetConnectionState(int connectionId, int index) + { + if (!IndexInRange(index, true)) + return RemoteConnectionState.Stopped; + + return _transports[index].GetConnectionState(connectionId); + } + + /// + /// Handles a ConnectionStateArgs for the local client. + /// + /// + private void Multipass_OnClientConnectionState(ClientConnectionStateArgs connectionStateArgs) + { + OnClientConnectionState?.Invoke(connectionStateArgs); + } + /// + /// Handles a ConnectionStateArgs for the local server. + /// + /// + private void Multipass_OnServerConnectionState(ServerConnectionStateArgs connectionStateArgs) + { + OnServerConnectionState?.Invoke(connectionStateArgs); + TryResetClientIds(false); + } + /// + /// Handles a ConnectionStateArgs for a remote client. + /// + /// + private void Multipass_OnRemoteConnectionState(RemoteConnectionStateArgs connectionStateArgs) + { + /* When starting Multipass needs to get a new + * connectionId to be used within FN. This is the 'ClientId' + * that is passed around for ownership, rpcs, ect. + * + * The new connectionId will be linked with the connectionId + * from the transport, named transportConnectionid. + * + * When data arrives the transportStateId is used as a key + * in fromClientIds, where Multipass Id is returned. The argument values + * are then overwritten with the MultipassId. + * + * When data is being sent the same process is performed but reversed. + * The connectionId is looked up in toClientIds, where the transportConnectionId + * is output. Then as before the argument values are overwritten with the + * transportConnectionId. */ + + int transportIndex = connectionStateArgs.TransportIndex; + int transportConnectionId = connectionStateArgs.ConnectionId; + /* MultipassId is set to a new value when connecting + * or discovered value when disconnecting. */ + int multipassId; + Dictionary transportToMultipass = _transportIdLookup[transportIndex]; + + //Started. + if (connectionStateArgs.ConnectionState == RemoteConnectionState.Started) + { + if (_availableMultipassIds.Count == 0) + { + bool addedIds = CreateAvailableIds(false); + if (!addedIds) + { + base.NetworkManager.Log($"There are no more available connectionIds to use. Connection {transportConnectionId} has been kicked."); + _transports[transportIndex].StopConnection(transportConnectionId, true); + return; + } + } + //Get a multipassId for new connections. + multipassId = _availableMultipassIds.Dequeue(); + //Get and update a clienttransportdata. + ClientTransportData ctd = new ClientTransportData(transportIndex, transportConnectionId, multipassId); + //Assign the lookup for transportId/index. + transportToMultipass[transportConnectionId] = ctd; + //Assign the lookup for multipassId. + _multpassIdLookup[multipassId] = ctd; + + //Update args to use multipassId before invoking. + connectionStateArgs.ConnectionId = multipassId; + OnRemoteConnectionState?.Invoke(connectionStateArgs); + + } + //Stopped. + else + { + ClientTransportData ctd = GetDataFromTransportId(transportIndex, transportConnectionId); + /* If CTD could not be found then the connection + * is not stored/known. Nothing further can be done; the event cannot + * invoke either since Id is unknown. */ + if (ctd.Equals(INVALID_CLIENTTRANSPORTDATA)) + return; + + //Add the multipassId back to the queue. + _availableMultipassIds.Enqueue(ctd.MultipassId); + transportToMultipass.Remove(transportConnectionId); + _multpassIdLookup.Remove(ctd.MultipassId); +#if DEVELOPMENT + //Remove packets held for connection from latency simulator. + base.NetworkManager.TransportManager.LatencySimulator.RemovePendingForConnection(ctd.MultipassId); +#endif + + //Update args to use multipassId before invoking. + connectionStateArgs.ConnectionId = ctd.MultipassId; + OnRemoteConnectionState?.Invoke(connectionStateArgs); + } + } + #endregion + + #region Iterating. + /// + /// Processes data received by the socket. + /// + /// True to process data received on the server. + public override void IterateIncoming(bool server) + { + foreach (Transport t in _transports) + t.IterateIncoming(server); + } + + /// + /// Processes data to be sent by the socket. + /// + /// True to process data received on the server. + public override void IterateOutgoing(bool server) + { + foreach (Transport t in _transports) + t.IterateOutgoing(server); + } + #endregion + + #region ReceivedData. + /// + /// Called when client receives data. + /// + public override event Action OnClientReceivedData; + /// + /// Handles a ClientReceivedDataArgs. + /// + /// + private void Multipass_OnClientReceivedData(ClientReceivedDataArgs receivedDataArgs) + { + OnClientReceivedData?.Invoke(receivedDataArgs); + } + /// + /// Called when server receives data. + /// + public override event Action OnServerReceivedData; + /// + /// Handles a ClientReceivedDataArgs. + /// + /// + private void Multipass_OnServerReceivedData(ServerReceivedDataArgs receivedDataArgs) + { + ClientTransportData ctd = GetDataFromTransportId(receivedDataArgs.TransportIndex, receivedDataArgs.ConnectionId); + if (ctd.Equals(INVALID_CLIENTTRANSPORTDATA)) + return; + + receivedDataArgs.ConnectionId = ctd.MultipassId; + OnServerReceivedData?.Invoke(receivedDataArgs); + } + #endregion + + #region Sending. + /// + /// Sends to the server on ClientTransport. + /// + /// Channel to use. + /// /// Data to send. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void SendToServer(byte channelId, ArraySegment segment) + { + if (ClientTransport != null) + ClientTransport.SendToServer(channelId, segment); + } + /// + /// Sends data to a client. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void SendToClient(byte channelId, ArraySegment segment, int multipassId) + { + ClientTransportData ctd = GetDataFromMultipassId(multipassId); + if (ctd.Equals(INVALID_CLIENTTRANSPORTDATA)) + return; + + _transports[ctd.TransportIndex].SendToClient(channelId, segment, ctd.TransportId); + } + /// + /// Sends data to a client. + /// + /// TransportIndex the client is using. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendToClient(byte channelId, ArraySegment segment, int transportId, int transportIndex) + { + _transports[transportIndex].SendToClient(channelId, segment, transportId); + } + #endregion + + #region Configuration. + /// + /// Returns if GlobalServerActions is true and if not logs an error. + /// + /// + private bool UseGlobalServerActionsWithError(string methodText) + { + if (!GlobalServerActions) + { + base.NetworkManager.LogError($"Method {methodText} is not supported while GlobalServerActions is false."); + return false; + } + else + { + return true; + } + } + + /// + /// Returns if ClientTransport is set and if not logs an error. + /// + /// + /// + private bool IsClientTransportSetWithError(string methodText) + { + if (ClientTransport == null) + { + base.NetworkManager.LogError($"ClientTransport is not set. Use SetClientTransport before calling {methodText}."); + return false; + } + else + { + return true; + } + } + /// + /// Populates the availableIds collection. + /// + /// True if at least 1 Id was added. + private bool CreateAvailableIds(bool reset) + { + if (reset) + { + _lastAvailableMultipassId = 0; + _availableMultipassIds.Clear(); + } + //Add in blocks of 1000. + int added = 0; + while ((_lastAvailableMultipassId <= NetworkConnection.MAXIMUM_CLIENTID_WITHOUT_SIMULATED_VALUE) + && (added < 1000)) + { + added++; + _availableMultipassIds.Enqueue(_lastAvailableMultipassId); + _lastAvailableMultipassId++; + } + + return (added > 0); + } + + /// + /// Sets the client transport to the first of type. + /// + /// + public void SetClientTransport() + { + int index = -1; + for (int i = 0; i < _transports.Count; i++) + { + if (_transports[i].GetType() == typeof(T)) + { + index = i; + break; + } + } + + SetClientTransport(index); + } + + /// + /// Sets the client transport to the first of type T. + /// + /// + public void SetClientTransport(Type type) + { + int index = -1; + for (int i = 0; i < _transports.Count; i++) + { + if (_transports[i].GetType() == type) + { + index = i; + break; + } + } + + SetClientTransport(index); + } + /// + /// Sets the client transport to the matching reference of transport. + /// + /// + public void SetClientTransport(Transport transport) + { + int index = -1; + for (int i = 0; i < _transports.Count; i++) + { + if (_transports[i] == transport) + { + index = i; + break; + } + } + + SetClientTransport(index); + } + /// + /// Sets the client transport to the transport on index. + /// + /// + public void SetClientTransport(int index) + { + if (!IndexInRange(index, true)) + return; + + ClientTransport = _transports[index]; + } + /// + /// Gets the Transport on index. + /// + /// + /// + public Transport GetTransport(int index) + { + if (!IndexInRange(index, true)) + return null; + + return _transports[index]; + } + /// + /// Gets the Transport on of type T. + /// + /// + /// + public T GetTransport() + { + foreach (Transport t in _transports) + { + if (t.GetType() == typeof(T)) + return (T)(object)t; + } + + return default(T); + } + /// + /// Returns if the transport for connectionId is a local transport. + /// While true several security checks are disabled. + /// + public override bool IsLocalTransport(int multipassId) + { + ClientTransportData ctd = GetDataFromMultipassId(multipassId); + if (ctd.Equals(INVALID_CLIENTTRANSPORTDATA)) + return false; + + return _transports[ctd.TransportIndex].IsLocalTransport(ctd.TransportId); + } + + /// + /// Returns the maximum number of clients allowed to connect to the server. If the transport does not support this method the value -1 is returned. + /// This method is not supported. Use GetMaximumClients(transportIndex) instead. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetMaximumClients() + { + base.NetworkManager.LogError($"This method is not supported. Use GetMaximumClients(transportIndex) instead."); + return -1; + } + /// + /// Returns the maximum number of clients allowed to connect to the server. If the transport does not support this method the value -1 is returned. + /// The first transport is used. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int GetMaximumClients(int transportIndex) + { + if (!IndexInRange(transportIndex, true)) + return -1; + + return _transports[transportIndex].GetMaximumClients(); + } + /// + /// Sets maximum number of clients allowed to connect to the server. If applied at runtime and clients exceed this value existing clients will stay connected but new clients may not connect. + /// This sets the value for every transport. + /// + /// + public override void SetMaximumClients(int value) + { + foreach (Transport t in _transports) + t.SetMaximumClients(value); + } + /// + /// Sets maximum number of clients allowed to connect to the server. If applied at runtime and clients exceed this value existing clients will stay connected but new clients may not connect. + /// This sets the value to the transport on index. + /// + /// + public void SetMaximumClients(int value, int transportIndex) + { + if (!IndexInRange(transportIndex, true)) + return; + + _transports[transportIndex].SetMaximumClients(value); + } + /// + /// Sets which address the client will connect to. + /// This will set the address for every transport. + /// + /// + public override void SetClientAddress(string address) + { + foreach (Transport t in _transports) + t.SetClientAddress(address); + } + /// + /// Sets which address the client will connect to. + /// + /// + /// Transport index to set for. + public void SetClientAddress(string address, int index) + { + if (!IndexInRange(index, true)) + return; + + _transports[index].SetClientAddress(address); + } + + /// + /// Sets which address the server will bind to. + /// This will set the address for every transport. + /// + public override void SetServerBindAddress(string address, IPAddressType addressType) + { + foreach (Transport t in _transports) + t.SetServerBindAddress(address, addressType); + } + + /// Sets which address the server will bind to. + /// This is called on the transport of index. + /// + /// + public void SetServerBindAddress(string address, IPAddressType addressType, int index) + { + if (!IndexInRange(index, true)) + return; + + _transports[index].SetServerBindAddress(address, addressType); + } + /// + /// Sets which port to use. + /// This will set the port for every transport. + /// + public override void SetPort(ushort port) + { + foreach (Transport t in _transports) + t.SetPort(port); + } + /// + /// Sets which port to use on transport of index. + /// + public void SetPort(ushort port, int index) + { + if (!IndexInRange(index, true)) + return; + + _transports[index].SetPort(port); + } + #endregion + + #region Start and stop. + /// + /// Starts the local server or client using configured settings on the first transport. + /// + /// True to start server. + public override bool StartConnection(bool server) + { + //Server. + if (server) + { + if (!UseGlobalServerActionsWithError("StartConnection")) + return false; + + bool success = true; + for (int i = 0; i < _transports.Count; i++) + { + if (!StartConnection(true, i)) + success = false; + } + + return success; + } + //Client. + else + { + if (IsClientTransportSetWithError("StartConnection")) + return StartConnection(false, ClientTransport.Index); + else + return false; + } + } + + /// + /// Starts the local server or client using configured settings on transport of index. + /// + /// True to start server. + public bool StartConnection(bool server, int index) + { + if (server) + { + return StartServer(index); + } + else + { + if (IsClientTransportSetWithError("StartConnection")) + return StartClient(); + else + return false; + } + } + + + /// + /// Stops the local server or client on the first transport. + /// + /// True to stop server. + public override bool StopConnection(bool server) + { + //Server + if (server) + { + if (!UseGlobalServerActionsWithError("StopConnection")) + return false; + + bool success = true; + for (int i = 0; i < _transports.Count; i++) + { + if (!StopConnection(true, i)) + success = false; + } + + return success; + } + //Client. + else + { + if (IsClientTransportSetWithError("StopConnection")) + return StopConnection(false, ClientTransport.Index); + else + return false; + } + } + /// + /// Stops the local server or client on transport of index. + /// + /// True to stop server. + public bool StopConnection(bool server, int index) + { + if (server) + { + return StopServer(index); + } + else + { + if (IsClientTransportSetWithError("StopConnection")) + return StopClient(); + else + return false; + } + } + + /// + /// Stops a remote client from the server, disconnecting the client. + /// + /// ConnectionId of the client to disconnect. + /// True to abrutly stp the client socket without waiting socket thread. + public override bool StopConnection(int connectionId, bool immediately) + { + return StopClient(connectionId, immediately); + } + + /// + /// Stops the server connection on transportIndex. + /// + /// True to send a disconnect message to connections before stopping them. + /// Index of transport to stop on. + public bool StopServerConnection(bool sendDisconnectMessage, int transportIndex) + { + if (sendDisconnectMessage) + { + //Get dictionary for transportIndex. + Dictionary dict = _transportIdLookup[transportIndex]; + //Create an array containing all multipass Ids for transportIndex. + int[] multipassIds = new int[dict.Count]; + int index = 0; + foreach (ClientTransportData item in dict.Values) + multipassIds[index++] = item.MultipassId; + //Tell serve manager to write disconnect for those ids. + base.NetworkManager.ServerManager.SendDisconnectMessages(multipassIds); + //Iterate outgoing on transport which is being stopped. + _transports[transportIndex].IterateOutgoing(true); + } + + return StopConnection(true, transportIndex); + } + + /// + /// Stops both client and server on all transports. + /// + public override void Shutdown() + { + foreach (Transport t in _transports) + { + //Stops client then server connections. + t.StopConnection(false); + t.StopConnection(true); + } + } + + #region Privates. + /// + /// Starts server of transport on index. + /// + /// True if there were no blocks. A true response does not promise a socket will or has connected. + private bool StartServer(int index) + { + if (!IndexInRange(index, true)) + return false; + + return _transports[index].StartConnection(true); + } + + /// + /// Stops server of transport on index. + /// + private bool StopServer(int index) + { + if (!IndexInRange(index, true)) + return false; + + return _transports[index].StopConnection(true); + } + + /// + /// Starts the client on ClientTransport. + /// + /// + /// True if there were no blocks. A true response does not promise a socket will or has connected. + private bool StartClient() + { + return ClientTransport.StartConnection(false); + } + + /// + /// Stops the client on ClientTransport. + /// + private bool StopClient() + { + return ClientTransport.StopConnection(false); + } + + /// + /// Stops a remote client on the server. + /// + /// + /// True to abrutly stp the client socket without waiting socket thread. + private bool StopClient(int multipassId, bool immediately) + { + ClientTransportData ctd = GetDataFromMultipassId(multipassId); + if (ctd.Equals(INVALID_CLIENTTRANSPORTDATA)) + return false; + + return _transports[ctd.TransportIndex].StopConnection(ctd.TransportId, immediately); + } + #endregion + #endregion + + #region Channels. + /// + /// Gets the MTU for a channel on the first transport. This should take header size into consideration. + /// For example, if MTU is 1200 and a packet header for this channel is 10 in size, this method should return 1190. + /// + /// + /// + public override int GetMTU(byte channel) + { + return GetMTU(channel, 0); + } + /// + /// Gets the MTU for a channel of transport on index. This should take header size into consideration. + /// For example, if MTU is 1200 and a packet header for this channel is 10 in size, this method should return 1190. + /// + /// + /// + public int GetMTU(byte channel, int index) + { + if (!IndexInRange(index, true)) + return -1; + + return _transports[index].GetMTU(channel); + } + + #endregion + + #region Misc. + /// + /// Returns if an index is within range of the Transports collection. + /// + private bool IndexInRange(int index, bool error) + { + if (index >= _transports.Count || index < 0) + { + if (error) + base.NetworkManager.LogError($"Index of {index} is out of Transports range."); + return false; + } + else + { + return true; + } + } + + //perf change events to direct calls in transports. + public override void HandleServerConnectionState(ServerConnectionStateArgs connectionStateArgs) { } + public override void HandleRemoteConnectionState(RemoteConnectionStateArgs connectionStateArgs) { } + public override void HandleClientReceivedDataArgs(ClientReceivedDataArgs receivedDataArgs) { } + public override void HandleServerReceivedDataArgs(ServerReceivedDataArgs receivedDataArgs) { } + public override void HandleClientConnectionState(ClientConnectionStateArgs connectionStateArgs) { } + #endregion + + } +} + + + +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs index cc1a4d2..8770339 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ClientSocket.cs @@ -105,7 +105,7 @@ namespace FishNet.Transporting.Tugboat.Client listener.PeerConnectedEvent += Listener_PeerConnectedEvent; listener.PeerDisconnectedEvent += Listener_PeerDisconnectedEvent; - base.NetManager = new NetManager(listener, _packetLayer); + base.NetManager = new NetManager(listener, _packetLayer, false); base.NetManager.DontRoute = _dontRoute; base.NetManager.MtuOverride = (_mtu + NetConstants.FragmentedHeaderTotalSize); diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs index f926016..a2f156b 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/Core/ServerSocket.cs @@ -147,7 +147,7 @@ namespace FishNet.Transporting.Tugboat.Server listener.NetworkReceiveEvent += Listener_NetworkReceiveEvent; listener.PeerDisconnectedEvent += Listener_PeerDisconnectedEvent; - base.NetManager = new NetManager(listener, _packetLayer); + base.NetManager = new NetManager(listener, _packetLayer, false); base.NetManager.DontRoute = _dontRoute; base.NetManager.MtuOverride = (_mtu + NetConstants.FragmentedHeaderTotalSize); @@ -200,11 +200,8 @@ namespace FishNet.Transporting.Tugboat.Server StopConnection(); return; } - if (!_enableIPv6) - { - base.NetManager.IPv6Mode = IPv6Mode.Disabled; - } + base.NetManager.IPv6Enabled = _enableIPv6; bool startResult = base.NetManager.Start(ipv4, ipv6, _port); //If started succcessfully. if (startResult) @@ -263,7 +260,7 @@ namespace FishNet.Transporting.Tugboat.Server return string.Empty; } - return peer.EndPoint.Address.ToString(); + return peer.Address.ToString(); } /// @@ -540,7 +537,7 @@ namespace FishNet.Transporting.Tugboat.Server /// internal int GetMaximumClients() { - return _maximumClients; + return Math.Min(_maximumClients, NetworkConnection.MAXIMUM_CLIENTID_WITHOUT_SIMULATED_VALUE); } /// diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs index 261839d..b70c436 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/BaseChannel.cs @@ -1,4 +1,4 @@ -using System.Collections.Concurrent; +using System.Collections.Generic; using System.Threading; namespace LiteNetLib @@ -6,7 +6,7 @@ namespace LiteNetLib internal abstract class BaseChannel { protected readonly NetPeer Peer; - protected readonly ConcurrentQueue OutgoingQueue; + protected readonly Queue OutgoingQueue = new Queue(NetConstants.DefaultWindowSize); private int _isAddedToPeerChannelSendQueue; public int PacketsInQueue => OutgoingQueue.Count; @@ -14,12 +14,14 @@ namespace LiteNetLib protected BaseChannel(NetPeer peer) { Peer = peer; - OutgoingQueue = new ConcurrentQueue(); } public void AddToQueue(NetPacket packet) { - OutgoingQueue.Enqueue(packet); + lock (OutgoingQueue) + { + OutgoingQueue.Enqueue(packet); + } AddToPeerChannelSendQueue(); } diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs index 3ee97d6..dc07fe1 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/Crc32cLayer.cs @@ -11,7 +11,7 @@ namespace LiteNetLib.Layers } - public override void ProcessInboundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length) + public override void ProcessInboundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int length) { if (length < NetConstants.HeaderSize + CRC32C.ChecksumSize) { @@ -22,7 +22,7 @@ namespace LiteNetLib.Layers } int checksumPoint = length - CRC32C.ChecksumSize; - if (CRC32C.Compute(data, offset, checksumPoint) != BitConverter.ToUInt32(data, checksumPoint)) + if (CRC32C.Compute(data, 0, checksumPoint) != BitConverter.ToUInt32(data, checksumPoint)) { NetDebug.Write("[NM] DataReceived checksum: bad!"); //Set length to 0 to have netManager drop the packet. diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs index b3d9b3a..f2e4c88 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/PacketLayerBase.cs @@ -11,7 +11,7 @@ namespace LiteNetLib.Layers ExtraPacketSizeForLayer = extraPacketSizeForLayer; } - public abstract void ProcessInboundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length); + public abstract void ProcessInboundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int length); public abstract void ProcessOutBoundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length); } } diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs index 9b67196..a3a130b 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Layers/XorEncryptLayer.cs @@ -35,14 +35,13 @@ namespace LiteNetLib.Layers Buffer.BlockCopy(key, 0, _byteKey, 0, key.Length); } - public override void ProcessInboundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int offset, ref int length) + public override void ProcessInboundPacket(ref IPEndPoint endPoint, ref byte[] data, ref int length) { if (_byteKey == null) return; - var cur = offset; - for (var i = 0; i < length; i++, cur++) + for (int i = 0; i < length; i++) { - data[cur] = (byte)(data[cur] ^ _byteKey[i % _byteKey.Length]); + data[i] = (byte)(data[i] ^ _byteKey[i % _byteKey.Length]); } } @@ -50,8 +49,8 @@ namespace LiteNetLib.Layers { if (_byteKey == null) return; - var cur = offset; - for (var i = 0; i < length; i++, cur++) + int cur = offset; + for (int i = 0; i < length; i++, cur++) { data[cur] = (byte)(data[cur] ^ _byteKey[i % _byteKey.Length]); } diff --git a/Assets/FishNet/Demos/Prediction 2/CharacterController/PredictionV2_CC.unity.meta b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta similarity index 74% rename from Assets/FishNet/Demos/Prediction 2/CharacterController/PredictionV2_CC.unity.meta rename to Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta index 9aeb488..0ad2686 100644 --- a/Assets/FishNet/Demos/Prediction 2/CharacterController/PredictionV2_CC.unity.meta +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/LiteNetLib.csproj.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 941f6f8cbac7e9d418ffc6f22ee9359f +guid: 1ec83424c5410b04aab06dddca60e7f6 DefaultImporter: externalObjects: {} userData: diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs index bab2fca..fdd156f 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NatPunchModule.cs @@ -1,5 +1,7 @@ using System.Collections.Concurrent; +using System.Diagnostics.CodeAnalysis; using System.Net; +using System.Net.Sockets; using LiteNetLib.Utils; namespace LiteNetLib @@ -58,21 +60,21 @@ namespace LiteNetLib class NatIntroduceRequestPacket { - public IPEndPoint Internal { get; set; } - public string Token { get; set; } + public IPEndPoint Internal { [Preserve] get; [Preserve] set; } + public string Token { [Preserve] get; [Preserve] set; } } class NatIntroduceResponsePacket { - public IPEndPoint Internal { get; set; } - public IPEndPoint External { get; set; } - public string Token { get; set; } + public IPEndPoint Internal { [Preserve] get; [Preserve] set; } + public IPEndPoint External { [Preserve] get; [Preserve] set; } + public string Token { [Preserve] get; [Preserve] set; } } class NatPunchPacket { - public string Token { get; set; } - public bool IsExternal { get; set; } + public string Token { [Preserve] get; [Preserve] set; } + public bool IsExternal { [Preserve] get; [Preserve] set; } } private readonly NetManager _socket; @@ -111,7 +113,11 @@ namespace LiteNetLib _natPunchListener = listener; } - private void Send(T packet, IPEndPoint target) where T : class, new() + private void Send< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>(T packet, IPEndPoint target) where T : class, new() { _cacheWriter.Reset(); _cacheWriter.Put((byte)PacketProperty.NatMessage); @@ -173,7 +179,7 @@ namespace LiteNetLib { //prepare outgoing data string networkIp = NetUtils.GetLocalIp(LocalAddrType.IPv4); - if (string.IsNullOrEmpty(networkIp)) + if (string.IsNullOrEmpty(networkIp) || masterServerEndPoint.AddressFamily == AddressFamily.InterNetworkV6) { networkIp = NetUtils.GetLocalIp(LocalAddrType.IPv6); } @@ -216,7 +222,7 @@ namespace LiteNetLib // send internal punch var punchPacket = new NatPunchPacket {Token = req.Token}; Send(punchPacket, req.Internal); - NetDebug.Write(NetLogLevel.Trace, "[NAT] internal punch sent to " + req.Internal); + NetDebug.Write(NetLogLevel.Trace, $"[NAT] internal punch sent to {req.Internal}"); // hack for some routers _socket.Ttl = 2; @@ -226,15 +232,14 @@ namespace LiteNetLib _socket.Ttl = NetConstants.SocketTTL; punchPacket.IsExternal = true; Send(punchPacket, req.External); - NetDebug.Write(NetLogLevel.Trace, "[NAT] external punch sent to " + req.External); + NetDebug.Write(NetLogLevel.Trace, $"[NAT] external punch sent to {req.External}"); } //We got punch and can connect private void OnNatPunch(NatPunchPacket req, IPEndPoint senderEndPoint) { //Read info - NetDebug.Write(NetLogLevel.Trace, "[NAT] punch received from {0} - additional info: {1}", - senderEndPoint, req.Token); + NetDebug.Write(NetLogLevel.Trace, $"[NAT] punch received from {senderEndPoint} - additional info: {req.Token}"); //Release punch success to client; enabling him to Connect() to Sender if token is ok if(UnsyncedEvents) diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs index fc846c8..e2959cb 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NativeSocket.cs @@ -7,111 +7,9 @@ using System.Runtime.InteropServices; namespace LiteNetLib { - internal readonly struct NativeAddr : IEquatable - { - //common parts - private readonly long _part1; //family, port, etc - private readonly long _part2; - //ipv6 parts - private readonly long _part3; - private readonly int _part4; - - private readonly int _hash; - - public NativeAddr(byte[] address, int len) - { - _part1 = BitConverter.ToInt64(address, 0); - _part2 = BitConverter.ToInt64(address, 8); - if (len > 16) - { - _part3 = BitConverter.ToInt64(address, 16); - _part4 = BitConverter.ToInt32(address, 24); - } - else - { - _part3 = 0; - _part4 = 0; - } - _hash = (int)(_part1 >> 32) ^ (int)_part1 ^ - (int)(_part2 >> 32) ^ (int)_part2 ^ - (int)(_part3 >> 32) ^ (int)_part3 ^ - _part4; - } - - public override int GetHashCode() - { - return _hash; - } - - public bool Equals(NativeAddr other) - { - return _part1 == other._part1 && - _part2 == other._part2 && - _part3 == other._part3 && - _part4 == other._part4; - } - - public override bool Equals(object obj) - { - return obj is NativeAddr other && Equals(other); - } - - public static bool operator ==(NativeAddr left, NativeAddr right) - { - return left.Equals(right); - } - - public static bool operator !=(NativeAddr left, NativeAddr right) - { - return !left.Equals(right); - } - } - - internal class NativeEndPoint : IPEndPoint - { - public readonly byte[] NativeAddress; - - public NativeEndPoint(byte[] address) : base(IPAddress.Any, 0) - { - NativeAddress = new byte[address.Length]; - Buffer.BlockCopy(address, 0, NativeAddress, 0, address.Length); - - short family = (short)((address[1] << 8) | address[0]); - Port =(ushort)((address[2] << 8) | address[3]); - - if ((NativeSocket.UnixMode && family == NativeSocket.AF_INET6) || (!NativeSocket.UnixMode && (AddressFamily)family == AddressFamily.InterNetworkV6)) - { - uint scope = unchecked((uint)( - (address[27] << 24) + - (address[26] << 16) + - (address[25] << 8) + - (address[24]))); -#if NETCOREAPP || NETSTANDARD2_1 || NETSTANDARD2_1_OR_GREATER - Address = new IPAddress(new ReadOnlySpan(address, 8, 16), scope); -#else - byte[] addrBuffer = new byte[16]; - Buffer.BlockCopy(address, 8, addrBuffer, 0, 16); - Address = new IPAddress(addrBuffer, scope); -#endif - } - else //IPv4 - { - long ipv4Addr = unchecked((uint)((address[4] & 0x000000FF) | - (address[5] << 8 & 0x0000FF00) | - (address[6] << 16 & 0x00FF0000) | - (address[7] << 24))); - Address = new IPAddress(ipv4Addr); - } - } - } - internal static class NativeSocket { - static -#if LITENETLIB_UNSAFE - unsafe -#endif - class WinSock + static unsafe class WinSock { private const string LibName = "ws2_32.dll"; @@ -127,22 +25,14 @@ namespace LiteNetLib [DllImport(LibName, SetLastError = true)] internal static extern int sendto( IntPtr socketHandle, -#if LITENETLIB_UNSAFE byte* pinnedBuffer, -#else - [In] byte[] pinnedBuffer, -#endif [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, [In] int socketAddressSize); } - static -#if LITENETLIB_UNSAFE - unsafe -#endif - class UnixSock + static unsafe class UnixSock { private const string LibName = "libc"; @@ -158,11 +48,7 @@ namespace LiteNetLib [DllImport(LibName, SetLastError = true)] internal static extern int sendto( IntPtr socketHandle, -#if LITENETLIB_UNSAFE byte* pinnedBuffer, -#else - [In] byte[] pinnedBuffer, -#endif [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, @@ -250,17 +136,9 @@ namespace LiteNetLib } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public -#if LITENETLIB_UNSAFE - unsafe -#endif - static int SendTo( + public static unsafe int SendTo( IntPtr socketHandle, -#if LITENETLIB_UNSAFE byte* pinnedBuffer, -#else - byte[] pinnedBuffer, -#endif int len, byte[] socketAddress, int socketAddressSize) diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs index a326c0d..44cb6f3 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetDebug.cs @@ -61,32 +61,32 @@ namespace LiteNetLib } [Conditional("DEBUG_MESSAGES")] - internal static void Write(string str, params object[] args) + internal static void Write(string str) { - WriteLogic(NetLogLevel.Trace, str, args); + WriteLogic(NetLogLevel.Trace, str); } [Conditional("DEBUG_MESSAGES")] - internal static void Write(NetLogLevel level, string str, params object[] args) + internal static void Write(NetLogLevel level, string str) { - WriteLogic(level, str, args); + WriteLogic(level, str); } [Conditional("DEBUG_MESSAGES"), Conditional("DEBUG")] - internal static void WriteForce(string str, params object[] args) + internal static void WriteForce(string str) { - WriteLogic(NetLogLevel.Trace, str, args); + WriteLogic(NetLogLevel.Trace, str); } [Conditional("DEBUG_MESSAGES"), Conditional("DEBUG")] - internal static void WriteForce(NetLogLevel level, string str, params object[] args) + internal static void WriteForce(NetLogLevel level, string str) { - WriteLogic(level, str, args); + WriteLogic(level, str); } - internal static void WriteError(string str, params object[] args) + internal static void WriteError(string str) { - WriteLogic(NetLogLevel.Error, str, args); + WriteLogic(NetLogLevel.Error, str); } } } diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.HashSet.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.HashSet.cs new file mode 100644 index 0000000..72181ac --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.HashSet.cs @@ -0,0 +1,310 @@ +using System; +using System.Net; +using System.Threading; + +namespace LiteNetLib +{ + //minimal hashset class from dotnet with some optimizations + public partial class NetManager + { + private const int MaxPrimeArrayLength = 0x7FFFFFC3; + private const int HashPrime = 101; + private const int Lower31BitMask = 0x7FFFFFFF; + private static readonly int[] Primes = + { + 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, + 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, + 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, + 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, + 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 + }; + + private static int HashSetGetPrime(int min) + { + foreach (int prime in Primes) + { + if (prime >= min) + return prime; + } + + // Outside of our predefined table. Compute the hard way. + for (int i = (min | 1); i < int.MaxValue; i += 2) + { + if (IsPrime(i) && ((i - 1) % HashPrime != 0)) + return i; + } + return min; + + bool IsPrime(int candidate) + { + if ((candidate & 1) != 0) + { + int limit = (int)Math.Sqrt(candidate); + for (int divisor = 3; divisor <= limit; divisor += 2) + { + if (candidate % divisor == 0) + return false; + } + return true; + } + return candidate == 2; + } + } + + private struct Slot + { + internal int HashCode; + internal int Next; + internal NetPeer Value; + } + + private int[] _buckets; + private Slot[] _slots; + private int _count; + private int _lastIndex; + private int _freeList = -1; + private NetPeer[] _peersArray = new NetPeer[32]; + private readonly ReaderWriterLockSlim _peersLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); + private volatile NetPeer _headPeer; + + private void ClearPeerSet() + { + _peersLock.EnterWriteLock(); + _headPeer = null; + if (_lastIndex > 0) + { + Array.Clear(_slots, 0, _lastIndex); + Array.Clear(_buckets, 0, _buckets.Length); + _lastIndex = 0; + _count = 0; + _freeList = -1; + } + _peersArray = new NetPeer[32]; + _peersLock.ExitWriteLock(); + } + + private bool ContainsPeer(NetPeer item) + { + if (_buckets != null) + { + int hashCode = item.GetHashCode() & Lower31BitMask; + for (int i = _buckets[hashCode % _buckets.Length] - 1; i >= 0; i = _slots[i].Next) + { + if (_slots[i].HashCode == hashCode && _slots[i].Value.Equals(item)) + return true; + } + } + return false; + } + + /// + /// Gets peer by peer id + /// + /// id of peer + /// Peer if peer with id exist, otherwise null + public NetPeer GetPeerById(int id) + { + return id >= 0 && id < _peersArray.Length ? _peersArray[id] : null; + } + + /// + /// Gets peer by peer id + /// + /// id of peer + /// resulting peer + /// True if peer with id exist, otherwise false + public bool TryGetPeerById(int id, out NetPeer peer) + { + peer = GetPeerById(id); + return peer != null; + } + + private void AddPeer(NetPeer peer) + { + _peersLock.EnterWriteLock(); + if (_headPeer != null) + { + peer.NextPeer = _headPeer; + _headPeer.PrevPeer = peer; + } + _headPeer = peer; + AddPeerToSet(peer); + if (peer.Id >= _peersArray.Length) + { + int newSize = _peersArray.Length * 2; + while (peer.Id >= newSize) + newSize *= 2; + Array.Resize(ref _peersArray, newSize); + } + _peersArray[peer.Id] = peer; + _peersLock.ExitWriteLock(); + } + + private void RemovePeer(NetPeer peer) + { + _peersLock.EnterWriteLock(); + RemovePeerInternal(peer); + _peersLock.ExitWriteLock(); + } + + private void RemovePeerInternal(NetPeer peer) + { + if (!RemovePeerFromSet(peer)) + return; + if (peer == _headPeer) + _headPeer = peer.NextPeer; + + if (peer.PrevPeer != null) + peer.PrevPeer.NextPeer = peer.NextPeer; + if (peer.NextPeer != null) + peer.NextPeer.PrevPeer = peer.PrevPeer; + peer.PrevPeer = null; + + _peersArray[peer.Id] = null; + _peerIds.Enqueue(peer.Id); + } + + private bool RemovePeerFromSet(NetPeer peer) + { + if (_buckets == null) + return false; + int hashCode = peer.GetHashCode() & Lower31BitMask; + int bucket = hashCode % _buckets.Length; + int last = -1; + for (int i = _buckets[bucket] - 1; i >= 0; last = i, i = _slots[i].Next) + { + if (_slots[i].HashCode == hashCode && _slots[i].Value.Equals(peer)) + { + if (last < 0) + _buckets[bucket] = _slots[i].Next + 1; + else + _slots[last].Next = _slots[i].Next; + _slots[i].HashCode = -1; + _slots[i].Value = null; + _slots[i].Next = _freeList; + + _count--; + if (_count == 0) + { + _lastIndex = 0; + _freeList = -1; + } + else + { + _freeList = i; + } + return true; + } + } + return false; + } + + private bool TryGetPeer(IPEndPoint endPoint, out NetPeer actualValue) + { + if (_buckets != null) + { +#if NET8_0_OR_GREATER + //can be NetPeer or IPEndPoint + int hashCode = (UseNativeSockets ? endPoint.GetHashCode() : endPoint.Serialize().GetHashCode()) & Lower31BitMask; +#else + int hashCode = endPoint.GetHashCode() & Lower31BitMask; +#endif + _peersLock.EnterReadLock(); + for (int i = _buckets[hashCode % _buckets.Length] - 1; i >= 0; i = _slots[i].Next) + { + if (_slots[i].HashCode == hashCode && _slots[i].Value.Equals(endPoint)) + { + actualValue = _slots[i].Value; + _peersLock.ExitReadLock(); + return true; + } + } + _peersLock.ExitReadLock(); + } + actualValue = null; + return false; + } + + //only used for NET8 + private bool TryGetPeer(SocketAddress saddr, out NetPeer actualValue) + { + if (_buckets != null) + { + int hashCode = saddr.GetHashCode() & Lower31BitMask; + _peersLock.EnterReadLock(); + for (int i = _buckets[hashCode % _buckets.Length] - 1; i >= 0; i = _slots[i].Next) + { + if (_slots[i].HashCode == hashCode && _slots[i].Value.Serialize().Equals(saddr)) + { + actualValue = _slots[i].Value; + _peersLock.ExitReadLock(); + return true; + } + } + _peersLock.ExitReadLock(); + } + actualValue = null; + return false; + } + + private bool AddPeerToSet(NetPeer value) + { + if (_buckets == null) + { + int size = HashSetGetPrime(0); + _buckets = new int[size]; + _slots = new Slot[size]; + } + + int hashCode = value.GetHashCode() & Lower31BitMask; + int bucket = hashCode % _buckets.Length; + for (int i = _buckets[hashCode % _buckets.Length] - 1; i >= 0; i = _slots[i].Next) + { + if (_slots[i].HashCode == hashCode && _slots[i].Value.Equals(value)) + return false; + } + + int index; + if (_freeList >= 0) + { + index = _freeList; + _freeList = _slots[index].Next; + } + else + { + if (_lastIndex == _slots.Length) + { + //increase capacity + int newSize = 2 * _count; + newSize = (uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > _count + ? MaxPrimeArrayLength + : HashSetGetPrime(newSize); + + // Able to increase capacity; copy elements to larger array and rehash + Slot[] newSlots = new Slot[newSize]; + Array.Copy(_slots, 0, newSlots, 0, _lastIndex); + _buckets = new int[newSize]; + for (int i = 0; i < _lastIndex; i++) + { + int b = newSlots[i].HashCode % newSize; + newSlots[i].Next = _buckets[b] - 1; + _buckets[b] = i + 1; + } + _slots = newSlots; + // this will change during resize + bucket = hashCode % _buckets.Length; + } + index = _lastIndex; + _lastIndex++; + } + _slots[index].HashCode = hashCode; + _slots[index].Value = value; + _slots[index].Next = _buckets[bucket] - 1; + _buckets[bucket] = index + 1; + _count++; + + return true; + } + } + +} diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.HashSet.cs.meta b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.HashSet.cs.meta new file mode 100644 index 0000000..68febb9 --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.HashSet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3dad2c47fd51d14fbb281bf3cb231e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs index b2ae5e5..0831220 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.PacketPool.cs @@ -1,5 +1,4 @@ using System; -using System.Threading; namespace LiteNetLib { @@ -42,6 +41,9 @@ namespace LiteNetLib internal NetPacket PoolGetPacket(int size) { + if (size > NetConstants.MaxPacketSize) + return new NetPacket(size); + NetPacket packet; lock (_poolLock) { diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs index e0d75e3..be64d54 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.Socket.cs @@ -1,3 +1,6 @@ +#if UNITY_2018_3_OR_NEWER +#define UNITY_SOCKET_FIX +#endif using System.Runtime.InteropServices; using System; using System.Collections.Generic; @@ -8,49 +11,31 @@ using LiteNetLib.Utils; namespace LiteNetLib { - public partial class NetManager { - public bool SocketActive(bool ipv4) - { - if (ipv4) - { - if (_udpSocketv4 != null) - return _udpSocketv4.Connected; - return false; - } - else - { - if (_udpSocketv6 != null) - return _udpSocketv6.Connected; - return false; - } - } - private const int ReceivePollingTime = 500000; //0.5 second private Socket _udpSocketv4; private Socket _udpSocketv6; - private Thread _threadv4; - private Thread _threadv6; + private Thread _receiveThread; private IPEndPoint _bufferEndPointv4; private IPEndPoint _bufferEndPointv6; - -#if !LITENETLIB_UNSAFE - [ThreadStatic] private static byte[] _sendToBuffer; +#if UNITY_SOCKET_FIX + private PausedSocketFix _pausedSocketFix; + private bool _useSocketFix; #endif - [ThreadStatic] private static byte[] _endPointBuffer; - private readonly Dictionary _nativeAddrMap = new Dictionary(); +#if NET8_0_OR_GREATER + private readonly SocketAddress _sockAddrCacheV4 = new SocketAddress(AddressFamily.InterNetwork); + private readonly SocketAddress _sockAddrCacheV6 = new SocketAddress(AddressFamily.InterNetworkV6); +#endif private const int SioUdpConnreset = -1744830452; //SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12 private static readonly IPAddress MulticastAddressV6 = IPAddress.Parse("ff02::1"); public static readonly bool IPv6Support; - /// - /// Maximum packets count that will be processed in Manual PollEvents - /// - public int MaxPacketsReceivePerUpdate = 0; + // special case in iOS (and possibly android that should be resolved in unity) + internal bool NotConnected; public short Ttl { @@ -79,38 +64,16 @@ namespace LiteNetLib IPv6Support = Socket.OSSupportsIPv6 && int.Parse(version.Remove(version.IndexOf('f')).Split('.')[2]) >= 6; #else IPv6Support = Socket.OSSupportsIPv6; -#endif - } - - private bool IsActive() - { - return IsRunning; - } - - private void RegisterEndPoint(IPEndPoint ep) - { - if (UseNativeSockets && ep is NativeEndPoint nep) - { - _nativeAddrMap.Add(new NativeAddr(nep.NativeAddress, nep.NativeAddress.Length), nep); - } - } - - private void UnregisterEndPoint(IPEndPoint ep) - { - if (UseNativeSockets && ep is NativeEndPoint nep) - { - var nativeAddr = new NativeAddr(nep.NativeAddress, nep.NativeAddress.Length); - _nativeAddrMap.Remove(nativeAddr); - } +#endif } private bool ProcessError(SocketException ex) { switch (ex.SocketErrorCode) { -#if UNITY_IOS && !UNITY_EDITOR case SocketError.NotConnected: -#endif + NotConnected = true; + return true; case SocketError.Interrupted: case SocketError.NotSocket: case SocketError.OperationAborted: @@ -119,6 +82,7 @@ namespace LiteNetLib case SocketError.MessageSize: case SocketError.TimedOut: case SocketError.NetworkReset: + case SocketError.WouldBlock: //NetDebug.Write($"[R]Ignored error: {(int)ex.SocketErrorCode} - {ex}"); break; default: @@ -129,7 +93,7 @@ namespace LiteNetLib return false; } - private void ManualReceive(Socket socket, EndPoint bufferEndPoint) + private void ManualReceive(Socket socket, EndPoint bufferEndPoint, int maxReceive) { //Reading data try @@ -137,13 +101,9 @@ namespace LiteNetLib int packetsReceived = 0; while (socket.Available > 0) { - var packet = PoolGetPacket(NetConstants.MaxPacketSize); - packet.Size = socket.ReceiveFrom(packet.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None, - ref bufferEndPoint); - //NetDebug.Write(NetLogLevel.Trace, $"[R]Received data from {bufferEndPoint}, result: {packet.Size}"); - OnMessageReceived(packet, (IPEndPoint)bufferEndPoint); + ReceiveFrom(socket, ref bufferEndPoint); packetsReceived++; - if (packetsReceived == MaxPacketsReceivePerUpdate) + if (packetsReceived == maxReceive) break; } } @@ -158,66 +118,55 @@ namespace LiteNetLib catch (Exception e) { //protects socket receive thread - NetDebug.WriteError("[NM] SocketReceiveThread error: " + e); + NetDebug.WriteError("[NM] SocketReceiveThread error: " + e ); } } - private void NativeReceiveLogic(object state) + private void NativeReceiveLogic() { - Socket socket = (Socket)state; - IntPtr socketHandle = socket.Handle; - byte[] addrBuffer = new byte[socket.AddressFamily == AddressFamily.InterNetwork - ? NativeSocket.IPv4AddrSize - : NativeSocket.IPv6AddrSize]; + IntPtr socketHandle4 = _udpSocketv4.Handle; + IntPtr socketHandle6 = _udpSocketv6?.Handle ?? IntPtr.Zero; + byte[] addrBuffer4 = new byte[NativeSocket.IPv4AddrSize]; + byte[] addrBuffer6 = new byte[NativeSocket.IPv6AddrSize]; + var tempEndPoint = new IPEndPoint(IPAddress.Any, 0); + var selectReadList = new List(2); + var socketv4 = _udpSocketv4; + var socketV6 = _udpSocketv6; + var packet = PoolGetPacket(NetConstants.MaxPacketSize); - int addrSize = addrBuffer.Length; - NetPacket packet = PoolGetPacket(NetConstants.MaxPacketSize); - - while (IsActive()) + while (IsRunning) { - //Reading data - packet.Size = NativeSocket.RecvFrom(socketHandle, packet.RawData, NetConstants.MaxPacketSize, addrBuffer, ref addrSize); - if (packet.Size == 0) - return; - if (packet.Size == -1) - { - SocketError errorCode = NativeSocket.GetSocketError(); - if (errorCode == SocketError.WouldBlock || errorCode == SocketError.TimedOut) //Linux timeout EAGAIN - continue; - if (ProcessError(new SocketException((int)errorCode))) - return; - continue; - } - - NativeAddr nativeAddr = new NativeAddr(addrBuffer, addrSize); - if (!_nativeAddrMap.TryGetValue(nativeAddr, out var endPoint)) - endPoint = new NativeEndPoint(addrBuffer); - - //All ok! - //NetDebug.WriteForce($"[R]Received data from {endPoint}, result: {packet.Size}"); - OnMessageReceived(packet, endPoint); - packet = PoolGetPacket(NetConstants.MaxPacketSize); - } - } - - private void ReceiveLogic(object state) - { - Socket socket = (Socket)state; - EndPoint bufferEndPoint = new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0); - - while (IsActive()) - { - //Reading data try { - if (socket.Available == 0 && !socket.Poll(ReceivePollingTime, SelectMode.SelectRead)) + if (socketV6 == null) + { + if (NativeReceiveFrom(socketHandle4, addrBuffer4) == false) + return; continue; - NetPacket packet = PoolGetPacket(NetConstants.MaxPacketSize); - packet.Size = socket.ReceiveFrom(packet.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None, - ref bufferEndPoint); + } + bool messageReceived = false; + if (socketv4.Available != 0 || selectReadList.Contains(socketv4)) + { + if (NativeReceiveFrom(socketHandle4, addrBuffer4) == false) + return; + messageReceived = true; + } + if (socketV6.Available != 0 || selectReadList.Contains(socketV6)) + { + if (NativeReceiveFrom(socketHandle6, addrBuffer6) == false) + return; + messageReceived = true; + } - //NetDebug.Write(NetLogLevel.Trace, $"[R]Received data from {bufferEndPoint}, result: {packet.Size}"); - OnMessageReceived(packet, (IPEndPoint)bufferEndPoint); + selectReadList.Clear(); + + if (messageReceived) + continue; + + selectReadList.Add(socketv4); + selectReadList.Add(socketV6); + + Socket.Select(selectReadList, null, null, ReceivePollingTime); } catch (SocketException ex) { @@ -237,7 +186,142 @@ namespace LiteNetLib catch (Exception e) { //protects socket receive thread - NetDebug.WriteError("[NM] SocketReceiveThread error: " + e); + NetDebug.WriteError("[NM] SocketReceiveThread error: " + e ); + } + } + + bool NativeReceiveFrom(IntPtr s, byte[] address) + { + int addrSize = address.Length; + packet.Size = NativeSocket.RecvFrom(s, packet.RawData, NetConstants.MaxPacketSize, address, ref addrSize); + if (packet.Size == 0) + return true; //socket closed or empty packet + + if (packet.Size == -1) + { + //Linux timeout EAGAIN + return ProcessError(new SocketException((int)NativeSocket.GetSocketError())) == false; + } + + //NetDebug.WriteForce($"[R]Received data from {endPoint}, result: {packet.Size}"); + //refresh temp Addr/Port + short family = (short)((address[1] << 8) | address[0]); + tempEndPoint.Port =(ushort)((address[2] << 8) | address[3]); + if ((NativeSocket.UnixMode && family == NativeSocket.AF_INET6) || (!NativeSocket.UnixMode && (AddressFamily)family == AddressFamily.InterNetworkV6)) + { + uint scope = unchecked((uint)( + (address[27] << 24) + + (address[26] << 16) + + (address[25] << 8) + + (address[24]))); +#if NETCOREAPP || NETSTANDARD2_1 || NETSTANDARD2_1_OR_GREATER + tempEndPoint.Address = new IPAddress(new ReadOnlySpan(address, 8, 16), scope); +#else + byte[] addrBuffer = new byte[16]; + Buffer.BlockCopy(address, 8, addrBuffer, 0, 16); + tempEndPoint.Address = new IPAddress(addrBuffer, scope); +#endif + } + else //IPv4 + { + long ipv4Addr = unchecked((uint)((address[4] & 0x000000FF) | + (address[5] << 8 & 0x0000FF00) | + (address[6] << 16 & 0x00FF0000) | + (address[7] << 24))); + tempEndPoint.Address = new IPAddress(ipv4Addr); + } + + if (TryGetPeer(tempEndPoint, out var peer)) + { + //use cached native ep + OnMessageReceived(packet, peer); + } + else + { + OnMessageReceived(packet, tempEndPoint); + tempEndPoint = new IPEndPoint(IPAddress.Any, 0); + } + packet = PoolGetPacket(NetConstants.MaxPacketSize); + return true; + } + } + + private void ReceiveFrom(Socket s, ref EndPoint bufferEndPoint) + { + var packet = PoolGetPacket(NetConstants.MaxPacketSize); +#if NET8_0_OR_GREATER + var sockAddr = s.AddressFamily == AddressFamily.InterNetwork ? _sockAddrCacheV4 : _sockAddrCacheV6; + packet.Size = s.ReceiveFrom(packet, SocketFlags.None, sockAddr); + OnMessageReceived(packet, TryGetPeer(sockAddr, out var peer) ? peer : (IPEndPoint)bufferEndPoint.Create(sockAddr)); +#else + packet.Size = s.ReceiveFrom(packet.RawData, 0, NetConstants.MaxPacketSize, SocketFlags.None, ref bufferEndPoint); + OnMessageReceived(packet, (IPEndPoint)bufferEndPoint); +#endif + } + + private void ReceiveLogic() + { + EndPoint bufferEndPoint4 = new IPEndPoint(IPAddress.Any, 0); + EndPoint bufferEndPoint6 = new IPEndPoint(IPAddress.IPv6Any, 0); + var selectReadList = new List(2); + var socketv4 = _udpSocketv4; + var socketV6 = _udpSocketv6; + + while (IsRunning) + { + //Reading data + try + { + if (socketV6 == null) + { + if (socketv4.Available == 0 && !socketv4.Poll(ReceivePollingTime, SelectMode.SelectRead)) + continue; + ReceiveFrom(socketv4, ref bufferEndPoint4); + } + else + { + bool messageReceived = false; + if (socketv4.Available != 0 || selectReadList.Contains(socketv4)) + { + ReceiveFrom(socketv4, ref bufferEndPoint4); + messageReceived = true; + } + if (socketV6.Available != 0 || selectReadList.Contains(socketV6)) + { + ReceiveFrom(socketV6, ref bufferEndPoint6); + messageReceived = true; + } + + selectReadList.Clear(); + + if (messageReceived) + continue; + + selectReadList.Add(socketv4); + selectReadList.Add(socketV6); + Socket.Select(selectReadList, null, null, ReceivePollingTime); + } + //NetDebug.Write(NetLogLevel.Trace, $"[R]Received data from {bufferEndPoint}, result: {packet.Size}"); + } + catch (SocketException ex) + { + if (ProcessError(ex)) + return; + } + catch (ObjectDisposedException) + { + //socket closed + return; + } + catch (ThreadAbortException) + { + //thread closed + return; + } + catch (Exception e) + { + //protects socket receive thread + NetDebug.WriteError("[NM] SocketReceiveThread error: " + e ); } } } @@ -251,75 +335,60 @@ namespace LiteNetLib /// mode of library public bool Start(IPAddress addressIPv4, IPAddress addressIPv6, int port, bool manualMode) { - if (IsRunning && !IsActive()) + if (IsRunning && NotConnected == false) return false; + + NotConnected = false; _manualMode = manualMode; UseNativeSockets = UseNativeSockets && NativeSocket.IsSupported; - - //osx doesn't support dual mode - if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && IPv6Mode == IPv6Mode.DualMode) - IPv6Mode = IPv6Mode.SeparateSocket; - - bool dualMode = IPv6Mode == IPv6Mode.DualMode && IPv6Support; - - _udpSocketv4 = new Socket( - dualMode ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, - SocketType.Dgram, - ProtocolType.Udp); - - if (!BindSocket(_udpSocketv4, new IPEndPoint(dualMode ? addressIPv6 : addressIPv4, port))) + _udpSocketv4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); + if (!BindSocket(_udpSocketv4, new IPEndPoint(addressIPv4, port))) return false; - LocalPort = ((IPEndPoint)_udpSocketv4.LocalEndPoint).Port; + LocalPort = ((IPEndPoint) _udpSocketv4.LocalEndPoint).Port; - if (dualMode) - _udpSocketv6 = _udpSocketv4; +#if UNITY_SOCKET_FIX + if (_useSocketFix && _pausedSocketFix == null) + _pausedSocketFix = new PausedSocketFix(this, addressIPv4, addressIPv6, port, manualMode); +#endif IsRunning = true; - if (!_manualMode) - { - ParameterizedThreadStart ts = ReceiveLogic; - if (UseNativeSockets) - ts = NativeReceiveLogic; - - _threadv4 = new Thread(ts) - { - Name = $"SocketThreadv4({LocalPort})", - IsBackground = true - }; - _threadv4.Start(_udpSocketv4); - - _logicThread = new Thread(UpdateLogic) { Name = "LogicThread", IsBackground = true }; - _logicThread.Start(); - } - else + if (_manualMode) { _bufferEndPointv4 = new IPEndPoint(IPAddress.Any, 0); } //Check IPv6 support - if (IPv6Support && IPv6Mode == IPv6Mode.SeparateSocket) + if (IPv6Support && IPv6Enabled) { _udpSocketv6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp); //Use one port for two sockets if (BindSocket(_udpSocketv6, new IPEndPoint(addressIPv6, LocalPort))) { if (_manualMode) - { _bufferEndPointv6 = new IPEndPoint(IPAddress.IPv6Any, 0); - } - else - { - ParameterizedThreadStart ts = ReceiveLogic; - if (UseNativeSockets) - ts = NativeReceiveLogic; - _threadv6 = new Thread(ts) - { - Name = $"SocketThreadv6({LocalPort})", - IsBackground = true - }; - _threadv6.Start(_udpSocketv6); - } + } + else + { + _udpSocketv6 = null; + } + } + + if (!manualMode) + { + ThreadStart ts = ReceiveLogic; + if (UseNativeSockets) + ts = NativeReceiveLogic; + _receiveThread = new Thread(ts) + { + Name = $"ReceiveThread({LocalPort})", + IsBackground = true + }; + _receiveThread.Start(); + if (_logicThread == null) + { + _logicThread = new Thread(UpdateLogic) { Name = "LogicThread", IsBackground = true }; + _logicThread.Start(); } } @@ -333,12 +402,13 @@ namespace LiteNetLib socket.SendTimeout = 500; socket.ReceiveBufferSize = NetConstants.SocketBufferSize; socket.SendBufferSize = NetConstants.SocketBufferSize; + socket.Blocking = true; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { try { - socket.IOControl(SioUdpConnreset, new byte[] { 0 }, null); + socket.IOControl(SioUdpConnreset, new byte[] {0}, null); } catch { @@ -356,7 +426,7 @@ namespace LiteNetLib { //Unity with IL2CPP throws an exception here, it doesn't matter in most cases so just ignore it } - if (ep.AddressFamily == AddressFamily.InterNetwork || IPv6Mode == IPv6Mode.DualMode) + if (ep.AddressFamily == AddressFamily.InterNetwork) { Ttl = NetConstants.SocketTTL; @@ -366,15 +436,7 @@ namespace LiteNetLib NetDebug.WriteError($"[B]Broadcast error: {e.SocketErrorCode}"); } - if (IPv6Mode == IPv6Mode.DualMode) - { - try { socket.DualMode = true; } - catch (Exception e) - { - NetDebug.WriteError($"[B]Bind exception (dualmode setting): {e}"); - } - } - else if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { try { socket.DontFragment = true; } catch (SocketException e) @@ -394,7 +456,7 @@ namespace LiteNetLib { try { -#if !UNITY_2018_3_OR_NEWER +#if !UNITY_SOCKET_FIX socket.SetSocketOption( SocketOptionLevel.IPv6, SocketOptionName.AddMembership, @@ -413,7 +475,7 @@ namespace LiteNetLib { //IPv6 bind fix case SocketError.AddressAlreadyInUse: - if (socket.AddressFamily == AddressFamily.InterNetworkV6 && IPv6Mode != IPv6Mode.DualMode) + if (socket.AddressFamily == AddressFamily.InterNetworkV6) { try { @@ -478,75 +540,23 @@ namespace LiteNetLib int result; try { - if (UseNativeSockets) + if (UseNativeSockets && remoteEndPoint is NetPeer peer) { - byte[] socketAddress; - - if (remoteEndPoint is NativeEndPoint nep) - { - socketAddress = nep.NativeAddress; - } - else //Convert endpoint to raw - { - if (_endPointBuffer == null) - _endPointBuffer = new byte[NativeSocket.IPv6AddrSize]; - socketAddress = _endPointBuffer; - - bool ipv4 = remoteEndPoint.AddressFamily == AddressFamily.InterNetwork; - short addressFamily = NativeSocket.GetNativeAddressFamily(remoteEndPoint); - - socketAddress[0] = (byte)(addressFamily); - socketAddress[1] = (byte)(addressFamily >> 8); - socketAddress[2] = (byte)(remoteEndPoint.Port >> 8); - socketAddress[3] = (byte)(remoteEndPoint.Port); - - if (ipv4) - { -#pragma warning disable 618 - long addr = remoteEndPoint.Address.Address; -#pragma warning restore 618 - socketAddress[4] = (byte)(addr); - socketAddress[5] = (byte)(addr >> 8); - socketAddress[6] = (byte)(addr >> 16); - socketAddress[7] = (byte)(addr >> 24); - } - else - { -#if NETCOREAPP || NETSTANDARD2_1 || NETSTANDARD2_1_OR_GREATER - remoteEndPoint.Address.TryWriteBytes(new Span(socketAddress, 8, 16), out _); -#else - byte[] addrBytes = remoteEndPoint.Address.GetAddressBytes(); - Buffer.BlockCopy(addrBytes, 0, socketAddress, 8, 16); -#endif - } - } - -#if LITENETLIB_UNSAFE unsafe { fixed (byte* dataWithOffset = &message[start]) - { - result = - NativeSocket.SendTo(socket.Handle, dataWithOffset, length, socketAddress, socketAddress.Length); - } + result = NativeSocket.SendTo(socket.Handle, dataWithOffset, length, peer.NativeAddress, peer.NativeAddress.Length); } -#else - if (start > 0) - { - if (_sendToBuffer == null) - _sendToBuffer = new byte[NetConstants.MaxPacketSize]; - Buffer.BlockCopy(message, start, _sendToBuffer, 0, length); - message = _sendToBuffer; - } - - result = NativeSocket.SendTo(socket.Handle, message, length, socketAddress, socketAddress.Length); -#endif if (result == -1) throw NativeSocket.GetSocketException(); } else { +#if NET8_0_OR_GREATER + result = socket.SendTo(new ReadOnlySpan(message, start, length), SocketFlags.None, remoteEndPoint.Serialize()); +#else result = socket.SendTo(message, start, length, SocketFlags.None, remoteEndPoint); +#endif } //NetDebug.WriteForce("[S]Send packet to {0}, result: {1}", remoteEndPoint, result); } @@ -558,15 +568,15 @@ namespace LiteNetLib case SocketError.Interrupted: return 0; case SocketError.MessageSize: - NetDebug.Write(NetLogLevel.Trace, "[SRD] 10040, datalen: {0}", length); + NetDebug.Write(NetLogLevel.Trace, $"[SRD] 10040, datalen: {length}"); return 0; case SocketError.HostUnreachable: case SocketError.NetworkUnreachable: - if (DisconnectOnUnreachable && TryGetPeer(remoteEndPoint, out var fromPeer)) + if (DisconnectOnUnreachable && remoteEndPoint is NetPeer peer) { DisconnectPeerForce( - fromPeer, + peer, ex.SocketErrorCode == SocketError.HostUnreachable ? DisconnectReason.HostUnreachable : DisconnectReason.NetworkUnreachable, @@ -577,6 +587,10 @@ namespace LiteNetLib CreateEvent(NetEvent.EType.Error, remoteEndPoint: remoteEndPoint, errorCode: ex.SocketErrorCode); return -1; + case SocketError.Shutdown: + CreateEvent(NetEvent.EType.Error, remoteEndPoint: remoteEndPoint, errorCode: ex.SocketErrorCode); + return -1; + default: NetDebug.WriteError($"[S] {ex}"); return -1; @@ -590,9 +604,7 @@ namespace LiteNetLib finally { if (expandedPacket != null) - { PoolRecycle(expandedPacket); - } } if (result <= 0) @@ -619,7 +631,7 @@ namespace LiteNetLib public bool SendBroadcast(byte[] data, int start, int length, int port) { - if (!IsActive()) + if (!IsRunning) return false; NetPacket packet; @@ -660,6 +672,13 @@ namespace LiteNetLib new IPEndPoint(MulticastAddressV6, port)) > 0; } } + catch (SocketException ex) + { + if (ex.SocketErrorCode == SocketError.HostUnreachable) + return broadcastSuccess; + NetDebug.WriteError($"[S][MCAST] {ex}"); + return broadcastSuccess; + } catch (Exception ex) { NetDebug.WriteError($"[S][MCAST] {ex}"); @@ -673,26 +692,16 @@ namespace LiteNetLib return broadcastSuccess || multicastSuccess; } - internal void CloseSocket(bool suspend) + private void CloseSocket() { - if (!suspend) - IsRunning = false; - - //cleanup dual mode - if (_udpSocketv4 == _udpSocketv6) - _udpSocketv6 = null; - + IsRunning = false; _udpSocketv4?.Close(); _udpSocketv6?.Close(); _udpSocketv4 = null; _udpSocketv6 = null; - - if (_threadv4 != null && _threadv4 != Thread.CurrentThread) - _threadv4.Join(); - if (_threadv6 != null && _threadv6 != Thread.CurrentThread) - _threadv6.Join(); - _threadv4 = null; - _threadv6 = null; + if (_receiveThread != null && _receiveThread != Thread.CurrentThread) + _receiveThread.Join(); + _receiveThread = null; } } } diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs index f176a5a..5d6f1e6 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetManager.cs @@ -1,4 +1,7 @@ -using System; +#if UNITY_2018_3_OR_NEWER +#define UNITY_SOCKET_FIX +#endif +using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; @@ -11,13 +14,6 @@ using LiteNetLib.Utils; namespace LiteNetLib { - public enum IPv6Mode - { - Disabled, - SeparateSocket, - DualMode - } - public sealed class NetPacketReader : NetDataReader { private NetPacket _packet; @@ -38,7 +34,7 @@ namespace LiteNetLib SetSource(packet.RawData, headerSize, packet.Size); } - internal void Recycle_Internal() + internal void RecycleInternal() { Clear(); if (_packet != null) @@ -51,7 +47,7 @@ namespace LiteNetLib { if (_manager.AutoRecycle) return; - Recycle_Internal(); + RecycleInternal(); } } @@ -96,19 +92,6 @@ namespace LiteNetLib /// public partial class NetManager : IEnumerable { - private class IPEndPointComparer : IEqualityComparer - { - public bool Equals(IPEndPoint x, IPEndPoint y) - { - return x.Address.Equals(y.Address) && x.Port == y.Port; - } - - public int GetHashCode(IPEndPoint obj) - { - return obj.GetHashCode(); - } - } - public struct NetPeerEnumerator : IEnumerator { private readonly NetPeer _initialPeer; @@ -156,8 +139,8 @@ namespace LiteNetLib private bool _manualMode; private readonly AutoResetEvent _updateTriggerEvent = new AutoResetEvent(true); - private Queue _netEventsProduceQueue = new Queue(); - private Queue _netEventsConsumeQueue = new Queue(); + private NetEvent _pendingEventHead; + private NetEvent _pendingEventTail; private NetEvent _netEventPoolHead; private readonly INetEventListener _netEventListener; @@ -165,16 +148,12 @@ namespace LiteNetLib private readonly INtpEventListener _ntpEventListener; private readonly IPeerAddressChangedListener _peerAddressChangedListener; - private readonly Dictionary _peersDict = new Dictionary(new IPEndPointComparer()); - private readonly Dictionary _requestsDict = new Dictionary(new IPEndPointComparer()); - private readonly Dictionary _ntpRequests = new Dictionary(new IPEndPointComparer()); - private readonly ReaderWriterLockSlim _peersLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); - private volatile NetPeer _headPeer; - private int _connectedPeersCount; + private readonly Dictionary _requestsDict = new Dictionary(); + private readonly ConcurrentDictionary _ntpRequests = new ConcurrentDictionary(); + private long _connectedPeersCount; private readonly List _connectedPeerListCache = new List(); - private NetPeer[] _peersArray = new NetPeer[32]; private readonly PacketLayerBase _extraPacketLayer; - private int _lastPeerId; + private int _nextPeerId; private ConcurrentQueue _peerIds = new ConcurrentQueue(); private byte _channelsCount = 1; private readonly object _eventLock = new object(); @@ -269,7 +248,7 @@ namespace LiteNetLib public bool ReuseAddress = false; /// - /// UDP Only Option. Enables socket option "DontRoute" for specific purposes. + /// UDP Only Socket Option /// Normally IP sockets send packets of data through routers and gateways until they reach the final destination. /// If the DontRoute flag is set to True, then data will be delivered on the local subnet only. /// @@ -308,7 +287,7 @@ namespace LiteNetLib /// /// IPv6 support /// - public IPv6Mode IPv6Mode = IPv6Mode.SeparateSocket; + public bool IPv6Enabled = true; /// /// Override MTU for all new peers registered in this NetManager, will ignores MTU Discovery! @@ -367,103 +346,30 @@ namespace LiteNetLib } } - /// - /// Gets peer by peer id - /// - /// id of peer - /// Peer if peer with id exist, otherwise null - public NetPeer GetPeerById(int id) - { - if (id >= 0 && id < _peersArray.Length) - { - return _peersArray[id]; - } - - return null; - } - - /// - /// Gets peer by peer id - /// - /// id of peer - /// resulting peer - /// True if peer with id exist, otherwise false - public bool TryGetPeerById(int id, out NetPeer peer) - { - peer = GetPeerById(id); - - return peer != null; - } - /// /// Returns connected peers count /// - public int ConnectedPeersCount => Interlocked.CompareExchange(ref _connectedPeersCount,0,0); + public int ConnectedPeersCount => (int)Interlocked.Read(ref _connectedPeersCount); public int ExtraPacketSizeForLayer => _extraPacketLayer?.ExtraPacketSizeForLayer ?? 0; - private bool TryGetPeer(IPEndPoint endPoint, out NetPeer peer) + public NetManager(bool useSocketFix = true) { - _peersLock.EnterReadLock(); - bool result = _peersDict.TryGetValue(endPoint, out peer); - _peersLock.ExitReadLock(); - return result; + _useSocketFix = useSocketFix; } - - private void AddPeer(NetPeer peer) - { - _peersLock.EnterWriteLock(); - if (_headPeer != null) - { - peer.NextPeer = _headPeer; - _headPeer.PrevPeer = peer; - } - _headPeer = peer; - _peersDict.Add(peer.EndPoint, peer); - if (peer.Id >= _peersArray.Length) - { - int newSize = _peersArray.Length * 2; - while (peer.Id >= newSize) - newSize *= 2; - Array.Resize(ref _peersArray, newSize); - } - _peersArray[peer.Id] = peer; - RegisterEndPoint(peer.EndPoint); - _peersLock.ExitWriteLock(); - } - - private void RemovePeer(NetPeer peer) - { - _peersLock.EnterWriteLock(); - RemovePeer_Internal(peer); - _peersLock.ExitWriteLock(); - } - - private void RemovePeer_Internal(NetPeer peer) - { - if (!_peersDict.Remove(peer.EndPoint)) - return; - if (peer == _headPeer) - _headPeer = peer.NextPeer; - - if (peer.PrevPeer != null) - peer.PrevPeer.NextPeer = peer.NextPeer; - if (peer.NextPeer != null) - peer.NextPeer.PrevPeer = peer.PrevPeer; - peer.PrevPeer = null; - - _peersArray[peer.Id] = null; - _peerIds.Enqueue(peer.Id); - UnregisterEndPoint(peer.EndPoint); - } - /// /// NetManager constructor /// /// Network events listener (also can implement IDeliveryEventListener) /// Extra processing of packages, like CRC checksum or encryption. All connected NetManagers must have same layer. +#if UNITY_SOCKET_FIX + public NetManager(INetEventListener listener, PacketLayerBase extraPacketLayer = null, bool useSocketFix = true) + { + _useSocketFix = useSocketFix; +#else public NetManager(INetEventListener listener, PacketLayerBase extraPacketLayer = null) { +#endif _netEventListener = listener; _deliveryEventListener = listener as IDeliveryEventListener; _ntpEventListener = listener as INtpEventListener; @@ -479,7 +385,7 @@ namespace LiteNetLib internal void MessageDelivered(NetPeer fromPeer, object userData) { - if(_deliveryEventListener != null) + if (_deliveryEventListener != null) CreateEvent(NetEvent.EType.MessageDelivered, fromPeer, userData: userData); } @@ -504,7 +410,7 @@ namespace LiteNetLib var shutdownResult = peer.Shutdown(data, start, count, force); if (shutdownResult == ShutdownResult.None) return; - if(shutdownResult == ShutdownResult.WasConnected) + if (shutdownResult == ShutdownResult.WasConnected) Interlocked.Decrement(ref _connectedPeersCount); CreateEvent( NetEvent.EType.Disconnect, @@ -535,7 +441,7 @@ namespace LiteNetLib else if (type == NetEvent.EType.MessageDelivered) unsyncEvent = UnsyncedDeliveryEvent; - lock(_eventLock) + lock (_eventLock) { evt = _netEventPoolHead; if (evt == null) @@ -544,6 +450,7 @@ namespace LiteNetLib _netEventPoolHead = evt.Next; } + evt.Next = null; evt.Type = type; evt.DataReader.SetSource(readerSource, readerSource?.GetHeaderSize() ?? 0); evt.Peer = peer; @@ -562,8 +469,14 @@ namespace LiteNetLib } else { - lock(_netEventsProduceQueue) - _netEventsProduceQueue.Enqueue(evt); + lock (_eventLock) + { + if (_pendingEventTail == null) + _pendingEventHead = evt; + else + _pendingEventTail.Next = evt; + _pendingEventTail = evt; + } } } @@ -584,6 +497,7 @@ namespace LiteNetLib SocketErrorCode = evt.ErrorCode }; _netEventListener.OnPeerDisconnected(evt.Peer, info); + RemovePeer(evt.Peer); break; case NetEvent.EType.Receive: _netEventListener.OnNetworkReceive(evt.Peer, evt.DataReader, evt.ChannelNumber, evt.DeliveryMethod); @@ -596,6 +510,7 @@ namespace LiteNetLib break; case NetEvent.EType.Error: _netEventListener.OnNetworkError(evt.RemoteEndPoint, evt.ErrorCode); + RemovePeer(evt.Peer); break; case NetEvent.EType.ConnectionLatencyUpdated: _netEventListener.OnNetworkLatencyUpdate(evt.Peer, evt.Latency); @@ -609,17 +524,17 @@ namespace LiteNetLib case NetEvent.EType.PeerAddressChanged: _peersLock.EnterUpgradeableReadLock(); IPEndPoint previousAddress = null; - if (_peersDict.ContainsKey(evt.Peer.EndPoint)) + if (ContainsPeer(evt.Peer)) { _peersLock.EnterWriteLock(); - _peersDict.Remove(evt.Peer.EndPoint); - previousAddress = evt.Peer.EndPoint; + RemovePeerFromSet(evt.Peer); + previousAddress = new IPEndPoint(evt.Peer.Address, evt.Peer.Port); evt.Peer.FinishEndPointChange(evt.RemoteEndPoint); - _peersDict.Add(evt.Peer.EndPoint, evt.Peer); + AddPeerToSet(evt.Peer); _peersLock.ExitWriteLock(); } _peersLock.ExitUpgradeableReadLock(); - if(previousAddress != null) + if (previousAddress != null && _peerAddressChangedListener != null) _peerAddressChangedListener.OnPeerAddressChanged(evt.Peer, previousAddress); break; } @@ -627,7 +542,7 @@ namespace LiteNetLib if (emptyData) RecycleEvent(evt); else if (AutoRecycle) - evt.DataReader.Recycle_Internal(); + evt.DataReader.RecycleInternal(); } internal void RecycleEvent(NetEvent evt) @@ -636,7 +551,7 @@ namespace LiteNetLib evt.ErrorCode = 0; evt.RemoteEndPoint = null; evt.ConnectionRequest = null; - lock(_eventLock) + lock (_eventLock) { evt.Next = _netEventPoolHead; _netEventPoolHead = evt; @@ -676,7 +591,7 @@ namespace LiteNetLib { _peersLock.EnterWriteLock(); for (int i = 0; i < peersToRemove.Count; i++) - RemovePeer_Internal(peersToRemove[i]); + RemovePeerInternal(peersToRemove[i]); _peersLock.ExitWriteLock(); peersToRemove.Clear(); } @@ -729,7 +644,7 @@ namespace LiteNetLib foreach (var ntpRequest in _ntpRequests) { ntpRequest.Value.Send(_udpSocketv4, elapsedMilliseconds); - if(ntpRequest.Value.NeedToKill) + if (ntpRequest.Value.NeedToKill) { if (requestsToRemove == null) requestsToRemove = new List(); @@ -741,7 +656,7 @@ namespace LiteNetLib { foreach (var ipEndPoint in requestsToRemove) { - _ntpRequests.Remove(ipEndPoint); + _ntpRequests.TryRemove(ipEndPoint, out _); } } } @@ -759,7 +674,7 @@ namespace LiteNetLib { if (netPeer.ConnectionState == ConnectionState.Disconnected && netPeer.TimeSinceLastPacket > DisconnectTimeout) { - RemovePeer_Internal(netPeer); + RemovePeerInternal(netPeer); } else { @@ -787,43 +702,61 @@ namespace LiteNetLib Buffer.BlockCopy(rejectData, start, shutdownPacket.RawData, 9, length); SendRawAndRecycle(shutdownPacket, request.RemoteEndPoint); } + lock (_requestsDict) + _requestsDict.Remove(request.RemoteEndPoint); } - else - { - _peersLock.EnterUpgradeableReadLock(); - if (_peersDict.TryGetValue(request.RemoteEndPoint, out netPeer)) + else lock (_requestsDict) { - //already have peer - _peersLock.ExitUpgradeableReadLock(); + if (TryGetPeer(request.RemoteEndPoint, out netPeer)) + { + //already have peer + } + else if (request.Result == ConnectionRequestResult.Reject) + { + netPeer = new NetPeer(this, request.RemoteEndPoint, GetNextPeerId()); + netPeer.Reject(request.InternalPacket, rejectData, start, length); + AddPeer(netPeer); + NetDebug.Write(NetLogLevel.Trace, "[NM] Peer connect reject."); + } + else //Accept + { + netPeer = new NetPeer(this, request, GetNextPeerId()); + AddPeer(netPeer); + CreateEvent(NetEvent.EType.Connect, netPeer); + NetDebug.Write(NetLogLevel.Trace, $"[NM] Received peer connection Id: {netPeer.ConnectTime}, EP: {netPeer}"); + } + _requestsDict.Remove(request.RemoteEndPoint); } - else if (request.Result == ConnectionRequestResult.Reject) - { - netPeer = new NetPeer(this, request.RemoteEndPoint, GetNextPeerId()); - netPeer.Reject(request.InternalPacket, rejectData, start, length); - AddPeer(netPeer); - _peersLock.ExitUpgradeableReadLock(); - NetDebug.Write(NetLogLevel.Trace, "[NM] Peer connect reject."); - } - else //Accept - { - netPeer = new NetPeer(this, request, GetNextPeerId()); - AddPeer(netPeer); - _peersLock.ExitUpgradeableReadLock(); - CreateEvent(NetEvent.EType.Connect, netPeer); - NetDebug.Write(NetLogLevel.Trace, "[NM] Received peer connection Id: {0}, EP: {1}", - netPeer.ConnectTime, netPeer.EndPoint); - } - } - - lock(_requestsDict) - _requestsDict.Remove(request.RemoteEndPoint); return netPeer; } private int GetNextPeerId() { - return _peerIds.TryDequeue(out int id) ? id : _lastPeerId++; + /* Build a small queue so that when fetching + * an id its unlikely to be one that was just returned. This adds + * a buffer to applications which may be using the Id to identity + * clients in their code, but may need time to dispose of objects + * associated with the Id. */ + const int addCount = 5000; + const int halfCount = (addCount / 2); + if (_peerIds.Count < halfCount) + { + //At most how many can be added. + const int maxIdValue = int.MaxValue; + long addable = Math.Min(addCount, (maxIdValue - _nextPeerId)); + + if (addable == 0) + { + NetDebug.Write(NetLogLevel.Error, $"[NM] PeerIds have exceeded the maximum value of {maxIdValue}. A new Id cannot be returned."); + return 0; + } + + for (int i = 0; i < addCount; i++) + _peerIds.Enqueue(_nextPeerId++); + } + + return (_peerIds.TryDequeue(out int result)) ? result : _nextPeerId++; } private void ProcessConnectRequest( @@ -835,11 +768,7 @@ namespace LiteNetLib if (netPeer != null) { var processResult = netPeer.ProcessConnectRequest(connRequest); - NetDebug.Write("ConnectRequest LastId: {0}, NewId: {1}, EP: {2}, Result: {3}", - netPeer.ConnectTime, - connRequest.ConnectionTime, - remoteEndPoint, - processResult); + NetDebug.Write($"ConnectRequest LastId: {netPeer.ConnectTime}, NewId: {connRequest.ConnectionTime}, EP: {remoteEndPoint}, Result: {processResult}"); switch (processResult) { @@ -863,13 +792,13 @@ namespace LiteNetLib } //ConnectRequestResult.NewConnection //Set next connection number - if(processResult != ConnectRequestResult.P2PLose) + if (processResult != ConnectRequestResult.P2PLose) connRequest.ConnectionNumber = (byte)((netPeer.ConnectionNum + 1) % NetConstants.MaxConnectionNumber); //To reconnect peer } else { - NetDebug.Write("ConnectRequest Id: {0}, EP: {1}", connRequest.ConnectionTime, remoteEndPoint); + NetDebug.Write($"ConnectRequest Id: {connRequest.ConnectionTime}, EP: {remoteEndPoint}"); } ConnectionRequest req; @@ -883,12 +812,17 @@ namespace LiteNetLib req = new ConnectionRequest(remoteEndPoint, connRequest, this); _requestsDict.Add(remoteEndPoint, req); } - NetDebug.Write("[NM] Creating request event: " + connRequest.ConnectionTime); + NetDebug.Write($"[NM] Creating request event: {connRequest.ConnectionTime}"); CreateEvent(NetEvent.EType.ConnectionRequest, connectionRequest: req); } private void OnMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint) { + if (packet.Size == 0) + { + PoolRecycle(packet); + return; + } #if DEBUG if (SimulatePacketLoss && _randomGenerator.NextDouble() * 100 < SimulationPacketLossChance) { @@ -921,48 +855,45 @@ namespace LiteNetLib private void DebugMessageReceived(NetPacket packet, IPEndPoint remoteEndPoint) { #endif + var originalPacketSize = packet.Size; if (EnableStatistics) { Statistics.IncrementPacketsReceived(); - Statistics.AddBytesReceived(packet.Size); + Statistics.AddBytesReceived(originalPacketSize); } - if (_ntpRequests.Count > 0) + if (_ntpRequests.Count > 0 && _ntpRequests.TryGetValue(remoteEndPoint, out var request)) { - if (_ntpRequests.TryGetValue(remoteEndPoint, out var request)) + if (packet.Size < 48) { - if (packet.Size < 48) - { - NetDebug.Write(NetLogLevel.Trace, "NTP response too short: {}", packet.Size); - return; - } - - byte[] copiedData = new byte[packet.Size]; - Buffer.BlockCopy(packet.RawData, 0, copiedData, 0, packet.Size); - NtpPacket ntpPacket = NtpPacket.FromServerResponse(copiedData, DateTime.UtcNow); - try - { - ntpPacket.ValidateReply(); - } - catch (InvalidOperationException ex) - { - NetDebug.Write(NetLogLevel.Trace, "NTP response error: {}", ex.Message); - ntpPacket = null; - } - - if (ntpPacket != null) - { - _ntpRequests.Remove(remoteEndPoint); - _ntpEventListener?.OnNtpResponse(ntpPacket); - } + NetDebug.Write(NetLogLevel.Trace, $"NTP response too short: {packet.Size}"); return; } + + byte[] copiedData = new byte[packet.Size]; + Buffer.BlockCopy(packet.RawData, 0, copiedData, 0, packet.Size); + NtpPacket ntpPacket = NtpPacket.FromServerResponse(copiedData, DateTime.UtcNow); + try + { + ntpPacket.ValidateReply(); + } + catch (InvalidOperationException ex) + { + NetDebug.Write(NetLogLevel.Trace, $"NTP response error: {ex.Message}"); + ntpPacket = null; + } + + if (ntpPacket != null) + { + _ntpRequests.TryRemove(remoteEndPoint, out _); + _ntpEventListener?.OnNtpResponse(ntpPacket); + } + return; } if (_extraPacketLayer != null) { - int start = 0; - _extraPacketLayer.ProcessInboundPacket(ref remoteEndPoint, ref packet.RawData, ref start, ref packet.Size); + _extraPacketLayer.ProcessInboundPacket(ref remoteEndPoint, ref packet.RawData, ref packet.Size); if (packet.Size == 0) return; } @@ -1002,9 +933,13 @@ namespace LiteNetLib } //Check normal packets - _peersLock.EnterReadLock(); - bool peerFound = _peersDict.TryGetValue(remoteEndPoint, out var netPeer); - _peersLock.ExitReadLock(); + bool peerFound = remoteEndPoint is NetPeer netPeer || TryGetPeer(remoteEndPoint, out netPeer); + + if (peerFound && EnableStatistics) + { + netPeer.Statistics.IncrementPacketsReceived(); + netPeer.Statistics.AddBytesReceived(originalPacketSize); + } switch (packet.Property) { @@ -1047,6 +982,7 @@ namespace LiteNetLib { _peersLock.EnterUpgradeableReadLock(); var peer = _peersArray[remoteData.PeerId]; + _peersLock.ExitUpgradeableReadLock(); if (peer != null && peer.ConnectTime == remoteData.ConnectionTime && peer.ConnectionNum == remoteData.ConnectionNumber) @@ -1054,15 +990,11 @@ namespace LiteNetLib if (peer.ConnectionState == ConnectionState.Connected) { peer.InitiateEndPointChange(); - if (_peerAddressChangedListener != null) - { - CreateEvent(NetEvent.EType.PeerAddressChanged, peer, remoteEndPoint); - } + CreateEvent(NetEvent.EType.PeerAddressChanged, peer, remoteEndPoint); NetDebug.Write("[NM] PeerNotFound change address of remote peer"); } isOldPeer = true; } - _peersLock.ExitUpgradeableReadLock(); } } @@ -1112,7 +1044,7 @@ namespace LiteNetLib CreateEvent(NetEvent.EType.Connect, netPeer); break; default: - if(peerFound) + if (peerFound) netPeer.ProcessPacket(packet); else SendRawAndRecycle(PoolGetWithProperty(PacketProperty.PeerNotFound), remoteEndPoint); @@ -1123,27 +1055,48 @@ namespace LiteNetLib internal void CreateReceiveEvent(NetPacket packet, DeliveryMethod method, byte channelNumber, int headerSize, NetPeer fromPeer) { NetEvent evt; - lock (_eventLock) - { - evt = _netEventPoolHead; - if (evt == null) - evt = new NetEvent(this); - else - _netEventPoolHead = evt.Next; - } - evt.Type = NetEvent.EType.Receive; - evt.DataReader.SetSource(packet, headerSize); - evt.Peer = fromPeer; - evt.DeliveryMethod = method; - evt.ChannelNumber = channelNumber; + if (UnsyncedEvents || UnsyncedReceiveEvent || _manualMode) { + lock (_eventLock) + { + evt = _netEventPoolHead; + if (evt == null) + evt = new NetEvent(this); + else + _netEventPoolHead = evt.Next; + } + evt.Next = null; + evt.Type = NetEvent.EType.Receive; + evt.DataReader.SetSource(packet, headerSize); + evt.Peer = fromPeer; + evt.DeliveryMethod = method; + evt.ChannelNumber = channelNumber; ProcessEvent(evt); } else { - lock(_netEventsProduceQueue) - _netEventsProduceQueue.Enqueue(evt); + lock (_eventLock) + { + evt = _netEventPoolHead; + if (evt == null) + evt = new NetEvent(this); + else + _netEventPoolHead = evt.Next; + + evt.Next = null; + evt.Type = NetEvent.EType.Receive; + evt.DataReader.SetSource(packet, headerSize); + evt.Peer = fromPeer; + evt.DeliveryMethod = method; + evt.ChannelNumber = channelNumber; + + if (_pendingEventTail == null) + _pendingEventHead = evt; + else + _pendingEventTail.Next = evt; + _pendingEventTail = evt; + } } } @@ -1282,7 +1235,6 @@ namespace LiteNetLib SendToAll(data, 0, data.Length, channelNumber, options, excludePeer); } - /// /// Send data to all connected peers /// @@ -1309,6 +1261,68 @@ namespace LiteNetLib } } +#if LITENETLIB_SPANS || NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1 || NETCOREAPP3_1 || NET5_0 || NETSTANDARD2_1 + /// + /// Send data to all connected peers (channel - 0) + /// + /// Data + /// Send options (reliable, unreliable, etc.) + public void SendToAll(ReadOnlySpan data, DeliveryMethod options) + { + SendToAll(data, 0, options, null); + } + + /// + /// Send data to all connected peers (channel - 0) + /// + /// Data + /// Send options (reliable, unreliable, etc.) + /// Excluded peer + public void SendToAll(ReadOnlySpan data, DeliveryMethod options, NetPeer excludePeer) + { + SendToAll(data, 0, options, excludePeer); + } + + /// + /// Send data to all connected peers + /// + /// Data + /// Number of channel (from 0 to channelsCount - 1) + /// Send options (reliable, unreliable, etc.) + /// Excluded peer + public void SendToAll(ReadOnlySpan data, byte channelNumber, DeliveryMethod options, NetPeer excludePeer) + { + try + { + _peersLock.EnterReadLock(); + for (var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + { + if (netPeer != excludePeer) + netPeer.Send(data, channelNumber, options); + } + } + finally + { + _peersLock.ExitReadLock(); + } + } + + /// + /// Send message without connection + /// + /// Raw data + /// Packet destination + /// Operation result + public bool SendUnconnectedMessage(ReadOnlySpan message, IPEndPoint remoteEndPoint) + { + int headerSize = NetPacket.GetHeaderSize(PacketProperty.UnconnectedMessage); + var packet = PoolGetPacket(message.Length + headerSize); + packet.Property = PacketProperty.UnconnectedMessage; + message.CopyTo(new Span(packet.RawData, headerSize, message.Length)); + return SendRawAndRecycle(packet, remoteEndPoint) > 0; + } +#endif + /// /// Start logic thread and listening on available port /// @@ -1454,29 +1468,42 @@ namespace LiteNetLib } /// - /// Receive all pending events. Call this in game update code + /// Receive "maxProcessedEvents" pending events. Call this in game update code /// In Manual mode it will call also socket Receive (which can be slow) + /// 0 - receive all events /// - public void PollEvents() + /// Max events that will be processed (called INetEventListener Connect/Receive/Etc), 0 - receive all events + public void PollEvents(int maxProcessedEvents = 0) { if (_manualMode) { if (_udpSocketv4 != null) - ManualReceive(_udpSocketv4, _bufferEndPointv4); + ManualReceive(_udpSocketv4, _bufferEndPointv4, maxProcessedEvents); if (_udpSocketv6 != null && _udpSocketv6 != _udpSocketv4) - ManualReceive(_udpSocketv6, _bufferEndPointv6); + ManualReceive(_udpSocketv6, _bufferEndPointv6, maxProcessedEvents); ProcessDelayedPackets(); return; } if (UnsyncedEvents) return; - lock (_netEventsProduceQueue) + NetEvent pendingEvent; + lock (_eventLock) { - (_netEventsConsumeQueue, _netEventsProduceQueue) = (_netEventsProduceQueue, _netEventsConsumeQueue); + pendingEvent = _pendingEventHead; + _pendingEventHead = null; + _pendingEventTail = null; } - while(_netEventsConsumeQueue.Count > 0) - ProcessEvent(_netEventsConsumeQueue.Dequeue()); + int counter = 0; + while (pendingEvent != null) + { + var next = pendingEvent.Next; + ProcessEvent(pendingEvent); + pendingEvent = next; + counter++; + if (counter == maxProcessedEvents) + break; + } } /// @@ -1527,7 +1554,6 @@ namespace LiteNetLib return Connect(target, NetDataWriter.FromString(key)); } - public bool IsClient { get; private set; } /// /// Connect to remote host /// @@ -1540,37 +1566,32 @@ namespace LiteNetLib if (!IsRunning) throw new InvalidOperationException("Client is not running"); - lock(_requestsDict) + lock (_requestsDict) { if (_requestsDict.ContainsKey(target)) return null; - } - byte connectionNumber = 0; - _peersLock.EnterUpgradeableReadLock(); - if (_peersDict.TryGetValue(target, out var peer)) - { - switch (peer.ConnectionState) + byte connectionNumber = 0; + if (TryGetPeer(target, out var peer)) { - //just return already connected peer - case ConnectionState.Connected: - case ConnectionState.Outgoing: - _peersLock.ExitUpgradeableReadLock(); - return peer; + switch (peer.ConnectionState) + { + //just return already connected peer + case ConnectionState.Connected: + case ConnectionState.Outgoing: + return peer; + } + //else reconnect + connectionNumber = (byte)((peer.ConnectionNum + 1) % NetConstants.MaxConnectionNumber); + RemovePeer(peer); } - //else reconnect - connectionNumber = (byte)((peer.ConnectionNum + 1) % NetConstants.MaxConnectionNumber); - RemovePeer(peer); + + //Create reliable connection + //And send connection request + peer = new NetPeer(this, target, GetNextPeerId(), connectionNumber, connectionData); + AddPeer(peer); + return peer; } - - //Create reliable connection - //And send connection request - peer = new NetPeer(this, target, GetNextPeerId(), connectionNumber, connectionData); - AddPeer(peer); - _peersLock.ExitUpgradeableReadLock(); - IsClient = true; - - return peer; } /// @@ -1591,13 +1612,20 @@ namespace LiteNetLib return; NetDebug.Write("[NM] Stop"); - IsClient = false; +#if UNITY_SOCKET_FIX + if (_useSocketFix) + { + _pausedSocketFix.Deinitialize(); + _pausedSocketFix = null; + } +#endif + //Send last disconnect - for(var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) + for (var netPeer = _headPeer; netPeer != null; netPeer = netPeer.NextPeer) netPeer.Shutdown(null, 0, 0, !sendDisconnectMessages); //Stop - CloseSocket(false); + CloseSocket(); _updateTriggerEvent.Set(); if (!_manualMode) { @@ -1606,20 +1634,16 @@ namespace LiteNetLib } //clear peers - _peersLock.EnterWriteLock(); - _headPeer = null; - _peersDict.Clear(); - _peersArray = new NetPeer[32]; - _peersLock.ExitWriteLock(); + ClearPeerSet(); _peerIds = new ConcurrentQueue(); - _lastPeerId = 0; + _nextPeerId = 0; #if DEBUG lock (_pingSimulationList) _pingSimulationList.Clear(); #endif _connectedPeersCount = 0; - _netEventsProduceQueue.Clear(); - _netEventsConsumeQueue.Clear(); + _pendingEventHead = null; + _pendingEventTail = null; } /// @@ -1754,7 +1778,7 @@ namespace LiteNetLib /// NTP Server address. public void CreateNtpRequest(IPEndPoint endPoint) { - _ntpRequests.Add(endPoint, new NtpRequest(endPoint)); + _ntpRequests.TryAdd(endPoint, new NtpRequest(endPoint)); } /// @@ -1765,7 +1789,7 @@ namespace LiteNetLib public void CreateNtpRequest(string ntpServerAddress, int port) { IPEndPoint endPoint = NetUtils.MakeEndPoint(ntpServerAddress, port); - _ntpRequests.Add(endPoint, new NtpRequest(endPoint)); + _ntpRequests.TryAdd(endPoint, new NtpRequest(endPoint)); } /// @@ -1775,7 +1799,7 @@ namespace LiteNetLib public void CreateNtpRequest(string ntpServerAddress) { IPEndPoint endPoint = NetUtils.MakeEndPoint(ntpServerAddress, NtpRequest.DefaultPort); - _ntpRequests.Add(endPoint, new NtpRequest(endPoint)); + _ntpRequests.TryAdd(endPoint, new NtpRequest(endPoint)); } public NetPeerEnumerator GetEnumerator() diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs index 7e29fe9..c1505d6 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPacket.cs @@ -1,5 +1,4 @@ using System; -using System.Net; using LiteNetLib.Utils; namespace LiteNetLib @@ -157,5 +156,9 @@ namespace LiteNetLib bool fragmented = (RawData[0] & 0x80) != 0; return Size >= headerSize && (!fragmented || Size >= headerSize + NetConstants.FragmentHeaderSize); } + + #if LITENETLIB_SPANS || NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1 || NETCOREAPP3_1 || NET5_0 || NETSTANDARD2_1 + public static implicit operator Span(NetPacket p) => new Span(p.RawData, 0, p.Size); + #endif } } diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs index 0ebf508..1852e69 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetPeer.cs @@ -50,7 +50,7 @@ namespace LiteNetLib /// /// Network peer. Main purpose is sending messages to specific peer. /// - public class NetPeer + public class NetPeer : IPEndPoint { //Ping and RTT private int _rtt; @@ -114,7 +114,6 @@ namespace LiteNetLib private int _mergeCount; //Connection - private IPEndPoint _remoteEndPoint; private int _connectAttempts; private int _connectTimer; private long _connectTime; @@ -128,11 +127,6 @@ namespace LiteNetLib private readonly NetPacket _connectRequestPacket; private readonly NetPacket _connectAcceptPacket; - /// - /// Peer ip address and port - /// - public IPEndPoint EndPoint => _remoteEndPoint; - /// /// Peer parent NetManager /// @@ -201,14 +195,48 @@ namespace LiteNetLib /// public readonly NetStatistics Statistics; + private SocketAddress _cachedSocketAddr; + private int _cachedHashCode; + + internal byte[] NativeAddress; + + /// + /// IPEndPoint serialize + /// + /// SocketAddress + public override SocketAddress Serialize() + { + return _cachedSocketAddr; + } + + public override int GetHashCode() + { + //uses SocketAddress hash in NET8 and IPEndPoint hash for NativeSockets and previous NET versions + return _cachedHashCode; + } + //incoming connection constructor - internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id) + internal NetPeer(NetManager netManager, IPEndPoint remoteEndPoint, int id) : base(remoteEndPoint.Address, remoteEndPoint.Port) { Id = id; Statistics = new NetStatistics(); NetManager = netManager; + + _cachedSocketAddr = base.Serialize(); + if (NetManager.UseNativeSockets) + { + NativeAddress = new byte[_cachedSocketAddr.Size]; + for (int i = 0; i < _cachedSocketAddr.Size; i++) + NativeAddress[i] = _cachedSocketAddr[i]; + } +#if NET8_0_OR_GREATER + _cachedHashCode = NetManager.UseNativeSockets ? base.GetHashCode() : _cachedSocketAddr.GetHashCode(); +#else + _cachedHashCode = base.GetHashCode(); +#endif + ResetMtu(); - _remoteEndPoint = remoteEndPoint; + _connectionState = ConnectionState.Connected; _mergeData = new NetPacket(PacketProperty.Merged, NetConstants.MaxPacketSize); _pongPacket = new NetPacket(PacketProperty.Pong, 0); @@ -233,7 +261,22 @@ namespace LiteNetLib if (_connectionState != ConnectionState.EndPointChange) return; _connectionState = ConnectionState.Connected; - _remoteEndPoint = newEndPoint; + + Address = newEndPoint.Address; + Port = newEndPoint.Port; + + if (NetManager.UseNativeSockets) + { + NativeAddress = new byte[_cachedSocketAddr.Size]; + for (int i = 0; i < _cachedSocketAddr.Size; i++) + NativeAddress[i] = _cachedSocketAddr[i]; + } + _cachedSocketAddr = base.Serialize(); +#if NET8_0_OR_GREATER + _cachedHashCode = NetManager.UseNativeSockets ? base.GetHashCode() : _cachedSocketAddr.GetHashCode(); +#else + _cachedHashCode = base.GetHashCode(); +#endif } internal void ResetMtu() @@ -357,7 +400,7 @@ namespace LiteNetLib _connectRequestPacket.ConnectionNumber = connectNum; //Send request - NetManager.SendRaw(_connectRequestPacket, _remoteEndPoint); + NetManager.SendRaw(_connectRequestPacket, this); NetDebug.Write(NetLogLevel.Trace, $"[CC] ConnectId: {_connectTime}, ConnectNum: {connectNum}"); } @@ -377,7 +420,7 @@ namespace LiteNetLib _connectionState = ConnectionState.Connected; //Send - NetManager.SendRaw(_connectAcceptPacket, _remoteEndPoint); + NetManager.SendRaw(_connectAcceptPacket, this); NetDebug.Write(NetLogLevel.Trace, $"[CC] ConnectId: {_connectTime}"); } @@ -435,7 +478,7 @@ namespace LiteNetLib { if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); - Send_Internal(data, 0, data.Length, channelNumber, deliveryMethod, userData); + SendInternal(data, 0, data.Length, channelNumber, deliveryMethod, userData); } /// @@ -454,7 +497,7 @@ namespace LiteNetLib { if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); - Send_Internal(data, start, length, channelNumber, deliveryMethod, userData); + SendInternal(data, start, length, channelNumber, deliveryMethod, userData); } /// @@ -471,7 +514,7 @@ namespace LiteNetLib { if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); - Send_Internal(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod, userData); + SendInternal(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod, userData); } /// @@ -486,7 +529,7 @@ namespace LiteNetLib /// public void Send(byte[] data, DeliveryMethod deliveryMethod) { - Send_Internal(data, 0, data.Length, 0, deliveryMethod, null); + SendInternal(data, 0, data.Length, 0, deliveryMethod, null); } /// @@ -501,7 +544,7 @@ namespace LiteNetLib /// public void Send(NetDataWriter dataWriter, DeliveryMethod deliveryMethod) { - Send_Internal(dataWriter.Data, 0, dataWriter.Length, 0, deliveryMethod, null); + SendInternal(dataWriter.Data, 0, dataWriter.Length, 0, deliveryMethod, null); } /// @@ -518,7 +561,7 @@ namespace LiteNetLib /// public void Send(byte[] data, int start, int length, DeliveryMethod options) { - Send_Internal(data, start, length, 0, options, null); + SendInternal(data, start, length, 0, options, null); } /// @@ -534,7 +577,7 @@ namespace LiteNetLib /// public void Send(byte[] data, byte channelNumber, DeliveryMethod deliveryMethod) { - Send_Internal(data, 0, data.Length, channelNumber, deliveryMethod, null); + SendInternal(data, 0, data.Length, channelNumber, deliveryMethod, null); } /// @@ -550,7 +593,7 @@ namespace LiteNetLib /// public void Send(NetDataWriter dataWriter, byte channelNumber, DeliveryMethod deliveryMethod) { - Send_Internal(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod, null); + SendInternal(dataWriter.Data, 0, dataWriter.Length, channelNumber, deliveryMethod, null); } /// @@ -568,10 +611,10 @@ namespace LiteNetLib /// public void Send(byte[] data, int start, int length, byte channelNumber, DeliveryMethod deliveryMethod) { - Send_Internal(data, start, length, channelNumber, deliveryMethod, null); + SendInternal(data, start, length, channelNumber, deliveryMethod, null); } - private void Send_Internal( + private void SendInternal( byte[] data, int start, int length, @@ -613,13 +656,12 @@ namespace LiteNetLib int packetDataSize = packetFullSize - NetConstants.FragmentHeaderSize; int totalPackets = length / packetDataSize + (length % packetDataSize == 0 ? 0 : 1); - NetDebug.Write("FragmentSend:\n" + - " MTU: {0}\n" + - " headerSize: {1}\n" + - " packetFullSize: {2}\n" + - " packetDataSize: {3}\n" + - " totalPackets: {4}", - mtu, headerSize, packetFullSize, packetDataSize, totalPackets); + NetDebug.Write($@"FragmentSend: + MTU: {mtu} + headerSize: {headerSize} + packetFullSize: {packetFullSize} + packetDataSize: {packetDataSize} + totalPackets: {totalPackets}"); if (totalPackets > ushort.MaxValue) throw new TooBigPacketException("Data was split in " + totalPackets + " fragments, which exceeds " + ushort.MaxValue); @@ -678,7 +720,7 @@ namespace LiteNetLib { if (deliveryMethod != DeliveryMethod.ReliableOrdered && deliveryMethod != DeliveryMethod.ReliableUnordered) throw new ArgumentException("Delivery event will work only for ReliableOrdered/Unordered packets"); - Send_Internal(data, channelNumber, deliveryMethod, userData); + SendInternal(data, channelNumber, deliveryMethod, userData); } /// @@ -693,7 +735,7 @@ namespace LiteNetLib /// public void Send(ReadOnlySpan data, DeliveryMethod deliveryMethod) { - Send_Internal(data, 0, deliveryMethod, null); + SendInternal(data, 0, deliveryMethod, null); } /// @@ -709,10 +751,10 @@ namespace LiteNetLib /// public void Send(ReadOnlySpan data, byte channelNumber, DeliveryMethod deliveryMethod) { - Send_Internal(data, channelNumber, deliveryMethod, null); + SendInternal(data, channelNumber, deliveryMethod, null); } - private void Send_Internal( + private void SendInternal( ReadOnlySpan data, byte channelNumber, DeliveryMethod deliveryMethod, @@ -874,7 +916,7 @@ namespace LiteNetLib } _connectionState = ConnectionState.ShutdownRequested; NetDebug.Write("[Peer] Send disconnect"); - NetManager.SendRaw(_shutdownPacket, _remoteEndPoint); + NetManager.SendRaw(_shutdownPacket, this); return result; } } @@ -891,7 +933,7 @@ namespace LiteNetLib { if (p.IsFragmented) { - NetDebug.Write("Fragment. Id: {0}, Part: {1}, Total: {2}", p.FragmentId, p.FragmentPart, p.FragmentsTotal); + NetDebug.Write($"Fragment. Id: {p.FragmentId}, Part: {p.FragmentPart}, Total: {p.FragmentsTotal}"); //Get needed array from dictionary ushort packetFragId = p.FragmentId; byte packetChannelId = p.ChannelId; @@ -942,16 +984,13 @@ namespace LiteNetLib if (pos+writtenSize > resultingPacket.RawData.Length) { _holdedFragments.Remove(packetFragId); - NetDebug.WriteError("Fragment error pos: {0} >= resultPacketSize: {1} , totalSize: {2}", - pos + writtenSize, - resultingPacket.RawData.Length, - incomingFragments.TotalSize); + NetDebug.WriteError($"Fragment error pos: {pos + writtenSize} >= resultPacketSize: {resultingPacket.RawData.Length} , totalSize: {incomingFragments.TotalSize}"); return; } if (fragment.Size > fragment.RawData.Length) { _holdedFragments.Remove(packetFragId); - NetDebug.WriteError("Fragment error size: {0} > fragment.RawData.Length: {1}", fragment.Size, fragment.RawData.Length); + NetDebug.WriteError($"Fragment error size: {fragment.Size} > fragment.RawData.Length: {fragment.RawData.Length}"); return; } @@ -992,7 +1031,7 @@ namespace LiteNetLib int endMtuCheck = BitConverter.ToInt32(packet.RawData, packet.Size - 4); if (receivedMtu != packet.Size || receivedMtu != endMtuCheck || receivedMtu > NetConstants.MaxPacketSize) { - NetDebug.WriteError("[MTU] Broken packet. RMTU {0}, EMTU {1}, PSIZE {2}", receivedMtu, endMtuCheck, packet.Size); + NetDebug.WriteError($"[MTU] Broken packet. RMTU {receivedMtu}, EMTU {endMtuCheck}, PSIZE {packet.Size}"); return; } @@ -1001,7 +1040,7 @@ namespace LiteNetLib _mtuCheckAttempts = 0; NetDebug.Write("[MTU] check. send back: " + receivedMtu); packet.Property = PacketProperty.MtuOk; - NetManager.SendRawAndRecycle(packet, _remoteEndPoint); + NetManager.SendRawAndRecycle(packet, this); } else if(receivedMtu > _mtu && !_finishMtu) //MtuOk { @@ -1051,7 +1090,7 @@ namespace LiteNetLib FastBitConverter.GetBytes(p.RawData, p.Size - 4, newMtu);//and end of packet //Must check result for MTU fix - if (NetManager.SendRawAndRecycle(p, _remoteEndPoint) <= 0) + if (NetManager.SendRawAndRecycle(p, this) <= 0) _finishMtu = true; } } @@ -1071,11 +1110,10 @@ namespace LiteNetLib //slow rare case check if (connRequest.ConnectionTime == _connectTime) { - var remoteBytes = _remoteEndPoint.Serialize(); var localBytes = connRequest.TargetAddress; - for (int i = remoteBytes.Size-1; i >= 0; i--) + for (int i = _cachedSocketAddr.Size-1; i >= 0; i--) { - byte rb = remoteBytes[i]; + byte rb = _cachedSocketAddr[i]; if (rb == localBytes[i]) continue; if (rb < localBytes[i]) @@ -1089,7 +1127,7 @@ namespace LiteNetLib if (connRequest.ConnectionTime == _connectTime) { //just reply accept - NetManager.SendRaw(_connectAcceptPacket, _remoteEndPoint); + NetManager.SendRaw(_connectAcceptPacket, this); } //New connect request else if (connRequest.ConnectionTime > _connectTime) @@ -1131,7 +1169,7 @@ namespace LiteNetLib } Interlocked.Exchange(ref _timeSinceLastPacket, 0); - NetDebug.Write("[RR]PacketProperty: {0}", packet.Property); + NetDebug.Write($"[RR]PacketProperty: {packet.Property}"); switch (packet.Property) { case PacketProperty.Merged: @@ -1162,7 +1200,7 @@ namespace LiteNetLib NetDebug.Write("[PP]Ping receive, send pong"); FastBitConverter.GetBytes(_pongPacket.RawData, 3, DateTime.UtcNow.Ticks); _pongPacket.Sequence = packet.Sequence; - NetManager.SendRaw(_pongPacket, _remoteEndPoint); + NetManager.SendRaw(_pongPacket, this); } NetManager.PoolRecycle(packet); break; @@ -1176,14 +1214,14 @@ namespace LiteNetLib _remoteDelta = BitConverter.ToInt64(packet.RawData, 3) + (elapsedMs * TimeSpan.TicksPerMillisecond ) / 2 - DateTime.UtcNow.Ticks; UpdateRoundTripTime(elapsedMs); NetManager.ConnectionLatencyUpdated(this, elapsedMs / 2); - NetDebug.Write("[PP]Ping: {0} - {1} - {2}", packet.Sequence, elapsedMs, _remoteDelta); + NetDebug.Write($"[PP]Ping: {packet.Sequence} - {elapsedMs} - {_remoteDelta}"); } NetManager.PoolRecycle(packet); break; case PacketProperty.Ack: case PacketProperty.Channeled: - if (packet.ChannelId > _channels.Length) + if (packet.ChannelId >= _channels.Length) { NetManager.PoolRecycle(packet); break; @@ -1220,12 +1258,12 @@ namespace LiteNetLib if (_mergeCount > 1) { NetDebug.Write("[P]Send merged: " + _mergePos + ", count: " + _mergeCount); - bytesSent = NetManager.SendRaw(_mergeData.RawData, 0, NetConstants.HeaderSize + _mergePos, _remoteEndPoint); + bytesSent = NetManager.SendRaw(_mergeData.RawData, 0, NetConstants.HeaderSize + _mergePos, this); } else { //Send without length information and merging - bytesSent = NetManager.SendRaw(_mergeData.RawData, NetConstants.HeaderSize + 2, _mergePos - 2, _remoteEndPoint); + bytesSent = NetManager.SendRaw(_mergeData.RawData, NetConstants.HeaderSize + 2, _mergePos - 2, this); } if (NetManager.EnableStatistics) @@ -1246,7 +1284,7 @@ namespace LiteNetLib if (mergedPacketSize + sizeTreshold >= _mtu) { NetDebug.Write(NetLogLevel.Trace, "[P]SendingPacket: " + packet.Property); - int bytesSent = NetManager.SendRaw(packet, _remoteEndPoint); + int bytesSent = NetManager.SendRaw(packet, this); if (NetManager.EnableStatistics) { @@ -1274,10 +1312,7 @@ namespace LiteNetLib case ConnectionState.Connected: if (_timeSinceLastPacket > NetManager.DisconnectTimeout) { - NetDebug.Write( - "[UPDATE] Disconnect by timeout: {0} > {1}", - _timeSinceLastPacket, - NetManager.DisconnectTimeout); + NetDebug.Write($"[UPDATE] Disconnect by timeout: {_timeSinceLastPacket} > {NetManager.DisconnectTimeout}"); NetManager.DisconnectPeerForce(this, DisconnectReason.Timeout, 0, null); return; } @@ -1294,7 +1329,7 @@ namespace LiteNetLib if (_shutdownTimer >= ShutdownDelay) { _shutdownTimer = 0; - NetManager.SendRaw(_shutdownPacket, _remoteEndPoint); + NetManager.SendRaw(_shutdownPacket, this); } } return; @@ -1312,7 +1347,7 @@ namespace LiteNetLib } //else send connect again - NetManager.SendRaw(_connectRequestPacket, _remoteEndPoint); + NetManager.SendRaw(_connectRequestPacket, this); } return; @@ -1333,7 +1368,7 @@ namespace LiteNetLib if (_pingTimer.IsRunning) UpdateRoundTripTime((int)_pingTimer.ElapsedMilliseconds); _pingTimer.Restart(); - NetManager.SendRaw(_pingPacket, _remoteEndPoint); + NetManager.SendRaw(_pingPacket, this); } //RTT - round trip time diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs index d162b2d..f7b2bd8 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/NetUtils.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net; using System.Net.Sockets; using System.Net.NetworkInformation; @@ -22,6 +23,8 @@ namespace LiteNetLib /// public static class NetUtils { + private static readonly NetworkSorter NetworkSorter = new NetworkSorter(); + public static IPEndPoint MakeEndPoint(string hostStr, int port) { return new IPEndPoint(ResolveAddress(hostStr), port); @@ -81,7 +84,12 @@ namespace LiteNetLib bool ipv6 = (addrType & LocalAddrType.IPv6) == LocalAddrType.IPv6; try { - foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) + // Sort networks interfaces so it prefer Wifi over Cellular networks + // Most cellulars networks seems to be incompatible with NAT Punch + var networks = NetworkInterface.GetAllNetworkInterfaces(); + Array.Sort(networks, NetworkSorter); + + foreach (NetworkInterface ni in networks) { //Skip loopback and disabled network interfaces if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback || @@ -119,7 +127,7 @@ namespace LiteNetLib { //ignored } - + if (targetList.Count == 0) { if(ipv4) @@ -150,7 +158,7 @@ namespace LiteNetLib // =========================================== internal static void PrintInterfaceInfos() { - NetDebug.WriteForce(NetLogLevel.Info, "IPv6Support: {0}", NetManager.IPv6Support); + NetDebug.WriteForce(NetLogLevel.Info, $"IPv6Support: { NetManager.IPv6Support}"); try { foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) @@ -162,18 +170,14 @@ namespace LiteNetLib { NetDebug.WriteForce( NetLogLevel.Info, - "Interface: {0}, Type: {1}, Ip: {2}, OpStatus: {3}", - ni.Name, - ni.NetworkInterfaceType.ToString(), - ip.Address.ToString(), - ni.OperationalStatus.ToString()); + $"Interface: {ni.Name}, Type: {ni.NetworkInterfaceType}, Ip: {ip.Address}, OpStatus: {ni.OperationalStatus}"); } } } } catch (Exception e) { - NetDebug.WriteForce(NetLogLevel.Info, "Error while getting interface infos: {0}", e.ToString()); + NetDebug.WriteForce(NetLogLevel.Info, $"Error while getting interface infos: {e}"); } } @@ -191,4 +195,44 @@ namespace LiteNetLib #endif } } + + // Pick the most obvious choice for the local IP + // Ethernet > Wifi > Others > Cellular + internal class NetworkSorter : IComparer + { + [SuppressMessage("ReSharper", "PossibleNullReferenceException")] + public int Compare(NetworkInterface a, NetworkInterface b) + { + var isCellularA = a.NetworkInterfaceType == NetworkInterfaceType.Wman || + a.NetworkInterfaceType == NetworkInterfaceType.Wwanpp || + a.NetworkInterfaceType == NetworkInterfaceType.Wwanpp2; + + var isCellularB = b.NetworkInterfaceType == NetworkInterfaceType.Wman || + b.NetworkInterfaceType == NetworkInterfaceType.Wwanpp || + b.NetworkInterfaceType == NetworkInterfaceType.Wwanpp2; + + var isWifiA = a.NetworkInterfaceType == NetworkInterfaceType.Wireless80211; + var isWifiB = b.NetworkInterfaceType == NetworkInterfaceType.Wireless80211; + + var isEthernetA = a.NetworkInterfaceType == NetworkInterfaceType.Ethernet || + a.NetworkInterfaceType == NetworkInterfaceType.Ethernet3Megabit || + a.NetworkInterfaceType == NetworkInterfaceType.GigabitEthernet || + a.NetworkInterfaceType == NetworkInterfaceType.FastEthernetFx || + a.NetworkInterfaceType == NetworkInterfaceType.FastEthernetT; + + var isEthernetB = b.NetworkInterfaceType == NetworkInterfaceType.Ethernet || + b.NetworkInterfaceType == NetworkInterfaceType.Ethernet3Megabit || + b.NetworkInterfaceType == NetworkInterfaceType.GigabitEthernet || + b.NetworkInterfaceType == NetworkInterfaceType.FastEthernetFx || + b.NetworkInterfaceType == NetworkInterfaceType.FastEthernetT; + + var isOtherA = !isCellularA && !isWifiA && !isEthernetA; + var isOtherB = !isCellularB && !isWifiB && !isEthernetB; + + var priorityA = isEthernetA ? 3 : isWifiA ? 2 : isOtherA ? 1 : 0; + var priorityB = isEthernetB ? 3 : isWifiB ? 2 : isOtherB ? 1 : 0; + + return priorityA > priorityB ? -1 : priorityA < priorityB ? 1 : 0; + } + } } diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PausedSocketFix.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PausedSocketFix.cs new file mode 100644 index 0000000..dc92122 --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PausedSocketFix.cs @@ -0,0 +1,57 @@ +#if UNITY_2018_3_OR_NEWER +using System.Net; + +namespace LiteNetLib +{ + public class PausedSocketFix + { + private readonly NetManager _netManager; + private readonly IPAddress _ipv4; + private readonly IPAddress _ipv6; + private readonly int _port; + private readonly bool _manualMode; + private bool _initialized; + + public PausedSocketFix(NetManager netManager, IPAddress ipv4, IPAddress ipv6, int port, bool manualMode) + { + _netManager = netManager; + _ipv4 = ipv4; + _ipv6 = ipv6; + _port = port; + _manualMode = manualMode; + UnityEngine.Application.focusChanged += Application_focusChanged; + _initialized = true; + } + + public void Deinitialize() + { + if (_initialized) + UnityEngine.Application.focusChanged -= Application_focusChanged; + _initialized = false; + } + + private void Application_focusChanged(bool focused) + { + //If coming back into focus see if a reconnect is needed. + if (focused) + { + //try reconnect + if (!_initialized) + return; + //Was intentionally disconnected at some point. + if (!_netManager.IsRunning) + return; + //Socket is in working state. + if (_netManager.NotConnected == false) + return; + + //Socket isn't running but should be. Try to start again. + if (!_netManager.Start(_ipv4, _ipv6, _port, _manualMode)) + { + NetDebug.WriteError($"[S] Cannot restore connection. Ipv4 {_ipv4}, Ipv6 {_ipv6}, Port {_port}, ManualMode {_manualMode}"); + } + } + } + } +} +#endif diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PausedSocketFix.cs.meta b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PausedSocketFix.cs.meta new file mode 100644 index 0000000..dc24789 --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/PausedSocketFix.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 85ea50adb87db074c9a1c587f35aebb2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs index f825e37..4a10d17 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/ReliableChannel.cs @@ -33,7 +33,7 @@ namespace LiteNetLib double packetHoldTime = currentTime - _timeStamp; if (packetHoldTime < resendDelay) return true; - NetDebug.Write("[RC]Resend: {0} > {1}", (int)packetHoldTime, resendDelay); + NetDebug.Write($"[RC]Resend: {packetHoldTime} > {resendDelay}"); } _timeStamp = currentTime; _isSent = true; @@ -148,7 +148,7 @@ namespace LiteNetLib } //Skip false ack - NetDebug.Write("[PA]False ack: {0}", pendingSeq); + NetDebug.Write($"[PA]False ack: {pendingSeq}"); continue; } @@ -160,7 +160,7 @@ namespace LiteNetLib //clear packet if (_pendingPackets[pendingIdx].Clear(Peer)) - NetDebug.Write("[PA]Removing reliableInOrder ack: {0} - true", pendingSeq); + NetDebug.Write($"[PA]Removing reliableInOrder ack: {pendingSeq} - true"); } } } @@ -181,19 +181,20 @@ namespace LiteNetLib lock (_pendingPackets) { //get packets from queue - while (!OutgoingQueue.IsEmpty) + lock (OutgoingQueue) { - int relate = NetUtils.RelativeSequenceNumber(_localSeqence, _localWindowStart); - if (relate >= _windowSize) - break; + while (OutgoingQueue.Count > 0) + { + int relate = NetUtils.RelativeSequenceNumber(_localSeqence, _localWindowStart); + if (relate >= _windowSize) + break; - if (!OutgoingQueue.TryDequeue(out var netPacket)) - break; - - netPacket.Sequence = (ushort) _localSeqence; - netPacket.ChannelId = _id; - _pendingPackets[_localSeqence % _windowSize].Init(netPacket); - _localSeqence = (_localSeqence + 1) % NetConstants.MaxSequence; + var netPacket = OutgoingQueue.Dequeue(); + netPacket.Sequence = (ushort) _localSeqence; + netPacket.ChannelId = _id; + _pendingPackets[_localSeqence % _windowSize].Init(netPacket); + _localSeqence = (_localSeqence + 1) % NetConstants.MaxSequence; + } } //send @@ -205,7 +206,7 @@ namespace LiteNetLib } } - return hasPendingPackets || _mustSendAcks || !OutgoingQueue.IsEmpty; + return hasPendingPackets || _mustSendAcks || OutgoingQueue.Count > 0; } //Process incoming packet diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs index a3763ee..bc47f86 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/SequencedChannel.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace LiteNetLib { @@ -39,21 +39,25 @@ namespace LiteNetLib } else { - while (OutgoingQueue.TryDequeue(out var packet)) + lock (OutgoingQueue) { - _localSequence = (_localSequence + 1) % NetConstants.MaxSequence; - packet.Sequence = (ushort)_localSequence; - packet.ChannelId = _id; - Peer.SendUserData(packet); + while (OutgoingQueue.Count > 0) + { + NetPacket packet = OutgoingQueue.Dequeue(); + _localSequence = (_localSequence + 1) % NetConstants.MaxSequence; + packet.Sequence = (ushort)_localSequence; + packet.ChannelId = _id; + Peer.SendUserData(packet); - if (_reliable && OutgoingQueue.Count == 0) - { - _lastPacketSendTime = DateTime.UtcNow.Ticks; - _lastPacket = packet; - } - else - { - Peer.NetManager.PoolRecycle(packet); + if (_reliable && OutgoingQueue.Count == 0) + { + _lastPacketSendTime = DateTime.UtcNow.Ticks; + _lastPacket = packet; + } + else + { + Peer.NetManager.PoolRecycle(packet); + } } } } diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Trimming.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Trimming.cs new file mode 100644 index 0000000..6c575b6 --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Trimming.cs @@ -0,0 +1,12 @@ +#if NET5_0_OR_GREATER +using System.Diagnostics.CodeAnalysis; +using static System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes; + +namespace LiteNetLib +{ + internal static class Trimming + { + internal const DynamicallyAccessedMemberTypes SerializerMemberTypes = PublicProperties | NonPublicProperties; + } +} +#endif diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Trimming.cs.meta b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Trimming.cs.meta new file mode 100644 index 0000000..66fa16d --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Trimming.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af5a9e06ff14c6c42ab091c2c19e2028 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs index 3ecd10c..82bedf4 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/FastBitConverter.cs @@ -6,7 +6,7 @@ namespace LiteNetLib.Utils { public static class FastBitConverter { -#if (LITENETLIB_UNSAFE || LITENETLIB_UNSAFELIB || NETCOREAPP3_1 || NET5_0 || NETCOREAPP3_0_OR_GREATER) && !BIGENDIAN +#if (LITENETLIB_UNSAFE || NETCOREAPP3_1 || NET5_0 || NETCOREAPP3_0_OR_GREATER) && !BIGENDIAN #if LITENETLIB_UNSAFE [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void GetBytes(byte[] bytes, int startIndex, T value) where T : unmanaged @@ -14,7 +14,7 @@ namespace LiteNetLib.Utils int size = sizeof(T); if (bytes.Length < startIndex + size) ThrowIndexOutOfRangeException(); -#if LITENETLIB_UNSAFELIB || NETCOREAPP3_1 || NET5_0 || NETCOREAPP3_0_OR_GREATER +#if NETCOREAPP3_1 || NET5_0 || NETCOREAPP3_0_OR_GREATER Unsafe.As(ref bytes[startIndex]) = value; #else fixed (byte* ptr = &bytes[startIndex]) diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs index 7022265..86ff9c4 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataReader.cs @@ -1,6 +1,6 @@ using System; using System.Net; -using System.Text; +using System.Runtime.CompilerServices; namespace LiteNetLib.Utils { @@ -11,19 +11,46 @@ namespace LiteNetLib.Utils protected int _dataSize; private int _offset; - public byte[] RawData => _data; - public int RawDataSize => _dataSize; - public int UserDataOffset => _offset; - public int UserDataSize => _dataSize - _offset; - public bool IsNull => _data == null; - public int Position => _position; - public bool EndOfData => _position == _dataSize; - public int AvailableBytes => _dataSize - _position; - - // Cache encoding instead of creating it with BinaryWriter each time - // 1000 readers before: 1MB GC, 30ms - // 1000 readers after: .8MB GC, 18ms - private static readonly UTF8Encoding _uTF8Encoding = new UTF8Encoding(false, true); + public byte[] RawData + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data; + } + public int RawDataSize + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _dataSize; + } + public int UserDataOffset + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _offset; + } + public int UserDataSize + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _dataSize - _offset; + } + public bool IsNull + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data == null; + } + public int Position + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _position; + } + public bool EndOfData + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _position == _dataSize; + } + public int AvailableBytes + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _dataSize - _position; + } public void SkipBytes(int count) { @@ -80,6 +107,94 @@ namespace LiteNetLib.Utils } #region GetMethods + + public void Get(out T result) where T : struct, INetSerializable + { + result = default(T); + result.Deserialize(this); + } + + public void Get(out T result, Func constructor) where T : class, INetSerializable + { + result = constructor(); + result.Deserialize(this); + } + + public void Get(out IPEndPoint result) + { + result = GetNetEndPoint(); + } + + public void Get(out byte result) + { + result = GetByte(); + } + + public void Get(out sbyte result) + { + result = (sbyte)GetByte(); + } + + public void Get(out bool result) + { + result = GetBool(); + } + + public void Get(out char result) + { + result = GetChar(); + } + + public void Get(out ushort result) + { + result = GetUShort(); + } + + public void Get(out short result) + { + result = GetShort(); + } + + public void Get(out ulong result) + { + result = GetULong(); + } + + public void Get(out long result) + { + result = GetLong(); + } + + public void Get(out uint result) + { + result = GetUInt(); + } + + public void Get(out int result) + { + result = GetInt(); + } + + public void Get(out double result) + { + result = GetDouble(); + } + + public void Get(out float result) + { + result = GetFloat(); + } + + public void Get(out string result) + { + result = GetString(); + } + + public void Get(out string result, int maxLength) + { + result = GetString(maxLength); + } + public IPEndPoint GetNetEndPoint() { string host = GetString(1000); @@ -90,123 +205,105 @@ namespace LiteNetLib.Utils public byte GetByte() { byte res = _data[_position]; - _position += 1; + _position++; return res; } public sbyte GetSByte() { - var b = (sbyte)_data[_position]; - _position++; - return b; + return (sbyte)GetByte(); } + public T[] GetArray(ushort size) + { + ushort length = BitConverter.ToUInt16(_data, _position); + _position += 2; + T[] result = new T[length]; + length *= size; + Buffer.BlockCopy(_data, _position, result, 0, length); + _position += length; + return result; + } + + public T[] GetArray() where T : INetSerializable, new() + { + ushort length = BitConverter.ToUInt16(_data, _position); + _position += 2; + T[] result = new T[length]; + for (int i = 0; i < length; i++) + { + var item = new T(); + item.Deserialize(this); + result[i] = item; + } + return result; + } + public bool[] GetBoolArray() { - ushort size = BitConverter.ToUInt16(_data, _position); - _position += 2; - var arr = new bool[size]; - Buffer.BlockCopy(_data, _position, arr, 0, size); - _position += size; - return arr; + return GetArray(1); } public ushort[] GetUShortArray() { - ushort size = BitConverter.ToUInt16(_data, _position); - _position += 2; - var arr = new ushort[size]; - Buffer.BlockCopy(_data, _position, arr, 0, size * 2); - _position += size * 2; - return arr; + return GetArray(2); } public short[] GetShortArray() { - ushort size = BitConverter.ToUInt16(_data, _position); - _position += 2; - var arr = new short[size]; - Buffer.BlockCopy(_data, _position, arr, 0, size * 2); - _position += size * 2; - return arr; - } - - public long[] GetLongArray() - { - ushort size = BitConverter.ToUInt16(_data, _position); - _position += 2; - var arr = new long[size]; - Buffer.BlockCopy(_data, _position, arr, 0, size * 8); - _position += size * 8; - return arr; - } - - public ulong[] GetULongArray() - { - ushort size = BitConverter.ToUInt16(_data, _position); - _position += 2; - var arr = new ulong[size]; - Buffer.BlockCopy(_data, _position, arr, 0, size * 8); - _position += size * 8; - return arr; + return GetArray(2); } public int[] GetIntArray() { - ushort size = BitConverter.ToUInt16(_data, _position); - _position += 2; - var arr = new int[size]; - Buffer.BlockCopy(_data, _position, arr, 0, size * 4); - _position += size * 4; - return arr; + return GetArray(4); } public uint[] GetUIntArray() { - ushort size = BitConverter.ToUInt16(_data, _position); - _position += 2; - var arr = new uint[size]; - Buffer.BlockCopy(_data, _position, arr, 0, size * 4); - _position += size * 4; - return arr; + return GetArray(4); } public float[] GetFloatArray() { - ushort size = BitConverter.ToUInt16(_data, _position); - _position += 2; - var arr = new float[size]; - Buffer.BlockCopy(_data, _position, arr, 0, size * 4); - _position += size * 4; - return arr; + return GetArray(4); } public double[] GetDoubleArray() { - ushort size = BitConverter.ToUInt16(_data, _position); - _position += 2; - var arr = new double[size]; - Buffer.BlockCopy(_data, _position, arr, 0, size * 8); - _position += size * 8; - return arr; + return GetArray(8); + } + + public long[] GetLongArray() + { + return GetArray(8); + } + + public ulong[] GetULongArray() + { + return GetArray(8); } public string[] GetStringArray() { - ushort arraySize = GetUShort(); - var arr = new string[arraySize]; - for (int i = 0; i < arraySize; i++) + ushort length = GetUShort(); + string[] arr = new string[length]; + for (int i = 0; i < length; i++) { arr[i] = GetString(); } return arr; } + /// + /// Note that "maxStringLength" only limits the number of characters in a string, not its size in bytes. + /// Strings that exceed this parameter are returned as empty + /// public string[] GetStringArray(int maxStringLength) { - ushort arraySize = GetUShort(); - var arr = new string[arraySize]; - for (int i = 0; i < arraySize; i++) + ushort length = GetUShort(); + string[] arr = new string[length]; + for (int i = 0; i < length; i++) { arr[i] = GetString(maxStringLength); } @@ -215,9 +312,7 @@ namespace LiteNetLib.Utils public bool GetBool() { - bool res = _data[_position] > 0; - _position += 1; - return res; + return GetByte() == 1; } public char GetChar() @@ -290,7 +385,7 @@ namespace LiteNetLib.Utils ushort size = GetUShort(); if (size == 0) { - return null; + return string.Empty; } int actualSize = size - 1; @@ -301,9 +396,9 @@ namespace LiteNetLib.Utils ArraySegment data = GetBytesSegment(actualSize); - return (maxLength > 0 && _uTF8Encoding.GetCharCount(data.Array, data.Offset, data.Count) > maxLength) ? + return (maxLength > 0 && NetDataWriter.uTF8Encoding.Value.GetCharCount(data.Array, data.Offset, data.Count) > maxLength) ? string.Empty : - _uTF8Encoding.GetString(data.Array, data.Offset, data.Count); + NetDataWriter.uTF8Encoding.Value.GetString(data.Array, data.Offset, data.Count); } public string GetString() @@ -311,7 +406,7 @@ namespace LiteNetLib.Utils ushort size = GetUShort(); if (size == 0) { - return null; + return string.Empty; } int actualSize = size - 1; @@ -322,7 +417,7 @@ namespace LiteNetLib.Utils ArraySegment data = GetBytesSegment(actualSize); - return _uTF8Encoding.GetString(data.Array, data.Offset, data.Count); + return NetDataWriter.uTF8Encoding.Value.GetString(data.Array, data.Offset, data.Count); } public ArraySegment GetBytesSegment(int count) @@ -339,13 +434,28 @@ namespace LiteNetLib.Utils return segment; } - public T Get() where T : INetSerializable, new() + public T Get() where T : struct, INetSerializable { - var obj = new T(); + var obj = default(T); obj.Deserialize(this); return obj; } + public T Get(Func constructor) where T : class, INetSerializable + { + var obj = constructor(); + obj.Deserialize(this); + return obj; + } + +#if LITENETLIB_SPANS || NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1 || NETCOREAPP3_1 || NET5_0 || NETSTANDARD2_1 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan GetRemainingBytesSpan() + { + return new ReadOnlySpan(_data, _position, _dataSize - _position); + } +#endif + public byte[] GetRemainingBytes() { byte[] outgoingData = new byte[AvailableBytes]; @@ -368,20 +478,12 @@ namespace LiteNetLib.Utils public sbyte[] GetSBytesWithLength() { - int length = GetInt(); - sbyte[] outgoingData = new sbyte[length]; - Buffer.BlockCopy(_data, _position, outgoingData, 0, length); - _position += length; - return outgoingData; + return GetArray(1); } public byte[] GetBytesWithLength() { - int length = GetInt(); - byte[] outgoingData = new byte[length]; - Buffer.BlockCopy(_data, _position, outgoingData, 0, length); - _position += length; - return outgoingData; + return GetArray(1); } #endregion @@ -399,7 +501,7 @@ namespace LiteNetLib.Utils public bool PeekBool() { - return _data[_position] > 0; + return _data[_position] == 1; } public char PeekChar() @@ -447,12 +549,15 @@ namespace LiteNetLib.Utils return BitConverter.ToDouble(_data, _position); } + /// + /// Note that "maxLength" only limits the number of characters in a string, not its size in bytes. + /// public string PeekString(int maxLength) { ushort size = PeekUShort(); if (size == 0) { - return null; + return string.Empty; } int actualSize = size - 1; @@ -461,9 +566,9 @@ namespace LiteNetLib.Utils return null; } - return (maxLength > 0 && _uTF8Encoding.GetCharCount(_data, _position + 2, actualSize) > maxLength) ? + return (maxLength > 0 && NetDataWriter.uTF8Encoding.Value.GetCharCount(_data, _position + 2, actualSize) > maxLength) ? string.Empty : - _uTF8Encoding.GetString(_data, _position + 2, actualSize); + NetDataWriter.uTF8Encoding.Value.GetString(_data, _position + 2, actualSize); } public string PeekString() @@ -471,7 +576,7 @@ namespace LiteNetLib.Utils ushort size = PeekUShort(); if (size == 0) { - return null; + return string.Empty; } int actualSize = size - 1; @@ -480,7 +585,7 @@ namespace LiteNetLib.Utils return null; } - return _uTF8Encoding.GetString(_data, _position + 2, actualSize); + return NetDataWriter.uTF8Encoding.Value.GetString(_data, _position + 2, actualSize); } #endregion @@ -634,9 +739,7 @@ namespace LiteNetLib.Utils public bool TryGetStringArray(out string[] result) { - ushort strArrayLength; - if (!TryGetUShort(out strArrayLength)) - { + if (!TryGetUShort(out ushort strArrayLength)) { result = null; return false; } @@ -656,10 +759,10 @@ namespace LiteNetLib.Utils public bool TryGetBytesWithLength(out byte[] result) { - if (AvailableBytes >= 4) + if (AvailableBytes >= 2) { - var length = PeekInt(); - if (length >= 0 && AvailableBytes >= length + 4) + ushort length = PeekUShort(); + if (length >= 0 && AvailableBytes >= 2 + length) { result = GetBytesWithLength(); return true; diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs index 1c9d724..0f08ade 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetDataWriter.cs @@ -2,6 +2,7 @@ using System.Net; using System.Runtime.CompilerServices; using System.Text; +using System.Threading; namespace LiteNetLib.Utils { @@ -12,15 +13,24 @@ namespace LiteNetLib.Utils private const int InitialSize = 64; private readonly bool _autoResize; - public int Capacity => _data.Length; - public byte[] Data => _data; - public int Length => _position; + public int Capacity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data.Length; + } + public byte[] Data + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _data; + } + public int Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _position; + } - // Cache encoding instead of creating it with BinaryWriter each time - // 1000 readers before: 1MB GC, 30ms - // 1000 readers after: .8MB GC, 18ms - private static readonly UTF8Encoding _uTF8Encoding = new UTF8Encoding(false, true); - public const int StringBufferMaxLength = 1024 * 32; // <- short.MaxValue + 1 + public static readonly ThreadLocal uTF8Encoding = new ThreadLocal(() => new UTF8Encoding(false, true)); + public const int StringBufferMaxLength = 65535; private readonly byte[] _stringBuffer = new byte[StringBufferMaxLength]; public NetDataWriter() : this(true, InitialSize) @@ -222,40 +232,32 @@ namespace LiteNetLib.Utils _position += data.Length; } - public void PutSBytesWithLength(sbyte[] data, int offset, int length) + public void PutSBytesWithLength(sbyte[] data, int offset, ushort length) { if (_autoResize) - ResizeIfNeed(_position + length + 4); + ResizeIfNeed(_position + 2 + length); FastBitConverter.GetBytes(_data, _position, length); - Buffer.BlockCopy(data, offset, _data, _position + 4, length); - _position += length + 4; + Buffer.BlockCopy(data, offset, _data, _position + 2, length); + _position += 2 + length; } public void PutSBytesWithLength(sbyte[] data) { - if (_autoResize) - ResizeIfNeed(_position + data.Length + 4); - FastBitConverter.GetBytes(_data, _position, data.Length); - Buffer.BlockCopy(data, 0, _data, _position + 4, data.Length); - _position += data.Length + 4; + PutArray(data, 1); } - public void PutBytesWithLength(byte[] data, int offset, int length) + public void PutBytesWithLength(byte[] data, int offset, ushort length) { if (_autoResize) - ResizeIfNeed(_position + length + 4); + ResizeIfNeed(_position + 2 + length); FastBitConverter.GetBytes(_data, _position, length); - Buffer.BlockCopy(data, offset, _data, _position + 4, length); - _position += length + 4; + Buffer.BlockCopy(data, offset, _data, _position + 2, length); + _position += 2 + length; } public void PutBytesWithLength(byte[] data) { - if (_autoResize) - ResizeIfNeed(_position + data.Length + 4); - FastBitConverter.GetBytes(_data, _position, data.Length); - Buffer.BlockCopy(data, 0, _data, _position + 4, data.Length); - _position += data.Length + 4; + PutArray(data, 1); } public void Put(bool value) @@ -263,7 +265,7 @@ namespace LiteNetLib.Utils Put((byte)(value ? 1 : 0)); } - private void PutArray(Array arr, int sz) + public void PutArray(Array arr, int sz) { ushort length = arr == null ? (ushort) 0 : (ushort)arr.Length; sz *= length; @@ -335,6 +337,14 @@ namespace LiteNetLib.Utils for (int i = 0; i < strArrayLength; i++) Put(value[i], strMaxLength); } + + public void PutArray(T[] value) where T : INetSerializable, new() + { + ushort strArrayLength = (ushort)(value?.Length ?? 0); + Put(strArrayLength); + for (int i = 0; i < strArrayLength; i++) + value[i].Serialize(this); + } public void Put(IPEndPoint endPoint) { @@ -352,16 +362,16 @@ namespace LiteNetLib.Utils /// public void Put(string value, int maxLength) { - if (value == null) + if (string.IsNullOrEmpty(value)) { Put((ushort)0); return; } int length = maxLength > 0 && value.Length > maxLength ? maxLength : value.Length; - int size = _uTF8Encoding.GetBytes(value, 0, length, _stringBuffer, 0); + int size = uTF8Encoding.Value.GetBytes(value, 0, length, _stringBuffer, 0); - if (size >= StringBufferMaxLength) + if (size == 0 || size >= StringBufferMaxLength) { Put((ushort)0); return; diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs index 007d520..c18683e 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetPacketProcessor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; namespace LiteNetLib.Utils { @@ -26,7 +27,6 @@ namespace LiteNetLib.Utils protected delegate void SubscribeDelegate(NetDataReader reader, object userData); private readonly NetSerializer _netSerializer; private readonly Dictionary _callbacks = new Dictionary(); - private readonly NetDataWriter _netDataWriter = new NetDataWriter(); public NetPacketProcessor() { @@ -118,35 +118,11 @@ namespace LiteNetLib.Utils ReadPacket(reader, null); } - public void Send(NetPeer peer, T packet, DeliveryMethod options) where T : class, new() - { - _netDataWriter.Reset(); - Write(_netDataWriter, packet); - peer.Send(_netDataWriter, options); - } - - public void SendNetSerializable(NetPeer peer, ref T packet, DeliveryMethod options) where T : INetSerializable - { - _netDataWriter.Reset(); - WriteNetSerializable(_netDataWriter, ref packet); - peer.Send(_netDataWriter, options); - } - - public void Send(NetManager manager, T packet, DeliveryMethod options) where T : class, new() - { - _netDataWriter.Reset(); - Write(_netDataWriter, packet); - manager.SendToAll(_netDataWriter, options); - } - - public void SendNetSerializable(NetManager manager, ref T packet, DeliveryMethod options) where T : INetSerializable - { - _netDataWriter.Reset(); - WriteNetSerializable(_netDataWriter, ref packet); - manager.SendToAll(_netDataWriter, options); - } - - public void Write(NetDataWriter writer, T packet) where T : class, new() + public void Write< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>(NetDataWriter writer, T packet) where T : class, new() { WriteHash(writer); _netSerializer.Serialize(writer, packet); @@ -175,7 +151,11 @@ namespace LiteNetLib.Utils /// event that will be called when packet deserialized with ReadPacket method /// Method that constructs packet instead of slow Activator.CreateInstance /// 's fields are not supported, or it has no fields - public void Subscribe(Action onReceive, Func packetConstructor) where T : class, new() + public void Subscribe< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>(Action onReceive, Func packetConstructor) where T : class, new() { _netSerializer.Register(); _callbacks[GetHash()] = (reader, userData) => @@ -192,7 +172,11 @@ namespace LiteNetLib.Utils /// event that will be called when packet deserialized with ReadPacket method /// Method that constructs packet instead of slow Activator.CreateInstance /// 's fields are not supported, or it has no fields - public void Subscribe(Action onReceive, Func packetConstructor) where T : class, new() + public void Subscribe< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T, TUserData>(Action onReceive, Func packetConstructor) where T : class, new() { _netSerializer.Register(); _callbacks[GetHash()] = (reader, userData) => @@ -209,7 +193,11 @@ namespace LiteNetLib.Utils /// /// event that will be called when packet deserialized with ReadPacket method /// 's fields are not supported, or it has no fields - public void SubscribeReusable(Action onReceive) where T : class, new() + public void SubscribeReusable< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>(Action onReceive) where T : class, new() { _netSerializer.Register(); var reference = new T(); @@ -226,7 +214,11 @@ namespace LiteNetLib.Utils /// /// event that will be called when packet deserialized with ReadPacket method /// 's fields are not supported, or it has no fields - public void SubscribeReusable(Action onReceive) where T : class, new() + public void SubscribeReusable< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T, TUserData>(Action onReceive) where T : class, new() { _netSerializer.Register(); var reference = new T(); diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs index 63f6cd6..1195488 100644 --- a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/NetSerializer.cs @@ -1,6 +1,7 @@ using System; using System.Reflection; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Net; using System.Runtime.Serialization; @@ -568,13 +569,16 @@ namespace LiteNetLib.Utils _maxStringLength = maxStringLength; } - private ClassInfo RegisterInternal() + private ClassInfo RegisterInternal< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>() { if (ClassInfo.Instance != null) return ClassInfo.Instance; - Type t = typeof(T); - var props = t.GetProperties( + var props = typeof(T).GetProperties( BindingFlags.Instance | BindingFlags.Public | BindingFlags.GetProperty | @@ -663,7 +667,11 @@ namespace LiteNetLib.Utils } /// 's fields are not supported, or it has no fields - public void Register() + public void Register< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>() { RegisterInternal(); } @@ -674,7 +682,11 @@ namespace LiteNetLib.Utils /// NetDataReader with packet /// Returns packet if packet in reader is matched type /// 's fields are not supported, or it has no fields - public T Deserialize(NetDataReader reader) where T : class, new() + public T Deserialize< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>(NetDataReader reader) where T : class, new() { var info = RegisterInternal(); var result = new T(); @@ -696,7 +708,11 @@ namespace LiteNetLib.Utils /// Deserialization target /// Returns true if packet in reader is matched type /// 's fields are not supported, or it has no fields - public bool Deserialize(NetDataReader reader, T target) where T : class, new() + public bool Deserialize< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>(NetDataReader reader, T target) where T : class, new() { var info = RegisterInternal(); try @@ -716,7 +732,11 @@ namespace LiteNetLib.Utils /// Serialization target NetDataWriter /// Object to serialize /// 's fields are not supported, or it has no fields - public void Serialize(NetDataWriter writer, T obj) where T : class, new() + public void Serialize< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>(NetDataWriter writer, T obj) where T : class, new() { RegisterInternal().Write(obj, writer); } @@ -726,7 +746,11 @@ namespace LiteNetLib.Utils /// /// Object to serialize /// byte array with serialized data - public byte[] Serialize(T obj) where T : class, new() + public byte[] Serialize< +#if NET5_0_OR_GREATER + [DynamicallyAccessedMembers(Trimming.SerializerMemberTypes)] +#endif + T>(T obj) where T : class, new() { if (_writer == null) _writer = new NetDataWriter(); diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/Preserve.cs b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/Preserve.cs new file mode 100644 index 0000000..b73e1b9 --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/Preserve.cs @@ -0,0 +1,12 @@ +using System; + +namespace LiteNetLib.Utils +{ + /// + /// PreserveAttribute prevents byte code stripping from removing a class, method, field, or property. + /// + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] + public class PreserveAttribute : Attribute + { + } +} diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/Preserve.cs.meta b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/Preserve.cs.meta new file mode 100644 index 0000000..4c1d258 --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/Utils/Preserve.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c1036adeea398ef48b307b909966d955 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/package.json b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/package.json new file mode 100644 index 0000000..e501145 --- /dev/null +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/package.json @@ -0,0 +1,11 @@ +{ + "name": "com.revenantx.litenetlib", + "version": "1.0.1-1", + "displayName": "LiteNetLib", + "description": "Lite reliable UDP library for .NET Standard 2.0 (Mono, .NET Core, .NET Framework)", + "unity": "2018.3", + "author": { + "name": "RevenantX", + "url": "https://github.com/RevenantX" + } +} \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt.meta b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/package.json.meta similarity index 75% rename from Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt.meta rename to Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/package.json.meta index 959d54e..be93016 100644 --- a/Assets/FishNet/Runtime/Plugins/Yak/CHANGELOG.txt.meta +++ b/Assets/FishNet/Runtime/Transporting/Transports/Tugboat/LiteNetLib/package.json.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 65389c57cd9accf47967cc3e6cb7ac1b +guid: f46cc664b3dd2944a8b04542ecb07732 TextScriptImporter: externalObjects: {} userData: diff --git a/Assets/FishNet/Runtime/Utility/AdaptiveInterpolationType.cs b/Assets/FishNet/Runtime/Utility/AdaptiveInterpolationType.cs new file mode 100644 index 0000000..94f13c8 --- /dev/null +++ b/Assets/FishNet/Runtime/Utility/AdaptiveInterpolationType.cs @@ -0,0 +1,36 @@ +#if !PREDICTION_1 + +namespace FishNet.Object.Prediction +{ + public enum AdaptiveInterpolationType + { + /// + /// Adaptive interpolation is disabled. An exact interpolation value is used. + /// + Off = 0, + /// + /// Visual disturbances caused by desynchronization are likely, but graphics are significantly closer to the actual position of the object. + /// + VeryLow = 1, + /// + /// Visual disturbances caused by desynchronization are uncommon, but still very possible for physics bodies. Graphics are closer to the actual position of the object. + /// + Low = 2, + /// + /// Visual disturbances caused by desynchronization are still possible but less likely. Graphics are moderately closer to the actual position of the object. + /// + Medium = 3, + /// + /// Visual disturbances caused by desynchronization are very unlikely. Graphics are are using interpolation almost approximate to clients ping. + /// + High = 4, + /// + /// Visual disturbances caused by desynchronization are extremely unlikely. Graphics are using a generous amount interpolation. + /// + VeryHigh = 5, + + } + + +} +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Utility/AdaptiveInterpolationType.cs.meta b/Assets/FishNet/Runtime/Utility/AdaptiveInterpolationType.cs.meta new file mode 100644 index 0000000..1e2e2a5 --- /dev/null +++ b/Assets/FishNet/Runtime/Utility/AdaptiveInterpolationType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9aaf062df354644098da9c46e2a9512 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Utility/AdaptiveLocalTransformSmoother.cs b/Assets/FishNet/Runtime/Utility/AdaptiveLocalTransformSmoother.cs new file mode 100644 index 0000000..9f36a18 --- /dev/null +++ b/Assets/FishNet/Runtime/Utility/AdaptiveLocalTransformSmoother.cs @@ -0,0 +1,612 @@ +#if !PREDICTION_1 +using FishNet.Managing; +using FishNet.Managing.Timing; +using FishNet.Utility.Extension; +using GameKit.Dependencies.Utilities; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace FishNet.Object.Prediction +{ + /// + /// This class is under regular development and it's API may change at any time. + /// + public sealed class ChildTransformTickSmoother : IResettable + { + #region Types. + private struct TickTransformProperties + { + public uint Tick; + public TransformProperties Properties; + + public TickTransformProperties(uint tick, Transform t) + { + Tick = tick; + Properties = new TransformProperties(t.localPosition, t.localRotation, t.localScale); + } + public TickTransformProperties(uint tick, Transform t, Vector3 localScale) + { + Tick = tick; + Properties = new TransformProperties(t.localPosition, t.localRotation, localScale); + } + public TickTransformProperties(uint tick, TransformProperties tp) + { + Tick = tick; + Properties = tp; + } + } + #endregion + + #region Private. + /// + /// Object to smooth. + /// + private Transform _graphicalObject; + /// + /// When not MoveRatesCls.UNSET_VALUE the graphical object will teleport into it's next position if the move distance exceeds this value. + /// + private float _teleportThreshold; + /// + /// How quickly to move towards goal values. + /// + private MoveRates _moveRates = new MoveRates(MoveRatesCls.UNSET_VALUE); + /// + /// True if a pretick occurred since last postTick. + /// + private bool _preTicked; + /// + /// World offset values of the graphical from the NetworkObject during initialization. + /// + private TransformProperties _gfxInitializedOffsetValues; + /// + /// World values of the graphical after it's been aligned to initialized values in PreTick. + /// + private TransformProperties _gfxPreSimulateWorldValues; + /// + /// TickDelta on the TimeManager. + /// + private float _tickDelta; + /// + /// How many ticks to interpolate over when not using adaptive. + /// + private byte _ownerInterpolation; + /// + /// Current interpolation, regardless of if using adaptive or not. + /// + private byte _interpolation; + /// + /// NetworkObject this is for. + /// + private NetworkObject _networkObject; + /// + /// Value to multiply movement by. This is used to reduce or increase the rate the movement buffer is consumed. + /// + private float _movementMultiplier = 1f; + /// + /// TransformProperties to move towards. + /// + private BasicQueue _transformProperties; + /// + /// Which properties to smooth. + /// + private TransformPropertiesFlag _ownerSmoothedProperties; + /// + /// Which properties to smooth. + /// + private TransformPropertiesFlag _spectatorSmoothedProperties; + /// + /// Updates the smoothedProperties value. + /// + /// New value. + /// True if updating values for the spectator, false if updating for owner. + public void SetSmoothedProperties(TransformPropertiesFlag value, bool forSpectator) + { + if (forSpectator) + _spectatorSmoothedProperties = value; + else + _ownerSmoothedProperties = value; + } + /// + /// Amount of adaptive interpolation to use. + /// + private AdaptiveInterpolationType _adaptiveInterpolation = AdaptiveInterpolationType.Low; + /// + /// Updates the adaptiveInterpolation value. + /// + /// New value. + public void SetAdaptiveInterpolation(AdaptiveInterpolationType adaptiveInterpolation) + { + _adaptiveInterpolation = adaptiveInterpolation; + } + /// + /// Set interpolation to use for spectated objects if adaptiveInterpolation is off. + /// + private byte _spectatorInterpolation; + /// + /// Sets the spectator interpolation value. + /// + /// New value. + /// True to also disable adaptive interpolation to use this new value. + public void SetSpectatorInterpolation(byte value, bool disableAdaptiveInterpolation = true) + { + _spectatorInterpolation = value; + if (disableAdaptiveInterpolation) + _adaptiveInterpolation = AdaptiveInterpolationType.Off; + } + /// + /// Previous parent the graphical was attached to. + /// + private Transform _previousParent; + /// + /// True if to detach at runtime. + /// + private bool _detach; + /// + /// True if were an owner of the NetworkObject during PreTick. + /// This is only used for performance gains. + /// + private bool _ownerOnPretick; + /// + /// True if adaptive interpolation should be used. + /// + private bool _useAdaptiveInterpolation => (!_ownerOnPretick && _adaptiveInterpolation != AdaptiveInterpolationType.Off); + /// + /// True if Initialized has been called and settings have not been reset. + /// + private bool _initialized; + #endregion + + #region Const. + /// + /// Maximum allowed entries to be queued over the interpolation amount. + /// + private int MAXIMUM_QUEUED_OVER_INTERPOLATION = 3; + #endregion + + ~ChildTransformTickSmoother() + { + //This is a last resort for if something didnt deinitialize right. + ResetState(); + } + + /// + /// Initializes this smoother; should only be completed once. + /// + public void Initialize(NetworkObject nob, Transform graphicalObject, bool detach, float teleportDistance, float tickDelta, byte ownerInterpolation, TransformPropertiesFlag ownerSmoothedProperties, byte spectatorInterpolation, TransformPropertiesFlag specatorSmoothedProperties, AdaptiveInterpolationType adaptiveInterpolation) + { + ResetState(); + _detach = detach; + _networkObject = nob; + _transformProperties = CollectionCaches.RetrieveBasicQueue(); + _gfxInitializedOffsetValues = nob.transform.GetTransformOffsets(graphicalObject); + _tickDelta = tickDelta; + _graphicalObject = graphicalObject; + _teleportThreshold = teleportDistance; + _ownerInterpolation = ownerInterpolation; + _spectatorInterpolation = spectatorInterpolation; + _ownerSmoothedProperties = ownerSmoothedProperties; + _spectatorSmoothedProperties = specatorSmoothedProperties; + SetAdaptiveInterpolation(adaptiveInterpolation); + UpdateInterpolation(0); + _initialized = true; + } + + /// + /// Deinitializes this smoother resetting values. + /// + public void Deinitialize() + { + ResetState(); + } + + /// + /// Updates interpolation based on localClient latency. + /// + private void UpdateInterpolation(uint clientStateTick) + { + if (_networkObject.IsServerStarted || _networkObject.IsOwner) + { + _interpolation = _ownerInterpolation; + } + else + { + if (_adaptiveInterpolation == AdaptiveInterpolationType.Off) + { + _interpolation = _spectatorInterpolation; + } + else + { + float interpolation; + TimeManager tm = _networkObject.TimeManager; + if (clientStateTick == 0) + { + //Not enough data to calculate; guestimate. This should only happen once. + float fRtt = (float)tm.RoundTripTime; + interpolation = (fRtt / 10f); + + } + else + { + interpolation = (tm.LocalTick - clientStateTick) + _networkObject.PredictionManager.StateInterpolation; + } + + switch (_adaptiveInterpolation) + { + case AdaptiveInterpolationType.VeryLow: + interpolation *= 0.25f; + break; + case AdaptiveInterpolationType.Low: + interpolation *= 0.375f; + break; + case AdaptiveInterpolationType.Medium: + interpolation *= 0.5f; + break; + case AdaptiveInterpolationType.High: + interpolation *= 0.75f; + break; + //Make no changes for maximum. + } + + interpolation = Mathf.Clamp(interpolation, 1f, (float)byte.MaxValue); + _interpolation = (byte)Mathf.RoundToInt(interpolation); + } + } + } + + internal void OnStartClient() + { + if (!_detach) + return; + + _previousParent = _graphicalObject.parent; + TransformProperties gfxWorldProperties = _graphicalObject.GetWorldProperties(); + _graphicalObject.SetParent(null); + _graphicalObject.SetWorldProperties(gfxWorldProperties); + } + + internal void OnStopClient() + { + if (!_detach || _previousParent == null || _graphicalObject == null) + return; + + _graphicalObject.SetParent(_previousParent); + _graphicalObject.SetWorldProperties(GetNetworkObjectWorldPropertiesWithOffset()); + } + + /// + /// Called every frame. + /// + internal void Update() + { + if (!CanSmooth()) + return; + + if (_useAdaptiveInterpolation) + AdaptiveMoveToTarget(Time.deltaTime); + else + BasicMoveToTarget(Time.deltaTime); + } + + /// + /// Called when the TimeManager invokes OnPreTick. + /// + public void OnPreTick() + { + if (!CanSmooth()) + return; + + _preTicked = true; + + _ownerOnPretick = _networkObject.IsOwner; + if (_useAdaptiveInterpolation) + DiscardExcessiveTransformPropertiesQueue(); + else + ClearTransformPropertiesQueue(); + //These only need to be set if still attached. + if (!_detach) + _gfxPreSimulateWorldValues = _graphicalObject.GetWorldProperties(); + } + + /// + /// Called when the PredictionManager invokes OnPreReconcile. + /// + public void OnPreReconcile() + { + UpdateInterpolation(_networkObject.PredictionManager.ClientStateTick); + } + + /// + /// Called when the TimeManager invokes OnPostReplay. + /// + /// Replay tick for the local client. + public void OnPostReplay(uint clientTick) + { + if (_transformProperties.Count == 0) + return; + if (!_useAdaptiveInterpolation) + return; + + uint firstTick = _transformProperties.Peek().Tick; + //Already in motion to first entry, or first entry passed tick. + if (clientTick <= firstTick) + return; + + ModifyTransformProperties(clientTick, firstTick); + } + + /// + /// Called when TimeManager invokes OnPostTick. + /// + /// Local tick of the client. + public void OnPostTick(uint clientTick) + { + if (!CanSmooth()) + return; + + //If preticked then previous transform values are known. + if (_preTicked) + { + if (_useAdaptiveInterpolation) + DiscardExcessiveTransformPropertiesQueue(); + else + ClearTransformPropertiesQueue(); + //Only needs to be put to pretick position if not detached. + if (!_detach) + _graphicalObject.SetWorldProperties(_gfxPreSimulateWorldValues); + AddTransformProperties(clientTick); + } + //If did not pretick then the only thing we can do is snap to instantiated values. + else + { + //Only set to position if not to detach. + if (!_detach) + _graphicalObject.SetWorldProperties(GetNetworkObjectWorldPropertiesWithOffset()); + } + } + + /// + /// Clears the pending movement queue. + /// + private void ClearTransformPropertiesQueue() + { + _transformProperties.Clear(); + //Also unset move rates since there is no more queue. + _moveRates = new MoveRates(MoveRatesCls.UNSET_VALUE); + } + + /// + /// Discards datas over interpolation limit from movement queue. + /// + private void DiscardExcessiveTransformPropertiesQueue() + { + if (!_useAdaptiveInterpolation) + { + _networkObject.NetworkManager.LogError($"This method should only be called when using adaptive interpolation."); + return; + } + + int dequeueCount = (_transformProperties.Count - (_interpolation + MAXIMUM_QUEUED_OVER_INTERPOLATION)); + //If there are entries to dequeue. + if (dequeueCount > 0) + { + TickTransformProperties tpp = default; + for (int i = 0; i < dequeueCount; i++) + tpp = _transformProperties.Dequeue(); + + SetAdaptiveMoveRates(tpp.Properties, _transformProperties[0].Properties); + } + } + + /// + /// Adds a new transform properties and sets move rates if needed. + /// + private void AddTransformProperties(uint tick) + { + TickTransformProperties tpp = new TickTransformProperties(tick, GetNetworkObjectWorldPropertiesWithOffset()); + + _transformProperties.Enqueue(tpp); + //If first entry then set move rates. + if (_transformProperties.Count == 1) + { + TransformProperties gfxWorldProperties = _graphicalObject.GetWorldProperties(); + if (_useAdaptiveInterpolation) + SetAdaptiveMoveRates(gfxWorldProperties, tpp.Properties); + else + SetBasicMoveRates(gfxWorldProperties, tpp.Properties); + } + } + + /// + /// Modifies a transform property for a tick. This does not error check for empty collections. + /// + /// First tick in the queue. If 0 this will be looked up. + private void ModifyTransformProperties(uint clientTick, uint firstTick) + { + uint tick = clientTick; + /*Ticks will always be added incremental by 1 so it's safe to jump ahead the difference + * of tick and firstTick. */ + int index = (int)(tick - firstTick); + //Replace with new data. + if (index < _transformProperties.Count) + { + _transformProperties[index] = new TickTransformProperties(tick, _networkObject.transform, _graphicalObject.localScale); + } + else + { + //This should never happen. + } + } + + /// + /// Returns TransformProperties of the NetworkObject with the graphicals world offset. + /// + /// + private TransformProperties GetNetworkObjectWorldPropertiesWithOffset() => _networkObject.transform.GetWorldProperties(_gfxInitializedOffsetValues); + + /// + /// Returns if prediction can be used on this rigidbody. + /// + /// + private bool CanSmooth() + { + if (_graphicalObject == null) + return false; + + return true; + } + + /// + /// Sets Position and Rotation move rates to reach Target datas. + /// + private void SetBasicMoveRates(TransformProperties prevValues, TransformProperties nextValues) + { + byte interpolation = _interpolation; + float duration = (_tickDelta * interpolation); + /* If interpolation is 1 then add on a tiny amount + * of more time to compensate for frame time, so that + * the smoothing does not complete before the next tick, + * as this would result in jitter. */ + if (interpolation == 1) + duration += (1 / 55f); + float teleportT = (_teleportThreshold * (float)interpolation); + + _moveRates = MoveRates.GetMoveRates(prevValues, nextValues, duration, teleportT); + _moveRates.TimeRemaining = duration; + } + + + /// + /// Sets Position and Rotation move rates to reach Target datas. + /// + private void SetAdaptiveMoveRates(TransformProperties prevValues, TransformProperties nextValues) + { + float duration = _tickDelta; + /* If interpolation is 1 then add on a tiny amount + * of more time to compensate for frame time, so that + * the smoothing does not complete before the next tick, + * as this would result in jitter. */ + float teleportT = _teleportThreshold; + _moveRates = MoveRates.GetMoveRates(prevValues, nextValues, duration, teleportT); + _moveRates.TimeRemaining = duration; + + SetMovementMultiplier(); + } + + private void SetMovementMultiplier() + { + /* If there's more in queue than interpolation then begin to move faster based on overage. + * Move 5% faster for every overage. */ + int overInterpolation = (_transformProperties.Count - _interpolation); + //If needs to be adjusted. + if (overInterpolation != 0f) + { + _movementMultiplier += (0.015f * overInterpolation); + } + //If does not need to be adjusted. + else + { + //If interpolation is 1 then slow down just barely to accomodate for frame delta variance. + if (_interpolation == 1) + _movementMultiplier = 0.99f; + } + + _movementMultiplier = Mathf.Clamp(_movementMultiplier, 0.95f, 1.05f); + } + + + /// + /// Moves transform to target values. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void BasicMoveToTarget(float delta) + { + int tpCount = _transformProperties.Count; + //No data. + if (tpCount == 0) + return; + + TickTransformProperties ttp = _transformProperties.Peek(); + _moveRates.MoveWorldToTarget(_graphicalObject, ttp.Properties, delta); + + //if TimeLeft is <= 0f then transform should be at goal. + if (_moveRates.TimeRemaining <= 0f) + ClearTransformPropertiesQueue(); + } + + /// + /// Moves transform to target values. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AdaptiveMoveToTarget(float delta) + { + int tpCount = _transformProperties.Count; + //No data. + if (tpCount == 0) + return; + /* If buffer is considerably under goal then halt + * movement. This will allow the buffer to grow. */ + if ((tpCount - _interpolation) < -4) + return; + + TickTransformProperties ttp = _transformProperties.Peek(); + TransformPropertiesFlag smoothedProperties = (_ownerOnPretick) ? _ownerSmoothedProperties : _spectatorSmoothedProperties; + _moveRates.MoveWorldToTarget(_graphicalObject, ttp.Properties, smoothedProperties, (delta * _movementMultiplier)); + float tRemaining = _moveRates.TimeRemaining; + //if TimeLeft is <= 0f then transform is at goal. Grab a new goal if possible. + if (tRemaining <= 0f) + { + //Dequeue current entry and if there's another call a move on it. + _transformProperties.Dequeue(); + + //If there are entries left then setup for the next. + if (_transformProperties.Count > 0) + { + SetAdaptiveMoveRates(ttp.Properties, _transformProperties.Peek().Properties); + //If delta is negative then call move again with abs. + if (tRemaining < 0f) + AdaptiveMoveToTarget(Mathf.Abs(tRemaining)); + } + //No remaining, set to snap. + else + { + ClearTransformPropertiesQueue(); + } + } + } + + public void ResetState() + { + if (!_initialized) + return; + + _networkObject = null; + if (_graphicalObject != null) + { + if (_networkObject != null) + { + if (_detach) + _graphicalObject.SetParent(_networkObject.transform); + _graphicalObject.SetWorldProperties(GetNetworkObjectWorldPropertiesWithOffset()); + _graphicalObject = null; + } + else if (_detach) + { + MonoBehaviour.Destroy(_graphicalObject.gameObject); + } + } + _movementMultiplier = 1f; + CollectionCaches.StoreAndDefault(ref _transformProperties); + _teleportThreshold = default; + _moveRates = default; + _preTicked = default; + _gfxInitializedOffsetValues = default; + _gfxPreSimulateWorldValues = default; + _tickDelta = default; + _interpolation = default; + } + + public void InitializeState() { } + } + +} +#endif \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Utility/AdaptiveLocalTransformSmoother.cs.meta b/Assets/FishNet/Runtime/Utility/AdaptiveLocalTransformSmoother.cs.meta new file mode 100644 index 0000000..e5d1ae0 --- /dev/null +++ b/Assets/FishNet/Runtime/Utility/AdaptiveLocalTransformSmoother.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 50721ce3e3600754dbc3c6e2e5446728 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs b/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs index 2f24933..c827340 100644 --- a/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs +++ b/Assets/FishNet/Runtime/Utility/Extension/Transforms.cs @@ -1,5 +1,6 @@ using FishNet.Documenting; using FishNet.Object; +using System.Runtime.CompilerServices; using UnityEngine; namespace FishNet.Utility.Extension @@ -16,6 +17,17 @@ namespace FishNet.Utility.Extension return tp; } + /// + /// Sets values of TransformProperties to a transforms world properties. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TransformProperties GetWorldProperties(this Transform t, TransformProperties offset) + { + TransformProperties tp = new TransformProperties(t.position, t.rotation, t.localScale); + tp.Add(offset); + return tp; + } + /// /// Sets values of TransformProperties to a transforms world properties. /// @@ -56,7 +68,7 @@ namespace FishNet.Utility.Extension } /// - /// Sets the offset values of target from a transform. + /// Gets the offset values by subtracting this from target. /// /// Position offset result. /// Rotation offset result. @@ -69,7 +81,7 @@ namespace FishNet.Utility.Extension } /// - /// Gets the offset values of target from a transform. + /// Gets the offset values by subtracting this from target. /// public static TransformProperties GetTransformOffsets(this Transform t, Transform target) { @@ -153,7 +165,7 @@ namespace FishNet.Utility.Extension } /// - /// Outputs properties to use for a transform. When a nullable property has value that value is used, otherwise the transforms current property is used. + /// Oututs properties to use for a transform. When a nullable property has value that value is used, otherwise the transforms current property is used. /// public static void OutLocalPropertyValues(this Transform t, Vector3? nullablePos, Quaternion? nullableRot, Vector3? nullableScale, out Vector3 pos, out Quaternion rot, out Vector3 scale) { diff --git a/Assets/FishNet/Runtime/Utility/Performance/BasicQueue.cs b/Assets/FishNet/Runtime/Utility/Performance/BasicQueue.cs index ea3b7f9..d3b04c9 100644 --- a/Assets/FishNet/Runtime/Utility/Performance/BasicQueue.cs +++ b/Assets/FishNet/Runtime/Utility/Performance/BasicQueue.cs @@ -1,231 +1,231 @@ -using System; +//using System; //Remove on V5 -namespace FishNet.Utility.Performance -{ +//namespace FishNet.Utility.Performance +//{ - /// - /// Unity 2022 has a bug where codegen will not compile when referencing a Queue type, - /// while also targeting .Net as the framework API. - /// As a work around this class is used for queues instead. - /// - public class BasicQueue - { - /// - /// Maximum size of the collection. - /// - public int Capacity => Collection.Length; - /// - /// Number of elements in the queue. - /// - public int Count => _written; - /// - /// Collection containing data. - /// - private T[] Collection = new T[4]; - /// - /// Current write index of the collection. - /// - public int WriteIndex { get; private set; } - /// - /// Buffer for resizing. - /// - private T[] _resizeBuffer = new T[0]; - /// - /// Read position of the next Dequeue. - /// - private int _read; +// /// +// /// Unity 2022 has a bug where codegen will not compile when referencing a Queue type, +// /// while also targeting .Net as the framework API. +// /// As a work around this class is used for queues instead. +// /// +// public class BasicQueue +// { +// /// +// /// Maximum size of the collection. +// /// +// public int Capacity => Collection.Length; +// /// +// /// Number of elements in the queue. +// /// +// public int Count => _written; +// /// +// /// Collection containing data. +// /// +// private T[] Collection = new T[4]; +// /// +// /// Current write index of the collection. +// /// +// public int WriteIndex { get; private set; } +// /// +// /// Buffer for resizing. +// /// +// private T[] _resizeBuffer = new T[0]; +// /// +// /// Read position of the next Dequeue. +// /// +// private int _read; - /// - /// Length of the queue. - /// - private int _written; +// /// +// /// Length of the queue. +// /// +// private int _written; - /// - /// Enqueues an entry. - /// - /// - public void Enqueue(T data) - { - if (_written == Collection.Length) - Resize(); +// /// +// /// Enqueues an entry. +// /// +// /// +// public void Enqueue(T data) +// { +// if (_written == Collection.Length) +// Resize(); - if (WriteIndex >= Collection.Length) - WriteIndex = 0; - Collection[WriteIndex] = data; +// if (WriteIndex >= Collection.Length) +// WriteIndex = 0; +// Collection[WriteIndex] = data; - WriteIndex++; - _written++; - } +// WriteIndex++; +// _written++; +// } - /// - /// Tries to dequeue the next entry. - /// - /// Dequeued entry. - /// True if an entry existed to dequeue. - public bool TryDequeue(out T result) - { - if (_written == 0) - { - result = default; - return false; - } +// /// +// /// Tries to dequeue the next entry. +// /// +// /// Dequeued entry. +// /// True if an entry existed to dequeue. +// public bool TryDequeue(out T result) +// { +// if (_written == 0) +// { +// result = default; +// return false; +// } - result = Dequeue(); - return true; - } +// result = Dequeue(); +// return true; +// } - /// - /// Dequeues the next entry. - /// - /// - public T Dequeue() - { - if (_written == 0) - throw new Exception($"Queue of type {typeof(T).Name} is empty."); +// /// +// /// Dequeues the next entry. +// /// +// /// +// public T Dequeue() +// { +// if (_written == 0) +// throw new Exception($"Queue of type {typeof(T).Name} is empty."); - T result = Collection[_read]; +// T result = Collection[_read]; - _written--; - _read++; - if (_read >= Collection.Length) - _read = 0; +// _written--; +// _read++; +// if (_read >= Collection.Length) +// _read = 0; - return result; - } +// return result; +// } - /// - /// Tries to peek the next entry. - /// - /// Peeked entry. - /// True if an entry existed to peek. - public bool TryPeek(out T result) - { - if (_written == 0) - { - result = default; - return false; - } +// /// +// /// Tries to peek the next entry. +// /// +// /// Peeked entry. +// /// True if an entry existed to peek. +// public bool TryPeek(out T result) +// { +// if (_written == 0) +// { +// result = default; +// return false; +// } - result = Peek(); - return true; - } +// result = Peek(); +// return true; +// } - /// - /// Peeks the next queue entry. - /// - /// - public T Peek() - { - if (_written == 0) - throw new Exception($"Queue of type {typeof(T).Name} is empty."); +// /// +// /// Peeks the next queue entry. +// /// +// /// +// public T Peek() +// { +// if (_written == 0) +// throw new Exception($"Queue of type {typeof(T).Name} is empty."); - return Collection[_read]; - } +// return Collection[_read]; +// } - /// - /// Clears the queue. - /// - public void Clear() - { - _read = 0; - WriteIndex = 0; - _written = 0; +// /// +// /// Clears the queue. +// /// +// public void Clear() +// { +// _read = 0; +// WriteIndex = 0; +// _written = 0; - DefaultCollection(Collection); - DefaultCollection(_resizeBuffer); +// DefaultCollection(Collection); +// DefaultCollection(_resizeBuffer); - void DefaultCollection(T[] array) - { - int count = array.Length; - for (int i = 0; i < count; i++) - array[i] = default; - } - } +// void DefaultCollection(T[] array) +// { +// int count = array.Length; +// for (int i = 0; i < count; i++) +// array[i] = default; +// } +// } - /// - /// Doubles the queue size. - /// - private void Resize() - { - int length = _written; - int doubleLength = (length * 2); - int read = _read; +// /// +// /// Doubles the queue size. +// /// +// private void Resize() +// { +// int length = _written; +// int doubleLength = (length * 2); +// int read = _read; - /* Make sure copy array is the same size as current - * and copy contents into it. */ - //Ensure large enough to fit contents. - T[] resizeBuffer = _resizeBuffer; - if (resizeBuffer.Length < doubleLength) - Array.Resize(ref resizeBuffer, doubleLength); - //Copy from the read of queue first. - int copyLength = (length - read); - Array.Copy(Collection, read, resizeBuffer, 0, copyLength); - /* If read index was higher than 0 - * then copy remaining data as well from 0. */ - if (read > 0) - Array.Copy(Collection, 0, resizeBuffer, copyLength, read); +// /* Make sure copy array is the same size as current +// * and copy contents into it. */ +// //Ensure large enough to fit contents. +// T[] resizeBuffer = _resizeBuffer; +// if (resizeBuffer.Length < doubleLength) +// Array.Resize(ref resizeBuffer, doubleLength); +// //Copy from the read of queue first. +// int copyLength = (length - read); +// Array.Copy(Collection, read, resizeBuffer, 0, copyLength); +// /* If read index was higher than 0 +// * then copy remaining data as well from 0. */ +// if (read > 0) +// Array.Copy(Collection, 0, resizeBuffer, copyLength, read); - //Set _array to resize. - Collection = resizeBuffer; - //Reset positions. - _read = 0; - WriteIndex = length; - } +// //Set _array to resize. +// Collection = resizeBuffer; +// //Reset positions. +// _read = 0; +// WriteIndex = length; +// } - /// - /// Returns value in actual index as it relates to simulated index. - /// - /// Simulated index to return. A value of 0 would return the first simulated index in the collection. - /// - public T this[int simulatedIndex] - { - get - { - int offset = GetRealIndex(simulatedIndex); - return Collection[offset]; - } - set - { - int offset = GetRealIndex(simulatedIndex); - Collection[offset] = value; - } - } +// /// +// /// Returns value in actual index as it relates to simulated index. +// /// +// /// Simulated index to return. A value of 0 would return the first simulated index in the collection. +// /// +// public T this[int simulatedIndex] +// { +// get +// { +// int offset = GetRealIndex(simulatedIndex); +// return Collection[offset]; +// } +// set +// { +// int offset = GetRealIndex(simulatedIndex); +// Collection[offset] = value; +// } +// } - /// - /// Returns the real index of the collection using a simulated index. - /// - /// True to allow an index be returned from an unused portion of the buffer so long as it is within bounds. - private int GetRealIndex(int simulatedIndex, bool allowUnusedBuffer = false) - { - if (simulatedIndex >= Capacity) - { - return ReturnError(); - } - else - { - int written = _written; - //May be out of bounds if allowUnusedBuffer is false. - if (simulatedIndex >= written) - { - if (!allowUnusedBuffer) - return ReturnError(); - } - int offset = (Capacity - written) + simulatedIndex + WriteIndex; - if (offset >= Capacity) - offset -= Capacity; +// /// +// /// Returns the real index of the collection using a simulated index. +// /// +// /// True to allow an index be returned from an unused portion of the buffer so long as it is within bounds. +// private int GetRealIndex(int simulatedIndex, bool allowUnusedBuffer = false) +// { +// if (simulatedIndex >= Capacity) +// { +// return ReturnError(); +// } +// else +// { +// int written = _written; +// //May be out of bounds if allowUnusedBuffer is false. +// if (simulatedIndex >= written) +// { +// if (!allowUnusedBuffer) +// return ReturnError(); +// } +// int offset = (Capacity - written) + simulatedIndex + WriteIndex; +// if (offset >= Capacity) +// offset -= Capacity; - return offset; - } +// return offset; +// } - int ReturnError() - { - UnityEngine.Debug.LogError($"Index {simulatedIndex} is out of range. Collection count is {_written}, Capacity is {Capacity}"); - return -1; - } - } +// int ReturnError() +// { +// UnityEngine.Debug.LogError($"Index {simulatedIndex} is out of range. Collection count is {_written}, Capacity is {Capacity}"); +// return -1; +// } +// } - } +// } -} \ No newline at end of file +//} \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Utility/Performance/DefaultObjectPool.cs b/Assets/FishNet/Runtime/Utility/Performance/DefaultObjectPool.cs index 5233afd..9097e30 100644 --- a/Assets/FishNet/Runtime/Utility/Performance/DefaultObjectPool.cs +++ b/Assets/FishNet/Runtime/Utility/Performance/DefaultObjectPool.cs @@ -79,9 +79,16 @@ namespace FishNet.Utility.Performance } else { - prefab.transform.OutLocalPropertyValues(nullableLocalPosition, nullableLocalRotation, nullableLocalScale, out Vector3 pos, out Quaternion rot, out Vector3 scale); + prefab.transform.OutLocalPropertyValues(nullableLocalPosition, nullableLocalRotation, nullableLocalScale, out Vector3 pos, out Quaternion rot, out Vector3 scale); + if (parent != null) + { + //Convert pos and rot to world values for the instantiate. + pos = parent.TransformPoint(pos); + rot = (parent.rotation * rot); + } NetworkObject result = Instantiate(prefab, pos, rot, parent); result.transform.localScale = scale; + if (makeActive) result.gameObject.SetActive(true); return result; @@ -185,7 +192,7 @@ namespace FishNet.Utility.Performance /// /// /// - private Stack GetOrCreateCache(int collectionId, int prefabId) + public Stack GetOrCreateCache(int collectionId, int prefabId) { if (collectionId >= _cacheCount) { diff --git a/Assets/FishNet/VERSION.txt b/Assets/FishNet/VERSION.txt deleted file mode 100644 index ef8d756..0000000 --- a/Assets/FishNet/VERSION.txt +++ /dev/null @@ -1 +0,0 @@ -4.2.0 \ No newline at end of file diff --git a/Assets/FishNet/VERSION.txt.meta b/Assets/FishNet/VERSION.txt.meta deleted file mode 100644 index fbab156..0000000 --- a/Assets/FishNet/VERSION.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 84a91b39bff26504e9cf03f8aa4fe3ab -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/FishNet/package.json b/Assets/FishNet/package.json index 45613a9..d0ad1b6 100644 --- a/Assets/FishNet/package.json +++ b/Assets/FishNet/package.json @@ -1,6 +1,6 @@ { "name": "com.firstgeargames.fishnet", - "version": "4.1.4", + "version": "4.3.1", "displayName": "FishNet: Networking Evolved", "description": "A feature-rich Unity networking solution aimed towards reliability, ease of use, efficiency, and flexibility.", "unity": "2021.3",